#!/usr/bin/env python3 """Generate the narrowly guarded mDNS 1.12.0 membership overlay; never edit upstream.""" import argparse import hashlib from pathlib import Path import re SOURCE_SHA256 = "adc139fa504a925ab644f21f8dce3659927f534e390a176b72b0ae3206c6a3ea" OLD_DEINIT = """ s_interfaces[tcpip_if].proto &= ~(ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6); if (s_interfaces[tcpip_if].proto == 0) { s_interfaces[tcpip_if].ready = false; join_group(tcpip_if, ip_protocol, false); """ NEW_DEINIT = """ int proto = (ip_protocol == MDNS_IP_PROTOCOL_V4 ? PROTO_IPV4 : PROTO_IPV6); if (!(s_interfaces[tcpip_if].proto & proto)) { return; } join_group(tcpip_if, ip_protocol, false); s_interfaces[tcpip_if].proto &= ~proto; if (s_interfaces[tcpip_if].proto == 0) { s_interfaces[tcpip_if].ready = false; """ OLD_INIT = """ err = pcb_init(); if (err) { return err; } """ NEW_INIT = """ err = pcb_init(); if (err) { join_group(tcpip_if, ip_protocol, false); return err; } """ def generate(component: Path, output: Path) -> None: manifest = (component / "idf_component.yml").read_text() if re.findall(r"^version:\s*(\S+)\s*$", manifest, re.MULTILINE) != ["1.12.0"]: raise ValueError("mDNS membership overlay requires exactly version 1.12.0; review upstream") original = (component / "mdns_networking_lwip.c").read_bytes() if hashlib.sha256(original).hexdigest() != SOURCE_SHA256: raise ValueError("mDNS networking source SHA-256 mismatch; review upstream, do not bypass guard") patched = original.decode("utf-8") for old, new in ((OLD_DEINIT, NEW_DEINIT), (OLD_INIT, NEW_INIT)): if patched.count(old) != 1: raise ValueError("mDNS membership replacement must match exactly once") patched = patched.replace(old, new, 1) result = patched.encode("utf-8") output.parent.mkdir(parents=True, exist_ok=True) if not output.exists() or output.read_bytes() != result: output.write_bytes(result) if __name__ == "__main__": parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("component", type=Path) parser.add_argument("output", type=Path) args = parser.parse_args() try: generate(args.component, args.output) except (OSError, ValueError) as error: parser.exit(1, f"mDNS membership overlay: {error}\n")