feat: Field for extras so we can support arbitrary record types without adding more fields...

This commit is contained in:
Kumi 2026-07-03 08:32:52 +02:00
commit c21d5d4f1e
No known key found for this signature in database
GPG key ID: ECBCC9082395383F
8 changed files with 76 additions and 27 deletions

View file

@ -144,9 +144,7 @@ class EmailInputView(RateLimitMixin, DynDNSContextMixin, FormView):
ip_address=ip_address,
token=token,
token_expires=(
timezone.now() + timedelta(hours=expiry_hours)
if expiry_hours
else None
timezone.now() + timedelta(hours=expiry_hours) if expiry_hours else None
),
)

View file

@ -45,7 +45,7 @@ class ZoneForm(forms.ModelForm):
class RecordForm(forms.ModelForm):
class Meta:
model = Record
fields = ["name", "type", "data", "ttl", "priority"]
fields = ["name", "type", "data", "ttl", "extra"]
class HostsOverrideRecordFilterForm(forms.Form):

View file

@ -15,7 +15,7 @@ class DNSRecord:
ttl: int = 60
wildcard: bool = False
source: str = ""
priority: int = None
extra: dict = None
rrsig: list = None
@ -65,7 +65,7 @@ class DNSCache:
ttl=rr.ttl,
wildcard=(rr.name.startswith("*")),
source=zonename,
priority=rr.priority,
extra=rr.extra,
)
if dr.wildcard:

View file

@ -524,19 +524,26 @@ class DjangoFullResolver(BaseResolver):
elif rec.type == "CNAME":
reply.add_answer(RR(qn, QTYPE.CNAME, CLASS.IN, ttl, CNAME(rec.value)))
elif rec.type == "MX":
ex = rec.extra or {}
reply.add_answer(
RR(qn, QTYPE.MX, CLASS.IN, ttl, MX(rec.value, rec.priority or 10))
RR(qn, QTYPE.MX, CLASS.IN, ttl, MX(rec.value, ex.get("priority", 10)))
)
elif rec.type == "TXT":
reply.add_answer(RR(qn, QTYPE.TXT, CLASS.IN, ttl, TXT(rec.value)))
elif rec.type == "SRV":
ex = rec.extra or {}
reply.add_answer(
RR(
qn,
QTYPE.SRV,
CLASS.IN,
ttl,
SRV(rec.priority or 0, 0, 0, rec.value), # TODO: weight, port
SRV(
ex.get("priority", 0),
ex.get("weight", 0),
ex.get("port", 0),
rec.value,
),
)
)
elif rec.type == "SOA":
@ -612,7 +619,13 @@ class DjangoFullResolver(BaseResolver):
SOA(
mname,
rname,
times=[int(serial), int(refresh), int(retry), int(expire), int(minimum)],
times=[
int(serial),
int(refresh),
int(retry),
int(expire),
int(minimum),
],
),
)
)
@ -628,7 +641,9 @@ class DjangoFullResolver(BaseResolver):
payload = request.pack()
for upstream in self.recursion_upstreams:
try:
parsed = self._dns_query(payload, upstream, self.recursion_upstream_port)
parsed = self._dns_query(
payload, upstream, self.recursion_upstream_port
)
cached_resp, ttl = cache_response_from_dnslib_reply(
qn, qtype, parsed, validated_dnssec=False
)
@ -688,7 +703,7 @@ class DjangoFullResolver(BaseResolver):
ttl=min(alias_rr.ttl or 60, rr.ttl or 60),
wildcard=False,
source=f"alias->{target}",
priority=getattr(rr, "priority", None),
extra=None,
)
self._add_rr(reply, owner_name, flat)
emitted = True
@ -735,7 +750,7 @@ class DjangoFullResolver(BaseResolver):
ttl=min(alias_rr.ttl or 60, rr.ttl or 60),
wildcard=False,
source=f"alias-forward->{target}",
priority=None,
extra=None,
)
self._add_rr(reply, owner_name, flat)
emitted = True
@ -749,7 +764,9 @@ class DjangoFullResolver(BaseResolver):
for upstream in self.recursion_upstreams:
try:
req = DNSRecord.question(target, qtype)
up_reply = self._dns_query(req.pack(), upstream, self.recursion_upstream_port)
up_reply = self._dns_query(
req.pack(), upstream, self.recursion_upstream_port
)
for rr in up_reply.rr:
rrtype_name = QTYPE.get(rr.rtype)
if rrtype_name != qtype:
@ -761,7 +778,7 @@ class DjangoFullResolver(BaseResolver):
ttl=min(alias_rr.ttl or 60, rr.ttl or 60),
wildcard=False,
source=f"alias-upstream->{target}",
priority=None,
extra=None,
)
self._add_rr(reply, owner_name, flat)
emitted = True
@ -799,7 +816,7 @@ class DjangoFullResolver(BaseResolver):
ttl=min(alias_rr.ttl or 60, rrset.ttl or 60),
wildcard=False,
source=f"alias-recursive->{target}",
priority=None,
extra=None,
)
self._add_rr(reply, owner_name, flat)
emitted = True

View file

@ -358,14 +358,14 @@ def add_record(stdscr, zone):
except ValueError:
ttl = 3600
priority = None
extra = None
if rtype in ("MX", "SRV"):
pr_str = prompt_input(stdscr, "Priority (integer, default 10): ", "10")
if pr_str is not None:
try:
priority = int(pr_str)
extra = {"priority": int(pr_str)}
except ValueError:
priority = 10
extra = {"priority": 10}
try:
with transaction.atomic():
@ -375,7 +375,7 @@ def add_record(stdscr, zone):
type=rtype.upper(),
data=data,
ttl=ttl,
priority=priority,
extra=extra,
)
except Exception as e:
show_message(stdscr, f"Failed to create record: {e}", level="error")
@ -403,20 +403,22 @@ def edit_record(stdscr, record):
except ValueError:
ttl = record.ttl
priority = record.priority
existing_extra = record.extra or {}
if rtype.upper() in ("MX", "SRV"):
current_priority = existing_extra.get("priority", 10)
pr_str = prompt_input(
stdscr,
f"Priority [{record.priority if record.priority is not None else '10'}]: ",
initial=str(record.priority or 10),
f"Priority [{current_priority}]: ",
initial=str(current_priority),
)
if pr_str is not None:
try:
priority = int(pr_str)
existing_extra = {**existing_extra, "priority": int(pr_str)}
except ValueError:
pass
new_extra = existing_extra if existing_extra else None
else:
priority = None
new_extra = {k: v for k, v in existing_extra.items() if k != "priority"} or None
try:
with transaction.atomic():
@ -424,7 +426,7 @@ def edit_record(stdscr, record):
record.type = rtype.upper()
record.data = data
record.ttl = ttl
record.priority = priority
record.extra = new_extra
record.save()
except Exception as e:
show_message(stdscr, f"Failed to update record: {e}", level="error")

View file

@ -0,0 +1,30 @@
# Generated by Django 5.2.7 on 2026-07-03 06:29
from django.db import migrations, models
def priority_to_extra(apps, schema_editor):
Record = apps.get_model("records", "Record")
for record in Record.objects.filter(priority__isnull=False):
record.extra = {"priority": record.priority}
record.save(update_fields=["extra"])
class Migration(migrations.Migration):
dependencies = [
("records", "0008_forwardingrule_last_updated_and_more"),
]
operations = [
migrations.AddField(
model_name="record",
name="extra",
field=models.JSONField(blank=True, null=True),
),
migrations.RunPython(priority_to_extra, migrations.RunPython.noop),
migrations.RemoveField(
model_name="record",
name="priority",
),
]

View file

@ -77,7 +77,9 @@ class Record(models.Model):
)
data = models.CharField(max_length=1000)
ttl = models.IntegerField(default=3600)
priority = models.IntegerField(null=True, blank=True) # for MX/SRV
extra = models.JSONField(
null=True, blank=True
) # type-specific fields (priority, weight, port, …)
last_updated = models.DateTimeField(auto_now=True)
def __str__(self):

View file

@ -49,7 +49,7 @@ def build_snapshot():
ttl=zone.soa_minimum or 300,
wildcard=False,
source="zone",
priority=None,
extra=None,
rrsig=None,
)
recs = [soa_rec] + recs