Skip to content

Apply auto-delegation across all of a users' domains (so far only LPS) - #1253

Draft
peterthomassen wants to merge 11 commits into
mainfrom
20260820_auto_delegation
Draft

peterthomassen wants to merge 11 commits into
mainfrom
20260820_auto_delegation

Conversation

@peterthomassen

Copy link
Copy Markdown
Member

No description provided.

DomainManager.parent_zone(name, exclude=()) returns the closest ancestor
domain that exists in the database, based on filter_qname(); the
Domain.parent_zone property applies it to a domain instance and does not
cache the result.

(cherry picked from commit dbb0360fbad9e8e6875180a1c693fd57402705b5)
…ic suffix

Domain.is_registrable() now returns False if the closest ancestor domain
lies below the domain's public suffix and that public suffix is local, so
that no subdomain of a domain such as example.dedyn.io can be registered by
anyone. This prevents circumventing the restrictions that apply to domains
delegated from a local public suffix.

(cherry picked from commit f78fcd928ad7c29f28077e4c2584461488e4a1c4)
Domain.is_locally_registrable is now based on the closest ancestor domain
instead of the literal parent name, so that domains like a.b.dedyn.io (with
no b.dedyn.io registered) are covered by the REGISTER_LPS suspension, by the
blocked subnet check for A records, and by the FRESH renewal state.
Domain.update_delegation() accepts such domains as children, the domain views
look up the delegating domain via Domain.parent_zone, and the now unused
Domain.parent_domain_name is removed.
Domain.update_delegation() is replaced by add_delegation()/remove_delegation()
on the delegating domain, which add and subtract our NS records and the child's
DS records (Domain.ds_contents) instead of rebuilding both RRsets, and drop the
DS RRset when no NS records remain. Domain.delegation_parent,
Domain.auto_delegate(), Domain.delegation_state() and Domain.auto_undelegate()
are the entry points used by the domain views, the account activation view and
the scavenge-unused command; a domain's DS records are read before it is
deleted, and Domain._partitioned_name goes away with update_delegation().
Domain.delegation_parent now also accepts the closest ancestor domain when it
belongs to the same account, so that creating a domain adds NS and DS records
to it and deleting the domain removes them again. Domain.delegation_error()
reports a CNAME RRset at the delegation point or an overlong delegation point
name, which DomainSerializer.validate_name() turns into a 400 response with
code delegation_impossible.
…pears

Domain.delegated_children() lists the domains a domain delegates, i.e. its
descendants with no other domain in between, whoever owns that one.
Domain.auto_delegate() now takes their delegations over from the domain that
delegated them before, and Domain.delegation_state()/auto_undelegate() hand
them to the next domain up when the domain delegating them is deleted. A
zonefile with a CNAME record at the delegation point of a domain that would be
taken over is rejected by DomainSerializer, as it would otherwise leave the new
domain created but undelegated.
manage.py fix-auto-delegations reports delegations that are missing at a
domain's delegating domain, and NS/DS records that carry our nameservers but
no longer belong to a domain delegated there. It considers all domains unless
domain names are given, in which case each name is taken both as a delegating
and as a delegated domain, and performs the changes only with --apply.
The domain management docs gain an "Automatic Delegation" section covering
which domains we delegate, how the records follow when a domain in between is
created or deleted, and what having foreign NS/DS records at the delegation
point means; the NS record notes in the RRset docs link to it. DomainSetup.vue
now asks the domains endpoint for the parent name via owns_qname instead of
matching the domain name against the local public suffixes only.
…me alone

Domain.is_under_local_public_suffix tests the domain name against
settings.LOCAL_PUBLIC_SUFFIXES without consulting the database, and now decides
the blocked subnet check for A records, the lock on NS record modification and
the FRESH renewal state instead of is_locally_registrable, which registering a
domain in between can turn off.
RRset.clean_records() rejects NS RRsets whose subname starts with an asterisk,
as the behavior of wildcard NS records in conjunction with DNSSEC is undefined
(RFC 4592, Sec. 4.2), and fix-auto-delegations skips them, as a wildcard can
never be a delegation point; the RRset docs say so instead of discouraging them.
@peterthomassen
peterthomassen force-pushed the 20260820_auto_delegation branch from 7ab951c to 2f851e5 Compare September 1, 2026 10:44
Describes how auto-delegation grows from direct children of a local public
suffix to any domain whose closest existing ancestor is owned by the same
account: the ancestor lookup, the restrictions that follow a name below an
LPS, record-level maintenance of NS and DS at the delegation point,
re-parenting when a domain in between appears or disappears, the
fix-auto-delegations command, and the tests and rollout checks per step.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant