Skip to content

Commit

Permalink
fix: correct name length package generation
Browse files Browse the repository at this point in the history
Fixed an issue with name length generation for domain names
which resulted into micropython-mdns creating wrongly
formatted dns packages which couldn't be parsed by
certain implementations of mdns like avahi.

Fixes #6
  • Loading branch information
Christoph Brand committed Oct 3, 2022
1 parent e8de880 commit 9a9ddae
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 9 deletions.
2 changes: 1 addition & 1 deletion src/mdns_client/responder.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def _get_service_of(self, query: str) -> "Optional[str]":
def _ptr_record_for(self, query: str) -> DNSRecord:
ptr_target = ".".join((self.host, query))
# For some reason the PTR is shortened and the last two bytes are removed
ptr_target_bytes = name_to_bytes(ptr_target)[:-2]
ptr_target_bytes = name_to_bytes(ptr_target)
return DNSRecord(query, TYPE_PTR, CLASS_IN, DEFAULT_TTL, ptr_target_bytes)

def _srv_record_for(self, query: str) -> "Optional[DNSRecord]":
Expand Down
6 changes: 3 additions & 3 deletions src/mdns_client/structs.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ def checked_name(self) -> "List[bytes]":

def to_bytes(self) -> bytes:
checked_name = self.checked_name
# Require a null bit in the end of the string
query_len = string_packed_len(checked_name)
header_length = query_len + 8
header_length = query_len + 10
rdata_length = len(self.rdata)
payload_length = 2 + rdata_length
buffer = bytearray(header_length + payload_length)
buffer = bytearray(header_length + rdata_length)
pack_name(buffer, checked_name)
index = query_len
pack_into("!HHLH", buffer, index, self.record_type, self.query_class, self.time_to_live, rdata_length)
Expand Down
10 changes: 5 additions & 5 deletions src/mdns_client/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,17 @@ def check_name(n: str) -> "List[bytes]":
n = n.split(".")
if n[-1] == "":
n = n[:-1]
n = [i.encode("UTF8") if isinstance(i, str) else i for i in n]
n = [i.encode("UTF-8") if isinstance(i, str) else i for i in n]
return n


def string_packed_len(string: "List[bytes]") -> int:
return sum(len(i) + 1 for i in string) + 1
def string_packed_len(byte_list: "List[bytes]") -> int:
return sum(len(i) + 1 for i in byte_list) + 1


def name_to_bytes(name: str) -> bytes:
name_bytes = check_name(name)
buffer = bytearray(len(name_bytes) + len(name))
buffer = bytearray(string_packed_len(name_bytes))
pack_name(buffer, name_bytes)
return buffer

Expand All @@ -60,7 +60,7 @@ def pack_name(buffer: bytes, string: "List[bytes]") -> None:
after_size_next_index = output_index + 1
end_of_pack_name_index = after_size_next_index + part_length
buffer[after_size_next_index:end_of_pack_name_index] = part
output_index += part_length + 1
output_index = end_of_pack_name_index
buffer[output_index] = 0


Expand Down
Empty file added test/__init__.py
Empty file.
23 changes: 23 additions & 0 deletions test/run-test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from zeroconf import ServiceBrowser, ServiceListener, Zeroconf


class MyListener(ServiceListener):

def update_service(self, zc: Zeroconf, type_: str, name: str) -> None:
print(f"Service {name} updated")

def remove_service(self, zc: Zeroconf, type_: str, name: str) -> None:
print(f"Service {name} removed")

def add_service(self, zc: Zeroconf, type_: str, name: str) -> None:
info = zc.get_service_info(type_, name)
print(f"Service {name} added, service info: {info}")


zeroconf = Zeroconf()
listener = MyListener()
browser = ServiceBrowser(zeroconf, "_myawesomeservice._tcp.local.", listener)
try:
input("Press enter to exit...\n\n")
finally:
zeroconf.close()
40 changes: 40 additions & 0 deletions test/service_announcement.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import uasyncio as asyncio

from mdns_client import Client
from mdns_client.responder import Responder, generate_random_postfix

print("Connected to WIFI!")


async def serve_client(reader, writer):
writer.write("HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n")
writer.write("<h1>test response</h1>")
await writer.drain()
await writer.wait_closed()
print("disconnected")


async def setup_mdns():
local_ip = "0.0.0.0"
print(f"Setting up MDNS on local ip: {local_ip}")
client = Client(local_ip)
host = "pico-{}".format(generate_random_postfix())
responder = Responder(
client,
own_ip=lambda: local_ip,
host=lambda: host,
)
responder.debug = True
responder.advertise("_myawesomeservice", "_tcp", port=1234)



async def run():
await setup_mdns()
await asyncio.create_task(asyncio.start_server(serve_client, "0.0.0.0", 1234)) # open port 1234

while True:
await asyncio.sleep(3)


asyncio.run(run())

0 comments on commit 9a9ddae

Please sign in to comment.