From ef5afbfe3a45db324466cbd823e7898e993d13a5 Mon Sep 17 00:00:00 2001 From: Sebastian Lohff Date: Fri, 31 May 2019 00:12:20 +0200 Subject: [PATCH] Support for DS records --- bin/dns-sync | 3 ++ domains/forms.py | 35 +++++++++++++++++-- domains/migrations/0004_auto_20170403_0533.py | 25 +++++++++++++ domains/migrations/0005_domain_ds_records.py | 20 +++++++++++ domains/models.py | 3 ++ whoisdb/helpers.py | 2 +- 6 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 domains/migrations/0004_auto_20170403_0533.py create mode 100644 domains/migrations/0005_domain_ds_records.py diff --git a/bin/dns-sync b/bin/dns-sync index 67a5eb5..e71c44e 100755 --- a/bin/dns-sync +++ b/bin/dns-sync @@ -105,6 +105,9 @@ def getDomainsFromQueryset(qs, zone, glueRecords, usedNameservers, v4reverse=Fal zone.append((domain.getZone(), "NS", servers)) + if domain.ds_records: + zone.append((domain.getZone(), "DS", domain.ds_records.split("\n"))) + if v4reverse: # for ipv4 reverse we have to do some extra work in case of classless delegations # see RFC2317 diff --git a/domains/forms.py b/domains/forms.py index 12c3ff4..744a920 100644 --- a/domains/forms.py +++ b/domains/forms.py @@ -15,10 +15,41 @@ import re import ipaddress -class DomainForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm): +class DSRecordMixin(object): + ds_re = re.compile(r"^(?P\d+)\s+(?P\d+)\s+(?P\d+)\s+(?P[0-9a-fA-F]+)$") + HASH_SUPPORTED = (1, 2) + CRYPTO_SUPPORTED = (3, 5, 6, 8, 10, 13, 15) + + def clean_ds_records(self): + ds_records = self.cleaned_data['ds_records'].strip() + result = [] + + if not ds_records: + return '' + + for n, rec in enumerate(ds_records.split("\n"), 1): + rec = rec.strip() + m = self.ds_re.match(rec) + if not m: + raise forms.ValidationError("Could not parse records {} - needs to be in format " + "' '".format(n)) + + if int(m.group('hashtype')) not in self.HASH_SUPPORTED: + raise forms.ValidationError("Record {} has an invalid hashtype of {}, supported are {}" + "".format(n, m.group('hashtype'), " ".join(map(str, self.HASH_SUPPORTED)))) + if int(m.group('crypto')) not in self.CRYPTO_SUPPORTED: + raise forms.ValidationError("Record {} has unsupported crypto {}, supported are {}" + "".format(n, m.group('crypto'), " ".join(map(str, self.CRYPTO_SUPPORTED)))) + + result.append("{id} {crypto} {hashtype} {hash}".format(**m.groupdict())) + + return "\n".join(result) + + +class DomainForm(MntFormMixin, WhoisObjectFormMixin, DSRecordMixin, forms.ModelForm): class Meta: model = Domain - fields = ['name', 'nameservers', 'mnt_by', 'admin_c'] + fields = ['name', 'nameservers', 'mnt_by', 'admin_c', 'ds_records'] def __init__(self, *args, **kwargs): super(DomainForm, self).__init__(*args, **kwargs) diff --git a/domains/migrations/0004_auto_20170403_0533.py b/domains/migrations/0004_auto_20170403_0533.py new file mode 100644 index 0000000..857d3aa --- /dev/null +++ b/domains/migrations/0004_auto_20170403_0533.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-04-03 05:33 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('domains', '0003_auto_20170322_1801'), + ] + + operations = [ + migrations.AlterField( + model_name='domain', + name='mnt_by', + field=models.ManyToManyField(help_text='You can select multiple maintainers here', to='whoisdb.Maintainer'), + ), + migrations.AlterField( + model_name='nameserver', + name='mnt_by', + field=models.ManyToManyField(help_text='You can select multiple maintainers here', to='whoisdb.Maintainer'), + ), + ] diff --git a/domains/migrations/0005_domain_ds_records.py b/domains/migrations/0005_domain_ds_records.py new file mode 100644 index 0000000..dcae33e --- /dev/null +++ b/domains/migrations/0005_domain_ds_records.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2019-05-30 21:18 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('domains', '0004_auto_20170403_0533'), + ] + + operations = [ + migrations.AddField( + model_name='domain', + name='ds_records', + field=models.TextField(blank=True), + ), + ] diff --git a/domains/models.py b/domains/models.py index fd290c1..16fd79a 100644 --- a/domains/models.py +++ b/domains/models.py @@ -50,6 +50,9 @@ class Domain(MntdObject): nameservers = models.ManyToManyField(Nameserver, blank=True) admin_c = models.ManyToManyField(Contact) + ds_records = models.TextField(blank=True, verbose_name='DS Records', + help_text='DS Records in the format of [id] [crypto-algo] [hash-algo] [hash]') + def getPK(self): return self.name diff --git a/whoisdb/helpers.py b/whoisdb/helpers.py index 87fde3e..55823be 100644 --- a/whoisdb/helpers.py +++ b/whoisdb/helpers.py @@ -39,7 +39,7 @@ def getWhoisObjectFields(obj, owner): fields.append(("Address CIDR", obj.prefix())) _addFields(fields, obj, ["description", "parent_range", "origin_as", "mnt_by", "mnt_lower", "admin_c"]) elif c == domains.models.Domain: - _addFields(fields, obj, ["name", "nameservers", "mnt_by", "admin_c"]) + _addFields(fields, obj, ["name", "nameservers", "mnt_by", "admin_c", "ds_records"]) elif c == domains.models.Nameserver: _addFields(fields, obj, ["name", "glueIPv4", "glueIPv6", "mnt_by", "admin_c"]) elif c == domains.models.ReverseZone: