Overriding some DNS entries in BIND for internal networks

binddomain-name-system

I have an internal network with a DNS server running BIND, connected to the internet through a single gateway. My domain "example.com" is managed by an external DNS provider. Some of the entries in that domain, say "host1.example.com" and "host2.example.com", as well as the top-level entry "example.com", point to the public IP address of the gateway.

I would like hosts located on the internal network to resolve "host1.example.com", "host2.example.com" and "example.com" to internal IP addresses instead of that of the gateway. Other hosts like "otherhost.example.com" should still be resolved by the external DNS provider.

I have succeeded in doing that for the host1 and host2 entries, by defining two single-entry zones in BIND for "host1.example.com" and "host2.example.com". However, if I add a zone for "example.com", all queries for that domain are resolved by my local DNS server, and e.g. querying "otherhost.example.com" results in an error.

Is it possible to configure BIND to override only some entries of a domain, and to resolve the rest recursively?

Best Answer

The best method is via the response policy zone in Bind 9.8.1 or newer. It allows you to override single records in arbitrary zones (and there's no need to create a whole subdomain for that, only the single record you want to change), it allows you to override CNAMEs, etc. Other solutions such as Unbound cannot override CNAMEs.

https://www.redpill-linpro.com/sysadvent/2015/12/08/dns-rpz.html


EDIT: Let's do this properly then. I will document what I've done based on the tutorial linked above.

My OS is Raspbian 4.4 for Raspberry Pi, but the technique should work without any changes on Debian and Ubuntu, or with minimal changes on other platforms.

Go to where your Bind config files are kept on your system - here it's in /etc/bind. Create in there a file called db.rpz with the following contents:

$TTL 60
@            IN    SOA  localhost. root.localhost.  (
                          2015112501   ; serial
                          1h           ; refresh
                          30m          ; retry
                          1w           ; expiry
                          30m)         ; minimum
                   IN     NS    localhost.

localhost       A   127.0.0.1

www.some-website.com    A        127.0.0.1

www.other-website.com   CNAME    fake-hostname.com.

What does it do?

  • it overrides the IP address for www.some-website.com with the fake address 127.0.0.1, effectively sending all traffic for that site to the loopback address
  • it sends traffic for www.other-website.com to another site called fake-hostname.com

Anything that could go in a Bind zone file you can use here.

To activate these changes there are a few more steps:

Edit named.conf.local and add this section:

zone "rpz" {
  type master;
  file "/etc/bind/db.rpz";
};

The tutorial linked above tells you to add more stuff to zone "rpz" { } but that's not necessary in simple setups - what I've shown here is the minimum to make it work on your local resolver.

Edit named.conf.options and somewhere in the options { } section add the response-policy option:

options {
  // bunch
  // of
  // stuff
  // please
  // ignore

  response-policy { zone "rpz"; };
}

Now restart Bind:

service bind9 restart

That's it. The nameserver should begin overriding those records now.

If you need to make changes, just edit db.rpz, then restart Bind again.

Bonus: if you want to log DNS queries to syslog, so you can keep an eye on the proceedings, edit named.conf.local and make sure there's a logging section that includes these statements:

logging {
    // stuff
    // already
    // there

    channel my_syslog {
        syslog daemon;
        severity info;
    };
    category queries { my_syslog; };
};

Restart Bind again and that's it.

Test it on the machine running Bind:

dig @127.0.0.1 www.other-website.com. any

If you run dig on a different machine just use @the-ip-address-of-Bind-server instead of @127.0.0.1

I've used this technique with great success to override the CNAME for a website I was working on, sending it to a new AWS load balancer that I was just testing. A Raspberry Pi was used to run Bind, and the RPi was also configured to function as a WiFi router - so by connecting devices to the SSID running on the RPi I would get the DNS overrides I needed for testing.

Related Topic