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:
+17
-10
@@ -218,21 +218,31 @@ def dns_response(packet, use_tcp=False):
|
|||||||
return struct.pack("!HHHHHH", transaction_id, response_flags | 1, 0, 0, 0, 0)
|
return struct.pack("!HHHHHH", transaction_id, response_flags | 1, 0, 0, 0, 0)
|
||||||
|
|
||||||
question = packet[12:question_end]
|
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).
|
# Exceptions bypass overrides and are forwarded upstream (nanoDNS semantics).
|
||||||
if match_any(name, EXCEPTIONS):
|
if is_exception:
|
||||||
try:
|
try:
|
||||||
return forward_query(packet, use_tcp=use_tcp)
|
return forward_query(packet, use_tcp=use_tcp)
|
||||||
except (OSError, ValueError) as error:
|
except (OSError, ValueError) as error:
|
||||||
print(f"DNS upstream failure for {name}: {error}", flush=True)
|
print(f"DNS upstream failure for {name}: {error}", flush=True)
|
||||||
return error_response(packet, 2) # SERVFAIL
|
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 = (
|
answer = (
|
||||||
b"\xc0\x0c"
|
b"\xc0\x0c"
|
||||||
+ struct.pack("!HHIH", 1, 1, 60, 4)
|
+ struct.pack("!HHIH", 1, 1, 60, 4)
|
||||||
@@ -240,9 +250,6 @@ def dns_response(packet, use_tcp=False):
|
|||||||
)
|
)
|
||||||
return struct.pack("!HHHHHH", transaction_id, response_flags, 1, 1, 0, 0) + question + answer
|
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
|
|
||||||
|
|
||||||
|
|
||||||
class ThreadingUDPServer(socketserver.ThreadingUDPServer):
|
class ThreadingUDPServer(socketserver.ThreadingUDPServer):
|
||||||
allow_reuse_address = True
|
allow_reuse_address = True
|
||||||
|
|||||||
@@ -207,6 +207,17 @@ overrides (spoof) → NXDOMAIN. Unlike upstream nanoDNS, a name matching no rule
|
|||||||
blocked by default. The PS5 sends DNS only to `net-utils01`; that host must be
|
blocked by default. The PS5 sends DNS only to `net-utils01`; that host must be
|
||||||
allowed to reach the configured upstream resolver on UDP/TCP 53.
|
allowed to reach the configured upstream resolver on UDP/TCP 53.
|
||||||
|
|
||||||
|
The gateway is **IPv4-only**: it serves only `A` (and `ANY`) queries. `AAAA` and
|
||||||
|
any other record type return NOERROR with no data, for both overrides and
|
||||||
|
forwarded names. The console LAN has no IPv6 route, so returning a real `AAAA`
|
||||||
|
would make clients stall on an unreachable IPv6 address. This specifically fixed
|
||||||
|
the PS5 Payload Manager looping forever on "synchronizing repositories": its
|
||||||
|
catalog host `itsplk.github.io` is dual-stack, the console tried the IPv6 address,
|
||||||
|
and the manager's libcurl download has no timeout, so the hung connection never
|
||||||
|
returned. The official Payload Manager repository needs only `itsplk.github.io`
|
||||||
|
(catalog), `github.com` (payload `url`s) and `release-assets.githubusercontent.com`
|
||||||
|
(release-download redirect target), all already in `[exceptions]`.
|
||||||
|
|
||||||
The gateway additionally restricts which source clients it answers, via
|
The gateway additionally restricts which source clients it answers, via
|
||||||
`[general] allowed_clients`. It defaults to the console VLAN `192.168.40.0/28`,
|
`[general] allowed_clients`. It defaults to the console VLAN `192.168.40.0/28`,
|
||||||
the server VLAN `192.168.20.0/24`, and the trusted management VLAN
|
the server VLAN `192.168.20.0/24`, and the trusted management VLAN
|
||||||
|
|||||||
Reference in New Issue
Block a user