Generating IPv6 PTR records on the fly

Achtung! Dieser Artikel ist älter als ein Jahr. Der Inhalt ist möglicherweise nicht mehr aktuell!

In the IPv4 world doing a reverse DNS search should always return a PTR record. BIND has the ability to create such a zonefile by calling the $GENERATE function. With this you did not have to write each PTR record by hand. In IPv6 where a /56 contains 4.722.366.482.869.645.213.696 IPv6 addresses you are not able to store it in memory or in a file.
The biggest ISP in germany is Deutsche Telekom and they provide a valid PTR for each IPv6 in their /23 network. For example:

:-$ dig -x 2003:d4:43f4:2f00:20d:b9ff:fe3f:7984 +short
p200300D443F42F00020DB9FFFE3F7984.dip0.t-ipconnect.de.

Is is even necessary?

I’ve found this IETF draft (🖇️ 🔐) handling exactly this question. Quote from section 2.1:

Some ISP DNS administrators may choose to provide only a NXDomain
response to PTR queries for subscriber addresses.  In some ways, this
is the most accurate response, since no name information is known
about the host.  Providing a negative response in response to PTR
queries does not satisfy the expectation in [RFC1912] for entries to
match.  Users of services which are dependent on a successful lookup
will have a poor experience.

I know two protocols which rely on a successfull reverse query: SSH and SMTP. I don’t know why SSH needs that information but SMTP somehow has a valid reason: Spam protection. Your mailserver should send its hostname in the HELO message and your IP must match that. If not you are most likely a spammer and the contacted mailserver denies the delivery.
All other protocols works fine without a valid PTR record.

My conclusion: Servers with static IPv6 addresses should resolve to PTR records instead of NXDOMAIN. Dynamic users generating their addresses via SLAAC don’t need it.

Generating records on the fly

My ISP provides me a /56 network and delegates RDNS requests to my own public nameserver. Their BIND nameserver has the following config inside their zone:

; 2001:db00:0000:b000::/56
$ORIGIN 0.b.0.0.0.0.0.b.d.0.1.0.0.2.ip6.arpa.
@   IN  NS  ns3.veloc1ty.de.
@   IN  NS  ns4.veloc1ty.de.

So it’s on my own to generate PTR records. BIND is not able to generate them on the fly so other solutions are needed. I’ve found CoreDNS. CoreDNS (🖇️ 🔐) is written in go (I’m a huge fan of go), easy to configure and follows a plugin philosophy: You chain plugin after plugin until a response to a request can be provided.

Checking out existing modules

CoreDNS has had the reverse (🖇️ 🔐) plugin. But they dropped support for it (🖇️ 🔐) since it had no owner. Bummer! But they write that the template module can do the same.

The template module takes a regex and you are able to build an answer based on the match groups. With IPv4 addresses the grouping are pretty easy: Four parts divided by dots. With IPv6 there are 32 groups each divived by a dot. So my regex looks like this:

^([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.([0-9a-z])\.ip6\.arpa\.$

Then the anwer uses that group:

{{ index .Match 32 }}{{ index .Match 31 }}{{ index .Match 30 }}{{ index .Match 29 }}{{ index .Match 28 }}{{ index .Match 27 }}{{ index .Match 26 }}{{ index .Match 25 }}{{ index .Match 24 }}{{ index .Match 23 }}{{ index .Match 22 }}{{ index .Match 21 }}{{ index .Match 20 }}{{ index .Match 19 }}{{ index .Match 18 }}{{ index .Match 17 }}{{ index .Match 16 }}{{ index .Match 15 }}{{ index .Match 14 }}{{ index .Match 13 }}{{ index .Match 12 }}{{ index .Match 11 }}{{ index .Match 10 }}{{ index .Match 9 }}{{ index .Match 8 }}{{ index .Match 7 }}{{ index .Match 6 }}{{ index .Match 5 }}{{ index .Match 4 }}{{ index .Match 3 }}{{ index .Match 2 }}{{ index .Match 1 }}.static.veloc1ty.de.

That’s not practical. And sometimes I want to provide a “real” PTR record. With the template module it’s not possible.

Creating my own module

Thankfully I know how DNS works and I know go. So I created my own module. The codumentation online is not that amazing. That’s why I cloned the existing any module and adpated it. Open source is nice, isn’t it?
My plugin should have this features:

  1. Respond with a generic PTR record based on the requested IPv6
  2. Custom responses: Ability to define a list containing custom PTR responses
  3. The appended suffix should be configurateable

A sample response for 4.3.2.1.2.1.e.f.f.f.0.0.4.5.0.5.2.0.0.b.0.0.3.0.8.b.d.0.1.0.0.2.arpa. should be 20010db80300b002505400fffe121234.lan.veloc1ty.de.. The dots in the IPv6 address are removed and the whole address reversed to be “human readable”. The configured suffix lan.veloc1ty.de is then added. There is also a presets file which contains a line like this:

5.3.2.1.2.1.e.f.f.f.0.0.4.5.0.5.2.0.0.b.0.0.3.0.8.b.d.0.1.0.0.2.arpa.;mycoolhost.veloc1ty.de

If I would query that address a generic response is not generated. The real response would be mycoolhost.veloc1ty.de then. My CoreDNS config file Corefile looks like this:

2.0.0.b.0.0.3.0.8.b.d.0.1.0.0.2.ip6.arpa {
    log
    autoipv6ptr {
        suffix lan.veloc1ty.de
        presetsfile /etc/coredns/zones/db.2.0.0.b.0.0.3.0.8.b.d.0.1.0.0.2.ip6.arpa.presets
    }
}

You can check out my module autoipv6ptr on GitHub (🖇️ 🔐) . See the README for all the features and installation guide. I’ve some ideas for usefull features like:

Currently it’s just a quickly hacked piece of software as a proof of concept.


Du hast einen Kommentar, einen Wunsch oder eine Verbesserung? Schreib mir doch eine E-Mail! Die Infos dazu stehen hier.

🖇️ = Link zu anderer Webseite
🔐 = Webseite nutzt HTTPS (verschlüsselter Transportweg)
Zurück