Skip to content

Conversation

@molikuner
Copy link
Contributor

@molikuner molikuner commented Jul 26, 2025

What does this PR do?

This PR introduces the possibility to update multiple subdomains in a single dyndns request.

Multi-Domain Updates

The update endpoint now allows passing a comma separated list of domains in places of the hostname and host_id request parameter, http basic auth username and the username request parameter. This allows updating www.example.com and host.example.com at the same time using a single update request, e.g. if for whatever reason a CNAME record can't be used.

Specific-Domain Overwrite

In addition, the update endpoint now supports parameters overwriting the IP-address for a specific domain. E.g. it would be possible to update www.example.com, host.example.com and other.example.com with the same IPv4 address, but overwrite the IPv6 address for other.example.com in a single request. This is achieved by supporting new request parameters in the form of {domain}.{parameter-name}, e.g. the parameter other.example.com.ipv6 could be used to specify the IPv4 address of other.example.com, while the other updated domains fallback to the value given in ipv6.

Example

A full request could look like this (assuming you own example.com):

GET https://update.dedyn.io/
  ?hostname=www.example.com,host.example.com,other.example.com
  &ip=1.2.3.4
  &ipv6=2001:1::/64
  &other.example.com.ipv6=2001:2::1
Authorization: Token <update-token>

This would do the following updates:

Domain IPv4 IPv6
www.example.com 1.2.3.4 2001:1::/64
host.example.com 1.2.3.4 2001:1::/64
other.example.com 1.2.3.4 2001:2::1

How is this implemented?

This change was implemented in two parts:

  1. Supporting Multi-Domain Updates
  2. Supporting Specific-Domain Overwrites

Supporting Multi-Domain Updates

This change adjusts the DynDNS12UpdateView to support parsing multiple subdomains from the request by splitting the domain name by comma. Afterwards it checks whether all given subdomains belong to a single domain. If that's not the case, a 400 bad request is returned to the caller. Internally the view had to now do more than one update in a single transaction.

Supporting Specific-Domain Overwrites

This change again adjusts the DynDNS12UpdateView to search the request parameters for the new {domain}.{parameter-name} parameters and respect them in case they were provided. In case none of the new parameters was provided, a fallback to the "global" {parameter-name} parameters is used. Thus this change is backwards compatible and could technically be released also at a later point in time.

References

  • Partially resolves Update IPv6 subnet on several subdomains with one request #13, as it's possible to update multiple subdomains, but not across domains.
    ** Though I would argue that this will solve 99% of the requests. E.g. people transitioning from dynv6.com, which was mentioned multiple times in the issue, would be able to fully replicate their update since all updated subdomains belong to a single domain in their API.
  • Partially resolves dyn: support multiple hostname update #187, as it's possible to update multiple subdomains, but not across domains.

Further Considerations

This PR contains 2 commits to make the review easier. If required it could also be split into different PRs.

@peterthomassen
Copy link
Member

peterthomassen commented Jul 26, 2025

First, thanks for this great and significant contribution!

Unfortuantely, while PDNSChangeTracker supports updating multiple RRsets (including at multiple subname values) at once (cf. REST API bulk requests), it does not support updating RRsets of multiple distinct domains at once. This is because PowerDNS does a commit per domain; it's not possible to keep the transaction open until all domains' updates are processed.

Thus, this PR either

  • would have to be restricted to one domain (but continue to allow multiple subname values), or
  • would have to add multi-domain transaction support to the platform. We have a long-term plan of migrating from PowerDNS to Knot, which is expected to support this, but that will require a major refactor.

Note that in the first case, the interface / URL syntax could remain untouched, but a 4xx response would have to be returned if FQDNs transcend the scope of one domain.

In the second case, the migration would specifically have to be for the nslord component. Before we do that, we'd like to practice the transition by migrating nsmaster (which is also more urgent for replication performance reasons) - in other words, that's really a long-term project.

@molikuner
Copy link
Contributor Author

This is because PowerDNS does a commit per domain; it's not possible to keep the transaction open until all domains' updates are processed.

I see, I guess I could have noticed this while writing the tests, when multiple update requests are made to PowerDNS from a single change, e.g updating multiple domains (e.g. test_update_multiple_v4) vs. updating domain + subdomain (e.g. test_update_and_create). Now my question would be: Is it a problem?

I could imagine that for some reason the second update fails and thus there would be difference between dbapi and nslord as the first update would be rolled back on dbapi, but kept on nslord. I could imagine some other ways where differences between dbapi and nslord could occur, even without these changes, e.g. when an update is accepted by nslord, but because of network issues api considers the update failed and triggers the rollback. Is there any way such differences would be noticed at the moment and "heal" automatically?

Note that in the first case, the interface / URL syntax could remain untouched, but a 4xx response would have to be returned if FQDNs transcend the scope of one domain.

Sounds reasonable, in case we need to introduce this restriction for now.

In the second case, the migration would specifically have to be for the nslord component. ... in other words, that's really a long-term project

Yeah, that's definitely not something I would be able to do. Sounds like an interesting project though!

Side note: Unfortunately I have problems getting the whole project to run locally, thus I wasn't really able to test the change fully (apart from the unit tests).

@renne
Copy link

renne commented Jul 27, 2025

@molikuner How would this work with a german full dual-stack internet socket?
On IPv6-prefix updates the router (e.g. a Fritz!Box) hands over two parameters in a DynDNSv2 update-request:

  1. The public global IPv6-prefix routed to the hosts in the LAN
  2. The public global IPv6-address of itself (not inside the /64-prefix but e.g. in the /56-prefix)

How do you aggregate the combination of the IPv6-prefix + device identifier (either EUI64 or manually set) for each AAAA-record?

Your proposal seems to be limited to one IPv6-address for all hosts.

@molikuner
Copy link
Contributor Author

molikuner commented Jul 27, 2025

Hi @renne,

If this PR is accepted, you should be able to configure the Fritz!Box using this:

Update URL: https://update.dedyn.io/?hostname=<domain>&ip=<ipaddr>&fritz.my-domain.de.ipv6=<ip6addr>&ipv6=<ip6lanprefix>
Domainname: fritz.my-domain.de,host.my-domain.de,mail.my-domain.de
Username: my-domain.de
Password: TOKEN

This should update host.my-domain.de and mail.my-domain.de with the IPv6 prefix that it received (preserving the previous interface identifier of the IPv6 address), and the fritz.my-domain.de with the specific IPv6 address that it received.

EDIT: replaced domain names for clarity

@molikuner
Copy link
Contributor Author

@peterthomassen I've looked a bit into restricting the update to one domain (but keep support for updating multiple subdomains). Would you prefer to "just" introduce a check somewhere to make sure only one domain is updated, or should I also "undo" the work of supporting multiple domains in the parsing / handling of the request parameters. This would include some changes inside the dyndns view and the update to support multiple buckets inside the ScopedRatesThrottle.

I would argue this decision depends on whether you would imagine this being useful in the future when the switch to Knot happens or you think it's too far away that too much will change until then. In the latter case it might make more sense to keep the code simple.

@peterthomassen
Copy link
Member

I'd prefer the change to be minimal -- not because it might not be useful later, but because we have not meaningful way of testing the multi-domain aspects before doing the Knot migration. Thank you, and sorry for the extra work!

@molikuner molikuner changed the title Allow updating multiple domains in single dyndns request Allow updating multiple subdomains in single dyndns request Aug 1, 2025
@molikuner molikuner force-pushed the allow-updating-multiple-domains-in-single-dyndns-request branch from 6823195 to efd95f3 Compare August 1, 2025 23:58
@molikuner
Copy link
Contributor Author

molikuner commented Aug 2, 2025

sorry for the extra work!

No worries at all! I've just updated the PR to restrict updates to a single domain, still supporting updates of multiple subdomains as suggested. I've also adjusted the PR description accordingly.

Copy link
Member

@peterthomassen peterthomassen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this looks quite promising!

I've only reviewed the first commit, and will review the second once the first is stable. (I also haven't look at tests yet; will do in the next iteration.)

Copy link
Contributor Author

@molikuner molikuner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@peterthomassen Thanks for the review. I'll try to fix the issues in the coming days. Would be nice to already get some responses on some followup questions that I have added in the corresponding threads.

@peterthomassen
Copy link
Member

I'll try to fix the issues in the coming days.

Thanks. Please comment here explicitly when done, so I know when to take a look.

Would be nice to already get some responses on some followup questions that I have added in the corresponding threads.

See above! Let me know if anything else is unclear.

@molikuner molikuner force-pushed the allow-updating-multiple-domains-in-single-dyndns-request branch from efd95f3 to 62d989e Compare August 15, 2025 16:16
@molikuner
Copy link
Contributor Author

@peterthomassen I think I've addressed all your comments and updated the code accordingly. Please have another look 😄

@molikuner molikuner force-pushed the allow-updating-multiple-domains-in-single-dyndns-request branch from 62d989e to 721b4e6 Compare August 15, 2025 16:34
@molikuner molikuner force-pushed the allow-updating-multiple-domains-in-single-dyndns-request branch from 721b4e6 to c5eb211 Compare August 30, 2025 18:49
@MacharaStormwing
Copy link

What are the open steps needed for this change to be available on dedyn.io?
Can you give an ETA?

@peterthomassen
Copy link
Member

I need time to finish the code review, and then do the deployment. I guess it'll be done in about 1 week max.

@MacharaStormwing
Copy link

I need time to finish the code review, and then do the deployment. I guess it'll be done in about 1 week max.

Thank you very much for the information.

@peterthomassen peterthomassen force-pushed the allow-updating-multiple-domains-in-single-dyndns-request branch from c5eb211 to 2807a5f Compare September 12, 2025 14:27
@peterthomassen
Copy link
Member

I've rebased and polished the code (and in the process modernized some of the code we touched anyway). Please take a look at this fixup 2807a5f and let me know what you think. We can then merge this.

Let's move your second commit to a different PR. I made a backup in the 20250912_1112_backup in this repository.

Copy link
Member

@peterthomassen peterthomassen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, but @nils-wisiol's opinion appreciated

@molikuner
Copy link
Contributor Author

Thanks @peterthomassen! The fixup looks good 👍. I'll work on rebasing the other commit and opening a new PR once the current one is merged.

Copy link
Contributor

@nils-wisiol nils-wisiol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, thanks! Looking forward to have this deployed. Found a couple of nits.

molikuner and others added 2 commits September 16, 2025 17:28
Updates the requirements on [requests](https://github.com/psf/requests) to permit the latest version.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](psf/requests@v2.32.4...v2.32.5)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.5
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Updates the requirements on [coverage](https://github.com/nedbat/coveragepy) to permit the latest version.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](coveragepy/coveragepy@7.10.4...7.10.6)

---
updated-dependencies:
- dependency-name: coverage
  dependency-version: 7.10.6
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Updates the requirements on [cryptography](https://github.com/pyca/cryptography) to permit the latest version.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](pyca/cryptography@45.0.6...45.0.7)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 45.0.7
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Updates the requirements on [psycopg[binary]](https://github.com/psycopg/psycopg) to permit the latest version.
- [Changelog](https://github.com/psycopg/psycopg/blob/master/docs/news.rst)
- [Commits](psycopg/psycopg@3.2.9...3.2.10)

---
updated-dependencies:
- dependency-name: psycopg[binary]
  dependency-version: 3.2.10
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Updates the requirements on [django-cors-headers](https://github.com/adamchainz/django-cors-headers) to permit the latest version.
- [Changelog](https://github.com/adamchainz/django-cors-headers/blob/main/CHANGELOG.rst)
- [Commits](adamchainz/django-cors-headers@4.7.0...4.8.0)

---
updated-dependencies:
- dependency-name: django-cors-headers
  dependency-version: 4.8.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
@peterthomassen peterthomassen force-pushed the allow-updating-multiple-domains-in-single-dyndns-request branch from 2807a5f to 7f753a9 Compare September 16, 2025 23:32
@peterthomassen peterthomassen merged commit 7f753a9 into desec-io:main Sep 16, 2025
5 checks passed
@molikuner
Copy link
Contributor Author

The follow-up PR can be found at #1141.

@schnz
Copy link

schnz commented Oct 29, 2025

Hi @renne,

If this PR is accepted, you should be able to configure the Fritz!Box using this:

Update URL: https://update.dedyn.io/?hostname=<domain>&ip=<ipaddr>&fritz.my-domain.de.ipv6=<ip6addr>&ipv6=<ip6lanprefix>
Domainname: fritz.my-domain.de,host.my-domain.de,mail.my-domain.de
Username: my-domain.de
Password: TOKEN

This should update host.my-domain.de and mail.my-domain.de with the IPv6 prefix that it received (preserving the previous interface identifier of the IPv6 address), and the fritz.my-domain.de with the specific IPv6 address that it received.

EDIT: replaced domain names for clarity

@molikuner Sorry to dig this up. I just stumbled upon this use-case and I am glad you put the effort into this PR :).

Is the quotation still accurate? Because I can't seem to get it working. Suppose I have the following DNS state:

Type Subname Content
A location.dyndns.mydomain.tld 22.33.44.55
AAAA location.dyndns.mydomain.tld fdac:d6ab:301d:1db2:b6fc:7dff:fe12:5dcd
A host.location.dyndns.mydomain.tld 22.33.44.55
AAAA host.location.dyndns.mydomain.tld fd0b:ef5b:54c7:0:c505:413d:8ba4:e4ee

Now, suppose my router (location.dyndns.mydomain.tld) gets a new IPv4 and v6 address and also a new IPv6 network for delegation purposes:

# line breaks are added for the sake of readability

curl -4 --user dyndns.mydomain.tld:mytoken \
  "https://update.dedyn.io/?hostname=location.dyndns.mydomain.tld,host.location.dyndns.mydomain.tld
  &ipv4=55.44.33.22
  &location.dyndns.mydomain.tld.ipv6=fd08:2d7e:b40a:6d00:fd61:75a:fe5b:d565
  &host.location.dyndns.mydomain.tld.ipv6=fdac:2812:b465::/48"

Then I would expect the following state (changes in bold):

Type Subname Content
A location.dyndns.mydomain.tld 55.44.33.22
AAAA location.dyndns.mydomain.tld fd08:2d7e:b40a:6d00:fd61:75a:fe5b:d565
A host.location.dyndns.mydomain.tld 55.44.33.22
AAAA host.location.dyndns.mydomain.tld fdac:2812:b465:0:c505:413d:8ba4:e4ee

However, this is the state I actually get (i.e. AAAA records are removed entirely)

Type Subname Content
A location.dyndns.mydomain.tld 55.44.33.22
A host.location.dyndns.mydomain.tld 55.44.33.22

When using curl -6 (as opposed to -4) then both AAAA records are updated to the IPv6 address of the requesting client. And when providing the &ipv6=<ip6lanprefix> parameter explicitly, then both AAAA records are updated according to the provided IPv6 prefix. In essence, it seems like the last two query parameters in the curl command above are ignored entirely.

@molikuner
Copy link
Contributor Author

Hey @schnz,

At the moment only the support for "Multi-Domain Updates" is implemented. The support for "Specific-Domain Overwrites" in the same request was moved into #1141 and isn't merged (yet).

Depending on your needs, you might be able to already replicate your desired setup, e.g. if it's fine for you to not have any IPv6 address for location.dyndns.mydomain.tld. Please checkout the comments in #1141 to see how to achieve this.

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.

dyn: support multiple hostname update Update IPv6 subnet on several subdomains with one request

6 participants