The IPv6 rDNS endpoints act strangely and frankly need a v2 rewrite.
Issue 1: addresses are treated as string literals and not normalized
As I understand things based on testing:
- IPv6 addresses are treated as string literals in storage/database
- The addresses are validated (with regex according to the error message)
- But they are not normalized to some canonical RFC 5952 form
Example:
$ go run cmd/netcup/main.go rdns get 2a0a:4cc0:2000:8fe5::
$ go run cmd/netcup/main.go rdns set 2a0a:4cc0:2000:8fe5:cafe:: test-0.example.com
$ go run cmd/netcup/main.go rdns set 2a0a:4cc0:2000:8fe5:cafe::0 test-1.example.com
$ go run cmd/netcup/main.go rdns set 2a0a:4cc0:2000:8fe5:cafe::00 test-2.example.com
$ go run cmd/netcup/main.go rdns set 2a0a:4cc0:2000:8fe5:cafe::000 test-3.example.com
$ go run cmd/netcup/main.go rdns set 2a0a:4cc0:2000:8fe5:cafe::0000 test-4.example.com
$ go run cmd/netcup/main.go rdns set 2a0a:4cc0:2000:8fe5:f00d::0000 test-4.example.net
$ go run cmd/netcup/main.go rdns set 2a0a:4cc0:2000:8fe5:f00d::000 test-3.example.net
$ go run cmd/netcup/main.go rdns set 2a0a:4cc0:2000:8fe5:f00d::00 test-2.example.net
$ go run cmd/netcup/main.go rdns set 2a0a:4cc0:2000:8fe5:f00d::0 test-1.example.net
$ go run cmd/netcup/main.go rdns set 2a0a:4cc0:2000:8fe5:f00d:: test-0.example.net
Alles anzeigen
These are the same addresses. Their most compact and expanded forms are:
2a0a:4cc0:2000:8fe5:cafe:: / 2a0a:4cc0:2000:8fe5:cafe:0000:0000:0000
2a0a:4cc0:2000:8fe5:f00d:: / 2a0a:4cc0:2000:8fe5:f00d:0000:0000:0000
The expectation then is we should see cafe be test-4.example.com, and f00d be test-0.example.net. And sure enough, after waiting for the clock to go past a multiple of 10 minutes (and a few seconds), we check what is actually being served from DNS:
$ dig @root-dns.netcup.net +noall +answer -x 2a0a:4cc0:2000:8fe5:cafe::
0.0.0.0.0.0.0.0.0.0.0.0.e.f.a.c.5.e.f.8.0.0.0.2.0.c.c.4.a.0.a.2.ip6.arpa. 86400 IN PTR test-4.example.com.
$ dig @root-dns.netcup.net +noall +answer -x 2a0a:4cc0:2000:8fe5:f00d::
0.0.0.0.0.0.0.0.0.0.0.0.d.0.0.f.5.e.f.8.0.0.0.2.0.c.c.4.a.0.a.2.ip6.arpa. 86400 IN PTR test-0.example.net.
As you can see, the responses show that the most recent POST is what gets committed to DNS configuration. This is perfectly fine and expected.
What's not acceptable is this API response:
$ go run cmd/netcup/main.go rdns get 2a0a:4cc0:2000:8fe5::
2a0a:4cc0:2000:8fe5:cafe:: test-0.example.com
2a0a:4cc0:2000:8fe5:cafe::0 test-1.example.com
2a0a:4cc0:2000:8fe5:cafe::00 test-2.example.com
2a0a:4cc0:2000:8fe5:cafe::000 test-3.example.com
2a0a:4cc0:2000:8fe5:cafe::0000 test-4.example.com
2a0a:4cc0:2000:8fe5:f00d:: test-0.example.net
2a0a:4cc0:2000:8fe5:f00d::0 test-1.example.net
2a0a:4cc0:2000:8fe5:f00d::00 test-2.example.net
2a0a:4cc0:2000:8fe5:f00d::000 test-3.example.net
2a0a:4cc0:2000:8fe5:f00d::0000 test-4.example.net
Alles anzeigen
Like we state before, all these addresses are the same. While it is possible (but typically recommended) to have multiple PTR records for the same address, that is not what is going on here. There should only be 1 instance of each address, even if in the future they can be for multiple PTR records. It doesn't matter if you store records compact or expanded, that mechanism needs to be consistent to avoid ambiguities like the above.
Issue 2: IPv6 GET endpoint is not for a singular address, but for a subnet prefix (with an undisclosed /64 prefix mask)
Related to the above issue, when I `rdns get 2a0a:4cc0:2000:8fe5::` I expect to get the PTR record(s) for the address `2a0a:4cc0:2000:8fe5:0000:0000:0000:0000`. Instead, what we get is a response that we would've expected from a command like `rdns list` or `rdns list 2a0a:4cc0:2000:8fe5::/64`.
At minimum, this behavior should be documented. However, I believe these endpoints should be written to be consistent, so like the IPv4 GET /api/v1/rdns/ipv4/{ip} endpoint, the IPv6 GET /api/v1/rdns/ipv6/{ip} endpoint is for a single address.
Issue 3: IPv4 and IPv6 endpoints are not consistent with each other
Similarly to the above issue:
- IPv4 `GET` returns just the PTR record, IPv6 `GET` returns both address and PTR record (see related next issue)
- /api/v1/rdns/ipv4/{ip} and /api/v1/rdns/ipv6/{ip} should have the `POST` method since they already also have the `GET` and `DELETE`
- /api/v1/rdns/ipv4 and /api/v1/rdns/ipv6 can then optionally be repurposed for retrieving all rDNS records associated with the user, similar to /api/v1/servers (but it can be argued that this is also ambiguous, and should be remade as /api/v1/users/{userId}/servers instead, unless there is a plan for org-based IAM in the future)
Issue 4: deleting an IPv6 PTR record sets it to `nobody.yourvserver.net` and not back to nothing
Similar to what I mentioned in another post regarding IPv4.
IPv6 addresses start out without any PTR records. Then the user adds one. The user then deletes that record, causing the address to have a `nobody.yourvserver.net` PTR record just like IPv4.
This is inconsistent behavior. Addresses that no longer have any PTR records in the REST API should stay that way.