Compare commits

...
4 Commits
Author SHA1 Message Date
Sven Luthi cfb4633006 modified: netbox_dns_bridge/__init__.py
Bump version
2026-07-20 15:21:36 +02:00
Sven Luthi b4ab5596d6 modified: netbox_dns_bridge/notify_handler.py
modified:   netbox_dns_bridge/signals/netbox_dns_zones.py
Some code cleanup
2026-07-20 15:21:14 +02:00
Sven Luthi 11ea9a6f1a modified: README.md
modified:   netbox_dns_bridge/notify_handler.py
Remove hardcoded client notify port and connect to plugin setting
instead.
2026-07-20 15:07:21 +02:00
Sven Luethi 83965817d6 Update README 2026-07-16 14:54:35 +02:00
4 changed files with 59 additions and 32 deletions

No files matched your search

+43 -13
View File
@@ -18,7 +18,8 @@ changes (RFC 1996).
<a href="https://pepy.tech/project/netbox-plugin-dns-bridge"><img src="https://static.pepy.tech/personalized-badge/netbox-plugin-dns-bridge?period=monthly&left_color=BLACK&right_color=BLUE&left_text=Downloads%2fMonth" alt="Downloads/Month"></a> <a href="https://pepy.tech/project/netbox-plugin-dns-bridge"><img src="https://static.pepy.tech/personalized-badge/netbox-plugin-dns-bridge?period=monthly&left_color=BLACK&right_color=BLUE&left_text=Downloads%2fMonth" alt="Downloads/Month"></a>
<a href="https://pepy.tech/project/netbox-plugin-dns-bridge"><img src="https://static.pepy.tech/personalized-badge/netbox-plugin-dns-bridge?period=weekly&left_color=BLACK&right_color=BLUE&left_text=Downloads%2fWeek" alt="Downloads/Week"></a> <a href="https://pepy.tech/project/netbox-plugin-dns-bridge"><img src="https://static.pepy.tech/personalized-badge/netbox-plugin-dns-bridge?period=weekly&left_color=BLACK&right_color=BLUE&left_text=Downloads%2fWeek" alt="Downloads/Week"></a>
## Plugin configuration
# Plugin configuration
While providing Zone transfers via AXFR, the Server also exposes specialized catalog zones that BIND While providing Zone transfers via AXFR, the Server also exposes specialized catalog zones that BIND
and other RFC9432 compliant DNS Servers use to automatically discover newly created zones and remove and other RFC9432 compliant DNS Servers use to automatically discover newly created zones and remove
deleted ones. The plugin supports views and basic DNS security via TSIG. deleted ones. The plugin supports views and basic DNS security via TSIG.
@@ -39,13 +40,15 @@ This process needs to be scheduled as a background service for the built-in DNS
correctly. For Linux users with Systemd (Ubuntu, etc), Matt Kollross provides a startup unit and correctly. For Linux users with Systemd (Ubuntu, etc), Matt Kollross provides a startup unit and
instructions [here](docs/install-systemd-service.md). instructions [here](docs/install-systemd-service.md).
### Service parameters
## Service parameters
Parameter | Description Parameter | Description
--------- | ------------------------------------------------------------------- --------- | -------------------------------------------------------------------
--port | Port to listen on for requests (defaults to 5354) --port | Port to listen on for requests (defaults to 5354)
--address | IP of interface to bind to (defaults to 0.0.0.0) --address | IP of interface to bind to (defaults to 0.0.0.0)
### Plugin settings
## Plugin settings
Plugin settings should be configured under `PLUGINS_CONFIG` in `netbox_dns_bridge`: Plugin settings should be configured under `PLUGINS_CONFIG` in `netbox_dns_bridge`:
``` ```
PLUGINS_CONFIG = { PLUGINS_CONFIG = {
@@ -56,7 +59,7 @@ PLUGINS_CONFIG = {
} }
``` ```
#### TSIG Authentication ### TSIG Authentication
Following sets the TSIG key that allows clients to query the transfer endpoint and also they key to Following sets the TSIG key that allows clients to query the transfer endpoint and also they key to
be used to sign NOTIFY messages to clients on zone changes. Each view should have its own unique be used to sign NOTIFY messages to clients on zone changes. Each view should have its own unique
key to allow the plugin to identify the view the client is trying to access. Re-using the key for key to allow the plugin to identify the view the client is trying to access. Re-using the key for
@@ -71,7 +74,21 @@ multiple views yields unpredicted behavior.
} }
``` ```
#### NOTIFY ### NOTIFY
The plugin has 2 different NOTIFY mechanisms that may be turned on individually or together.
1. [Client Notify](#client-notify)
2. [NS Notify](ns-notify)
- [Per Zone](ns-notify-per-zone)
- [For all Zones](ns-notify-for-all-zones)
Note: This makes the *Per Zone* mechanism redundant. There is no point in enabling both.
#### Global NOTIFY Settings
```
'notify_over_tcp': True
```
Switch to using TCP instead of UDP. Defaults to False
#### Client NOTIFY
Clients may be notified of zone changes using the NOTIFY mechanism defined in RFC 1996. Clients may be notified of zone changes using the NOTIFY mechanism defined in RFC 1996.
When enabled, the zone transfer endpoint keeps track of any client that successfully queried the When enabled, the zone transfer endpoint keeps track of any client that successfully queried the
endpoint. Once a zone has changed, NetBox informs each client about the zone changed so that the endpoint. Once a zone has changed, NetBox informs each client about the zone changed so that the
@@ -81,7 +98,6 @@ Note that this feature uses NetBox's background job system to schedule the messa
In order to work, you need at least one `rq-worker` service running in the background to handle In order to work, you need at least one `rq-worker` service running in the background to handle
the queued jobs. the queued jobs.
##### NOTIFY Settings
``` ```
'notify_clients': True 'notify_clients': True
``` ```
@@ -93,12 +109,15 @@ This enables the NOTIFY system. Defaults to False
This sets how long a client is considred "alive" after it last queried the transfer endpoint. This sets how long a client is considred "alive" after it last queried the transfer endpoint.
Once the client has failed to check in for this amout of time, it is automatically removed from the Once the client has failed to check in for this amout of time, it is automatically removed from the
list of clients to be notified on zone changes. Default is 24 hours. list of clients to be notified on zone changes. Default is 24 hours.
```
'notify_over_tcp': True
```
Switch to using TCP instead of UDP. Defaults to False
#### NOTIFY to a zone's own nameservers ```
'notify_client_port': 53
```
Destination port used to send NOTIFY messages to clients. Defaults to 53.
#### NS NOTIFY
In addition to notifying clients that queried the transfer endpoint, the plugin can send a NOTIFY In addition to notifying clients that queried the transfer endpoint, the plugin can send a NOTIFY
directly to a zone's own nameservers whenever that zone's SOA serial number changes. This is useful directly to a zone's own nameservers whenever that zone's SOA serial number changes. This is useful
when you want nameservers to pull updates immediately, independent of the `notify_clients` mechanism. when you want nameservers to pull updates immediately, independent of the `notify_clients` mechanism.
@@ -108,7 +127,12 @@ not.
This can be enabled per zone, globally, or both. If neither of the settings below is configured, the This can be enabled per zone, globally, or both. If neither of the settings below is configured, the
feature is disabled entirely. feature is disabled entirely.
**Per zone (custom field).** Create a boolean custom field (e.g. `dns_bridge_notify_ns`) that applies
##### NS NOTIFY per Zone
This uses a True/False custom field attached to each Zone to enable/disable NOTIFY for each
individually.
Create a boolean custom field (e.g. `dns_bridge_notify_ns`) that applies
to `netbox_dns > zone`, then point the plugin at it: to `netbox_dns > zone`, then point the plugin at it:
``` ```
'notify_ns_custom_field_name': 'dns_bridge_notify_ns' 'notify_ns_custom_field_name': 'dns_bridge_notify_ns'
@@ -116,7 +140,8 @@ to `netbox_dns > zone`, then point the plugin at it:
A NOTIFY is then sent for any zone whose custom field is set to `True`. This lets you toggle the A NOTIFY is then sent for any zone whose custom field is set to `True`. This lets you toggle the
behavior per zone straight from the NetBox UI, without changing the plugin config. behavior per zone straight from the NetBox UI, without changing the plugin config.
**Globally (all zones).**
##### NS NOTIFY for all Zones
``` ```
'notify_ns_all_zones': True 'notify_ns_all_zones': True
``` ```
@@ -124,6 +149,9 @@ When enabled, a NOTIFY is sent for every zone on serial change, regardless of th
Defaults to `False`. The two options coexist: a NOTIFY is sent if the global switch is on **or** the Defaults to `False`. The two options coexist: a NOTIFY is sent if the global switch is on **or** the
zone's custom field is set. zone's custom field is set.
##### NS NOTIFY Settings
The nameserver addresses are resolved from NetBox DNS itself by looking up active A/AAAA records The nameserver addresses are resolved from NetBox DNS itself by looking up active A/AAAA records
(within the zone's view) matching each nameserver's hostname. The NOTIFY messages are signed with the (within the zone's view) matching each nameserver's hostname. The NOTIFY messages are signed with the
same per-view TSIG key configured under `tsig_keys`, so the receiving nameservers must accept NOTIFY same per-view TSIG key configured under `tsig_keys`, so the receiving nameservers must accept NOTIFY
@@ -137,12 +165,14 @@ Destination port used for these NOTIFY messages. Defaults to 53.
As with the client NOTIFY feature, this uses NetBox's background job system, so at least one As with the client NOTIFY feature, this uses NetBox's background job system, so at least one
`rq-worker` service must be running. `rq-worker` service must be running.
## Plugin compatibility ## Plugin compatibility
This plugin extends the netbox-plugin-dns plugin. As such the versioning was changed to match the This plugin extends the netbox-plugin-dns plugin. As such the versioning was changed to match the
one of netbox-plugin-dns more closely. To guarantee compatability, ensure that the major and minor one of netbox-plugin-dns more closely. To guarantee compatability, ensure that the major and minor
version match between both plugins. For example, when using netbox-plugin-dns `v1.5.5` install version match between both plugins. For example, when using netbox-plugin-dns `v1.5.5` install
netbox-plugin-dns-bridge `v1.5.x`. netbox-plugin-dns-bridge `v1.5.x`.
## Installation guide ## Installation guide
This setup provisions a BIND9 server directly with DNS data from NetBox. BIND9 can optionally run on This setup provisions a BIND9 server directly with DNS data from NetBox. BIND9 can optionally run on
a separate server. If so, any reference to 127.0.0.1 in step 6 must be replaced with the IP address a separate server. If so, any reference to 127.0.0.1 in step 6 must be replaced with the IP address
+1 -1
View File
@@ -2,7 +2,7 @@ from netbox.plugins import PluginConfig
from django.conf import settings from django.conf import settings
from .logger import get_logger from .logger import get_logger
__version__ = "1.5.7" __version__ = "1.5.8"
LOGGER = get_logger(__name__) LOGGER = get_logger(__name__)
+13 -16
View File
@@ -42,12 +42,13 @@ def _load_tsig_key(view_name: str) -> dns.tsig.Key:
return dns.tsig.Key(name=key_name, secret=secret, algorithm=algorithm) return dns.tsig.Key(name=key_name, secret=secret, algorithm=algorithm)
class SendDNSNotify(JobRunner): class SendClientDNSNotify(JobRunner):
class Meta: class Meta:
name = "Send DNS NOTIFY" name = "Send DNS NOTIFY"
def run(self, *args, **kwargs): def run(self, *args, **kwargs):
notify_over_tcp = SETTINGS.get("notify_over_tcp", False) notify_over_tcp = SETTINGS.get("notify_over_tcp", False)
port = SETTINGS.get("notify_client_port", 53)
view_name = kwargs["view_name"] view_name = kwargs["view_name"]
try: try:
@@ -89,17 +90,17 @@ class SendDNSNotify(JobRunner):
try: try:
if notify_over_tcp: if notify_over_tcp:
LOGGER.debug("Sending NOTIFY over TCP") LOGGER.debug("Sending NOTIFY over TCP")
dns.query.tcp(msg, client.source_ip, port=5355, timeout=2) dns.query.tcp(msg, client.source_ip, port=port, timeout=2)
else: else:
LOGGER.debug("Sending NOTIFY over UDP") LOGGER.debug("Sending NOTIFY over UDP")
dns.query.udp(msg, client.source_ip, port=5355, timeout=2) dns.query.udp(msg, client.source_ip, port=port, timeout=2)
LOGGER.info( LOGGER.info(
f"NOTIFY sent: {client.source_ip} {view_name}/{zone_name} {soa_serial}" f"NOTIFY sent: {client.source_ip} {view_name}/{zone_name} {soa_serial}"
) )
except Exception as e: except Exception as e:
LOGGER.error( LOGGER.error(
f"NOTIFY failed: {client.source_ip}" f"NOTIFY failed: {client.source_ip}:{port}"
f" {view_name}/{zone_name} {soa_serial}: {e}" f" {view_name}/{zone_name} {soa_serial}: {e}"
) )
@@ -111,10 +112,10 @@ class SendDNSNotify(JobRunner):
close_old_connections() close_old_connections()
class SendZoneNSNotify(JobRunner): class SendNSNotify(JobRunner):
"""Send a NOTIFY straight to a zone's own nameservers. """Send a NOTIFY straight to a zone's own nameservers.
Unlike ``SendDNSNotify`` (which notifies clients that previously queried the Unlike ``SendClientDNSNotify`` (which notifies clients that previously queried the
transfer endpoint), this job resolves the addresses of the zone's configured transfer endpoint), this job resolves the addresses of the zone's configured
nameservers from NetBox DNS itself and notifies each of them so they pick up nameservers from NetBox DNS itself and notifies each of them so they pick up
the changed zone quickly. the changed zone quickly.
@@ -151,9 +152,7 @@ class SendZoneNSNotify(JobRunner):
try: try:
tsig_key = _load_tsig_key(view_name) tsig_key = _load_tsig_key(view_name)
except RuntimeError as e: except RuntimeError as e:
LOGGER.error( LOGGER.error(f"NS NOTIFY aborted for {view_name}/{zone_name}: {e}")
f"NS NOTIFY aborted for {view_name}/{zone_name}: {e}"
)
return return
fqdn = dns.name.from_text(zone_name, dns.name.root).to_text() fqdn = dns.name.from_text(zone_name, dns.name.root).to_text()
@@ -178,9 +177,7 @@ class SendZoneNSNotify(JobRunner):
LOGGER.debug("Sending NS NOTIFY over UDP") LOGGER.debug("Sending NS NOTIFY over UDP")
dns.query.udp(msg, ip, port=port, timeout=2) dns.query.udp(msg, ip, port=port, timeout=2)
LOGGER.info( LOGGER.info(f"NS NOTIFY sent: {ip} {view_name}/{fqdn} {soa_serial}")
f"NS NOTIFY sent: {ip} {view_name}/{fqdn} {soa_serial}"
)
except Exception as e: except Exception as e:
LOGGER.error( LOGGER.error(
f"NS NOTIFY failed: {ip} {view_name}/{fqdn} {soa_serial}: {e}" f"NS NOTIFY failed: {ip} {view_name}/{fqdn} {soa_serial}: {e}"
@@ -241,24 +238,24 @@ def _resolve_zone_nameserver_ips(zone: Zone) -> list:
return ips return ips
def schedule(zone: Zone): def schedule_client_notify(zone: Zone):
soa_serial = _get_soa_serial(zone) soa_serial = _get_soa_serial(zone)
if soa_serial is None: if soa_serial is None:
return return
SendDNSNotify.enqueue( SendClientDNSNotify.enqueue(
zone_name=zone.name, zone_name=zone.name,
view_name=zone.view.name, view_name=zone.view.name,
soa_serial=soa_serial, soa_serial=soa_serial,
) )
def schedule_notify_ns(zone: Zone): def schedule_ns_notify(zone: Zone):
soa_serial = _get_soa_serial(zone) soa_serial = _get_soa_serial(zone)
if soa_serial is None: if soa_serial is None:
return return
SendZoneNSNotify.enqueue( SendNSNotify.enqueue(
zone_id=zone.pk, zone_id=zone.pk,
zone_name=zone.name, zone_name=zone.name,
view_name=zone.view.name, view_name=zone.view.name,
@@ -52,12 +52,12 @@ def zone_post_save(sender, instance, created, **kwargs):
catzm.increment_soa_serial() catzm.increment_soa_serial()
if SETTINGS.get("notify_clients", False): if SETTINGS.get("notify_clients", False):
notify_handler.schedule(zone) notify_handler.schedule_client_notify(zone)
# Send a NOTIFY to the zone's own nameservers when its SOA serial changed # Send a NOTIFY to the zone's own nameservers when its SOA serial changed
# and the feature is enabled — globally or per zone via a custom field. # and the feature is enabled — globally or per zone via a custom field.
if soa_serial_changed and _notify_ns_enabled(zone): if soa_serial_changed and _notify_ns_enabled(zone):
notify_handler.schedule_notify_ns(zone) notify_handler.schedule_ns_notify(zone)
transaction.on_commit(_on_commit) transaction.on_commit(_on_commit)