Skip to content

Commit c79de6e

Browse files
committed
DiscoveryClient: Remove IP addresses from response, handle IPv6 link-local
1 parent a87c5f7 commit c79de6e

File tree

1 file changed

+38
-29
lines changed

1 file changed

+38
-29
lines changed

zbnt/DiscoveryClient.py

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,21 @@
2828
class DiscoveryClient(MessageReceiver):
2929
MSG_DISCOVERY_PORT = 5466
3030

31-
def __init__(self, address_list, on_device_discovered):
31+
def __init__(self, address_list, ip6, on_device_discovered):
3232
super().__init__()
3333

34+
self.ip6 = ip6
3435
self.address_list = address_list
3536
self.on_device_discovered = on_device_discovered
3637

3738
@staticmethod
38-
async def create(addr, callback):
39+
async def create(addr, ip6, callback):
3940
loop = asyncio.get_running_loop()
4041

4142
_, protocol = await loop.create_datagram_endpoint(
42-
lambda: DiscoveryClient(addr, callback),
43+
lambda: DiscoveryClient(addr, ip6, callback),
4344
remote_addr=None,
44-
family=socket.AF_INET,
45+
family=socket.AF_INET6 if ip6 else socket.AF_INET,
4546
allow_broadcast=True
4647
)
4748

@@ -58,7 +59,10 @@ def connection_made(self, transport):
5859
message += encode_u64(self.validator)
5960

6061
for address in self.address_list:
61-
self.transport.sendto(message, (address, DiscoveryClient.MSG_DISCOVERY_PORT))
62+
if not self.ip6:
63+
self.transport.sendto(message, (address, DiscoveryClient.MSG_DISCOVERY_PORT))
64+
else:
65+
self.transport.sendto(message, address)
6266

6367
def datagram_received(self, data, addr):
6468
self.remote_addr = addr
@@ -74,7 +78,7 @@ def connection_lost(self, exc):
7478
pass
7579

7680
def message_received(self, msg_id, msg_payload):
77-
if msg_id != Messages.MSG_ID_DISCOVERY or len(msg_payload) <= 67:
81+
if msg_id != Messages.MSG_ID_DISCOVERY or len(msg_payload) <= 47:
7882
return
7983

8084
validator = decode_u64(msg_payload[0:8])
@@ -106,45 +110,50 @@ def message_received(self, msg_id, msg_payload):
106110
elif len(device["version"][5]) != 0:
107111
device["versionstr"] += "+d"
108112

109-
msg_ip, _ = self.remote_addr
110-
ip4 = str(ipaddress.IPv4Address(msg_payload[48:44:-1]))
111-
ip6 = str(ipaddress.IPv6Address(msg_payload[49:65]))
112-
address_list = []
113+
if not self.ip6:
114+
ip, _ = self.remote_addr
115+
else:
116+
ip, _ = socket.getnameinfo(self.remote_addr, 0)
113117

114-
if ip4 != msg_ip:
115-
return
116-
117-
if ip4 != "0.0.0.0":
118-
address_list.append(ip4)
119-
120-
if ip6 != "::":
121-
address_list.append(ip6)
122-
123-
if len(address_list) == 0:
124-
return
125-
126-
device["address"] = address_list
127-
device["port"] = decode_u16(msg_payload[65:67])
128-
device["name"] = msg_payload[67:].decode("UTF-8")
118+
device["address"] = ip
119+
device["port"] = decode_u16(msg_payload[45:47])
120+
device["name"] = msg_payload[47:].decode("UTF-8")
129121

130122
self.on_device_discovered(device)
131123

132124
async def discover_devices(timeout):
133-
address_list = []
134125
device_list = []
126+
address4_set = set()
127+
address6_list = []
135128

136129
# Get broadcast address of every available interface
130+
137131
for iface in netifaces.interfaces():
138132
for addr_family, addr_list in netifaces.ifaddresses(iface).items():
139133
if netifaces.address_families[addr_family] == "AF_INET":
140134
for addr in addr_list:
141135
if "broadcast" in addr:
142-
address_list.append(addr["broadcast"])
136+
address4_set.add(addr["broadcast"])
137+
elif addr["addr"][:8] == "169.254.":
138+
address4_set.add("169.254.255.255")
139+
140+
address6_list.append(
141+
socket.getaddrinfo(
142+
"ff12::{0}%{1}".format(DiscoveryClient.MSG_DISCOVERY_PORT, iface),
143+
5466, socket.AF_INET6, socket.SOCK_DGRAM
144+
)[0][-1]
145+
)
143146

144147
# Broadcast DISCOVERY message on every interface
148+
149+
await DiscoveryClient.create(
150+
address4_set, False,
151+
lambda dev: device_list.append(dev)
152+
)
153+
145154
await DiscoveryClient.create(
146-
address_list,
147-
lambda dev: device_list.append(dev)
155+
address6_list, True,
156+
lambda dev: device_list.append(dev)
148157
)
149158

150159
await asyncio.sleep(timeout)

0 commit comments

Comments
 (0)