Running BIND/named on DHCP Linux client

Scenario

The scenario is this: you want to run BIND on a server that gets its IP address via DHCP. Furthermore, you want to use the provider’s DNS as a forwarder for everything not in the scope of the DNS server you want to run.

For instance, for some very good reason you need to run DNS on your server but you are behind a firewall requiring you to use a DNS server inside the firewall to resolve addresses on the Internet.

Or another case (mine in fact) you are running a network of virtual machines in a cloud provider like Google Compute Engine. You have a local dns-based service-discovery environment that requires you to run BIND locally so that service discovery inquires can get shunted to the service-discovery’s propriety DNS system. However, the cloud provider also provides proprietary name resolution for their services, so you are motivated to to forward queieries to their server and let it do the proprietary lookups or forward your query into the Internet.

Problem #1

You can’t be sure that the namesever IP you get from DHCP will remain. Your administrator could move DNS around and figure it doesn’t matter because it’s assigned by DHCP anyways. This means you aren’t comfortable hardcoding the address in your BIND config.

Problem #2

The DHCP client (dhclient) overwrites resolv.conf. You keep editing it to have nameserver 127.0.0.1 and dhclient changes it back to the nameserver provided by DHCP.

Solutions

resolv.conf

This problem is the easier of the two to solve. dhclient communicates with the DHCP server, then passes what it has learned to a dhclient script with all that it has learned passed as environment variables. Before this script does anything, it calls enter scripts which can do things before any changes are made by the main script. Then the main script rewrites /etc/resolv.conf and reconfigures the interfaces. Then the main script calls the exit scripts. The process can be depicted like this:

We can take advantage of the enter scripts. Assuming something resembling a vaguely standard DHCP configuration, you can create a dhclient hook. On my Debian systems, there is a directory called /etc/dhcp/dhclient-enter-hooks.d. It may be called something else on other distros. Look for /etc/dhcp or /etc/dhcp3/ and then subdirectories under them with names containing “enter” and “exit”. We are looking for the proper directories to store hooks to be run before and after the main dhclient script. In our case we want to define an “enter” hook so that we can create a bogus resolv.conf-rewrite script before dhclient messes with resolv.conf.

Create a file, called something like nodnsupdate and paste the following into it:

#!/bin/sh
make_resolv_conf(){
        :
}

Make sure to chmod the file to be executable. dhclient will call this script to rewrite resolv.conf but the script actually does nothing.

This should be all that’s necessary to keep dhclient from overwriting your resolv.conf

DNS forwarding to upstream provider

We will use another dhclient enter script for this solution. The dhclient daemon passes a large number of environment variables into the scripts that it calls. The DHCP-assigned nameservers are contained in the $new_domain_name_servers environment variable. We can use this to create a shell script to write a very small BIND config file that defines one or more forwarders. The file will look something like this:

forwarders {
  169.254.169.254;
};

This needs to be included in the options { }; section of your named.conf file (or whatever you system calls it). It will look something like this:

options {
        directory "/var/cache/bind";

        include "/etc/bind/forwarders.conf";
        dnssec-validation auto;

        auth-nxdomain no;    # conform to RFC1035
        listen-on-v6 { any; };
};

The actual contents will vary. The important line is

include "/etc/bind/forwarders.conf";

(Your path may be different). That will cause BIND/named to read the file our script writes. The script itself looks like this, but you may need to customize the paths:

#!/bin/bash

CONFIG=/etc/bind/forwarders.conf

if [ -n "$new_domain_name_servers" ]; then
    echo "forwarders {" > $CONFIG
    for nameserver in $new_domain_name_servers; do
        echo "  ${nameserver};" >> $CONFIG
    done
    echo "};" >> $CONFIG
fi

systemctl reload bind9

The last line performs a reload of BIND/named on my Debian system. The command may be different on your system. It’s important to include this step or the daemon won’t know to read the changes to the file.

This script will be called when dhclient requests/renews your IP info from the DHCP server. If the upstream DNS server changes, that change will be captured in forwarders.conf and incorporated into your BIND/named server.

We have now modified the DHCP process to look like this:

which will hopefully let you run your own BIND/named server while still being able to recurse to an upstream provider.

Lee Nelson

Long time Programmer, Systems Administrator and Network Engineer. Lifetime tinkerer.

nelsonov nelnet_org


Published