aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/dhcpns/.gitignore3
-rw-r--r--tools/dhcpns/main.py87
-rw-r--r--tools/dhcpns/poetry.lock16
-rw-r--r--tools/dhcpns/pyproject.toml1
4 files changed, 94 insertions, 13 deletions
diff --git a/tools/dhcpns/.gitignore b/tools/dhcpns/.gitignore
new file mode 100644
index 0000000..ba7663d
--- /dev/null
+++ b/tools/dhcpns/.gitignore
@@ -0,0 +1,3 @@
+dhcp4.conf
+dhcp6.conf
+ddns.conf \ No newline at end of file
diff --git a/tools/dhcpns/main.py b/tools/dhcpns/main.py
index 32087e0..b81042f 100644
--- a/tools/dhcpns/main.py
+++ b/tools/dhcpns/main.py
@@ -5,6 +5,8 @@ import json
from pdns import PowerDNS
import ipaddress
import subprocess
+import re
+import netaddr
from config.dhcp4 import base as dhcp4
from config.dhcp6 import base as dhcp6
@@ -59,7 +61,7 @@ for vlan in vlans:
subnet6(vlan, prefix, DOMAIN_NAME, vlan_domain_name))
prefixes6.append(prefix)
- if vlan_domain_name not in zones and len(prefixes4) >= 1:
+ if f"{vlan_domain_name}." not in zones and len(prefixes4) >= 1:
print(pdns.create_zone(f"{vlan_domain_name}.", NAMESERVERS))
print(pdns.create_zone_metadata(
f"{vlan_domain_name}.", 'TSIG-ALLOW-DNSUPDATE', 'dhcpns'))
@@ -70,17 +72,20 @@ for vlan in vlans:
network = ipaddress.ip_network(prefix)
# Network ID
- zone_rrsets.append({'name': f'net-{network[0]}.{vlan_domain_name}', 'changetype': 'replace', 'type': 'A', 'records': [
+ zone_rrsets.append({'name': f'net-{network[0]}.{vlan_domain_name}.', 'changetype': 'replace', 'type': 'A', 'records': [
{'content': str(network[0]), 'disabled': False, 'type':'A'}], 'ttl': 900})
# Gateway
- zone_rrsets.append({'name': f'gw-{network[1]}.{vlan_domain_name}', 'changetype': 'replace', 'type': 'A', 'records': [
+ zone_rrsets.append({'name': f'gw-{network[1]}.{vlan_domain_name}.', 'changetype': 'replace', 'type': 'A', 'records': [
{'content': str(network[1]), 'disabled': False, 'type':'A'}], 'ttl': 900})
# Broadcast
- zone_rrsets.append({'name': f'broadcast-{network[-1]}.{vlan_domain_name}', 'changetype': 'replace', 'type': 'A', 'records': [
+ zone_rrsets.append({'name': f'broadcast-{network[-1]}.{vlan_domain_name}.', 'changetype': 'replace', 'type': 'A', 'records': [
{'content': str(network[-1]), 'disabled': False, 'type':'A'}], 'ttl': 900})
+ # Apply zone_rrsets
+ pdns.set_records(vlan_domain_name, zone_rrsets)
+
rdns_zone = pdns.get_rdns_zone_from_ip(network[0])
rdns_rrsets = []
if rdns_zone is None:
@@ -88,15 +93,18 @@ for vlan in vlans:
# Network ID
rdns_rrsets.append({"name": network[0].reverse_pointer + '.', "changetype": "replace", "type": "PTR", "records": [
- {"content": f'net-{network[0]}.{vlan_domain_name}', "disabled": False, "type": "PTR"}], "ttl": 900})
+ {"content": f'net-{network[0]}.{vlan_domain_name}.', "disabled": False, "type": "PTR"}], "ttl": 900})
# Gateway
rdns_rrsets.append({"name": network[1].reverse_pointer + '.', "changetype": "replace", "type": "PTR", "records": [
- {"content": f'gw-{network[1]}.{vlan_domain_name}', "disabled": False, "type": "PTR"}], "ttl": 900})
+ {"content": f'gw-{network[1]}.{vlan_domain_name}.', "disabled": False, "type": "PTR"}], "ttl": 900})
# Broadcast
rdns_rrsets.append({"name": network[-1].reverse_pointer + '.', "changetype": "replace", "type": "PTR", "records": [
- {"content": f'broadcast-{network[-1]}.{vlan_domain_name}', "disabled": False, "type": "PTR"}], "ttl": 900})
+ {"content": f'broadcast-{network[-1]}.{vlan_domain_name}.', "disabled": False, "type": "PTR"}], "ttl": 900})
+
+ # Apply rdns_rrsets
+ pdns.set_records(network[1].reverse_pointer + '.', rdns_rrsets)
# dhcp-mgmt-edge
vlans = nb.ipam.vlans.filter(tag='dhcp-mgmt-edge')
@@ -128,12 +136,69 @@ if os.environ['KEA_DHCP6_FILE'] is not None:
# Test DHCPv4
try:
- subprocess.check_call(['/usr/sbin/kea-dhcp4', '-t', os.environ['KEA_DHCP4_FILE']])
+ subprocess.check_call(['/usr/sbin/kea-dhcp4', '-t',
+ os.environ['KEA_DHCP4_FILE']])
except subprocess.CalledProcessError:
print("Failed to validate kea-dhcp4 config. What do we do now?")
-
+
# Test DHCPv6
try:
- subprocess.check_call(['/usr/sbin/kea-dhcp6', '-t', os.environ['KEA_DHCP6_FILE']])
+ subprocess.check_call(['/usr/sbin/kea-dhcp6', '-t',
+ os.environ['KEA_DHCP6_FILE']])
except subprocess.CalledProcessError:
- print("Failed to validate kea-dhcp6 config. What do we do now?") \ No newline at end of file
+ print("Failed to validate kea-dhcp6 config. What do we do now?")
+
+
+# Reload all zones
+zones = [zone['name'] for zone in pdns.list_zones()]
+
+# Create DNS for devices
+devices = nb.dcim.devices.all()
+for device in devices:
+ if device.primary_ip4 is None or device.primary_ip6 is None:
+ continue
+
+ zone = "tg23.gathering.org"
+
+ print(device.name)
+ r = re.search('^([A-Za-z1-9]*)\.([A-Za-z1-9]*)$', device.name)
+
+ if f"{device.name}.{zone}." in zones:
+ device_name = ""
+ zone = f"{device.name}.{zone}"
+ elif r is not None:
+ device_name = r.group(1) + "."
+ zone = "{}.{}".format(r.group(2), zone)
+ elif re.search('^([A-Za-z1-9]*) \(([A-Za-z1-9 -\/]*)\)', device.name) is not None:
+ zone = "{}".format(zone)
+ device_name = re.search(
+ '^([A-Za-z1-9]*) \(([A-Za-z1-9 -\/]*)\)', device.name).group(1) + "."
+ else:
+ zone = "{}".format(zone)
+ device_name = device.name + "."
+
+ print(f"zone: {zone}")
+ print(f"name: {device_name}")
+ print(str(netaddr.IPNetwork(str(device.primary_ip4)).ip))
+ print()
+
+ # Network ID
+ zone_rrsets = []
+ zone_rrsets.append({'name': f'{device_name}{zone}.', 'changetype': 'replace', 'type': 'A', 'records': [
+ {'content': str(netaddr.IPNetwork(str(device.primary_ip4)).ip), 'disabled': False, 'type': 'A'}], 'ttl': 900})
+
+ # Apply zone_rrsets
+ print(pdns.set_records(f"{zone}", zone_rrsets))
+
+ rdns_zone = pdns.get_rdns_zone_from_ip(
+ str(netaddr.IPNetwork(str(device.primary_ip4)).ip))
+ rdns_rrsets = []
+ if rdns_zone is None:
+ print(f"Failed to find RDNS Zone for IP")
+
+ # Broadcast
+ rdns_rrsets.append({"name": ipaddress.ip_address(str(netaddr.IPNetwork(str(device.primary_ip4)).ip)).reverse_pointer + '.', "changetype": "replace", "type": "PTR", "records": [
+ {"content": f'{device_name}{zone}.', "disabled": False, "type": "PTR"}], "ttl": 900})
+
+ # Apply rdns_rrsets
+ print(pdns.set_records(rdns_zone, rdns_rrsets))
diff --git a/tools/dhcpns/poetry.lock b/tools/dhcpns/poetry.lock
index ff010f1..69b8885 100644
--- a/tools/dhcpns/poetry.lock
+++ b/tools/dhcpns/poetry.lock
@@ -110,6 +110,18 @@ files = [
]
[[package]]
+name = "netaddr"
+version = "0.8.0"
+description = "A network address manipulation library for Python"
+category = "main"
+optional = false
+python-versions = "*"
+files = [
+ {file = "netaddr-0.8.0-py2.py3-none-any.whl", hash = "sha256:9666d0232c32d2656e5e5f8d735f58fd6c7457ce52fc21c98d45f2af78f990ac"},
+ {file = "netaddr-0.8.0.tar.gz", hash = "sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243"},
+]
+
+[[package]]
name = "pynetbox"
version = "7.0.1"
description = "NetBox API client library"
@@ -180,5 +192,5 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[metadata]
lock-version = "2.0"
-python-versions = "^3.11"
-content-hash = "4135825998043fdcea3674cc119324247b3de7379607a62979b5a8d392d615c4"
+python-versions = "^3.9"
+content-hash = "6b6ab04814884674356e174b6d88393b881c7aa0a3632f05bcc5335699b3e715"
diff --git a/tools/dhcpns/pyproject.toml b/tools/dhcpns/pyproject.toml
index c0e5fdf..8b71ac3 100644
--- a/tools/dhcpns/pyproject.toml
+++ b/tools/dhcpns/pyproject.toml
@@ -10,6 +10,7 @@ python = "^3.9"
requests = "^2.28.2"
pynetbox = "^7.0.1"
python-dotenv = "^1.0.0"
+netaddr = "^0.8.0"
[build-system]