add secondary nameserver, prefer it for queries, add migration, fixes #175

This commit is contained in:
Thomas Waldmann 2014-11-15 22:42:13 +01:00
parent b6968fdb6f
commit 536a5f5d9d
5 changed files with 43 additions and 6 deletions

View File

@ -20,6 +20,7 @@ TEST_SECRET2 = "somethingelse"
RELATED_HOST_NAME = 'rh' RELATED_HOST_NAME = 'rh'
TEST_HOST_RELATED = FQDN(RELATED_HOST_NAME + '.' + TEST_HOST.host, TEST_HOST.domain) TEST_HOST_RELATED = FQDN(RELATED_HOST_NAME + '.' + TEST_HOST.host, TEST_HOST.domain)
NAMESERVER_IP = "85.10.192.104" NAMESERVER_IP = "85.10.192.104"
NAMESERVER2_IP = NAMESERVER_IP # use same server as tests query shortly after update, too quick for secondary
NAMESERVER_UPDATE_ALGORITHM = "HMAC_SHA512" NAMESERVER_UPDATE_ALGORITHM = "HMAC_SHA512"
# no problem, you can ONLY update the TESTDOMAIN with this secret, nothing else: # no problem, you can ONLY update the TESTDOMAIN with this secret, nothing else:
NAMESERVER_UPDATE_SECRET = "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYQ==" NAMESERVER_UPDATE_SECRET = "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYQ=="
@ -75,6 +76,7 @@ def db_init(db): # note: db is a predefined fixture and required here to have t
dt = Domain.objects.create( dt = Domain.objects.create(
name=TESTDOMAIN, # special: test-domain update secret! name=TESTDOMAIN, # special: test-domain update secret!
nameserver_ip=NAMESERVER_IP, nameserver_ip=NAMESERVER_IP,
nameserver2_ip=NAMESERVER2_IP,
nameserver_update_algorithm=NAMESERVER_UPDATE_ALGORITHM, nameserver_update_algorithm=NAMESERVER_UPDATE_ALGORITHM,
nameserver_update_secret=NAMESERVER_UPDATE_SECRET, nameserver_update_secret=NAMESERVER_UPDATE_SECRET,
public=NAMESERVER_PUBLIC, public=NAMESERVER_PUBLIC,
@ -84,6 +86,7 @@ def db_init(db): # note: db is a predefined fixture and required here to have t
d = Domain.objects.create( d = Domain.objects.create(
name=BASEDOMAIN, name=BASEDOMAIN,
nameserver_ip=NAMESERVER_IP, nameserver_ip=NAMESERVER_IP,
nameserver2_ip=NAMESERVER2_IP,
nameserver_update_algorithm=NAMESERVER_UPDATE_ALGORITHM, nameserver_update_algorithm=NAMESERVER_UPDATE_ALGORITHM,
nameserver_update_secret='invalid=', # we don't send updates there (and the real key is really secret) nameserver_update_secret='invalid=', # we don't send updates there (and the real key is really secret)
public=NAMESERVER_PUBLIC, public=NAMESERVER_PUBLIC,

View File

@ -197,11 +197,14 @@ def query_ns(fqdn, rdtype):
:raises: see dns.resolver.Resolver.query :raises: see dns.resolver.Resolver.query
""" """
assert isinstance(fqdn, FQDN) assert isinstance(fqdn, FQDN)
nameserver, origin = get_ns_info(fqdn)[0:2] nameserver, nameserver2, origin = get_ns_info(fqdn)[0:3]
resolver = dns.resolver.Resolver(configure=False) resolver = dns.resolver.Resolver(configure=False)
# we do not configure it from resolv.conf, but patch in the values we # we do not configure it from resolv.conf, but patch in the values we
# want into the documented attributes: # want into the documented attributes:
resolver.nameservers = [nameserver, ] resolver.nameservers = [nameserver, ]
if nameserver2:
# if we have a secondary ns, prefer it for queries
resolver.nameservers.insert(0, nameserver2)
resolver.search = [] resolver.search = []
resolver.lifetime = RESOLVER_TIMEOUT resolver.lifetime = RESOLVER_TIMEOUT
# as we query directly the (authoritative) master dns, we do not desire # as we query directly the (authoritative) master dns, we do not desire
@ -269,7 +272,7 @@ def get_ns_info(fqdn):
# retry timeout is over, set it available again # retry timeout is over, set it available again
set_ns_availability(domain, True) set_ns_availability(domain, True)
algorithm = getattr(dns.tsig, d.nameserver_update_algorithm) algorithm = getattr(dns.tsig, d.nameserver_update_algorithm)
return d.nameserver_ip, fqdn.domain, domain, fqdn.host, domain, d.nameserver_update_secret, algorithm return d.nameserver_ip, d.nameserver2_ip, fqdn.domain, domain, fqdn.host, domain, d.nameserver_update_secret, algorithm
def update_ns(fqdn, rdtype='A', ipaddr=None, action='upd', ttl=60): def update_ns(fqdn, rdtype='A', ipaddr=None, action='upd', ttl=60):
@ -286,7 +289,7 @@ def update_ns(fqdn, rdtype='A', ipaddr=None, action='upd', ttl=60):
""" """
assert isinstance(fqdn, FQDN) assert isinstance(fqdn, FQDN)
assert action in ['add', 'del', 'upd', ] assert action in ['add', 'del', 'upd', ]
nameserver, origin, domain, name, keyname, key, algo = get_ns_info(fqdn) nameserver, nameserver2, origin, domain, name, keyname, key, algo = get_ns_info(fqdn)
upd = dns.update.Update(origin, upd = dns.update.Update(origin,
keyring=dns.tsigkeyring.from_text({keyname: key}), keyring=dns.tsigkeyring.from_text({keyname: key}),
keyalgorithm=algo) keyalgorithm=algo)

View File

@ -44,7 +44,7 @@ class EditRelatedHostForm(forms.ModelForm):
class CreateDomainForm(forms.ModelForm): class CreateDomainForm(forms.ModelForm):
class Meta(object): class Meta(object):
model = Domain model = Domain
fields = ['name', 'nameserver_ip', 'nameserver_update_algorithm', fields = ['name', 'nameserver_ip', 'nameserver2_ip', 'nameserver_update_algorithm',
'public', 'available', 'comment'] 'public', 'available', 'comment']
widgets = { widgets = {
'name': forms.widgets.TextInput(attrs=dict(autofocus=None)), 'name': forms.widgets.TextInput(attrs=dict(autofocus=None)),
@ -54,7 +54,7 @@ class CreateDomainForm(forms.ModelForm):
class EditDomainForm(forms.ModelForm): class EditDomainForm(forms.ModelForm):
class Meta(object): class Meta(object):
model = Domain model = Domain
fields = ['comment', 'nameserver_ip', 'public', 'available', fields = ['comment', 'nameserver_ip', 'nameserver2_ip', 'public', 'available',
'nameserver_update_algorithm', 'nameserver_update_secret'] 'nameserver_update_algorithm', 'nameserver_update_secret']

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('main', '0002_auto_20141115_2227'),
]
operations = [
migrations.AddField(
model_name='domain',
name='nameserver2_ip',
field=models.GenericIPAddressField(help_text='IP of additional nameserver (used for queries)', null=True, verbose_name='nameserver IP (secondary)', blank=True),
preserve_default=True,
),
migrations.AlterField(
model_name='domain',
name='nameserver_ip',
field=models.GenericIPAddressField(help_text='IP where the dynamic DNS updates for this zone will be sent to', verbose_name='nameserver IP (primary)'),
preserve_default=True,
),
]

View File

@ -83,9 +83,14 @@ class Domain(models.Model):
unique=True, unique=True,
help_text=_("Name of the zone where dynamic hosts may get added")) help_text=_("Name of the zone where dynamic hosts may get added"))
nameserver_ip = models.GenericIPAddressField( nameserver_ip = models.GenericIPAddressField(
_("nameserver IP"), _("nameserver IP (primary)"),
max_length=40, # ipv6 = 8 * 4 digits + 7 colons max_length=40, # ipv6 = 8 * 4 digits + 7 colons
help_text=_("IP where the dynamic DNS updates for this zone will be sent to")) help_text=_("IP where the dynamic DNS updates for this zone will be sent to"))
nameserver2_ip = models.GenericIPAddressField(
_("nameserver IP (secondary)"),
max_length=40, # ipv6 = 8 * 4 digits + 7 colons
blank=True, null=True,
help_text=_("IP of additional nameserver (used for queries)"))
nameserver_update_secret = models.CharField( nameserver_update_secret = models.CharField(
_("nameserver update secret"), _("nameserver update secret"),
max_length=88, # 512 bits base64 -> 88 bytes max_length=88, # 512 bits base64 -> 88 bytes