Make the guide gateway IPv4-only to stop IPv6 stalls
Serve only A/ANY queries; answer AAAA and all other record types with NOERROR and no data, for overrides and forwarded names alike. The console LAN has no IPv6 route, so returning a real AAAA made clients stall on an unreachable address. This fixes the PS5 Payload Manager looping on "synchronizing repositories": its dual-stack catalog host itsplk.github.io handed back an IPv6 address and the manager's libcurl download (no timeout) hung on it indefinitely. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
+23
-16
@@ -218,30 +218,37 @@ def dns_response(packet, use_tcp=False):
|
||||
return struct.pack("!HHHHHH", transaction_id, response_flags | 1, 0, 0, 0, 0)
|
||||
|
||||
question = packet[12:question_end]
|
||||
is_exception = match_any(name, EXCEPTIONS)
|
||||
address = None if is_exception else override_for(name)
|
||||
|
||||
# Default-deny: a name matching no rule returns NXDOMAIN.
|
||||
if not is_exception and address is None:
|
||||
return struct.pack("!HHHHHH", transaction_id, response_flags | 3, 1, 0, 0, 0) + question
|
||||
|
||||
noerror_nodata = struct.pack("!HHHHHH", transaction_id, response_flags, 1, 0, 0, 0) + question
|
||||
|
||||
# IPv4-only resolver. Only A (and ANY) queries are served; AAAA and any other
|
||||
# record type get NOERROR with no data. The console LAN has no IPv6 route, so
|
||||
# handing back an AAAA record would make clients stall on an unreachable IPv6
|
||||
# address -- this is what left the PS5 Payload Manager looping on "synchronizing
|
||||
# repositories" for the dual-stack itsplk.github.io host.
|
||||
if qclass != 1 or qtype not in (1, 255):
|
||||
return noerror_nodata
|
||||
|
||||
# Exceptions bypass overrides and are forwarded upstream (nanoDNS semantics).
|
||||
if match_any(name, EXCEPTIONS):
|
||||
if is_exception:
|
||||
try:
|
||||
return forward_query(packet, use_tcp=use_tcp)
|
||||
except (OSError, ValueError) as error:
|
||||
print(f"DNS upstream failure for {name}: {error}", flush=True)
|
||||
return error_response(packet, 2) # SERVFAIL
|
||||
|
||||
address = override_for(name)
|
||||
if address is None:
|
||||
# Default-deny: a name matching no rule returns NXDOMAIN.
|
||||
return struct.pack("!HHHHHH", transaction_id, response_flags | 3, 1, 0, 0, 0) + question
|
||||
|
||||
if qclass == 1 and qtype in (1, 255):
|
||||
answer = (
|
||||
b"\xc0\x0c"
|
||||
+ struct.pack("!HHIH", 1, 1, 60, 4)
|
||||
+ address.packed
|
||||
)
|
||||
return struct.pack("!HHHHHH", transaction_id, response_flags, 1, 1, 0, 0) + question + answer
|
||||
|
||||
# NOERROR with no data prevents IPv6 or unsupported record fallback.
|
||||
return struct.pack("!HHHHHH", transaction_id, response_flags, 1, 0, 0, 0) + question
|
||||
answer = (
|
||||
b"\xc0\x0c"
|
||||
+ struct.pack("!HHIH", 1, 1, 60, 4)
|
||||
+ address.packed
|
||||
)
|
||||
return struct.pack("!HHHHHH", transaction_id, response_flags, 1, 1, 0, 0) + question + answer
|
||||
|
||||
|
||||
class ThreadingUDPServer(socketserver.ThreadingUDPServer):
|
||||
|
||||
Reference in New Issue
Block a user