diff --git a/RNS/Discovery.py b/RNS/Discovery.py index 677e654f..2515a8e1 100644 --- a/RNS/Discovery.py +++ b/RNS/Discovery.py @@ -6,18 +6,19 @@ from .vendor import umsgpack as msgpack NAME = 0xFF INTERFACE_TYPE = 0x00 -REACHABLE_ON = 0x01 -LATITUDE = 0x02 -LONGITUDE = 0x03 -HEIGHT = 0x04 -PORT = 0x05 -IFAC_NETNAME = 0x06 -IFAC_NETKEY = 0x07 -FREQUENCY = 0x08 -BANDWIDTH = 0x09 -SPREADINGFACTOR = 0x0A -CODINGRATE = 0x0B -MODULATION = 0x0C +TRANSPORT = 0x01 +REACHABLE_ON = 0x02 +LATITUDE = 0x03 +LONGITUDE = 0x04 +HEIGHT = 0x05 +PORT = 0x06 +IFAC_NETNAME = 0x07 +IFAC_NETKEY = 0x08 +FREQUENCY = 0x09 +BANDWIDTH = 0x0A +SPREADINGFACTOR = 0x0B +CODINGRATE = 0x0C +MODULATION = 0x0D APP_NAME = "rnstransport" @@ -86,6 +87,7 @@ class InterfaceAnnouncer(): if not interface_type in self.DISCOVERABLE_INTERFACE_TYPES: return None else: info = {INTERFACE_TYPE: interface_type, + TRANSPORT: RNS.Reticulum.transport_enabled(), NAME: self.sanitize(interface.discovery_name), LATITUDE: interface.discovery_latitude, LONGITUDE: interface.discovery_longitude, @@ -160,6 +162,7 @@ class InterfaceAnnounceHandler: if INTERFACE_TYPE in unpacked: interface_type = unpacked[INTERFACE_TYPE] info = {"type": interface_type, + "transport": unpacked[TRANSPORT], "name": unpacked[NAME] or f"Discovered {interface_type}", "received": time.time(), "stamp": stamp, @@ -257,6 +260,8 @@ class InterfaceDiscovery(): STATUS_CODE_MAP = {"available": STATUS_AVAILABLE, "unknown": STATUS_UNKNOWN, "stale": STATUS_STALE} def __init__(self, required_value=InterfaceAnnouncer.DEFAULT_STAMP_VALUE, callback=None, discover_interfaces=True): + if not required_value: required_value = InterfaceAnnouncer.DEFAULT_STAMP_VALUE + self.required_value = required_value self.discovery_callback = callback self.rns_instance = RNS.Reticulum.get_instance() diff --git a/RNS/Reticulum.py b/RNS/Reticulum.py index df8c71e9..6627b913 100755 --- a/RNS/Reticulum.py +++ b/RNS/Reticulum.py @@ -256,6 +256,8 @@ class Reticulum: Reticulum.__use_implicit_proof = True Reticulum.__allow_probes = False Reticulum.__discovery_enabled = False + Reticulum.__discover_interfaces = False + Reticulum.__required_discovery_value = None Reticulum.panic_on_interface_error = False @@ -344,7 +346,9 @@ class Reticulum: thread.daemon = True thread.start() - if Reticulum.__discovery_enabled: RNS.Transport.enable_discovery() + if self.is_shared_instance or self.is_standalone_instance: + if Reticulum.__discovery_enabled: RNS.Transport.enable_discovery() + if Reticulum.__discover_interfaces: RNS.Transport.discover_interfaces() atexit.register(Reticulum.exit_handler) signal.signal(signal.SIGINT, Reticulum.sigint_handler) @@ -478,16 +482,13 @@ class Reticulum: self.rpc_key = None if option == "enable_transport": v = self.config["reticulum"].as_bool(option) - if v == True: - Reticulum.__transport_enabled = True + if v == True: Reticulum.__transport_enabled = True if option == "link_mtu_discovery": v = self.config["reticulum"].as_bool(option) - if v == True: - Reticulum.__link_mtu_discovery = True + if v == True: Reticulum.__link_mtu_discovery = True if option == "enable_remote_management": v = self.config["reticulum"].as_bool(option) - if v == True: - Reticulum.__remote_management_enabled = True + if v == True: Reticulum.__remote_management_enabled = True if option == "remote_management_allowed": v = self.config["reticulum"].as_list(option) for hexhash in v: @@ -503,21 +504,25 @@ class Reticulum: RNS.Transport.remote_management_allowed.append(allowed_hash) if option == "respond_to_probes": v = self.config["reticulum"].as_bool(option) - if v == True: - Reticulum.__allow_probes = True + if v == True: Reticulum.__allow_probes = True if option == "force_shared_instance_bitrate": v = self.config["reticulum"].as_int(option) Reticulum._force_shared_instance_bitrate = v if option == "panic_on_interface_error": v = self.config["reticulum"].as_bool(option) - if v == True: - Reticulum.panic_on_interface_error = True + if v == True: Reticulum.panic_on_interface_error = True if option == "use_implicit_proof": v = self.config["reticulum"].as_bool(option) - if v == True: - Reticulum.__use_implicit_proof = True - if v == False: - Reticulum.__use_implicit_proof = False + if v == True: Reticulum.__use_implicit_proof = True + if v == False: Reticulum.__use_implicit_proof = False + if option == "discover_interfaces": + v = self.config["reticulum"].as_bool(option) + if v == True: Reticulum.__discover_interfaces = True + if v == False: Reticulum.__discover_interfaces = False + if option == "required_discovery_value": + v = self.config["reticulum"].as_int(option) + if v > 0: Reticulum.__required_discovery_value = v + else: Reticulum.__required_discovery_value = None if RNS.compiled: RNS.log("Reticulum running in compiled mode", RNS.LOG_DEBUG) else: RNS.log("Reticulum running in interpreted mode", RNS.LOG_DEBUG) @@ -1425,6 +1430,16 @@ class Reticulum: def probe_destination_enabled(): return Reticulum.__allow_probes + @staticmethod + def required_discovery_value(): + """ + Returns the required stam value for a discovered interface + to be considered valid and remembered. + + :returns: The required stamp value as an integer. + """ + return Reticulum.__required_discovery_value + # Default configuration file: __default_rns_config__ = '''# This is the default Reticulum config file. # You should probably edit it to include any additional, @@ -1467,6 +1482,7 @@ share_instance = Yes instance_name = default + # Some platforms don't support domain sockets, and if that # is the case, you can isolate different instances by # specifying a unique set of ports for each: @@ -1482,6 +1498,14 @@ instance_name = default # shared_instance_type = tcp +# You can configure whether Reticulum should discover +# available interfaces from other Transport Instances over +# the network. If this option is enabled, Reticulum will +# collect interface information discovered from the network. + +# discover_interfaces = No + + # 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 diff --git a/RNS/Transport.py b/RNS/Transport.py index fb122d0b..cb52474e 100755 --- a/RNS/Transport.py +++ b/RNS/Transport.py @@ -157,6 +157,7 @@ class Transport: interface_jobs_interval = 5.0 inbound_announce_lock = Lock() interface_announcer = None + discovery_handler = None traffic_rxb = 0 traffic_txb = 0 @@ -356,6 +357,11 @@ class Transport: Transport.interface_announcer = RNS.Discovery.InterfaceAnnouncer(Transport) Transport.interface_announcer.start() + @staticmethod + def discover_interfaces(): + if not Transport.discovery_handler: + Transport.discovery_handler = RNS.Discovery.InterfaceDiscovery(required_value=RNS.Reticulum.required_discovery_value(), discover_interfaces=True) + @staticmethod def count_traffic_loop(): while True: diff --git a/RNS/Utilities/rnsd.py b/RNS/Utilities/rnsd.py index 15ae69c2..b85513d9 100755 --- a/RNS/Utilities/rnsd.py +++ b/RNS/Utilities/rnsd.py @@ -160,6 +160,22 @@ instance_name = default # remote_management_allowed = 9fb6d773498fb3feda407ed8ef2c3229, 2d882c5586e548d79b5af27bca1776dc +# You can configure whether Reticulum should discover +# available interfaces from other Transport Instances over +# the network. If this option is enabled, Reticulum will +# collect interface information discovered from the network. + +# discover_interfaces = No + + +# To prevent interface discovery spamming, a valid crypto- +# graphic stamp is required per announced interface. You +# can configure the minimum required value to accept as +# valid for discovered interfaces. + +# required_discovery_value = 20 + + # 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