Skip to content

Commit 3d793b5

Browse files
authored
Add files via upload
1 parent 57594a1 commit 3d793b5

1 file changed

Lines changed: 61 additions & 16 deletions

File tree

dnsd.py

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,22 @@
1919
from urllib import urlencode
2020

2121
# -----------------------------
22-
# Root server IPs (a subset)
22+
# Root server IPs
2323
# -----------------------------
2424
ROOT_SERVERS = [
2525
"198.41.0.4", # a.root-servers.net
2626
"199.9.14.201", # b.root-servers.net
2727
"192.33.4.12", # c.root-servers.net
2828
"199.7.91.13", # d.root-servers.net
2929
"192.203.230.10", # e.root-servers.net
30+
"192.5.5.241", # f.root-servers.net
31+
"192.112.36.4", # g.root-servers.net
32+
"198.97.190.53", # h.root-servers.net
33+
"192.36.148.17", # i.root-servers.net
34+
"192.58.128.30", # j.root-servers.net
35+
"193.0.14.129", # k.root-servers.net
36+
"199.7.83.42", # l.root-servers.net
37+
"202.12.27.33", # m.root-servers.net
3038
]
3139

3240
QTYPE = {"A": 1, "NS": 2, "CNAME": 5, "MX": 15, "TXT": 16, "AAAA": 28}
@@ -217,16 +225,19 @@ def parse_sections(msg):
217225
}
218226

219227
def rr_ip_from_additional(rr):
220-
# A glue only (AAAA glue requires IPv6 socket support; intentionally skipped)
221228
if rr["type"] == QTYPE["A"] and rr["rdlen"] == 4:
222229
b = bytearray(rr["rdata"])
223230
return "%d.%d.%d.%d" % (b[0], b[1], b[2], b[3])
231+
if rr["type"] == QTYPE["AAAA"] and rr["rdlen"] == 16:
232+
return socket.inet_ntop(socket.AF_INET6, rr["rdata"])
224233
return None
225234

226235
def udp_exchange(server_ip, wire_query, timeout=2, port=53):
227-
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
236+
family = socket.AF_INET6 if ":" in server_ip else socket.AF_INET
237+
s = socket.socket(family, socket.SOCK_DGRAM)
228238
s.settimeout(float(timeout))
229239
try:
240+
# For AF_INET6, address tuple can be (ip, port) and Python fills flowinfo/scopeid
230241
s.sendto(wire_query, (server_ip, int(port)))
231242
data, _ = s.recvfrom(4096)
232243
return data
@@ -279,21 +290,34 @@ def iterative_resolve(qname, qtype, timeout=2, max_steps=25):
279290
next_servers = glue_ips + next_servers
280291
continue
281292

282-
# No glue: resolve NS name A using recursion of *this* iterative resolver
293+
# No glue: resolve NS name (try AAAA first, then A)
283294
if ns_names:
284295
random.shuffle(ns_names)
285296
resolved_ns_ips = []
297+
286298
for nsn in ns_names[:3]:
287-
ns_resp = iterative_resolve(nsn, QTYPE["A"], timeout=timeout, max_steps=max_steps)
288-
if not ns_resp:
289-
continue
290-
ns_parsed = parse_sections(ns_resp)
291-
for a_rr in ns_parsed["answers"]:
292-
if a_rr["type"] == QTYPE["A"] and a_rr["rdlen"] == 4:
293-
b = bytearray(a_rr["rdata"])
294-
resolved_ns_ips.append("%d.%d.%d.%d" % (b[0], b[1], b[2], b[3]))
299+
resolved_ns_ips = []
300+
301+
for qt in (QTYPE["AAAA"], QTYPE["A"]):
302+
ns_resp = iterative_resolve(nsn, qt, timeout=timeout, max_steps=max_steps)
303+
if not ns_resp:
304+
continue
305+
306+
ns_parsed = parse_sections(ns_resp)
307+
308+
for rr in ns_parsed["answers"]:
309+
if rr["type"] == QTYPE["A"] and rr["rdlen"] == 4:
310+
b = bytearray(rr["rdata"])
311+
resolved_ns_ips.append("%d.%d.%d.%d" % (b[0], b[1], b[2], b[3]))
312+
elif rr["type"] == QTYPE["AAAA"] and rr["rdlen"] == 16:
313+
resolved_ns_ips.append(socket.inet_ntop(socket.AF_INET6, rr["rdata"]))
314+
315+
if resolved_ns_ips:
316+
break # prefer AAAA if it worked
317+
295318
if resolved_ns_ips:
296-
break
319+
break # first NS that yields IPs
320+
297321
if resolved_ns_ips:
298322
random.shuffle(resolved_ns_ips)
299323
next_servers = resolved_ns_ips + next_servers
@@ -397,8 +421,20 @@ def handle_query_wire(query_wire, client_addr=None):
397421
CACHE.put(key, resp, ttl=ttl)
398422
return resp
399423

424+
def _bind_family(bind_ip):
425+
return socket.AF_INET6 if ":" in bind_ip else socket.AF_INET
426+
400427
def udp_server(bind_ip="127.0.0.1", port=5353):
401-
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
428+
fam = _bind_family(bind_ip)
429+
s = socket.socket(fam, socket.SOCK_DGRAM)
430+
431+
# Optional dual-stack (may be ignored on Android)
432+
if fam == socket.AF_INET6:
433+
try:
434+
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
435+
except Exception:
436+
pass
437+
402438
s.bind((bind_ip, port))
403439
print("UDP DNS stub listening on %s:%d" % (bind_ip, port))
404440
while True:
@@ -410,8 +446,17 @@ def udp_server(bind_ip="127.0.0.1", port=5353):
410446
s.sendto(resp, addr)
411447

412448
def tcp_server(bind_ip="127.0.0.1", port=5353):
413-
ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
449+
fam = _bind_family(bind_ip)
450+
ss = socket.socket(fam, socket.SOCK_STREAM)
414451
ss.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
452+
453+
# Optional dual-stack (may be ignored on Android)
454+
if fam == socket.AF_INET6:
455+
try:
456+
ss.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
457+
except Exception:
458+
pass
459+
415460
ss.bind((bind_ip, port))
416461
ss.listen(50)
417462
print("TCP DNS stub listening on %s:%d" % (bind_ip, port))
@@ -489,7 +534,7 @@ def run_stub(bind_ip="127.0.0.1", port=5353):
489534

490535
args = parser.parse_args()
491536

492-
# Apply runtime config
537+
# Apply runtime config (top-level assignments; no 'global' needed)
493538
UPSTREAM_TIMEOUT = float(args.upstream_timeout)
494539
if args.timeout is not None:
495540
UPSTREAM_TIMEOUT = float(args.timeout)

0 commit comments

Comments
 (0)