Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Delegate zone to another name server #30

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion .idea/netbox_ddns.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 35 additions & 2 deletions netbox_ddns/background_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
from django.db import IntegrityError
from django_rq import job
from dns import rcode
from netaddr import ip
from netaddr import ip, IPNetwork

from netbox_ddns.models import ACTION_CREATE, ACTION_DELETE, DNSStatus, RCODE_NO_ZONE, ReverseZone, Zone
from netbox_ddns.utils import get_soa
from netbox_ddns.utils import get_soa, check_servers_authoritative, get_ip

logger = logging.getLogger('netbox_ddns')

Expand Down Expand Up @@ -198,3 +198,36 @@ def dns_delete(dns_name: str, address: ip.IPAddress, forward=True, reverse=True,
status.save(force_update=True)

return ', '.join(output)


# TODO: dns_create,dns_remove check if it is not delegated to another server
def create_reverse_delegation(nameservers: List[str], prefix: IPNetwork, status: Optional[DNSStatus], output: List[str]):
if prefix.size > 24:
output.append(f'Classless delegation is not implemented, prefix size too big: {prefix.cidr}')

if status:
status.reverse_action = ACTION_CREATE

nameservers = {x: get_ip(x) for x in nameservers}

subnets = prefix.subnet(24)
while 1:
subnet = next(subnets, None)
if subnet is None:
break

zone = ReverseZone.objects.find_for_address(subnet.network)
if zone:
for nameserver, addresses in nameservers.items():
# TODO: check authority
nameserver = {nameserver: address}
if check_servers_authoritative(zone.name, addresses):
pass
update = zone.server.create_update(zone.name)
for nameserver in nameservers.keys():
update.add(
zone.name,
zone.ttl,
dns.rdatatype.NS,
nameserver
)
32 changes: 32 additions & 0 deletions netbox_ddns/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import List, Dict

import dns.rdatatype
import dns.resolver

Expand Down Expand Up @@ -26,3 +28,33 @@ def get_soa(dns_name: str) -> str:
for rrset in response.authority:
if rrset.rdtype == dns.rdatatype.SOA:
return rrset.name.to_text()


def check_servers_authoritative(zone: str, nameservers: Dict[str, List[str]]) -> Dict[str, bool]:
resolver = dns.resolver.Resolver()
res = {}

for ns, addr in nameservers.items():
try:
resolver.nameservers = [addr]
answer = resolver.resolve(zone, dns.rdatatype.NS)
if ns in answer.rrset.to_text():
res[ns] = True
else:
res[ns] = False
except dns.resolver.NoNameservers:
res[ns] = False

return res


def get_ip(address: str, family=0) -> List[str]:
resolver = dns.resolver.Resolver()

if family == 0:
answer_a = [res.to_text() for res in resolver.resolve(address, dns.rdatatype.A)]
answer_aaaa = [res.to_text() for res in resolver.resolve(address, dns.rdatatype.AAAA)]
return answer_a + answer_aaaa
else:
answer = resolver.resolve(address, dns.rdatatype.AAAA if family == 6 else dns.rdatatype.A)
return [res.to_text() for res in answer]