Merge pull request #506 from liamcottle/feature/windows-auto-interface

Implement AutoInterface support on Windows
This commit is contained in:
markqvist 2024-05-17 16:32:33 +02:00 committed by GitHub
commit 583e65419e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 66 additions and 47 deletions

View File

@ -77,6 +77,15 @@ class AutoInterface(Interface):
ifas = self.netinfo.ifaddresses(ifname) ifas = self.netinfo.ifaddresses(ifname)
return ifas 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): 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 from RNS.vendor.ifaddr import niwrapper
super().__init__() 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) RNS.log(str(self)+" Creating multicast discovery listener on "+str(ifname)+" with address "+str(mcast_addr), RNS.LOG_EXTREME)
# Struct with interface index # 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 # Set up multicast socket
discovery_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) discovery_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
@ -219,6 +228,15 @@ class AutoInterface(Interface):
discovery_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mcast_group) discovery_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mcast_group)
# Bind socket # Bind socket
if RNS.vendor.platformutils.is_windows():
# 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: if self.discovery_scope == AutoInterface.SCOPE_LINK:
addr_info = socket.getaddrinfo(mcast_addr+"%"+ifname, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) addr_info = socket.getaddrinfo(mcast_addr+"%"+ifname, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM)
else: else:
@ -253,7 +271,7 @@ class AutoInterface(Interface):
socketserver.UDPServer.address_family = socket.AF_INET6 socketserver.UDPServer.address_family = socket.AF_INET6
for ifname in self.adopted_interfaces: 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) addr_info = socket.getaddrinfo(local_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM)
address = addr_info[0][4] address = addr_info[0][4]
@ -380,7 +398,7 @@ class AutoInterface(Interface):
announce_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) 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) 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.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis)
announce_socket.sendto(discovery_token, addr_info[0][4]) announce_socket.sendto(discovery_token, addr_info[0][4])
announce_socket.close() announce_socket.close()
@ -434,7 +452,7 @@ class AutoInterface(Interface):
if self.outbound_udp_socket == None: if self.outbound_udp_socket == None:
self.outbound_udp_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) 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) 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]) self.outbound_udp_socket.sendto(data, addr_info[0][4])

View File

@ -536,7 +536,6 @@ 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 (("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 c["type"] == "AutoInterface":
if not RNS.vendor.platformutils.is_windows():
group_id = c["group_id"] if "group_id" 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_scope = c["discovery_scope"] if "discovery_scope" in c else None
discovery_port = int(c["discovery_port"]) if "discovery_port" in c else None discovery_port = int(c["discovery_port"]) if "discovery_port" in c else None
@ -572,11 +571,6 @@ class Reticulum:
else: else:
interface.ifac_size = 16 interface.ifac_size = 16
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);
if c["type"] == "UDPInterface": if c["type"] == "UDPInterface":
device = c["device"] if "device" in c else None device = c["device"] if "device" in c else None
port = int(c["port"]) if "port" in c else None port = int(c["port"]) if "port" in c else None

View File

@ -11,6 +11,13 @@ def interfaces() -> List[str]:
adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True) adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True)
return [a.name for a in adapters] 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: def ifaddresses(ifname) -> dict:
adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True) adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True)
ifa = {} ifa = {}