Two-in-one DNS server with BIND9

by

This tutorial shows you how to configure BIND9 DNS server to serve an internal network and a external network at the same time with different set of information. To accomplish that goal, a new feature of BIND9 called view is used. As a tutorial it’ll walk you through the whole set up, but initial knowledge of BIND and DNS is required, there are plenty of documents that cover that information on the Internet.

The problem

It is a typical problem in organizations that are growing that they have to resolve two problems at once:

  • To have a DNS server for the internal network of the company because long ago there were already too many computers to remember their IPs and even too many computers to maintain a set of host files.
  • To have a DNS server for the external servers, for external clients, etc.

To solve these problems become a bigger problem when the growing organization can’t supply more resources than one DNS server. It is a bigger problem because if you just configure your server with all your names, public and private, you’ll end up polluting the Internet with private addresses, something that is very bad, and also showing the world part of the topology of your internal network. Something you don’t want a possible attacker/cracker to have.

The other part of the problem is that for efficiency you may want to resolve to internal IPs when you are inside and external IPs when you are outside. Here I am taking about computers which have public and private connections.

There are many different solutions to this problem and I remember solving it even with BIND4, but now I am going to use BIND9 to make a solution that is very clean. This was deployed in a Debian GNU/Linux 3.1 server but it should also work for other operating systems that run BIND9, just be sure to change your paths appropriately.

Initial configuration

Let’s imagine the organization I work for makes examples… of what ? I don’t know, but you can order them on example.com. Examples Corporation has been assigned the network 1.1.1.0/24 and internally we are using 192.0.2.0/24.

Let’s start serving the external names and IPs, we edit /etc/bind/named.conf.local and add:

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

and then we create /etc/bind/db.example.com with the following contents:

; example.com
$TTL    604800
@       IN      SOA     ns1.example.com. root.example.com. (
                     2006020201 ; Serial
                         604800 ; Refresh
                          86400 ; Retry
                        2419200 ; Expire
                         604800); Negative Cache TTL;
@       IN      NS      ns1
        IN      MX      10 mail
        IN      A       192.0.2.1
ns1     IN      A       192.0.2.1
mail    IN      A       192.0.2.128 ; We have our mail server somewhere else.
www     IN      A       192.0.2.1
client1 IN      A       192.0.2.201 ; We connect to client1 very often.

As you can see, our start up has one computer to serve all, except mail, it even holds the IP forwarding and a couple of databases.

Now, a good DNS set up has at least one secondary server and in fact, some registrars (where you register domain names) enforce this. Since we don’t have a second computer, we go to , open an account and register example.com as secondary with 192.0.2.1 as IP to transfer from. We now need to let XName’s IP do the transfer; we are a small organization but since we want to be a successful start up we try to do everything as smartly as possible. So we use the BIND9 configuration directive acl to define an identifier that aliases to the XName’s IP addresses; at the beginning of /etc/bind/named.conf.local we add:

acl slaves {
    195.234.42.0/24;    // XName
    193.218.105.144/28; // XName
    193.24.212.232/29;  // XName
};

and we change the zone declaration to:

zone "example.com" {
    type master;
    file "/etc/bind/db.example.com";
    allow-transfer { slaves; };
};

We could have just typed the IPs where we type “slaves”.

Internals and externals

Now that we have a solid base, we can start to thing about serving different contents to the internal and external network, but first,
we have to define what is internal and what is external.

On /etc/bind/named.conf.local we add the following definition (at the top or below the definition of slaves):

acl internals {
    127.0.0.0/8;
    10.0.0.0/24;
};

If we had more internal networks, we could just add them there. We don’t define externals because everything that is not internal is external. You may, if you want, define sets of different externals if you want to serve different content to different chunks of the Internet.

We will use a new feature of BIND9 called views. A view let’s put a piece of configuration inside a conditional that can depend on a number of things, in this case we’ll just depend on internals. We replace the zone declaration at /etc/bind/named.conf.local with:

view "internal" {
    match-clients { internals; };
    zone "example.com" {
        type master;
        file "/etc/bind/internals/db.example.com";
    };
};

view "external" {
    match-clients { any; };
    zone "example.com" {
        type master;
        file "/etc/bind/externals/db.example.com";
        allow-transfer { slaves; };
    };
};

The match clients configuration directive allow us to conditionally show that view based on a set of IPs, ”any” stands for any IP. Internal IPs will be cached by the internal view and the rest will be dropped on the external view. The outside world can’t see the internal view, and that includes XName, our secondary DNS provider, but we removed the allow-transfer from the internal view since we don’t want anyone to be able to transfer under any circumstances the contents of the internal view.

We also changed the path, we will have to create the directory /etc/bind/externals and /etc/bind/internals and move /etc/bind/db.example.com to /etc/bind/externals/.

On /etc/bind/internals/db.example.com we put a zone file similar to the counterpart on external but holding the internal IPs:

; example.com
$TTL    604800
@       IN      SOA     ns1.example.com. root.example.com. (
                 2006020201 ; Serial
                     604800 ; Refresh
                      86400 ; Retry
                    2419200 ; Expire
                     604800); Negative Cache TTL
@       IN      A       10.0.0.1
boss    IN      A       10.0.0.100
printer IN      A       10.0.0.101
scrtry  IN      A       10.0.0.102
sip01   IN      A       10.0.0.201
lab     IN      A       10.0.0.103

Great, we can now ping our boss’ computer with

ping boss.example.com

but trying to reach mail.example.com will disappoint us, what happened ? There’s no reference to mail.example.com on the internal zone file and since we are in the internal network we can resolve mail.example.com. Fine, let’s just copy the contents of the external zone file to the internal zone file. That’ll work.

But we are a small, smart start up, we can do better than copy-paste each modification to the zone file, furthermore, that is very error prone (will you always remember to modify the internal zone file when you modify the external one, or will you forget and spend some days debugging network problems ?).

What we will do is include the external zone file in the internal file this way:

$include "/etc/bind/external/db.example.com"
@       IN      A       10.0.0.1
boss    IN      A       10.0.0.100
printer IN      A       10.0.0.101
scrtry  IN      A       10.0.0.102
sip01   IN      A       10.0.0.201
lab     IN      A       10.0.0.103

and voila! Just remember to change the serial of the external zone file whenever you change the internal one, but it is not a big deal, if you forget, nothing bad will happen since you are not likely to have caching servers inside your own small network.

Security

It is not recommended to use the same DNS server as primary for some domain (in our case example.com) and as caching DNS server, but in our case we are forced to do it. From the outside world 192.0.2.1 is the primary DNS server for example.com, from our own internal network, 192.0.2.1 (or its private address, 10.0.0.1) is our caching name server that should be configured as the nameserver to use on each workstation we have.

One of the problems is that someone might start using our caching nameserver from the outside, there’s an attack called cache-poisoning and many other nasty things that can be done and are documented on Secure an Internet Name Server (including how to avoid them).

To improve our security a bit, we’ll add a couple of directives to the configuration file:

view "internal" {
    match-clients { internals; };
    recursion yes;
    zone "example.com" {
        type master;
        file "/etc/bind/internals/db.example.com";
    };
};

view "external" {
    match-clients { any; };
    recursion no;
    zone "example.com" {
        type master;
        file "/etc/bind/externals/db.example.com";
        allow-transfer { slaves; };
    };
};

That will prevent anyone on the dangerous Internet to use our server recursively while we, on our own network, can still do it.

Configuration files

/etc/bind/named.conf.local

acl slaves {195.234.42.0/24;    // XName
    193.218.105.144/28; // XName
    193.24.212.232/29;  // XName
};

acl internals {
    127.0.0.0/8;
    10.0.0.0/24;
};

view "internal" {
    match-clients { internals; };
    recursion yes;
    zone "example.com" {
        type master;
        file "/etc/bind/internals/db.example.com";
    };
};

view "external" {
    match-clients { any; };
    recursion no;
    zone "example.com" {
        type master;
        file "/etc/bind/externals/db.example.com";
        allow-transfer { slaves; };
    };
};

/etc/bind/externals/db.example.com

; example.com
$TTL    604800
@       IN      SOA     ns1.example.com. root.example.com. (
                     2006020201 ; Serial
                         604800 ; Refresh
                          86400 ; Retry
                        2419200 ; Expire
                         604800); Negative Cache TTL
;
@       IN      NS      ns1
IN      MX      10 mail
IN      A       192.0.2.1
ns1     IN      A       192.0.2.1
mail    IN      A       192.0.2.128 ; We have our mail server somewhere else.
www     IN      A       192.0.2.1
client1 IN      A       192.0.2.201 ; We connect to client1 very often.

/etc/bind/internals/db.example.com

$include "/etc/bind/external/db.example.com"
@       IN      A       10.0.0.1
boss    IN      A       10.0.0.100
printer IN      A       10.0.0.101
scrtry  IN      A       10.0.0.102
sip01   IN      A       10.0.0.201
lab     IN      A       10.0.0.103

Comments in the original posting

  1. tarik Says:
    this conf is working for masterand the problem now is how to configure the slave

    April 13th, 2008 at 15:34 e

  2. Pupeno Says:

    Tarik,

    The tricky part about configuring a slave in this case is that the
    master-slave replication happens at the DNS-protocol level, so the
    views are not transfered. But, it is very simple to have an external
    slave, I’ve done, that just syncs out the external view, or an internal
    one that just syncs out the internal view.

    When I did this kind of install, we didn’t care about the internal
    slave because if the master was dead, DNS was the less important of our
    problems.

    Now, if you want to replicate both parts, I’d like into having a
    slave with views being internal and external, both slaves, replicating
    from the master’s internal and external IPs respectively. And again, I
    have done this a long time ago and I may be totally mistaken. If you
    have any specific error, just post it and I’ll try to analyze it.

    Hope it helps.

    April 13th, 2008 at 15:49 e

  3. tarik Says:

    hi

    in my case I have a master and a slave with the same conf. with
    internal and external views. but my slave get it’s external zone files
    from the master’s internal cause I have only one interface and this one
    is in internal so the slave dns can only get zone files from internal
    view

    Thanks

    April 15th, 2008 at 9:39 e

  4. Radha Krishna Says:

    Nice Article. Thanks!

    But a quick question. How do I use Bind9 in conjunction with DHCP??

    Lemme explain my scenario. I have a home network setup with all
    ubuntu PCs networked through a wireless router, but am not able to ping
    one machine from another using their names (not IPs).

    The wireless router runs a DHCP server, and all my machines get an
    IP from the router. I prefer to leave it that way. I don’t intend to
    use /etc/hosts; I want to have an internal network set up at my home.

    The article above discusses how to use it with static addresses –
    adding them to /etc/bind/internals/db.example.com. But in my case, the
    addresses are all dynamic. How do I handle this case??

    Any help will be greatly appreciated.

    Regards,

    Radha

    May 12th, 2008 at 1:44 e

  5. Pupeno Says:

    Hello Radha,

    My recomendation is, run DHCP but set a static IPs for the
    computers. That is on the DHCP server configure the IPs static to a MAC
    address. It may not be the best and cleanest way, but it is very good.
    You can even use the IP addresses directly if you want because your DNS
    server is down or something.

    On top of that, since you are using DHCP, you still can change router
    information or plug new computers and get them a (dynamic) IP.

    There’s a way to make dynamic DNSs, I did it, but connecting it to DHCP
    was hard and in your case, since your DHCP server is in the router, I
    bet it’ll be impossible.

    My advice, go for the static IPs on the DHCP server, it’s not worth the
    time to do anything else, specially in a home network. Unless you are
    just enjoying it.

    I hope it helps!

    May 12th, 2008 at 9:33 e

  6. John Marvin Magsino Says:

    Good day!

    very nice article…. but i had a problem… you see… i am using Debian
    Etch i386 net-install on an IBM x3200 with 2 ethernet (the Built-in and
    a 3Com PCI card. the PCI is connected to my Internal Network
    (192.168.30.0/24) and my builtin, for the Public (124.xxx.xxx.xxx/16).

    My question is, how will my /etc/hosts, /etc/hostname and /etc/resolv.conf looks like?

    i dont know how to nameserver is declared in resolv.conf so what i did was

    domain company.com

    search company.com company2.com.ph

    nameserver 124.xxx.xxx.xxx {DNS given by my

    ISP}

    nameserver 192.168.30.10 {my internal Gateway}

    nameserver 127.0.0.1 {selflookup}

    also, would it be possible to host Multiple Domains?

    im so lost… maybe you can point me out to somewhere…

    May 15th, 2008 at 9:12 e

  7. Pupeno Says:

    John,

    hosts should only have localhost and the local host name.

    hostname should have the local host name.

    resolv.conf should have more or lest what you have there, but only list
    nameservers capable of resolv any name (is your gateway also a dns
    server?). Having your ISP’s good idea, instead you should make your DNS
    server point to the ISP’s nameserver when it doesn’t know.

    I’m sorry for the short answers, the long answer is really a whole book on networking.

    May 15th, 2008 at 19:56 e

  8. Joe Says:

    Hey,could I ask a newbie questionn:

    It seems to me that you just used forward zone file,where is your reversal zone file?

    Thanks!

    May 26th, 2008 at 4:44 e

You may also like:

If you want to work with me or hire me? Contact me

You can follow me or connect with me:

Or get new content delivered directly to your inbox.

Join 5,047 other subscribers

I wrote a book:

Stack of copies of How to Hire and Manage Remote Teams

How to Hire and Manage Remote Teams, where I distill all the techniques I’ve been using to build and manage distributed teams for the past 10 years.

I write about:

announcement blogging book book review book reviews books building Sano Business C# Clojure ClojureScript Common Lisp database Debian Esperanto Git ham radio history idea Java Kubuntu Lisp management Non-Fiction OpenID programming Python Radio Society of Great Britain Rails rant re-frame release Ruby Ruby on Rails Sano science science fiction security self-help Star Trek technology Ubuntu web Windows WordPress

I’ve been writing for a while:

Mastodon