Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| aaf0ace027 | |||
| d8b76b4bc5 | |||
| d29ff38a05 | |||
| 65e8487b39 | |||
| 6362e04567 | |||
| 711b754dcc | |||
| 1351316f17 | |||
| 7af14cec84 | |||
| 0687ee2231 | |||
| 872075a31e | |||
| d8f0380aa9 | |||
| 569f9bd2b1 | |||
| 450b88d0f0 | |||
| 1cb9df109a | |||
| 80455c9614 | |||
| c1e280d896 | |||
| 4a2925cdea | |||
| 7f38c32e90 | |||
| 8646be0dcf | |||
| 6b3cc07740 | |||
| 3b57b0013b | |||
| 24d8f39dd1 | |||
| 58e4bf3c80 | |||
| 1da8a0c8f1 | |||
| 8b8d4410ef | |||
| 7d804daa8f | |||
| ce00822cb0 | |||
| 6d6c91edaf | |||
| 8432cf40c2 | |||
| 5e21bdd233 |
@@ -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
|
||||||
|
|||||||
@@ -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+"]"
|
||||||
@@ -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+"]"
|
||||||
@@ -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)+"]"
|
||||||
|
|||||||
@@ -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+"]"
|
||||||
|
|||||||
@@ -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+"]"
|
||||||
|
|||||||
@@ -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)+"]"
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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 @@
|
|||||||
__version__ = "0.2.4"
|
__version__ = "0.2.5"
|
||||||
@@ -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
|
||||||
|
|||||||
|
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
|
||||||
|
|||||||
@@ -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,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',
|
||||||
|
|||||||
@@ -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 — Reticulum Network Stack 0.2.4 beta documentation</title>
|
<title>Examples — 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> »</li>
|
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.5 beta documentation</a> »</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> »</li>
|
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.5 beta documentation</a> »</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>
|
||||||
|
|||||||
@@ -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 — Reticulum Network Stack 0.2.4 beta documentation</title>
|
<title>Index — 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> »</li>
|
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.5 beta documentation</a> »</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> »</li>
|
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.5 beta documentation</a> »</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>
|
||||||
|
|||||||
@@ -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 — Reticulum Network Stack 0.2.4 beta documentation</title>
|
<title>Getting Started Fast — 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> »</li>
|
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.5 beta documentation</a> »</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 @@ don’t 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> »</li>
|
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.5 beta documentation</a> »</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>
|
||||||
|
|||||||
@@ -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 — Reticulum Network Stack 0.2.4 beta documentation</title>
|
<title>Reticulum Network Stack Manual — 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> »</li>
|
<li class="nav-item nav-item-0"><a href="#">Reticulum Network Stack 0.2.5 beta documentation</a> »</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> »</li>
|
<li class="nav-item nav-item-0"><a href="#">Reticulum Network Stack 0.2.5 beta documentation</a> »</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,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 — Reticulum Network Stack 0.2.4 beta documentation</title>
|
<title>API Reference — 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> »</li>
|
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.5 beta documentation</a> »</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> »</li>
|
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.5 beta documentation</a> »</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>
|
||||||
|
|||||||
@@ -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 — Reticulum Network Stack 0.2.4 beta documentation</title>
|
<title>Search — 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> »</li>
|
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.5 beta documentation</a> »</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> »</li>
|
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.5 beta documentation</a> »</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>
|
||||||
|
|||||||
@@ -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 — Reticulum Network Stack 0.2.4 beta documentation</title>
|
<title>Understanding Reticulum — 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> »</li>
|
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.5 beta documentation</a> »</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> »</li>
|
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.5 beta documentation</a> »</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,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? — Reticulum Network Stack 0.2.4 beta documentation</title>
|
<title>What is Reticulum? — 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> »</li>
|
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.5 beta documentation</a> »</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> »</li>
|
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.5 beta documentation</a> »</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>
|
||||||
|
|||||||
@@ -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 ---------------------------------------------------
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 68 KiB |
@@ -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
|
||||||
|
|||||||