Two-in-one DNS server with BIND9

Posted by pupeno on Mon 20 Feb 2006 at 07:33

Tags: ,

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.

Continue reading at original site or download PDF.

Contents

1 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 IPs1 and even too many computers to maintain a set of host files2.
  • To have a DNS server for the external servers, for external clients, etc.

two solve this problems at once become a bigger problem when the growing organization can't supply more resources than one DNS server3. 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.

2 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 192.0.2.0/24 and internally we are using 10.0.0.0/24.

Let's start serving the external names and IPs, we edit /etc/bind/named.conf.local4 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 XName, 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".

3 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! Finding the $include directive in the current documentation was hard.. 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.

4 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 [SINS] (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.

5 Configuration files

5.1 /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; };
    };
};

5.2 /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.

5.3 /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

Bibliography

SINS
Securing an Internet Name Server

Footnotes

... IPs1
For me, two computers already qualify as too many computers to remember their IPs.
... files2
The host file resides on /etc/hosts and is a simple mapping for the local computer from names to IP. It was the first way to resolve names to IPs and long ago a central big hosts file was maintained, latter distributed by FTP or similar. It rapidly grow into a problem which was solved by the invention of DNS. Try not to let your hosts file grow into a problem before you turn it into DNS, learn from the pioneers!
... server3
Or when you are a perfectionist and believe that this should be doable with only one server.
.../etc/bind/named.conf.local4
It may be just /etc/bind/named.conf in your operating system if it is not Debian.

 

 


Posted by Anonymous (87.96.xx.xx) on Mon 20 Feb 2006 at 13:34

Thanks! But avoid using addresses that are or might be publicly assigned. RFC 3330, which "describes the global and other specialized IPv4 address blocks that have been assigned by the Internet Assigned Numbers Authority (IANA).", says:

192.0.2.0/24 - This block is assigned as "TEST-NET" for use in documentation and example code. It is often used in conjunction with domain names example.com or example.net in vendor and protocol documentation. Addresses within this block should not appear on the public Internet.

So the best thing to do would be to use parts of that block in the examples. Example:
192.0.2.0/26 - instead of 1.1.1.0/24.
192.0.2.64 - instead of 21.21.21.21
192.0.2.65 - instead of 45.45.45.45

Some readers might be a little confused by 192.0.2.0/26. In that case one might consider using 192.0.2.0/24 instead, and choosing addresses from other blocks for the other addresses. Addresses in any of the following blocks would be better suited than using possibly assigned addresses. 10.0.0.0/8     - Private-Use Networks
169.254.0.0/16 - Link Local
172.16.0.0/12  - Private-Use Networks
192.0.2.0/24   - Test-Net
192.168.0.0/16 - Private-Use Networks


Best regards, /Martin :-)

[ Parent | Reply to this comment ]

Posted by pupeno (201.252.xx.xx) on Mon 20 Feb 2006 at 13:41
[ Send Message ]
Thank you, when I was writting the doc I thought about it and asked in various channels, nobody knew if there were reserved IPs for documentation.
I'll change it.
Thank you.

[ Parent | Reply to this comment ]

Posted by pupeno (201.252.xx.xx) on Mon 20 Feb 2006 at 14:31
[ Send Message ]

The article at my web site has been corrected. I've sent a request to correct the IP addresses here as well.

Thank you.

[ Parent | Reply to this comment ]

Posted by Steve (82.41.xx.xx) on Mon 20 Feb 2006 at 15:53
[ Send Message | View Steve's Scratchpad | View Weblogs ]

Done now, thanks for letting me know.

Sorry for the delay, but some of that markup was nasty!

Steve

[ Parent | Reply to this comment ]

Posted by Anonymous (87.96.xx.xx) on Mon 20 Feb 2006 at 16:58
You're most welcome.

But I don't understand what the address 1.1.1.1 is about. Shouldn't that be 192.0.2.1 instead? (The public address of our name server.)

BR, /Martin

[ Parent | Reply to this comment ]

Posted by pupeno (201.252.xx.xx) on Mon 20 Feb 2006 at 17:12
[ Send Message ]
Yes, my mistake, I forgot to change those.

[ Parent | Reply to this comment ]

Posted by Anonymous (82.173.xx.xx) on Wed 1 Mar 2006 at 12:50
Very nice howto, my setup is about the same,

only for the internal network i also have DHCP3-server running
DHCP3-server has the ability to add dns records to bind9

heres how i did it:

I created a news tsic key
and include this in named.local.options

include "/etc/bind/ddns.key";

this key has rights 644 and is owned by root:bind
the default is root:bind with 640
if you dont want 644 rights just add the user dhcp3-server
is running on to group bind and put 640 on this file.

/etc/bind/ddns.key
key "ddns-key" {
algorithm hmac-md5;
secret "ThiSNeed2BeChangedAlso!";
};

in the internal zone, put
allow-update { key ddns-key; };
in it.

to protect my local zone's i use
allow-query { "network2"; "server1"; "server2"; "localhost"; };
allow-transfer { "server1"; "server2"; "network2"; "localhost"; };

( i have multiplex networks and 4 dns server ;-) )

for the DHCP3-server ( you need dhcp3-server and not dhcp-server )
make the server authoritive
here small example of my config.


server-identifier servername;
authoritative;
#
# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;
#
ddns-update-style interim;
allow-cient-updates;
ddns-updates on;
ddns-domainname "internal.domain.tld";
ddns-rev-domainname "in-addr.arpa";


key ddns-key {
algorithm hmac-md5; secret "ThiSNeed2BeChangedAlso!";";
}
zone rotterdam.bazuin.nl. {
primary 127.0.0.1;
key ddns-key;
}
zone 1.168.192.in-addr.arpa. {
primary 127.0.0.1;
key ddns-key;
}
#
#
# use shared-network if you have a interface alias like eth0 and et0:1
# Shared Network on Bazuin
shared-network bazuin-shared {
# Subnet definition for Servers LocalNet
subnet 127.0.0.0 netmask 255.0.0.0 {
}
# Subnet definition for internal network options
subnet 192.168.1.0 netmask 255.255.255.0 {
range 192.168.1.101 192.168.1.200;
option broadcast-address 192.168.1.255;
option subnet-mask 255.255.255.0;
option domain-name "internal.domain.tld";
option domain-name-servers 192.168.1.241, 192.168.1.242;
option netbios-name-servers 192.168.1.241, 192.168.1.241;
option routers 192.168.249.1;
option netbios-node-type 8;
option ntp-servers 192.168.249.1;
default-lease-time 86400;
max-lease-time 172800;
one-lease-per-client on;
option ip-forwarding off;
option time-offset -18000;
allow unknown-clients;
}
}

[ Parent | Reply to this comment ]

Posted by Anonymous (213.164.xx.xx) on Mon 20 Feb 2006 at 14:37
I don't think it's true about recursive DNS servers being a security issue any more.

If it was still a problem, then every user on a large isp should worry.

[ Parent | Reply to this comment ]

Posted by pupeno (201.252.xx.xx) on Mon 20 Feb 2006 at 14:56
[ Send Message ]
At any rate it is better not to let the whole world use your DNS recursively.

[ Parent | Reply to this comment ]

Posted by Anonymous (213.164.xx.xx) on Mon 20 Feb 2006 at 15:07
Why?

[ Parent | Reply to this comment ]

Posted by pupeno (201.252.xx.xx) on Mon 20 Feb 2006 at 15:23
[ Send Message ]
Because it is not needed there's no reason to provide it. The reasons not to do it are, for example, that they might use your bandwith to find out about names you are not serving, bandwith, HD, processor, etc. Also, recursivity might or might not represent a security problem. Better safe than sorry.

[ Parent | Reply to this comment ]

Posted by spiney (85.125.xx.xx) on Mon 20 Feb 2006 at 19:01
[ Send Message ]
Instead of allowing recursion or not I'd rather put
allow-query { your; networks; here; };
into the servers main options (not mentioned in the article, in Debian sarge/sid they can be found in /etc/bind/named.conf.options, basically using your "internals" acl in there should work) and
allow-query { any; };
into the zone definition in the external view.

And I would also (as suggested in another comment) use pre-shared keys between master and slave servers for zone transfers. IP addresses alone are not good enough an identification for slave servers, and you don't want your whole domain data being transferred to someone not authenticated properly.
--
Debian GNU/Linux on an IBM Thinkpad T43p

[ Parent | Reply to this comment ]

Posted by mvanbaak (80.126.xx.xx) on Mon 20 Feb 2006 at 21:42
[ Send Message ]
The allow-query and pre-shared keys are fine when you are dealing with internal views etc.
But as soon as you are dealing with zones that provide information about public services I can only see it as a no-go.
When a customer wants to transfer their domain to us (ISP), the first thing we do is try a transfer of the zone. That way, you can make the transfer go more smoothly.
If everyone would do that, things would go a lot better.

Just my 2 cents as ISP admin.

[ Parent | Reply to this comment ]

Posted by spiney (85.125.xx.xx) on Mon 20 Feb 2006 at 21:50
[ Send Message ]
I think the main problem in the case of an ISP and also in case of the author of the article (nice one btw, in case my last comment made it look different) arises if you don't control both master and slave servers. If you do, both allow-query (in case you have both caching-only functions for a private network AND public zones) and also pre-shared keys are a good idea.

My 2 cents not-as-ISP-but-otherwise DNS admin. :)
--
Debian GNU/Linux on an IBM Thinkpad T43p

[ Parent | Reply to this comment ]

Posted by mvanbaak (80.126.xx.xx) on Mon 20 Feb 2006 at 22:05
[ Send Message ]
The article is indeed very nice, Thanks for that.

The shared keys and other restrictions on transfers are ok, as long as the domain will never be candidate to be transferred to another ISP.
We as ISP don't allow transfers of our main domains (linked to our company name and products).
The rest is not secured so it will be easier for others to act quick in case of a domain transfer.

As the article poster wrote: It's a bad idea to keep private ip space in your public zones.
So if those are not in there, ppl on the internet could do a dig on your mx, www, A, ns etc records and assemble a zonefile that way.

Ah well, if you are only hosting domains for yourself or your company, and not for customers, either way should be fine.

[ Parent | Reply to this comment ]

Posted by Anonymous (217.155.xx.xx) on Tue 18 Apr 2006 at 22:07
what about restricting recursion to a fixed list of servers?

options {
allow-recursion { 192.168.196.0/24; localhost; };
};

[ Parent | Reply to this comment ]

Posted by daemon (198.54.xx.xx) on Mon 20 Feb 2006 at 18:53
[ Send Message | View Weblogs ]
If you're interested in keeping your DNS secure, you might want to look at using keys for your allow-transfer statements, it's a small addition, but worthwhile.

Otherwise, it's a nice article, I've been wanting to play around with view for a while, I've just never quite had the time to get around to it ;-)

Laters...

[ Parent | Reply to this comment ]

Posted by pupeno (201.252.xx.xx) on Mon 20 Feb 2006 at 19:23
[ Send Message ]
For this and the other comment regarding shared keys. Yes, that is a good idea, as long as you are in control of the secondary nameservers. The secondary nameservers in the example are XName's, which are free and a good resource for small organizations; I am very thankfull to XName; but I don't think they offer shared keys... yet.

[ Parent | Reply to this comment ]

Posted by Anonymous (222.126.xx.xx) on Wed 8 Mar 2006 at 07:47
Hi
Im just asking if I have own registered domain how can i configure it please help thank you very much.

Thanks
Vher

[ Parent | Reply to this comment ]

Posted by Anonymous (83.204.xx.xx) on Sun 26 Mar 2006 at 19:25
Hello,

First, thank you for this howto, it's great.

However, I still wonder on some points :
- on debian, the file /etc/bind/named.conf contains definitions for the generic zones each dns server should serve. These are not included in the view statements giving an error at bind start : "/etc/bind/named.conf:12: when using 'view' statements, all zones must be in views". This error does not prevent the named server to start, but it gives the feeling that something is wrong. So my question is should we modify the named.conf and include the zones it contains in the "internal" view ? In this case, how could we preserve the named.conf/named.conf.local/named.conf.options spli that is default on debian ?
- second question, what about reverse zones, should we include them in views ? How ?

I hope you'll have some time to answer this and complete the howto with the answers if you find the topics relevant.

Thank you

[ Parent | Reply to this comment ]

Posted by Anonymous (220.233.xx.xx) on Tue 23 Jan 2007 at 07:31
your message "/etc/bind/named.conf:12: when using 'view' statements"

As you probably have already worked this out - this response may be redundant.

Simply move your zone information from named.conf to named.conf.local under view "internal", and restart bind and the error message should disappear<g>

// I to struggled over this for some time and could find no other
// references on the web.

Danny

[ Parent | Reply to this comment ]

Posted by Anonymous (202.90.xx.xx) on Thu 13 Sep 2007 at 10:57
seems it doesnt work. the message "/etc/bind/named.conf:XX: when using 'view' statements" still appear in syslog. using "named-checkconf" command, it also appear. anyway, does the message affect my dns server? if yes, in what way? my dns server seems working normally, thanks to pupeno =)

kidlat

[ Parent | Reply to this comment ]

Posted by pdu (66.90.xx.xx) on Wed 28 Nov 2007 at 17:45
[ Send Message ]
I too would like to know how to best handle reverse zones with this configuration.

[ Parent | Reply to this comment ]

Posted by mjh2000 (72.89.xx.xx) on Thu 3 Apr 2008 at 17:51
[ Send Message ]
Great article -
Missing 2 things..can anyone help ????

1)How do you handle reverse dns like 2.168.192.arpa..... zones???? When you are dealing with multiple domains zones on the same box with using views????

2)How do you get replication to work with views??? I have a wierd thing going on that if i disable one view, it replicates out my external and internal table for a zone...???

Can anyone help ???? Please.

thanks
mjh

[ Parent | Reply to this comment ]

Sign In

Username:

Password:

[Register|Advanced]

 

Flattr

 

Current Poll

Which init system are you using in Debian?






( 1599 votes ~ 7 comments )