From 1564930a512c5ab6d5e41fecda8d12c1ed3cc4c2 Mon Sep 17 00:00:00 2001 From: liamcottle Date: Fri, 17 May 2024 04:09:11 +1200 Subject: [PATCH] auto interface working on windows --- RNS/Interfaces/AutoInterface.py | 38 +++++++++++++----- RNS/Reticulum.py | 68 +++++++++++++++------------------ RNS/vendor/ifaddr/niwrapper.py | 7 ++++ 3 files changed, 66 insertions(+), 47 deletions(-) diff --git a/RNS/Interfaces/AutoInterface.py b/RNS/Interfaces/AutoInterface.py index 0c86184..f3f6496 100644 --- a/RNS/Interfaces/AutoInterface.py +++ b/RNS/Interfaces/AutoInterface.py @@ -77,6 +77,15 @@ class AutoInterface(Interface): ifas = self.netinfo.ifaddresses(ifname) return ifas + def interface_name_to_index(self, ifname): + + # socket.if_nametoindex doesn't work with uuid interface names on windows, it wants the ethernet_0 style + # we will just get the index from netinfo instead as it seems to work + if RNS.vendor.platformutils.is_windows(): + return self.netinfo.interface_names_to_indexes()[ifname] + + return socket.if_nametoindex(ifname) + def __init__(self, owner, name, group_id=None, discovery_scope=None, discovery_port=None, multicast_address_type=None, data_port=None, allowed_interfaces=None, ignored_interfaces=None, configured_bitrate=None): from RNS.vendor.ifaddr import niwrapper super().__init__() @@ -205,7 +214,7 @@ class AutoInterface(Interface): RNS.log(str(self)+" Creating multicast discovery listener on "+str(ifname)+" with address "+str(mcast_addr), RNS.LOG_EXTREME) # Struct with interface index - if_struct = struct.pack("I", socket.if_nametoindex(ifname)) + if_struct = struct.pack("I", self.interface_name_to_index(ifname)) # Set up multicast socket discovery_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) @@ -219,12 +228,21 @@ class AutoInterface(Interface): discovery_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mcast_group) # Bind socket - if self.discovery_scope == AutoInterface.SCOPE_LINK: - addr_info = socket.getaddrinfo(mcast_addr+"%"+ifname, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) - else: - addr_info = socket.getaddrinfo(mcast_addr, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) + if RNS.vendor.platformutils.is_windows(): - discovery_socket.bind(addr_info[0][4]) + # window throws "[WinError 10049] The requested address is not valid in its context" + # when trying to use the multicast address as host, or when providing interface index + # passing an empty host appears to work, but probably not exactly how we want it to... + discovery_socket.bind(('', self.discovery_port)) + + else: + + if self.discovery_scope == AutoInterface.SCOPE_LINK: + addr_info = socket.getaddrinfo(mcast_addr+"%"+ifname, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) + else: + addr_info = socket.getaddrinfo(mcast_addr, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) + + discovery_socket.bind(addr_info[0][4]) # Set up thread for discovery packets def discovery_loop(): @@ -253,7 +271,7 @@ class AutoInterface(Interface): socketserver.UDPServer.address_family = socket.AF_INET6 for ifname in self.adopted_interfaces: - local_addr = self.adopted_interfaces[ifname]+"%"+ifname + local_addr = self.adopted_interfaces[ifname]+"%"+str(self.interface_name_to_index(ifname)) addr_info = socket.getaddrinfo(local_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM) address = addr_info[0][4] @@ -380,7 +398,7 @@ class AutoInterface(Interface): announce_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) addr_info = socket.getaddrinfo(self.mcast_discovery_address, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) - ifis = struct.pack("I", socket.if_nametoindex(ifname)) + ifis = struct.pack("I", self.interface_name_to_index(ifname)) announce_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis) announce_socket.sendto(discovery_token, addr_info[0][4]) announce_socket.close() @@ -433,8 +451,8 @@ class AutoInterface(Interface): try: if self.outbound_udp_socket == None: self.outbound_udp_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) - - peer_addr = str(peer)+"%"+str(self.peers[peer][0]) + + peer_addr = str(peer)+"%"+str(self.interface_name_to_index(self.peers[peer][0])) addr_info = socket.getaddrinfo(peer_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM) self.outbound_udp_socket.sendto(data, addr_info[0][4]) diff --git a/RNS/Reticulum.py b/RNS/Reticulum.py index 44d9028..4a9bb9b 100755 --- a/RNS/Reticulum.py +++ b/RNS/Reticulum.py @@ -536,46 +536,40 @@ class Reticulum: if (("interface_enabled" in c) and c.as_bool("interface_enabled") == True) or (("enabled" in c) and c.as_bool("enabled") == True): if c["type"] == "AutoInterface": - if not RNS.vendor.platformutils.is_windows(): - group_id = c["group_id"] if "group_id" in c else None - discovery_scope = c["discovery_scope"] if "discovery_scope" in c else None - discovery_port = int(c["discovery_port"]) if "discovery_port" in c else None - multicast_address_type = c["multicast_address_type"] if "multicast_address_type" in c else None - data_port = int(c["data_port"]) if "data_port" in c else None - allowed_interfaces = c.as_list("devices") if "devices" in c else None - ignored_interfaces = c.as_list("ignored_devices") if "ignored_devices" in c else None + group_id = c["group_id"] if "group_id" in c else None + discovery_scope = c["discovery_scope"] if "discovery_scope" in c else None + discovery_port = int(c["discovery_port"]) if "discovery_port" in c else None + multicast_address_type = c["multicast_address_type"] if "multicast_address_type" in c else None + data_port = int(c["data_port"]) if "data_port" in c else None + allowed_interfaces = c.as_list("devices") if "devices" in c else None + ignored_interfaces = c.as_list("ignored_devices") if "ignored_devices" in c else None - interface = AutoInterface.AutoInterface( - RNS.Transport, - name, - group_id, - discovery_scope, - discovery_port, - multicast_address_type, - data_port, - allowed_interfaces, - ignored_interfaces - ) - - if "outgoing" in c and c.as_bool("outgoing") == False: - interface.OUT = False - else: - interface.OUT = True - - interface.mode = interface_mode - - interface.announce_cap = announce_cap - if configured_bitrate: - interface.bitrate = configured_bitrate - if ifac_size != None: - interface.ifac_size = ifac_size - else: - interface.ifac_size = 16 + interface = AutoInterface.AutoInterface( + RNS.Transport, + name, + group_id, + discovery_scope, + discovery_port, + multicast_address_type, + data_port, + allowed_interfaces, + ignored_interfaces + ) + if "outgoing" in c and c.as_bool("outgoing") == False: + interface.OUT = False else: - RNS.log("AutoInterface is not currently supported on Windows, disabling interface.", RNS.LOG_ERROR); - RNS.log("Please remove this AutoInterface instance from your configuration file.", RNS.LOG_ERROR); - RNS.log("You will have to manually configure other interfaces for connectivity.", RNS.LOG_ERROR); + interface.OUT = True + + interface.mode = interface_mode + + interface.announce_cap = announce_cap + if configured_bitrate: + interface.bitrate = configured_bitrate + if ifac_size != None: + interface.ifac_size = ifac_size + else: + interface.ifac_size = 16 if c["type"] == "UDPInterface": device = c["device"] if "device" in c else None diff --git a/RNS/vendor/ifaddr/niwrapper.py b/RNS/vendor/ifaddr/niwrapper.py index bd44c72..e6c8b96 100644 --- a/RNS/vendor/ifaddr/niwrapper.py +++ b/RNS/vendor/ifaddr/niwrapper.py @@ -11,6 +11,13 @@ def interfaces() -> List[str]: adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True) return [a.name for a in adapters] +def interface_names_to_indexes() -> dict: + adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True) + results = {} + for adapter in adapters: + results[adapter.name] = adapter.index + return results + def ifaddresses(ifname) -> dict: adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True) ifa = {}