John Floren

Home | Blog | Uses | Links
Back to blog archive

Posted 2021/6/9

Reverse DNS in CoreDNS

I recently decided to add reverse DNS to my home network, but had a bit of trouble figuring out how to do it. I run CoreDNS, and my starting configuration looked a bit like this:

.:53 {
        log stderr
        errors
        file /opt/coredns/zones/floren.lan floren.lan
        hosts /opt/coredns/hostfiles/hosts {
                fallthrough
        }
        forward . tls://1.1.1.1 tls://1.0.0.1 {
                tls_servername  cloudflare-dns.com
                health_check 5s
        }
[...]

I have an RFC 1035 zone file, /opt/coredns/zones/floren.lan, which contains the records for my local network (the example below is, of course, truncated):

floren.lan.        IN  SOA router.floren.lan. john.floren.net. 1 7200 3600 1209600 3600

router.floren.lan.      IN      A       192.168.0.254

rpi4.floren.lan. IN A 192.168.0.43 ;raspberry pi 4
nas.floren.lan. IN A 192.168.0.70 ; FreeNAS

The hosts file is an automatically-updated DNS blacklist of known-bad hosts, fetched daily from github.com/StevenBlack/hosts via a cron job (see appendix).

Lookups first hit the zone file, then the hosts file, then the Cloudflare public DNS servers.

First Attempt: Hostfile

Because the hosts plugin documentation says it’ll automatically build PTR records from the host file, my first instinct was to just convert my zone file into hosts format and add another stanza. Unfortunately, the plugin documentation also says you can only have one instance of the hosts plugin per server block, and I didn’t want to get rid of my blocklist.

Success: Autogenerated Zone File

With a host file out of the question, I decided the best thing to do was create a zone file containing PTR records, but I certainly didn’t want to have to change two files every time I created/modified an A record! Therefore I wrote a quick script which (ab)uses awk to build a reverse zone file from my existing “master” file:

#!/bin/sh
MASTER=/opt/coredns/zones/floren.lan
REVERSE=/opt/coredns/zones/reverse
# Increment SOA serial on master zone file
awk '/SOA/{$6=$6+1} {print $0}' $MASTER > /tmp/zone.new
mv /tmp/zone.new $MASTER
# Generate reverse file
awk '/SOA/{$1="168.192.in-addr.arpa."; print $0}' $MASTER > $REVERSE
tail -n +1 $MASTER | awk '$3=="A"{split($4,addr,"."); print addr[4] "." addr[3] "." addr[2] "." addr[1] ".in-addr.arpa.", "6230 IN PTR", $1}' >> $REVERSE

First, it increments the SOA on the master zone file, then takes that SOA header and uses it to start the newly-generated reverse zone file. Then it just walks every A record in the master zone file and converts it to a PTR record, generating something like this:

168.192.in-addr.arpa. IN SOA router.floren.lan. john.floren.net. 6 7200 3600 1209600 3600
254.0.168.192.in-addr.arpa. 6230 IN PTR router.floren.lan.
43.0.168.192.in-addr.arpa. 6230 IN PTR rpi4.floren.lan.
70.0.168.192.in-addr.arpa. 6230 IN PTR nas.floren.lan.

To use the new zone file in CoreDNS, I just had to make a small tweak to my config:

.:53 {
        log stderr
        errors
        file /opt/coredns/zones/floren.lan floren.lan
        file /opt/coredns/zones/reverse 168.192.in-addr.arpa
        hosts /opt/coredns/hostfiles/hosts {
                fallthrough
        }
        forward . tls://1.1.1.1 tls://1.0.0.1 {
                tls_servername  cloudflare-dns.com
                health_check 5s
        }

Every time I modify the master zone file (/opt/coredns/zones/floren.lan, in my case), I just re-run my script. CoreDNS detects the updated SOA in the files and reloads them.

Using this yourself

If you want to do the same, you’ll need to modify the MASTER variable in my script to point at your own zone file.

If your home network isn’t on the 192.168.0.0/16 subnet, make sure you change “168.192.in-addr.arpa” to whatever would be appropriate on your network.

Appendix: Automated Blocklist

I’ve got the following entry in my crontab to keep the blocklist updated:

0 0 * * *       curl https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts > /opt/coredns/hostfiles/hosts