modified: src/netbox_plugin_bind_provisioner/management/commands/bind-transfer-endpoint.py

Fixes broken dns responses to UDP endpoint (denyRequest function replaced)
This commit is contained in:
Sven Luethi committed 2025-11-25 00:03:36 +01:00
1 parent 204a946a84
commit 962be7a048
1 file changed
+28 -14
@@ -260,17 +260,15 @@ class DNSBaseRequestHandler(socketserver.BaseRequestHandler):
# Replace the rdataset for the given name and type # Replace the rdataset for the given name and type
zone.replace_rdataset(name, rdataset) zone.replace_rdataset(name, rdataset)
return zone return zone
# def denyRequest(self, query, rcode: dns.rcode = dns.rcode.REFUSED):
def denyRequest(self, query, rcode: dns.rcode = dns.rcode.REFUSED): # response = dns.message.make_response(query)
response = dns.message.make_response(query) # response.set_rcode(rcode)
response.set_rcode(rcode) # wire = response.to_wire(multi=False)
wire = response.to_wire(multi=False) # length = len(wire).to_bytes(2, byteorder="big")
length = len(wire).to_bytes(2, byteorder="big") # self.request.sendall(length + wire)
self.request.sendall(length + wire)
def denyRequestBadTSIG(self, wire, tsig_error: dns.rcode): def denyRequestBadTSIG(self, wire, tsig_error: dns.rcode):
@@ -292,6 +290,13 @@ class DNSBaseRequestHandler(socketserver.BaseRequestHandler):
class UDPRequestHandler(DNSBaseRequestHandler): class UDPRequestHandler(DNSBaseRequestHandler):
def denyRequest(self, query, rcode: dns.rcode = dns.rcode.REFUSED):
response = dns.message.make_response(query)
response.set_rcode(rcode)
wire = response.to_wire(multi=False)
sock = self.request[1]
sock.sendto(wire, self.client_address)
def handle(self): def handle(self):
data, sock = self.request data, sock = self.request
peer = self.client_address[0] peer = self.client_address[0]
@@ -301,7 +306,7 @@ class UDPRequestHandler(DNSBaseRequestHandler):
query = dns.message.from_wire( query = dns.message.from_wire(
data, data,
keyring=self.server.keyring, keyring=self.server.keyring,
continue_on_error=True, continue_on_error=False,
ignore_trailing=True ignore_trailing=True
) )
except Exception as e: except Exception as e:
@@ -328,12 +333,13 @@ class UDPRequestHandler(DNSBaseRequestHandler):
return return
# Identify TSIG key used # Identify TSIG key used
key_name = query.keyname.canonicalize().to_text() if query.keyname else None if not query.had_tsig:
if not key_name:
logger.warning(f"Request denied from {peer}: No TSIG key used") logger.warning(f"Request denied from {peer}: No TSIG key used")
self.denyRequest(query) self.denyRequest(query)
return return
key_name = query.keyname.canonicalize().to_text()
# Check if key matches a view # Check if key matches a view
nb_view = self.server.tsig_view_map.get(key_name) nb_view = self.server.tsig_view_map.get(key_name)
if not nb_view: if not nb_view:
@@ -387,6 +393,13 @@ class UDPRequestHandler(DNSBaseRequestHandler):
class TCPRequestHandler(DNSBaseRequestHandler): class TCPRequestHandler(DNSBaseRequestHandler):
def denyRequest(self, query, rcode: dns.rcode = dns.rcode.REFUSED):
response = dns.message.make_response(query)
response.set_rcode(rcode)
wire = response.to_wire(multi=False)
length = len(wire).to_bytes(2, byteorder="big")
self.request.sendall(length + wire)
def handle(self): def handle(self):
MAX_WIRE = 65535 MAX_WIRE = 65535
# MAX_WIRE = 2000 # For testing fragmentation # MAX_WIRE = 2000 # For testing fragmentation
@@ -443,12 +456,13 @@ class TCPRequestHandler(DNSBaseRequestHandler):
return return
# Identify TSIG key used # Identify TSIG key used
key_name = query.keyname.canonicalize().to_text() if query.keyname else None if not query.had_tsig:
if not key_name:
logger.warning(f"Request denied from {peer}: No TSIG key used") logger.warning(f"Request denied from {peer}: No TSIG key used")
self.denyRequest(query) self.denyRequest(query)
return return
key_name = query.keyname.canonicalize().to_text()
# Check if the key matches a view # Check if the key matches a view
nb_view = self.server.tsig_view_map.get(key_name) nb_view = self.server.tsig_view_map.get(key_name)
if not nb_view: if not nb_view:
@@ -630,7 +644,7 @@ class Command(BaseCommand):
name=key_name_obj, secret=secret, algorithm=algorithm_str name=key_name_obj, secret=secret, algorithm=algorithm_str
) )
self.tsig_view_map[key_name_str] = nb_view self.tsig_view_map[key_name_str] = nb_view
logger.debug(f"Loaded TSIG key: {key_name_str} (view: {nb_view.name})") logger.debug(f"Loaded TSIG key: {key_name_str} view: {nb_view.name}")
if not self.keyring: if not self.keyring:
msg = "No TSIG keys found in database." msg = "No TSIG keys found in database."