Securing BIND DNS server

  Security, System

The DNS is a critical service often exploited by hackers for gathering information about the company attacked or for distributed deny of service (DDOS).

It’s possible to be protected from these attacks configuring opportunely the service. The actions to implement are very easy and it will be explained in this article.

The laboratory implemented is described in the following picture.

secure bind

As showed above, we imagine that the dns service is reachable from internet for resolving the names of the domain and queried from a inside network for internal resolution.

This architecture is enough  to synthesize the greater part of possible requirements.

Let’s start with the bind installation.

DNS Bind Installation

For improving the security the bind-chroot will be installed with selinux enabled.

Selinux is a layer security that must be always used. A lot of administrators prefer to disable it because they think that it difficult to manage: it’s not true and in internet it’s possible to find a lot of useful forum for resolving problems.

With chroot-bind, even if the bind server is exploited (this scenario is always possible, in the 2016 a lot of vulnerabilties have been discovered on it) the attacker has privilige limited (selinux) in a reduced file system (chroot) for exploiting the server.

Following the commands for installation chroot-bind and configure selinux (the server is a Centos 7.2):

[root@bind-server chroot]# sestatus|grep enabled
SELinux status: enabled
[root@bind-server chroot]# yum install bind-chroot
[root@bind-server chroot]# /usr/libexec/ /var/named/chroot on
[root@bind-server chroot]# systemctl enable named-chroot
[root@bind-server chroot]# systemctl start named-chroot

By default, named is not allowed by the SELinux policy to write, create or delete any files except in these directories:


From the moment that the zone will be signed using DNSSEC it’s necessary to create it in a place where named daemon has write permissions and data directory it’s ok.

Following is showed the context of data directory and the domain named_t of daemon bind that has write permission on it (default selinux configuration):

[root@bind-server name]# ps -afeZ |grep named
system_u:system_r:named_t:s0 named 15464 1 0 14:26 ? 00:00:00 /usr/sbin/named -u named -t /var/named/chroot
[root@bind-server named]# ls -ltrZ |grep data
drwxrwx—. named named system_u:object_r:named_cache_t:s0 data
[root@bind-server named]# sesearch –allow –source named_t –target named_cache_t –class file
Found 1 semantic av rules:
allow named_t named_cache_t : file { ioctl read write create getattr setattr lock append unlink link rename open } ;

No change on selinux was necessary: as I told it’s easy to work with it.

Note that the named daemon is running with named user privileges as chrooting a process running as root doesn’t enhance security because it’s possible to escape a chroot jail.

[root@bind-server ~]# ps -afe |grep named
named 19865 1 0 Jan03 ? 00:00:00 /usr/sbin/named -u named -t /var/named/chroot

Now the bind server is up&running: let’s start to configure it

DNS Bind Configuration

The configuration file of bind server is /etc/named.conf (this file is mounted with –bind in /var/named/chroot/etc/named.conf).

The default configuration has the dnssec resolution enabled. The configuration that enables it is:

root@bind-server etc]# more named.conf |grep dnssec
dnssec-enable yes;
dnssec-validation yes;

The dnssec is a protocol that adds a layer of security by answers digital signature into DNS data. Each DNS response can be verified for integrity. You can find a lot of information about it in

With DNSSEC the answers received contain digital signature for message integrity and authentication: the bind server is protected against cache poisoning or forged anwsers.

With the configuration above, the resolver of the bind verifies automatically the integrity of answers received. The flags ‘ad‘ received confirms that the validation process has been completed correctly (below the domain is signed, the same query against a domain not signed will not produce any data signed and any ad flags):

root@bind-serer chroot]# dig @ A +dnssec +multiline
; <<>> DiG 9.9.4-RedHat-9.9.4-38.el7_3 <<>> @ A +dnssec +multiline
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56353
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 5, ADDITIONAL: 13
; EDNS: version: 0, flags: do; udp: 4096
; IN A
;; ANSWER SECTION: 60 IN A 60 IN RRSIG A 5 3 60 (
20170201234103 20170102234103 13953
cTTd0sC+mowXck2l5FE2waS78UW7scHUv1/I99k= )

In this way the internal network is protected against attempts to forge the dns answers. Of course the domain queried must be signed.

This picture describe the scenario with the role of dnssec protection:

DNSSEC Protection

DNSSEC doesn’t protect completely the client because the SO and the browser are not dnssec aware. If a malicious user forges the dns aswers, the browsers doesn’t check the validity signature as resolvers does. If all the world (domain signed, SO, browser and resolvers) was dnssec aware, would be impossible main in the middle attacks in the dns service: unfortunately it’s not so.

If it’s possible, I suggest to sign the public zone: in this way you will protect other resolvers against attempts to forge your dns answers improving the security in internet.

Below I will explain how to do for signing the public view of the zone.

First: create the keys useful for signing the zone. The keys created are two: one is user for signing the records, the other is used for signing the public key released to resolvers

[root@bind-server named]# mkdir -p /var/named/chroot/var/named/keys/
[root@bind-server named]# chown -R named:named /var/named/chroot/var/named/keys
[root@bind-server named]# cd /var/named/chroot/var/named/keys/
[root@bind-server named]# dnssec-keygen -a RSASHA256 -b 1024
Generating key pair….++++++ ….++++++
[root@bind-server named]# dnssec-keygen -a RSASHA256 -b 2048 -f KSK
Generating key pair………+++ ..+++

Next step: For completing the signing zone is necessary to call the parent zone for completing the chain of trust (for this step see

Let’s start now to create a internal view for serving all the dns request from inside network. This network generally has the recursive functionality enabled and other custom configuration: the public server, for example, can be resolved with its private ip address instead of public.

The final bind configuration becomes:

[root@bind-server named]# vi /etc/named.conf
options {
listen-on port 53 {; };
listen-on-v6 port 53 { ::1; };
directory “/var/named”;
dump-file “/var/named/data/cache_dump.db”;
statistics-file “/var/named/data/named_stats.txt”;
memstatistics-file “/var/named/data/named_mem_stats.txt”;
dnssec-enable yes;
dnssec-validation auto;
/* Path to ISC DLV key */
bindkeys-file “/etc/named.iscdlv.key”;
managed-keys-directory “/var/named/dynamic”;
pid-file “/run/named/”;
session-keyfile “/run/named/session.key”;
acl inside-networks {;;
view “internal” {
match-clients { inside-networks; };
allow-query { any; };
recursion yes;
allow-transfer { none;};
zone “” IN {
type master;
file “data/”;
zone “.” IN {
type hint;
file “”;
include “/etc/named.rfc1912.zones”;
include “/etc/named.root.key”;
view “public” {
match-clients { any; };
allow-query { any; };
recursion no;
allow-transfer { none;};
zone “” IN {
type master;
file “data/”;
key-directory “keys/”;
inline-signing yes;
auto-dnssec maintain;
[root@bind-server named]#systemctl reload named

If everything is ok, the dig command from internet must return the records signed:

[root@docker-test-02 ~]# dig -t A +dnssec +multiline @
; <<>> DiG 9.9.4-RedHat-9.9.4-29.el7_2.3 <<>> -t A +dnssec +multiline @
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 51435
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 2, ADDITIONAL: 3
;; WARNING: recursion requested but not available
; EDNS: version: 0, flags: do; udp: 4096
; IN A
;; ANSWER SECTION: 3600 IN A 3600 IN RRSIG A 8 3 3600 (
20170202104548 20170103103948 60903
B8wDW35N4y8IuJlw3GLj/rqwCg+VF2AQ1WKwltA= )
;; AUTHORITY SECTION: 3600 IN NS 3600 IN RRSIG NS 8 2 3600 (
20170202104548 20170103103948 60903
ia00syW5J9ZetBPQcS/5WSsTjtvWDjmkurcDwDA= )
;; ADDITIONAL SECTION: 3600 IN A 3600 IN RRSIG A 8 3 3600 (
20170202104548 20170103103948 60903
SZjoklgEs53RrlO1qOp/TXauynkc07mFA4K1U7Q= )

Security final considerations:

  1. Two view have been created. In the public view the recursive is disabled. If you want to be a recursive dns for internet, you can be used for DDOS attack. In this case I suggest to limit the query served configuring the iptables of the server with a rule like that:”ACCEPT     udp  —  anywhere             anywhere             udp dpt:domain limit: up to x/min burst y mode src” .This rule limit the dns query to x/min with a burst of y (y> x).
  2. Allow transfer zone has been disabled in both view. If it is enabled, a malicious user can transfer the zone information from the server. This should contain the ip address of bind slave in case of a bind master-slave configuration. In this case the bind-slave can ask to master to download the zone.
  3. I configured dnssec-validation to auto as suggested by ISC :DNSSEC validation is enabled, and a default trust anchor (included as part of BIND) for the DNS root zone is used automatically. Read paragraph 3.3.1 (
  4. With the “auto-dnssec maintain” option enabled, BIND will periodically check to see if new keys are available, or old keys need to be retired, and automatically add or remove the appropriate DNSKEY records from the zone.
  5. Allow query is any for both the view because any client can query the dns service.
  6. Before putting live the service, don’t forget to run some penetration testing with some dns scanner like dnsmap or dnsenum. The results are good in this case:

root@kali:~# dnsmap
dnsmap 0.30 – DNS Network Mapper by pagvac (
[+] searching (sub)domains for using built-in wordlist
[+] using maximum random delay of 10 millisecond(s) between requests
IP address #1:
IP address #1:
[+] 2 (sub)domains and 2 IP address(es) found
[+] completion time: 171 second(s)
root@kali:~# dnsenum
—– —–
Host’s addresses:_______________
Name Servers:__________ 3600 IN A
Mail (MX) Servers:_______________
Trying Zone Transfers and getting Bind Versions:_____________________________________________
Trying Zone Transfer for on …
AXFR record query failed: connection failed


In this article I showed how to secure bind dns server using dnssec, selinux and a view configuration (public and internal).

Another suggestion is to always have system operation and bind upgraded to last version available: as I told on bind server this year a lot of vulnerabilties was found and the only way to protect is upgrade the software.

The last suggestion is to monitor the exploits about bind on exploit-db in order to verify if there is some exploits for the bind server and test it if possible:

Let me know for any question or suggestion.

Best Regards