Compare commits

...

59 Commits

Author SHA1 Message Date
Mark Qvist dcde5035b9 Updated docs 2021-09-25 23:22:33 +02:00
Mark Qvist c14f6aa14a Updated documentation 2021-09-25 21:39:31 +02:00
Mark Qvist 77fe621cba Updated readme 2021-09-25 17:37:35 +02:00
Mark Qvist 129b1d0713 Updated readme 2021-09-25 17:35:51 +02:00
Mark Qvist 161eeca509 Updated logging 2021-09-25 15:39:42 +02:00
Mark Qvist f25906d44e Improved path utility output 2021-09-25 11:27:43 +02:00
Mark Qvist dd5133751e Updated utilities 2021-09-25 11:03:43 +02:00
Mark Qvist 5f8a55b702 Updated readme 2021-09-24 20:32:48 +02:00
Mark Qvist 7991db5c74 Added rnstatus utility 2021-09-24 20:10:04 +02:00
Mark Qvist f5510f9777 Added verbosity options to rnsd 2021-09-24 20:05:24 +02:00
Mark Qvist 05e0b17fbf Improved rnprobe utility output. 2021-09-24 16:49:07 +02:00
Mark Qvist 7e9d608530 Improved shutdown handling for local shared instances 2021-09-24 16:42:31 +02:00
Mark Qvist 3d4ac0126b Added signal handler and interface detachment oon exit. 2021-09-24 16:09:07 +02:00
Mark Qvist 81cdb0b7e6 Updated version 2021-09-24 15:34:33 +02:00
Mark Qvist c71660a9c3 Added verbosity level to utilities 2021-09-24 15:34:03 +02:00
Mark Qvist 9c1ac46989 Added loglevel override 2021-09-24 15:18:06 +02:00
Mark Qvist c5b792f64a Added rnprobe utility 2021-09-24 14:20:12 +02:00
Mark Qvist 76d75e9a3e Updated rnpath utility 2021-09-24 14:16:25 +02:00
Mark Qvist 9edb641058 Updated utility name 2021-09-24 14:15:15 +02:00
Mark Qvist 1bc2d4015e Fixed bug in reverse table culling 2021-09-24 14:14:34 +02:00
Mark Qvist ab4f3ad8ae Updated logging and default config 2021-09-24 14:13:31 +02:00
Mark Qvist 16dae81844 Fixed regression in TCPInterface client spawner. 2021-09-24 14:11:04 +02:00
Mark Qvist e9e2ffbe0d Improved log output from local interfaces 2021-09-24 14:10:18 +02:00
Mark Qvist dc36644a1e Added rnpath utility 2021-09-24 12:42:24 +02:00
Mark Qvist 8436bc5ba3 Update rnsd utility description 2021-09-24 11:26:29 +02:00
Mark Qvist 858d54f90d Added utility entry points 2021-09-24 11:21:08 +02:00
Mark Qvist 9323fd22ee Improved TCP client interface recovery 2021-09-24 11:20:10 +02:00
Mark Qvist 544e15afdf Added rnsd utility 2021-09-24 11:17:23 +02:00
Mark Qvist acae9e34c2 Improved link status detection and recovery of TCP interfaces over unreliable IP links. 2021-09-23 16:07:57 +02:00
Mark Qvist aaf0ace027 Updated version 2021-09-18 23:32:08 +02:00
Mark Qvist d8b76b4bc5 Improved config parsing 2021-09-18 23:24:12 +02:00
Mark Qvist d29ff38a05 Updated documentation 2021-09-18 23:13:36 +02:00
Mark Qvist 65e8487b39 Added TCP client reconnection on TCP socket drop 2021-09-18 22:49:04 +02:00
Mark Qvist 6362e04567 Cleanup 2021-09-18 21:52:28 +02:00
Mark Qvist 711b754dcc Implemented tunnel saving/restoring. 2021-09-18 21:47:37 +02:00
Mark Qvist 1351316f17 Implemented endpoint tunneling and path restoration on intermittent link layer connections. 2021-09-18 20:38:23 +02:00
Mark Qvist 7af14cec84 Work on tunnels 2021-09-18 20:33:42 +02:00
Mark Qvist 0687ee2231 Work on tunnels 2021-09-18 20:31:43 +02:00
Mark Qvist 872075a31e Work on tunnels 2021-09-18 20:13:51 +02:00
Mark Qvist d8f0380aa9 Work on tunnels 2021-09-18 20:10:39 +02:00
Mark Qvist 569f9bd2b1 Work on tunnels 2021-09-18 19:46:28 +02:00
Mark Qvist 450b88d0f0 Work on tunnels 2021-09-18 19:14:30 +02:00
Mark Qvist 1cb9df109a Work on tunnels 2021-09-18 19:12:09 +02:00
Mark Qvist 80455c9614 Work on tunnels 2021-09-18 19:08:45 +02:00
Mark Qvist c1e280d896 Work on tunnels 2021-09-18 18:54:57 +02:00
Mark Qvist 4a2925cdea Work on tunnels 2021-09-18 18:54:01 +02:00
Mark Qvist 7f38c32e90 Work on tunnels 2021-09-18 18:40:49 +02:00
Mark Qvist 8646be0dcf Work on tunnels 2021-09-18 18:40:27 +02:00
Mark Qvist 6b3cc07740 Work on tunnels 2021-09-18 18:35:10 +02:00
Mark Qvist 3b57b0013b Work on tunnels 2021-09-18 18:34:00 +02:00
Mark Qvist 24d8f39dd1 Work on tunnels 2021-09-18 18:33:28 +02:00
Mark Qvist 58e4bf3c80 Work on tunnels 2021-09-18 18:32:12 +02:00
Mark Qvist 1da8a0c8f1 Work on tunnels 2021-09-18 18:26:50 +02:00
Mark Qvist 8b8d4410ef Work on tunnels 2021-09-18 18:21:32 +02:00
Mark Qvist 7d804daa8f Work on tunnels 2021-09-18 18:19:42 +02:00
Mark Qvist ce00822cb0 Work on tunnels 2021-09-18 18:11:23 +02:00
Mark Qvist 6d6c91edaf Updated docs 2021-09-18 18:10:58 +02:00
Mark Qvist 8432cf40c2 Updated documentation 2021-09-18 16:29:47 +02:00
Mark Qvist 5e21bdd233 Improved link teardown handling. 2021-09-16 20:40:37 +02:00
63 changed files with 3713 additions and 180 deletions
+15 -10
View File
@@ -3,7 +3,7 @@ Reticulum Network Stack β
Reticulum is a cryptography-based networking stack for wide-area networks built on readily available hardware, and can operate even with very high latency and extremely low bandwidth. Reticulum allows you to build very wide-area networks with off-the-shelf tools, and offers end-to-end encryption, autoconfiguring cryptographically backed multi-hop transport, efficient addressing, unforgeable packet acknowledgements and more.
Reticulum is a complete networking stack, and does not use IP or higher layers, although it is easy to utilise IP (with TCP or UDP) as the underlying carrier for Reticulum. It is therefore trivial to tunnel Reticulum over the Internet or private IP networks.
Reticulum is a complete networking stack, and does not need IP or higher layers, although it is easy to use IP (with TCP or UDP) as the underlying carrier for Reticulum. It is therefore trivial to tunnel Reticulum over the Internet or private IP networks.
Having no dependencies on traditional networking stacks free up overhead that has been utilised to implement a networking stack built directly on cryptographic principles, allowing resilience and stable functionality in open and trustless networks.
@@ -20,11 +20,11 @@ For more info, see [unsigned.io/projects/reticulum](https://unsigned.io/projects
- Fully self-configuring multi-hop routing
- Asymmetric X25519 encryption and Ed25519 signatures as a basis for all communication
- Forward Secrecy with ephemereal Elliptic Curve Diffie-Hellman keys on Curve25519
- Reticulum uses the [Fernet](https://github.com/fernet/spec/blob/master/Spec.md) specification for encryption
- Reticulum uses the [Fernet](https://github.com/fernet/spec/blob/master/Spec.md) specification for on-the-wire / over-the-air encryption
- Keys are ephemeral and derived from an ECDH key exchange on Curve25519
- AES-128 in CBC mode with PKCS7 padding
- HMAC using SHA256 for authentication
- IVs are generated through os.urandom()
- Keys are ephemeral and derived from an ECDH key exchange on Curve25519
- Unforgeable packet delivery confirmations
- A variety of supported interface types
- An intuitive and easy-to-use API
@@ -60,14 +60,19 @@ Reticulum implements a range of generalised interface types that covers most of
- TCP over IP networks
- UDP over IP networks
## What is currently being worked on?
- API documentation
- Useful example programs and utilities
- A delay and disruption tolerant message transfer protocol built on Reticulum, see [LXMF](https://github.com/markqvist/lxmf)
- A few useful-in-the-real-world apps built with Reticulum
## Can I use Reticulum on amateur radio spectrum?
Some countries still ban the use of encryption when operating under an amateur radio license. Reticulum offers several encryptionless modes, while still using cryptographic principles for station verification, link establishment, data integrity verification, acknowledgements and routing. It is therefore perfectly possible to include Reticulum in amateur radio use, even if your country bans encryption.
## Feature Roadmap
- More interface types for even broader compatibility
- ESP32 devices (ESP-Now, Bluetooth, etc.)
- AT-compatible modems
- CAN-bus
- ZeroMQ
- MQTT
- SPI
- i²c
- A delay and disruption tolerant message transfer protocol built on Reticulum, see [LXMF](https://github.com/markqvist/lxmf)
- A few useful-in-the-real-world apps built with Reticulum, see [Nomad Network](https://github.com/markqvist/NomadNet)
## Dependencies:
- Python 3
+11 -1
View File
@@ -48,6 +48,9 @@ class AX25KISSInterface(Interface):
serial = None
def __init__(self, owner, name, callsign, ssid, port, speed, databits, parity, stopbits, preamble, txtail, persistence, slottime, flow_control):
self.rxb = 0
self.txb = 0
self.serial = None
self.owner = owner
self.name = name
@@ -188,10 +191,12 @@ class AX25KISSInterface(Interface):
def processIncoming(self, data):
if (len(data) > AX25.HEADER_SIZE):
self.rxb += len(data)
self.owner.inbound(data[AX25.HEADER_SIZE:], self)
def processOutgoing(self,data):
datalen = len(data)
if self.online:
if self.interface_ready:
if self.flow_control:
@@ -224,6 +229,8 @@ class AX25KISSInterface(Interface):
kiss_frame = bytes([KISS.FEND])+bytes([0x00])+data+bytes([KISS.FEND])
written = self.serial.write(kiss_frame)
self.txb += datalen
if written != len(kiss_frame):
if self.flow_control:
self.interface_ready = True
@@ -301,7 +308,10 @@ class AX25KISSInterface(Interface):
except Exception as e:
self.online = False
RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR)
RNS.log("The interface "+str(self.name)+" is now offline. Restart Reticulum to attempt reconnection.", RNS.LOG_ERROR)
RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR)
if RNS.Reticulum.panic_on_interface_error:
RNS.panic()
def __str__(self):
return "AX25KISSInterface["+self.name+"]"
+7 -2
View File
@@ -8,7 +8,12 @@ class Interface:
name = None
def __init__(self):
pass
self.rxb = 0
self.txb = 0
self.online = False
def get_hash(self):
return RNS.Identity.full_hash(str(self).encode("utf-8"))
return RNS.Identity.full_hash(str(self).encode("utf-8"))
def detach(self):
pass
+10 -1
View File
@@ -40,6 +40,9 @@ class KISSInterface(Interface):
serial = None
def __init__(self, owner, name, port, speed, databits, parity, stopbits, preamble, txtail, persistence, slottime, flow_control, beacon_interval, beacon_data):
self.rxb = 0
self.txb = 0
if beacon_data == None:
beacon_data = ""
@@ -174,10 +177,12 @@ class KISSInterface(Interface):
def processIncoming(self, data):
self.rxb += len(data)
self.owner.inbound(data, self)
def processOutgoing(self,data):
datalen = len(data)
if self.online:
if self.interface_ready:
if self.flow_control:
@@ -189,6 +194,7 @@ class KISSInterface(Interface):
frame = bytes([KISS.FEND])+bytes([0x00])+data+bytes([KISS.FEND])
written = self.serial.write(frame)
self.txb += datalen
if data == self.beacon_d:
self.first_tx = None
@@ -277,7 +283,10 @@ class KISSInterface(Interface):
except Exception as e:
self.online = False
RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR)
RNS.log("The interface "+str(self.name)+" is now offline. Restart Reticulum to attempt reconnection.", RNS.LOG_ERROR)
RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR)
if RNS.Reticulum.panic_on_interface_error:
RNS.panic()
def __str__(self):
return "KISSInterface["+self.name+"]"
+63 -3
View File
@@ -24,6 +24,10 @@ class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
class LocalClientInterface(Interface):
def __init__(self, owner, name, target_port = None, connected_socket=None):
self.rxb = 0
self.txb = 0
self.online = False
self.IN = True
self.OUT = False
self.socket = None
@@ -36,6 +40,8 @@ class LocalClientInterface(Interface):
self.target_port = None
self.socket = connected_socket
self.is_connected_to_shared_instance = False
elif target_port != None:
self.receives = True
self.target_ip = "127.0.0.1"
@@ -56,6 +62,10 @@ class LocalClientInterface(Interface):
thread.start()
def processIncoming(self, data):
self.rxb += len(data)
if hasattr(self, "parent_interface") and self.parent_interface != None:
self.parent_interface.rxb += len(data)
self.owner.inbound(data, self)
def processOutgoing(self, data):
@@ -68,6 +78,10 @@ class LocalClientInterface(Interface):
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
self.socket.sendall(data)
self.writing = False
self.txb += len(data)
if hasattr(self, "parent_interface") and self.parent_interface != None:
self.parent_interface.txb += len(data)
except Exception as e:
RNS.log("Exception occurred while transmitting via "+str(self)+", tearing down interface", RNS.LOG_ERROR)
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
@@ -106,7 +120,7 @@ class LocalClientInterface(Interface):
data_buffer = data_buffer+bytes([byte])
else:
RNS.log("Socket for "+str(self)+" was closed, tearing down interface", RNS.LOG_VERBOSE)
self.teardown()
self.teardown(nowarning=True)
break
@@ -116,7 +130,26 @@ class LocalClientInterface(Interface):
RNS.log("Tearing down "+str(self), RNS.LOG_ERROR)
self.teardown()
def teardown(self):
def detach(self):
if self.socket != None:
if hasattr(self.socket, "close"):
if callable(self.socket.close):
RNS.log("Detaching "+str(self), RNS.LOG_DEBUG)
self.detached = True
try:
self.socket.shutdown(socket.SHUT_RDWR)
except Exception as e:
RNS.log("Error while shutting down socket for "+str(self)+": "+str(e))
try:
self.socket.close()
except Exception as e:
RNS.log("Error while closing socket for "+str(self)+": "+str(e))
self.socket = None
def teardown(self, nowarning=False):
self.online = False
self.OUT = False
self.IN = False
@@ -126,6 +159,22 @@ class LocalClientInterface(Interface):
if self in RNS.Transport.local_client_interfaces:
RNS.Transport.local_client_interfaces.remove(self)
if hasattr(self, "parent_interface") and self.parent_interface != None:
self.parent_interface.clients -= 1
if nowarning == False:
RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR)
if RNS.Reticulum.panic_on_interface_error:
RNS.panic()
if self.is_connected_to_shared_instance:
# TODO: Maybe add automatic recovery here.
# Needs thinking through, since user needs
# to now that all connectivity has been cut
# while service is recovering. Better for
# now to take down entire stack.
RNS.log("Lost connection to local shared RNS instance. Exiting now.", RNS.LOG_CRITICAL)
RNS.panic()
def __str__(self):
@@ -135,6 +184,11 @@ class LocalClientInterface(Interface):
class LocalServerInterface(Interface):
def __init__(self, owner, bindport=None):
self.rxb = 0
self.txb = 0
self.online = False
self.clients = 0
self.IN = True
self.OUT = False
self.name = "Reticulum"
@@ -153,12 +207,17 @@ class LocalServerInterface(Interface):
self.is_local_shared_instance = True
address = (self.bind_ip, self.bind_port)
ThreadingTCPServer.allow_reuse_address = True
self.server = ThreadingTCPServer(address, handlerFactory(self.incoming_connection))
thread = threading.Thread(target=self.server.serve_forever)
thread.setDaemon(True)
thread.start()
self.online = True
def incoming_connection(self, handler):
interface_name = str(str(handler.client_address[1]))
@@ -171,13 +230,14 @@ class LocalServerInterface(Interface):
RNS.log("Accepting new connection to shared instance: "+str(spawned_interface), RNS.LOG_VERBOSE)
RNS.Transport.interfaces.append(spawned_interface)
RNS.Transport.local_client_interfaces.append(spawned_interface)
self.clients += 1
spawned_interface.read_loop()
def processOutgoing(self, data):
pass
def __str__(self):
return "Shared Instance ["+str(self.bind_port)+"]"
return "Shared Instance["+str(self.bind_port)+"]"
class LocalInterfaceHandler(socketserver.BaseRequestHandler):
def __init__(self, callback, *args, **keys):
+11 -2
View File
@@ -72,6 +72,9 @@ class RNodeInterface(Interface):
CALLSIGN_MAX_LEN = 32
def __init__(self, owner, name, port, frequency = None, bandwidth = None, txpower = None, sf = None, cr = None, flow_control = False, id_interval = None, id_callsign = None):
self.rxb = 0
self.txb = 0
self.serial = None
self.owner = owner
self.name = name
@@ -273,15 +276,17 @@ class RNodeInterface(Interface):
try:
self.bitrate = self.r_sf * ( (4.0/self.r_cr) / (math.pow(2,self.r_sf)/(self.r_bandwidth/1000)) ) * 1000
self.bitrate_kbps = round(self.bitrate/1000.0, 2)
RNS.log(str(self)+" On-air bitrate is now "+str(self.bitrate_kbps)+ " kbps", RNS.LOG_INFO)
RNS.log(str(self)+" On-air bitrate is now "+str(self.bitrate_kbps)+ " kbps", RNS.LOG_VERBOSE)
except:
self.bitrate = 0
def processIncoming(self, data):
self.rxb += len(data)
self.owner.inbound(data, self)
def processOutgoing(self,data):
datalen = len(data)
if self.online:
if self.interface_ready:
if self.flow_control:
@@ -297,6 +302,7 @@ class RNodeInterface(Interface):
frame = bytes([0xc0])+bytes([0x00])+data+bytes([0xc0])
written = self.serial.write(frame)
self.txb += datalen
if written != len(frame):
raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data)))
@@ -463,7 +469,10 @@ class RNodeInterface(Interface):
except Exception as e:
self.online = False
RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR)
RNS.log("The interface "+str(self.name)+" is now offline. Restart Reticulum to attempt reconnection.", RNS.LOG_ERROR)
RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR)
if RNS.Reticulum.panic_on_interface_error:
RNS.panic()
def __str__(self):
return "RNodeInterface["+self.name+"]"
+9 -1
View File
@@ -31,6 +31,9 @@ class SerialInterface(Interface):
serial = None
def __init__(self, owner, name, port, speed, databits, parity, stopbits):
self.rxb = 0
self.txb = 0
self.serial = None
self.owner = owner
self.name = name
@@ -79,6 +82,7 @@ class SerialInterface(Interface):
def processIncoming(self, data):
self.rxb += len(data)
self.owner.inbound(data, self)
@@ -86,6 +90,7 @@ class SerialInterface(Interface):
if self.online:
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
written = self.serial.write(data)
self.txb += len(data)
if written != len(data):
raise IOError("Serial interface only wrote "+str(written)+" bytes of "+str(len(data)))
@@ -130,7 +135,10 @@ class SerialInterface(Interface):
except Exception as e:
self.online = False
RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR)
RNS.log("The interface "+str(self.name)+" is now offline. Restart Reticulum to attempt reconnection.", RNS.LOG_ERROR)
RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR)
if RNS.Reticulum.panic_on_interface_error:
RNS.panic()
def __str__(self):
return "SerialInterface["+self.name+"]"
+177 -11
View File
@@ -2,6 +2,7 @@ from .Interface import Interface
import socketserver
import threading
import netifaces
import platform
import socket
import time
import sys
@@ -23,13 +24,36 @@ class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
class TCPClientInterface(Interface):
RECONNECT_WAIT = 5
RECONNECT_MAX_TRIES = None
def __init__(self, owner, name, target_ip=None, target_port=None, connected_socket=None):
# TCP socket options
TCP_USER_TIMEOUT = 20
TCP_PROBE_AFTER = 5
TCP_PROBE_INTERVAL = 3
TCP_PROBES = 5
def __init__(self, owner, name, target_ip=None, target_port=None, connected_socket=None, max_reconnect_tries=None):
self.rxb = 0
self.txb = 0
self.IN = True
self.OUT = False
self.socket = None
self.parent_interface = None
self.name = name
self.initiator = False
self.reconnecting = False
self.never_connected = True
self.owner = owner
self.writing = False
self.online = False
self.detached = False
if max_reconnect_tries == None:
self.max_reconnect_tries = TCPClientInterface.RECONNECT_MAX_TRIES
else:
self.max_reconnect_tries = max_reconnect_tries
if connected_socket != None:
self.receives = True
@@ -37,24 +61,129 @@ class TCPClientInterface(Interface):
self.target_port = None
self.socket = connected_socket
if platform.system() == "Linux":
self.set_timeouts_linux()
elif platform.system() == "Darwin":
self.set_timeouts_osx()
elif target_ip != None and target_port != None:
self.receives = True
self.target_ip = target_ip
self.target_port = target_port
self.initiator = True
if not self.connect(initial=True):
thread = threading.Thread(target=self.reconnect)
thread.setDaemon(True)
thread.start()
else:
thread = threading.Thread(target=self.read_loop)
thread.setDaemon(True)
thread.start()
self.wants_tunnel = True
def set_timeouts_linux(self):
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_USER_TIMEOUT, int(TCPClientInterface.TCP_USER_TIMEOUT * 1000))
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, int(TCPClientInterface.TCP_PROBE_AFTER))
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, int(TCPClientInterface.TCP_PROBE_INTERVAL))
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, int(TCPClientInterface.TCP_PROBES))
def set_timeouts_osx(self):
if hasattr(socket, "TCP_KEEPALIVE"):
TCP_KEEPIDLE = socket.TCP_KEEPALIVE
else:
TCP_KEEPIDLE = 0x10
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
sock.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(TCPClientInterface.TCP_PROBE_AFTER))
def detach(self):
if self.socket != None:
if hasattr(self.socket, "close"):
if callable(self.socket.close):
RNS.log("Detaching "+str(self), RNS.LOG_DEBUG)
self.detached = True
try:
self.socket.shutdown(socket.SHUT_RDWR)
except Exception as e:
RNS.log("Error while shutting down socket for "+str(self)+": "+str(e))
try:
self.socket.close()
except Exception as e:
RNS.log("Error while closing socket for "+str(self)+": "+str(e))
self.socket = None
def connect(self, initial=False):
try:
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((self.target_ip, self.target_port))
self.online = True
except Exception as e:
if initial:
RNS.log("Initial connection for "+str(self)+" could not be established: "+str(e), RNS.LOG_ERROR)
RNS.log("Leaving unconnected and retrying connection in "+str(TCPClientInterface.RECONNECT_WAIT)+" seconds.", RNS.LOG_ERROR)
return False
else:
raise e
self.owner = owner
if platform.system() == "Linux":
self.set_timeouts_linux()
elif platform.system() == "Darwin":
self.set_timeouts_osx()
self.online = True
self.writing = False
self.never_connected = False
if connected_socket == None:
thread = threading.Thread(target=self.read_loop)
thread.setDaemon(True)
thread.start()
return True
def reconnect(self):
if self.initiator:
if not self.reconnecting:
self.reconnecting = True
attempts = 0
while not self.online:
time.sleep(TCPClientInterface.RECONNECT_WAIT)
attempts += 1
if self.max_reconnect_tries != None and attempts > self.max_reconnect_tries:
RNS.log("Max reconnection attempts reached for "+str(self), RNS.LOG_ERROR)
self.teardown()
break
try:
self.connect()
except Exception as e:
RNS.log("Connection attempt for "+str(self)+" failed: "+str(e), RNS.LOG_DEBUG)
if not self.never_connected:
RNS.log("Reconnected TCP socket for "+str(self)+".", RNS.LOG_INFO)
self.reconnecting = False
thread = threading.Thread(target=self.read_loop)
thread.setDaemon(True)
thread.start()
RNS.Transport.synthesize_tunnel(self)
else:
RNS.log("Attempt to reconnect on a non-initiator TCP interface. This should not happen.", RNS.LOG_ERROR)
raise IOError("Attempt to reconnect on a non-initiator TCP interface")
def processIncoming(self, data):
self.rxb += len(data)
if hasattr(self, "parent_interface") and self.parent_interface != None:
self.parent_interface.rxb += len(data)
self.owner.inbound(data, self)
def processOutgoing(self, data):
@@ -67,6 +196,10 @@ class TCPClientInterface(Interface):
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
self.socket.sendall(data)
self.writing = False
self.txb += len(data)
if hasattr(self, "parent_interface") and self.parent_interface != None:
self.parent_interface.txb += len(data)
except Exception as e:
RNS.log("Exception occurred while transmitting via "+str(self)+", tearing down interface", RNS.LOG_ERROR)
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
@@ -104,21 +237,43 @@ class TCPClientInterface(Interface):
escape = False
data_buffer = data_buffer+bytes([byte])
else:
RNS.log("TCP socket for "+str(self)+" was closed, tearing down interface", RNS.LOG_VERBOSE)
self.teardown()
self.online = False
if self.initiator and not self.detached:
RNS.log("TCP socket for "+str(self)+" was closed, attempting to reconnect...", RNS.LOG_WARNING)
self.reconnect()
else:
RNS.log("TCP socket for remote client "+str(self)+" was closed.", RNS.LOG_VERBOSE)
self.teardown()
break
except Exception as e:
self.online = False
RNS.log("An interface error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR)
RNS.log("Tearing down "+str(self), RNS.LOG_ERROR)
self.teardown()
RNS.log("An interface error occurred for "+str(self)+", the contained exception was: "+str(e), RNS.LOG_WARNING)
if self.initiator:
RNS.log("Attempting to reconnect...", RNS.LOG_WARNING)
self.reconnect()
else:
self.teardown()
def teardown(self):
if self.initiator and not self.detached:
RNS.log("The interface "+str(self)+" experienced an unrecoverable error and is being torn down. Restart Reticulum to attempt to open this interface again.", RNS.LOG_ERROR)
if RNS.Reticulum.panic_on_interface_error:
RNS.panic()
else:
RNS.log("The interface "+str(self)+" is being torn down.", RNS.LOG_VERBOSE)
self.online = False
self.OUT = False
self.IN = False
if hasattr(self, "parent_interface") and self.parent_interface != None:
self.parent_interface.clients -= 1
if self in RNS.Transport.interfaces:
RNS.Transport.interfaces.remove(self)
@@ -136,6 +291,11 @@ class TCPServerInterface(Interface):
return netifaces.ifaddresses(name)[netifaces.AF_INET][0]['broadcast']
def __init__(self, owner, name, device=None, bindip=None, bindport=None):
self.rxb = 0
self.txb = 0
self.online = False
self.clients = 0
self.IN = True
self.OUT = False
self.name = name
@@ -155,12 +315,16 @@ class TCPServerInterface(Interface):
self.owner = owner
address = (self.bind_ip, self.bind_port)
ThreadingTCPServer.allow_reuse_address = True
self.server = ThreadingTCPServer(address, handlerFactory(self.incoming_connection))
thread = threading.Thread(target=self.server.serve_forever)
thread.setDaemon(True)
thread.start()
self.online = True
def incoming_connection(self, handler):
RNS.log("Accepting incoming TCP connection", RNS.LOG_VERBOSE)
@@ -171,8 +335,10 @@ class TCPServerInterface(Interface):
spawned_interface.target_ip = handler.client_address[0]
spawned_interface.target_port = str(handler.client_address[1])
spawned_interface.parent_interface = self
spawned_interface.online = True
RNS.log("Spawned new TCPClient Interface: "+str(spawned_interface), RNS.LOG_VERBOSE)
RNS.Transport.interfaces.append(spawned_interface)
self.clients += 1
spawned_interface.read_loop()
def processOutgoing(self, data):
+14 -3
View File
@@ -18,9 +18,12 @@ class UDPInterface(Interface):
return netifaces.ifaddresses(name)[netifaces.AF_INET][0]['broadcast']
def __init__(self, owner, name, device=None, bindip=None, bindport=None, forwardip=None, forwardport=None):
self.rxb = 0
self.txb = 0
self.IN = True
self.OUT = False
self.name = name
self.online = False
if device != None:
if bindip == None:
@@ -47,6 +50,8 @@ class UDPInterface(Interface):
thread.setDaemon(True)
thread.start()
self.online = True
if (forwardip != None and forwardport != None):
self.forwards = True
self.forward_ip = forwardip
@@ -54,12 +59,18 @@ class UDPInterface(Interface):
def processIncoming(self, data):
self.rxb += len(data)
self.owner.inbound(data, self)
def processOutgoing(self,data):
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
udp_socket.sendto(data, (self.forward_ip, self.forward_port))
try:
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
udp_socket.sendto(data, (self.forward_ip, self.forward_port))
self.txb += len(data)
except Exception as e:
RNS.log("Could not transmit on "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
def __str__(self):
+5
View File
@@ -419,6 +419,11 @@ class Link:
self.shared_key = None
self.derived_key = None
if self.destination != None:
if self.destination.direction == RNS.Destination.IN:
if self in self.destination.links:
self.destination.links.remove(self)
if self.callbacks.link_closed != None:
self.callbacks.link_closed(self)
+129 -13
View File
@@ -1,7 +1,10 @@
from .Interfaces import *
import configparser
from .vendor.configobj import ConfigObj
import configparser
import multiprocessing.connection
import RNS
import signal
import threading
import atexit
import struct
import array
@@ -78,7 +81,13 @@ class Reticulum:
RNS.Transport.exit_handler()
RNS.Identity.exit_handler()
def __init__(self,configdir=None):
@staticmethod
def sigint_handler(signal, frame):
RNS.Transport.detach_interfaces()
RNS.exit()
def __init__(self,configdir=None, loglevel=None):
"""
Initialises and starts a Reticulum instance. This must be
done before any other operations, and Reticulum will not
@@ -98,8 +107,21 @@ class Reticulum:
Reticulum.__transport_enabled = False
Reticulum.__use_implicit_proof = True
Reticulum.panic_on_interface_error = False
self.local_interface_port = 37428
self.share_instance = True
self.local_control_port = 37429
self.share_instance = True
self.rpc_listener = None
self.requested_loglevel = loglevel
if self.requested_loglevel != None:
if self.requested_loglevel > RNS.LOG_EXTREME:
self.requested_loglevel = RNS.LOG_EXTREME
if self.requested_loglevel < RNS.LOG_CRITICAL:
self.requested_loglevel = RNS.LOG_CRITICAL
RNS.loglevel = self.requested_loglevel
self.is_shared_instance = False
self.is_connected_to_shared_instance = False
@@ -117,7 +139,6 @@ class Reticulum:
if os.path.isfile(self.configpath):
try:
self.config = ConfigObj(self.configpath)
RNS.log("Configuration loaded from "+self.configpath)
except Exception as e:
RNS.log("Could not parse the configuration at "+self.configpath, RNS.LOG_ERROR)
RNS.log("Check your configuration file for errors!", RNS.LOG_ERROR)
@@ -130,11 +151,23 @@ class Reticulum:
exit(1)
self.__apply_config()
RNS.log("Configuration loaded from "+self.configpath, RNS.LOG_VERBOSE)
RNS.Identity.load_known_destinations()
RNS.Transport.start(self)
self.rpc_addr = ("127.0.0.1", self.local_control_port)
self.rpc_key = RNS.Identity.full_hash(RNS.Transport.identity.get_private_key())
if self.is_shared_instance:
self.rpc_listener = multiprocessing.connection.Listener(self.rpc_addr, authkey=self.rpc_key)
thread = threading.Thread(target=self.rpc_loop)
thread.setDaemon(True)
thread.start()
atexit.register(Reticulum.exit_handler)
signal.signal(signal.SIGINT, Reticulum.sigint_handler)
def __start_local_interface(self):
if self.share_instance:
@@ -145,6 +178,7 @@ class Reticulum:
)
interface.OUT = True
RNS.Transport.interfaces.append(interface)
self.is_shared_instance = True
RNS.log("Started shared instance interface: "+str(interface), RNS.LOG_DEBUG)
except Exception as e:
@@ -175,7 +209,7 @@ class Reticulum:
if "logging" in self.config:
for option in self.config["logging"]:
value = self.config["logging"][option]
if option == "loglevel":
if option == "loglevel" and self.requested_loglevel == None:
RNS.loglevel = int(value)
if RNS.loglevel < 0:
RNS.loglevel = 0
@@ -191,10 +225,17 @@ class Reticulum:
if option == "shared_instance_port":
value = int(self.config["reticulum"][option])
self.local_interface_port = value
if option == "instance_control_port":
value = int(self.config["reticulum"][option])
self.local_control_port = value
if option == "enable_transport":
v = self.config["reticulum"].as_bool(option)
if v == True:
Reticulum.__transport_enabled = True
if option == "panic_on_interface_error":
v = self.config["reticulum"].as_bool(option)
if v == True:
Reticulum.panic_on_interface_error = True
if option == "use_implicit_proof":
v = self.config["reticulum"].as_bool(option)
if v == True:
@@ -305,7 +346,7 @@ class Reticulum:
stopbits
)
if "outgoing" in c and c["outgoing"].lower() == "true":
if "outgoing" in c and c.as_bool("outgoing") == True:
interface.OUT = True
else:
interface.OUT = False
@@ -346,7 +387,7 @@ class Reticulum:
beacon_data
)
if "outgoing" in c and c["outgoing"].lower() == "true":
if "outgoing" in c and c.as_bool("outgoing") == True:
interface.OUT = True
else:
interface.OUT = False
@@ -388,7 +429,7 @@ class Reticulum:
flow_control
)
if "outgoing" in c and c["outgoing"].lower() == "true":
if "outgoing" in c and c.as_bool("outgoing") == True:
interface.OUT = True
else:
interface.OUT = False
@@ -424,14 +465,14 @@ class Reticulum:
id_callsign = id_callsign
)
if "outgoing" in c and c["outgoing"].lower() == "true":
if "outgoing" in c and c.as_bool("outgoing") == True:
interface.OUT = True
else:
interface.OUT = False
RNS.Transport.interfaces.append(interface)
else:
RNS.log("Skipping disabled interface \""+name+"\"", RNS.LOG_NOTICE)
RNS.log("Skipping disabled interface \""+name+"\"", RNS.LOG_INFO)
except Exception as e:
RNS.log("The interface \""+name+"\" could not be created. Check your configuration file for errors!", RNS.LOG_ERROR)
@@ -451,6 +492,71 @@ class Reticulum:
self.config.write()
self.__apply_config()
def rpc_loop(self):
while True:
try:
rpc_connection = self.rpc_listener.accept()
call = rpc_connection.recv()
if "get" in call:
path = call["get"]
if path == "interface_stats":
rpc_connection.send(self.get_interface_stats())
if path == "next_hop_if_name":
rpc_connection.send(self.get_next_hop_if_name(call["destination_hash"]))
if path == "next_hop":
rpc_connection.send(self.get_next_hop(call["destination_hash"]))
rpc_connection.close()
except Exception as e:
RNS.log("An error ocurred while handling RPC call from local client: "+str(e), RNS.LOG_ERROR)
def get_interface_stats(self):
if self.is_connected_to_shared_instance:
rpc_connection = multiprocessing.connection.Client(self.rpc_addr, authkey=self.rpc_key)
rpc_connection.send({"get": "interface_stats"})
response = rpc_connection.recv()
return response
else:
stats = []
for interface in RNS.Transport.interfaces:
ifstats = {}
if hasattr(interface, "clients"):
ifstats["clients"] = interface.clients
else:
ifstats["clients"] = None
ifstats["name"] = str(interface)
ifstats["rxb"] = interface.rxb
ifstats["txb"] = interface.txb
ifstats["status"] = interface.online
stats.append(ifstats)
return stats
def get_next_hop_if_name(self, destination):
if self.is_connected_to_shared_instance:
rpc_connection = multiprocessing.connection.Client(self.rpc_addr, authkey=self.rpc_key)
rpc_connection.send({"get": "next_hop_if_name", "destination_hash": destination})
response = rpc_connection.recv()
return response
else:
return str(RNS.Transport.next_hop_interface(destination))
def get_next_hop(self, destination):
if self.is_connected_to_shared_instance:
rpc_connection = multiprocessing.connection.Client(self.rpc_addr, authkey=self.rpc_key)
rpc_connection.send({"get": "next_hop", "destination_hash": destination})
response = rpc_connection.recv()
return response
else:
return RNS.Transport.next_hop(destination)
@staticmethod
def should_use_implicit_proof():
"""
@@ -504,11 +610,21 @@ share_instance = Yes
# If you want to run multiple *different* shared instances
# on the same system, you will need to specify a different
# shared instance port for each. The default is given below,
# and again, this option is optional and can be left out.
# on the same system, you will need to specify different
# shared instance ports for each. The defaults are given
# below, and again, these options can be left out if you
# don't need them.
shared_instance_port = 37428
instance_control_port = 37429
# You can configure Reticulum to panic and forcibly close
# if an unrecoverable interface error occurs, such as the
# hardware device for an interface disappearing. This is
# an optional directive, and can be left out for brevity.
# This behaviour is disabled by default.
panic_on_interface_error = No
[logging]
+337 -31
View File
@@ -10,8 +10,8 @@ from .vendor import umsgpack as umsgpack
class Transport:
"""
Through static methods of this class you can interact with Reticulums
Transport system.
Through static methods of this class you can interact with the
Transport system of Reticulum.
"""
# Constants
BROADCAST = 0x00;
@@ -30,40 +30,41 @@ class Transport:
"""
Maximum amount of hops that Reticulum will transport a packet.
"""
PATHFINDER_C = 2.0 # Decay constant
PATHFINDER_R = 1 # Retransmit retries
PATHFINDER_T = 10 # Retry grace period
PATHFINDER_RW = 10 # Random window for announce rebroadcast
PATHFINDER_E = 60*15 # Path expiration in seconds
PATHFINDER_C = 2.0 # Decay constant
PATHFINDER_R = 1 # Retransmit retries
PATHFINDER_T = 10 # Retry grace period
PATHFINDER_RW = 10 # Random window for announce rebroadcast
PATHFINDER_E = 60*60*24*7 # Path expiration in seconds
# TODO: Calculate an optimal number for this in
# various situations
LOCAL_REBROADCASTS_MAX = 2 # How many local rebroadcasts of an announce is allowed
LOCAL_REBROADCASTS_MAX = 2 # How many local rebroadcasts of an announce is allowed
PATH_REQUEST_GRACE = 0.35 # Grace time before a path announcement is made, allows directly reachable peers to respond first
PATH_REQUEST_RW = 2 # Path request random window
PATH_REQUEST_GRACE = 0.35 # Grace time before a path announcement is made, allows directly reachable peers to respond first
PATH_REQUEST_RW = 2 # Path request random window
LINK_TIMEOUT = RNS.Link.KEEPALIVE * 2
REVERSE_TIMEOUT = 30*60 # Reverse table entries are removed after max 30 minutes
DESTINATION_TIMEOUT = 60*60*24*7 # Destination table entries are removed if unused for one week
MAX_RECEIPTS = 1024 # Maximum number of receipts to keep track of
REVERSE_TIMEOUT = 30*60 # Reverse table entries are removed after max 30 minutes
DESTINATION_TIMEOUT = PATHFINDER_E # Destination table entries are removed if unused for one week
MAX_RECEIPTS = 1024 # Maximum number of receipts to keep track of
interfaces = [] # All active interfaces
destinations = [] # All active destinations
pending_links = [] # Links that are being established
active_links = [] # Links that are active
packet_hashlist = [] # A list of packet hashes for duplicate detection
receipts = [] # Receipts of all outgoing packets for proof processing
interfaces = [] # All active interfaces
destinations = [] # All active destinations
pending_links = [] # Links that are being established
active_links = [] # Links that are active
packet_hashlist = [] # A list of packet hashes for duplicate detection
receipts = [] # Receipts of all outgoing packets for proof processing
# TODO: "destination_table" should really be renamed to "path_table"
# Notes on memory usage: 1 megabyte of memory can store approximately
# 55.100 path table entries or approximately 22.300 link table entries.
announce_table = {} # A table for storing announces currently waiting to be retransmitted
destination_table = {} # A lookup table containing the next hop to a given destination
reverse_table = {} # A lookup table for storing packet hashes used to return proofs and replies
link_table = {} # A lookup table containing hops for links
held_announces = {} # A table containing temporarily held announce-table entries
announce_handlers = [] # A table storing externally registered announce handlers
announce_table = {} # A table for storing announces currently waiting to be retransmitted
destination_table = {} # A lookup table containing the next hop to a given destination
reverse_table = {} # A lookup table for storing packet hashes used to return proofs and replies
link_table = {} # A lookup table containing hops for links
held_announces = {} # A table containing temporarily held announce-table entries
announce_handlers = [] # A table storing externally registered announce handlers
tunnels = {} # A table storing tunnels to other transport instances
# Transport control destinations are used
# for control purposes like path requests
@@ -119,12 +120,19 @@ class Transport:
Transport.control_destinations.append(Transport.path_request_destination)
Transport.control_hashes.append(Transport.path_request_destination.hash)
Transport.tunnel_synthesize_destination = RNS.Destination(None, RNS.Destination.IN, RNS.Destination.PLAIN, Transport.APP_NAME, "tunnel", "synthesize")
Transport.tunnel_synthesize_destination.set_packet_callback(Transport.tunnel_synthesize_handler)
Transport.control_destinations.append(Transport.tunnel_synthesize_handler)
Transport.control_hashes.append(Transport.tunnel_synthesize_destination.hash)
thread = threading.Thread(target=Transport.jobloop)
thread.setDaemon(True)
thread.start()
if RNS.Reticulum.transport_enabled():
destination_table_path = RNS.Reticulum.storagepath+"/destination_table"
tunnel_table_path = RNS.Reticulum.storagepath+"/tunnels"
if os.path.isfile(destination_table_path) and not Transport.owner.is_connected_to_shared_instance:
serialised_destinations = []
try:
@@ -168,7 +176,63 @@ class Transport:
except Exception as e:
RNS.log("Could not load destination table from storage, the contained exception was: "+str(e), RNS.LOG_ERROR)
RNS.log("Transport instance "+str(Transport.identity)+" started")
if os.path.isfile(tunnel_table_path) and not Transport.owner.is_connected_to_shared_instance:
serialised_tunnels = []
try:
file = open(tunnel_table_path, "rb")
serialised_tunnels = umsgpack.unpackb(file.read())
file.close()
for serialised_tunnel in serialised_tunnels:
tunnel_id = serialised_tunnel[0]
interface_hash = serialised_tunnel[1]
serialised_paths = serialised_tunnel[2]
expires = serialised_tunnel[3]
tunnel_paths = {}
for serialised_entry in serialised_paths:
destination_hash = serialised_entry[0]
timestamp = serialised_entry[1]
received_from = serialised_entry[2]
hops = serialised_entry[3]
expires = serialised_entry[4]
random_blobs = serialised_entry[5]
receiving_interface = Transport.find_interface_from_hash(serialised_entry[6])
announce_packet = Transport.get_cached_packet(serialised_entry[7])
if announce_packet != None:
announce_packet.unpack()
# We increase the hops, since reading a packet
# from cache is equivalent to receiving it again
# over an interface. It is cached with it's non-
# increased hop-count.
announce_packet.hops += 1
tunnel_path = [timestamp, received_from, hops, expires, random_blobs, receiving_interface, announce_packet]
tunnel_paths[destination_hash] = tunnel_path
tunnel = [tunnel_id, None, tunnel_paths, expires]
Transport.tunnels[tunnel_id] = tunnel
if len(Transport.destination_table) == 1:
specifier = "entry"
else:
specifier = "entries"
RNS.log("Loaded "+str(len(Transport.tunnels))+" tunnel table "+specifier+" from storage", RNS.LOG_VERBOSE)
except Exception as e:
RNS.log("Could not load tunnel table from storage, the contained exception was: "+str(e), RNS.LOG_ERROR)
RNS.log("Transport instance "+str(Transport.identity)+" started", RNS.LOG_VERBOSE)
# Synthesize tunnels for any interfaces wanting it
for interface in Transport.interfaces:
interface.tunnel_id = None
if hasattr(interface, "wants_tunnel") and interface.wants_tunnel:
Transport.synthesize_tunnel(interface)
@staticmethod
def jobloop():
@@ -258,10 +322,11 @@ class Transport:
if time.time() > Transport.tables_last_culled + Transport.tables_cull_interval:
# Cull the reverse table according to timeout
stale_reverse_entries = []
for truncated_packet_hash in Transport.reverse_table:
reverse_entry = Transport.reverse_table[truncated_packet_hash]
if time.time() > reverse_entry[2] + Transport.REVERSE_TIMEOUT:
Transport.reverse_table.pop(truncated_packet_hash)
stale_reverse_entries.append(truncated_packet_hash)
# Cull the link table according to timeout
stale_links = []
@@ -279,11 +344,56 @@ class Transport:
if time.time() > destination_entry[0] + Transport.DESTINATION_TIMEOUT:
stale_paths.append(destination_hash)
RNS.log("Path to "+RNS.prettyhexrep(destination_hash)+" timed out and was removed", RNS.LOG_DEBUG)
if not attached_interface in Transport.interfaces:
elif not attached_interface in Transport.interfaces:
stale_paths.append(destination_hash)
RNS.log("Path to "+RNS.prettyhexrep(destination_hash)+" was removed since the attached interface no longer exists", RNS.LOG_DEBUG)
# Cull the tunnel table
stale_tunnels = []
ti = 0
for tunnel_id in Transport.tunnels:
tunnel_entry = Transport.tunnels[tunnel_id]
expires = tunnel_entry[3]
if time.time() > expires:
stale_tunnels.append(tunnel_id)
RNS.log("Tunnel "+RNS.prettyhexrep(tunnel_id)+" timed out and was removed", RNS.LOG_DEBUG)
else:
stale_tunnel_paths = []
tunnel_paths = tunnel_entry[2]
for tunnel_path in tunnel_paths:
tunnel_path_entry = tunnel_paths[tunnel_path]
if time.time() > tunnel_path_entry[0] + Transport.DESTINATION_TIMEOUT:
stale_tunnel_paths.append(tunnel_path)
RNS.log("Tunnel path to "+RNS.prettyhexrep(tunnel_path)+" timed out and was removed", RNS.LOG_DEBUG)
for tunnel_path in stale_tunnel_paths:
tunnel_paths.pop(tunnel_path)
ti += 1
if ti > 0:
if ti == 1:
RNS.log("Removed "+str(ti)+" tunnel path", RNS.LOG_DEBUG)
else:
RNS.log("Removed "+str(ti)+" tunnel paths", RNS.LOG_DEBUG)
i = 0
for truncated_packet_hash in stale_reverse_entries:
Transport.reverse_table.pop(truncated_packet_hash)
i += 1
if i > 0:
if i == 1:
RNS.log("Dropped "+str(i)+" reverse table entry", RNS.LOG_DEBUG)
else:
RNS.log("Dropped "+str(i)+" reverse table entries", RNS.LOG_DEBUG)
i = 0
for link_id in stale_links:
Transport.link_table.pop(link_id)
@@ -306,6 +416,17 @@ class Transport:
else:
RNS.log("Removed "+str(i)+" paths", RNS.LOG_DEBUG)
i = 0
for tunnel_id in stale_tunnels:
Transport.tunnels.pop(tunnel_id)
i += 1
if i > 0:
if i == 1:
RNS.log("Removed "+str(i)+" tunnel", RNS.LOG_DEBUG)
else:
RNS.log("Removed "+str(i)+" tunnels", RNS.LOG_DEBUG)
Transport.tables_last_culled = time.time()
except Exception as e:
@@ -395,6 +516,7 @@ class Transport:
if should_transmit:
if not stored_hash:
Transport.packet_hashlist.append(packet.packet_hash)
stored_hash = True
interface.processOutgoing(packet.raw)
sent = True
@@ -768,10 +890,20 @@ class Transport:
new_announce.hops = packet.hops
new_announce.send()
Transport.destination_table[packet.destination_hash] = [now, received_from, announce_hops, expires, random_blobs, packet.receiving_interface, packet]
destination_table_entry = [now, received_from, announce_hops, expires, random_blobs, packet.receiving_interface, packet]
Transport.destination_table[packet.destination_hash] = destination_table_entry
RNS.log("Path to "+RNS.prettyhexrep(packet.destination_hash)+" is now "+str(announce_hops)+" hops away via "+RNS.prettyhexrep(received_from)+" on "+str(packet.receiving_interface), RNS.LOG_VERBOSE)
# If the receiving interface is a tunnel, we add the
# announce to the tunnels table
if hasattr(packet.receiving_interface, "tunnel_id") and packet.receiving_interface.tunnel_id != None:
tunnel_entry = Transport.tunnels[packet.receiving_interface.tunnel_id]
paths = tunnel_entry[2]
paths[packet.destination_hash] = destination_table_entry
expires = time.time() + Transport.DESTINATION_TIMEOUT
tunnel_entry[3] = expires
RNS.log("Path to "+RNS.prettyhexrep(packet.destination_hash)+" associated with tunnel "+RNS.prettyhexrep(packet.receiving_interface.tunnel_id), RNS.LOG_VERBOSE)
# Call externally registered callbacks from apps
# wanting to know when an announce arrives
for handler in Transport.announce_handlers:
@@ -898,6 +1030,97 @@ class Transport:
Transport.jobs_locked = False
@staticmethod
def synthesize_tunnel(interface):
interface_hash = interface.get_hash()
public_key = RNS.Transport.identity.get_public_key()
random_hash = RNS.Identity.get_random_hash()
tunnel_id_data = public_key+interface_hash
tunnel_id = RNS.Identity.full_hash(tunnel_id_data)
signed_data = tunnel_id_data+random_hash
signature = Transport.identity.sign(signed_data)
data = signed_data+signature
tnl_snth_dst = RNS.Destination(None, RNS.Destination.OUT, RNS.Destination.PLAIN, Transport.APP_NAME, "tunnel", "synthesize")
packet = RNS.Packet(tnl_snth_dst, data, packet_type = RNS.Packet.DATA, transport_type = RNS.Transport.BROADCAST, header_type = RNS.Packet.HEADER_1, attached_interface = interface)
packet.send()
interface.wants_tunnel = False
@staticmethod
def tunnel_synthesize_handler(data, packet):
try:
expected_length = RNS.Identity.KEYSIZE//8+RNS.Identity.HASHLENGTH//8+RNS.Reticulum.TRUNCATED_HASHLENGTH//8+RNS.Identity.SIGLENGTH//8
if len(data) == expected_length:
public_key = data[:RNS.Identity.KEYSIZE//8]
interface_hash = data[RNS.Identity.KEYSIZE//8:RNS.Identity.KEYSIZE//8+RNS.Identity.HASHLENGTH//8]
tunnel_id_data = public_key+interface_hash
tunnel_id = RNS.Identity.full_hash(tunnel_id_data)
random_hash = data[RNS.Identity.KEYSIZE//8+RNS.Identity.HASHLENGTH//8:RNS.Identity.KEYSIZE//8+RNS.Identity.HASHLENGTH//8+RNS.Reticulum.TRUNCATED_HASHLENGTH//8]
signature = data[RNS.Identity.KEYSIZE//8+RNS.Identity.HASHLENGTH//8+RNS.Reticulum.TRUNCATED_HASHLENGTH//8:expected_length]
signed_data = tunnel_id_data+random_hash
remote_transport_identity = RNS.Identity(create_keys=False)
remote_transport_identity.load_public_key(public_key)
if remote_transport_identity.validate(signature, signed_data):
Transport.handle_tunnel(tunnel_id, packet.receiving_interface)
except Exception as e:
RNS.log("An error occurred while validating tunnel establishment packet.", RNS.LOG_DEBUG)
RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG)
@staticmethod
def handle_tunnel(tunnel_id, interface):
expires = time.time() + Transport.DESTINATION_TIMEOUT
if not tunnel_id in Transport.tunnels:
RNS.log("Tunnel endpoint "+RNS.prettyhexrep(tunnel_id)+" established.", RNS.LOG_DEBUG)
paths = {}
tunnel_entry = [tunnel_id, interface, paths, expires]
interface.tunnel_id = tunnel_id
Transport.tunnels[tunnel_id] = tunnel_entry
else:
RNS.log("Tunnel endpoint "+RNS.prettyhexrep(tunnel_id)+" reappeared. Restoring paths...", RNS.LOG_DEBUG)
tunnel_entry = Transport.tunnels[tunnel_id]
tunnel_entry[1] = interface
tunnel_entry[3] = expires
interface.tunnel_id = tunnel_id
paths = tunnel_entry[2]
for destination_hash, path_entry in paths.items():
received_from = path_entry[1]
announce_hops = path_entry[2]
expires = path_entry[3]
random_blobs = path_entry[4]
receiving_interface = interface
packet = path_entry[6]
new_entry = [time.time(), received_from, announce_hops, expires, random_blobs, receiving_interface, packet]
should_add = False
if destination_hash in Transport.destination_table:
old_entry = Transport.destination_table[destination_hash]
old_hops = old_entry[2]
old_expires = old_entry[3]
if announce_hops <= old_hops or time.time() > old_expires:
should_add = True
else:
RNS.log("Did not restore path to "+RNS.prettyhexrep(packet.destination_hash)+" because a newer path with fewer hops exist", RNS.LOG_DEBUG)
else:
should_add = True
if should_add:
Transport.destination_table[destination_hash] = new_entry
RNS.log("Restored path to "+RNS.prettyhexrep(packet.destination_hash)+" is now "+str(announce_hops)+" hops away via "+RNS.prettyhexrep(received_from)+" on "+str(receiving_interface), RNS.LOG_DEBUG)
@staticmethod
def register_destination(destination):
destination.MTU = RNS.Reticulum.MTU
@@ -1069,6 +1292,28 @@ class Transport:
else:
return Transport.PATHFINDER_M
@staticmethod
def next_hop(destination_hash):
"""
:param destination_hash: A destination hash as *bytes*.
:returns: The destination hash as *bytes* for the next hop to the specified destination, or *None* if the next hop is unknown.
"""
if destination_hash in Transport.destination_table:
return Transport.destination_table[destination_hash][1]
else:
return None
@staticmethod
def next_hop_interface(destination_hash):
"""
:param destination_hash: A destination hash as *bytes*.
:returns: The interface for the next hop to the specified destination, or *None* if the interface is unknown.
"""
if destination_hash in Transport.destination_table:
return Transport.destination_table[destination_hash][5]
else:
return None
@staticmethod
def request_path(destination_hash):
"""
@@ -1177,6 +1422,15 @@ class Transport:
else:
return False
@staticmethod
def detach_interfaces():
for interface in Transport.interfaces:
interface.detach()
for interface in Transport.local_client_interfaces:
interface.detach()
@staticmethod
def exit_handler():
try:
@@ -1237,3 +1491,55 @@ class Transport:
RNS.log("Done saving "+str(len(serialised_destinations))+" path table entries to storage", RNS.LOG_VERBOSE)
except Exception as e:
RNS.log("Could not save path table to storage, the contained exception was: "+str(e), RNS.LOG_ERROR)
RNS.log("Saving tunnel table to storage...", RNS.LOG_VERBOSE)
try:
serialised_tunnels = []
for tunnel_id in Transport.tunnels:
te = Transport.tunnels[tunnel_id]
interface = te[1]
tunnel_paths = te[2]
expires = te[3]
if interface != None:
interface_hash = interface.get_hash()
else:
interface_hash = None
serialised_paths = []
for destination_hash in tunnel_paths:
de = tunnel_paths[destination_hash]
timestamp = de[0]
received_from = de[1]
hops = de[2]
expires = de[3]
random_blobs = de[4]
packet_hash = de[6].get_hash()
serialised_entry = [
destination_hash,
timestamp,
received_from,
hops,
expires,
random_blobs,
interface_hash,
packet_hash
]
serialised_paths.append(serialised_entry)
Transport.cache(de[6], force_cache=True)
serialised_tunnel = [tunnel_id, interface_hash, serialised_paths, expires]
serialised_tunnels.append(serialised_tunnel)
tunnels_path = RNS.Reticulum.storagepath+"/tunnels"
file = open(tunnels_path, "wb")
file.write(umsgpack.packb(serialised_tunnels))
file.close()
RNS.log("Done saving "+str(len(serialised_tunnels))+" tunnel table entries to storage", RNS.LOG_VERBOSE)
except Exception as e:
RNS.log("Could not save tunnel table to storage, the contained exception was: "+str(e), RNS.LOG_ERROR)
+5
View File
@@ -0,0 +1,5 @@
import os
import glob
modules = glob.glob(os.path.dirname(__file__)+"/*.py")
__all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')]
+97
View File
@@ -0,0 +1,97 @@
#!/usr/bin/env python3
import RNS
import sys
import time
import argparse
from RNS._version import __version__
def program_setup(configdir, destination_hexhash, verbosity):
try:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len:
raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2))
try:
destination_hash = bytes.fromhex(destination_hexhash)
except Exception as e:
raise ValueError("Invalid destination entered. Check your input.")
except Exception as e:
print(str(e))
exit()
reticulum = RNS.Reticulum(configdir = configdir, loglevel = 3+verbosity)
if not RNS.Transport.has_path(destination_hash):
RNS.Transport.request_path(destination_hash)
print("Path to "+RNS.prettyhexrep(destination_hash)+" requested ", end=" ")
sys.stdout.flush()
i = 0
syms = "⢄⢂⢁⡁⡈⡐⡠"
while not RNS.Transport.has_path(destination_hash):
time.sleep(0.1)
print(("\b\b"+syms[i]+" "), end="")
sys.stdout.flush()
i = (i+1)%len(syms)
hops = RNS.Transport.hops_to(destination_hash)
next_hop = RNS.prettyhexrep(reticulum.get_next_hop(destination_hash))
next_hop_interface = reticulum.get_next_hop_if_name(destination_hash)
if hops != 1:
ms = "s"
else:
ms = ""
print("\rPath found, destination "+RNS.prettyhexrep(destination_hash)+" is "+str(hops)+" hop"+ms+" away via "+next_hop+" on "+next_hop_interface)
def main():
try:
parser = argparse.ArgumentParser(description="Reticulum Path Discovery Utility")
parser.add_argument("--config",
action="store",
default=None,
help="path to alternative Reticulum config directory",
type=str
)
parser.add_argument(
"--version",
action="version",
version="rnpath {version}".format(version=__version__)
)
parser.add_argument(
"destination",
nargs="?",
default=None,
help="hexadecimal hash of the destination",
type=str
)
parser.add_argument('-v', '--verbose', action='count', default=0)
args = parser.parse_args()
if args.config:
configarg = args.config
else:
configarg = None
if not args.destination:
print("")
parser.print_help()
print("")
else:
program_setup(configdir = configarg, destination_hexhash = args.destination, verbosity = args.verbose)
except KeyboardInterrupt:
print("")
exit()
if __name__ == "__main__":
main()
+172
View File
@@ -0,0 +1,172 @@
#!/usr/bin/env python3
import RNS
import os
import sys
import time
import argparse
from RNS._version import __version__
DEFAULT_PROBE_SIZE = 16
def program_setup(configdir, destination_hexhash, size=DEFAULT_PROBE_SIZE, full_name = None, verbosity = 0):
if full_name == None:
print("The full destination name including application name aspects must be specified for the destination")
exit()
try:
app_name, aspects = RNS.Destination.app_and_aspects_from_name(full_name)
except Exception as e:
print(str(e))
exit()
try:
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
if len(destination_hexhash) != dest_len:
raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2))
try:
destination_hash = bytes.fromhex(destination_hexhash)
except Exception as e:
raise ValueError("Invalid destination entered. Check your input.")
except Exception as e:
print(str(e))
exit()
if verbosity > 0:
more_output = True
verbosity -= 1
else:
more_output = False
verbosity -= 1
reticulum = RNS.Reticulum(configdir = configdir, loglevel = 3+verbosity)
if not RNS.Transport.has_path(destination_hash):
RNS.Transport.request_path(destination_hash)
print("Path to "+RNS.prettyhexrep(destination_hash)+" requested ", end=" ")
sys.stdout.flush()
i = 0
syms = "⢄⢂⢁⡁⡈⡐⡠"
while not RNS.Transport.has_path(destination_hash):
time.sleep(0.1)
print(("\b\b"+syms[i]+" "), end="")
sys.stdout.flush()
i = (i+1)%len(syms)
server_identity = RNS.Identity.recall(destination_hash)
request_destination = RNS.Destination(
server_identity,
RNS.Destination.OUT,
RNS.Destination.SINGLE,
app_name,
*aspects
)
probe = RNS.Packet(request_destination, os.urandom(size))
receipt = probe.send()
if more_output:
more = " via "+RNS.prettyhexrep(reticulum.get_next_hop(destination_hash))+" on "+str(reticulum.get_next_hop_if_name(destination_hash))
else:
more = ""
print("\rSent "+str(size)+" byte probe to "+RNS.prettyhexrep(destination_hash)+more+" ", end=" ")
i = 0
while not receipt.status == RNS.PacketReceipt.DELIVERED:
time.sleep(0.1)
print(("\b\b"+syms[i]+" "), end="")
sys.stdout.flush()
i = (i+1)%len(syms)
print("\b\b ")
sys.stdout.flush()
hops = RNS.Transport.hops_to(destination_hash)
if hops != 1:
ms = "s"
else:
ms = ""
rtt = receipt.get_rtt()
if (rtt >= 1):
rtt = round(rtt, 3)
rttstring = str(rtt)+" seconds"
else:
rtt = round(rtt*1000, 3)
rttstring = str(rtt)+" milliseconds"
print(
"Valid reply received from "+
RNS.prettyhexrep(receipt.destination.hash)+
"\nRound-trip time is "+rttstring+
" over "+str(hops)+" hop"+ms
)
def main():
try:
parser = argparse.ArgumentParser(description="Reticulum Probe Utility")
parser.add_argument("--config",
action="store",
default=None,
help="path to alternative Reticulum config directory",
type=str
)
parser.add_argument(
"--version",
action="version",
version="rnprobe {version}".format(version=__version__)
)
parser.add_argument(
"full_name",
nargs="?",
default=None,
help="full destination name in dotted notation",
type=str
)
parser.add_argument(
"destination_hash",
nargs="?",
default=None,
help="hexadecimal hash of the destination",
type=str
)
parser.add_argument('-v', '--verbose', action='count', default=0)
args = parser.parse_args()
if args.config:
configarg = args.config
else:
configarg = None
if not args.destination_hash:
print("")
parser.print_help()
print("")
else:
program_setup(
configdir = configarg,
destination_hexhash = args.destination_hash,
full_name = args.full_name,
verbosity = args.verbose
)
except KeyboardInterrupt:
print("")
exit()
if __name__ == "__main__":
main()
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env python3
import RNS
import argparse
from RNS._version import __version__
def program_setup(configdir, verbosity = 0, quietness = 0):
reticulum = RNS.Reticulum(configdir = configdir, loglevel = 3+verbosity-quietness)
RNS.log("Started rnsd version {version}".format(version=__version__), RNS.LOG_NOTICE)
while True:
input()
def main():
try:
parser = argparse.ArgumentParser(description="Reticulum Network Stack Daemon")
parser.add_argument("--config", action="store", default=None, help="path to alternative Reticulum config directory", type=str)
parser.add_argument('-v', '--verbose', action='count', default=0)
parser.add_argument('-q', '--quiet', action='count', default=0)
parser.add_argument("--version", action="version", version="rnsd {version}".format(version=__version__))
args = parser.parse_args()
if args.config:
configarg = args.config
else:
configarg = None
program_setup(configdir = configarg, verbosity=args.verbose, quietness=args.quiet)
except KeyboardInterrupt:
print("")
exit()
if __name__ == "__main__":
main()
+91
View File
@@ -0,0 +1,91 @@
#!/usr/bin/env python3
import RNS
import argparse
from RNS._version import __version__
def size_str(num, suffix='B'):
units = ['','K','M','G','T','P','E','Z']
last_unit = 'Y'
if suffix == 'b':
num *= 8
units = ['','K','M','G','T','P','E','Z']
last_unit = 'Y'
for unit in units:
if abs(num) < 1000.0:
if unit == "":
return "%.0f %s%s" % (num, unit, suffix)
else:
return "%.2f %s%s" % (num, unit, suffix)
num /= 1000.0
return "%.2f%s%s" % (num, last_unit, suffix)
def program_setup(configdir, dispall=False, verbosity = 0):
reticulum = RNS.Reticulum(configdir = configdir, loglevel = 3+verbosity)
ifstats = reticulum.get_interface_stats()
if ifstats != None:
for ifstat in ifstats:
name = ifstat["name"]
print("")
if dispall or not (name.startswith("LocalInterface[") or name.startswith("TCPInterface[Client")):
if ifstat["status"]:
ss = "Up"
else:
ss = "Down"
if ifstat["clients"] != None:
clients = ifstat["clients"]
if name.startswith("Shared Instance["):
clients_string = "Connected applications: "+str(clients-1)
else:
clients_string = "Connected clients: "+str(clients)
else:
clients = None
print(" {n}".format(n=ifstat["name"]))
print("\tStatus: {ss}".format(ss=ss))
if clients != None:
print("\t"+clients_string)
print("\tRX: {rxb}\n\tTX: {txb}".format(rxb=size_str(ifstat["rxb"]), txb=size_str(ifstat["txb"])))
else:
print("Could not get RNS status")
def main():
try:
parser = argparse.ArgumentParser(description="Reticulum Network Stack Status")
parser.add_argument("--config", action="store", default=None, help="path to alternative Reticulum config directory", type=str)
parser.add_argument("--version", action="version", version="rnstatus {version}".format(version=__version__))
parser.add_argument(
"-a",
"--all",
action="store_true",
help="show all interfaces",
default=False
)
parser.add_argument('-v', '--verbose', action='count', default=0)
args = parser.parse_args()
if args.config:
configarg = args.config
else:
configarg = None
program_setup(configdir = configarg, dispall = args.all, verbosity=args.verbose)
except KeyboardInterrupt:
print("")
exit()
if __name__ == "__main__":
main()
+4 -1
View File
@@ -108,4 +108,7 @@ def prettyhexrep(data):
return hexrep
def panic():
os._exit(255)
os._exit(255)
def exit():
sys.exit(0)
+1 -1
View File
@@ -1 +1 @@
__version__ = "0.2.4"
__version__ = "0.2.6"
-2
View File
@@ -1,7 +1,5 @@
import os
import glob
__version__ = "0.1.9"
modules = glob.glob(os.path.dirname(__file__)+"/*.py")
__all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')]
Binary file not shown.
+1 -1
View File
@@ -1,4 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: eda3a1317314f558917722e3479f8836
config: bf2e68cefd79a49afe077549bac593bf
tags: 645f666f9bcd5a90fca523b33c5a78b7
Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

+4 -3
View File
@@ -1,8 +1,9 @@
.. _examples-main:
********
Examples
********
*************
Code Examples
*************
A number of examples are included in the source distribution of Reticulum.
You can use these examples to learn how to write your own programs.
@@ -12,13 +12,46 @@ If you simply want to try using a program built with Reticulum, you can take
a look at `Nomad Network <https://github.com/markqvist/nomadnet>`_, which
provides a basic encrypted communications suite built completely on Reticulum.
.. image:: screenshots/nomadnet3.png
:target: _images/nomadnet3.png
.. image:: screenshots/nomadnet_3.png
:target: _images/nomadnet_3.png
`Nomad Network <https://github.com/markqvist/nomadnet>`_ is a user-facing client
in the development for the messaging and information-sharing protocol
`LXMF <https://github.com/markqvist/lxmf>`_, another project built with Reticulum.
You can install Nomad Network via pip:
.. code::
# Install ...
pip3 install nomadnet
# ... and run
nomadnet
Creating a Network With Reticulum
=============================================
To create a network, you will need to specify one or more *interfaces* for
Reticulum to use. This is done in the Reticulum configuration file, which by
default is located at ``~/.reticulum/config``.
When Reticulum is started for the first time, it will create a default
configuration file, with one active interface. This default interface uses
your existing ethernet network (if there is one), and only allows you to
communicate with other Reticulum peers within your local broadcast domain.
To communicate further, you will have to add one or more interfaces. The default
configuration includes a number of examples, ranging from using TCP over the
internet, to LoRa and Packet Radio interfaces.
Possibly, the examples in the config file are enough to get you started. If
you want more information, you can read the :ref:`Building Networks<networks-main>`
and :ref:`Interfaces<interfaces-main>` chapters of this manual.
Develop a Program with Reticulum
===========================================
If you want to develop programs that use Reticulum, the easiest way to get
@@ -44,7 +77,7 @@ don't use pip, but try this recipe:
.. code::
# Install dependencies
pip3 install cryptography pyserial
pip3 install cryptography pyserial netifaces
# Clone repository
git clone https://github.com/markqvist/Reticulum.git
+5 -2
View File
@@ -2,14 +2,17 @@
Reticulum Network Stack Manual
******************************
This manual aims to provide you with all the information you need to
understand Reticulum, develop programs using it, or to participate in
the development of Reticulum itself.
understand Reticulum, build networks or develop programs using it, or
to participate in the development of Reticulum itself.
.. toctree::
:maxdepth: 3
whatis
gettingstartedfast
using
networks
interfaces
understanding
reference
examples
+342
View File
@@ -0,0 +1,342 @@
.. _interfaces-main:
********************
Supported Interfaces
********************
Reticulum supports using many kinds of devices as networking interfaces, and
allows you to mix and match them in any way you choose. The number of distinct
network topologies you can create with Reticulum is more or less endless, but
common to them all is that you will need to define one or more *interfaces*
for Reticulum to use.
The following sections describe the interfaces currently available in Reticulum,
and gives example configurations for the respective interface types.
.. _interfaces-udp:
UDP Interface
=============
A UDP interface can be useful for communicating over IP networks, both
private and the internet. It can also allow broadcast communication
over IP networks, so it can provide an easy way to enable connectivity
with all other peers on a local area network.
The below example is enabled by default on new Reticulum installations,
as it provides an easy way to get started and to test Reticulum on a
pre-existing LAN.
.. code::
# This example enables communication with other
# local Reticulum peers over UDP.
[[Default UDP Interface]]
type = UDPInterface
interface_enabled = True
outgoing = True
listen_ip = 0.0.0.0
listen_port = 4242
forward_ip = 255.255.255.255
forward_port = 4242
# The above configuration will allow communication
# within the local broadcast domains of all local
# IP interfaces. This is enabled by default as an
# easy way to get started, but you might want to
# consider altering it to something more specific.
# Instead of specifying listen_ip, listen_port,
# forward_ip and forward_port, you can also bind
# to a specific network device like below.
# device = eth0
# port = 4242
# Assuming the eth0 device has the address
# 10.55.0.72/24, the above configuration would
# be equivalent to the following manual setup.
# Note that we are both listening and forwarding to
# the broadcast address of the network segments.
# listen_ip = 10.55.0.255
# listen_port = 4242
# forward_ip = 10.55.0.255
# forward_port = 4242
# You can of course also communicate only with
# a single IP address
# listen_ip = 10.55.0.15
# listen_port = 4242
# forward_ip = 10.55.0.16
# forward_port = 4242
.. _interfaces-tcps:
TCP Server Interface
====================
The TCP Server interface is suitable for allowing other peers to connect over
the Internet or private IP networks. When a TCP server interface has been
configured, other Reticulum peers can connect to it with a TCP Client interface.
.. code::
# This example demonstrates a TCP server interface.
# It will listen for incoming connections on the
# specified IP address and port number.
[[TCP Server Interface]]
type = TCPServerInterface
interface_enabled = True
outgoing = True
# This configuration will listen on all IP
# interfaces on port 4242
listen_ip = 0.0.0.0
listen_port = 4242
# Alternatively you can bind to a specific IP
# listen_ip = 10.0.0.88
# listen_port = 4242
# Or a specific network device
# device = eth0
# port = 4242
.. _interfaces-tcpc:
TCP Client Interface
====================
To connect to a TCP server interface, you would naturally use the TCP client
interface. Many TCP Client interfaces from different peers can connect to the
same TCP Server interface at the same time.
.. code::
# Here's an example of a TCP Client interface. The
# target_host can either be an IP address or a hostname.
[[TCP Client Interface]]
type = TCPClientInterface
interface_enabled = True
outgoing = True
target_host = 127.0.0.1
target_port = 4242
.. _interfaces-rnode:
RNode LoRa Interface
====================
To use Reticulum over LoRa, the `RNode <https://unsigned.io/rnode/>`_ interface
can be used, and offers full control over LoRa parameters.
.. code::
# Here's an example of how to add a LoRa interface
# using the RNode LoRa transceiver.
[[RNode LoRa Interface]]
type = RNodeInterface
# Enable interface if you want use it!
interface_enabled = True
# Allow transmit on interface. Setting
# this to false will create a listen-
# only interface.
outgoing = true
# Serial port for the device
port = /dev/ttyUSB0
# Set frequency to 867.2 MHz
frequency = 867200000
# Set LoRa bandwidth to 125 KHz
bandwidth = 125000
# Set TX power to 7 dBm (5 mW)
txpower = 7
# Select spreading factor 8. Valid
# range is 7 through 12, with 7
# being the fastest and 12 having
# the longest range.
spreadingfactor = 8
# Select coding rate 5. Valid range
# is 5 throough 8, with 5 being the
# fastest, and 8 the longest range.
codingrate = 5
# You can configure the RNode to send
# out identification on the channel with
# a set interval by configuring the
# following two parameters.
# id_callsign = MYCALL-0
# id_interval = 600
# For certain homebrew RNode interfaces
# with low amounts of RAM, using packet
# flow control can be useful. By default
# it is disabled.
flow_control = False
.. _interfaces-serial:
Serial Interface
================
Reticulum can be used over serial ports directly, or over any device with a
serial port, that will transparently pass data. Useful for communicating
directly over a wire-pair, or for using devices such as data radios and lasers.
.. code::
[[Serial Interface]]
type = SerialInterface
interface_enabled = True
outgoing = True
# Serial port for the device
port = /dev/ttyUSB0
# Set the serial baud-rate and other
# configuration parameters.
speed = 115200
databits = 8
parity = none
stopbits = 1
.. _interfaces-kiss:
KISS Interface
==============
With the KISS interface, you can use Reticulum over a variety of packet
radio modems and TNCs, including `OpenModem <https://unsigned.io/openmodem/>`_.
KISS interfaces can also be configured to periodically send out beacons
for station identification purposes.
.. code::
[[Packet Radio KISS Interface]]
type = KISSInterface
interface_enabled = True
outgoing = true
# Serial port for the device
port = /dev/ttyUSB1
# Set the serial baud-rate and other
# configuration parameters.
speed = 115200
databits = 8
parity = none
stopbits = 1
# Set the modem preamble.
preamble = 150
# Set the modem TX tail.
txtail = 10
# Configure CDMA parameters. These
# settings are reasonable defaults.
persistence = 200
slottime = 20
# You can configure the interface to send
# out identification on the channel with
# a set interval by configuring the
# following two parameters. The KISS
# interface will only ID if the set
# interval has elapsed since it's last
# actual transmission. The interval is
# configured in seconds.
# This option is commented out and not
# used by default.
# id_callsign = MYCALL-0
# id_interval = 600
# Whether to use KISS flow-control.
# This is useful for modems that have
# a small internal packet buffer, but
# support packet flow control instead.
flow_control = false
.. _interfaces-ax25:
AX.25 KISS Interface
====================
If you're using Reticulum on amateur radio spectrum, you might want to
use the AX.25 KISS interface. This way, Reticulum will automatically
encapsulate it's traffic in AX.25 and also identify your stations
transmissions with your callsign and SSID.
Only do this if you really need to! Reticulum doesn't need the AX.25
layer for anything, and it incurs extra overhead on every packet to
encapsulate in AX.25.
A more efficient way is to use the plain KISS interface with the
beaconing functionality described above.
.. code::
[[Packet Radio AX.25 KISS Interface]]
type = AX25KISSInterface
# Set the station callsign and SSID
callsign = NO1CLL
ssid = 0
# Enable interface if you want use it!
interface_enabled = True
# Allow transmit on interface.
outgoing = True
# Serial port for the device
port = /dev/ttyUSB2
# Set the serial baud-rate and other
# configuration parameters.
speed = 115200
databits = 8
parity = none
stopbits = 1
# Set the modem preamble. A 150ms
# preamble should be a reasonable
# default, but may need to be
# increased for radios with slow-
# opening squelch and long TX/RX
# turnaround
preamble = 150
# Set the modem TX tail. In most
# cases this should be kept as low
# as possible to not waste airtime.
txtail = 10
# Configure CDMA parameters. These
# settings are reasonable defaults.
persistence = 200
slottime = 20
# Whether to use KISS flow-control.
# This is useful for modems with a
# small internal packet buffer.
flow_control = false
+149
View File
@@ -0,0 +1,149 @@
.. _networks-main:
*****************
Building Networks
*****************
This chapter will provide you with the knowledge needed to build networks with
Reticulum, which can often be easier than using traditional stacks, since you
don't have to worry about coordinating addresses, subnets and routing for an
entire network that you might not know how will evolve in the future. With
Reticulum, you can simply add more segments to your network when it becomes
necesarry, and Reticulum will handle the convergence of the entire network
automatically.
Concepts & Overview
--------------------
There are important points that need to be kept in mind when building networks
with Reticulum:
* | In a Reticulum network, any node can autonomously generate as many adresses
(called *destinations* in Reticulum terminology) as it needs, which become
globally reachable to the rest of the network. There is no central point of
control over the adress space.
* | Reticulum was designed to handle both very small, and very large networks.
While the adress space can support billions of endpoints, Reticulum is
also very useful when just a few devices needs to communicate.
* | Reticulum provides sender/initiator anonymity by default. There is no way
to filter traffic or discriminate it based on the source of the traffic.
* | All traffic is encrypted using ephemeral keys generated by an Elliptic Curve
Diffie-Hellman key exchange on Curve25519. There is no way to inspect traffic
contents, and no way to prioritise or throttle certain kinds of traffic.
All transport and routing layers are thus completely agnostic to traffic type,
and will pass all traffic equally.
* | Reticulum can function both with and without infrastructure. When *transport
nodes* are available, they can route traffic over multiple hops for other
nodes, and will function as a distributed cryptographic keystore. When there
is no transport nodes available, all nodes that are within communication range
can still communicate.
* | Every node can become a transport node, simply by enabling it in it's
configuration, but there is no need for every node on the network to be a
transport node. Letting every node be a transport node will in most cases
degrade the performance and reliability of the network.
In general terms, if a node is stationary, well-connected and kept running
most of the time, it is a good candidate to be a transport node. For optimal
performance, a network should contain the amount of transport nodes that
provides connectivity to the intended area / topography, and not many more
than that.
Reticulum allows you to mix very different kinds of networking mediums into a
unified mesh, or to keep everything within one medium. You could build a "virtual
network" running entirely over the Internet, where all nodes communicate over TCP
and UDP "channels". You could also build such a network using MQTT or ZeroMQ as
the underlying carrier for Reticulum.
However, most real-world networks will probably involve either some form of
wireless or direct hardline communications. To allow Reticulum to communicate
over any type of medium, you must specify it in the configuration file, by default
located at ``~/.reticulum/config``.
Any number of interfaces can be configured, and Reticulum will automatically
decide which are suitable to use in any given situation, depending on where
traffic needs to flow.
Example Scenarios
-----------------
This section illustrates a few example scenarios, and how they would, in general
terms, be planned, implemented and configured.
Interconnected LoRa Sites
=========================
An organisation wants to provide communication and information services to it's
members, which are located mainly in three separate areas. Three suitable hill-top
locations are found, where the organisation can install equipment: Site A, B and C.
Since the amount of data that needs to be exchanged between users is mainly text-
based, the bandwidth requirements are low, and LoRa radios are chosen to connect
users to the network.
Due to the hill-top locations found, there is radio line-of-sight between site A
and B, and also between site B and C. Because of this, the organisation does not
need to use the Internet to interconnect the sites, but purchases four Point-to-Point
WiFi based radios for interconnecting the sites.
At each site, a Raspberry Pi is installed to function as a gateway. A LoRa radio
is connected to the Pi with a USB cable, and the WiFi radio is connected to the
ethernet port of the Pi. At site B, two WiFi radios are needed to be able to reach
both site A and site C, so an extra ethernet adapter is connected to the Pi in
this location.
Once the hardware has been installed, Reticulum is installed on all the Pis, and at
site A and C, one interface is added for the LoRa radio, as well as one for the WiFi
radio. At site B, an interface for the LoRa radio, and one interface for each WiFi
radio is added to the Reticulum configuration file. The transport node option is
enabled in the configuration of all three gateways.
The network is now operational, and ready to serve users across all three areas.
The organisation prepares a LoRa radio that is supplied to the end users, along
with a Reticulum configuration file, that contains the right parameters for
communicating with the LoRa radios installed at the gateway sites.
Once users connect to the network, anyone will be able to communicate with anyone
else across all three sites.
Bridging Over the Internet
==========================
As the organisation grows, several new communities form in places too far away
from the core network to be reachable over WiFi links. New gateways similar to those
previously installed are set up for the new communities at the new sites D and E, but
they are islanded from the core network, and only serve the local users.
After investigating the options, it is found that it is possible to install an
Internet connection at site A, and an interface on the Internet connection is
configured for Reticulum on the Raspberry Pi at site A.
A member of the organisation at site D, named Dori, is willing to help by sharing
the Internet connection she already has in her home, and is able to leave a Raspberry
Pi running. A new Reticulum interface is configured on her Pi, connecting to the newly
enabled Internet interface on the gateway at site A. Dori is now connected to both
all the nodes at her own local site (through the hill-top LoRa gateway), and all the
combined users of sites A, B and C. She then enables transport on her node, and
traffic from site D can now reach everyone at site A, B and C, and vice versa.
Growth and Convergence
======================
As the organisation grows, more gateways are added to keep up with the growing user
base. Some local gateways even add VHF radios and packet modems to reach outlying users
and communities that are out of reach for the LoRa radios and WiFi backhauls.
As more sites, gateways and users are connected, the amount of coordination required
is kept to a minimum. If one community wants to add connectivity to the next one
over, it can simply be done without having to involve everyone or coordinate address
space or routing tables.
With the added geographical coverage, the operators at site A one day find that
the original internet bridged interfaces are no longer utilised. The network has
converged to be completely self-connected, and the sites that were once poorly
connected outliers are now an integral part of the network.
+1 -1
View File
@@ -52,7 +52,7 @@ by using multiple hops).
Goals
=====
To be as widely usable and easy to implement as possible, the following goals have been used to
To be as widely usable and easy to use as possible, the following goals have been used to
guide the design of Reticulum:
+165
View File
@@ -0,0 +1,165 @@
.. _using-main:
******************************
Using Reticulum on Your System
******************************
Reticulum is not installed as a driver or kernel module, as one might expect
of a networking stack. Instead, Reticulum is distributed as a Python module.
This means that no special privileges are required to install or use it.
Any program or application that uses Reticulum will automatically load and
initialise Reticulum when it starts.
In many cases, this approach is sufficient. When any program needs to use
Reticulum, it is loaded, initialised, interfaces are brought up, and the
program can now communicate over Reticulum. If another program starts up
and also wants access to the same Reticulum network, the instance is simply
shared. This works for any number of programs running concurrently, and is
very easy to use, but depending on your use case, there are other options.
Included Utility Programs
-------------------------
If you often use Reticulum from several different programs, or simply want
Reticulum to stay available all the time, for example if you are hosting
a transport node, you might want to run Reticulum as a separate service that
other programs, applications and services can utilise.
The rnsd Utility
================
To do so is very easy. Simply run the included ``rnsd`` command. When ``rnsd``
is running, it will keep all configured interfaces open, handle transport if
it is enabled, and allow any other programs to immediately utilise the
Reticulum network it is configured for.
You can even run multiple instances of rnsd with different configurations on
the same system.
.. code:: text
# Install Reticulum
pip3 install rns
# Run rnsd
rnsd
.. code:: text
usage: rnsd [-h] [--config CONFIG] [-v] [-q] [--version]
Reticulum Network Stack Daemon
optional arguments:
-h, --help show this help message and exit
--config CONFIG path to alternative Reticulum config directory
-v, --verbose
-q, --quiet
--version show program's version number and exit
The rnstatus Utility
====================
Using the ``rnstatus`` utility, you can view the status of configured Reticulum
interfaces, similar to the ``ifconfig`` program.
.. code:: text
# Run rnstatus
rnstatus
# Example output
Shared Instance[37428]
Status: Up
Connected applications: 1
RX: 1.13 KB
TX: 1.07 KB
UDPInterface[Default UDP Interface/0.0.0.0:4242]
Status: Up
RX: 1.01 KB
TX: 1.01 KB
TCPInterface[RNS Testnet Frankfurt/frankfurt.rns.unsigned.io:4965]
Status: Up
RX: 1.37 KB
TX: 9.02 KB
.. code:: text
usage: rnsd [-h] [--config CONFIG] [-v] [-q] [--version]
Reticulum Network Stack Daemon
optional arguments:
-h, --help show this help message and exit
--config CONFIG path to alternative Reticulum config directory
-v, --verbose
-q, --quiet
--version show program's version number and exit
The rnpath Utility
====================
With the ``rnpath`` utility, you can look up and view paths for
destinations on the Reticulum network.
.. code:: text
# Run rnpath
rnpath eca6f4e4dc26ae329e61
# Example output
Path found, destination <eca6f4e4dc26ae329e61> is 4 hops away via <56b115c30cd386cad69c> on TCPInterface[Testnet/frankfurt.rns.unsigned.io:4965]
.. code:: text
usage: rnpath.py [-h] [--config CONFIG] [--version] [-v] [destination]
Reticulum Path Discovery Utility
positional arguments:
destination hexadecimal hash of the destination
optional arguments:
-h, --help show this help message and exit
--config CONFIG path to alternative Reticulum config directory
--version show program's version number and exit
-v, --verbose
The rnprobe Utility
====================
The ``rnprobe`` utility lets you probe a destination for connectivity, similar
to the ``ping`` program. Please note that probes will only be answered if the
specified destination is configured to send proofs for received packets. Many
destinations will not have this option enabled, and will not be probable.
.. code:: text
# Run rnprobe
python3 -m RNS.Utilities.rnprobe example_utilities.echo.request 9382f334de63217a4278
# Example output
Sent 16 byte probe to <9382f334de63217a4278>
Valid reply received from <9382f334de63217a4278>
Round-trip time is 38.469 milliseconds over 2 hops
.. code:: text
usage: rnprobe.py [-h] [--config CONFIG] [--version] [-v] [full_name] [destination_hash]
Reticulum Probe Utility
positional arguments:
full_name full destination name in dotted notation
destination_hash hexadecimal hash of the destination
optional arguments:
-h, --help show this help message and exit
--config CONFIG path to alternative Reticulum config directory
--version show program's version number and exit
-v, --verbose
+11 -9
View File
@@ -6,9 +6,9 @@ Reticulum is a cryptography-based networking stack for wide-area networks built
Reticulum allows you to build very wide-area networks with off-the-shelf tools, and offers end-to-end encryption, autoconfiguring cryptographically backed multi-hop transport, efficient addressing, unforgeable packet acknowledgements and more.
Reticulum is a complete networking stack, and does not use IP or higher layers, although it is easy to utilise IP (with TCP or UDP) as the underlying carrier for Reticulum. It is therefore trivial to tunnel Reticulum over the Internet or private IP networks. Reticulum is built directly on cryptographic principles, allowing resilience and stable functionality in open and trustless networks.
Reticulum is a complete networking stack, and does not need IP or higher layers, although it is easy to utilise IP (with TCP or UDP) as the underlying carrier for Reticulum. It is therefore trivial to tunnel Reticulum over the Internet or private IP networks. Reticulum is built directly on cryptographic principles, allowing resilience and stable functionality in open and trustless networks.
No kernel modules or drivers are required. Reticulum runs completely in userland, and can run on practically any system that runs Python 3.
No kernel modules or drivers are required. Reticulum runs completely in userland, and can run on practically any system that runs Python 3. Reticulum runs well even on small single-board computers like the Pi Zero.
Current Status
@@ -18,7 +18,7 @@ Reticulum should currently be considered beta software. All core protocol featur
Caveat Emptor
==============
Reticulum is an experimental networking stack, and should be considered as such. While it has been built with cryptography best-practices very foremost in mind, it has not been externally security audited, and there could very well be privacy-breaking bugs. To be considered even remotely secure, Reticulum needs a very thourough security review by independt cryptographers and security researchers. If you want to help out, or help sponsor an audit, please do get in touch.
Reticulum is an experimental networking stack, and should be considered as such. While it has been built with cryptography best-practices very foremost in mind, it has not been externally security audited, and there could very well be privacy-breaking bugs. To be considered secure, Reticulum needs a thourough security review by independt cryptographers and security researchers. If you want to help out, or help sponsor an audit, please do get in touch.
What does Reticulum Offer?
@@ -31,7 +31,9 @@ What does Reticulum Offer?
* Forward Secrecy with ephemereal Elliptic Curve Diffie-Hellman keys on Curve25519
* Reticulum uses the `Fernet <https://github.com/fernet/spec/blob/master/Spec.md>`_ specification for encryption
* Reticulum uses the `Fernet <https://github.com/fernet/spec/blob/master/Spec.md>`_ specification for on-the-wire / over-the-air encryption
* All keys are ephemeral and derived from an ECDH key exchange on Curve25519
* AES-128 in CBC mode with PKCS7 padding
@@ -39,8 +41,6 @@ What does Reticulum Offer?
* IVs are generated through os.urandom()
* Keys are ephemeral and derived from an ECDH key exchange on Curve25519
* Unforgeable packet delivery confirmations
* A variety of supported interface types
@@ -87,8 +87,8 @@ configured, Reticulum will take care of the rest, and any device on the WiFi
network can communicate with nodes on the LoRa and packet radio sides of the
network, and vice versa.
Supported Interface Types and Devices
=====================================
Interface Types and Devices
===========================
Reticulum implements a range of generalised interface types that covers most of the communications hardware that Reticulum can run over. If your hardware is not supported, it's relatively simple to implement an interface class. Currently, the following interfaces are supported:
* Any ethernet device
@@ -101,4 +101,6 @@ Reticulum implements a range of generalised interface types that covers most of
* TCP over IP networks
* UDP over IP networks
* UDP over IP networks
For a full list and more details, see the :ref:`Supported Interfaces<interfaces-main>` chapter.
+1 -1
View File
@@ -1,6 +1,6 @@
var DOCUMENTATION_OPTIONS = {
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
VERSION: '0.2.4 beta',
VERSION: '0.2.6 beta',
LANGUAGE: 'None',
COLLAPSE_INDEX: false,
BUILDER: 'html',
+8 -8
View File
@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Examples &#8212; Reticulum Network Stack 0.2.4 beta documentation</title>
<title>Code Examples &#8212; Reticulum Network Stack 0.2.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -27,8 +27,8 @@
<li class="right" >
<a href="reference.html" title="API Reference"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Examples</a></li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Code Examples</a></li>
</ul>
</div>
@@ -37,8 +37,8 @@
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="examples">
<span id="examples-main"></span><h1>Examples<a class="headerlink" href="#examples" title="Permalink to this headline"></a></h1>
<div class="section" id="code-examples">
<span id="examples-main"></span><h1>Code Examples<a class="headerlink" href="#code-examples" title="Permalink to this headline"></a></h1>
<p>A number of examples are included in the source distribution of Reticulum.
You can use these examples to learn how to write your own programs.</p>
<div class="section" id="minimal">
@@ -2273,7 +2273,7 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
<div class="sphinxsidebarwrapper">
<h3><a href="index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Examples</a><ul>
<li><a class="reference internal" href="#">Code Examples</a><ul>
<li><a class="reference internal" href="#minimal">Minimal</a></li>
<li><a class="reference internal" href="#announce">Announce</a></li>
<li><a class="reference internal" href="#broadcast">Broadcast</a></li>
@@ -2319,8 +2319,8 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
<li class="right" >
<a href="reference.html" title="API Reference"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Examples</a></li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Code Examples</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
+8 -4
View File
@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Index &#8212; Reticulum Network Stack 0.2.4 beta documentation</title>
<title>Index &#8212; Reticulum Network Stack 0.2.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -23,7 +23,7 @@
<li class="right" style="margin-right: 10px">
<a href="#" title="General Index"
accesskey="I">index</a></li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Index</a></li>
</ul>
</div>
@@ -255,10 +255,14 @@
<h2 id="N">N</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Link.no_inbound_for">no_inbound_for() (RNS.Link method)</a>
<li><a href="reference.html#RNS.Transport.next_hop">next_hop() (RNS.Transport static method)</a>
</li>
<li><a href="reference.html#RNS.Transport.next_hop_interface">next_hop_interface() (RNS.Transport static method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="reference.html#RNS.Link.no_inbound_for">no_inbound_for() (RNS.Link method)</a>
</li>
<li><a href="reference.html#RNS.Link.no_outbound_for">no_outbound_for() (RNS.Link method)</a>
</li>
</ul></td>
@@ -412,7 +416,7 @@
<li class="right" style="margin-right: 10px">
<a href="#" title="General Index"
>index</a></li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Index</a></li>
</ul>
</div>
+35 -10
View File
@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Getting Started Fast &#8212; Reticulum Network Stack 0.2.4 beta documentation</title>
<title>Getting Started Fast &#8212; Reticulum Network Stack 0.2.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -16,7 +16,7 @@
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Understanding Reticulum" href="understanding.html" />
<link rel="next" title="Using Reticulum on Your System" href="using.html" />
<link rel="prev" title="What is Reticulum?" href="whatis.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
@@ -26,12 +26,12 @@
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="understanding.html" title="Understanding Reticulum"
<a href="using.html" title="Using Reticulum on Your System"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="whatis.html" title="What is Reticulum?"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Getting Started Fast</a></li>
</ul>
</div>
@@ -51,10 +51,34 @@ scenarios.</p>
<p>If you simply want to try using a program built with Reticulum, you can take
a look at <a class="reference external" href="https://github.com/markqvist/nomadnet">Nomad Network</a>, which
provides a basic encrypted communications suite built completely on Reticulum.</p>
<a class="reference external image-reference" href="_images/nomadnet3.png"><img alt="_images/nomadnet3.png" src="_images/nomadnet3.png" /></a>
<a class="reference external image-reference" href="_images/nomadnet_3.png"><img alt="_images/nomadnet_3.png" src="_images/nomadnet_3.png" /></a>
<p><a class="reference external" href="https://github.com/markqvist/nomadnet">Nomad Network</a> is a user-facing client
in the development for the messaging and information-sharing protocol
<a class="reference external" href="https://github.com/markqvist/lxmf">LXMF</a>, another project built with Reticulum.</p>
<p>You can install Nomad Network via pip:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Install ...</span>
<span class="n">pip3</span> <span class="n">install</span> <span class="n">nomadnet</span>
<span class="c1"># ... and run</span>
<span class="n">nomadnet</span>
</pre></div>
</div>
</div>
<div class="section" id="creating-a-network-with-reticulum">
<h2>Creating a Network With Reticulum<a class="headerlink" href="#creating-a-network-with-reticulum" title="Permalink to this headline"></a></h2>
<p>To create a network, you will need to specify one or more <em>interfaces</em> for
Reticulum to use. This is done in the Reticulum configuration file, which by
default is located at <code class="docutils literal notranslate"><span class="pre">~/.reticulum/config</span></code>.</p>
<p>When Reticulum is started for the first time, it will create a default
configuration file, with one active interface. This default interface uses
your existing ethernet network (if there is one), and only allows you to
communicate with other Reticulum peers within your local broadcast domain.</p>
<p>To communicate further, you will have to add one or more interfaces. The default
configuration includes a number of examples, ranging from using TCP over the
internet, to LoRa and Packet Radio interfaces.</p>
<p>Possibly, the examples in the config file are enough to get you started. If
you want more information, you can read the <a class="reference internal" href="networks.html#networks-main"><span class="std std-ref">Building Networks</span></a>
and <a class="reference internal" href="interfaces.html#interfaces-main"><span class="std std-ref">Interfaces</span></a> chapters of this manual.</p>
</div>
<div class="section" id="develop-a-program-with-reticulum">
<h2>Develop a Program with Reticulum<a class="headerlink" href="#develop-a-program-with-reticulum" title="Permalink to this headline"></a></h2>
@@ -74,7 +98,7 @@ likely be to look at some <a class="reference internal" href="examples.html#exam
utilities, youll want to get the latest source from GitHub. In that case,
dont use pip, but try this recipe:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Install dependencies</span>
<span class="n">pip3</span> <span class="n">install</span> <span class="n">cryptography</span> <span class="n">pyserial</span>
<span class="n">pip3</span> <span class="n">install</span> <span class="n">cryptography</span> <span class="n">pyserial</span> <span class="n">netifaces</span>
<span class="c1"># Clone repository</span>
<span class="n">git</span> <span class="n">clone</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">markqvist</span><span class="o">/</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">git</span>
@@ -121,6 +145,7 @@ dont use pip, but try this recipe:</p>
<ul>
<li><a class="reference internal" href="#">Getting Started Fast</a><ul>
<li><a class="reference internal" href="#try-using-a-reticulum-based-program">Try Using a Reticulum-based Program</a></li>
<li><a class="reference internal" href="#creating-a-network-with-reticulum">Creating a Network With Reticulum</a></li>
<li><a class="reference internal" href="#develop-a-program-with-reticulum">Develop a Program with Reticulum</a></li>
<li><a class="reference internal" href="#participate-in-reticulum-development">Participate in Reticulum Development</a></li>
</ul>
@@ -131,8 +156,8 @@ dont use pip, but try this recipe:</p>
<p class="topless"><a href="whatis.html"
title="previous chapter">What is Reticulum?</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="understanding.html"
title="next chapter">Understanding Reticulum</a></p>
<p class="topless"><a href="using.html"
title="next chapter">Using Reticulum on Your System</a></p>
<div role="note" aria-label="source link">
<h3>This Page</h3>
<ul class="this-page-menu">
@@ -161,12 +186,12 @@ dont use pip, but try this recipe:</p>
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="understanding.html" title="Understanding Reticulum"
<a href="using.html" title="Using Reticulum on Your System"
>next</a> |</li>
<li class="right" >
<a href="whatis.html" title="What is Reticulum?"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Getting Started Fast</a></li>
</ul>
</div>
+38 -7
View File
@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Reticulum Network Stack Manual &#8212; Reticulum Network Stack 0.2.4 beta documentation</title>
<title>Reticulum Network Stack Manual &#8212; Reticulum Network Stack 0.2.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -27,7 +27,7 @@
<li class="right" >
<a href="whatis.html" title="What is Reticulum?"
accesskey="N">next</a> |</li>
<li class="nav-item nav-item-0"><a href="#">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-0"><a href="#">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Reticulum Network Stack Manual</a></li>
</ul>
</div>
@@ -40,8 +40,8 @@
<div class="section" id="reticulum-network-stack-manual">
<h1>Reticulum Network Stack Manual<a class="headerlink" href="#reticulum-network-stack-manual" title="Permalink to this headline"></a></h1>
<p>This manual aims to provide you with all the information you need to
understand Reticulum, develop programs using it, or to participate in
the development of Reticulum itself.</p>
understand Reticulum, build networks or develop programs using it, or
to participate in the development of Reticulum itself.</p>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="whatis.html">What is Reticulum?</a><ul>
@@ -49,15 +49,46 @@ the development of Reticulum itself.</p>
<li class="toctree-l2"><a class="reference internal" href="whatis.html#caveat-emptor">Caveat Emptor</a></li>
<li class="toctree-l2"><a class="reference internal" href="whatis.html#what-does-reticulum-offer">What does Reticulum Offer?</a></li>
<li class="toctree-l2"><a class="reference internal" href="whatis.html#where-can-reticulum-be-used">Where can Reticulum be Used?</a></li>
<li class="toctree-l2"><a class="reference internal" href="whatis.html#supported-interface-types-and-devices">Supported Interface Types and Devices</a></li>
<li class="toctree-l2"><a class="reference internal" href="whatis.html#interface-types-and-devices">Interface Types and Devices</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="gettingstartedfast.html">Getting Started Fast</a><ul>
<li class="toctree-l2"><a class="reference internal" href="gettingstartedfast.html#try-using-a-reticulum-based-program">Try Using a Reticulum-based Program</a></li>
<li class="toctree-l2"><a class="reference internal" href="gettingstartedfast.html#creating-a-network-with-reticulum">Creating a Network With Reticulum</a></li>
<li class="toctree-l2"><a class="reference internal" href="gettingstartedfast.html#develop-a-program-with-reticulum">Develop a Program with Reticulum</a></li>
<li class="toctree-l2"><a class="reference internal" href="gettingstartedfast.html#participate-in-reticulum-development">Participate in Reticulum Development</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a><ul>
<li class="toctree-l2"><a class="reference internal" href="using.html#included-utility-programs">Included Utility Programs</a><ul>
<li class="toctree-l3"><a class="reference internal" href="using.html#the-rnsd-utility">The rnsd Utility</a></li>
<li class="toctree-l3"><a class="reference internal" href="using.html#the-rnstatus-utility">The rnstatus Utility</a></li>
<li class="toctree-l3"><a class="reference internal" href="using.html#the-rnpath-utility">The rnpath Utility</a></li>
<li class="toctree-l3"><a class="reference internal" href="using.html#the-rnprobe-utility">The rnprobe Utility</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a><ul>
<li class="toctree-l2"><a class="reference internal" href="networks.html#concepts-overview">Concepts &amp; Overview</a></li>
<li class="toctree-l2"><a class="reference internal" href="networks.html#example-scenarios">Example Scenarios</a><ul>
<li class="toctree-l3"><a class="reference internal" href="networks.html#interconnected-lora-sites">Interconnected LoRa Sites</a></li>
<li class="toctree-l3"><a class="reference internal" href="networks.html#bridging-over-the-internet">Bridging Over the Internet</a></li>
<li class="toctree-l3"><a class="reference internal" href="networks.html#growth-and-convergence">Growth and Convergence</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Supported Interfaces</a><ul>
<li class="toctree-l2"><a class="reference internal" href="interfaces.html#udp-interface">UDP Interface</a></li>
<li class="toctree-l2"><a class="reference internal" href="interfaces.html#tcp-server-interface">TCP Server Interface</a></li>
<li class="toctree-l2"><a class="reference internal" href="interfaces.html#tcp-client-interface">TCP Client Interface</a></li>
<li class="toctree-l2"><a class="reference internal" href="interfaces.html#rnode-lora-interface">RNode LoRa Interface</a></li>
<li class="toctree-l2"><a class="reference internal" href="interfaces.html#serial-interface">Serial Interface</a></li>
<li class="toctree-l2"><a class="reference internal" href="interfaces.html#kiss-interface">KISS Interface</a></li>
<li class="toctree-l2"><a class="reference internal" href="interfaces.html#ax-25-kiss-interface">AX.25 KISS Interface</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a><ul>
<li class="toctree-l2"><a class="reference internal" href="understanding.html#motivation">Motivation</a></li>
<li class="toctree-l2"><a class="reference internal" href="understanding.html#goals">Goals</a></li>
@@ -98,7 +129,7 @@ the development of Reticulum itself.</p>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a><ul>
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a><ul>
<li class="toctree-l2"><a class="reference internal" href="examples.html#minimal">Minimal</a></li>
<li class="toctree-l2"><a class="reference internal" href="examples.html#announce">Announce</a></li>
<li class="toctree-l2"><a class="reference internal" href="examples.html#broadcast">Broadcast</a></li>
@@ -168,7 +199,7 @@ the development of Reticulum itself.</p>
<li class="right" >
<a href="whatis.html" title="What is Reticulum?"
>next</a> |</li>
<li class="nav-item nav-item-0"><a href="#">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-0"><a href="#">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Reticulum Network Stack Manual</a></li>
</ul>
</div>
+418
View File
@@ -0,0 +1,418 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Supported Interfaces &#8212; Reticulum Network Stack 0.2.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/doctools.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Understanding Reticulum" href="understanding.html" />
<link rel="prev" title="Building Networks" href="networks.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="understanding.html" title="Understanding Reticulum"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="networks.html" title="Building Networks"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Supported Interfaces</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="supported-interfaces">
<span id="interfaces-main"></span><h1>Supported Interfaces<a class="headerlink" href="#supported-interfaces" title="Permalink to this headline"></a></h1>
<p>Reticulum supports using many kinds of devices as networking interfaces, and
allows you to mix and match them in any way you choose. The number of distinct
network topologies you can create with Reticulum is more or less endless, but
common to them all is that you will need to define one or more <em>interfaces</em>
for Reticulum to use.</p>
<p>The following sections describe the interfaces currently available in Reticulum,
and gives example configurations for the respective interface types.</p>
<div class="section" id="udp-interface">
<span id="interfaces-udp"></span><h2>UDP Interface<a class="headerlink" href="#udp-interface" title="Permalink to this headline"></a></h2>
<p>A UDP interface can be useful for communicating over IP networks, both
private and the internet. It can also allow broadcast communication
over IP networks, so it can provide an easy way to enable connectivity
with all other peers on a local area network.</p>
<p>The below example is enabled by default on new Reticulum installations,
as it provides an easy way to get started and to test Reticulum on a
pre-existing LAN.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># This example enables communication with other</span>
<span class="c1"># local Reticulum peers over UDP.</span>
<span class="p">[[</span><span class="n">Default</span> <span class="n">UDP</span> <span class="n">Interface</span><span class="p">]]</span>
<span class="nb">type</span> <span class="o">=</span> <span class="n">UDPInterface</span>
<span class="n">interface_enabled</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">outgoing</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">listen_ip</span> <span class="o">=</span> <span class="mf">0.0</span><span class="o">.</span><span class="mf">0.0</span>
<span class="n">listen_port</span> <span class="o">=</span> <span class="mi">4242</span>
<span class="n">forward_ip</span> <span class="o">=</span> <span class="mf">255.255</span><span class="o">.</span><span class="mf">255.255</span>
<span class="n">forward_port</span> <span class="o">=</span> <span class="mi">4242</span>
<span class="c1"># The above configuration will allow communication</span>
<span class="c1"># within the local broadcast domains of all local</span>
<span class="c1"># IP interfaces. This is enabled by default as an</span>
<span class="c1"># easy way to get started, but you might want to</span>
<span class="c1"># consider altering it to something more specific.</span>
<span class="c1"># Instead of specifying listen_ip, listen_port,</span>
<span class="c1"># forward_ip and forward_port, you can also bind</span>
<span class="c1"># to a specific network device like below.</span>
<span class="c1"># device = eth0</span>
<span class="c1"># port = 4242</span>
<span class="c1"># Assuming the eth0 device has the address</span>
<span class="c1"># 10.55.0.72/24, the above configuration would</span>
<span class="c1"># be equivalent to the following manual setup.</span>
<span class="c1"># Note that we are both listening and forwarding to</span>
<span class="c1"># the broadcast address of the network segments.</span>
<span class="c1"># listen_ip = 10.55.0.255</span>
<span class="c1"># listen_port = 4242</span>
<span class="c1"># forward_ip = 10.55.0.255</span>
<span class="c1"># forward_port = 4242</span>
<span class="c1"># You can of course also communicate only with</span>
<span class="c1"># a single IP address</span>
<span class="c1"># listen_ip = 10.55.0.15</span>
<span class="c1"># listen_port = 4242</span>
<span class="c1"># forward_ip = 10.55.0.16</span>
<span class="c1"># forward_port = 4242</span>
</pre></div>
</div>
</div>
<div class="section" id="tcp-server-interface">
<span id="interfaces-tcps"></span><h2>TCP Server Interface<a class="headerlink" href="#tcp-server-interface" title="Permalink to this headline"></a></h2>
<p>The TCP Server interface is suitable for allowing other peers to connect over
the Internet or private IP networks. When a TCP server interface has been
configured, other Reticulum peers can connect to it with a TCP Client interface.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># This example demonstrates a TCP server interface.</span>
<span class="c1"># It will listen for incoming connections on the</span>
<span class="c1"># specified IP address and port number.</span>
<span class="p">[[</span><span class="n">TCP</span> <span class="n">Server</span> <span class="n">Interface</span><span class="p">]]</span>
<span class="nb">type</span> <span class="o">=</span> <span class="n">TCPServerInterface</span>
<span class="n">interface_enabled</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">outgoing</span> <span class="o">=</span> <span class="kc">True</span>
<span class="c1"># This configuration will listen on all IP</span>
<span class="c1"># interfaces on port 4242</span>
<span class="n">listen_ip</span> <span class="o">=</span> <span class="mf">0.0</span><span class="o">.</span><span class="mf">0.0</span>
<span class="n">listen_port</span> <span class="o">=</span> <span class="mi">4242</span>
<span class="c1"># Alternatively you can bind to a specific IP</span>
<span class="c1"># listen_ip = 10.0.0.88</span>
<span class="c1"># listen_port = 4242</span>
<span class="c1"># Or a specific network device</span>
<span class="c1"># device = eth0</span>
<span class="c1"># port = 4242</span>
</pre></div>
</div>
</div>
<div class="section" id="tcp-client-interface">
<span id="interfaces-tcpc"></span><h2>TCP Client Interface<a class="headerlink" href="#tcp-client-interface" title="Permalink to this headline"></a></h2>
<p>To connect to a TCP server interface, you would naturally use the TCP client
interface. Many TCP Client interfaces from different peers can connect to the
same TCP Server interface at the same time.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Here&#39;s an example of a TCP Client interface. The</span>
<span class="c1"># target_host can either be an IP address or a hostname.</span>
<span class="p">[[</span><span class="n">TCP</span> <span class="n">Client</span> <span class="n">Interface</span><span class="p">]]</span>
<span class="nb">type</span> <span class="o">=</span> <span class="n">TCPClientInterface</span>
<span class="n">interface_enabled</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">outgoing</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">target_host</span> <span class="o">=</span> <span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span>
<span class="n">target_port</span> <span class="o">=</span> <span class="mi">4242</span>
</pre></div>
</div>
</div>
<div class="section" id="rnode-lora-interface">
<span id="interfaces-rnode"></span><h2>RNode LoRa Interface<a class="headerlink" href="#rnode-lora-interface" title="Permalink to this headline"></a></h2>
<p>To use Reticulum over LoRa, the <a class="reference external" href="https://unsigned.io/rnode/">RNode</a> interface
can be used, and offers full control over LoRa parameters.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Here&#39;s an example of how to add a LoRa interface</span>
<span class="c1"># using the RNode LoRa transceiver.</span>
<span class="p">[[</span><span class="n">RNode</span> <span class="n">LoRa</span> <span class="n">Interface</span><span class="p">]]</span>
<span class="nb">type</span> <span class="o">=</span> <span class="n">RNodeInterface</span>
<span class="c1"># Enable interface if you want use it!</span>
<span class="n">interface_enabled</span> <span class="o">=</span> <span class="kc">True</span>
<span class="c1"># Allow transmit on interface. Setting</span>
<span class="c1"># this to false will create a listen-</span>
<span class="c1"># only interface.</span>
<span class="n">outgoing</span> <span class="o">=</span> <span class="n">true</span>
<span class="c1"># Serial port for the device</span>
<span class="n">port</span> <span class="o">=</span> <span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">ttyUSB0</span>
<span class="c1"># Set frequency to 867.2 MHz</span>
<span class="n">frequency</span> <span class="o">=</span> <span class="mi">867200000</span>
<span class="c1"># Set LoRa bandwidth to 125 KHz</span>
<span class="n">bandwidth</span> <span class="o">=</span> <span class="mi">125000</span>
<span class="c1"># Set TX power to 7 dBm (5 mW)</span>
<span class="n">txpower</span> <span class="o">=</span> <span class="mi">7</span>
<span class="c1"># Select spreading factor 8. Valid</span>
<span class="c1"># range is 7 through 12, with 7</span>
<span class="c1"># being the fastest and 12 having</span>
<span class="c1"># the longest range.</span>
<span class="n">spreadingfactor</span> <span class="o">=</span> <span class="mi">8</span>
<span class="c1"># Select coding rate 5. Valid range</span>
<span class="c1"># is 5 throough 8, with 5 being the</span>
<span class="c1"># fastest, and 8 the longest range.</span>
<span class="n">codingrate</span> <span class="o">=</span> <span class="mi">5</span>
<span class="c1"># You can configure the RNode to send</span>
<span class="c1"># out identification on the channel with</span>
<span class="c1"># a set interval by configuring the</span>
<span class="c1"># following two parameters.</span>
<span class="c1"># id_callsign = MYCALL-0</span>
<span class="c1"># id_interval = 600</span>
<span class="c1"># For certain homebrew RNode interfaces</span>
<span class="c1"># with low amounts of RAM, using packet</span>
<span class="c1"># flow control can be useful. By default</span>
<span class="c1"># it is disabled.</span>
<span class="n">flow_control</span> <span class="o">=</span> <span class="kc">False</span>
</pre></div>
</div>
</div>
<div class="section" id="serial-interface">
<span id="interfaces-serial"></span><h2>Serial Interface<a class="headerlink" href="#serial-interface" title="Permalink to this headline"></a></h2>
<p>Reticulum can be used over serial ports directly, or over any device with a
serial port, that will transparently pass data. Useful for communicating
directly over a wire-pair, or for using devices such as data radios and lasers.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[[</span><span class="n">Serial</span> <span class="n">Interface</span><span class="p">]]</span>
<span class="nb">type</span> <span class="o">=</span> <span class="n">SerialInterface</span>
<span class="n">interface_enabled</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">outgoing</span> <span class="o">=</span> <span class="kc">True</span>
<span class="c1"># Serial port for the device</span>
<span class="n">port</span> <span class="o">=</span> <span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">ttyUSB0</span>
<span class="c1"># Set the serial baud-rate and other</span>
<span class="c1"># configuration parameters.</span>
<span class="n">speed</span> <span class="o">=</span> <span class="mi">115200</span>
<span class="n">databits</span> <span class="o">=</span> <span class="mi">8</span>
<span class="n">parity</span> <span class="o">=</span> <span class="n">none</span>
<span class="n">stopbits</span> <span class="o">=</span> <span class="mi">1</span>
</pre></div>
</div>
</div>
<div class="section" id="kiss-interface">
<span id="interfaces-kiss"></span><h2>KISS Interface<a class="headerlink" href="#kiss-interface" title="Permalink to this headline"></a></h2>
<p>With the KISS interface, you can use Reticulum over a variety of packet
radio modems and TNCs, including <a class="reference external" href="https://unsigned.io/openmodem/">OpenModem</a>.
KISS interfaces can also be configured to periodically send out beacons
for station identification purposes.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[[</span><span class="n">Packet</span> <span class="n">Radio</span> <span class="n">KISS</span> <span class="n">Interface</span><span class="p">]]</span>
<span class="nb">type</span> <span class="o">=</span> <span class="n">KISSInterface</span>
<span class="n">interface_enabled</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">outgoing</span> <span class="o">=</span> <span class="n">true</span>
<span class="c1"># Serial port for the device</span>
<span class="n">port</span> <span class="o">=</span> <span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">ttyUSB1</span>
<span class="c1"># Set the serial baud-rate and other</span>
<span class="c1"># configuration parameters.</span>
<span class="n">speed</span> <span class="o">=</span> <span class="mi">115200</span>
<span class="n">databits</span> <span class="o">=</span> <span class="mi">8</span>
<span class="n">parity</span> <span class="o">=</span> <span class="n">none</span>
<span class="n">stopbits</span> <span class="o">=</span> <span class="mi">1</span>
<span class="c1"># Set the modem preamble.</span>
<span class="n">preamble</span> <span class="o">=</span> <span class="mi">150</span>
<span class="c1"># Set the modem TX tail.</span>
<span class="n">txtail</span> <span class="o">=</span> <span class="mi">10</span>
<span class="c1"># Configure CDMA parameters. These</span>
<span class="c1"># settings are reasonable defaults.</span>
<span class="n">persistence</span> <span class="o">=</span> <span class="mi">200</span>
<span class="n">slottime</span> <span class="o">=</span> <span class="mi">20</span>
<span class="c1"># You can configure the interface to send</span>
<span class="c1"># out identification on the channel with</span>
<span class="c1"># a set interval by configuring the</span>
<span class="c1"># following two parameters. The KISS</span>
<span class="c1"># interface will only ID if the set</span>
<span class="c1"># interval has elapsed since it&#39;s last</span>
<span class="c1"># actual transmission. The interval is</span>
<span class="c1"># configured in seconds.</span>
<span class="c1"># This option is commented out and not</span>
<span class="c1"># used by default.</span>
<span class="c1"># id_callsign = MYCALL-0</span>
<span class="c1"># id_interval = 600</span>
<span class="c1"># Whether to use KISS flow-control.</span>
<span class="c1"># This is useful for modems that have</span>
<span class="c1"># a small internal packet buffer, but</span>
<span class="c1"># support packet flow control instead.</span>
<span class="n">flow_control</span> <span class="o">=</span> <span class="n">false</span>
</pre></div>
</div>
</div>
<div class="section" id="ax-25-kiss-interface">
<span id="interfaces-ax25"></span><h2>AX.25 KISS Interface<a class="headerlink" href="#ax-25-kiss-interface" title="Permalink to this headline"></a></h2>
<p>If youre using Reticulum on amateur radio spectrum, you might want to
use the AX.25 KISS interface. This way, Reticulum will automatically
encapsulate its traffic in AX.25 and also identify your stations
transmissions with your callsign and SSID.</p>
<p>Only do this if you really need to! Reticulum doesnt need the AX.25
layer for anything, and it incurs extra overhead on every packet to
encapsulate in AX.25.</p>
<p>A more efficient way is to use the plain KISS interface with the
beaconing functionality described above.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[[</span><span class="n">Packet</span> <span class="n">Radio</span> <span class="n">AX</span><span class="o">.</span><span class="mi">25</span> <span class="n">KISS</span> <span class="n">Interface</span><span class="p">]]</span>
<span class="nb">type</span> <span class="o">=</span> <span class="n">AX25KISSInterface</span>
<span class="c1"># Set the station callsign and SSID</span>
<span class="n">callsign</span> <span class="o">=</span> <span class="n">NO1CLL</span>
<span class="n">ssid</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1"># Enable interface if you want use it!</span>
<span class="n">interface_enabled</span> <span class="o">=</span> <span class="kc">True</span>
<span class="c1"># Allow transmit on interface.</span>
<span class="n">outgoing</span> <span class="o">=</span> <span class="kc">True</span>
<span class="c1"># Serial port for the device</span>
<span class="n">port</span> <span class="o">=</span> <span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">ttyUSB2</span>
<span class="c1"># Set the serial baud-rate and other</span>
<span class="c1"># configuration parameters.</span>
<span class="n">speed</span> <span class="o">=</span> <span class="mi">115200</span>
<span class="n">databits</span> <span class="o">=</span> <span class="mi">8</span>
<span class="n">parity</span> <span class="o">=</span> <span class="n">none</span>
<span class="n">stopbits</span> <span class="o">=</span> <span class="mi">1</span>
<span class="c1"># Set the modem preamble. A 150ms</span>
<span class="c1"># preamble should be a reasonable</span>
<span class="c1"># default, but may need to be</span>
<span class="c1"># increased for radios with slow-</span>
<span class="c1"># opening squelch and long TX/RX</span>
<span class="c1"># turnaround</span>
<span class="n">preamble</span> <span class="o">=</span> <span class="mi">150</span>
<span class="c1"># Set the modem TX tail. In most</span>
<span class="c1"># cases this should be kept as low</span>
<span class="c1"># as possible to not waste airtime.</span>
<span class="n">txtail</span> <span class="o">=</span> <span class="mi">10</span>
<span class="c1"># Configure CDMA parameters. These</span>
<span class="c1"># settings are reasonable defaults.</span>
<span class="n">persistence</span> <span class="o">=</span> <span class="mi">200</span>
<span class="n">slottime</span> <span class="o">=</span> <span class="mi">20</span>
<span class="c1"># Whether to use KISS flow-control.</span>
<span class="c1"># This is useful for modems with a</span>
<span class="c1"># small internal packet buffer.</span>
<span class="n">flow_control</span> <span class="o">=</span> <span class="n">false</span>
</pre></div>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h3><a href="index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Supported Interfaces</a><ul>
<li><a class="reference internal" href="#udp-interface">UDP Interface</a></li>
<li><a class="reference internal" href="#tcp-server-interface">TCP Server Interface</a></li>
<li><a class="reference internal" href="#tcp-client-interface">TCP Client Interface</a></li>
<li><a class="reference internal" href="#rnode-lora-interface">RNode LoRa Interface</a></li>
<li><a class="reference internal" href="#serial-interface">Serial Interface</a></li>
<li><a class="reference internal" href="#kiss-interface">KISS Interface</a></li>
<li><a class="reference internal" href="#ax-25-kiss-interface">AX.25 KISS Interface</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="networks.html"
title="previous chapter">Building Networks</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="understanding.html"
title="next chapter">Understanding Reticulum</a></p>
<div role="note" aria-label="source link">
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/interfaces.rst.txt"
rel="nofollow">Show Source</a></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="understanding.html" title="Understanding Reticulum"
>next</a> |</li>
<li class="right" >
<a href="networks.html" title="Building Networks"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Supported Interfaces</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2021, Mark Qvist.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 4.0.1.
</div>
</body>
</html>
+258
View File
@@ -0,0 +1,258 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Building Networks &#8212; Reticulum Network Stack 0.2.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/doctools.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Supported Interfaces" href="interfaces.html" />
<link rel="prev" title="Using Reticulum on Your System" href="using.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="interfaces.html" title="Supported Interfaces"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="using.html" title="Using Reticulum on Your System"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Building Networks</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="building-networks">
<span id="networks-main"></span><h1>Building Networks<a class="headerlink" href="#building-networks" title="Permalink to this headline"></a></h1>
<p>This chapter will provide you with the knowledge needed to build networks with
Reticulum, which can often be easier than using traditional stacks, since you
dont have to worry about coordinating addresses, subnets and routing for an
entire network that you might not know how will evolve in the future. With
Reticulum, you can simply add more segments to your network when it becomes
necesarry, and Reticulum will handle the convergence of the entire network
automatically.</p>
<div class="section" id="concepts-overview">
<h2>Concepts &amp; Overview<a class="headerlink" href="#concepts-overview" title="Permalink to this headline"></a></h2>
<p>There are important points that need to be kept in mind when building networks
with Reticulum:</p>
<blockquote>
<div><ul>
<li><div class="line-block">
<div class="line">In a Reticulum network, any node can autonomously generate as many adresses
(called <em>destinations</em> in Reticulum terminology) as it needs, which become
globally reachable to the rest of the network. There is no central point of
control over the adress space.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">Reticulum was designed to handle both very small, and very large networks.
While the adress space can support billions of endpoints, Reticulum is
also very useful when just a few devices needs to communicate.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">Reticulum provides sender/initiator anonymity by default. There is no way
to filter traffic or discriminate it based on the source of the traffic.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">All traffic is encrypted using ephemeral keys generated by an Elliptic Curve
Diffie-Hellman key exchange on Curve25519. There is no way to inspect traffic
contents, and no way to prioritise or throttle certain kinds of traffic.
All transport and routing layers are thus completely agnostic to traffic type,
and will pass all traffic equally.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">Reticulum can function both with and without infrastructure. When <em>transport
nodes</em> are available, they can route traffic over multiple hops for other
nodes, and will function as a distributed cryptographic keystore. When there
is no transport nodes available, all nodes that are within communication range
can still communicate.</div>
</div>
</li>
<li><div class="line-block">
<div class="line">Every node can become a transport node, simply by enabling it in its
configuration, but there is no need for every node on the network to be a
transport node. Letting every node be a transport node will in most cases
degrade the performance and reliability of the network.</div>
</div>
<blockquote>
<div><p>In general terms, if a node is stationary, well-connected and kept running
most of the time, it is a good candidate to be a transport node. For optimal
performance, a network should contain the amount of transport nodes that
provides connectivity to the intended area / topography, and not many more
than that.</p>
</div></blockquote>
</li>
</ul>
</div></blockquote>
<p>Reticulum allows you to mix very different kinds of networking mediums into a
unified mesh, or to keep everything within one medium. You could build a “virtual
network” running entirely over the Internet, where all nodes communicate over TCP
and UDP “channels”. You could also build such a network using MQTT or ZeroMQ as
the underlying carrier for Reticulum.</p>
<p>However, most real-world networks will probably involve either some form of
wireless or direct hardline communications. To allow Reticulum to communicate
over any type of medium, you must specify it in the configuration file, by default
located at <code class="docutils literal notranslate"><span class="pre">~/.reticulum/config</span></code>.</p>
<p>Any number of interfaces can be configured, and Reticulum will automatically
decide which are suitable to use in any given situation, depending on where
traffic needs to flow.</p>
</div>
<div class="section" id="example-scenarios">
<h2>Example Scenarios<a class="headerlink" href="#example-scenarios" title="Permalink to this headline"></a></h2>
<p>This section illustrates a few example scenarios, and how they would, in general
terms, be planned, implemented and configured.</p>
<div class="section" id="interconnected-lora-sites">
<h3>Interconnected LoRa Sites<a class="headerlink" href="#interconnected-lora-sites" title="Permalink to this headline"></a></h3>
<p>An organisation wants to provide communication and information services to its
members, which are located mainly in three separate areas. Three suitable hill-top
locations are found, where the organisation can install equipment: Site A, B and C.</p>
<p>Since the amount of data that needs to be exchanged between users is mainly text-
based, the bandwidth requirements are low, and LoRa radios are chosen to connect
users to the network.</p>
<p>Due to the hill-top locations found, there is radio line-of-sight between site A
and B, and also between site B and C. Because of this, the organisation does not
need to use the Internet to interconnect the sites, but purchases four Point-to-Point
WiFi based radios for interconnecting the sites.</p>
<p>At each site, a Raspberry Pi is installed to function as a gateway. A LoRa radio
is connected to the Pi with a USB cable, and the WiFi radio is connected to the
ethernet port of the Pi. At site B, two WiFi radios are needed to be able to reach
both site A and site C, so an extra ethernet adapter is connected to the Pi in
this location.</p>
<p>Once the hardware has been installed, Reticulum is installed on all the Pis, and at
site A and C, one interface is added for the LoRa radio, as well as one for the WiFi
radio. At site B, an interface for the LoRa radio, and one interface for each WiFi
radio is added to the Reticulum configuration file. The transport node option is
enabled in the configuration of all three gateways.</p>
<p>The network is now operational, and ready to serve users across all three areas.
The organisation prepares a LoRa radio that is supplied to the end users, along
with a Reticulum configuration file, that contains the right parameters for
communicating with the LoRa radios installed at the gateway sites.</p>
<p>Once users connect to the network, anyone will be able to communicate with anyone
else across all three sites.</p>
</div>
<div class="section" id="bridging-over-the-internet">
<h3>Bridging Over the Internet<a class="headerlink" href="#bridging-over-the-internet" title="Permalink to this headline"></a></h3>
<p>As the organisation grows, several new communities form in places too far away
from the core network to be reachable over WiFi links. New gateways similar to those
previously installed are set up for the new communities at the new sites D and E, but
they are islanded from the core network, and only serve the local users.</p>
<p>After investigating the options, it is found that it is possible to install an
Internet connection at site A, and an interface on the Internet connection is
configured for Reticulum on the Raspberry Pi at site A.</p>
<p>A member of the organisation at site D, named Dori, is willing to help by sharing
the Internet connection she already has in her home, and is able to leave a Raspberry
Pi running. A new Reticulum interface is configured on her Pi, connecting to the newly
enabled Internet interface on the gateway at site A. Dori is now connected to both
all the nodes at her own local site (through the hill-top LoRa gateway), and all the
combined users of sites A, B and C. She then enables transport on her node, and
traffic from site D can now reach everyone at site A, B and C, and vice versa.</p>
</div>
<div class="section" id="growth-and-convergence">
<h3>Growth and Convergence<a class="headerlink" href="#growth-and-convergence" title="Permalink to this headline"></a></h3>
<p>As the organisation grows, more gateways are added to keep up with the growing user
base. Some local gateways even add VHF radios and packet modems to reach outlying users
and communities that are out of reach for the LoRa radios and WiFi backhauls.</p>
<p>As more sites, gateways and users are connected, the amount of coordination required
is kept to a minimum. If one community wants to add connectivity to the next one
over, it can simply be done without having to involve everyone or coordinate address
space or routing tables.</p>
<p>With the added geographical coverage, the operators at site A one day find that
the original internet bridged interfaces are no longer utilised. The network has
converged to be completely self-connected, and the sites that were once poorly
connected outliers are now an integral part of the network.</p>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h3><a href="index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Building Networks</a><ul>
<li><a class="reference internal" href="#concepts-overview">Concepts &amp; Overview</a></li>
<li><a class="reference internal" href="#example-scenarios">Example Scenarios</a><ul>
<li><a class="reference internal" href="#interconnected-lora-sites">Interconnected LoRa Sites</a></li>
<li><a class="reference internal" href="#bridging-over-the-internet">Bridging Over the Internet</a></li>
<li><a class="reference internal" href="#growth-and-convergence">Growth and Convergence</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="using.html"
title="previous chapter">Using Reticulum on Your System</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="interfaces.html"
title="next chapter">Supported Interfaces</a></p>
<div role="note" aria-label="source link">
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/networks.rst.txt"
rel="nofollow">Show Source</a></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="interfaces.html" title="Supported Interfaces"
>next</a> |</li>
<li class="right" >
<a href="using.html" title="Using Reticulum on Your System"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Building Networks</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2021, Mark Qvist.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 4.0.1.
</div>
</body>
</html>
Binary file not shown.
+32 -6
View File
@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>API Reference &#8212; Reticulum Network Stack 0.2.4 beta documentation</title>
<title>API Reference &#8212; Reticulum Network Stack 0.2.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -31,7 +31,7 @@
<li class="right" >
<a href="understanding.html" title="Understanding Reticulum"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">API Reference</a></li>
</ul>
</div>
@@ -51,7 +51,7 @@
<span id="api-reticulum"></span><h3>Reticulum<a class="headerlink" href="#reticulum" title="Permalink to this headline"></a></h3>
<dl class="py class">
<dt class="sig sig-object py" id="RNS.Reticulum">
<em class="property"><span class="pre">class</span> </em><span class="sig-prename descclassname"><span class="pre">RNS.</span></span><span class="sig-name descname"><span class="pre">Reticulum</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">configdir</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Reticulum" title="Permalink to this definition"></a></dt>
<em class="property"><span class="pre">class</span> </em><span class="sig-prename descclassname"><span class="pre">RNS.</span></span><span class="sig-name descname"><span class="pre">Reticulum</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">configdir</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">loglevel</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Reticulum" title="Permalink to this definition"></a></dt>
<dd><p>This class is used to initialise access to Reticulum within a
program. You must create exactly one instance of this class before
carrying out any other RNS operations, such as creating destinations
@@ -1072,8 +1072,8 @@ the resource advertisement it will begin transferring.</p>
<dl class="py class">
<dt class="sig sig-object py" id="RNS.Transport">
<em class="property"><span class="pre">class</span> </em><span class="sig-prename descclassname"><span class="pre">RNS.</span></span><span class="sig-name descname"><span class="pre">Transport</span></span><a class="headerlink" href="#RNS.Transport" title="Permalink to this definition"></a></dt>
<dd><p>Through static methods of this class you can interact with Reticulums
Transport system.</p>
<dd><p>Through static methods of this class you can interact with the
Transport system of Reticulum.</p>
<dl class="py attribute">
<dt class="sig sig-object py" id="RNS.Transport.PATHFINDER_M">
<span class="sig-name descname"><span class="pre">PATHFINDER_M</span></span><em class="property"> <span class="pre">=</span> <span class="pre">128</span></em><a class="headerlink" href="#RNS.Transport.PATHFINDER_M" title="Permalink to this definition"></a></dt>
@@ -1128,6 +1128,32 @@ Transport system.</p>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="RNS.Transport.next_hop">
<em class="property"><span class="pre">static</span> </em><span class="sig-name descname"><span class="pre">next_hop</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">destination_hash</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Transport.next_hop" title="Permalink to this definition"></a></dt>
<dd><dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>destination_hash</strong> A destination hash as <em>bytes</em>.</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>The destination hash as <em>bytes</em> for the next hop to the specified destination, or <em>None</em> if the next hop is unknown.</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="RNS.Transport.next_hop_interface">
<em class="property"><span class="pre">static</span> </em><span class="sig-name descname"><span class="pre">next_hop_interface</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">destination_hash</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Transport.next_hop_interface" title="Permalink to this definition"></a></dt>
<dd><dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>destination_hash</strong> A destination hash as <em>bytes</em>.</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>The interface for the next hop to the specified destination, or <em>None</em> if the interface is unknown.</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="RNS.Transport.request_path">
<em class="property"><span class="pre">static</span> </em><span class="sig-name descname"><span class="pre">request_path</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">destination_hash</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Transport.request_path" title="Permalink to this definition"></a></dt>
@@ -1212,7 +1238,7 @@ will announce it.</p>
<li class="right" >
<a href="understanding.html" title="Understanding Reticulum"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">API Reference</a></li>
</ul>
</div>
+3 -3
View File
@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Search &#8212; Reticulum Network Stack 0.2.4 beta documentation</title>
<title>Search &#8212; Reticulum Network Stack 0.2.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -29,7 +29,7 @@
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Search</a></li>
</ul>
</div>
@@ -85,7 +85,7 @@
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Search</a></li>
</ul>
</div>
File diff suppressed because one or more lines are too long
+9 -9
View File
@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Understanding Reticulum &#8212; Reticulum Network Stack 0.2.4 beta documentation</title>
<title>Understanding Reticulum &#8212; Reticulum Network Stack 0.2.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -17,7 +17,7 @@
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="API Reference" href="reference.html" />
<link rel="prev" title="Getting Started Fast" href="gettingstartedfast.html" />
<link rel="prev" title="Building Networks" href="networks.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@@ -29,9 +29,9 @@
<a href="reference.html" title="API Reference"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="gettingstartedfast.html" title="Getting Started Fast"
<a href="networks.html" title="Building Networks"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Understanding Reticulum</a></li>
</ul>
</div>
@@ -80,7 +80,7 @@ by using multiple hops).</p>
</div>
<div class="section" id="goals">
<span id="understanding-goals"></span><h2>Goals<a class="headerlink" href="#goals" title="Permalink to this headline"></a></h2>
<p>To be as widely usable and easy to implement as possible, the following goals have been used to
<p>To be as widely usable and easy to use as possible, the following goals have been used to
guide the design of Reticulum:</p>
<ul class="simple">
<li><dl class="simple">
@@ -815,8 +815,8 @@ proof 11
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="gettingstartedfast.html"
title="previous chapter">Getting Started Fast</a></p>
<p class="topless"><a href="networks.html"
title="previous chapter">Building Networks</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="reference.html"
title="next chapter">API Reference</a></p>
@@ -851,9 +851,9 @@ proof 11
<a href="reference.html" title="API Reference"
>next</a> |</li>
<li class="right" >
<a href="gettingstartedfast.html" title="Getting Started Fast"
<a href="networks.html" title="Building Networks"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Understanding Reticulum</a></li>
</ul>
</div>
+258
View File
@@ -0,0 +1,258 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Using Reticulum on Your System &#8212; Reticulum Network Stack 0.2.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/doctools.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Building Networks" href="networks.html" />
<link rel="prev" title="Getting Started Fast" href="gettingstartedfast.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="networks.html" title="Building Networks"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="gettingstartedfast.html" title="Getting Started Fast"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Using Reticulum on Your System</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="using-reticulum-on-your-system">
<span id="using-main"></span><h1>Using Reticulum on Your System<a class="headerlink" href="#using-reticulum-on-your-system" title="Permalink to this headline"></a></h1>
<p>Reticulum is not installed as a driver or kernel module, as one might expect
of a networking stack. Instead, Reticulum is distributed as a Python module.
This means that no special privileges are required to install or use it.
Any program or application that uses Reticulum will automatically load and
initialise Reticulum when it starts.</p>
<p>In many cases, this approach is sufficient. When any program needs to use
Reticulum, it is loaded, initialised, interfaces are brought up, and the
program can now communicate over Reticulum. If another program starts up
and also wants access to the same Reticulum network, the instance is simply
shared. This works for any number of programs running concurrently, and is
very easy to use, but depending on your use case, there are other options.</p>
<div class="section" id="included-utility-programs">
<h2>Included Utility Programs<a class="headerlink" href="#included-utility-programs" title="Permalink to this headline"></a></h2>
<p>If you often use Reticulum from several different programs, or simply want
Reticulum to stay available all the time, for example if you are hosting
a transport node, you might want to run Reticulum as a separate service that
other programs, applications and services can utilise.</p>
<div class="section" id="the-rnsd-utility">
<h3>The rnsd Utility<a class="headerlink" href="#the-rnsd-utility" title="Permalink to this headline"></a></h3>
<p>To do so is very easy. Simply run the included <code class="docutils literal notranslate"><span class="pre">rnsd</span></code> command. When <code class="docutils literal notranslate"><span class="pre">rnsd</span></code>
is running, it will keep all configured interfaces open, handle transport if
it is enabled, and allow any other programs to immediately utilise the
Reticulum network it is configured for.</p>
<p>You can even run multiple instances of rnsd with different configurations on
the same system.</p>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span># Install Reticulum
pip3 install rns
# Run rnsd
rnsd
</pre></div>
</div>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnsd [-h] [--config CONFIG] [-v] [-q] [--version]
Reticulum Network Stack Daemon
optional arguments:
-h, --help show this help message and exit
--config CONFIG path to alternative Reticulum config directory
-v, --verbose
-q, --quiet
--version show program&#39;s version number and exit
</pre></div>
</div>
</div>
<div class="section" id="the-rnstatus-utility">
<h3>The rnstatus Utility<a class="headerlink" href="#the-rnstatus-utility" title="Permalink to this headline"></a></h3>
<p>Using the <code class="docutils literal notranslate"><span class="pre">rnstatus</span></code> utility, you can view the status of configured Reticulum
interfaces, similar to the <code class="docutils literal notranslate"><span class="pre">ifconfig</span></code> program.</p>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span># Run rnstatus
rnstatus
# Example output
Shared Instance[37428]
Status: Up
Connected applications: 1
RX: 1.13 KB
TX: 1.07 KB
UDPInterface[Default UDP Interface/0.0.0.0:4242]
Status: Up
RX: 1.01 KB
TX: 1.01 KB
TCPInterface[RNS Testnet Frankfurt/frankfurt.rns.unsigned.io:4965]
Status: Up
RX: 1.37 KB
TX: 9.02 KB
</pre></div>
</div>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnsd [-h] [--config CONFIG] [-v] [-q] [--version]
Reticulum Network Stack Daemon
optional arguments:
-h, --help show this help message and exit
--config CONFIG path to alternative Reticulum config directory
-v, --verbose
-q, --quiet
--version show program&#39;s version number and exit
</pre></div>
</div>
</div>
<div class="section" id="the-rnpath-utility">
<h3>The rnpath Utility<a class="headerlink" href="#the-rnpath-utility" title="Permalink to this headline"></a></h3>
<p>With the <code class="docutils literal notranslate"><span class="pre">rnpath</span></code> utility, you can look up and view paths for
destinations on the Reticulum network.</p>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span># Run rnpath
rnpath eca6f4e4dc26ae329e61
# Example output
Path found, destination &lt;eca6f4e4dc26ae329e61&gt; is 4 hops away via &lt;56b115c30cd386cad69c&gt; on TCPInterface[Testnet/frankfurt.rns.unsigned.io:4965]
</pre></div>
</div>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnpath.py [-h] [--config CONFIG] [--version] [-v] [destination]
Reticulum Path Discovery Utility
positional arguments:
destination hexadecimal hash of the destination
optional arguments:
-h, --help show this help message and exit
--config CONFIG path to alternative Reticulum config directory
--version show program&#39;s version number and exit
-v, --verbose
</pre></div>
</div>
</div>
<div class="section" id="the-rnprobe-utility">
<h3>The rnprobe Utility<a class="headerlink" href="#the-rnprobe-utility" title="Permalink to this headline"></a></h3>
<p>The <code class="docutils literal notranslate"><span class="pre">rnprobe</span></code> utility lets you probe a destination for connectivity, similar
to the <code class="docutils literal notranslate"><span class="pre">ping</span></code> program. Please note that probes will only be answered if the
specified destination is configured to send proofs for received packets. Many
destinations will not have this option enabled, and will not be probable.</p>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span># Run rnprobe
python3 -m RNS.Utilities.rnprobe example_utilities.echo.request 9382f334de63217a4278
# Example output
Sent 16 byte probe to &lt;9382f334de63217a4278&gt;
Valid reply received from &lt;9382f334de63217a4278&gt;
Round-trip time is 38.469 milliseconds over 2 hops
</pre></div>
</div>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnprobe.py [-h] [--config CONFIG] [--version] [-v] [full_name] [destination_hash]
Reticulum Probe Utility
positional arguments:
full_name full destination name in dotted notation
destination_hash hexadecimal hash of the destination
optional arguments:
-h, --help show this help message and exit
--config CONFIG path to alternative Reticulum config directory
--version show program&#39;s version number and exit
-v, --verbose
</pre></div>
</div>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<h3><a href="index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Using Reticulum on Your System</a><ul>
<li><a class="reference internal" href="#included-utility-programs">Included Utility Programs</a><ul>
<li><a class="reference internal" href="#the-rnsd-utility">The rnsd Utility</a></li>
<li><a class="reference internal" href="#the-rnstatus-utility">The rnstatus Utility</a></li>
<li><a class="reference internal" href="#the-rnpath-utility">The rnpath Utility</a></li>
<li><a class="reference internal" href="#the-rnprobe-utility">The rnprobe Utility</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="gettingstartedfast.html"
title="previous chapter">Getting Started Fast</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="networks.html"
title="next chapter">Building Networks</a></p>
<div role="note" aria-label="source link">
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/using.rst.txt"
rel="nofollow">Show Source</a></li>
</ul>
</div>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="networks.html" title="Building Networks"
>next</a> |</li>
<li class="right" >
<a href="gettingstartedfast.html" title="Getting Started Fast"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Using Reticulum on Your System</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2021, Mark Qvist.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 4.0.1.
</div>
</body>
</html>
+12 -11
View File
@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>What is Reticulum? &#8212; Reticulum Network Stack 0.2.4 beta documentation</title>
<title>What is Reticulum? &#8212; Reticulum Network Stack 0.2.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -31,7 +31,7 @@
<li class="right" >
<a href="index.html" title="Reticulum Network Stack Manual"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">What is Reticulum?</a></li>
</ul>
</div>
@@ -45,15 +45,15 @@
<h1>What is Reticulum?<a class="headerlink" href="#what-is-reticulum" title="Permalink to this headline"></a></h1>
<p>Reticulum is a cryptography-based networking stack for wide-area networks built on readily available hardware, and can operate even with very high latency and extremely low bandwidth.</p>
<p>Reticulum allows you to build very wide-area networks with off-the-shelf tools, and offers end-to-end encryption, autoconfiguring cryptographically backed multi-hop transport, efficient addressing, unforgeable packet acknowledgements and more.</p>
<p>Reticulum is a complete networking stack, and does not use IP or higher layers, although it is easy to utilise IP (with TCP or UDP) as the underlying carrier for Reticulum. It is therefore trivial to tunnel Reticulum over the Internet or private IP networks. Reticulum is built directly on cryptographic principles, allowing resilience and stable functionality in open and trustless networks.</p>
<p>No kernel modules or drivers are required. Reticulum runs completely in userland, and can run on practically any system that runs Python 3.</p>
<p>Reticulum is a complete networking stack, and does not need IP or higher layers, although it is easy to utilise IP (with TCP or UDP) as the underlying carrier for Reticulum. It is therefore trivial to tunnel Reticulum over the Internet or private IP networks. Reticulum is built directly on cryptographic principles, allowing resilience and stable functionality in open and trustless networks.</p>
<p>No kernel modules or drivers are required. Reticulum runs completely in userland, and can run on practically any system that runs Python 3. Reticulum runs well even on small single-board computers like the Pi Zero.</p>
<div class="section" id="current-status">
<h2>Current Status<a class="headerlink" href="#current-status" title="Permalink to this headline"></a></h2>
<p>Reticulum should currently be considered beta software. All core protocol features are implemented and functioning, but additions will probably occur as real-world use is explored. There will be bugs. The API and wire-format can be considered relatively stable at the moment, but could change if warranted.</p>
</div>
<div class="section" id="caveat-emptor">
<h2>Caveat Emptor<a class="headerlink" href="#caveat-emptor" title="Permalink to this headline"></a></h2>
<p>Reticulum is an experimental networking stack, and should be considered as such. While it has been built with cryptography best-practices very foremost in mind, it has not been externally security audited, and there could very well be privacy-breaking bugs. To be considered even remotely secure, Reticulum needs a very thourough security review by independt cryptographers and security researchers. If you want to help out, or help sponsor an audit, please do get in touch.</p>
<p>Reticulum is an experimental networking stack, and should be considered as such. While it has been built with cryptography best-practices very foremost in mind, it has not been externally security audited, and there could very well be privacy-breaking bugs. To be considered secure, Reticulum needs a thourough security review by independt cryptographers and security researchers. If you want to help out, or help sponsor an audit, please do get in touch.</p>
</div>
<div class="section" id="what-does-reticulum-offer">
<h2>What does Reticulum Offer?<a class="headerlink" href="#what-does-reticulum-offer" title="Permalink to this headline"></a></h2>
@@ -62,12 +62,12 @@
<li><p>Fully self-configuring multi-hop routing</p></li>
<li><p>Asymmetric X25519 encryption and Ed25519 signatures as a basis for all communication</p></li>
<li><p>Forward Secrecy with ephemereal Elliptic Curve Diffie-Hellman keys on Curve25519</p></li>
<li><p>Reticulum uses the <a class="reference external" href="https://github.com/fernet/spec/blob/master/Spec.md">Fernet</a> specification for encryption</p>
<li><p>Reticulum uses the <a class="reference external" href="https://github.com/fernet/spec/blob/master/Spec.md">Fernet</a> specification for on-the-wire / over-the-air encryption</p>
<ul>
<li><p>All keys are ephemeral and derived from an ECDH key exchange on Curve25519</p></li>
<li><p>AES-128 in CBC mode with PKCS7 padding</p></li>
<li><p>HMAC using SHA256 for authentication</p></li>
<li><p>IVs are generated through os.urandom()</p></li>
<li><p>Keys are ephemeral and derived from an ECDH key exchange on Curve25519</p></li>
</ul>
</li>
<li><p>Unforgeable packet delivery confirmations</p></li>
@@ -110,8 +110,8 @@ configured, Reticulum will take care of the rest, and any device on the WiFi
network can communicate with nodes on the LoRa and packet radio sides of the
network, and vice versa.</p>
</div>
<div class="section" id="supported-interface-types-and-devices">
<h2>Supported Interface Types and Devices<a class="headerlink" href="#supported-interface-types-and-devices" title="Permalink to this headline"></a></h2>
<div class="section" id="interface-types-and-devices">
<h2>Interface Types and Devices<a class="headerlink" href="#interface-types-and-devices" title="Permalink to this headline"></a></h2>
<p>Reticulum implements a range of generalised interface types that covers most of the communications hardware that Reticulum can run over. If your hardware is not supported, its relatively simple to implement an interface class. Currently, the following interfaces are supported:</p>
<ul class="simple">
<li><p>Any ethernet device</p></li>
@@ -121,6 +121,7 @@ network, and vice versa.</p>
<li><p>TCP over IP networks</p></li>
<li><p>UDP over IP networks</p></li>
</ul>
<p>For a full list and more details, see the <a class="reference internal" href="interfaces.html#interfaces-main"><span class="std std-ref">Supported Interfaces</span></a> chapter.</p>
</div>
</div>
@@ -138,7 +139,7 @@ network, and vice versa.</p>
<li><a class="reference internal" href="#caveat-emptor">Caveat Emptor</a></li>
<li><a class="reference internal" href="#what-does-reticulum-offer">What does Reticulum Offer?</a></li>
<li><a class="reference internal" href="#where-can-reticulum-be-used">Where can Reticulum be Used?</a></li>
<li><a class="reference internal" href="#supported-interface-types-and-devices">Supported Interface Types and Devices</a></li>
<li><a class="reference internal" href="#interface-types-and-devices">Interface Types and Devices</a></li>
</ul>
</li>
</ul>
@@ -182,7 +183,7 @@ network, and vice versa.</p>
<li class="right" >
<a href="index.html" title="Reticulum Network Stack Manual"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.4 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.6 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">What is Reticulum?</a></li>
</ul>
</div>
+1 -1
View File
@@ -22,7 +22,7 @@ copyright = '2021, Mark Qvist'
author = 'Mark Qvist'
# The full version, including alpha/beta/rc tags
release = '0.2.4 beta'
release = '0.2.6 beta'
# -- General configuration ---------------------------------------------------
+4 -3
View File
@@ -1,8 +1,9 @@
.. _examples-main:
********
Examples
********
*************
Code Examples
*************
A number of examples are included in the source distribution of Reticulum.
You can use these examples to learn how to write your own programs.
+36 -3
View File
@@ -12,13 +12,46 @@ If you simply want to try using a program built with Reticulum, you can take
a look at `Nomad Network <https://github.com/markqvist/nomadnet>`_, which
provides a basic encrypted communications suite built completely on Reticulum.
.. image:: screenshots/nomadnet3.png
:target: _images/nomadnet3.png
.. image:: screenshots/nomadnet_3.png
:target: _images/nomadnet_3.png
`Nomad Network <https://github.com/markqvist/nomadnet>`_ is a user-facing client
in the development for the messaging and information-sharing protocol
`LXMF <https://github.com/markqvist/lxmf>`_, another project built with Reticulum.
You can install Nomad Network via pip:
.. code::
# Install ...
pip3 install nomadnet
# ... and run
nomadnet
Creating a Network With Reticulum
=============================================
To create a network, you will need to specify one or more *interfaces* for
Reticulum to use. This is done in the Reticulum configuration file, which by
default is located at ``~/.reticulum/config``.
When Reticulum is started for the first time, it will create a default
configuration file, with one active interface. This default interface uses
your existing ethernet network (if there is one), and only allows you to
communicate with other Reticulum peers within your local broadcast domain.
To communicate further, you will have to add one or more interfaces. The default
configuration includes a number of examples, ranging from using TCP over the
internet, to LoRa and Packet Radio interfaces.
Possibly, the examples in the config file are enough to get you started. If
you want more information, you can read the :ref:`Building Networks<networks-main>`
and :ref:`Interfaces<interfaces-main>` chapters of this manual.
Develop a Program with Reticulum
===========================================
If you want to develop programs that use Reticulum, the easiest way to get
@@ -44,7 +77,7 @@ don't use pip, but try this recipe:
.. code::
# Install dependencies
pip3 install cryptography pyserial
pip3 install cryptography pyserial netifaces
# Clone repository
git clone https://github.com/markqvist/Reticulum.git
+5 -2
View File
@@ -2,14 +2,17 @@
Reticulum Network Stack Manual
******************************
This manual aims to provide you with all the information you need to
understand Reticulum, develop programs using it, or to participate in
the development of Reticulum itself.
understand Reticulum, build networks or develop programs using it, or
to participate in the development of Reticulum itself.
.. toctree::
:maxdepth: 3
whatis
gettingstartedfast
using
networks
interfaces
understanding
reference
examples
+342
View File
@@ -0,0 +1,342 @@
.. _interfaces-main:
********************
Supported Interfaces
********************
Reticulum supports using many kinds of devices as networking interfaces, and
allows you to mix and match them in any way you choose. The number of distinct
network topologies you can create with Reticulum is more or less endless, but
common to them all is that you will need to define one or more *interfaces*
for Reticulum to use.
The following sections describe the interfaces currently available in Reticulum,
and gives example configurations for the respective interface types.
.. _interfaces-udp:
UDP Interface
=============
A UDP interface can be useful for communicating over IP networks, both
private and the internet. It can also allow broadcast communication
over IP networks, so it can provide an easy way to enable connectivity
with all other peers on a local area network.
The below example is enabled by default on new Reticulum installations,
as it provides an easy way to get started and to test Reticulum on a
pre-existing LAN.
.. code::
# This example enables communication with other
# local Reticulum peers over UDP.
[[Default UDP Interface]]
type = UDPInterface
interface_enabled = True
outgoing = True
listen_ip = 0.0.0.0
listen_port = 4242
forward_ip = 255.255.255.255
forward_port = 4242
# The above configuration will allow communication
# within the local broadcast domains of all local
# IP interfaces. This is enabled by default as an
# easy way to get started, but you might want to
# consider altering it to something more specific.
# Instead of specifying listen_ip, listen_port,
# forward_ip and forward_port, you can also bind
# to a specific network device like below.
# device = eth0
# port = 4242
# Assuming the eth0 device has the address
# 10.55.0.72/24, the above configuration would
# be equivalent to the following manual setup.
# Note that we are both listening and forwarding to
# the broadcast address of the network segments.
# listen_ip = 10.55.0.255
# listen_port = 4242
# forward_ip = 10.55.0.255
# forward_port = 4242
# You can of course also communicate only with
# a single IP address
# listen_ip = 10.55.0.15
# listen_port = 4242
# forward_ip = 10.55.0.16
# forward_port = 4242
.. _interfaces-tcps:
TCP Server Interface
====================
The TCP Server interface is suitable for allowing other peers to connect over
the Internet or private IP networks. When a TCP server interface has been
configured, other Reticulum peers can connect to it with a TCP Client interface.
.. code::
# This example demonstrates a TCP server interface.
# It will listen for incoming connections on the
# specified IP address and port number.
[[TCP Server Interface]]
type = TCPServerInterface
interface_enabled = True
outgoing = True
# This configuration will listen on all IP
# interfaces on port 4242
listen_ip = 0.0.0.0
listen_port = 4242
# Alternatively you can bind to a specific IP
# listen_ip = 10.0.0.88
# listen_port = 4242
# Or a specific network device
# device = eth0
# port = 4242
.. _interfaces-tcpc:
TCP Client Interface
====================
To connect to a TCP server interface, you would naturally use the TCP client
interface. Many TCP Client interfaces from different peers can connect to the
same TCP Server interface at the same time.
.. code::
# Here's an example of a TCP Client interface. The
# target_host can either be an IP address or a hostname.
[[TCP Client Interface]]
type = TCPClientInterface
interface_enabled = True
outgoing = True
target_host = 127.0.0.1
target_port = 4242
.. _interfaces-rnode:
RNode LoRa Interface
====================
To use Reticulum over LoRa, the `RNode <https://unsigned.io/rnode/>`_ interface
can be used, and offers full control over LoRa parameters.
.. code::
# Here's an example of how to add a LoRa interface
# using the RNode LoRa transceiver.
[[RNode LoRa Interface]]
type = RNodeInterface
# Enable interface if you want use it!
interface_enabled = True
# Allow transmit on interface. Setting
# this to false will create a listen-
# only interface.
outgoing = true
# Serial port for the device
port = /dev/ttyUSB0
# Set frequency to 867.2 MHz
frequency = 867200000
# Set LoRa bandwidth to 125 KHz
bandwidth = 125000
# Set TX power to 7 dBm (5 mW)
txpower = 7
# Select spreading factor 8. Valid
# range is 7 through 12, with 7
# being the fastest and 12 having
# the longest range.
spreadingfactor = 8
# Select coding rate 5. Valid range
# is 5 throough 8, with 5 being the
# fastest, and 8 the longest range.
codingrate = 5
# You can configure the RNode to send
# out identification on the channel with
# a set interval by configuring the
# following two parameters.
# id_callsign = MYCALL-0
# id_interval = 600
# For certain homebrew RNode interfaces
# with low amounts of RAM, using packet
# flow control can be useful. By default
# it is disabled.
flow_control = False
.. _interfaces-serial:
Serial Interface
================
Reticulum can be used over serial ports directly, or over any device with a
serial port, that will transparently pass data. Useful for communicating
directly over a wire-pair, or for using devices such as data radios and lasers.
.. code::
[[Serial Interface]]
type = SerialInterface
interface_enabled = True
outgoing = True
# Serial port for the device
port = /dev/ttyUSB0
# Set the serial baud-rate and other
# configuration parameters.
speed = 115200
databits = 8
parity = none
stopbits = 1
.. _interfaces-kiss:
KISS Interface
==============
With the KISS interface, you can use Reticulum over a variety of packet
radio modems and TNCs, including `OpenModem <https://unsigned.io/openmodem/>`_.
KISS interfaces can also be configured to periodically send out beacons
for station identification purposes.
.. code::
[[Packet Radio KISS Interface]]
type = KISSInterface
interface_enabled = True
outgoing = true
# Serial port for the device
port = /dev/ttyUSB1
# Set the serial baud-rate and other
# configuration parameters.
speed = 115200
databits = 8
parity = none
stopbits = 1
# Set the modem preamble.
preamble = 150
# Set the modem TX tail.
txtail = 10
# Configure CDMA parameters. These
# settings are reasonable defaults.
persistence = 200
slottime = 20
# You can configure the interface to send
# out identification on the channel with
# a set interval by configuring the
# following two parameters. The KISS
# interface will only ID if the set
# interval has elapsed since it's last
# actual transmission. The interval is
# configured in seconds.
# This option is commented out and not
# used by default.
# id_callsign = MYCALL-0
# id_interval = 600
# Whether to use KISS flow-control.
# This is useful for modems that have
# a small internal packet buffer, but
# support packet flow control instead.
flow_control = false
.. _interfaces-ax25:
AX.25 KISS Interface
====================
If you're using Reticulum on amateur radio spectrum, you might want to
use the AX.25 KISS interface. This way, Reticulum will automatically
encapsulate it's traffic in AX.25 and also identify your stations
transmissions with your callsign and SSID.
Only do this if you really need to! Reticulum doesn't need the AX.25
layer for anything, and it incurs extra overhead on every packet to
encapsulate in AX.25.
A more efficient way is to use the plain KISS interface with the
beaconing functionality described above.
.. code::
[[Packet Radio AX.25 KISS Interface]]
type = AX25KISSInterface
# Set the station callsign and SSID
callsign = NO1CLL
ssid = 0
# Enable interface if you want use it!
interface_enabled = True
# Allow transmit on interface.
outgoing = True
# Serial port for the device
port = /dev/ttyUSB2
# Set the serial baud-rate and other
# configuration parameters.
speed = 115200
databits = 8
parity = none
stopbits = 1
# Set the modem preamble. A 150ms
# preamble should be a reasonable
# default, but may need to be
# increased for radios with slow-
# opening squelch and long TX/RX
# turnaround
preamble = 150
# Set the modem TX tail. In most
# cases this should be kept as low
# as possible to not waste airtime.
txtail = 10
# Configure CDMA parameters. These
# settings are reasonable defaults.
persistence = 200
slottime = 20
# Whether to use KISS flow-control.
# This is useful for modems with a
# small internal packet buffer.
flow_control = false
+149
View File
@@ -0,0 +1,149 @@
.. _networks-main:
*****************
Building Networks
*****************
This chapter will provide you with the knowledge needed to build networks with
Reticulum, which can often be easier than using traditional stacks, since you
don't have to worry about coordinating addresses, subnets and routing for an
entire network that you might not know how will evolve in the future. With
Reticulum, you can simply add more segments to your network when it becomes
necesarry, and Reticulum will handle the convergence of the entire network
automatically.
Concepts & Overview
--------------------
There are important points that need to be kept in mind when building networks
with Reticulum:
* | In a Reticulum network, any node can autonomously generate as many adresses
(called *destinations* in Reticulum terminology) as it needs, which become
globally reachable to the rest of the network. There is no central point of
control over the adress space.
* | Reticulum was designed to handle both very small, and very large networks.
While the adress space can support billions of endpoints, Reticulum is
also very useful when just a few devices needs to communicate.
* | Reticulum provides sender/initiator anonymity by default. There is no way
to filter traffic or discriminate it based on the source of the traffic.
* | All traffic is encrypted using ephemeral keys generated by an Elliptic Curve
Diffie-Hellman key exchange on Curve25519. There is no way to inspect traffic
contents, and no way to prioritise or throttle certain kinds of traffic.
All transport and routing layers are thus completely agnostic to traffic type,
and will pass all traffic equally.
* | Reticulum can function both with and without infrastructure. When *transport
nodes* are available, they can route traffic over multiple hops for other
nodes, and will function as a distributed cryptographic keystore. When there
is no transport nodes available, all nodes that are within communication range
can still communicate.
* | Every node can become a transport node, simply by enabling it in it's
configuration, but there is no need for every node on the network to be a
transport node. Letting every node be a transport node will in most cases
degrade the performance and reliability of the network.
In general terms, if a node is stationary, well-connected and kept running
most of the time, it is a good candidate to be a transport node. For optimal
performance, a network should contain the amount of transport nodes that
provides connectivity to the intended area / topography, and not many more
than that.
Reticulum allows you to mix very different kinds of networking mediums into a
unified mesh, or to keep everything within one medium. You could build a "virtual
network" running entirely over the Internet, where all nodes communicate over TCP
and UDP "channels". You could also build such a network using MQTT or ZeroMQ as
the underlying carrier for Reticulum.
However, most real-world networks will probably involve either some form of
wireless or direct hardline communications. To allow Reticulum to communicate
over any type of medium, you must specify it in the configuration file, by default
located at ``~/.reticulum/config``.
Any number of interfaces can be configured, and Reticulum will automatically
decide which are suitable to use in any given situation, depending on where
traffic needs to flow.
Example Scenarios
-----------------
This section illustrates a few example scenarios, and how they would, in general
terms, be planned, implemented and configured.
Interconnected LoRa Sites
=========================
An organisation wants to provide communication and information services to it's
members, which are located mainly in three separate areas. Three suitable hill-top
locations are found, where the organisation can install equipment: Site A, B and C.
Since the amount of data that needs to be exchanged between users is mainly text-
based, the bandwidth requirements are low, and LoRa radios are chosen to connect
users to the network.
Due to the hill-top locations found, there is radio line-of-sight between site A
and B, and also between site B and C. Because of this, the organisation does not
need to use the Internet to interconnect the sites, but purchases four Point-to-Point
WiFi based radios for interconnecting the sites.
At each site, a Raspberry Pi is installed to function as a gateway. A LoRa radio
is connected to the Pi with a USB cable, and the WiFi radio is connected to the
ethernet port of the Pi. At site B, two WiFi radios are needed to be able to reach
both site A and site C, so an extra ethernet adapter is connected to the Pi in
this location.
Once the hardware has been installed, Reticulum is installed on all the Pis, and at
site A and C, one interface is added for the LoRa radio, as well as one for the WiFi
radio. At site B, an interface for the LoRa radio, and one interface for each WiFi
radio is added to the Reticulum configuration file. The transport node option is
enabled in the configuration of all three gateways.
The network is now operational, and ready to serve users across all three areas.
The organisation prepares a LoRa radio that is supplied to the end users, along
with a Reticulum configuration file, that contains the right parameters for
communicating with the LoRa radios installed at the gateway sites.
Once users connect to the network, anyone will be able to communicate with anyone
else across all three sites.
Bridging Over the Internet
==========================
As the organisation grows, several new communities form in places too far away
from the core network to be reachable over WiFi links. New gateways similar to those
previously installed are set up for the new communities at the new sites D and E, but
they are islanded from the core network, and only serve the local users.
After investigating the options, it is found that it is possible to install an
Internet connection at site A, and an interface on the Internet connection is
configured for Reticulum on the Raspberry Pi at site A.
A member of the organisation at site D, named Dori, is willing to help by sharing
the Internet connection she already has in her home, and is able to leave a Raspberry
Pi running. A new Reticulum interface is configured on her Pi, connecting to the newly
enabled Internet interface on the gateway at site A. Dori is now connected to both
all the nodes at her own local site (through the hill-top LoRa gateway), and all the
combined users of sites A, B and C. She then enables transport on her node, and
traffic from site D can now reach everyone at site A, B and C, and vice versa.
Growth and Convergence
======================
As the organisation grows, more gateways are added to keep up with the growing user
base. Some local gateways even add VHF radios and packet modems to reach outlying users
and communities that are out of reach for the LoRa radios and WiFi backhauls.
As more sites, gateways and users are connected, the amount of coordination required
is kept to a minimum. If one community wants to add connectivity to the next one
over, it can simply be done without having to involve everyone or coordinate address
space or routing tables.
With the added geographical coverage, the operators at site A one day find that
the original internet bridged interfaces are no longer utilised. The network has
converged to be completely self-connected, and the sites that were once poorly
connected outliers are now an integral part of the network.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

+1 -1
View File
@@ -52,7 +52,7 @@ by using multiple hops).
Goals
=====
To be as widely usable and easy to implement as possible, the following goals have been used to
To be as widely usable and easy to use as possible, the following goals have been used to
guide the design of Reticulum:
+165
View File
@@ -0,0 +1,165 @@
.. _using-main:
******************************
Using Reticulum on Your System
******************************
Reticulum is not installed as a driver or kernel module, as one might expect
of a networking stack. Instead, Reticulum is distributed as a Python module.
This means that no special privileges are required to install or use it.
Any program or application that uses Reticulum will automatically load and
initialise Reticulum when it starts.
In many cases, this approach is sufficient. When any program needs to use
Reticulum, it is loaded, initialised, interfaces are brought up, and the
program can now communicate over Reticulum. If another program starts up
and also wants access to the same Reticulum network, the instance is simply
shared. This works for any number of programs running concurrently, and is
very easy to use, but depending on your use case, there are other options.
Included Utility Programs
-------------------------
If you often use Reticulum from several different programs, or simply want
Reticulum to stay available all the time, for example if you are hosting
a transport node, you might want to run Reticulum as a separate service that
other programs, applications and services can utilise.
The rnsd Utility
================
To do so is very easy. Simply run the included ``rnsd`` command. When ``rnsd``
is running, it will keep all configured interfaces open, handle transport if
it is enabled, and allow any other programs to immediately utilise the
Reticulum network it is configured for.
You can even run multiple instances of rnsd with different configurations on
the same system.
.. code:: text
# Install Reticulum
pip3 install rns
# Run rnsd
rnsd
.. code:: text
usage: rnsd [-h] [--config CONFIG] [-v] [-q] [--version]
Reticulum Network Stack Daemon
optional arguments:
-h, --help show this help message and exit
--config CONFIG path to alternative Reticulum config directory
-v, --verbose
-q, --quiet
--version show program's version number and exit
The rnstatus Utility
====================
Using the ``rnstatus`` utility, you can view the status of configured Reticulum
interfaces, similar to the ``ifconfig`` program.
.. code:: text
# Run rnstatus
rnstatus
# Example output
Shared Instance[37428]
Status: Up
Connected applications: 1
RX: 1.13 KB
TX: 1.07 KB
UDPInterface[Default UDP Interface/0.0.0.0:4242]
Status: Up
RX: 1.01 KB
TX: 1.01 KB
TCPInterface[RNS Testnet Frankfurt/frankfurt.rns.unsigned.io:4965]
Status: Up
RX: 1.37 KB
TX: 9.02 KB
.. code:: text
usage: rnsd [-h] [--config CONFIG] [-v] [-q] [--version]
Reticulum Network Stack Daemon
optional arguments:
-h, --help show this help message and exit
--config CONFIG path to alternative Reticulum config directory
-v, --verbose
-q, --quiet
--version show program's version number and exit
The rnpath Utility
====================
With the ``rnpath`` utility, you can look up and view paths for
destinations on the Reticulum network.
.. code:: text
# Run rnpath
rnpath eca6f4e4dc26ae329e61
# Example output
Path found, destination <eca6f4e4dc26ae329e61> is 4 hops away via <56b115c30cd386cad69c> on TCPInterface[Testnet/frankfurt.rns.unsigned.io:4965]
.. code:: text
usage: rnpath.py [-h] [--config CONFIG] [--version] [-v] [destination]
Reticulum Path Discovery Utility
positional arguments:
destination hexadecimal hash of the destination
optional arguments:
-h, --help show this help message and exit
--config CONFIG path to alternative Reticulum config directory
--version show program's version number and exit
-v, --verbose
The rnprobe Utility
====================
The ``rnprobe`` utility lets you probe a destination for connectivity, similar
to the ``ping`` program. Please note that probes will only be answered if the
specified destination is configured to send proofs for received packets. Many
destinations will not have this option enabled, and will not be probable.
.. code:: text
# Run rnprobe
python3 -m RNS.Utilities.rnprobe example_utilities.echo.request 9382f334de63217a4278
# Example output
Sent 16 byte probe to <9382f334de63217a4278>
Valid reply received from <9382f334de63217a4278>
Round-trip time is 38.469 milliseconds over 2 hops
.. code:: text
usage: rnprobe.py [-h] [--config CONFIG] [--version] [-v] [full_name] [destination_hash]
Reticulum Probe Utility
positional arguments:
full_name full destination name in dotted notation
destination_hash hexadecimal hash of the destination
optional arguments:
-h, --help show this help message and exit
--config CONFIG path to alternative Reticulum config directory
--version show program's version number and exit
-v, --verbose
+11 -9
View File
@@ -6,9 +6,9 @@ Reticulum is a cryptography-based networking stack for wide-area networks built
Reticulum allows you to build very wide-area networks with off-the-shelf tools, and offers end-to-end encryption, autoconfiguring cryptographically backed multi-hop transport, efficient addressing, unforgeable packet acknowledgements and more.
Reticulum is a complete networking stack, and does not use IP or higher layers, although it is easy to utilise IP (with TCP or UDP) as the underlying carrier for Reticulum. It is therefore trivial to tunnel Reticulum over the Internet or private IP networks. Reticulum is built directly on cryptographic principles, allowing resilience and stable functionality in open and trustless networks.
Reticulum is a complete networking stack, and does not need IP or higher layers, although it is easy to utilise IP (with TCP or UDP) as the underlying carrier for Reticulum. It is therefore trivial to tunnel Reticulum over the Internet or private IP networks. Reticulum is built directly on cryptographic principles, allowing resilience and stable functionality in open and trustless networks.
No kernel modules or drivers are required. Reticulum runs completely in userland, and can run on practically any system that runs Python 3.
No kernel modules or drivers are required. Reticulum runs completely in userland, and can run on practically any system that runs Python 3. Reticulum runs well even on small single-board computers like the Pi Zero.
Current Status
@@ -18,7 +18,7 @@ Reticulum should currently be considered beta software. All core protocol featur
Caveat Emptor
==============
Reticulum is an experimental networking stack, and should be considered as such. While it has been built with cryptography best-practices very foremost in mind, it has not been externally security audited, and there could very well be privacy-breaking bugs. To be considered even remotely secure, Reticulum needs a very thourough security review by independt cryptographers and security researchers. If you want to help out, or help sponsor an audit, please do get in touch.
Reticulum is an experimental networking stack, and should be considered as such. While it has been built with cryptography best-practices very foremost in mind, it has not been externally security audited, and there could very well be privacy-breaking bugs. To be considered secure, Reticulum needs a thourough security review by independt cryptographers and security researchers. If you want to help out, or help sponsor an audit, please do get in touch.
What does Reticulum Offer?
@@ -31,7 +31,9 @@ What does Reticulum Offer?
* Forward Secrecy with ephemereal Elliptic Curve Diffie-Hellman keys on Curve25519
* Reticulum uses the `Fernet <https://github.com/fernet/spec/blob/master/Spec.md>`_ specification for encryption
* Reticulum uses the `Fernet <https://github.com/fernet/spec/blob/master/Spec.md>`_ specification for on-the-wire / over-the-air encryption
* All keys are ephemeral and derived from an ECDH key exchange on Curve25519
* AES-128 in CBC mode with PKCS7 padding
@@ -39,8 +41,6 @@ What does Reticulum Offer?
* IVs are generated through os.urandom()
* Keys are ephemeral and derived from an ECDH key exchange on Curve25519
* Unforgeable packet delivery confirmations
* A variety of supported interface types
@@ -87,8 +87,8 @@ configured, Reticulum will take care of the rest, and any device on the WiFi
network can communicate with nodes on the LoRa and packet radio sides of the
network, and vice versa.
Supported Interface Types and Devices
=====================================
Interface Types and Devices
===========================
Reticulum implements a range of generalised interface types that covers most of the communications hardware that Reticulum can run over. If your hardware is not supported, it's relatively simple to implement an interface class. Currently, the following interfaces are supported:
* Any ethernet device
@@ -101,4 +101,6 @@ Reticulum implements a range of generalised interface types that covers most of
* TCP over IP networks
* UDP over IP networks
* UDP over IP networks
For a full list and more details, see the :ref:`Supported Interfaces<interfaces-main>` chapter.
+9
View File
@@ -20,6 +20,15 @@ setuptools.setup(
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
entry_points= {
'console_scripts': [
'rnsd=RNS.Utilities.rnsd:main',
'rnstatus=RNS.Utilities.rnstatus:main',
'rnprobe=RNS.Utilities.rnprobe:main',
'rnpath=RNS.Utilities.rnpath:main',
]
},
install_requires=['cryptography>=3.4.7', 'pyserial', 'netifaces>=0.10.4'],
python_requires='>=3.6',
)