diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..7deb88a --- /dev/null +++ b/conftest.py @@ -0,0 +1,22 @@ +import pytest + +from django.utils.translation import activate + + +# Note: fixture must be "function" scope (default), see https://github.com/pelme/pytest_django/issues/33 +@pytest.fixture(autouse=True) +def db_init(db): + """ + Init the database contents for testing, so we have a service domain, ... + """ + from nsupdate.main.models import Domain + from django.db import IntegrityError + Domain.objects.create(domain='nsupdate.info', + nameserver_ip='85.10.192.104', + nameserver_update_algorithm='HMAC_SHA512', + nameserver_update_key='YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYQ==', + available_for_everyone=True) + + +def pytest_runtest_setup(item): + activate('en') diff --git a/nsupdate/main/_tests/test_dnstools.py b/nsupdate/main/_tests/test_dnstools.py index 186d6a5..df004f7 100644 --- a/nsupdate/main/_tests/test_dnstools.py +++ b/nsupdate/main/_tests/test_dnstools.py @@ -3,6 +3,7 @@ Tests for dnstools module. """ import pytest +pytestmark = pytest.mark.django_db from dns.resolver import NXDOMAIN diff --git a/nsupdate/main/dnstools.py b/nsupdate/main/dnstools.py index d393fd3..4654532 100644 --- a/nsupdate/main/dnstools.py +++ b/nsupdate/main/dnstools.py @@ -4,6 +4,9 @@ Misc. DNS related code: query, dynamic update, etc. Usually, higher level code wants to call the add/update/delete functions. """ +import logging +logger = logging.getLogger(__name__) + import dns.inet import dns.name import dns.resolver @@ -167,11 +170,10 @@ def get_ns_info(origin): :param origin: zone we are dealing with, must be with trailing dot :return: master nameserver, update key, update algo """ - # later look this up from Domain model: domain+'.': nameserver_ip, nameserver_update_key - ns_info = { - settings.BASEDOMAIN + '.': (settings.SERVER, settings.UPDATE_KEY, settings.UPDATE_ALGO), - } - return ns_info[origin] + from .models import Domain + d = Domain.objects.get(domain=origin.rstrip('.')) + algorithm = getattr(dns.tsig, d.nameserver_update_algorithm) + return d.nameserver_ip, d.nameserver_update_key, algorithm def update_ns(fqdn, rdtype='A', ipaddr=None, origin=None, action='upd', ttl=60): @@ -201,5 +203,7 @@ def update_ns(fqdn, rdtype='A', ipaddr=None, origin=None, action='upd', ttl=60): elif action == 'upd': assert ipaddr is not None upd.replace(name, ttl, rdtype, ipaddr) + logger.debug("performing %s for name %s and origin %s with rdtype %s and ipaddr %s" % ( + action, name, origin, rdtype, ipaddr)) response = dns.query.tcp(upd, nameserver) return response diff --git a/nsupdate/main/forms.py b/nsupdate/main/forms.py index e2ae1b9..0a916d4 100644 --- a/nsupdate/main/forms.py +++ b/nsupdate/main/forms.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from django import forms -from .models import Host +from .models import Host, Domain class CreateHostForm(forms.ModelForm): @@ -14,3 +14,9 @@ class EditHostForm(forms.ModelForm): class Meta(object): model = Host fields = ['comment'] + + +class CreateDomainForm(forms.ModelForm): + class Meta(object): + model = Domain + exclude = ['created_by'] diff --git a/nsupdate/main/models.py b/nsupdate/main/models.py index c9a29fa..59100d3 100644 --- a/nsupdate/main/models.py +++ b/nsupdate/main/models.py @@ -34,12 +34,25 @@ def domain_blacklist_validator(value): raise ValidationError(u'This domain is not allowed') +UPDATE_ALGORITHMS = ( + ('HMAC_SHA512', 'HMAC_SHA512'), + ('HMAC_SHA384', 'HMAC_SHA384'), + ('HMAC_SHA256', 'HMAC_SHA256'), + ('HMAC_SHA224', 'HMAC_SHA224'), + ('HMAC_SHA1', 'HMAC_SHA1'), + ('HMAC_MD5', 'HMAC_MD5'), +) + + class Domain(models.Model): domain = models.CharField(max_length=256, unique=True) nameserver_ip = models.GenericIPAddressField( max_length=256, - help_text="An IP where the nsupdates for this domain will be sent to") + help_text="IP where the dynamic updates for this domain will be sent to") nameserver_update_key = models.CharField(max_length=256) + nameserver_update_algorithm = models.CharField( + max_length=256, default='HMAC_SHA512', choices=UPDATE_ALGORITHMS) + available_for_everyone = models.BooleanField(default=False) last_update = models.DateTimeField(auto_now=True) created = models.DateTimeField(auto_now_add=True) @@ -88,14 +101,14 @@ class Host(models.Model): def getIPv4(self): try: - return dnstools.query_ns(self.get_fqdn(), 'A') - except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer, dns.resolver.NoNameservers): + return dnstools.query_ns(self.get_fqdn(), 'A', origin=self.domain.domain) + except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer, dns.resolver.NoNameservers, dns.resolver.Timeout): return '' def getIPv6(self): try: - return dnstools.query_ns(self.get_fqdn(), 'AAAA') - except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer, dns.resolver.NoNameservers): + return dnstools.query_ns(self.get_fqdn(), 'AAAA', origin=self.domain.domain) + except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer, dns.resolver.NoNameservers, dns.resolver.Timeout): return '' def poke(self): @@ -118,6 +131,6 @@ class Host(models.Model): def post_delete_host(sender, **kwargs): obj = kwargs['instance'] - dnstools.delete(obj.get_fqdn()) + dnstools.delete(obj.get_fqdn(), origin=obj.domain.domain) post_delete.connect(post_delete_host, sender=Host) diff --git a/nsupdate/main/templates/main/delete_host.html b/nsupdate/main/templates/main/delete_object.html similarity index 71% rename from nsupdate/main/templates/main/delete_host.html rename to nsupdate/main/templates/main/delete_object.html index 2d8c01e..b8808ce 100644 --- a/nsupdate/main/templates/main/delete_host.html +++ b/nsupdate/main/templates/main/delete_object.html @@ -2,10 +2,9 @@ {% load bootstrap %} {% block content %} -
Domain | +Nameserver IP | +Update key | +Algorithm | +Public? | +Action | +
---|---|---|---|---|---|
{{ domain.domain }} | +{{ domain.nameserver_ip }} | +{{ domain.nameserver_update_key }} | +{{ domain.get_nameserver_update_algorithm_display }} | +{{ domain.available_for_everyone|yesno }} | ++ delete + | +
No domains yet. |
Here you can add new domains (zones) which you control (and this is only useful if you + have some own zone which you can update automatically).
+You need to configure the primary master nameserver of the zone so it accepts dynamic updates + if the correct update key is presented (which is just a shared secret between the nameserver + and this service). +
+