Compare commits

..

30 Commits

Author SHA1 Message Date
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
37 changed files with 460 additions and 87 deletions
+2 -2
View File
@@ -20,11 +20,11 @@ For more info, see [unsigned.io/projects/reticulum](https://unsigned.io/projects
- Fully self-configuring multi-hop routing - Fully self-configuring multi-hop routing
- Asymmetric X25519 encryption and Ed25519 signatures as a basis for all communication - Asymmetric X25519 encryption and Ed25519 signatures as a basis for all communication
- Forward Secrecy with ephemereal Elliptic Curve Diffie-Hellman keys on Curve25519 - 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 - AES-128 in CBC mode with PKCS7 padding
- HMAC using SHA256 for authentication - HMAC using SHA256 for authentication
- IVs are generated through os.urandom() - IVs are generated through os.urandom()
- Keys are ephemeral and derived from an ECDH key exchange on Curve25519
- Unforgeable packet delivery confirmations - Unforgeable packet delivery confirmations
- A variety of supported interface types - A variety of supported interface types
- An intuitive and easy-to-use API - An intuitive and easy-to-use API
+4 -1
View File
@@ -301,7 +301,10 @@ class AX25KISSInterface(Interface):
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) 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): def __str__(self):
return "AX25KISSInterface["+self.name+"]" return "AX25KISSInterface["+self.name+"]"
+4 -1
View File
@@ -277,7 +277,10 @@ class KISSInterface(Interface):
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) 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): def __str__(self):
return "KISSInterface["+self.name+"]" return "KISSInterface["+self.name+"]"
+4
View File
@@ -127,6 +127,10 @@ class LocalClientInterface(Interface):
if self in RNS.Transport.local_client_interfaces: if self in RNS.Transport.local_client_interfaces:
RNS.Transport.local_client_interfaces.remove(self) RNS.Transport.local_client_interfaces.remove(self)
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): def __str__(self):
return "LocalInterface["+str(self.target_port)+"]" return "LocalInterface["+str(self.target_port)+"]"
+4 -1
View File
@@ -463,7 +463,10 @@ class RNodeInterface(Interface):
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) 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): def __str__(self):
return "RNodeInterface["+self.name+"]" return "RNodeInterface["+self.name+"]"
+4 -1
View File
@@ -130,7 +130,10 @@ class SerialInterface(Interface):
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log("A serial port error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) 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): def __str__(self):
return "SerialInterface["+self.name+"]" return "SerialInterface["+self.name+"]"
+51 -4
View File
@@ -23,13 +23,21 @@ class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass pass
class TCPClientInterface(Interface): class TCPClientInterface(Interface):
RECONNECT_WAIT = 5
RECONNECT_MAX_TRIES = None
def __init__(self, owner, name, target_ip=None, target_port=None, connected_socket=None): def __init__(self, owner, name, target_ip=None, target_port=None, connected_socket=None, max_reconnect_tries=None):
self.IN = True self.IN = True
self.OUT = False self.OUT = False
self.socket = None self.socket = None
self.parent_interface = None self.parent_interface = None
self.name = name self.name = name
self.initiator = 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: if connected_socket != None:
self.receives = True self.receives = True
@@ -50,9 +58,42 @@ class TCPClientInterface(Interface):
self.writing = False self.writing = False
if connected_socket == None: if connected_socket == None:
self.initiator = True
thread = threading.Thread(target=self.read_loop) thread = threading.Thread(target=self.read_loop)
thread.setDaemon(True) thread.setDaemon(True)
thread.start() thread.start()
self.wants_tunnel = True
def reconnect(self):
if self.initiator:
attempts = 0
while not self.online:
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.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((self.target_ip, self.target_port))
self.online = True
self.writing = False
thread = threading.Thread(target=self.read_loop)
thread.setDaemon(True)
thread.start()
RNS.Transport.synthesize_tunnel(self)
except Exception as e:
RNS.log("Reconnection attempt for "+str(self)+" failed. The contained exception was: "+str(e), RNS.LOG_ERROR)
time.sleep(TCPClientInterface.RECONNECT_WAIT)
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): def processIncoming(self, data):
self.owner.inbound(data, self) self.owner.inbound(data, self)
@@ -104,24 +145,30 @@ class TCPClientInterface(Interface):
escape = False escape = False
data_buffer = data_buffer+bytes([byte]) data_buffer = data_buffer+bytes([byte])
else: else:
RNS.log("TCP socket for "+str(self)+" was closed, tearing down interface", RNS.LOG_VERBOSE) RNS.log("TCP socket for "+str(self)+" was closed, attempting to reconnect...", RNS.LOG_WARNING)
self.teardown() self.online = False
if self.initiator:
self.reconnect()
break break
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log("An interface error occurred, the contained exception was: "+str(e), RNS.LOG_ERROR) 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() self.teardown()
def teardown(self): def teardown(self):
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)
self.online = False self.online = False
self.OUT = False self.OUT = False
self.IN = False self.IN = False
if self in RNS.Transport.interfaces: if self in RNS.Transport.interfaces:
RNS.Transport.interfaces.remove(self) RNS.Transport.interfaces.remove(self)
if RNS.Reticulum.panic_on_interface_error:
RNS.panic()
def __str__(self): def __str__(self):
return "TCPInterface["+str(self.name)+"/"+str(self.target_ip)+":"+str(self.target_port)+"]" return "TCPInterface["+str(self.name)+"/"+str(self.target_ip)+":"+str(self.target_port)+"]"
+5
View File
@@ -419,6 +419,11 @@ class Link:
self.shared_key = None self.shared_key = None
self.derived_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: if self.callbacks.link_closed != None:
self.callbacks.link_closed(self) self.callbacks.link_closed(self)
+18 -4
View File
@@ -98,6 +98,8 @@ class Reticulum:
Reticulum.__transport_enabled = False Reticulum.__transport_enabled = False
Reticulum.__use_implicit_proof = True Reticulum.__use_implicit_proof = True
Reticulum.panic_on_interface_error = False
self.local_interface_port = 37428 self.local_interface_port = 37428
self.share_instance = True self.share_instance = True
@@ -195,6 +197,10 @@ class Reticulum:
v = self.config["reticulum"].as_bool(option) v = self.config["reticulum"].as_bool(option)
if v == True: if v == True:
Reticulum.__transport_enabled = 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": if option == "use_implicit_proof":
v = self.config["reticulum"].as_bool(option) v = self.config["reticulum"].as_bool(option)
if v == True: if v == True:
@@ -305,7 +311,7 @@ class Reticulum:
stopbits stopbits
) )
if "outgoing" in c and c["outgoing"].lower() == "true": if "outgoing" in c and c.as_bool("outgoing") == True:
interface.OUT = True interface.OUT = True
else: else:
interface.OUT = False interface.OUT = False
@@ -346,7 +352,7 @@ class Reticulum:
beacon_data beacon_data
) )
if "outgoing" in c and c["outgoing"].lower() == "true": if "outgoing" in c and c.as_bool("outgoing") == True:
interface.OUT = True interface.OUT = True
else: else:
interface.OUT = False interface.OUT = False
@@ -388,7 +394,7 @@ class Reticulum:
flow_control flow_control
) )
if "outgoing" in c and c["outgoing"].lower() == "true": if "outgoing" in c and c.as_bool("outgoing") == True:
interface.OUT = True interface.OUT = True
else: else:
interface.OUT = False interface.OUT = False
@@ -424,7 +430,7 @@ class Reticulum:
id_callsign = id_callsign 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 interface.OUT = True
else: else:
interface.OUT = False interface.OUT = False
@@ -510,6 +516,14 @@ share_instance = Yes
shared_instance_port = 37428 shared_instance_port = 37428
# 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] [logging]
# Valid log levels are 0 through 7: # Valid log levels are 0 through 7:
+267 -8
View File
@@ -10,8 +10,8 @@ from .vendor import umsgpack as umsgpack
class Transport: class Transport:
""" """
Through static methods of this class you can interact with Reticulums Through static methods of this class you can interact with the
Transport system. Transport system of Reticulum.
""" """
# Constants # Constants
BROADCAST = 0x00; BROADCAST = 0x00;
@@ -34,7 +34,7 @@ class Transport:
PATHFINDER_R = 1 # Retransmit retries PATHFINDER_R = 1 # Retransmit retries
PATHFINDER_T = 10 # Retry grace period PATHFINDER_T = 10 # Retry grace period
PATHFINDER_RW = 10 # Random window for announce rebroadcast PATHFINDER_RW = 10 # Random window for announce rebroadcast
PATHFINDER_E = 60*15 # Path expiration in seconds PATHFINDER_E = 60*60*24*7 # Path expiration in seconds
# TODO: Calculate an optimal number for this in # TODO: Calculate an optimal number for this in
# various situations # various situations
@@ -45,7 +45,7 @@ class Transport:
LINK_TIMEOUT = RNS.Link.KEEPALIVE * 2 LINK_TIMEOUT = RNS.Link.KEEPALIVE * 2
REVERSE_TIMEOUT = 30*60 # Reverse table entries are removed after max 30 minutes 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 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 MAX_RECEIPTS = 1024 # Maximum number of receipts to keep track of
interfaces = [] # All active interfaces interfaces = [] # All active interfaces
@@ -64,6 +64,7 @@ class Transport:
link_table = {} # A lookup table containing hops for links link_table = {} # A lookup table containing hops for links
held_announces = {} # A table containing temporarily held announce-table entries held_announces = {} # A table containing temporarily held announce-table entries
announce_handlers = [] # A table storing externally registered announce handlers announce_handlers = [] # A table storing externally registered announce handlers
tunnels = {} # A table storing tunnels to other transport instances
# Transport control destinations are used # Transport control destinations are used
# for control purposes like path requests # for control purposes like path requests
@@ -119,12 +120,19 @@ class Transport:
Transport.control_destinations.append(Transport.path_request_destination) Transport.control_destinations.append(Transport.path_request_destination)
Transport.control_hashes.append(Transport.path_request_destination.hash) 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 = threading.Thread(target=Transport.jobloop)
thread.setDaemon(True) thread.setDaemon(True)
thread.start() thread.start()
if RNS.Reticulum.transport_enabled(): if RNS.Reticulum.transport_enabled():
destination_table_path = RNS.Reticulum.storagepath+"/destination_table" 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: if os.path.isfile(destination_table_path) and not Transport.owner.is_connected_to_shared_instance:
serialised_destinations = [] serialised_destinations = []
try: try:
@@ -168,8 +176,64 @@ class Transport:
except Exception as e: except Exception as e:
RNS.log("Could not load destination table from storage, the contained exception was: "+str(e), RNS.LOG_ERROR) RNS.log("Could not load destination table from storage, the contained exception was: "+str(e), RNS.LOG_ERROR)
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("Transport instance "+str(Transport.identity)+" started")
# 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 @staticmethod
def jobloop(): def jobloop():
while (True): while (True):
@@ -279,11 +343,41 @@ class Transport:
if time.time() > destination_entry[0] + Transport.DESTINATION_TIMEOUT: if time.time() > destination_entry[0] + Transport.DESTINATION_TIMEOUT:
stale_paths.append(destination_hash) stale_paths.append(destination_hash)
RNS.log("Path to "+RNS.prettyhexrep(destination_hash)+" timed out and was removed", RNS.LOG_DEBUG) RNS.log("Path to "+RNS.prettyhexrep(destination_hash)+" timed out and was removed", RNS.LOG_DEBUG)
elif not attached_interface in Transport.interfaces:
if not attached_interface in Transport.interfaces:
stale_paths.append(destination_hash) 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) 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 i = 0
for link_id in stale_links: for link_id in stale_links:
Transport.link_table.pop(link_id) Transport.link_table.pop(link_id)
@@ -306,6 +400,17 @@ class Transport:
else: else:
RNS.log("Removed "+str(i)+" paths", RNS.LOG_DEBUG) 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() Transport.tables_last_culled = time.time()
except Exception as e: except Exception as e:
@@ -395,6 +500,7 @@ class Transport:
if should_transmit: if should_transmit:
if not stored_hash: if not stored_hash:
Transport.packet_hashlist.append(packet.packet_hash) Transport.packet_hashlist.append(packet.packet_hash)
stored_hash = True
interface.processOutgoing(packet.raw) interface.processOutgoing(packet.raw)
sent = True sent = True
@@ -768,10 +874,20 @@ class Transport:
new_announce.hops = packet.hops new_announce.hops = packet.hops
new_announce.send() new_announce.send()
destination_table_entry = [now, received_from, announce_hops, expires, random_blobs, packet.receiving_interface, packet]
Transport.destination_table[packet.destination_hash] = [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) 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 # Call externally registered callbacks from apps
# wanting to know when an announce arrives # wanting to know when an announce arrives
for handler in Transport.announce_handlers: for handler in Transport.announce_handlers:
@@ -898,6 +1014,97 @@ class Transport:
Transport.jobs_locked = False 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_VERBOSE)
@staticmethod @staticmethod
def register_destination(destination): def register_destination(destination):
destination.MTU = RNS.Reticulum.MTU destination.MTU = RNS.Reticulum.MTU
@@ -1237,3 +1444,55 @@ class Transport:
RNS.log("Done saving "+str(len(serialised_destinations))+" path table entries to storage", RNS.LOG_VERBOSE) RNS.log("Done saving "+str(len(serialised_destinations))+" path table entries to storage", RNS.LOG_VERBOSE)
except Exception as e: except Exception as e:
RNS.log("Could not save path table to storage, the contained exception was: "+str(e), RNS.LOG_ERROR) 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)
+1 -1
View File
@@ -1 +1 @@
__version__ = "0.2.4" __version__ = "0.2.5"
Binary file not shown.
+1 -1
View File
@@ -1,4 +1,4 @@
# Sphinx build info version 1 # 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. # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: eda3a1317314f558917722e3479f8836 config: ca50760ac810704080bd9b8fd39823dc
tags: 645f666f9bcd5a90fca523b33c5a78b7 tags: 645f666f9bcd5a90fca523b33c5a78b7
Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

@@ -12,13 +12,25 @@ 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 a look at `Nomad Network <https://github.com/markqvist/nomadnet>`_, which
provides a basic encrypted communications suite built completely on Reticulum. provides a basic encrypted communications suite built completely on Reticulum.
.. image:: screenshots/nomadnet3.png .. image:: screenshots/nomadnet_3.png
:target: _images/nomadnet3.png :target: _images/nomadnet_3.png
`Nomad Network <https://github.com/markqvist/nomadnet>`_ is a user-facing client `Nomad Network <https://github.com/markqvist/nomadnet>`_ is a user-facing client
in the development for the messaging and information-sharing protocol in the development for the messaging and information-sharing protocol
`LXMF <https://github.com/markqvist/lxmf>`_, another project built with Reticulum. `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
Develop a Program with Reticulum Develop a Program with Reticulum
=========================================== ===========================================
If you want to develop programs that use Reticulum, the easiest way to get If you want to develop programs that use Reticulum, the easiest way to get
+3 -3
View File
@@ -31,7 +31,9 @@ What does Reticulum Offer?
* Forward Secrecy with ephemereal Elliptic Curve Diffie-Hellman keys on Curve25519 * 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 * AES-128 in CBC mode with PKCS7 padding
@@ -39,8 +41,6 @@ What does Reticulum Offer?
* IVs are generated through os.urandom() * IVs are generated through os.urandom()
* Keys are ephemeral and derived from an ECDH key exchange on Curve25519
* Unforgeable packet delivery confirmations * Unforgeable packet delivery confirmations
* A variety of supported interface types * A variety of supported interface types
+1 -1
View File
@@ -1,6 +1,6 @@
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
VERSION: '0.2.4 beta', VERSION: '0.2.5 beta',
LANGUAGE: 'None', LANGUAGE: 'None',
COLLAPSE_INDEX: false, COLLAPSE_INDEX: false,
BUILDER: 'html', BUILDER: 'html',
+3 -3
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Examples &#8212; Reticulum Network Stack 0.2.4 beta documentation</title> <title>Examples &#8212; Reticulum Network Stack 0.2.5 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -27,7 +27,7 @@
<li class="right" > <li class="right" >
<a href="reference.html" title="API Reference" <a href="reference.html" title="API Reference"
accesskey="P">previous</a> |</li> 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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Examples</a></li> <li class="nav-item nav-item-this"><a href="">Examples</a></li>
</ul> </ul>
</div> </div>
@@ -2319,7 +2319,7 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
<li class="right" > <li class="right" >
<a href="reference.html" title="API Reference" <a href="reference.html" title="API Reference"
>previous</a> |</li> >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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Examples</a></li> <li class="nav-item nav-item-this"><a href="">Examples</a></li>
</ul> </ul>
</div> </div>
+3 -3
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <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.5 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -23,7 +23,7 @@
<li class="right" style="margin-right: 10px"> <li class="right" style="margin-right: 10px">
<a href="#" title="General Index" <a href="#" title="General Index"
accesskey="I">index</a></li> 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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Index</a></li> <li class="nav-item nav-item-this"><a href="">Index</a></li>
</ul> </ul>
</div> </div>
@@ -412,7 +412,7 @@
<li class="right" style="margin-right: 10px"> <li class="right" style="margin-right: 10px">
<a href="#" title="General Index" <a href="#" title="General Index"
>index</a></li> >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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Index</a></li> <li class="nav-item nav-item-this"><a href="">Index</a></li>
</ul> </ul>
</div> </div>
+12 -4
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <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.5 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -31,7 +31,7 @@
<li class="right" > <li class="right" >
<a href="whatis.html" title="What is Reticulum?" <a href="whatis.html" title="What is Reticulum?"
accesskey="P">previous</a> |</li> 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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Getting Started Fast</a></li> <li class="nav-item nav-item-this"><a href="">Getting Started Fast</a></li>
</ul> </ul>
</div> </div>
@@ -51,10 +51,18 @@ scenarios.</p>
<p>If you simply want to try using a program built with Reticulum, you can take <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 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> 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 <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 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> <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>
<div class="section" id="develop-a-program-with-reticulum"> <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> <h2>Develop a Program with Reticulum<a class="headerlink" href="#develop-a-program-with-reticulum" title="Permalink to this headline"></a></h2>
@@ -166,7 +174,7 @@ dont use pip, but try this recipe:</p>
<li class="right" > <li class="right" >
<a href="whatis.html" title="What is Reticulum?" <a href="whatis.html" title="What is Reticulum?"
>previous</a> |</li> >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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Getting Started Fast</a></li> <li class="nav-item nav-item-this"><a href="">Getting Started Fast</a></li>
</ul> </ul>
</div> </div>
+3 -3
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <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.5 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -27,7 +27,7 @@
<li class="right" > <li class="right" >
<a href="whatis.html" title="What is Reticulum?" <a href="whatis.html" title="What is Reticulum?"
accesskey="N">next</a> |</li> 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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Reticulum Network Stack Manual</a></li> <li class="nav-item nav-item-this"><a href="">Reticulum Network Stack Manual</a></li>
</ul> </ul>
</div> </div>
@@ -168,7 +168,7 @@ the development of Reticulum itself.</p>
<li class="right" > <li class="right" >
<a href="whatis.html" title="What is Reticulum?" <a href="whatis.html" title="What is Reticulum?"
>next</a> |</li> >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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Reticulum Network Stack Manual</a></li> <li class="nav-item nav-item-this"><a href="">Reticulum Network Stack Manual</a></li>
</ul> </ul>
</div> </div>
+5 -5
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <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.5 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -31,7 +31,7 @@
<li class="right" > <li class="right" >
<a href="understanding.html" title="Understanding Reticulum" <a href="understanding.html" title="Understanding Reticulum"
accesskey="P">previous</a> |</li> 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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">API Reference</a></li> <li class="nav-item nav-item-this"><a href="">API Reference</a></li>
</ul> </ul>
</div> </div>
@@ -1072,8 +1072,8 @@ the resource advertisement it will begin transferring.</p>
<dl class="py class"> <dl class="py class">
<dt class="sig sig-object py" id="RNS.Transport"> <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> <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 <dd><p>Through static methods of this class you can interact with the
Transport system.</p> Transport system of Reticulum.</p>
<dl class="py attribute"> <dl class="py attribute">
<dt class="sig sig-object py" id="RNS.Transport.PATHFINDER_M"> <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> <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>
@@ -1212,7 +1212,7 @@ will announce it.</p>
<li class="right" > <li class="right" >
<a href="understanding.html" title="Understanding Reticulum" <a href="understanding.html" title="Understanding Reticulum"
>previous</a> |</li> >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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">API Reference</a></li> <li class="nav-item nav-item-this"><a href="">API Reference</a></li>
</ul> </ul>
</div> </div>
+3 -3
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <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.5 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -29,7 +29,7 @@
<li class="right" style="margin-right: 10px"> <li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index" <a href="genindex.html" title="General Index"
accesskey="I">index</a></li> 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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Search</a></li> <li class="nav-item nav-item-this"><a href="">Search</a></li>
</ul> </ul>
</div> </div>
@@ -85,7 +85,7 @@
<li class="right" style="margin-right: 10px"> <li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index" <a href="genindex.html" title="General Index"
>index</a></li> >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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Search</a></li> <li class="nav-item nav-item-this"><a href="">Search</a></li>
</ul> </ul>
</div> </div>
File diff suppressed because one or more lines are too long
+3 -3
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <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.5 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -31,7 +31,7 @@
<li class="right" > <li class="right" >
<a href="gettingstartedfast.html" title="Getting Started Fast" <a href="gettingstartedfast.html" title="Getting Started Fast"
accesskey="P">previous</a> |</li> 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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Understanding Reticulum</a></li> <li class="nav-item nav-item-this"><a href="">Understanding Reticulum</a></li>
</ul> </ul>
</div> </div>
@@ -853,7 +853,7 @@ proof 11
<li class="right" > <li class="right" >
<a href="gettingstartedfast.html" title="Getting Started Fast" <a href="gettingstartedfast.html" title="Getting Started Fast"
>previous</a> |</li> >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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Understanding Reticulum</a></li> <li class="nav-item nav-item-this"><a href="">Understanding Reticulum</a></li>
</ul> </ul>
</div> </div>
+5 -5
View File
@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <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.5 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" /> <link rel="stylesheet" type="text/css" href="_static/classic.css" />
@@ -31,7 +31,7 @@
<li class="right" > <li class="right" >
<a href="index.html" title="Reticulum Network Stack Manual" <a href="index.html" title="Reticulum Network Stack Manual"
accesskey="P">previous</a> |</li> 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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">What is Reticulum?</a></li> <li class="nav-item nav-item-this"><a href="">What is Reticulum?</a></li>
</ul> </ul>
</div> </div>
@@ -62,12 +62,12 @@
<li><p>Fully self-configuring multi-hop routing</p></li> <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>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>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> <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>AES-128 in CBC mode with PKCS7 padding</p></li>
<li><p>HMAC using SHA256 for authentication</p></li> <li><p>HMAC using SHA256 for authentication</p></li>
<li><p>IVs are generated through os.urandom()</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> </ul>
</li> </li>
<li><p>Unforgeable packet delivery confirmations</p></li> <li><p>Unforgeable packet delivery confirmations</p></li>
@@ -182,7 +182,7 @@ network, and vice versa.</p>
<li class="right" > <li class="right" >
<a href="index.html" title="Reticulum Network Stack Manual" <a href="index.html" title="Reticulum Network Stack Manual"
>previous</a> |</li> >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.5 beta documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">What is Reticulum?</a></li> <li class="nav-item nav-item-this"><a href="">What is Reticulum?</a></li>
</ul> </ul>
</div> </div>
+1 -1
View File
@@ -22,7 +22,7 @@ copyright = '2021, Mark Qvist'
author = 'Mark Qvist' author = 'Mark Qvist'
# The full version, including alpha/beta/rc tags # The full version, including alpha/beta/rc tags
release = '0.2.4 beta' release = '0.2.5 beta'
# -- General configuration --------------------------------------------------- # -- General configuration ---------------------------------------------------
+14 -2
View File
@@ -12,13 +12,25 @@ 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 a look at `Nomad Network <https://github.com/markqvist/nomadnet>`_, which
provides a basic encrypted communications suite built completely on Reticulum. provides a basic encrypted communications suite built completely on Reticulum.
.. image:: screenshots/nomadnet3.png .. image:: screenshots/nomadnet_3.png
:target: _images/nomadnet3.png :target: _images/nomadnet_3.png
`Nomad Network <https://github.com/markqvist/nomadnet>`_ is a user-facing client `Nomad Network <https://github.com/markqvist/nomadnet>`_ is a user-facing client
in the development for the messaging and information-sharing protocol in the development for the messaging and information-sharing protocol
`LXMF <https://github.com/markqvist/lxmf>`_, another project built with Reticulum. `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
Develop a Program with Reticulum Develop a Program with Reticulum
=========================================== ===========================================
If you want to develop programs that use Reticulum, the easiest way to get If you want to develop programs that use Reticulum, the easiest way to get
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

+3 -3
View File
@@ -31,7 +31,9 @@ What does Reticulum Offer?
* Forward Secrecy with ephemereal Elliptic Curve Diffie-Hellman keys on Curve25519 * 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 * AES-128 in CBC mode with PKCS7 padding
@@ -39,8 +41,6 @@ What does Reticulum Offer?
* IVs are generated through os.urandom() * IVs are generated through os.urandom()
* Keys are ephemeral and derived from an ECDH key exchange on Curve25519
* Unforgeable packet delivery confirmations * Unforgeable packet delivery confirmations
* A variety of supported interface types * A variety of supported interface types