mdns: support primitive clients (android, rfc-6.7)

This commit is contained in:
ed 2022-11-20 20:31:11 +00:00
parent d326ba9723
commit 35175fd685
4 changed files with 64 additions and 15 deletions

View file

@ -621,7 +621,7 @@ def run_argparse(
ap2.add_argument("--qr", action="store_true", help="show http:// QR-code on startup") ap2.add_argument("--qr", action="store_true", help="show http:// QR-code on startup")
ap2.add_argument("--qrs", action="store_true", help="show https:// QR-code on startup") ap2.add_argument("--qrs", action="store_true", help="show https:// QR-code on startup")
ap2.add_argument("--qrl", metavar="PATH", type=u, default="", help="location to include in the url, for example [\033[32mpriv/?pw=hunter2\033[0m]") ap2.add_argument("--qrl", metavar="PATH", type=u, default="", help="location to include in the url, for example [\033[32mpriv/?pw=hunter2\033[0m]")
ap2.add_argument("--qri", metavar="PREFIX", type=u, default="", help="select IP which starts with PREFIX") ap2.add_argument("--qri", metavar="PREFIX", type=u, default="", help="select IP which starts with PREFIX; [\033[32m.\033[0m] to force default IP when mDNS URL would have been used instead")
ap2.add_argument("--qr-fg", metavar="COLOR", type=int, default=0 if tty else 16, help="foreground; try [\033[32m0\033[0m] if the qr-code is unreadable") ap2.add_argument("--qr-fg", metavar="COLOR", type=int, default=0 if tty else 16, help="foreground; try [\033[32m0\033[0m] if the qr-code is unreadable")
ap2.add_argument("--qr-bg", metavar="COLOR", type=int, default=229, help="background (white=255)") ap2.add_argument("--qr-bg", metavar="COLOR", type=int, default=229, help="background (white=255)")
ap2.add_argument("--qrp", metavar="CELLS", type=int, default=4, help="padding (spec says 4 or more, but 1 is usually fine)") ap2.add_argument("--qrp", metavar="CELLS", type=int, default=4, help="padding (spec says 4 or more, but 1 is usually fine)")

View file

@ -373,24 +373,66 @@ class MDNS(MCast):
self.stop(True) self.stop(True)
return return
# then rfc-6.7; dns pretending to be mdns (android...)
if p.header.id or addr[1] != 5353:
rsp: Optional[DNSRecord] = None
for r in p.questions:
try:
lhn = U(r.qname).lower()
except:
self.log("invalid question: {}".format(r))
continue
if lhn != self.lhn:
continue
if p.header.id and r.qtype in (QTYPE.A, QTYPE.AAAA):
rsp = rsp or DNSRecord(DNSHeader(p.header.id, 0x8400))
rsp.add_question(r)
for ip in srv.ips:
qt = r.qtype
v6 = ":" in ip
if v6 == (qt == QTYPE.AAAA):
rd = AAAA(ip) if v6 else A(ip)
rr = RR(self.hn, qt, DC.IN, 10, rd)
rsp.add_answer(rr)
if rsp:
srv.sck.sendto(rsp.pack(), addr[:2])
# but don't return in case it's a differently broken client
# then a/aaaa records # then a/aaaa records
for r in p.questions: for r in p.questions:
if U(r.qname).lower() != self.lhn: try:
lhn = U(r.qname).lower()
except:
self.log("invalid question: {}".format(r))
continue
if lhn != self.lhn:
continue continue
# gvfs keeps repeating itself # gvfs keeps repeating itself
found = False found = False
unicast = False unicast = False
for r in p.rr: for rr in p.rr:
rname = U(r.rname).lower() try:
rname = U(rr.rname).lower()
except:
self.log("invalid rr: {}".format(rr))
continue
if rname == self.lhn: if rname == self.lhn:
if r.ttl > 60: if rr.ttl > 60:
found = True found = True
if r.rclass == DC.F_IN: if rr.rclass == DC.F_IN:
unicast = True unicast = True
if unicast: if unicast:
# spec-compliant mDNS-over-unicast
srv.sck.sendto(srv.bp_ip, (cip, 5353)) srv.sck.sendto(srv.bp_ip, (cip, 5353))
elif addr[1] != 5353:
# just in case some clients use (and want us to use) invalid ports
srv.sck.sendto(srv.bp_ip, addr[:2])
if not found: if not found:
self.q[cip] = (0, srv, srv.bp_ip) self.q[cip] = (0, srv, srv.bp_ip)
@ -400,6 +442,9 @@ class MDNS(MCast):
# and service queries # and service queries
for r in p.questions: for r in p.questions:
if not r or not r.qname:
continue
qname = U(r.qname).lower() qname = U(r.qname).lower()
if qname in self.lsvcs or qname == "_services._dns-sd._udp.local.": if qname in self.lsvcs or qname == "_services._dns-sd._udp.local.":
self.q[cip] = (deadline, srv, srv.bp_svc) self.q[cip] = (deadline, srv, srv.bp_svc)
@ -408,10 +453,13 @@ class MDNS(MCast):
# (workaround gvfs race-condition where it occasionally # (workaround gvfs race-condition where it occasionally
# doesn't read/decode the full response...) # doesn't read/decode the full response...)
if now < srv.last_tx + 12: if now < srv.last_tx + 12:
for r in p.rr: for rr in p.rr:
rdata = U(r.rdata).lower() if not rr.rdata:
continue
rdata = U(rr.rdata).lower()
if rdata in self.lsfqdns: if rdata in self.lsfqdns:
if r.ttl > 2250: if rr.ttl > 2250:
self.q.pop(cip, None) self.q.pop(cip, None)
break break

View file

@ -106,9 +106,9 @@ class DNSRecord(object):
) -> None: ) -> None:
self.header = header or DNSHeader() self.header = header or DNSHeader()
self.questions: list[DNSQuestion] = questions or [] self.questions: list[DNSQuestion] = questions or []
self.rr = rr or [] self.rr: list[RR] = rr or []
self.auth = auth or [] self.auth: list[RR] = auth or []
self.ar = ar or [] self.ar: list[RR] = ar or []
if q: if q:
self.questions.append(q) self.questions.append(q)

View file

@ -508,19 +508,20 @@ class TcpSrv(object):
def _qr(self, t1: dict[str, list[int]], t2: dict[str, list[int]]) -> str: def _qr(self, t1: dict[str, list[int]], t2: dict[str, list[int]]) -> str:
ip = None ip = None
ips = list(t1) + list(t2) ips = list(t1) + list(t2)
if self.args.zm: qri = self.args.qri
if self.args.zm and not qri:
name = self.args.name + ".local" name = self.args.name + ".local"
t1[name] = next(v for v in (t1 or t2).values()) t1[name] = next(v for v in (t1 or t2).values())
ips = [name] + ips ips = [name] + ips
for ip in ips: for ip in ips:
if ip.startswith(self.args.qri): if ip.startswith(qri) or qri == ".":
break break
ip = "" ip = ""
if not ip: if not ip:
# maybe /bin/ip is missing or smth # maybe /bin/ip is missing or smth
ip = self.args.qri ip = qri
if not ip: if not ip:
return "" return ""