Configure BIND as a Catching-only DNS Server on Debian

When a DNS server resolves a query, it returns the answer to the client. The DNS server also stores the answer in its cache for the period of time that was allowed by the record’s TTL value. This way any subsequent requests are processed faster when the nameserver is asked to resolve the same names again. Caching-only server does not forward any zones.


Software used in this article:

  1. Debian Wheezy
  2. Bind 9.8.4

Before We Begin

We are going to to set up a general purpose DNS server, which:

  1. Acts as master for two internal zones, and
  2. Acts as cache server for all other requests.

BIND server’s info:

  1. Hostname: dns.
  2. IP:
  3. LAN:

Two internal DNS zones will be setup:

  1. lan.local – a forward zone, translates domain names into IP addresses.
  2. 1.10.10 – a reverse zone, translates IP addresses into domain names.

DNS server will be secured by:

  1. Running BIND with less privileges.
  2. Limiting queries to LAN only.
  3. Limiting zone transfers to LAN only.
  4. Hiding the BIND version number and hostname from being disclosed.
  5. Configuring iptables to allow access to TCP/UDP ports 53 from LAN only.


Install BIND and resolvconf packages:

# apt-get update && apt-get install bind9 bind9utils resolvconf

Start BIND on boot:

# update-rc.d bind9 defaults
update-rc.d: using dependency based boot sequencing

The dnsutils package contains dig and nslookup:

# apt-get install dnsutils

Our server’s network configuration is as below:

# cat /etc/network/interfaces
auto lo
iface lo inet loopback

allow-hotplug eth0
iface eth0 inet static

Restart network configuration if any changes have been made:

# nohup sh -c "ifdown eth0 && ifup eth0"

Update the /etc/resolv.conf file:

# resolvconf -u


First thing to do is to make sure that BIND is not kept running with root privileges. Open /etc/default/bind9 and add the following line if one is not yet present:

OPTIONS="-u bind"

This tells the BIND service to setuid to the “bind” user after completing privileged operations, such as creating sockets that listen on privileged ports.


Some comments are provided. You are advised to check BIND v9.8 documentation for more info.

include "/etc/bind/rndc.key";
include "/etc/bind/named.conf.default-zones";

# Declaring control channels to be used by the rndc utility.
controls {
	inet port 953
	allow {; } keys { "rndc-key"; };

# Limiting access to local networks only.
acl "clients" {;;

# Global server configuration.
options {
	directory "/var/cache/bind";
        pid-file "/var/run/named/";
        dump-file "/var/cache/bind/named.dump";
        statistics-file "/var/cache/bind/named.stats";

	# no forwarding, plus listen on IPv4 only
	forwarders {};
	listen-on-v6 { none; };
	# Maximum number of simultaneous client TCP connections to accept.
	tcp-clients 50;

	# Disable built-in server information zones.
	version none;
	hostname none;
	server-id none;

	# Attempt to do all the work required to answer the query.
	recursion yes;
	recursive-clients 500;
        allow-recursion { clients; };
        allow-query { clients; };
	# Only LAN users are allowed to receive zone transfers from the server.
        allow-transfer { clients; };

	auth-nxdomain no;
        notify no;
	dnssec-enable yes;
	dnssec-validation auto;

# Specifications of what to log, and where the log messages are sent.
logging {
        channel "common_log" {
                file "/var/log/bind/named.log" versions 10 size 5m;
		severity error;
                print-category yes;
                print-severity yes;
                print-time yes;
        category default { "common_log"; };
        category general { "common_log"; };
        category queries { "common_log"; };
	category client { "common_log"; };
	category security { "common_log"; };
	category query-errors { "common_log"; };
	category lame-servers { null; };

# Internal zone definitions.
zone "lan.local" {
        type master;
        file "/etc/bind/db.lan.local";
zone "" {
        type master;
        file "/etc/bind/db.1.10.10";


$TTL    86400

@               IN      SOA     localhost. root.localhost. (
                                        2014082401      ; Serial
                                        86400           ; Refresh
                                        3600            ; Retry
                                        604800          ; Expire
                                        7200 )          ; Negative Cache TTL

@               IN      NS      localhost.

@		IN	A
dns             IN      A
gw		IN	A
www             IN      A


$TTL    86400

@               IN      SOA     localhost. root.localhost. (
                                        2014082401      ; Serial
                                        86400           ; Refresh
                                        3600            ; Retry
                                        604800          ; Expire
                                        7200 )          ; Negative Cache TTL

@               IN      NS      localhost.

1		IN	PTR	gw.lan.local.		;
2		IN	PTR	dns.lan.local.		;
17		IN	PTR	www.lan.local.		;

Verify BIND Configuration

# named-checkconf /etc/bind/named.conf

Restart the Service

# service bind9 restart

Verify the service is listening on TCP/UDP ports 53:

# netstat -nltup | grep :53
tcp        0      0*       LISTEN   10905/named     
tcp        0      0*       LISTEN   10905/named     
udp        0      0*                10905/named     
udp        0      0*                10905/named

Configure Iptables on the BIND Server to Allow LAN Access

# iptables -A INPUT -s -p tcp --dport 53 -j ACCEPT
# iptables -A INPUT -s -p udp --dport 53 -j ACCEPT

Quering DNS Server from a Client PC

Caching DNS Server

Verify that the BIND server is caching queries:

$ dig | grep time
;; Query time: 237 msec
$ dig | grep time
;; Query time: 1 msec

Note that cache data is discarded when BIND is restarted.

DNS Zone Transfer

This does not work if “allow-transfer { none; };” is specified in the named.conf.

$ host -l lan.local
lan.local name server localhost.
lan.local has address
dns.lan.local has address
gw.lan.local has address
www.lan.local has address

To make dig output more readable:

$ alias dig='dig +noquestion +nocomments +nostats'

You can also use something like “dig +noall +answer”.

$ dig @lan.local lan.local axfr
; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> +noquestion +nocomments +nostats @lan.local lan.local axfr
; (1 server found)
;; global options: +cmd
lan.local.		3600	IN	SOA	localhost. root.localhost. 2014082401 86400 3600 604800 7200
lan.local.		3600	IN	NS	localhost.
lan.local.		3600	IN	A
dns.lan.local.		3600	IN	A
gw.lan.local.		3600	IN	A
www.lan.local.		3600	IN	A
lan.local.		3600	IN	SOA	localhost. root.localhost. 2014082401 86400 3600 604800 7200

Reverse DNS Lookup

$ dig -x
; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> +noquestion +nocomments +nostats -x
;; global options: +cmd	3600	IN	PTR	dns.lan.local.	3600	IN	NS	localhost.
localhost.		604800	IN	A
localhost.		604800	IN	AAAA	::1

Query BIND Server’s Version and Hostname

Get BIND version. This does not work if “version none;” is specified in the named.conf.

$ dig @lan.local version.bind chaos txt
; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> +noquestion +nocomments +nostats @lan.local version.bind chaos txt
; (1 server found)
;; global options: +cmd
version.bind.		0	CH	TXT	"9.8.4-rpz2+rl005.12-P1"
version.bind.		0	CH	NS	version.bind.

Get BIND hostname. This does not work if “hostname none;” is specified in the named.conf.

$ dig @lan.local hostname.bind chaos txt
; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> +noquestion +nocomments +nostats @lan.local hostname.bind chaos txt
; (1 server found)
;; global options: +cmd
hostname.bind.		0	CH	TXT	"dns"
hostname.bind.		0	CH	NS	hostname.bind.


Check syslog:

# grep named /var/log/syslog | less

Check BIND log:

# tail /var/log/bind/named.log

Leave a Reply

Your email address will not be published. Required fields are marked *