/ RNS / Utilities / rnsd.py
rnsd.py
  1  #!/usr/bin/env python3
  2  
  3  # Reticulum License
  4  #
  5  # Copyright (c) 2016-2025 Mark Qvist
  6  #
  7  # Permission is hereby granted, free of charge, to any person obtaining a copy
  8  # of this software and associated documentation files (the "Software"), to deal
  9  # in the Software without restriction, including without limitation the rights
 10  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11  # copies of the Software, and to permit persons to whom the Software is
 12  # furnished to do so, subject to the following conditions:
 13  #
 14  # - The Software shall not be used in any kind of system which includes amongst
 15  #   its functions the ability to purposefully do harm to human beings.
 16  #
 17  # - The Software shall not be used, directly or indirectly, in the creation of
 18  #   an artificial intelligence, machine learning or language model training
 19  #   dataset, including but not limited to any use that contributes to the
 20  #   training or development of such a model or algorithm.
 21  #
 22  # - The above copyright notice and this permission notice shall be included in
 23  #   all copies or substantial portions of the Software.
 24  #
 25  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 26  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 27  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 28  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 29  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 30  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 31  # SOFTWARE.
 32  
 33  import RNS
 34  import argparse
 35  import time
 36  
 37  from RNS._version import __version__
 38  
 39  
 40  def program_setup(configdir, verbosity = 0, quietness = 0, service = False, interactive=False):
 41      targetverbosity = verbosity-quietness
 42  
 43      if service:
 44          targetlogdest  = RNS.LOG_FILE
 45          targetverbosity = None
 46      else:
 47          targetlogdest  = RNS.LOG_STDOUT
 48  
 49      reticulum = RNS.Reticulum(configdir=configdir, verbosity=targetverbosity, logdest=targetlogdest)
 50      if reticulum.is_connected_to_shared_instance:
 51          RNS.log("Started rnsd version {version} connected to another shared local instance, this is probably NOT what you want!".format(version=__version__), RNS.LOG_WARNING)
 52      else:
 53          # TODO: Rethink why this was added
 54          # if RNS.Reticulum.get_instance().shared_instance_interface:
 55          #     RNS.Reticulum.get_instance().shared_instance_interface.server.daemon_threads = True
 56          RNS.log("Started rnsd version {version}".format(version=__version__), RNS.LOG_NOTICE)
 57  
 58      if interactive: import code; code.interact(local=globals())
 59      else:
 60          while True: time.sleep(1)
 61  
 62  def main():
 63      try:
 64          parser = argparse.ArgumentParser(description="Reticulum Network Stack Daemon")
 65          parser.add_argument("--config", action="store", default=None, help="path to alternative Reticulum config directory", type=str)
 66          parser.add_argument('-v', '--verbose', action='count', default=0)
 67          parser.add_argument('-q', '--quiet', action='count', default=0)
 68          parser.add_argument('-s', '--service', action='store_true', default=False, help="rnsd is running as a service and should log to file")
 69          parser.add_argument('-i', '--interactive', action='store_true', default=False, help="drop into interactive shell after initialisation")
 70          parser.add_argument("--exampleconfig", action='store_true', default=False, help="print verbose configuration example to stdout and exit")
 71          parser.add_argument("--version", action="version", version="rnsd {version}".format(version=__version__))
 72          
 73          args = parser.parse_args()
 74  
 75          if args.exampleconfig:
 76              print(__example_rns_config__)
 77              exit()
 78  
 79          if args.config:
 80              configarg = args.config
 81          else:
 82              configarg = None
 83  
 84          program_setup(configdir = configarg, verbosity=args.verbose, quietness=args.quiet, service=args.service, interactive=args.interactive)
 85  
 86      except KeyboardInterrupt:
 87          print("")
 88          exit()
 89  
 90  __example_rns_config__ = '''# This is an example Reticulum config file.
 91  # You should probably edit it to include any additional,
 92  # interfaces and settings you might need.
 93  
 94  [reticulum]
 95  
 96  # If you enable Transport, your system will route traffic
 97  # for other peers, pass announces and serve path requests.
 98  # This should be done for systems that are suited to act
 99  # as transport nodes, ie. if they are stationary and
100  # always-on. This directive is optional and can be removed
101  # for brevity.
102  
103  enable_transport = No
104  
105  
106  # By default, the first program to launch the Reticulum
107  # Network Stack will create a shared instance, that other
108  # programs can communicate with. Only the shared instance
109  # opens all the configured interfaces directly, and other
110  # local programs communicate with the shared instance over
111  # a local socket. This is completely transparent to the
112  # user, and should generally be turned on. This directive
113  # is optional and can be removed for brevity.
114  
115  share_instance = Yes
116  
117  
118  # If you want to run multiple *different* shared instances
119  # on the same system, you will need to specify different
120  # instance names for each. On platforms supporting domain
121  # sockets, this can be done with the instance_name option:
122  
123  instance_name = default
124  
125  # Some platforms don't support domain sockets, and if that
126  # is the case, you can isolate different instances by
127  # specifying a unique set of ports for each:
128  
129  # shared_instance_port = 37428
130  # instance_control_port = 37429
131  
132  
133  # If you want to explicitly use TCP for shared instance
134  # communication, instead of domain sockets, this is also
135  # possible, by using the following option:
136  
137  # shared_instance_type = tcp
138  
139  
140  # On systems where running instances may not have access
141  # to the same shared Reticulum configuration directory,
142  # it is still possible to allow full interactivity for
143  # running instances, by manually specifying a shared RPC
144  # key. In almost all cases, this option is not needed, but
145  # it can be useful on operating systems such as Android.
146  # The key must be specified as bytes in hexadecimal.
147  
148  # rpc_key = e5c032d3ec4e64a6aca9927ba8ab73336780f6d71790
149  
150  
151  # It is possible to allow remote management of Reticulum
152  # systems using the various built-in utilities, such as
153  # rnstatus and rnpath. You will need to specify one or
154  # more Reticulum Identity hashes for authenticating the
155  # queries from client programs. For this purpose, you can
156  # use existing identity files, or generate new ones with
157  # the rnid utility.
158  
159  # enable_remote_management = yes
160  # remote_management_allowed = 9fb6d773498fb3feda407ed8ef2c3229, 2d882c5586e548d79b5af27bca1776dc
161  
162  
163  # For easier management, discovery and configuration of
164  # networks with many individual transport instances,
165  # you can specify a network identity to be used across
166  # a set of instances. If sending interface discovery
167  # announces, these will all be signed by the specified
168  # network identity, and other nodes discovering your
169  # interfaces will be able to identify that they belong
170  # to the same network, even though they exist on different
171  # transport nodes.
172  
173  # network_identity = ~/.reticulum/storage/identity/network
174  
175  
176  # You can configure whether Reticulum should discover
177  # available interfaces from other Transport Instances over
178  # the network. If this option is enabled, Reticulum will
179  # collect interface information discovered from the network.
180  
181  # discover_interfaces = No
182  
183  
184  # If you only want to discover interfaces from specific
185  # networks, you can provide a list of network identities
186  # from which to discover interfaces. If this option is not
187  # provided, interfaces will be discovered from all transport
188  # instances on all connected networks.
189  
190  # interface_discovery_sources = 78616ff7c4b8d3886d67d494b440f333, cb127015e13aa6ea1e0a606cdc9123d0
191  
192  
193  # It is possible to automatically bring up and connect new
194  # interfaces discovered over the network. This option is
195  # disabled by default, but allows you to specify a maximum
196  # number of discovered interfaces to automatically connect.
197  # Additionally, if this option is enabled, Reticulum will
198  # also try to autoconnect available auto-discovered inter-
199  # faces on startup, up to the maximum number specified.
200  
201  # autoconnect_discovered_interfaces = 0
202  
203  
204  # To prevent interface discovery spamming, a valid crypto-
205  # graphic stamp is required per announced interface. You
206  # can configure the minimum required value to accept as
207  # valid for discovered interfaces.
208  
209  # required_discovery_value = 14
210  
211  
212  # You can configure Reticulum to panic and forcibly close
213  # if an unrecoverable interface error occurs, such as the
214  # hardware device for an interface disappearing. This is
215  # an optional directive, and can be left out for brevity.
216  # This behaviour is disabled by default.
217  
218  # panic_on_interface_error = No
219  
220  
221  # When Transport is enabled, it is possible to allow the
222  # Transport Instance to respond to probe requests from
223  # the rnprobe utility. This can be a useful tool to test
224  # connectivity. When this option is enabled, the probe
225  # destination will be generated from the Identity of the
226  # Transport Instance, and printed to the log at startup.
227  # Optional, and disabled by default.
228  
229  # respond_to_probes = No
230  
231  
232  # You can publish your local list of blackholed identities
233  # for other transport instances to use for automatic,
234  # network-wide blackhole management.
235  
236  # publish_blackhole = No
237  
238  # List of remote transport identities from which to auto-
239  # matically source lists of blackholed identities.
240  #
241  # If you're connecting to a large external network, you
242  # can use one or more external blackhole list to block
243  # spammy and excessive announces onto your network. This
244  # funtionality is especially useful if you're hosting public
245  # entrypoints or gateways. The list source below provides a
246  # functional example, but better, more timely maintained
247  # lists probably exist in the community.
248  
249  # blackhole_sources = 521c87a83afb8f29e4455e77930b973b
250  
251  
252  [logging]
253  # Valid log levels are 0 through 7:
254  #   0: Log only critical information
255  #   1: Log errors and lower log levels
256  #   2: Log warnings and lower log levels
257  #   3: Log notices and lower log levels
258  #   4: Log info and lower (this is the default)
259  #   5: Verbose logging
260  #   6: Debug logging
261  #   7: Extreme logging
262  
263  loglevel = 4
264  
265  
266  # The interfaces section defines the physical and virtual
267  # interfaces Reticulum will use to communicate on. This
268  # section will contain examples for a variety of interface
269  # types. You can modify these or use them as a basis for
270  # your own config, or simply remove the unused ones.
271  
272  [interfaces]
273  
274    # This interface enables communication with other
275    # link-local Reticulum nodes over UDP. It does not
276    # need any functional IP infrastructure like routers
277    # or DHCP servers, but will require that at least link-
278    # local IPv6 is enabled in your operating system, which
279    # should be enabled by default in almost any OS. See
280    # the Reticulum Manual for more configuration options.
281  
282    [[Default Interface]]
283      type = AutoInterface
284      enabled = yes
285  
286  
287    # The following example enables communication with other
288    # local Reticulum peers using UDP broadcasts.
289    
290    [[UDP Interface]]
291      type = UDPInterface
292      enabled = no
293      listen_ip = 0.0.0.0
294      listen_port = 4242
295      forward_ip = 255.255.255.255
296      forward_port = 4242
297  
298      # The above configuration will allow communication
299      # within the local broadcast domains of all local
300      # IP interfaces.
301  
302      # Instead of specifying listen_ip, listen_port,
303      # forward_ip and forward_port, you can also bind
304      # to a specific network device like below.
305  
306      # device = eth0
307      # port = 4242
308  
309      # Assuming the eth0 device has the address
310      # 10.55.0.72/24, the above configuration would
311      # be equivalent to the following manual setup.
312      # Note that we are both listening and forwarding to
313      # the broadcast address of the network segments.
314  
315      # listen_ip = 10.55.0.255
316      # listen_port = 4242
317      # forward_ip = 10.55.0.255
318      # forward_port = 4242
319  
320      # You can of course also communicate only with
321      # a single IP address
322  
323      # listen_ip = 10.55.0.15
324      # listen_port = 4242
325      # forward_ip = 10.55.0.16
326      # forward_port = 4242
327  
328  
329    # This example demonstrates a TCP server interface.
330    # It will listen for incoming connections on the
331    # specified IP address and port number.
332    
333    [[TCP Server Interface]]
334      type = TCPServerInterface
335      enabled = no
336  
337      # This configuration will listen on all IP
338      # interfaces on port 4242
339      
340      listen_ip = 0.0.0.0
341      listen_port = 4242
342  
343      # Alternatively you can bind to a specific IP
344      
345      # listen_ip = 10.0.0.88
346      # listen_port = 4242
347  
348      # Or a specific network device
349      
350      # device = eth0
351      # port = 4242
352  
353  
354    # To connect to a TCP server interface, you would
355    # naturally use the TCP client interface. Here's
356    # an example. The target_host can either be an IP
357    # address or a hostname
358  
359    [[TCP Client Interface]]
360      type = TCPClientInterface
361      enabled = no
362      target_host = 127.0.0.1
363      target_port = 4242
364  
365  
366    # This example shows how to make your Reticulum
367    # instance available over I2P, and connect to
368    # another I2P peer. Please be aware that you
369    # must have an I2P router running on your system
370    # with the SAMv3 API enabled for this to work.
371  
372    [[I2P]]
373      type = I2PInterface
374      enabled = no
375      connectable = yes
376      peers = ykzlw5ujbaqc2xkec4cpvgyxj257wcrmmgkuxqmqcur7cq3w3lha.b32.i2p
377  
378  
379    # Here's an example of how to add a LoRa interface
380    # using the RNode LoRa transceiver.
381  
382    [[RNode LoRa Interface]]
383      type = RNodeInterface
384  
385      # Enable interface if you want use it!
386      enabled = no
387  
388      # Serial port for the device
389      port = /dev/ttyUSB0
390  
391      # It is also possible to use BLE devices
392      # instead of wired serial ports. The
393      # target RNode must be paired with the
394      # host device before connecting. BLE
395      # devices can be connected by name,
396      # BLE MAC address or by any available.
397      
398      # Connect to specific device by name
399      # port = ble://RNode 3B87
400  
401      # Or by BLE MAC address
402      # port = ble://F4:12:73:29:4E:89
403  
404      # Or connect to the first available,
405      # paired device
406      # port = ble://
407  
408      # Set frequency to 867.2 MHz
409      frequency = 867200000
410  
411      # Set LoRa bandwidth to 125 KHz
412      bandwidth = 125000
413  
414      # Set TX power to 7 dBm (5 mW)
415      txpower = 7
416  
417      # Select spreading factor 8. Valid 
418      # range is 7 through 12, with 7
419      # being the fastest and 12 having
420      # the longest range.
421      spreadingfactor = 8
422  
423      # Select coding rate 5. Valid range
424      # is 5 throough 8, with 5 being the
425      # fastest, and 8 the longest range.
426      codingrate = 5
427  
428      # You can configure the RNode to send
429      # out identification on the channel with
430      # a set interval by configuring the
431      # following two parameters. The trans-
432      # ceiver will only ID if the set
433      # interval has elapsed since it's last
434      # actual transmission. The interval is
435      # configured in seconds.
436      # This option is commented out and not
437      # used by default.
438      # id_callsign = MYCALL-0
439      # id_interval = 600
440  
441      # For certain homebrew RNode interfaces
442      # with low amounts of RAM, using packet
443      # flow control can be useful. By default
444      # it is disabled.
445      flow_control = False
446      
447      
448    # An example KISS modem interface. Useful for running
449    # Reticulum over packet radio hardware.
450  
451    [[Packet Radio KISS Interface]]
452      type = KISSInterface
453  
454      # Enable interface if you want use it!
455      enabled = no
456  
457      # Serial port for the device
458      port = /dev/ttyUSB1
459  
460      # Set the serial baud-rate and other
461      # configuration parameters.
462      speed = 115200    
463      databits = 8
464      parity = none
465      stopbits = 1
466  
467      # Set the modem preamble. A 150ms
468      # preamble should be a reasonable
469      # default, but may need to be
470      # increased for radios with slow-
471      # opening squelch and long TX/RX
472      # turnaround
473      preamble = 150
474  
475      # Set the modem TX tail. In most
476      # cases this should be kept as low
477      # as possible to not waste airtime.
478      txtail = 10
479  
480      # Configure CDMA parameters. These
481      # settings are reasonable defaults.
482      persistence = 200
483      slottime = 20
484  
485      # You can configure the interface to send
486      # out identification on the channel with
487      # a set interval by configuring the
488      # following two parameters. The KISS
489      # interface will only ID if the set
490      # interval has elapsed since it's last
491      # actual transmission. The interval is
492      # configured in seconds.
493      # This option is commented out and not
494      # used by default.
495      # id_callsign = MYCALL-0
496      # id_interval = 600
497  
498      # Whether to use KISS flow-control.
499      # This is useful for modems that have
500      # a small internal packet buffer, but
501      # support packet flow control instead.
502      flow_control = false
503  
504  
505    # If you're using Reticulum on amateur radio spectrum,
506    # you might want to use the AX.25 KISS interface. This
507    # way, Reticulum will automatically encapsulate it's
508    # traffic in AX.25 and also identify your stations
509    # transmissions with your callsign and SSID.
510    # 
511    # Only do this if you really need to! Reticulum doesn't
512    # need the AX.25 layer for anything, and it incurs extra
513    # overhead on every packet to encapsulate in AX.25.
514    #
515    # A more efficient way is to use the plain KISS interface
516    # with the beaconing functionality described above.
517  
518    [[Packet Radio AX.25 KISS Interface]]
519      type = AX25KISSInterface
520  
521      # Set the station callsign and SSID
522      callsign = NO1CLL
523      ssid = 0
524  
525      # Enable interface if you want use it!
526      enabled = no
527  
528      # Serial port for the device
529      port = /dev/ttyUSB2
530  
531      # Set the serial baud-rate and other
532      # configuration parameters.
533      speed = 115200    
534      databits = 8
535      parity = none
536      stopbits = 1
537  
538      # Whether to use KISS flow-control.
539      # This is useful for modems with a
540      # small internal packet buffer.
541      flow_control = false
542  
543      # Set the modem preamble. A 150ms
544      # preamble should be a reasonable
545      # default, but may need to be
546      # increased for radios with slow-
547      # opening squelch and long TX/RX
548      # turnaround
549      preamble = 150
550  
551      # Set the modem TX tail. In most
552      # cases this should be kept as low
553      # as possible to not waste airtime.
554      txtail = 10
555  
556      # Configure CDMA parameters. These
557      # settings are reasonable defaults.
558      persistence = 200
559      slottime = 20
560  
561  '''
562  
563  if __name__ == "__main__":
564      main()