Renaming Project and changing license

This commit is contained in:
Sven Luthi committed 2026-04-08 10:24:24 +02:00
1 parent 4a1930a896
commit 756c491e28
24 files changed
+173 -555

No files matched your search

@@ -0,0 +1,117 @@
import logging
import threading
import dns.query
import dns.message
import dns.tsigkeyring
import dns.name
import dns.zone
import dns.rdatatype
import dns.rdataclass
import dns.rdtypes
import dns.exception
import dns.renderer
from django.core.management.base import BaseCommand
from django.conf import settings
from netbox_dns.models import View
from netbox_dns_bridge.service.endpoint.request_handler import UDPRequestHandler, TCPRequestHandler
from netbox_dns_bridge.service.endpoint.dns_server import UDPDNSServer, TCPDNSServer
from netbox_dns_bridge.service.endpoint import catalog_zone_manager as catzm
logger = logging.getLogger("dns-transfer-endpoint")
class Command(BaseCommand):
help = "Run a minimal AXFR DNS server using data from NetBox DNS plugin"
def load_settings(self):
self.settings = settings.PLUGINS_CONFIG.get(
"netbox_dns_bridge", None
)
if not self.settings:
raise RuntimeError(
"Command failed to initialize due to missing settings. Terminating Netbox."
)
self.tsig_keys = self.settings.get("tsig_keys", None)
if not self.tsig_keys:
raise RuntimeError("tsig_keys variable not set in plugin settings.")
# Load TSIG keys and map them to views
def load_tsig_key_settings(self):
self.keyring = {}
self.tsig_view_map = {}
for view_name, data in self.tsig_keys.items():
raw_key_name = data.get("keyname")
secret = data.get("secret")
algorithm_str = data.get("algorithm", "hmac-sha256")
if not raw_key_name or not secret:
logger.error(
f"Skipping TSIG key for view {view_name}: missing keyname or secret."
)
continue
try:
nb_view = View.objects.get(name=view_name)
except View.DoesNotExist:
logger.error(
f"Skipping TSIG key {raw_key_name}: view '{view_name}' not found."
)
continue
# Normalize key name to absolute DNS name
key_name_obj = dns.name.from_text(raw_key_name, origin=None).canonicalize()
if not key_name_obj.is_absolute():
key_name_obj = key_name_obj.concatenate(dns.name.root)
key_name_str = key_name_obj.to_text() # Will always include trailing do
self.keyring[key_name_obj] = dns.tsig.Key(
name=key_name_obj, secret=secret, algorithm=algorithm_str
)
self.tsig_view_map[key_name_str] = nb_view
logger.debug(f"Loaded TSIG key: {key_name_str} view: {nb_view.name}")
if not self.keyring:
msg = "No TSIG keys found in database."
logger.critical(msg)
raise RuntimeError(msg)
def add_arguments(self, parser):
parser.add_argument(
"--port", type=int, default=5354, help="Port number to listen on"
)
parser.add_argument(
"--address", type=str, default="0.0.0.0", help="IP to bind to"
)
def handle(self, *args, **options):
# Load parameters
port = options["port"]
address = options["address"]
catzm.init()
# Initialize settings
self.load_settings()
self.load_tsig_key_settings()
udp_server = UDPDNSServer(
(address, port), UDPRequestHandler, self.keyring, self.tsig_view_map
)
tcp_server = TCPDNSServer(
(address, port), TCPRequestHandler, self.keyring, self.tsig_view_map
)
def run_udp_server(server):
logger.debug(f"Query endpoint listening on {address} udp/{port}")
server.serve_forever()
udp_thread = threading.Thread(
target=run_udp_server, args=(udp_server,), daemon=True
)
udp_thread.start()
logger.debug(f"Query endpoint listening on {address} tcp/{port}")
tcp_server.serve_forever()
@@ -0,0 +1,47 @@
import os
import dns.zone
import dns.rdatatype
import dns.rdataclass
import dns.exception
import netbox_dns.models
from netbox_dns_bridge.utils import export_bind_zone_file
from django.core.management.base import BaseCommand, CommandError
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument(
"--path", type=str, help="Path to the directory where zone files are to be written"
)
def handle(self, *args, **options):
# Load parameters
base_path = options['path']
if not base_path:
raise CommandError("No --path parameter given")
# Ensure base_path exists
os.makedirs(base_path, exist_ok=True)
# Iterate through all zones
nb_zones = netbox_dns.models.Zone.objects.prefetch_related("view").all()
if not nb_zones.exists():
self.stdout.write(self.style.WARNING("No zones found in NetBox DNS."))
return
for zone in nb_zones:
# Determine view directory
view_name = zone.view.name
view_dir = os.path.join(base_path, view_name)
os.makedirs(view_dir, exist_ok=True)
# Zone file path
file_path = os.path.join(view_dir, zone.name)
try:
# Call existing export function
export_bind_zone_file(zone, file_path=file_path)
self.stdout.write(self.style.SUCCESS(f"Exported zone '{zone.name}' to '{file_path}'"))
except Exception as e:
self.stderr.write(f"Failed to export zone '{zone.name}': {e}")
@@ -0,0 +1,56 @@
import os
import dns.zone
import dns.rdatatype
import dns.rdataclass
import dns.exception
import netbox_dns.models
from netbox_dns_bridge.utils import export_bind_zone_file
from django.core.management.base import BaseCommand, CommandError
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument(
"--view", type=str, help="The name of the view the Zone to be exported is in"
)
parser.add_argument(
"--zone", type=str, help="The FQDN of the Zone to be exported"
)
parser.add_argument(
"--file", type=str, help="Path of the zone file to be written"
)
def handle(self, *args, **options):
#if len(options) < 2:
# print("export-zone <zone name> <file path>")
# sys.exit(1)
# Load parameters
view_name = options['view']
zone_name = options['zone']
file_path = options['file']
if not view_name:
raise CommandError("No --view parameter given")
elif not zone_name:
raise CommandError("No --zone parameter given")
elif not file_path:
raise CommandError("No --file parameter given")
try:
# Load the zone from NetBox DNS
nb_zone = netbox_dns.models.Zone.objects.get(view__name=view_name, name=zone_name)
if nb_zone:
export_bind_zone_file(nb_zone, file_path=file_path)
else:
print("Zone not found in Netbox. Aborting")
sys.exit(1)
except Exception as e:
raise CommandError(f"Failed to export zone: {e}")
self.stdout.write(self.style.SUCCESS(f"Zone '{zone_name}' exported to '{file_path}'"))