mirror of
https://git.private.coffee/PrivateCoffee/mallarddns.git
synced 2026-08-06 17:22:50 +05:30
feat: Field for extras so we can support arbitrary record types without adding more fields...
This commit is contained in:
parent
2039d4d173
commit
c21d5d4f1e
8 changed files with 76 additions and 27 deletions
|
|
@ -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
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
),
|
||||
]
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue