Split Views with Bind 9 Howto

Most of what follows comes from trying to help a friend configure Bind to be a bit more secure.  So this isn't anywhere near a comprehensive guide.  The most important glaring omission is that I'm not covering how to chroot Bind 9 because there are already plenty of good guides.  And yes, you should absolutely chroot your Bind service.  I'm also not covering the zone files.  This is strictly about how to increase the security of your Bind 9 installation using views.


This is applicable when you're running a caching nameserver for your internal network, but also wish to publically serve (publish) your domain(s) from the same nameserver.
  • Enable split views to allow for differentiated access control
  • Disable recursive lookups to external hosts to prevent resource abuse
  • Disallow zone transfers to all except slave nameservers to prevent information leakage

Primer on DNS

DNS stands for Domain Name Service, and exists to resolve hostnames to IP addresses (and vice versa, but mostly the former).  In the days before the current distributed DNS scheme, one resolved hostnames to IP addresses using a single file - /etc/hosts (that you'd have to edit or download every time a host is added to the Internet).  So due to the Internet's own success, this was obviously going to be an impractical thing to do.

Instead of a central authority managing a registry of hostname to IP address mappings, the (distributed) DNS system was created to allow for anyone to manage the name records of their own domains using their own nameservers.  And since the Internet was designed for robustness in case of partial or intermitten network or host failures, it was decided that every domain should be served by at least two nameservers, typically called "primary" and "secondary" servers (additional tertiary servers are optional).
  • Who's on First?

"Master" and "slave" nameservers are not the same as "primary" and "secondary" nameservers.  A "primary" is the default server that a lookup query will go to.  A query will failover to the "secondary" when the primary isn't available.  While a "primary" can be the same server as a "master" and a "secondary" can be a "slave," this need not be the case.  So, in the case of a "unpublished master" scheme, the "master" DNS server isn't mentioned anywhere in the domain zone records (nor in the global domain name registry).  In this case, both the primary and secondary nameservers are in fact slaves and get their zone info from a hidden master nameserver.  One can also have a primary nameserver that's the slave and a secondary nameserver that's the master.  So only concidentally are most primaries acting as masters and secondaries acting as slaves.

Make sure you understand the concept mentioned above.  There seems to be wide spread confusion on this in a lot of the "documentation" I've found online.

  • Got Zone?

What's the difference between a master nameserver and a slave?  The zone file is managed by the master nameserver, and synched to the slave via a "zone transfer" either periodically or when a change occurs on the master.

What's a zone file?  It's basically a file that contains all information or records about a single domain.  The problem with allowing anyone to do a zone transfer is that they can see all of your defined host information per that zone.  So if someone is up to no good, he now has an overview of your network that he would not otherwise possess.  Simply, keep your zone info private.  The only reason a host ought to have your entire zone info (i.e. allowed to transfer zones) is if that host is acting as slave nameserver.

  • Caching vs. Publishing

Caching nameservers as the name suggests, cache hostname lookups.  The first time it attempts to resolve a hostname, it has to obtain the info from somewhere else.  However, once it has done that lookup, it won't have to ask anyone for future lookups of that hostname until the cached record expires.  A caching nameserver is typically configured to automatically expire cached lookups within 48 hours.  This is the reason why you often see "there may be a 24-48 hour delay until the DNS record propagates."  The important thing to note that this is configurable.  A local evil admin may configure the expiration timeframe to be much longer.  The result is that the caching nameserver could have stale or incorrect information for longer than 48 hours.

What about publishing nameservers?  Because a caching nameserver will have to obtain the lookup info from another server, it's know as "non-authoritative."  A publishing nameserver then, is one that doesn't have to ask anyone.  And it doesn't have to ask anyone because it's authoritative for that domain.  A nameserver can claim to be authoritative for any domain, even domains that one doesn't own.  However, the only reason why other (caching) nameservers would come asking is because the root DNS servers told them to do so.  And that, is controlled by the domain owners via the global DNS registry. 
  • Recursive Queries

Basically, a recursive query is a query where the nameserver has to ask another nameserver in order to fulfill the lookup request (i.e. any query in which the nameserver isn't authoritative).  Disabling recursive queries by default prevents any host on the Internet from excuting queries on the nameserver unless the query is for a published record (e.g. lookups to will fail but lookups to will succeed).
  • Split Personalities

Views allow for the presentation of different data to different clients.  So in named.conf, internal hosts are allowed to query the caching nameserver to recursively lookup domains for them, but external hosts are only allow to ask about domains that are published via the zone records.  Although the example below shows only two views, multiple are allowed.  Note that if you have clients that are matched in multiple views, they will only be able to see the info defined in the first view (by order).


In the (commented) example below, we define two custom access control lists (ACLs).  "dns_slaves" for slave nameservers to be used in the "external" view.  And "lan_hosts" to be used in the "internal" view.  Note that each view has to have its own zone files declaration.  While they can technically share the same files, it's a good idea to create separate zone files (if you have an internal address space where the hosts are NAT'ed, use internal IP addresses instead of the public IP addresses in the corresponding zones - this prevents packets unnecessarily traveling through your gateway/router/firewall).

An important note on the "localnets" keyword.  If you have a simple "flat" network, then the network addresses on the nameservers local network interfaces will describe your entire network and can be used instead of the "lan_hosts" ACL.  However, if your internal network is routed, then the "lan_hosts" acl should contain the network addresses in use by your network (unless certain segments of your network have no need for name resolution).

Example named.conf

// This is the primary configuration file for the BIND DNS server named.
// This is for example only
acl "dns_slaves" {; # IP of the slave DNS nameserver # ditto
acl "lan_hosts" {; # network address of your local LAN; # allow loop back
options {					# this section sets the default options
directory "/etc/namedb" # directory where the zone files will reside
listen-on {; # IP address of the local interface to listen; # ditto
auth-nxdomain no; # conform to RFC1035
allow-query { any; }; # allow anyone to issue queries
recursion no; # disallow recursive queries unless over-ridden below
version "0"; # obscures version reporting - can't hurt
key "rndc-key" {
        algorithm hmac-md5;
        secret "nOzUd7+Hwdq6k6CQq7SbDw=="; # DO NOT USE THIS KEY - example only
controls {
        inet allow { localhost; }
        keys { rndc-key; };
view "internal" {
        match-clients { lan_hosts; }; # match hosts in acl "lan_hosts" above
        recursion yes; # allow recursive queries
        notify no; # disable AA notifies

        // prime the server with knowledge of the root servers
        zone "." {
                type hint;
                file "db.root";
        // be authoritative for the localhost forward and reverse zones, and for
        // broadcast zones as per RFC 1912
        zone "localhost" {
                type master;
                file "db.local";
        zone "" {
                type master;
                file "db.127";
        zone "" {
                type master;
                file "db.0";
        zone "" {
                type master;
                file "db.255";
        zone "" {
                type master;
                file "internal/";
view "external" {

// "localnets" and "any" are special reserved words
// "localnets" mean any network address (as opposed to host address) configured
// on the local network interfaces - "!" means to negate
        match-clients { !localnets; any; };
        recursion no; # disallow recursive queries
        allow-transfer { dns_slaves; }; # allow "hosts in act "dns_slaves" to transfer zones

        zone "" {
                type master;
                file "external/";
Shane Tzen © 2010