Refuse AXFR over UDP instead of crashing
AXFR is a TCP-only operation (RFC 5936), but the request handler did
not enforce that. When a UDP datagram carrying an AXFR query arrived,
control reached _handle_axfr_request, which builds the multi-message
response and writes each chunk with:
self.request.sendall(len(wire).to_bytes(2, 'big') + wire)
For a UDP handler self.request is a (data, sock) tuple, not a socket,
so sendall raised AttributeError. The exception was caught by the
outer try/except in UDPRequestHandler.handle, so the server stayed up,
but the client received no response at all and the error was only
visible in a generic 'Error handling request' traceback.
Add a 'transport' class attribute ('tcp' / 'udp') to the concrete
handler classes and, immediately after the qtype check (before TSIG
validation and zone lookup), deny AXFR-over-UDP with REFUSED. The
client now gets a proper refusal and the AXFR handler is never entered
on a UDP socket.
This commit is contained in:
1 parent
74ceb0206a
commit
0277063dcc
1 file changed
+11
@@ -24,6 +24,8 @@ SETTINGS = settings.PLUGINS_CONFIG["netbox_dns_bridge"]
|
|||||||
|
|
||||||
|
|
||||||
class DNSBaseRequestHandler(socketserver.BaseRequestHandler):
|
class DNSBaseRequestHandler(socketserver.BaseRequestHandler):
|
||||||
|
transport = None
|
||||||
|
|
||||||
def __init__(self, request, client_address, server) -> None:
|
def __init__(self, request, client_address, server) -> None:
|
||||||
self.MAX_WIRE = 65535
|
self.MAX_WIRE = 65535
|
||||||
self.RESERVED_TSIG = 300
|
self.RESERVED_TSIG = 300
|
||||||
@@ -265,6 +267,11 @@ class DNSBaseRequestHandler(socketserver.BaseRequestHandler):
|
|||||||
self._deny_request(query)
|
self._deny_request(query)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if qtype == dns.rdatatype.AXFR and self.transport != "tcp":
|
||||||
|
LOGGER.warning(f"Request denied from {peer}: AXFR requires TCP")
|
||||||
|
self._deny_request(query, dns.rcode.REFUSED)
|
||||||
|
return
|
||||||
|
|
||||||
# Identify TSIG key used
|
# Identify TSIG key used
|
||||||
if not query.had_tsig:
|
if not query.had_tsig:
|
||||||
LOGGER.warning(f"Request denied from {peer}: No TSIG key used")
|
LOGGER.warning(f"Request denied from {peer}: No TSIG key used")
|
||||||
@@ -309,6 +316,8 @@ class DNSBaseRequestHandler(socketserver.BaseRequestHandler):
|
|||||||
|
|
||||||
|
|
||||||
class UDPRequestHandler(DNSBaseRequestHandler):
|
class UDPRequestHandler(DNSBaseRequestHandler):
|
||||||
|
transport = "udp"
|
||||||
|
|
||||||
def __init__(self, request, client_address, server) -> None:
|
def __init__(self, request, client_address, server) -> None:
|
||||||
super().__init__(request, client_address, server)
|
super().__init__(request, client_address, server)
|
||||||
|
|
||||||
@@ -329,6 +338,8 @@ class UDPRequestHandler(DNSBaseRequestHandler):
|
|||||||
|
|
||||||
|
|
||||||
class TCPRequestHandler(DNSBaseRequestHandler):
|
class TCPRequestHandler(DNSBaseRequestHandler):
|
||||||
|
transport = "tcp"
|
||||||
|
|
||||||
def __init__(self, request, client_address, server) -> None:
|
def __init__(self, request, client_address, server) -> None:
|
||||||
super().__init__(request, client_address, server)
|
super().__init__(request, client_address, server)
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user