DNS: how to get local server to superimpose results over authoritative server?

I've got a domain for which the DNS I control, and is hosted on the internet. I also have a NAT'd internal network (192.168.0.0/24) which has internet access, and which I also control. On this internal network, I also have a DNS resolver. DNS software on both is PowerDNS.

What I want to be able to do is for the DNS resolver on the internal network to be able to add/change records of queries and results that come down from the authoritative server. For example, the authoritative server might have a single record for animal.example.com:

animal.example.com.    IN    AAAA    2001:140:283::1

However, I'd like it so that when internal clients do a dns lookup for animal.example.com, they might get back the following:

animal.example.com.    IN    AAAA    2001:140:283::1
animal.example.com.    IN    A       192.168.0.2

Obviously, I could set up the internal DNS server to pretend to be authoritative for example.com, but that would require a fair bit of effort to keep the main DNS server and the internal DNS server in sync for the records which are the same between both. If the internal DNS server could somehow be made a slave of the main DNS server, but also have the provision to add its own results in, that would be ideal.

Is this possible?


Solution 1:

Actually if i had to do it i would use a Lua Script with the recursor that mangles with the data on postresolve.

Hoever i really do recommend something different: Simply use a seperate authoritative Zone like internal.example.com where you AXFR example.com from the authoritative Servers and simply append your local RFC1918 data.

This way you can still debug the authoritative Zone like it is on the internet from your LAN and use the internal data.

About PowerDNS Recursor Lua Scripting: http://doc.powerdns.com/recursor-scripting.html

Solution 2:

What I think you want is a split-horizon DNS setup, however PowerDNS doesn't directly support such (unlike Bind or DJBDNS). The official response about it from the author is here: http://mailman.powerdns.com/pipermail/pdns-users/2006-September/003779.html

I've never found split-horizon DNS to be particularly confusing, myself, especially if files are laid out clearly in the file system, e.g. ./master-interal/domain.com ./master-external/domain.com

The only option they're suggesting is to have two different instances of PowerDNS running on a server listening on different ports. I guess you would then leverage iptables to redirect traffic to port 53 to whichever instance is relevant.

Solution 3:

I strongly recommend that you don't go down this path as it is extremely confusing, complex, and difficult to manage. Instead, you should set up a separate internal domain like inside.example.com. Then, if your outside dns server is also on your inside network, you should set it up to be authoritative for both domains. However if your external dns server isn't on your internal network, you should set up your inside dns server to be authoritative for inside.example.com. Then your inside dns server should forward all other requests to the outside dns server.

I realize the downside of this is you have to change the domain on all your inside machines, but doing that up-front work now will save you a lot of confusion later on.

Solution 4:

Split DNS via PowerDNS Recursor

After fumbling around for some time on my Fedora 20, I seem to have made it work. I haven't found a full how-to anywhere, so a short writeup for a minimal setup:

Explanation

We want to resolve webserver.dyndns.org to access a web service on it, both from the Internet and the LAN.

From the Internet

Machine a on the Internet resolves webserver.dyndns.org to the IP address IPisp. Behing IPisp is a router with NAT, which port-forwards port 80 to LAN IP IPx, thus making a web service available on the Internet.

This is naturally done by registering IP address IPisp at the authoritative nameserver for domain dyndns.org, which, in the case of a service like DynDns, is done using ddclient running on the router or somewhere in the LAN, and thus of no further interest here.

From the LAN

Machine b on the LAN resolves webserver.dyndns.org to the IP address IPx, so that the web service becomes available on the LAN directly. Additionally, assuming all the machines on the LAN are named along the lines of bar.localdomain, the name webserver.localdomain should also resolve to IPx. We also want to have reverse lookup for good measure, resolving IPx to webserver.dyndns.orginside the LAN (on the Internet, IPx resolves of course to nothing and IPisp resolves to some arbitrary string generated by the ISP.)

We assume pdns-recursor is running on a separate machine with IP IPdns, but we could also have it running on the webserver (on the same IP address as IPx or on an alias), or have only a single machine on the LAN.

Machine "b" may be configured statically or dynamically via DHCP; see dhclient and dnsmasq and possibly avahi. NetworkManager also enters here because it may rewrite /etc/resolv.conf; for now, assume static configuration.

Also, assume:

IPx = 192.168.1.1
IPdns = 192.168.1.2
IPbar = 192.168.1.3

Then:

/etc/resolv.conf on any machine:

nameserver 192.168.1.2
domain localdomain

Configuration for pdns-recursor:

/etc/pdns-recursor/recursor.conf basically reduces to:

setuid=pdns-recursor
setgid=pdns-recursor
allow-from=127.0.0.0/8, 192.168.1.0/8, ::1/128, fe80::/10
auth-zones=webserver.dyndns.org=/etc/pdns-recursor/[webserver.dyndns.org].zone, localdomain=/etc/pdns-recursor/[localdomain].zone, 168.192.in-addr.arpa=/etc/pdns-recursor/[168.192.in-addr.arpa].zone
local-address=192.168.1.2

The above references very much cut-down zone files (their actual names are unimportant):

In /etc/pdns-recursor/[168.192.in-addr.arpa].zone (note the lack of a dot at the end of the record name - it is a relative name not an absolute one: 1.1 means 1.1.168.192.in-addr.arpa). This works with or without the "IN".

1.1   IN   PTR     webserver.dyndns.org.
2.1   IN   PTR     dns.localdomain.
3.1   IN   PTR     b.localdomain.

In /etc/pdns-recursor/[webserver.dyndns.org].zone (note the dot at the end of the record name - it is an absolute name not a relative one)

webserver.dyndns.org.  IN  A  192.168.1.1

In /etc/pdns-recursor/[localdomain].zone

webserver    IN  A  192.168.1.1
dns          IN  A  192.168.1.2
b            IN  A  192.168.1.3

After a restart of pdns-recursor, on can test using dig by running these commands:

PDNS=192.168.1.2

# Test unknwon domain resolution and webserver resolution    
dig @$PDNS www.cnn.com | grep -A1 ";; ANSWER SECTION:"                  
dig @$PDNS webserver.dyndns.org | grep -A1 ";; ANSWER SECTION:"

# Test responses for localdomain
dig @$PDNS unknown.localdomain | grep -A1 ";; ANSWER SECTION:"
dig @$PDNS webserver.localdomain | grep -A1 ";; ANSWER SECTION:"
dig @$PDNS b.localdomain | grep -A1 ";; ANSWER SECTION:"
dig @$PDNS dns.localdomain A | grep -A1 ";; ANSWER SECTION:"

# Test responses for localdomain if the domain is omitted
dig +search @$PDNS webserver | grep -A1 ";; ANSWER SECTION:"

# Test reverse resolution
dig @$PDNS -x 192.168.1.1 | grep -A1 ";; ANSWER SECTION:"
dig @$PDNS -x 192.168.1.2 | grep -A1 ";; ANSWER SECTION:"
dig @$PDNS -x 192.168.1.3 | grep -A1 ";; ANSWER SECTION:"
dig @$PDNS -x 192.168.1.4 | grep -A1 ";; ANSWER SECTION:"