From bf9035aded097deded0077e082160dcc0b7d11c3 Mon Sep 17 00:00:00 2001 From: Sven Luethi Date: Tue, 11 Aug 2026 10:59:36 +0200 Subject: [PATCH] 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. --- netbox_dns_bridge/request_handler.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/netbox_dns_bridge/request_handler.py b/netbox_dns_bridge/request_handler.py index 60ead04..a456b81 100644 --- a/netbox_dns_bridge/request_handler.py +++ b/netbox_dns_bridge/request_handler.py @@ -24,6 +24,8 @@ SETTINGS = settings.PLUGINS_CONFIG["netbox_dns_bridge"] class DNSBaseRequestHandler(socketserver.BaseRequestHandler): + transport = None + def __init__(self, request, client_address, server) -> None: self.MAX_WIRE = 65535 self.RESERVED_TSIG = 300 @@ -265,6 +267,11 @@ class DNSBaseRequestHandler(socketserver.BaseRequestHandler): self._deny_request(query) 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 if not query.had_tsig: LOGGER.warning(f"Request denied from {peer}: No TSIG key used") @@ -309,6 +316,8 @@ class DNSBaseRequestHandler(socketserver.BaseRequestHandler): class UDPRequestHandler(DNSBaseRequestHandler): + transport = "udp" + def __init__(self, request, client_address, server) -> None: super().__init__(request, client_address, server) @@ -329,6 +338,8 @@ class UDPRequestHandler(DNSBaseRequestHandler): class TCPRequestHandler(DNSBaseRequestHandler): + transport = "tcp" + def __init__(self, request, client_address, server) -> None: super().__init__(request, client_address, server)