PowerDNS Training May 2026

1 Introduction

  • what is your interest in DNS/PowerDNS?
  • what is your prior knowledge of DNS/PowerDNS?
  • what do you want to learn about DNS/PowerDNS?

2 New terminology used in DNS

  • The terms master and slave have been used to describe primary and secondary authoritative DNS servers in the past.
  • In this document, and in configuration examples, we are using the new terms primary (instead of master) and secondary (instead of slave) whenever possible.
  • PowerDNS made this switch in version 4.5.0
  • The old terminology will also be found in older books and standards documents (RFCs and Internet Drafts)
  • DNS terminology can be confusing and is sometimes overloaded. RFC 8499 DNS terminology ( https://tools.ietf.org/html/rfc8499 ) tries to collect and document the current usage of DNS terminology.

3 Intro - DNS 1x1

4 Operating a PowerDNS authoritative Server

4.1 Authoritative DNS server deployment strategies (hidden primary, DNSSEC signer, anycast)

4.1.1 Authoritative DNS Server location

  • Authoritative DNS server, such as the PowerDNS server, can be deployed in various different setups
  1. Classic DNS
    • In a classic case, one DNS server hosts the primary (master) zones and one or more other server host the secondary zones (slave zones)
      • The zone content is maintained on the machine hosting the primary zone
      • The secondary zones are synchronized via full zone transfer (AXFR) or incremental zone transfer (IXFR)
      • The server should be placed in different data-center and in different autonomous systems (AS)
      • There should be authoritative server near each customer population to make use of the DNS resolver round-trip-time measurement

      DNSarch-classic-dns.png

      • In classic DNS deployments, each authoritative server has one or more dedicated IP-addresses and a single domain name for the DNS service

      DNSarch-unicast.png

  2. Anycast deployments
    • To enhance resilience against certain attacks (like distributed denial of service attacks), authoritative server can be deployed with anycast addresses and routing
    • In an anycast deployment, all authoritative server have the same IP address (IPv6 or IPv4) and the same domain name and are located in different routing domains / autonomous systems (AS)
    • The routing protocol (BGP for Internet routing or OSPF for internal routing) is being used to direct the DNS query to an authoritative DNS server with optimal network distance to the client

      DNSarch-anycast.png

  3. Database zone storage
    • Some DNS server products (such as PowerDNS, BIND 9, Microsoft DNS) support zone storage in database systems (SQL or other, like NoSQL, LDAP/Active directory)
    • In such an setup, all authoritative DNS server are primaries (multi-master)
    • One option is to have all DNS server to connect to the same database (shared database setup)

      DNSarch-shared-db.png

    • Alternatively, multiple databases can be used. The DNS data is then either synchronized with database replication or with traditional DNS functions such as AXFR/IXFR zone-transfer

      DNSarch-replicated-db.png

4.1.2 Hidden Primaries

  • For security reasons, it sometimes not desirable to have the zone data write-able on a server that is exposed to the Internet
    • In such situations, a hidden primary setup can be useful
    • In an hidden primary setup, the server hosting the primary zone is located inside a protected network (often behind a firewall)
    • The public secondaries are exposed to the Internet, but as secondaries the zone data is read-only.
    • In a hidden primary setup, the delegation and in-zone NS-records do only list the publicly reachable secondaries
      • As an option, the domain name of the hidden primary can be listed in the SOA record MNAME field to support synamic updates to the zone

    DNSarch-hidden-primary.png

  • For DNSSEC signed zones, the hidden master could also act as a DNSSEC signer, adding DNSSEC data to the zones
    • The precious DNSSEC keys are not exposed to the Internet
    • Non-DNSSEC aware DNS management software can be augmented with DNSSEC capabilities using such a hidden signer (also known as a bump-in-the-wire signer.

    DNSarch-hidden-signer.png

4.2 Downloading, Compiling and Installing PowerDNS authoritative Server

  • There are several options to install a PowerDNS authoritative DNS server on a Linux/Unix operating system

4.2.1 Installing PowerDNS authoritative Server on Debian 11

  • In the hands-on lab sessions for this training, we will be installing the PowerDNS server from the Debain 13 repositories
apt-get install pdns-server
  • PowerDNS supports a range of different backend (SQL Database, BIND 9, LDAP, Lua, Pipe etc). To list the available PowerDNS backends (on Debian 13):
# apt search pdns-backend
Sorting... Done
Full Text Search... Done
pdns-backend-bind/stable,now 4.4.1-1 amd64 [installed,automatic]
  BIND backend for PowerDNS

pdns-backend-geoip/stable 4.4.1-1 amd64
  GeoIP backend for PowerDNS

pdns-backend-ldap/stable 4.4.1-1 amd64
  LDAP backend for PowerDNS

pdns-backend-lmdb/stable 4.4.1-1 amd64
  LMDB backend for PowerDNS

pdns-backend-lua2/stable 4.4.1-1 amd64
  Lua2 backend for PowerDNS

pdns-backend-mysql/stable 4.4.1-1 amd64
  MySQL backend for PowerDNS

pdns-backend-odbc/stable 4.4.1-1 amd64
  UnixODBC backend for PowerDNS

pdns-backend-pgsql/stable 4.4.1-1 amd64
  PostgreSQL backend for PowerDNS

pdns-backend-pipe/stable 4.4.1-1 amd64
  pipe/coprocess backend for PowerDNS

pdns-backend-remote/stable 4.4.1-1 amd64
  remote backend for PowerDNS

pdns-backend-sqlite3/stable 4.4.1-1 amd64
  sqlite 3 backend for PowerDNS

pdns-backend-tinydns/stable 4.4.1-1 amd64
  tinydns compatibility backend for PowerDNS
  • Select and install once or more of the available backends. In this example we're installing the MySQL/MariaDB backend:
% apt install pdns-backend-mysql
  • After installation, the PowerDNS server should be up and running with a default configuration. To check the status of the PowerDNS service, we use systemctl status pdns:
# systemctl status pdns.service
● pdns.service - PowerDNS Authoritative Server
     Loaded: loaded (/lib/systemd/system/pdns.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2021-10-29 06:38:25 UTC; 14s ago
       Docs: man:pdns_server(1)
	     man:pdns_control(1)
	     https://doc.powerdns.com
   Main PID: 22789 (pdns_server)
      Tasks: 8 (limit: 1132)
     Memory: 43.6M
	CPU: 139ms
     CGroup: /system.slice/pdns.service
	     └─22789 /usr/sbin/pdns_server --guardian=no --daemon=no --disable-syslog --log-timestamp=no --write-pid=no

Oct 29 06:38:25 pdns01 pdns_server[22789]: TCP server bound to [::]:53
Oct 29 06:38:25 pdns01 pdns_server[22789]: PowerDNS Authoritative Server 4.4.1 (C) 2001-2020 PowerDNS.COM BV
Oct 29 06:38:25 pdns01 pdns_server[22789]: Using 64-bits mode. Built using gcc 10.2.1 20210110.
Oct 29 06:38:25 pdns01 pdns_server[22789]: PowerDNS comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it according to the terms >
Oct 29 06:38:25 pdns01 pdns_server[22789]: Creating backend connection for TCP
Oct 29 06:38:25 pdns01 pdns_server[22789]: [bindbackend] Parsing 0 domain(s), will report when done
Oct 29 06:38:25 pdns01 pdns_server[22789]: [bindbackend] Done parsing domains, 0 rejected, 0 new, 0 removed
Oct 29 06:38:25 pdns01 systemd[1]: Started PowerDNS Authoritative Server.
Oct 29 06:38:25 pdns01 pdns_server[22789]: About to create 3 backend threads for UDP
Oct 29 06:38:25 pdns01 pdns_server[22789]: Done launching threads, ready to distribute questions
  • The default security settings of the PowerDNS service is already quite good, as can be seen with systemd-analyze:
% systemd-analyze security pdns
  • However some additional hardening steps are possible (optional):
    • MemoryDenyWriteExecute - enables a function in the memory management unit (and modern CPUs) that makes memory pages either write-able (data) or executable (program code), but never both. This prevents certain attacks, such as buffer overflow attacks
    • umask - Files created by the PowerDNS processes can only be read or written by the PowerDNS user or root, but not by any other user
    • MemoryMax - Restrict the memory consumption of the PowerDNS process to 2 GB. This is usually more than enough for an authoritative server even with large zone files and prevents system instability in case of a memory leak
    • TasksMax - restricts the number of threads (tasks) of the PowerDNS service to 20. This prevents DoS attacks through a security vulnerability that would allow and external attacker to start new threads. This setting should be monitored and adjusted to the real world scenario where PowerDNS is deloyed (number of CPU cores, network interfaces etc).
# Additional hardening for the PowerDNS systemd unit
MemoryDenyWriteExecute=true
UMask=077
MemoryMax=2G
TasksMax=20

4.2.2 Exercise

  • Login to your hands-on lab machine pdnsNNNa.dnslab.org
    • Account user
    • Password PowerDNS
    • use ssh or https from a web browser
  • Become root
  • Install the PowerDNS authoritative server from the Debian 13 package repository
  • Use systemctl edit --full pdns to add the additional hardening configuration shown above. Add the additional lines inside the [service] section
  • Restart the PowerDNS service, and check with systemctl status that the Task and Memory restrictions are in place

4.3 SQL Database-Backend (MySQL/MariaDB)

  • MySQL (or MariaDB) is a popular backend for PowerDNS server. To install MariaDB/MySQL on Debian 13, execute:
% apt install mariadb-server
  • Use systemctl status to verify that the database process is started
% systemctl status mysql
● mariadb.service - MariaDB 10.5.12 database server
     Loaded: loaded (/lib/systemd/system/mariadb.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2021-10-29 06:46:53 UTC; 23s ago
       Docs: man:mariadbd(8)
	     https://mariadb.com/kb/en/library/systemd/
    Process: 23536 ExecStartPre=/usr/bin/install -m 755 -o mysql -g root -d /var/run/mysqld (code=exited, status=0/SUCCESS)
    Process: 23537 ExecStartPre=/bin/sh -c systemctl unset-environment _WSREP_START_POSITION (code=exited, status=0/SUCCESS)
    Process: 23539 ExecStartPre=/bin/sh -c [ ! -e /usr/bin/galera_recovery ] && VAR= ||   VAR=`cd /usr/bin/..; /usr/bin/galera_recovery`; [ $? -eq 0 ]   && systemctl set-en>
    Process: 23598 ExecStartPost=/bin/sh -c systemctl unset-environment _WSREP_START_POSITION (code=exited, status=0/SUCCESS)
    Process: 23600 ExecStartPost=/etc/mysql/debian-start (code=exited, status=0/SUCCESS)
   Main PID: 23586 (mariadbd)
     Status: "Taking your SQL requests now..."
      Tasks: 12 (limit: 1132)
     Memory: 81.1M
	CPU: 1.092s
     CGroup: /system.slice/mariadb.service
	     └─23586 /usr/sbin/mariadbd

Oct 29 06:46:54 pdns01 /etc/mysql/debian-start[23605]: mysql
Oct 29 06:46:54 pdns01 /etc/mysql/debian-start[23605]: performance_schema
Oct 29 06:46:54 pdns01 /etc/mysql/debian-start[23605]: Phase 6/7: Checking and upgrading tables
Oct 29 06:46:54 pdns01 /etc/mysql/debian-start[23605]: Processing databases
Oct 29 06:46:54 pdns01 /etc/mysql/debian-start[23605]: information_schema
Oct 29 06:46:54 pdns01 /etc/mysql/debian-start[23605]: performance_schema
Oct 29 06:46:54 pdns01 /etc/mysql/debian-start[23605]: Phase 7/7: Running 'FLUSH PRIVILEGES'
Oct 29 06:46:54 pdns01 /etc/mysql/debian-start[23605]: OK
Oct 29 06:46:54 pdns01 /etc/mysql/debian-start[23811]: Checking for insecure root accounts.
Oct 29 06:46:55 pdns01 /etc/mysql/debian-start[23819]: Triggering myisam-recover for all MyISAM tables and aria-recover for all Aria tables
  • Login to the database command line tool to create the database for PowerDNS zones. Database-User is root, password is empty by default
% mysql -u root -p
Enter password:
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 44
Server version: 10.5.12-MariaDB-0+deb11u1 Debian 13

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>
  • Create the database
MariaDB [(none)]> CREATE DATABASE powerdns;
  • Create a database user for PowerDNS and set the password (don't use the insecure password shown here, use your own secure password):
MariaDB [(none)]> GRANT ALL ON powerdns.* TO 'pdnsuser'@'localhost' IDENTIFIED BY 'securepw';
MariaDB [(none)]> FLUSH PRIVILEGES;
MariaDB [(none)]> \q
CREATE TABLE domains (
  id                    INT AUTO_INCREMENT,
  name                  VARCHAR(255) NOT NULL,
  master                VARCHAR(128) DEFAULT NULL,
  last_check            INT DEFAULT NULL,
  type                  VARCHAR(8) NOT NULL,
  notified_serial       INT UNSIGNED DEFAULT NULL,
  account               VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL,
  options               VARCHAR(64000) DEFAULT NULL,
  catalog               VARCHAR(255) DEFAULT NULL,
  PRIMARY KEY (id)
) Engine=InnoDB CHARACTER SET 'latin1';

CREATE UNIQUE INDEX name_index ON domains(name);
CREATE INDEX catalog_idx ON domains(catalog);


CREATE TABLE records (
  id                    BIGINT AUTO_INCREMENT,
  domain_id             INT DEFAULT NULL,
  name                  VARCHAR(255) DEFAULT NULL,
  type                  VARCHAR(10) DEFAULT NULL,
  content               VARCHAR(64000) DEFAULT NULL,
  ttl                   INT DEFAULT NULL,
  prio                  INT DEFAULT NULL,
  disabled              TINYINT(1) DEFAULT 0,
  ordername             VARCHAR(255) BINARY DEFAULT NULL,
  auth                  TINYINT(1) DEFAULT 1,
  PRIMARY KEY (id)
) Engine=InnoDB CHARACTER SET 'latin1';

CREATE INDEX nametype_index ON records(name,type);
CREATE INDEX domain_id ON records(domain_id);
CREATE INDEX ordername ON records (ordername);


CREATE TABLE supermasters (
  ip                    VARCHAR(64) NOT NULL,
  nameserver            VARCHAR(255) NOT NULL,
  account               VARCHAR(40) CHARACTER SET 'utf8' NOT NULL,
  PRIMARY KEY (ip, nameserver)
) Engine=InnoDB CHARACTER SET 'latin1';


CREATE TABLE comments (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  name                  VARCHAR(255) NOT NULL,
  type                  VARCHAR(10) NOT NULL,
  modified_at           INT NOT NULL,
  account               VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL,
  comment               TEXT CHARACTER SET 'utf8' NOT NULL,
  PRIMARY KEY (id)
) Engine=InnoDB CHARACTER SET 'latin1';

CREATE INDEX comments_name_type_idx ON comments (name, type);
CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);


CREATE TABLE domainmetadata (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  kind                  VARCHAR(32),
  content               TEXT,
  PRIMARY KEY (id)
) Engine=InnoDB CHARACTER SET 'latin1';

CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);


CREATE TABLE cryptokeys (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  flags                 INT NOT NULL,
  active                BOOL,
  published             BOOL DEFAULT 1,
  content               TEXT,
  PRIMARY KEY(id)
) Engine=InnoDB CHARACTER SET 'latin1';

CREATE INDEX domainidindex ON cryptokeys(domain_id);


CREATE TABLE tsigkeys (
  id                    INT AUTO_INCREMENT,
  name                  VARCHAR(255),
  algorithm             VARCHAR(50),
  secret                VARCHAR(255),
  PRIMARY KEY (id)
) Engine=InnoDB CHARACTER SET 'latin1';

CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);

  • Apply the schema to the powerdns database to initialize the database
% mysql -u root -p powerdns < pdns47.sql

4.3.1 Exercise

  • Work to your hands-on lab machine pdnsNNNa.dnslab.org
  • Install the MariaDB database server from the Debian 13 package repository
  • Create and initialize a database for PowerDNS as shown above

4.4 PowerDNS Configuration Files

  • The PowerDNS configuration file is in /etc/powerdns/pdns.conf. The default configuration file can be overwhelming in the beginning, so we start with a clean file and build our configuration from there. We backup the original configuration files.
% mv /etc/powerdns/pdns.conf /etc/powerdns/pdns.conf.debian13
% mkdir /etc/powerdns/pdns.d.disabled
% mv /etc/powerdns/pdns.d/bind.conf /etc/powerdns/pdns.d.disabled/
% touch /etc/powerdns/pdns.conf
  • PowerDNS configuration can be stored either in a monolithic (all-on-one-file) or a split configuration file (smaller configuration files included into the main file). For a split configuration, the configuration snippets are stored in /etc/powerdns/pdns.d. Which configuration scheme to use is a matter of taste or sometimes demanded by a configuration management tool. This training lab sessions will use a monolithic configuration file.
  • Example on how to include configuration snippets from the main configuration file /etc/powerdns/pdns.conf:
#################################
# include-dir   Include *.conf files from this directory
#
# include-dir=
include-dir=/etc/powerdns/pdns.d
  • First we add the Database configuration for our MySQL/MariaDB instance in /etc/powerdns/pdns.conf
# MySQL / MariaDB Database access configuration
launch=gmysql
gmysql-socket=/run/mysqld/mysqld.sock
gmysql-dbname=powerdns
gmysql-user=pdnsuser
gmysql-password=securepw
  • Restart the PowerDNS server so that the new configuration becomes active
% systemctl restart pdns
  • Install DNS look-up utilities (Debian packet dnsutils) and test that the PowerDNS server listens on UDP port 53 and responds to DNS queries
% dig @localhost ns .

; <<>> DiG 9.16.22-Debian <<>> @localhost ns .
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 48594
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;.                              IN      NS

;; Query time: 3 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Fri Oct 29 07:36:59 UTC 2021
;; MSG SIZE  rcvd: 28
  • Here we get a DNS answer (good), it is of Return-Code REFUSED, as PowerDNS is not authoritative for the root zone

4.4.1 Exercise

  • Add the configuration for the MariaDB database to PowerDNS configuration
  • Check the configuration with pdns_server --config=check
  • If there are no syntax errors in the configuration file, restart the PowerDNS server
  • Test with dig that the PowerDNS server responds to DNS requests

4.5 Hosting a primary zone

  • There are multiple options on how to create a new primary zone on a PowerDNS server
    • One is converting a RFC standard zone file into SQL statements that are used to provisioning the zone data into the SQL database
    • Others are using a BIND 9 configuration file named.conf (for the BIND backend), pdnsutil, dynamic updates or graphical user interfaces
  • DNS zones are often stored in RFC 1035 "MASTER FILE FORMAT". This format is supported my almost all DNS server products

  • We need a zone-file for our new zone. The zone-name will be zoneNNN.dnslab.org. Our authoritative name-server is named pdnsNNNa.dnslab.org.
  • Use the zone template below (replace the NNN with your attendee number) to create a new zone-file with the filename zoneNNN.dnslab.org somewhere on the file system (proposal: /etc/powerdns/zones). Having a low TTL of 60 seconds is important in our lab environment. For production environments, the recommendation is 3600 seconds (1 hour) as a default TTL.
  • the period . at the end of domain names is very important in zone files. Don't omit it.
  • Change the IPv4 and IPv6 Address records to match the IP-addresses of your lab server. To display the IPv4 and IPv6 addresses of a Linux-Server
% hostname -I
  • The Zone Template:
$TTL 60
zoneNNN.dnslab.org.             IN SOA    pdnsNNNa.dnslab.org.  (
						hostmaster  1001
						1h 30m 41d 60s )
zoneNNN.dnslab.org.             IN NS     pdnsNNNa.dnslab.org.
zoneNNN.dnslab.org.             IN A      <ipv4-address-of-the-lab-server>
zoneNNN.dnslab.org.             IN AAAA   <ipv6-address-of-the-lab-server>
  • We use the PowerDNS tool zone2sql to convert the DNS zone from RFC1035 format into SQL statements for MariaDB/MySQL
% zone2sql --gmysql --transactions --zone-name=zoneNNN.dnslab.org --zone=zoneNNN.dnslab.org
BEGIN;
insert into domains (name,type) values ('zoneNNN.dnslab.org','NATIVE');
insert into records (domain_id, name, type,content,ttl,prio,disabled) select id ,'zoneNNN.dnslab.org', 'SOA', 'pdnsNNNa.dnslab.org hostmaster.zoneNNN.dnslab.org 1NNN 3600 1800 3542400 60', 60, 0, 0 from domains where name='zoneNNN.dnslab.org';
insert into records (domain_id, name, type,content,ttl,prio,disabled) select id ,'zoneNNN.dnslab.org', 'NS', 'pdnsNNNa.dnslab.org', 60, 0, 0 from domains where name='zoneNNN.dnslab.org';
insert into records (domain_id, name, type,content,ttl,prio,disabled) select id ,'zoneNNN.dnslab.org', 'A', '192.0.2.53', 60, 0, 0 from domains where name='zoneNNN.dnslab.org';
insert into records (domain_id, name, type,content,ttl,prio,disabled) select id ,'zoneNNN.dnslab.org', 'AAAA', '2001:db8:100::133d:1', 60, 0, 0 from domains where name='zoneNNN.dnslab.org';
1 domains were fully parsed, containing 4 records
COMMIT WORK;
  • We can pipe the output of zone2sql into the MySQL/MariaDB command line tool to create the zone content
% zone2sql --gmysql --transactions --zone-name=zoneNNN.dnslab.org --zone=zoneNNN.dnslab.org | mysql -u root -p powerdns
  • Our PowerDNS server will now answer to queries for this zone
# dig @localhost zoneNNN.dnslab.org soa +norec

; <<>> DiG 9.16.22-Debian <<>> @localhost zoneNNN.dnslab.org soa
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50489
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;zoneNNN.dnslab.org.            IN      SOA

;; ANSWER SECTION:
zoneNNN.dnslab.org.     60      IN      SOA     pdnsNNNa.dnslab.org. hostmaster.zoneNNN.dnslab.org. 1001 3600 1800 3542400 60

;; Query time: 3 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Fri Oct 29 07:59:28 UTC 2021
;; MSG SIZE  rcvd: 101

4.6 Querying the DNS with "dig"

  • dig is the standard tool to send DNS queries.
  • It replaces the older (and obsolete nslookup)
  • the output of dig resembles the structure of DNS packets on the wire

0302-DNS-Components-DNS-packet.png

  • The dig output explained

0301-dig-command.png

  • the DNS data is separated in sections

0302-dig-command.png

4.6.1 DNS Packet Header

0303-dig-command.png

  • opcode: query, notify, update, DSOsee IANA registry for DNS OpCodes
  • status/rcode:
    • NOERROR - the operation was successful
    • NXDOMAIN - the domain name requested does not exist (or is not delegated)
    • SERVFAIL - some remote DNS server failure or DNSSEC validation failure
    • FORMERR - the query was not correct DNS
    • REFUSED - this server has an access control list that forbids the answer to this client
    • NOTIMPL - a feature used/requested that this server does not implement
    • BADCOOKIE - Bad/missing Server Cookie

    see IANA registry for DNS RCODEs

  • queryid: 16bit value to sort DNS answers to DNS queries
  • flags: information on the query and the answer (see IANA registry for DNS Header Flags)
    • AA authoritative answer - answer is coming directly from an authoritative server
    • TC truncated - answer does not fit into the advertised UDP packet size, please re-query over TCP
    • RD recursion desired - this is a query from a client machine, please provide a full complete answer (no referral please)
    • RA recursion available - this answer comes from a DNS resolver that is willing to accept queries with RD flag set
  • DNSSEC flags: AD- and CD-Flag
    • AD authentic data - the DNS resolver sending this answer has performed a successful DNSSEC validation on the data. If we trust the resolver, we can trust the data
    • CD checking disabled - a client asking a DNSSEC validating DNS resolver to not perform DNSSEC validation but to pass all DNSSEC data unaltered (even if the data is invalid). Used for troubleshooting DNSSEC issues.
  • QUERY: number of query resource records (usually one)
  • ANSWER: count of DNS resource records in the answer. Can be more than one. Can be zero if no data is available for the query.
  • AUTHORITY: number of authority records in the answer. Can be a SOA-Record (for negative answers) or NS-Records for referrals or positive answers. Many modern DNS server only fill the authority section if required by the protocol to keep answer packets small
  • ADDITIONAL: additional resource records that not have been requested but might help with the name resolution, and the EDNS (Extended DNS) OPT-Record (see RFC 6891 Extension Mechanisms for DNS (EDNS(0))

4.6.2 Extended DNS OPT Section

0304-dig-command.png

  • EDNS Version 0 is the current version
    • new Versions are being discussed in the IETF
  • additional EDNS flags. DO - DNSSEC OK, this DNS client supports DNSSEC records
  • maximum UDP answer packet size in byte as negotiated between dig and the DNS server/resolver. Current default is 4096, must be between 512 and 4096. The default changed to 1232 on DNS flag day 2020

4.6.3 Answer Section

0305-dig-command.png

  • The answer section contains zero (if there is no data available), one or more DNS resource records that match the query

4.6.4 Authority Section

0306-dig-command.png

  • if present, the authority section contains the authoritative name server that hosts the content delivered in the answer. For negative (NXDOMAIN/NOERROR-NODATA) answers, the authority section contains the SOA record of the zone that is authoritative for the negative answer.

4.6.5 Additional Section

0307-dig-command.png

  • if present, the additional section contains additional DNS records that have not been explicitly requested, but might help in the name resolution process. Because the additional section can be misused in attacks, modern DNS server software minimizes the additional section data.
  • If EDNS data is available, it is also in the additional section, but dig displays this data in the OPT pseudo-section

4.6.6 Footer

0308-dig-command.png

  • the footer contains the size (in bytes) of the answer packet, the DNS server that has send the answer, the time it took to receive the answer and the time and date of the DNS communication

4.6.7 sending the query to a specific DNS server/resolver

0309-dig-command.png

  • usually dig sends the query to the DNS resolver configured in the operating system (file /etc/resolv.conf on Unix/Linux)
  • with the @ syntax the query can be sent to other DNS servers (resolver or authoritative server)

4.6.8 sending non-recursive queries

0310-dig-command.png

  • command line switches can alter the query sent by dig.
    • +multi formats the output in human readable form (wrapped for 80 column terminal)
    • +norec sends a query without RD flag (non-recursive or iterative query)

4.6.9 asking for DNSSEC data

0311-dig-command.png

  • the switch +dnssec requests DNSSEC data from the upstream server
  • the switch +cd sends the CD (checking disabled) flag to disable upstream DNSSEC validation (if the target of the query is a DNS resolver)

4.6.10 Zone-Transfer

0312-dig-command.png

  • dig can initiate a zone transfer from an authoritative server that contains the zone database (primary or secondary server)
  • the data is printed in the Master Zone Format and can be used to start a new zone database file
  • Example: list top level domains with DNSSEC delegation:
    $ dig @f.root-servers.net AXFR . +noidnout | \
      grep DS | \
      grep -v RRSIG | \
      cut -d "." -f 1 | \
      uniq
    

4.7 PowerDNS Management Tools

  • The PowerDNS Server comes with a couple of command line tools that help operating and maintaining the PowerDNS service
  • The tools pdns_control and pdnsutil overlap sometimes in their functionality. pdnsutil was originally a tool to manage DNSSEC data in PowerDNS installations, and later morphed into a general management tool.

4.7.1 pdns_server

  • pdns_server is the actual PowerDNS server binary. Besides starting the PowerDNS service, this command can be used to check the configuration file
% pdns_server --config=check
Apr 28 08:31:46 Loading '/usr/lib/x86_64-linux-gnu/pdns/libgmysqlbackend.so'
  • The parameter --version shows some help information, but also the compile time configuration of the PowerDNS server binary. This is helpful to recompile a newer PowerDNS version with the same configuration, or to check for the existence of a compile-time feature
% pdns_server --version
Apr 28 08:32:29 PowerDNS Authoritative Server 4.9.7 (C) PowerDNS.COM BV
Apr 28 08:32:29 Using 64-bits mode. Built using gcc 14.2.0.
Apr 28 08:32:29 PowerDNS comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it according to the terms of the GPL version 2.
Apr 28 08:32:29 Features: libcrypto-ecdsa libcrypto-ed25519 libcrypto-ed448 libcrypto-eddsa libgeoip libmaxminddb lua lua-records PKCS#11 protobuf sodium curl scrypt 
Apr 28 08:32:29 Built-in modules: 
Apr 28 08:32:29 Loading '/usr/lib/x86_64-linux-gnu/pdns/libbindbackend.so'
Apr 28 08:32:29 Loading '/usr/lib/x86_64-linux-gnu/pdns/libgmysqlbackend.so'
Apr 28 08:32:29 Loaded modules: bind gmysql
Apr 28 08:32:29 Configured with: " '--build=x86_64-linux-gnu'
                   '--prefix=/usr'
		   '--includedir=${prefix}/include'
		   '--mandir=${prefix}/share/man'
		   '--infodir=${prefix}/share/info'
		   '--sysconfdir=/etc'
		   '--localstatedir=/var'
		   '--disable-option-checking'
		   '--libdir=${prefix}/lib/x86_64-linux-gnu'
		   '--runstatedir=/run'
		   '--disable-maintainer-mode'
		   '--disable-dependency-tracking'
		   '--sysconfdir=/etc/powerdns'
		   '--enable-systemd'
		   '--with-systemd=/usr/lib/systemd/system'
		   '--with-dynmodules=bind ldap lmdb lua2 pipe gmysql godbc gpgsql gsqlite3 geoip remote tinydns'
		   '--with-modules='
		   '--enable-ixfrdist'
		   '--enable-tools'
		   '--with-protobuf'
		   '--enable-unit-tests'
		   '--enable-lua-records'
		   '--enable-experimental-pkcs11'
		   '--enable-reproducible'
		   '--disable-silent-rules'
		   '--with-libcrypto=/usr'
		   'build_alias=x86_64-linux-gnu'
		   'CFLAGS=-g -O2 -Werror=implicit-function-declaration -ffile-prefix-map=/build/reproducible-path/pdns-4.9.7=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection' 'LDFLAGS=-Wl,-z,relro -Wl,-z,now' 'CPPFLAGS=-Wdate-time -D_FORTIFY_SOURCE=2' 'CXXFLAGS=-g -O2 -ffile-prefix-map=/build/reproducible-path/pdns-4.9.7=. -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -DPACKAGEVERSION='\''"4.9.7-1.Debian"'\'''"

4.7.2 Tool: pdns_control

  • pdns_control is the older of the two PowerDNS command line utilities. It contains many functions to maintain the running PowerDNS server
  1. Basic operation
    • Is the server alive and listening?
    % pdns_control rping
    PONG
    
    • Show the uptime of the PowerDNS process
    % pdns_control uptime
    47 minutes
    
    • Show the version of the running PowerDNS server
    % pdns_control version
    4.9.7
    
  2. Statistics
    • Dump out all available statistics to the standard output
    % pdns_control list
    backend-queries=8,corrupt-packets=0,deferred-cache-inserts=0,deferred-cache-lookup=0,deferred-packetcache-inserts=0,deferred-packetcache-lookup=0,dnsupdate-answers=0,dnsupdate-changes=0,dnsupdate-queries=0,dnsupdate-refused=0,incoming-notifications=0,noerror-packets=0,nxdomain-packets=0,overload-drops=0,packetcache-hit=0,packetcache-miss=6,packetcache-size=3,query-cache-hit=0,query-cache-miss=8,query-cache-size=4,rd-queries=7,recursing-answers=0,recursing-questions=0,recursion-unanswered=0,security-status=0,servfail-packets=0,signatures=0,tcp-answers=0,tcp-answers-bytes=0,tcp-queries=0,tcp4-answers=0,tcp4-answers-bytes=0,tcp4-queries=0,tcp6-answers=0,tcp6-answers-bytes=0,tcp6-queries=0,timedout-packets=0,udp-answers=7,udp-answers-bytes=338,udp-do-queries=2,udp-queries=7,udp4-answers=7,udp4-answers-bytes=338,udp4-queries=7,udp6-answers=0,udp6-answers-bytes=0,udp6-queries=0,unauth-packets=3,cpu-iowait=1296,cpu-steal=56,fd-usage=21,key-cache-size=0,latency=15,meta-cache-size=1,open-tcp-connections=0,qsize-q=0,real-memory-usage=104902656,ring-logmessages-capacity=10000,ring-logmessages-size=0,ring-noerror-queries-capacity=10000,ring-noerror-queries-size=0,ring-nxdomain-queries-capacity=10000,ring-nxdomain-queries-size=0,ring-queries-capacity=10000,ring-queries-size=0,ring-remotes-capacity=10000,ring-remotes-corrupt-capacity=10000,ring-remotes-corrupt-size=0,ring-remotes-size=0,ring-remotes-unauth-capacity=10000,ring-remotes-unauth-size=0,ring-servfail-queries-capacity=10000,ring-servfail-queries-size=0,ring-unauth-queries-capacity=10000,ring-unauth-queries-size=0,signature-cache-size=0,sys-msec=253,udp-in-errors=0,udp-noport-errors=494,udp-recvbuf-errors=0,udp-sndbuf-errors=0,uptime=1819,user-msec=119,xfr-queue=0,
    
    • The statistics output can be piped into a monitoring tool, or it can be processed on a shell pipe
      • Here we're changing the formatting to display the statistics one line per metric
    % pdns_control list | sed s/,/\\n/g
    
    • Show a single statistics value (name of metric is taken from the pdns_control list output)
    % pdns_control show backend-queries
    
    • Show the statistics on DNS query types (QTYPES)
    % pdns_control qtypes
    NS      1
    SOA     1
    TXT     3
    ANY     2
    
    • Display histogram of response sizes. For optimal performance, the majority (> 99%) if responses should be below 1232 bytes. If larger responses are generated, the zone content should be optimized (large resource record reviewed etc) to prevent TCP traffic
    # pdns_control respsizes
    20      5
    40      0
    60      1
    80      0
    100     1
    150     0
    200     0
    400     0
    600     0
    800     0
    [...]
    

4.7.3 Tool "pdnsutil"

  • pdnsutil is the newer command line management tools. It contains functions to work with DNSSEC and TSIG security protocols (which will be covered on day 3 of this training).
    • It also contains functions to manage zones and zone content
  1. Zone management
    • List all available zones
    % pdnsutil list-all-zones
    zone001.dnslab.org
    
    • Dump the zone content in RFC1035 format
    # pdnsutil list-zone zone001.dnslab.org
    $ORIGIN .
    test.zone001.dnslab.org 60      IN      TXT     "Hello PowerDNS"
    zone001.dnslab.org      60      IN      A       138.68.87.93
    zone001.dnslab.org      60      IN      AAAA    2a03:b0c0:3:d0::133d:1
    zone001.dnslab.org      60      IN      NS      ns001a.dnslab.org.
    zone001.dnslab.org      60      IN      SOA     ns001a.dnslab.org hostmaster.zone001.dnslab.org 1001 3600 1800 3542400 60
    
    • Show the status of a zone (including DNSSEC status)
    % pdnsutil show-zone zone001.dnslab.org
    This is a Native zone
    Zone is not actively secured
    Metadata items: None
    No keys for zone 'zone001.dnslab.org'.
    
    • Increment the SOA serial of a zone, triggering a zone transfer to all secondaries
    % pdnsutil increase-serial zone001.dnslab.org
    SOA serial for zone zone001.dnslab.org set to 1002
    
    • Create a new, empty zone. The new zone will have a bogus SOA records that needs to be changed
    % pdnsutil create-zone pdns001.dnslab.org
    Creating empty zone 'pdns001.dnslab.org'
    % pdnsutil list-zone pdns001.dnslab.org
    $ORIGIN .
    pdns001.dnslab.org      3600    IN      SOA     a.misconfigured.dns.server.invalid hostmaster.pdns001.dnslab.org 0 10800 3600 604800 3600
    
    • The command clear-zone will remove all DNS resource records from the zone (including NS and SOA), but will keep the zone in the configuration (and database)
    % pdnsutil clear-zone pdns001.dnslab.org
    % pdnsutil list-zone pdns001.dnslab.org
    $ORIGIN .
    
    • The command delete-zone will remove a zone from the configuration and the database
    % pdnsutil delete-zone pdns001.dnslab.org
    % pdnsutil list-zone pdns001.dnslab.org
    Domain 'pdns001.dnslab.org' not found!
    
  2. Adding / Removing zone content
    • The tool pdnsutil can be used to add DNS resource records to existing DNS zones. The RDATA (Data part of the record) must be in double quotes. As the shell normally removes the double quote after parsing, the double quotes " need to be escaped, for example with single quotes '. The domain name of the new record cannot be fully qualified, it should not contain the name of the zone! Here we create a TXT record with the label test in the zone zoneNNN.dnslab.org:
    % pdnsutil add-record zone001.dnslab.org test TXT 60 '"Hello PowerDNS"'
    New rrset:
    test.zone001.dnslab.org. 60 IN TXT "Hello PowerDNS"
    
    • The new record should be public immediately
    % dig @localhost test.zone001.dnslab.org txt
    
    ; <<>> DiG 9.16.22-Debian <<>> @localhost test.zone001.dnslab.org txt
    ; (1 server found)
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35999
    ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    ;; WARNING: recursion requested but not available
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 1232
    ;; QUESTION SECTION:
    ;test.zone001.dnslab.org.       IN      TXT
    
    ;; ANSWER SECTION:
    test.zone001.dnslab.org. 60     IN      TXT     "Hello PowerDNS"
    
    ;; Query time: 3 msec
    ;; SERVER: 127.0.0.1#53(127.0.0.1)
    ;; WHEN: Fri Oct 29 08:32:24 UTC 2021
    ;; MSG SIZE  rcvd: 79
    
    • Deleting a resource record set. This will remove all records for the given domain name and record type:
    % pdnsutil delete-rrset zone001.dnslab.org test txt
    
    • Changing a resource record set
    # pdnsutil replace-rrset zone001.dnslab.org test TXT 60    '"Hello PowerDNS, how are you?"'
    Current records for test.zone001.dnslab.org IN TXT will be replaced
    New rrset:
    test.zone001.dnslab.org. 60 IN TXT "Hello PowerDNS, how are you?"
    
    • Editing a zone with the text editor stored in the EDITOR environment variable, or the defaul editor of the system. After editing, the tool displays a diff of all the changes and checks if the SOA serial has been incremented. If the SOA serial is still the same, it offers to increment it.
    % export EDITOR=emacs
    % pdnsutil edit-zone zone001.dnslab.org
    Checked 5 records of 'zone001.dnslab.org', 0 errors, 0 warnings.
    Detected the following changes:
    -test.zone001.dnslab.org 60 IN TXT "Hello PowerDNS"
    +test.zone001.dnslab.org 60 IN TXT "Hello PowerDNS, how are you?"
    
    You have not updated the SOA record! Would you like to increase-serial?
    (y)es - increase serial, (n)o - leave SOA record as is, (e)dit your changes, (q)uit:
    y
    (a)pply these changes, (e)dit again, (r)etry with original zone, (q)uit: a
    Adding empty non-terminals for non-DNSSEC zone
    
  3. Checking Zones
    • Check all zones for errors
    % pdnsutil check-all-zones
    Checked 4 records of 'zone001.dnslab.org', 0 errors, 0 warnings.
    Checked 1 zones, 0 had errors.
    
    • Check a single zone
    % pdnsutil check-zone zone001.dnslab.org
    Checked 4 records of 'zone001.dnslab.org', 0 errors, 0 warnings.
    

4.8 Generating and Reading PowerDNS Log Files

4.8.1 Systemd Journal

  • In the default configuration PowerDNS will write log information to standard-out (stdout), which will be read by systemd and send to the systemd journal. This is the command that is executed by systemd to start the PowerDNS process:
/usr/sbin/pdns_server --guardian=no --daemon=no --disable-syslog --log-timestamp=no --write-pid=no
  • The PowerDNS unit name is pdns. The command tool journalctl can be used to show and filter the PowerDNS log content. Here the log is shown in follow mode where journalctl will block and display new log messages as they arrive:
# journalctl -fu pdns
-- Journal begins at Fri 2021-10-29 06:10:29 UTC. --
Oct 29 07:34:23 pdns01 pdns_server[26503]: TCP server bound to 0.0.0.0:53
Oct 29 07:34:23 pdns01 pdns_server[26503]: TCP server bound to [::]:53
Oct 29 07:34:23 pdns01 pdns_server[26503]: PowerDNS Authoritative Server 4.4.1 (C) 2001-2020 PowerDNS.COM BV
Oct 29 07:34:23 pdns01 pdns_server[26503]: Using 64-bits mode. Built using gcc 10.2.1 20210110.
Oct 29 07:34:23 pdns01 pdns_server[26503]: PowerDNS comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it according to the terms of the GPL version 2.
Oct 29 07:34:23 pdns01 pdns_server[26503]: Not validating response for security status update, this is a non-release version
Oct 29 07:34:23 pdns01 pdns_server[26503]: Creating backend connection for TCP
Oct 29 07:34:23 pdns01 systemd[1]: Started PowerDNS Authoritative Server.
Oct 29 07:34:23 pdns01 pdns_server[26503]: About to create 3 backend threads for UDP
Oct 29 07:34:24 pdns01 pdns_server[26503]: Done launching threads, ready to distribute questions
Oct 29 08:04:23 pdns01 pdns_server[26503]: Not validating response for security status update, this is a non-release version
Oct 29 08:11:28 pdns01 pdns_server[26503]: Cache clear request for 'zone001.dnslab.org' received from operator
Oct 29 08:11:37 pdns01 pdns_server[26503]: Cache clear request received from operator
Oct 29 08:13:11 pdns01 pdns_server[26503]: Rediscovery was requested
Oct 29 08:29:42 pdns01 pdns_server[26503]: Cache clear request received from operator
Oct 29 08:30:05 pdns01 pdns_server[26503]: AXFR-out zone 'zone001.dnslab.org', client '127.0.0.1:48973', transfer initiated
Oct 29 08:34:23 pdns01 pdns_server[26503]: Not validating response for security status update, this is a non-release version
  • You might see the message below in the log and might be worried. The release versions of PowerDNS as distributed by PowerDNS B.V. will phone home to check for new security vulnerabilities. This does not work on non-release version, such as the version distributed in Debian 13.
    Not validating response for security status update, this is a non-release version
    
  • This function can be disabled by setting the security-poll-suffix to an empty string in the PowerDNS configuration:

Zone name from which to query security update notifications. Setting this to an empty string disables secpoll.

4.8.2 DNS/SQL Query-Logging

  • PowerDNS can log every incoming DNS query. This DNS query-logging is CPU intensive and can slow down the DNS server operation. It is recommended to only enable query-logging in a debugging situation for a limited time and under direct control of the administrator. Configuration in pdns.conf
# Query Logging
log-dns-queries=yes
loglevel=6
  • Example DNS query-log output
Oct 30 02:01:24 pdns01 pdns_server[28629]: Remote 127.0.0.1 wants 'zone001.dnslab.org|SOA', do = 0, bufsize = 1232 (4096): packetcache MISS
Oct 30 02:04:44 pdns01 pdns_server[28629]: Remote 127.0.0.1 wants 'zone001.dnslab.org|SOA', do = 0, bufsize = 1232 (4096): packetcache MISS
Oct 30 02:04:55 pdns01 pdns_server[28629]: Remote 127.0.0.1 wants 'zone001.dnslab.org|A', do = 0, bufsize = 1232 (4096): packetcache MISS
Oct 30 02:05:08 pdns01 pdns_server[28629]: Remote 127.0.0.1 wants 'zone001.dnslab.org|A', do = 0, bufsize = 1232 (4096): packetcache HIT
Oct 30 02:05:37 pdns01 pdns_server[28629]: Remote 127.0.0.1 wants 'zone001.dnslab.org|AAAA', do = 1, bufsize = 1232 (4096): packetcache MISS
  • Log more DNS details. In the PowerDNS configuration file
log-dns-details=yes

4.8.3 Backend query logging

  • In addition to DNS queries, PowerDNS can also log the database or backend queries. In the PowerDNS configuration file add
query-logging=yes
  • As SQL query-logging is also CPU intensive and can hurt the DNS servers performance, the SQL query-logging function can be controlled at run-time from pdns_control
% pdns_control set query-logging yes
done
  • Example of SQL query-logging output
Oct 30 02:29:50 pdns01 pdns_server[28849]: Remote 127.0.0.1 wants 'zone001.dnslab.org|AAAA', do = 1, bufsize = 1232 (4096): packetcache MISS
Oct 30 02:29:50 pdns01 pdns_server[28849]: Query 140584614378640: SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and type=? and name=?
Oct 30 02:29:50 pdns01 pdns_server[28849]: Query 140584614378640: 709 usec to execute
Oct 30 02:29:50 pdns01 pdns_server[28849]: Query 140584614378640: 780 total usec to last row
Oct 30 02:29:50 pdns01 pdns_server[28849]: Query 140584614420096: select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=?
Oct 30 02:29:50 pdns01 pdns_server[28849]: Query 140584614420096: 1108 usec to execute
Oct 30 02:29:50 pdns01 pdns_server[28849]: Query 140584614420096: 1141 total usec to last row
Oct 30 02:29:50 pdns01 pdns_server[28849]: Query 140584614379408: SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and name=? and domain_id=?
Oct 30 02:29:50 pdns01 pdns_server[28849]: Query 140584614379408: 1108 usec to execute
Oct 30 02:29:50 pdns01 pdns_server[28849]: Query 140584614379408: 1181 total usec to last row
  1. Exercise

    • Work on the VM machine pdnsNNNa.dnslab.org
    • Enable DNS and SQL query logging
    • Send some DNS queries to the PowerDNS server with dig

  2. Solution
    • Entries in the PowerDNS configuration file
    ## Backend SQL logging
    query-logging=yes
    
    ## DNS query logging
    log-dns-queries=yes
    loglevel=6
    log-dns-details=yes
    

4.9 Secondary zones

  • PowerDNS can be operated in multi-primary mode where all instances are primary server where the replication happens on the database level
  • Optional PowerDNS can also recieve secondary zone content via RFC standard DNS zone transfer (TCP)
    • To transfer a zone from a non-PowerDNS server
  • PowerDNS secondary mode must be enabled on a global level in the PowerDNS configuration file
# Secondary operation
secondary=on
  • A secondary (slave) zone can be created with pdnsutil:
% pdnsutil create-secondary-zone <zonename> <ip-address-of-primary>
Creating secondary zone 'zone001.dnslab.org', with master(s) '138.68.87.93'
  • Once created, the PowerDNS server will transfer the zone via DNS zone transfer from the primary and will store the content in the database. The secondary server is now authoritative for the zone
% dig @localhost zone001.dnslab.org soa +norec
; <<>> DiG 9.16.22-Debian <<>> @localhost zone001.dnslab.org soa +norec
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26321
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
[...]
  • On the primary server we should see the incoming zone transfer request from the secondary server
Oct 30 03:15:50 pdns01 pdns_server[29144]: Remote 165.22.233.102 wants 'zone001.dnslab.org|SOA', do = 0, bufsize = 512: packetcache MISS
Oct 30 03:15:50 pdns01 pdns_server[29144]: AXFR-out zone 'zone001.dnslab.org', client '165.22.233.102:44233', transfer initiated
Oct 30 03:15:50 pdns01 pdns_server[29144]: AXFR-out zone 'zone001.dnslab.org', client '165.22.233.102:44233', allowed: client IP is in allow-axfr-ips
Oct 30 03:15:50 pdns01 pdns_server[29144]: gmysql Connection successful. Connected to database 'powerdns' on '/run/mysqld/mysqld.sock'.
Oct 30 03:15:50 pdns01 pdns_server[29144]: AXFR-out zone 'zone001.dnslab.org', client '165.22.233.102:44233', AXFR finished
  • The server hosting the secondary zone will check for new zone content on the primary server based on the refresh timer of the zone. As this can create a notable delay in zone content propagation, PowerDNS also support sending DNS NOTIFY messages from the primary server towards all secondary servers whenever the zone content has been changed

  • For NOTIFY messages to be send on changes, the primary server must be operated in primary mode (default is native mode where no NOTIFY messages are send)
# Operate in primary mode
primary=yes
  • Also, the primary zone must be set into primary state
% pdnsutil set-kind <zone-name> primary
  • NOTIFY messages will be send out 60 seconds after a change. To trigger NOTIFY messages manually, use pdns_control:
% pdns_control notify <zone-name>
  • Example Log Output on primary
Oct 30 03:36:12 pdns01 pdns_server[29637]: Notification request to host 165.22.233.102 for domain 'zone001.dnslab.org' received from operator
Oct 30 03:36:14 pdns01 pdns_server[29637]: Remote 165.22.233.102 wants 'zone001.dnslab.org|SOA', do = 0, bufsize = 512: packetcache MISS
Oct 30 03:36:14 pdns01 pdns_server[29637]: AXFR-out zone 'zone001.dnslab.org', client '165.22.233.102:45783', transfer initiated
Oct 30 03:36:14 pdns01 pdns_server[29637]: AXFR-out zone 'zone001.dnslab.org', client '165.22.233.102:45783', allowed: client IP is in allow-axfr-ips
Oct 30 03:36:14 pdns01 pdns_server[29637]: gmysql Connection successful. Connected to database 'powerdns' on '/run/mysqld/mysqld.sock'.
Oct 30 03:36:14 pdns01 pdns_server[29637]: AXFR-out zone 'zone001.dnslab.org', client '165.22.233.102:45783', AXFR finished
Oct 30 03:36:14 pdns01 pdns_server[29637]: Removed from notification list: 'zone001.dnslab.org' to 165.22.233.102:53 (was acknowledged)
  • Incremental Zone-Transfer (IXFR) can speed up zone transfer for large zones, as only the changes are transmitted. PowerDNS does not serve IXFR, but other DNS server products do (BIND 9, NSD, MS Windows DNS).
    • Use IXFR when PowerDNS is hosting a secondary zone where the primary zone is on a DNS server that supports outgoing IXFR.
% pdnsutil set-meta example.com IXFR 1
Set 'example.com' meta IXFR = 1
  • Log-output on a PowerDNS server hosing a primary zone and receiving a IXFR zone-transfer request
Oct 30 03:53:17 pdns01 pdns_server[29637]: Notification request for domain 'zone001.dnslab.org' received from operator
Oct 30 03:53:17 pdns01 pdns_server[29637]: Queued notification of domain 'zone001.dnslab.org' to 165.22.233.102:53
Oct 30 03:53:18 pdns01 pdns_server[29637]: Remote 165.22.233.102 wants 'zone001.dnslab.org|SOA', do = 0, bufsize = 512: packetcache MISS
Oct 30 03:53:18 pdns01 pdns_server[29637]: Removed from notification list: 'zone001.dnslab.org' to 165.22.233.102:53 (was acknowledged)
Oct 30 03:53:18 pdns01 pdns_server[29637]: IXFR-out zone 'zone001.dnslab.org', client '165.22.233.102:37241', transfer initiated with serial 1005
Oct 30 03:53:18 pdns01 pdns_server[29637]: IXFR-out zone 'zone001.dnslab.org', client '165.22.233.102:37241', allowed: client IP is in allow-axfr-ips
Oct 30 03:53:18 pdns01 pdns_server[29637]: IXFR-out zone 'zone001.dnslab.org', client '165.22.233.102:37241', IXFR fallback to AXFR
Oct 30 03:53:18 pdns01 pdns_server[29637]: AXFR-out zone 'zone001.dnslab.org', client '165.22.233.102:37241', transfer initiated
Oct 30 03:53:18 pdns01 pdns_server[29637]: AXFR-out zone 'zone001.dnslab.org', client '165.22.233.102:37241', allowed: client IP is in allow-axfr-ips
Oct 30 03:53:18 pdns01 pdns_server[29637]: gmysql Connection successful. Connected to database 'powerdns' on '/run/mysqld/mysqld.sock'.
Oct 30 03:53:18 pdns01 pdns_server[29637]: AXFR-out zone 'zone001.dnslab.org', client '165.22.233.102:37241', AXFR finished
  • Log-output on the secondary server
Oct 30 03:53:23 pdns02 pdns_server[17960]: AXFR-in zone: 'zone001.dnslab.org', primary: '138.68.87.93', zone committed with serial 1006
  1. Exercise

    • Work on the VM machine pdnsNNNb.dnslab.org (this is the 2nd server!)
    • Install PowerDNS and MariaDB on the secondary machine, using the instructions from above
    • Add the IP-Address(es) (IPv6 and IPv4) of the secondary server to the zone transfer access control on the primary PowerDNS server. Change the IP addresses in the example below to match the IP addresses of the secondary server
    allow-axfr-ips=2001:db8::53,192.0.2.53
    
    • Configure the primary server to be in primary mode, configure the zone zoneNNN.dnslab.org to be in orimary mode
    • On the secondary server, check that the primary is providing a regular zone transfer (AXFR)
    % dig @pdnsNNNa.dnslab.org zone001.dnslab.org axfr
    
    • Create the secondary zone on the secondary server
    • Use the edit-zone function of pdnsutil on the primary server to add the required 2nd NS record for the new secondary machine
    % export EDITOR=emacs
    % pdnsutil edit-zone zone001.dnslab.org
    Checked 5 records of 'zone001.dnslab.org', 0 errors, 0 warnings.
    Detected the following changes:
    -test.zone001.dnslab.org 60 IN TXT "Hello PowerDNS"
    +test.zone001.dnslab.org 60 IN TXT "Hello PowerDNS, how are you?"
    
    You have not updated the SOA record! Would you like to increase-serial?
    (y)es - increase serial, (n)o - leave SOA record as is, (e)dit your changes, (q)uit:
    y
    (a)pply these changes, (e)dit again, (r)etry with original zone, (q)uit: a
    Adding empty non-terminals for non-DNSSEC zone
    
    • This is the NS record
    zoneNNN.dnslab.org      60      IN      NS      pdnsNNNb.dnslab.org
    
    • Check that NOTIFY messages are send and received and that the zone content propagates after the change. Both PowerDNS server should host the same zone (same SOA serial number)

  2. Solution
    • PowerDNS configuration file (secondary)
    # MySQL / MariaDB Database access configuration
    launch=gmysql
    gmysql-socket=/run/mysqld/mysqld.sock
    gmysql-dbname=powerdns
    gmysql-user=pdnsuser
    gmysql-password=securepw
    
    # Server for secondary zones
    secondary=on
    
    • PowerDNS configuration file (primary)
    [...]
    primary=yes
    allow-axfr-ips=142.93.145.28, 2604:a880:cad:d0::d8c:4001
    
    • Mark zone as primary zone on the primary server
    [primary]% pdnsutil set-kind zoneNNN.dnslab.org  primary
    
    • Create the secondary zone on the secondary server
    [secondary]% pdnsutil create-secondary-zone zoneNNN.dnslab.org 2a03:b0c0:3:d0::138d:3001
    
    • On the primary-server, add the 2nd NS record to the zone
    [primary]% pdnsutil edit-zone zoneNNN.dnslab.org
    
    • Use dig +nssearch to verify that both authoritative server have the same SOA serial
    [primary]% dig zoneNNN.dnslab.org +nssearch
    SOA pdns010a.dnslab.org. hostmaster.zoneNNN.dnslab.org. 1003 3600 1800 3542400 60 from server 142.93.145.28 in 4 ms.
    SOA pdns010a.dnslab.org. hostmaster.zoneNNN.dnslab.org. 1003 3600 1800 3542400 60 from server 46.101.218.115 in 104 ms.
    
    • Note: PowerDNS sends NOTIFY messages over IPv4 only. To change the primary IP addresses on a secondary zone to contain the IPv4 address of the primary, use
    % pdnsutil change-secondary-zone-primary  zoneNNN.dnslab.org 46.101.218.115
    

4.10 Dynamic DNS (DDNS), NOTIFY, & Incremental Zone Transfers

4.10.1 Dynamic Updates

  • DNSIND is shorthand for a group of extensions to the original DNS protocol.
    • I is for Incremental Zone Transfer
    • N is for NOTIFY
    • D is for Dynamic Update
  • Together, the DNSIND extensions allow DNS to handle dynamic networks.
  • A dynamic update allows a node to change the contents of a zone. DNS dynamic update is the RFC standard API to change DNS content over the network. As it is a RFC standard, it works across different DNS server products. Use cases:
    • DHCP servers, for example, can add A, AAAA and PTR records to reflect the leases they give out.
    • Microsoft Active Directory can update the SRV records required for service discovery via dynamic updates
    • DNS management systems such as VinylDNS (https://www.vinyldns.io) or Men & Mice Micetro (https://menandmice.com) can manage zone content through dynamic updates
    • ACME compatible x509 certificate management systems (e.g. Let's encrypt, RFC 8555 https://datatracker.ietf.org/doc/html/rfc8555) can authenticate the domain owner with the help of dynamic DNS updates, allowing centralized automated certificate management
  • A dynamic update can:
    • Add resource records to a zone
    • Delete records from a zone:
      • One record
      • All records of a certain type with one domain name (an RRSet)
      • All records with one domain name
  • A server can be configured to only accept updates from senders with the proper PSK (Pre-Shared TSIG Key).
  • A sender can define update prerequisites, such as the existence/non-existence of:
    • A particular record
    • Resource Records with a specific domain name and type
  • A sender first tries to transmit an update to a zone's primary master.
    • Most compare the SOA's mname field to the NS RRSet.
    • If the mname matches an NS RR, the update is sent there.
    • Otherwise the update is sent to one of the domain names in the NS RRSet (from the sender's perspective, a secondary).

4.10.2 Dynamic Updates and PowerDNS

  • PowerDNS supports dynamic updates on a server that hosts primary (master) zones. Dynamic updates are disabled and can be enabled in the configuration file (global)
dnsupdate=yes
  • In addition to the global configuration, dynamic updates need to be enabled on a zone
% pdnsutil set-meta example.org ALLOW-DNSUPDATE-FROM 127.0.0.0/8
Oct 30 08:03:57 gmysql Connection successful. Connected to database 'powerdns' on '/run/mysqld/mysqld.sock'.
Oct 30 08:03:57 gmysql Connection successful. Connected to database 'powerdns' on '/run/mysqld/mysqld.sock'.
Set 'example.org' meta ALLOW-DNSUPDATE-FROM = 127.0.0.0/8
  • The tool nsupdate (Debian packet dnsutils) is the standard tool to send dynamic update messages. Here an example on how to add a new record to a zone:
$ nsupdate
> server 127.0.0.1
> ttl 60
> add ddns.zoneNNN.dnslab.org in TXT "This is a dynamically added DNS record"
> send
> quit
  • The dynamic update in the PowerDNS logfile
Oct 30 08:05:45 pdns01 pdns_server[30874]: Remote 127.0.0.1 wants 'ddns.zoneNNN.dnslab.org|SOA', do = 0, bufsize = 512: packetcache MISS
Oct 30 08:05:45 pdns01 pdns_server[30874]: Remote 127.0.0.1 wants 'zoneNNN.dnslab.org|SOA', do = 0, bufsize = 512: packetcache MISS
Oct 30 08:05:45 pdns01 pdns_server[30874]: UPDATE (9824) from 127.0.0.1 for zoneNNN.dnslab.org: Processing started.
Oct 30 08:05:45 pdns01 pdns_server[30874]: UPDATE (9824) from 127.0.0.1 for zoneNNN.dnslab.org: starting transaction.
Oct 30 08:05:45 pdns01 pdns_server[30874]: UPDATE (9824) from 127.0.0.1 for zoneNNN.dnslab.org: Adding record ddns.zoneNNN.dnslab.org|TXT
Oct 30 08:05:45 pdns01 pdns_server[30874]: UPDATE (9824) from 127.0.0.1 for zoneNNN.dnslab.org: Increasing SOA serial (1111 -> 2021103001)
Oct 30 08:05:45 pdns01 pdns_server[30874]: UPDATE (9824) from 127.0.0.1 for zoneNNN.dnslab.org: Update completed, 2 changed records committed.
Oct 30 08:06:26 pdns01 pdns_server[30874]: 1 domain for which we are master needs notifications
Oct 30 08:06:26 pdns01 pdns_server[30874]: Queued notification of domain 'zoneNNN.dnslab.org' to 165.22.233.102:53
  • The record will be published immediately and can be queried over DNS:
% dig @localhost ddns.zone001.dnslab.org txt

; <<>> DiG 9.16.22-Debian <<>> @localhost ddns.zone001.dnslab.org txt
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2483
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;ddns.zone001.dnslab.org.       IN      TXT

;; ANSWER SECTION:
ddns.zone001.dnslab.org. 60     IN      TXT     "This is a dynamically added DNS record"

;; Query time: 3 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sat Oct 30 08:06:28 UTC 2021
;; MSG SIZE  rcvd: 103
  • In the default configuration PowerDNS will wait 60 seconds after a dynamic update before sending out NOTIFY messages to the secondary. This configuration changes PowerDNS to send a notification to all slave servers after every update. This will speed up the propagation of changes and is very useful for ACME TLS certificate verification
% pdnsutil set-meta example.org NOTIFY-DNSUPDATE 1
  • Each dynamic update will increment the SOA serial number. PowerDNS has a SOA serial number edit policy (SOA-EDIT-DNSUPDATE) that defines how the SOA serial number should be incremented
    • DEFAULT: Generate a soa serial of YYYYMMDDNN. If the current serial is lower than the generated serial, use the generated serial. If the current serial is higher or equal to the generated serial, increase the current serial by 1.
    • INCREASE: Increase (increment) the current serial by 1.
    • EPOCH: Change the serial to the number of seconds since the EPOCH (seconds since 1.1.1970, also known as unixtime)
    • SOA-EDIT: Change the serial to whatever SOA-EDIT would provide. Used for DNSSEC zones to ensure freshness of signatures on secondary (slave) server
    • SOA-EDIT-INCREASE: Change the serial to whatever SOA-EDIT would provide. If what SOA-EDIT provides is lower than the current serial, increase the current serial by 1. Exception: with SOA-EDIT=INCEPTION-EPOCH, the serial is bumped to at least the current EPOCH time.
% pdnsutil set-meta example.org SOA-EDIT-DNSUPDATE INCREASE

4.10.3 Using nsupdate

  • nsupdate is a BIND application for sending dynamic changes to a server.
    • It works both interactively and non-interactively.
    • In both modes, commands are one-per-line.
  • The three main commands are:
    • update add
    • update delete
    • send
  • update prepares RRs changes, send executes them.
  • Note: ENTER by itself is the same as send
  • Non-interactively, commands come from a file or STDIN.
$ nsupdate nsupdate.input.file

$ nsupdate < nsupdate.input.file
  • Interactive mode:
$ nsupdate
>
  • The interactive command show allows changes to be reviewed before being sent.
    • Here no updates have been prepared.
$ nsupdate
> show
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:      0
;; flags:; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
>
  • update add prepares a RR to be added to a zone.
    • All fields, except the Class must be provided.
    • TTL can be provided in a separate statement.
> update add a.example.com IN A 192.0.2.1
ttl 'IN': not a valid number
> update add a.example.com 3600 IN A 192.0.2.1
> ttl 3600
> update add a.example.com AAAA 2001:db8:0:deaf::1
> show
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:      0
;; flags:; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; UPDATE SECTION:
a.example.com.		3600	IN	A	192.0.2.1
a.example.com.		3600	IN	AAAA	2001:db8:0:deaf::1
> send
  • update delete prepares RRs to be deleted.
    • Class is optional, and TTL, if provided, is ignored.
    • Providing all fields except TTL and Class deletes one RR.
> update delete b.example.com. 1800 A 192.0.2.99
> update delete example.net. MX 15 mailserver.example.net.
> show
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:      0
;; flags:; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; UPDATE SECTION:
b.example.com.		0	NONE	A	192.0.2.99
example.net.		    0	NONE	MX	15 mailserver.example.net.
  • update delete Providing the RTYPE without RDATA, deletes a RRSet.
> update delete b.example.com. AAAA
> update delete c.example.com IN SRV
> show
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:      0
;; flags:; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; UPDATE SECTION:
b.example.com.		0	NONE	A	192.0.2.99
example.net.		  0	NONE	MX	15 mailserver.example.net.
b.example.com.		0	ANY	AAAA
c.example.com.		0	ANY	SRV
>
  • update delete Omitting RTYPE and RDATA deletes all RRSets.
> update delete d.example.com.
> show
Outgoing update query:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id:      0
;; flags:; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
;; UPDATE SECTION:
b.example.com.		0	NONE	A	192.0.2.99
example.net.	    0	NONE	MX	15 mailserver.example.net.
b.example.com.		0	ANY	AAAA
c.example.com.		0	ANY	SRV
d.example.com.		0	ANY	ANY
  • Since BIND 9.9.0, the key word update is optional.
> delete  www.example.com. A
> add www.example.com. 600 A 192.0.2.80
> add www.example.com. 600 A 192.0.2.88
  • send - Transmit the prepared updates to the authoritative server.
    • WARNING - hitting ENTER is the same as send!
> send
  • answer - shows the results received from the server after a send.
> send
update failed: REFUSED
> answer
Answer:
;; ->>HEADER<<- opcode: UPDATE, status: REFUSED, id:  13117
;; flags: qr; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0
>
  • prereq nxdomain <domain name> - requires that "domain name" doesn't exist (no RRs of any type).
> prereq nxdomain www.example.com
> update add www.example.com 3600 CNAME example.com.
> send
  • prereq yxdomain <domain name> - requires that "domain name" does exist.
> prereq yxdomain www.example.com
> update add web.example.com 3600 CNAME www.example.com.
> send
  • server <servername or IP> [port] - specifies the authoritative server that will receive the update.
    • If not set, nsupdate uses MNAME from the SOA RR and port 53.
    • Generally, updates should be sent to the primary authoritative server.
> server ns0.example.com
  • nsupdate -l sends all updates to localhost.
    • The MNAME is not checked, and server commands are ignored.
    • This is easy use, and is recommended if you are on the primary server
  • local <IP address> [port] - specifies the outgoing IP address. This is useful for multi-homed machines, especially when IPv6 is used, and when the server limits updates to specific IPs.
> local 2001:db8:100:0:ff:aa01:42:12:feaa
  • zone <zonename> - specify the zone to be changed.
    • This is necessary when the update is an NS or glue RR to be made in the parent zone.
$ nsupdate
> zone example.com.
> update add ns1.subdomain.example.com. 3600 IN A 192.0.2.53
> update add ns2.subdomain.example.com. 3600 IN A 203.0.113.53
> send

4.11 Extended DNS (EDNS)

udp-truncation-threshold=1232

4.12 Autoprimary (Supermaster) operation

  • PowerDNS as a secondary server can automatically create a new secondary zone when receiving a NOTIFY from a trusted primary server
    • The primary is trusted either by IP-address or by TSIG-key
  • To use this function, the autoprimary function (old name superslave) needs to be enabled
# Automatically fetch new zones from primary
superprimary=on
  • Also on the secondary, the primary is configured as a new superprimary. This creates the trust based on the source IP address
% pdnsutil add-superprimary 2a03:b0c0:3:d0::133d:1 ns001a.dnslab.org
% pdnsutil add-superprimary 138.68.87.93 ns001a.dnslab.org
  1. Exercise

    • Configure the secondary pdnsNNNb.dnslab.org to have pdnsNNNa.dnslab.org as it's autoprimary (supermaster)
    • Create a new zone example.com on the primary server, configure the zone as a primary (master) zone, and populate the zone using pdnsutil with a correct SOA record and NS records
    • Check that the new zone is being created on the secondary and that all zone content is synchronized

  2. Solution
    • On the secpndary server pdnsNNNb.dnslab.org, set the PowerDNS server to be in superprimary mode (in /etc/powerdns/pdns.conf)
    superprimary=on
    
    • Mark the IP-Addresses of the primary server as trusted autoprimary:
    pdnsutil add-superprimary <ip-v6-address-of-primary> nsNNNa.dnslab.org
    pdnsutil add-superprimary <ip-v4-address-of-primary> nsNNNa.dnslab.org
    
    • On the (super)primary, add a new zones with content
    % pdnsutil create-zone example.com
    Creating empty zone 'example.com'
    Oct 30 08:34:10 No serial for 'example.com' found - zone is missing?
    
    % pdnsutil replace-rrset example.com . SOA 3600 'pdnsNNNa.dnslab.org . 1001 3600 1800 3600000 3600'
    Current records for example.com IN SOA will be replaced
    New rrset:
    example.com. 3600 IN SOA pdnsNNNa.dnslab.org . 1001 3600 1800 3600000 3600
    
    % pdnsutil add-record example.com . NS 1800 "pdnsNNNa.dnslab.org"
    New rrset:
    example.com. 1800 IN NS pdnsNNNa.dnslab.org
    
    % pdnsutil add-record example.com . NS 1800 "pdnsNNNb.dnslab.org"
    New rrset:
    example.com. 1800 IN NS pdnsNNNa.dnslab.org
    example.com. 1800 IN NS pdnsNNNb.dnslab.org
    
    • Configure the new zone to be a master zone
    % pdnsutil set-kind example.com primary
    
    • Log on the primary server
    Oct 30 08:41:29 pdns01 pdns_server[30874]: 1 domain for which we are master needs notifications
    Oct 30 08:41:29 pdns01 pdns_server[30874]: Queued notification of domain 'example.com' to 165.22.233.102:53
    Oct 30 08:41:30 pdns01 pdns_server[30874]: Removed from notification list: 'example.com' to 165.22.233.102:53 (was acknowledged)
    Oct 30 08:41:30 pdns01 pdns_server[30874]: Remote 165.22.233.102 wants 'example.com|SOA', do = 0, bufsize = 512: packetcache MISS
    Oct 30 08:41:30 pdns01 pdns_server[30874]: Remote 165.22.233.102 wants 'example.com|NS', do = 0, bufsize = 512: packetcache MISS
    Oct 30 08:41:30 pdns01 pdns_server[30874]: Remote 165.22.233.102 wants 'example.com|SOA', do = 0, bufsize = 512: packetcache HIT
    Oct 30 08:41:30 pdns01 pdns_server[30874]: AXFR-out zone 'example.com', client '165.22.233.102:53777', transfer initiated
    Oct 30 08:41:30 pdns01 pdns_server[30874]: AXFR-out zone 'example.com', client '165.22.233.102:53777', allowed: client IP is in allow-axfr-ips
    Oct 30 08:41:30 pdns01 pdns_server[30874]: gmysql Connection successful. Connected to database 'powerdns' on '/run/mysqld/mysqld.sock'.
    Oct 30 08:41:30 pdns01 pdns_server[30874]: AXFR-out zone 'example.com', client '165.22.233.102:53777', AXFR finished
    Oct 30 08:41:32 pdns01 pdns_server[30874]: No master domains need notifications
    
    • Log on the secondary
    Oct 30 08:41:29 pdns02 pdns_server[19475]: Received NOTIFY for example.com from 138.68.87.93:16522 for which we are not authoritative, trying supermaster
    Oct 30 08:41:30 pdns02 pdns_server[19475]: Created new slave zone 'example.com' from supermaster 138.68.87.93
    Oct 30 08:41:31 pdns02 pdns_server[19475]: AXFR-in zone: 'example.com', primary: '138.68.87.93', zone committed with serial 1001
    

4.13 Performance tuning

  • Performance tuning an authoritative DNS server requires some experience. DNS server performance is bound to different factors (network, hardware, database, logging configuration etc)
    • Most installations do not need any performance tuning, PowerDNS on modern hardware works just fine and is fast enough
    • Only start tuning if you know performance can be an issue
    • Measure, don't speculate
  • It is recommended to validate each performance tuning step in a test lab that mimics the real world DNS traffic
    • PowerDNS provides a couple of tools (located in the pdns-utils package in Debian 13) that can help with benchmarking a PowerDNS server:
      • dnsreplay reads recorded DNS query and responses and replays them to a DNS server and reports on the matches
      • dnsscope - sends data from a PCAP (Packet Capture) file towards an authoritative server
      • dnstcpbench - Tool to perform a benchmark of TCP connections to a DNS server
      • dumpresp - a dump responder that just echo back the query. Useful to establish a baseline of network and operating system DNS message performance
    • Other DNS benchmarking tools:

4.13.1 Hardware

  • The hardware used to host the DNS server can have a big impact on DNS server performance
    • Turn off symmetric multi-threading (aka Hyper-Threading) and run the DNS server on real CPU cores
    • 4-8 Cores are usually enough for an authoritative DNS server. More CPU cores can kill CPU cache performance.
      • Pin the PowerDNS processes and the Database processes to their own CPU cores
      • Check for IRQ balancing of the network cards. Sometimes all IRQs are routed towards one CPU core, which becomes a bottleneck for DNS style IP traffic (many small packets)
    • When selecting hardware, use server with less number of cores but high performance of each core
    • Configure the PowerDNS receiver-threads to be one per core
    • Memory bandwidth between CPU, cache-memory und main-memory is important
    • Select quality network cards with good driver support for you operating system
    • Avoid system virtualization (VMWare, QEMU, VirtualBox etc). If virtualization is required, use PCI pass-through for the network cards
    • The Spectre and Meltdown type of CPU vulnerabilities usually don't affect dedicated non-virtualized DNS server. Consider switching off the kernel mitigation for these security issue to gain more performance. Consult with your security department first.
    • Possibly adjust the memory allocation scheme of the operating system LIBC library (see MALLOC_ARENA_MAX https://doc.powerdns.com/authoritative/performance.html)

4.13.2 Logging

  • Logging can hurt the DNS server performance. Generating text base log message is CPU intensive, and can slow down the PowerDNS server under high query load. Disable query- and detail-logging.

4.13.3 Server placement

  • The DNS protocol has a build in load-distribution function
    • DNS query load will be spread over all authoritative server (primary and secondary)
    • Deploy DNS server in many different networks and geographic regions
    • Select data-center with fast Internet access that are near potential DNS user
  • DNS load-balancer in front of authoritative server can hurt the performance and increase the query latency

4.13.4 Network

  • PowerDNS configuration options that have an impact on the network performance
    • If the operating system support the reuseport socket option, configure PowerDNS to use this option to be able to have multiple processes/threads listening on the same IP address and port. This helps distributing the load over multiple CPU cores
    • For DNS server with many TCP connections (primary with many secondaries, large Resource-Records set that demand TCP connections, DNS-over-TLS/HTTPS) tune the TCP network stack of your operating system and the PowerDNS TCP configuration:
      • Enable tcp-fast-open when available in the operating system
      • Adjust the max-tcp-connections and max-tcp-connections-per-client to match your PowerDNS server workload. Monitor the PowerDNS server to detect if these threshold
      • Limit the time a TCP connection can be held open from a client (see max-tcp-connection-duration)
      • Limit the number of transactions that can be send through one TCP connection (see max-tcp-transactions-per-conn)

4.13.5 Cache

  • For a PowerDNS server with database backend, the packet and query caches are an important performance factor. The packet cache holds DNS responses that have been fetched from the database. The query cache holds results from additional database queries required to find DNS data in the database. Carefully tune the PowerDNS caches:
    • max-cache-entries - Max entries in the query cache
    • max-packet-cache-entries - Max entries in the packet cache
    • query-cache-ttl - How long are database queries resulting in positive answers be stored in the query cache
    • negquery-cache-ttl - How long are database queries resulting in negative answers be stored in the query cache
    • cache-ttl - How long are full DNS answer packets are stored in the packet cache

4.13.6 Database

  • Database performance can be the bottleneck with a PowerDNS instance using a database backend. PowerDNS stores DNS queries in a queue waiting to the send to the database. Settings that effects the performance of the database query queue
    • max-queue-length length of the backend query queue. If this threshold is reached, close the database connection and restart operation (to work around database connection issues)
    • overload-queue-length defines a threshold size for the database query queue. Default unlimited. Once reached, DNS requests are only answered from the packet cache
    • queue-limit - Maximum time (milliseconds) that a query can be waiting in the backend queue

4.13.7 Benchmarking

  • The PowerDNS command line tool pdnsutil contains a build-in benchmarking function for database connections
% pdnsutil bench-db

4.14 DNS-Debugging & PowerDNS Debugging

  • The SOA serial must match on all authoritative servers.
    • If the zone is changed but the serial number not incremented, the secondaries won't zone transfer… primary and secondary DATA will not match.
    • dig +nssearch <zone name> queries the SOA from all servers listed in the zone's NS RRset.
    $ dig menandmice.com +nssearch
    SOA dns1.menandmice.com. hostmaster.menandmice.com. 2020052201 900 300 604800 900 from server 213.176.128.100 in 62 ms.
    SOA dns1.menandmice.com. hostmaster.menandmice.com. 2020052201 900 300 604800 900 from server 213.176.143.102 in 62 ms.
    SOA dns1.menandmice.com. hostmaster.menandmice.com. 2020052201 900 300 604800 900 from server 193.4.194.100 in 62 ms.
    SOA dns1.menandmice.com. hostmaster.menandmice.com. 2020052201 900 300 604800 900 from server 217.151.171.7 in 64 ms.
    SOA dns1.menandmice.com. hostmaster.menandmice.com. 2020052201 900 300 604800 900 from server 217.151.171.21 in 67 ms.
    SOA dns1.menandmice.com. hostmaster.menandmice.com. 2020052201 900 300 604800 900 from server 45.79.153.125 in 100 ms.
    SOA dns1.menandmice.com. hostmaster.menandmice.com. 2020052201 900 300 604800 900 from server 2600:3c03::f03c:91ff:fe67:57a0 in 100 ms.
    

4.14.1 External Domain Checking

4.14.2 Exercise

  • use the external website checkers above to check your zoneXXX.dnslab.org zone
  • try to understand the output
  • are there any errors reported? Warnings? Recommendations?

4.15 Web-server, Prometheus Metrics and REST API

4.15.1 Web-server

  • PowerDNS provides an optional build-in web-server. This web-server provides:
    • A simple web page that show vital performance data
    • A metrics endpoint for the Prometheus (https://prometheus.io) monitoring system
    • A URL endpoint for a restful API
  • The web-server can be enabled in the PowerDNS configuration file
# Webserver
webserver=yes
webserver-address=127.0.0.1
webserver-password=powerDNS
webserver-port=8053
webserver-allow-from=127.0.0.1/32
  • After a restart, PowerDNS should now listen of the defined TCP port
% lsof -Poni :8053
COMMAND     PID USER   FD   TYPE DEVICE OFFSET NODE NAME
pdns_serv 29892 pdns    9u  IPv4  85197    0t0  TCP 138.68.87.93:8053 (LISTEN)

4.15.2 Prometheus

  • The URL endpoint /metrics provides a metrics page that get be used ("scraped") by Prometheus and compatible monitoring systems

4.15.3 API

  • Access to the REST-API must be secured by an API key. At least 16 byte of random key is recommended. Such a key can be generated as a hexadecimal string with openssl:
% openssl rand -hex 16
  • The configuration settings below enable the API
api=yes
api-key=<api-key>
  • Testing the API from curl. It is required to send the API-Key with the X-API-Key header with every request
# curl -s -H 'X-API-Key: ac90ae012cdaba61101a9061eda492d6' http://ns001a.dnslab.org:8053/api/v1/servers/localhost/zones | jq .
[
  {
    "account": "",
    "dnssec": false,
    "edited_serial": 1007,
    "id": "zone001.dnslab.org.",
    "kind": "Native",
    "last_check": 0,
    "masters": [],
    "name": "zone001.dnslab.org.",
    "notified_serial": 1007,
    "serial": 1007,
    "url": "/api/v1/servers/localhost/zones/zone001.dnslab.org."
  }
]
  • The API documentation is available from the PowerDNS server itself (benefit: it is always correct for the running version of PowerDNS). To dump out the API documentation, the API-Key needs to be send as well
$ curl -s -H 'X-API-Key: <api-key>' http://nsNNNa.dnslab.org:8053/api/docs | less

4.15.4 Exercise

  • Enable the PowerDNS web-server to listen on the public IP addresses (IPv6 and IPv4) of the server, protect the access with a password
  • Check out the statistics and Prometheus metrics page from a web browser
  • Create an API key for your primary server using openssl
  • Enable the API with the API-key, check the configuration
  • Use curl to download the API documentation
  • Find the API function to delete a record from a zone, test to remove a record from the zone
    • Does the SOA serial increment?

4.15.5 Solution

  • API call to remove the IPv6 AAAA record from a PowerDNS hosted zone. The name parameter must be fully qualified, ending with the dot .:
% curl -s -X PATCH --data '{"rrsets": [ {"name": "zoneNNN.dnslab.org.", "type": "AAAA", "changetype": "DELETE" } ] }' \
   -H 'X-API-Key: <api-key>' http://pdnsNNNa.dnslab.org:8053/api/v1/servers/localhost/zones/zoneNNN.dnslab.org
% pdnsutil list-zone zoneNNN.dnslab.org
  • As the pdnsutil list-zone shows, the SOA serial is not incremented. To increment the SOA record, another API call is required.

5 PowerDNS recursor

5.1 DNS Resolver placement

  • in managed networks (company, university) the IT department manages one or more dedicated DNS resolvers

0401-resolver-placement.png

  • ISP (Internet Service Provider) customers often use the DNS resolvers provided by the ISP

0402-resolver-placement.png

  • although sometimes problematic from privacy and security point of view, many users today use public DNS resolvers in the Internet

0403-resolver-placement.png

  • some operating systems support operating a full DNS resolver on each system

0404-resolver-placement.png

5.2 Compiling and Installing the PowerDNS Recursor

  • There are several options to install a PowerDNS recursor on a Linux/Unix operating system

5.2.1 Installation of the PowerDNS recursor on Debian 13

  • In the hands-on lab sessions for this training, we will be installing the PowerDNS recursor from the Debain 11 repositories
% apt install pdns-recursor
  • After installation, the PowerDNS recursor should be up and running with the default configuration. You can use the rec_control tool to check that all PowerDNS recursor threads are alive
% rec_control ping
pong
pong
pong
  • The PowerDNS recursor main binary is pdns_recursor. Beside being used to start the PowerDNS recursor process, it can be used to print out the compile time configuration
# pdns_recursor --version
Oct 31 11:48:51 PowerDNS Recursor 4.4.2 (C) 2001-2020 PowerDNS.COM BV
Oct 31 11:48:51 Using 64-bits mode. Built using gcc 10.2.1 20210110.
Oct 31 11:48:51 PowerDNS comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it according to the terms of the GPL version 2.
Oct 31 11:48:51 Features: fcontext libcrypto-ecdsa libcrypto-ed25519 libcrypto-ed448 libcrypto-eddsa lua protobuf dnstap-framestream snmp sodium
Oct 31 11:48:51 Configured with: " '--build=x86_64-linux-gnu' '--prefix=/usr' '--includedir=${prefix}/include'
                '--mandir=${prefix}/share/man' '--infodir=${prefix}/share/info' '--sysconfdir=/etc' '--localstatedir=/var'
                '--disable-option-checking' '--libdir=${prefix}/lib/x86_64-linux-gnu' '--runstatedir=/run' '--disable-maintainer-mode'
                '--disable-dependency-tracking' '--sysconfdir=/etc/powerdns' '--enable-systemd' '--with-systemd=/lib/systemd/system'
                '--enable-reproducible' '--enable-unit-tests' '--disable-silent-rules' '--with-service-user=pdns' '--with-service-group=pdns'
                '--with-libsodium' '--with-lua' '--with-net-snmp' '--with-protobuf=yes' '--enable-dnstap'
                'build_alias=x86_64-linux-gnu'
                'CFLAGS=-g -O2 -ffile-prefix-map=/build/pdns-recursor-MyWXnC/pdns-recursor-4.4.2=. -fstack-protector-strong -Wformat -Werror=format-security'
                'LDFLAGS=-Wl,-z,relro -Wl,-z,now'
                'CPPFLAGS=-Wdate-time -D_FORTIFY_SOURCE=2'
                'CXXFLAGS=-g -O2 -ffile-prefix-map=/build/pdns-recursor-MyWXnC/pdns-recursor-4.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -DPACKAGEVERSION='\''"4.4.2-3.Debian"'\'''"
  • The default security settings of the PowerDNS recursor service is already quite good, as can be seen with systemd-analyze:
% systemd-analyze security pdns-recursor
  • However some additional hardening steps are possible (optional):
    • MemoryDenyWriteExecute - enables a function in the memory management unit (and modern CPUs) that makes memory pages either write-able (data) or executable (program code), but never both. This prevents certain attacks, such as buffer overflow attacks
    • umask - Files created by the PowerDNS recursor processes can only be read or written by the PowerDNS recursor user or root, but not by any other user
    • MemoryMax - Restrict the memory consumption of the PowerDNS process to 1 GB. This is usually more than enough for an DNS resolver server and prevents system instability in case of a memory leak. For a DNS resolver with a large user base (millions of user), this setting might need to be adjusted. However values over 2 GB are usually not needed.
    • TasksMax - restricts the number of threads (tasks) of the PowerDNS service to 512. This prevents DoS attacks through a security vulnerability that would allow and external attacker to start new threads. This setting should be monitored and adjusted to the real world scenario where PowerDNS is deloyed (number of CPU cores, network interfaces etc).
MemoryDenyWriteExecute=true
UMask=077
MemoryMax=1G
TasksMax=512

5.2.2 Exercise

  • Login to your hands-on lab machine pdnsrNNN.dnslab.org
  • Become root
  • Install the PowerDNS recursor server from the Debian 13 package repository
  • Use systemctl edit --full pdns-recursor to add the additional hardening configuration seen above. Add the additional lines inside the [service] section
  • Restart the PowerDNS service, and check with systemctl status that the Task and Memory restrictions are in place

5.3 PowerDNS recursor configuration

  • The PowerDNS recursor configuration file is in /etc/powerdns/recursor.conf. The default configuration file can be overwhelming in the beginning, so we start with a clean file and build our configuration from there. We backup the original configuration files.
% mv /etc/powerdns/recursor.conf /etc/powerdns/recursor.conf.debian11
  • Below is a basic working configuration for a PowerDNS recursor
# Access
allow-from=127.0.0.0/8

# Network
local-address=127.0.0.1
local-port=53
reuseport=yes

# Socket
socket-dir=/run/pdns-recursor
write-pid=yes

# Logging
disable-syslog=no

# Security
udp-truncation-threshold=1232
edns-outgoing-bufsize=1232

version-string="My PowerDNS"
qname-minimization=yes

security-poll-suffix=
lowercase-outgoing=yes
serve-rfc1918=yes
  • After restart, the PowerDNS recursor listens on port 53 (DNS) UDP and TCP
% lsof -Poni :53
COMMAND     PID USER   FD   TYPE DEVICE OFFSET NODE NAME
pdns_recu 22415 pdns    6u  IPv4  90499    0t0  UDP 127.0.0.1:53
pdns_recu 22415 pdns    9u  IPv4  90502    0t0  TCP 127.0.0.1:53 (LISTEN)
  • The resolver should now resolve DNS queries
% dig @localhost sys4.de
; <<>> DiG 9.16.22-Debian <<>> @localhost sys4.de
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 25571
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;sys4.de.                       IN      A

;; ANSWER SECTION:
sys4.de.                3600    IN      A       194.126.158.154

;; Query time: 91 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Nov 01 06:44:22 UTC 2021
;; MSG SIZE  rcvd: 52
  • Besides the normal key-value style configuration file, PowerDNS recursor can be configured using the Lua programming language. This allows more complex configurations and is required for some special functions, such as DNSTAP, Response-Policy-Zones and DNSSEC trust-anchor management.
  • The Lua-Configuration file is loaded from the main PowerDNS recursor configuration and is stored in /etc/powerdns/recursor.lua. The Lua configuration file example below prints a log message to inform that the Lua configuration file has been loaded, and the loads the DNSSEC root-keys:
-- Debian default Lua configuration file for PowerDNS Recursor
pdnslog("PowerDNS recursor Lua config file loaded", pdns.loglevels.All)
-- Load DNSSEC root keys from dns-root-data package.
-- Note: If you provide your own Lua configuration file, consider
-- running rootkeys.lua too.
dofile("/usr/share/pdns-recursor/lua-config/rootkeys.lua")
  • To load the Lua configuration file, add the line below to the PowerDNS recursor config file in /etc/powerdns/recursor.conf
# Lua config file
lua-config-file=/etc/powerdns/recursor.lua
  • Restart the PowerDNS recursor and watch for the message from the Lua configuration file in the log output

5.3.1 Exercise

  • Save the original PowerDNS recursor configuration file on pdnsrNNN.dnslab.org and replace the configuration with the example file above
  • Add the Lua configuration
  • Restart the PowerDNS recursor, check the log-files (systemd journal) for errors and the Lua configuration log message configured
  • Verify that the DNS resolver still works as expected and does resolver names in the Internet
  • The operating system should use the same DNS "view" the DNS namespace, esp. in the case of a split-horizon DNS setup.
    • There are many ways on how to configure the operation system resolver (manual, DHCPv4, IPv6-SLAAC, DHCPv6 …). Here we use the brutal direct method which is not recommended in production:
rm /etc/resolv.conf
echo "nameserver 127.0.0.1" > /etc/resolv.conf
echo "search ." >> /etc/resolv.conf
chattr +i /etc/resolv.conf
  • After changing the operating system resolver config, check that DNS name resolution still works from the operating system (dig uses /etc/resolv.conf to find the DNS resolver, but used it's own resolver routines. getent uses the libc DNS lookup)
% dig sys4.de aaaa
% getent hosts sys4.de
2001:1578:400:111::8 sys4.de

5.4 DNSSEC validation

5.4.1 DNSSEC intro

5.4.2 DNSSEC Validation with PowerDNS recursor

  • PowerDNS comes with the DNSSEC trust anchors for the Internet DNS system
  • Using DNSSEC validation is just a matter of switching it on
    • Every DNS resolver for the Internet should have DNSSEC validation enabled, there is no downside of doing DNSSEC validation
  • To enable DNSSEC validation, add the dnssec=validate statement to the PowerDNS recursor configuration file
# DNSSEC
dnssec=validate
  • The Root Trust Anchor for DNSSEC used in a Debian 13 system can be found in /usr/share/dns/root.key which is loaded from /usr/share/pdns-recursor/lua-config/rootkeys.lua
-- readTrustAnchorsFromFile reads the DNSSEC trust anchors from the provided file
-- and reloads it every 24 hours.
readTrustAnchorsFromFile("/usr/share/dns/root.key")
  • Other values for the dnssec setting statement:
    • off - completely disables DNSSEC
    • process-no-validate - (default until version 4.5.0): creates a "security aware, non-validating" nameserver, where PowerDNS will request DNSSEC data with the DO flag and will provide the data to a downstream client when requested, but will not do any DNSSEC validation
    • process - (default since version 4.5.0): the PowerDNS recursor will always request DNSSEC data, but will only validate when requested by the client with either the DO or the AD flag in the query from the client
    • log-fail - same as process, but additionally will log DNSSEC validation issues. This can be used to find DNSSEC validation issues before enabling full validation
    • validate - PowerDNS recursor does full DNSSEC validation on all DNS data that contains DNSSEC information

5.4.3 DNSSEC related configuration options

  • allow-trust-anchor-query - Allow trustanchor.server CH TXT and negativetrustanchor.server CH TXT queries to view the configured DNSSEC (negative) trust anchors. Can be used to monitor trust anchors.
  • dnssec-log-bogus - Log every DNSSEC validation failure. Note: This is not logged per-query but every time records are validated as Bogus.
  • aggressive-nsec-cache-size - The number of records to cache in the aggressive cache. If set to a value greater than 0, the recursor will cache NSEC and NSEC3 records to generate negative answers, as defined in RFC 8198. To use this, DNSSEC processing or validation must be enabled by setting dnssec to process, log-fail or validate.
  • max-cache-bogus-ttl - Maximum number of seconds to cache an item in the DNS cache (negative or positive) if its DNSSEC validation failed, no matter what the original TTL specified, to reduce the impact of a broken domain.
  • nsec3-max-iterations - Maximum number of iterations allowed for an NSEC3 record. If an answer containing an NSEC3 record with more iterations is received, its DNSSEC validation status is treated as Insecure. New recommendation is to set this to 150 iterations, see Guidance for NSEC3 parameter settings - draft-ietf-dnsop-nsec3-guidance
  • signature-inception-skew - Allow the signature inception to be off by this number of seconds. Negative values are not allowed (Default 60 seconds since version 4.2.0).
  1. Exercise

    • Enable DNSSEC validation on your PowerDNS recursor
    • Test the following DNS queries with dig
      • heise.de A - should resolve, but not validate
      • sys4.de A - should resolver and validate (AD-Flag)
      • fail03.dnssec.works - should not resolve (Error SERVFAIL, domain is bogus)
    • Enable dnssec-log-bogus on the PowerDNS recursor, try the domains fail01.dnssec.works to fail05.dnssec.works. Are the DNSSEC validation errors being written to the log?

5.5 DNS Cache

  • Providing a DNS cache for faster DNS name resolution is a major part of a DNS resolver (the other important function is the smart resolver that can traverse the DNS namespace tree)
    • Most of the time, the DNS cache is maintenance free
    • But in case of attacks or external mis-configurations, the DNS resolver administrator might need to maintain the cache content manually

5.5.1 DNS Name Resolution

  • DNS Query - what the client sends

  • DNS Name Resolution

5.5.2 Caching

  • DNS Resolver caching

5.5.3 Negative Caching

  • NXDOMAIN - the domain name does not exist.
  • NOERROR/NODATA - the domain name exists, but not the RR type. AKA: NOERROR/NOANSWER.
  • For NXDOMAIN and NOERROR/NODATA, the zone's SOA is returned in the authoritative section.
  • The negative TTL is the minimum of SOA's TTL and the SOA's RDATA MIN field. (RFC 2308 -Negative Caching of DNS Queries (DNS NCACHE))

5.5.4 PowerDNS cache maintenance

  • Sometimes wrong DNS data might be stored in the cache (caused by an operational error on the authoritative zone side, or through an cache-poisioning attack
  • The command rec_control dump-cache can be used to write the content of the cache into a file in human readable form (RFC 1035 master file format)
    • Such a file can be quite large, up to 400% larger than the (binary) cache content in memory. Check the available space on the file system first before dumping a large cache!
% rec_control dump-cache /some/path/in/the/filesystem/cache.txt
dumped 88 records
  • Malicious or wrong content in the cache can be removed with the wipe-cache sub-command of rec_control
    • This command takes one or more domain names and removed all cached entries (all record types) of that name (but only that name).
    • When the domain name is suffixed with a $, the domain name and all sub-domains are removed as well
% rec_control wipe-cache powerdns.com$ sys4.de
  • The sub-command wipe-cache-typed can be used to remove a specific record type (A, AAAA, MX, TXT …) of a domain name from the cache
% rec_control wipe-cache-typed MX powerdns.com$ sys4.de

5.5.5 Exercise

  • Resolve the name yahoo.co.jp (Yahoo Japan) from your PowerDNS recursor. Note the DNS resolution time
  • Repeat the query. The DNS resolution time should now be much lower, as the answer comes from the cache
    • Repeat the query, see the TTL decrease
  • Wipe the name yahoo.co.jp from the cache, repeat the query, note the query time
  • Wipe the top-level-domain jp and all sub-domains from the cache, repeat the query for yahoo.co.jp, note the query time
  • Dump the content of the cache into /tmp/cache.txt, try to view the file. Are you able to view the file? What might be wrong? How to solve this? Discuss with the other training participants.

5.5.6 Solution

  • As a security measure, PowerDNS recursor run with a private /tmp and /var/tmp directory
    • The file is written, but only the same process can see and access it (see systemd hardening above)
% rec_control dump-cache /tmp/cache.txt
dumped 88 records
% less /tmp/cache.txt
/tmp/cache.txt: No such file or directory
  • We need to write the file into a non-temp directory
% mkdir /var/cache/pdns
% chown pdns /var/cache/pdns/
% rec_control dump-cache /var/cache/pdns/cache.txt
% less /var/cache/pdns/cache.txt

5.5.7 PowerDNS cache configuration

  • The PowerDNS cache function can be tuned in the configuration file
  • disable-packetcache - disables the cache. Only recommended in special cases where PowerDNS recursor is used to manipulate DNS data on-the-fly that should not be cached, for example though Lua scripts
  • max-cache-entries - Maximum number of DNS record cache entries (default 1 million), shared by all threads. Each entry associates a name and type with a record set. The size of the negative cache is 10% of this number. Having a too large cache can hurt performance, as it fragments DNS cache memory. This value can be changed at runtime with rec_control set-max-cache-entries <num>. This is useful to dynamically re-size the cache to find the best cache size for a workload.
  • max-packetcache-entries - While the normal cache holds DNS resource records, the packet cache holds the full DNS response packets. This setting controls the maximum number of Packet Cache entries (default 500.000). Each worker and each distributor thread has a packet cache instance. This number will be divided by the number of worker plus the number of distributor threads to compute the maximum number of entries per cache instance. Can be set at run-time with set-max-packetcache-entries <num>
  • max-cache-ttl - Maximum number of seconds to cache an item in the DNS cache (default 86400 or 24 hours), no matter what the original TTL specified. The minimum value of this setting is 15. i.e. setting this to lower than 15 will make this value 15.
  • max-negative-ttl - How long are negative responses (NXDOMAIN and NXRRSET/NODATA being cached. Default 3600 (1 hour). Can overwrite the SOA negTTL/minTTL of the authoritative zone
  • minimum-ttl-override - This setting artificially raises all TTLs to be at least this long. Setting this to a value greater than 1 technically is an RFC violation (and might break applications and web-pages!), but might improve performance a lot. Using a value of 0 impacts performance of TTL 0 records greatly, since it forces the recursor to contact authoritative servers each time a client requests them. Can be set at runtime using rec_control set-minimum-ttl <num>
  • packetcache-ttl - Maximum number of seconds to cache an item in the packet cache, no matter what the original TTL specified. Default 3600 (1 hour)
  • packetcache-servfail-ttl Maximum number of seconds to cache an answer indicating a failure to resolve in the packet cache. Before version 4.6.0 only ServFail answers were considered as such. Starting with 4.6.0, all responses with a code other than NoError and NXDomain, or without records in the answer and authority sections, are considered as a failure to resolve.
  • record-cache-shards - Sets the number of shards in the record cache (Default 1024). If you have high contention as reported by record-cache-contented / record-cache-acquired (see statistics/metrics), you can try to enlarge this value or run with fewer threads.

5.6 SplitDNS and Forward-Zones

  • Sometimes it is desired that a DNS resolver can resolve names that are not delegated from the Internet DNS root down
    • Internal versions of a zone that also exists on the Internet (Split-DNS)
    • Internal Active Directory domains
    • Local-Domains (home.arpa)
    • For testing purposes of new Internet domains, before connecting them to the Internet DNS delegation tree
  • DNS resolver can send queries to upstream server in two different modes
    • Recursive mode (RD – recursion desired – flag set) - these queries should be send to other DNS resolver
    • Iterative mode (RD – recursion desired – flag clear) - these queries should be send to authoritative DNS server
  • In other DNS server software (BIND 9, Windows DNS), forwarding always is operating in recursive mode. Iterative name resolution to authoritative server is implemented through Stub-Zones
    • The PowerDNS recursor can do forwarding in recursive and iterative mode

5.6.1 Forwarding (Recursive mode)

  • Forwarding in recursive mode is configured with one or more forward-zones-recurse statements in the configuration file
    • This statement takes the domain to be forwarded (including all sub-domains). Use . to generate a global forwarding where all queries to being forwarded to the upstream DNS resolver
    • The second parameter are the IP addresses of the upstream DNS resolver. The addresses are separated by semicolons (not comma or space)!
forward-zones-recurse=example.org=192.0.2.53;2001:db8::53
  1. Exercise

    • Configure a forwarding to 2 (!) upstream DNS resolver from Quad9 (https://www.quad9.net) for the domain name powerdns.com (and everything below)
    • Restart the PowerDNS recursor
    • Run tcpdump in a separate terminal window (or use tmux) to observe the DNS queries going out from the server machine. Send test queries for powerdns.com and other domains. Validate that the requests for powerdns.com are being send to Quad9.

  2. Solution
    • PowerDNS recusor configuration
    forward-zones-recurse=powerdns.com=9.9.9.9;149.112.112.112
    
    • tcpdump
    % tcpdump port 53 and host 9.9.9.9 or host 149.112.112.112
    tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
    listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
    15:34:03.721440 IP pdnsrNNN.dnslab.org.31778 > dns9.quad9.net.domain: 30694+% [1au] DS? www.powerdns.com. (45)
    15:34:03.733552 IP dns9.quad9.net.domain > pdnsrNNN.dnslab.org.31778: 30694$ 0/4/1 (500)
    15:34:03.733852 IP pdnsrNNN.dnslab.org.18160 > dns9.quad9.net.domain: 23994+% [1au] DNSKEY? powerdns.com. (41)
    15:34:03.742156 IP dns9.quad9.net.domain > pdnsrNNN.dnslab.org.18160: 23994$ 3/0/1 DNSKEY, DNSKEY, RRSIG (765)
    15:34:03.742854 IP pdnsrNNN.dnslab.org.22697 > dns9.quad9.net.domain: 57733+% [1au] A? www.powerdns.com. (45)
    15:34:03.929210 IP dns9.quad9.net.domain > pdnsrNNN.dnslab.org.22697: 57733$ 2/0/1 A 188.166.104.92, RRSIG (233)
    
    

5.6.2 Sending queries to a non-delegated zone (Iterative forwarding)

  • Iterative forwarding is configured with the forward-zone statement. The statement format is identical with forward-zone-recurse (IP addresses are separated by semicolons)
forward-zones=internal-zone.loc=10.0.0.1;192.168.10.53
  1. Exercise

    • There is an undelegated DNS zone with the name undelegated.home.arpa hosted on the authoritative DNS server ns3.myinfrastructure.org
      • Check that this zone cannot be resolved with normal DNS name resolution
      • Configure a non-recursive (iterative) forwarding for this zone
      • Restart the PowerDNS recursor and test if you can now resolve the zone

  2. Solution
    • PowerDNS recursor configuration:
    forward-zones=undelegated.home.arpa=5.45.109.212
    
    • Now the DNS resolver can reach the undelegated zone
    $ dig undelegated.home.arpa
    
    ; <<>> DiG 9.16.22-Debian <<>> undelegated.home.arpa
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56466
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 512
    ;; QUESTION SECTION:
    ;undelegated.home.arpa.         IN      A
    
    ;; ANSWER SECTION:
    undelegated.home.arpa.  3600    IN      A       5.45.109.212
    
    ;; Query time: 27 msec
    ;; SERVER: 127.0.0.1#53(127.0.0.1)
    ;; WHEN: Tue Nov 02 20:12:16 UTC 2021
    ;; MSG SIZE  rcvd: 66
    

5.6.3 DNSSEC Trust Anchor for non-delegated zones

  • Sometimes an (internal or external) undelegated DNS zone is secured with DNSSEC and the DNS resolver should validate the data
    • Internal Active Directory domains
    • Private domains
    • Split-DNS domains
  • As the zone is not delegated, there cannot be a DNSSEC chain-of-trust from the parent zone (as there is no parent zone)
  • The solution is to create a dedicated Trust-Anchor for the undelegated zone(s)
  • The PowerDNS recursor uses the Key-Signing-Key (KSK, DNSKEY flag 257) of a zone as the trust anchor
    • All trust anchors should be in a single file and loaded at startup
    • It is possible to inject a trust anchor at runtime, but that trust anchor will be lost after an restart of the service
  1. Creating a Trust Anchor file for PowerDNS recursor
    • In this example we fetch the KSK of the undelegated zone from one of their authoritative servers (manually validate that the KSK is the correct one!)
    % dig undelegated.home.arpa dnskey | grep 257
    undelegated.home.arpa.  3600    IN      DNSKEY  257 3 13 Vc6u0+qBFFUcc/S7LVdURP1PlIDsXPcKKNpqqoVylcv3FQq97npGNp9A xNf6odw2W+LkUv5At6UoaN79ghrtJQ==
    
    • The KSK data of the root KSK and all other zones is stored into a trust-anchor file, one KSK per line
    % dig . dnskey | grep 257 > dnssec.ta
    % dig undelegated.home.arpa dnskey | grep 257 >> dnssec.ta
    
    • In the PowerDNS recursor Lua configuration file /etc/powerdns/recursor.lua, the new trust anchor file is being loaded. This will replace all previous loaded trust anchors!
    -- Trust Anchor for undelegated.home.arpa
    readTrustAnchorsFromFile("/etc/powerdns/dnssec.ta")
    
    • After restart, the PowerDNS recursor should have all trust anchors configured:
    # rec_control get-tas
    Configured Trust Anchors:
    .
                    20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d
    undelegated.home.arpa
                    40068 13 2 566ec09d6e001eb78d4dfad2e4789e0c6ebcf3f2bcc5051fa2dce08df0a728a5
    
    • Now the undelegated zone should resolve and validate (check the AD flag in the DNS response):
    % dig undelegated.home.arpa
    
    ; <<>> DiG 9.16.22-Debian <<>> undelegated.home.arpa
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 11174
    ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 512
    ;; QUESTION SECTION:
    ;undelegated.home.arpa.         IN      A
    
    ;; ANSWER SECTION:
    undelegated.home.arpa.  3600    IN      A       5.45.109.212
    
    ;; Query time: 63 msec
    ;; SERVER: 127.0.0.1#53(127.0.0.1)
    ;; WHEN: Tue Nov 02 20:44:40 UTC 2021
    ;; MSG SIZE  rcvd: 66
    
  2. Exercise

    • Create a trust anchor for the zone undelegated.home.arpa as shown in the example above

5.7 Webserver

  • As the other PowerDNS products (PowerDNS authoritative server, DNSdist), the PowerDNS recursor comes with a build in web-server powerdns-recursor-web.png
  • The web-server does show the CPU utilization, current queries per second (QPS) and SERVFAIL per second, Query-Names and remote IP addresses from DNS clients
  • For the PowerDNS recursor web-server to work, the API-key must be configured, even if not used
# Webserver
webserver=yes
webserver-address=<ip-address-of-server>
webserver-password=PowerDNS
webserver-port=8053
webserver-allow-from=0.0.0.0/0
webserver-loglevel=none

# API
api-key=56372de136e76af5d373eda664d0d30c

5.7.1 Exercise

  • Enable the web-interface for PowerDNS recursor
  • Login to the web-interface with a web-browser
  • Send some DNS queries to the PowerDNS recursor, see the statistics change

5.8 DNStap (Advanced Query & Response Logging)

5.8.1 DNS server operations monitoring

  • It is difficult to monitor the internal operation of a DNS server
    • Classic monitoring has a huge performance impact (on busy DNS servers)
      • Example: PowerDNS query-logging
      • Up to 200% performance loss seen
      • Speed of the disk storage is often the limiting factor
      • Conversation from binary to text format is CPU intensive
  1. Network packet capture
    • An alternative solution is to look from the outside via a network traffic capture tool
      • No performance impact on the DNS server
      • Can only observe from the outside (no internal DNS server events, like cache-events, seen)
      • Difficult to work with UDP fragments and DNS data in TCP streams
  2. DNSTAP
    • DNSTAP is an open protocol to capture and store DNS server events
    • Events are recorded inside the server
    • Fast and lightweight protocol
    • Non-blocking, designed to have minimal impact on the DNS servers performance
  3. DNSTAP Operation

  4. DNSTAP implementations
    • DNSTAP has been developed by Farsight Security 
(Paul Vixie and Robert Edmonds)
      • Homepage is http://dnstap.info
      • Implementations:
        • Unbound
        • Knot 2.x
        • BIND 9
        • NSD
        • CoreDNS
        • PowerDNS Recursor
        • DNSDist (PowerDNS Load Balancer)
  5. DNSTAP dependencies
    • DNSTAP support is a compile-time option
      • Sometimes not enabled in distribution package code
        • Might requires compilation from source
    • fstrm (Frame Streams data transport protocol): lightweight protocol to transport frames of data, can be used with any data serialisation format that produces byte sequences https://github.com/farsightsec/fstrm
    • Google Protocol Buffers: Protocol buffers are a language-neutral, platform-neutral extensible mechanism for serialising structured data. https://developers.google.com/protocol-buffers/
  6. DNSTAP Receiver Tools
  7. Using DNSTAP with PowerDNS recursor
    • Installing the dnstap reader from the Debian 13 repositories
    % apt install golang-github-dnstap-golang-dnstap-cli dnstap-ldns
    
    • (Alternative): Installing the dnstap reader from source
    % apt install golang
    % go get -u github.com/dnstap/golang-dnstap/dnstap
    % mv ~/go/bin/dnstap /usr/local/bin/
    
    • DNSTAP can be enabled in the PowerDNS Lua configuration file /etc/powerdns/recursor.lua
    -- DNSTAP
    dnstapFrameStreamServer("127.0.0.1:9999", {logQueries=true, logResponses=true})
    
    • Start DNSTAP reader from the command line. For a production installation create a systemd unit. For forensic analysis, it is recommended to trigger the dnstap systemd unit from a system event (high load, unusual traffic pattern etc)
    % dnstap -l 127.0.0.1:9999
    
    • Restart the PowerDNS recursor
    • The DNSTAP reader will print out log information to stderr after successful connections from PowerDNS
    2021/11/01 09:52:35 127.0.0.1:9999: accepted connection 1 from 127.0.0.1:47500
    2021/11/01 09:52:35 127.0.0.1:9999: accepted connection 2 from 127.0.0.1:47502
    2021/11/01 09:52:35 127.0.0.1:9999: accepted connection 3 from 127.0.0.1:47504
    2021/11/01 09:52:35 127.0.0.1:9999: accepted connection 4 from 127.0.0.1:47506
    
    • Example DNSTAP reader output of a resolution for heise.de A
    09:55:02.069423 RQ 2001:500:1::53 UDP 31b "de." IN DS
    09:55:02.070849 RR 2001:500:1::53 UDP 366b "de." IN DS
    09:55:02.071227 RQ 192.203.230.10 UDP 31b "de." IN A
    09:55:02.079721 RR 192.203.230.10 UDP 736b "de." IN A
    09:55:02.080183 RQ 194.0.0.53 UDP 37b "heise.de." IN DS
    09:55:02.102337 RR 194.0.0.53 UDP 750b "heise.de." IN DS
    09:55:02.102529 RQ 77.67.63.105 UDP 31b "de." IN DNSKEY
    09:55:02.112821 RR 77.67.63.105 UDP 745b "de." IN DNSKEY
    09:55:02.113324 RQ 194.146.107.6 UDP 37b "heise.de." IN A
    09:55:02.126413 RR 194.146.107.6 UDP 810b "heise.de." IN A
    09:55:02.126897 RQ 2001:500:d937::30 UDP 45b "pop-hannover.net." IN A
    09:55:02.135566 RR 2001:500:d937::30 UDP 660b "pop-hannover.net." IN A
    09:55:02.135752 RQ 62.48.67.66 UDP 37b "heise.de." IN A
    09:55:02.145127 RR 62.48.67.66 UDP 255b "heise.de." IN A
    
    • In production environment, the DNSTAP data should be written to disk for later analysis. The command below will receive DNSTAP traffic on Port 9999 and write the DNSTAP data to a file
    % dnstap -l 127.0.0.1:9999 -w capture.dnstap
    
    • To read the DNSTAP data from the file, open the file with a DNSTAP reader
    % dnstap -r capture.dnstap
    
  8. Exercise

    • Install a DNSTAP reader on the PowerDNS recursor machine
    • Start the DNSTAP reader to listen on port 9999 and to print the output in verbose YAML format
    • Configure DNSTAP in the PowerDNS recursor Lua configuration file
    • Restart the PowerDNS recursor and send some test queries towards the recursor
    • Observe the output of the DNSTAP reader

6 DNS Security with PowerDNS products

6.1 DNSDist Load-Balancer

6.1.1 DNSDist Intro

6.1.2 Exercise

  1. Installing dnsdist
    • We work on the resolver machine pdnsrNNN.dnslab.org
    • We install dnsdist from the Debian 13 repositories
    apt install -y dnsdist
    
  2. DNSdist as load balancer for authoritative server
    • In this session we build a load balancer for our authoritative PowerDNS servers
    • Save and remove a previous dnsdist configuration /etc/dnsdist/dnsdist.conf and start with a clean file
    • We use Port 65053 on the IPv4 loopback address, as port 53 on all IP addresses is currently occupied by the PowerDNS recursor
    newServer({address="<ip-v6-address-of-server1>",   checkType="SOA", checkType=DNSClass.IN, checkName="zoneNNN.dnslab.org"})
    newServer({address="<ip-v6-address-of-server2>",   checkType="SOA", checkType=DNSClass.IN, checkName="zoneNNN.dnslab.org"})
    newServer({address="<ip-v4-address-of-server1>",   checkType="SOA", checkType=DNSClass.IN, checkName="zoneNNN.dnslab.org"})
    newServer({address="<ip-v4-address-of-server2>",   checkType="SOA", checkType=DNSClass.IN, checkName="zoneNNN.dnslab.org"})
    setServerPolicy(leastOutstanding)
    setLocal("127.0.0.1:65053")
    
    1. Starting dnsdist
      • check the configuration of dnsdist for syntax errors
      % /usr/bin/dnsdist -u dnsdist -g dnsdist --check-config
      Configuration '/etc/dnsdist/dnsdist.conf' OK!
      
      • enable and start the dnsdist service (or restart)
      % systemctl restart dnsdist
      
      • check that the service has been started without errors:
      % systemctl status dnsdist
         ● dnsdist.service - DNS Loadbalancer
           Loaded: loaded (/usr/lib/systemd/system/dnsdist.service; enabled; vendor preset: disabled)
           Active: active (running) since Wed 2021-04-21 07:45:47 UTC; 2min 26s ago
             Docs: man:dnsdist(1)
                   https://dnsdist.org
          Process: 27803 ExecStartPre=/usr/bin/dnsdist -u dnsdist -g dnsdist --check-config (code=exited, status=0/SUCCESS)
         Main PID: 27804 (dnsdist)
            Tasks: 25 (limit: 8192)
           Memory: 159.4M
           CGroup: /system.slice/dnsdist.service
                   └─27804 /usr/bin/dnsdist -u dnsdist -g dnsdist --supervised --disable-syslog
      
         Apr 21 07:47:21 dnsdist001 dnsdist[27804]: Marking downstream 149.20.1.73:53 as 'down'
         Apr 21 07:47:24 dnsdist001 dnsdist[27804]: Marking downstream 149.20.1.73:53 as 'up'
         Apr 21 07:47:37 dnsdist001 dnsdist[27804]: Marking downstream [2001:4f8:1:f::73]:53 as 'down'
         Apr 21 07:47:38 dnsdist001 dnsdist[27804]: Marking downstream [2001:4f8:1:f::73]:53 as 'up'
         Apr 21 07:47:50 dnsdist001 dnsdist[27804]: Marking downstream 149.20.1.73:53 as 'down'
         Apr 21 07:47:51 dnsdist001 dnsdist[27804]: Marking downstream 149.20.1.73:53 as 'up'
         Apr 21 07:47:58 dnsdist001 dnsdist[27804]: Marking downstream 149.20.1.73:53 as 'down'
         Apr 21 07:47:59 dnsdist001 dnsdist[27804]: Marking downstream 149.20.1.73:53 as 'up'
         Apr 21 07:48:05 dnsdist001 dnsdist[27804]: Marking downstream 149.20.1.73:53 as 'down'
         Apr 21 07:48:06 dnsdist001 dnsdist[27804]: Marking downstream 149.20.1.73:53 as 'up'
      
    2. Testing the load-balancing setup
      • we send the request to the port 65053 where dnsdist is listening
      % dig -p 65053 @localhost zoneNNN.dnslab.org +norec
      ; <<>> DiG 9.16.22-Debian <<>> -p 65053 @localhost zoneNNN.dnslab.org +norec
      ; (1 server found)
      ;; global options: +cmd
      ;; Got answer:
      ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43793
      ;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
      
      ;; OPT PSEUDOSECTION:
      ; EDNS: version: 0, flags:; udp: 1232
      ;; QUESTION SECTION:
      ;zoneNNN.dnslab.org.            IN      A
      
      ;; ANSWER SECTION:
      zoneNNN.dnslab.org.     60      IN      A       46.101.218.115
      
      ;; Query time: 3 msec
      ;; SERVER: 127.0.0.1#65053(127.0.0.1)
      ;; WHEN: Tue Nov 02 21:20:54 UTC 2021
      ;; MSG SIZE  rcvd: 63
      
      • The AA Flag tell us that the response comes indeed from an authoritative DNS server
    3. Configuring the dnsdist webserver
      • Add the following lines to the dnsdist configuration
      webserver("0.0.0.0:8853")
      setWebserverConfig({acl="0.0.0.0/0",password="dnsdist-is-great"})
      
      • Reload the dnsdist
      % systemctl restart dnsdist
      
      • Access the web-interface from a web browser
      http://pdnsrNNN.dnslab.org:8853/
      
  3. DNSdist as load balancer for DNS resolver
    • In this session we build a load balancer for multiple DNS resolver. We use the local PowerDNS recursor together with a selection of public DNS resolver
    • Save and remove a previous dnsdist configuration /etc/dnsdist/dnsdist.conf and start with a clean file
    • We use Port 65053 on the IPv4 loopback address, as port 53 on all IP addresses is currently occupied by the PowerDNS recursor
    newServer({address="127.0.0.1", qps=10000, order=1}) -- our PowerDNS recursor
    newServer({address="1.1.1.1",   qps=100, order=3})   -- Cloudflare Public DNS
    newServer({address="8.8.8.8",   qps=100, order=2})   -- Google Public DNS
    -- Cache
    pc = newPacketCache(10000, {maxTTL=86400, minTTL=0, temporaryFailureTTL=60, staleTTL=60, dontAge=false})
    getPool(""):setCache(pc)
    -- Load-balancing Policy
    setServerPolicy(leastOutstanding)
    -- local IP address for dnsdist
    setLocal("127.0.0.1:65053")
    
    1. (Re-)start dnsdist
      • check the configuration of dnsdist for syntax errors
      % dnsdist -u dnsdist -g dnsdist --check-config
      Configuration '/etc/dnsdist/dnsdist.conf' OK!
      
      • restart the dnsdist service
      % systemctl restart dnsdist
      
      • check that the service has been started without errors:
      % systemctl status dnsdist
         ● dnsdist.service - DNS Loadbalancer
         Loaded: loaded (/usr/lib/systemd/system/dnsdist.service; enabled; vendor preset: disabled)
         Active: active (running) since Wed 2021-04-21 08:20:01 UTC; 1min 34s ago
           Docs: man:dnsdist(1)
                 https://dnsdist.org
        Process: 29682 ExecStartPre=/usr/bin/dnsdist -u dnsdist -g dnsdist --check-config (code=exited, status=0/SUCCESS)
       Main PID: 29684 (dnsdist)
          Tasks: 23 (limit: 8192)
         Memory: 106.1M
         CGroup: /system.slice/dnsdist.service
                 └─29684 /usr/bin/dnsdist -u dnsdist -g dnsdist --supervised --disable-syslog
      
      Apr 21 08:20:01 dnsdist001 dnsdist[29684]: Listening on 127.0.0.1:65053
      Apr 21 08:20:01 dnsdist001 dnsdist[29684]: dnsdist 1.6.0-rc1 comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it according to>
      Apr 21 08:20:01 dnsdist001 dnsdist[29684]: ACL allowing queries from: 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.168.0.0/16, ::1/128, fc00>
      Apr 21 08:20:01 dnsdist001 dnsdist[29684]: Console ACL allowing connections from: 127.0.0.0/8, ::1/128
      Apr 21 08:20:01 dnsdist001 dnsdist[29684]: Webserver launched on 0.0.0.0:8053
      Apr 21 08:20:01 dnsdist001 dnsdist[29684]: Marking downstream 8.8.8.8:53 as 'up'
      Apr 21 08:20:01 dnsdist001 dnsdist[29684]: Marking downstream 1.1.1.1:53 as 'up'
      Apr 21 08:20:01 dnsdist001 dnsdist[29684]: Marking downstream 127.0.0.1:53 as 'up'
      Apr 21 08:20:01 dnsdist001 systemd[1]: Started DNS Loadbalancer.
      Apr 21 08:20:01 dnsdist001 dnsdist[29684]: Polled security status of version 1.6.0-rc1 at startup, no known issues reported: OK
      
    2. Testing the load-balancing setup
      • we send the request to the port 65053 where dnsdist is listening
      % dig -p 65053 @localhost powerdns.com
      
      ; <<>> DiG 9.16.22-Debian <<>> -p 65053 @localhost powerdns.com
      ; (1 server found)
      ;; global options: +cmd
      ;; Got answer:
      ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2499
      ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
      
      ;; OPT PSEUDOSECTION:
      ; EDNS: version: 0, flags:; udp: 512
      ;; QUESTION SECTION:
      ;powerdns.com.                  IN      A
      
      ;; ANSWER SECTION:
      powerdns.com.           3600    IN      A       188.166.104.92
      
      ;; Query time: 175 msec
      ;; SERVER: 127.0.0.1#65053(127.0.0.1)
      ;; WHEN: Tue Nov 02 21:53:37 UTC 2021
      ;; MSG SIZE  rcvd: 57
      
      • The RD and AD Flags tell us that the response comes indeed from a DNS resolver
    3. Configuring the dnsdist webserver
      • Add the following lines to the dnsdist configuration
      webserver("0.0.0.0:8853")
      setWebserverConfig({acl="0.0.0.0/0",password="dnsdist-is-great"})
      
      • Reload the dnsdist
      % systemctl restart dnsdist
      
      • Access the web-interface from a browser
      http://pdnsrXXX.dnslab.org:8853/
      
    4. More tests
      • Performance testing a DNS resolver with dnsblast
      • dnsblast is a simple tool that sends random DNS queries for the com TLD
      • compiling dnsblast
      % apt -y install gcc make
      % git clone https://github.com/jedisct1/dnsblast
      % cd dnsblast
      % make
      
      • We use dnsblast to send 5,000 queries at a rate of 100 qps to our dnsdist load-balancer at port 65053
      % ./dnsblast 127.0.0.1 5000 100 65053
      
  4. dnsdist as a DoT/DoH proxy
    • In this exercise, we will configure dnsdist as a DoH/DoT proxy for the PowerDNS recursor
    • Save and remove a previous dnsdist configuration /etc/dnsdist/dnsdist.conf and start with a clean file
    • Check that the PowerDNS recursor server is up and running (our pre-installed DNS resolver serving classic DNS over Port 53):
    % dig @localhost powerdns.com
    
    • the response should look like this
    ; <<>> DiG 9.16.22-Debian <<>> @localhost powerdns.com
    ; (1 server found)
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38445
    ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 512
    ;; QUESTION SECTION:
    ;powerdns.com.                  IN      A
    
    ;; ANSWER SECTION:
    powerdns.com.           3278    IN      A       188.166.104.92
    
    ;; Query time: 0 msec
    ;; SERVER: 127.0.0.1#53(127.0.0.1)
    ;; WHEN: Tue Nov 02 21:58:59 UTC 2021
    ;; MSG SIZE  rcvd: 57
    
    1. TLS x509 certificates
      • Our server already has x509 certificates for TLS from Let's Encrypt. We need to copy the certificate file and the private key file into the dnsdist configuration directory and adjust the file permissions, so that dnsdist can read the files
      % cp /etc/ssl/private/dnslab.* /etc/dnsdist/
      % chown _dnsdist: /etc/dnsdist/*
      
    2. Configuration for the "upstream" DNS resolver
      • first we need to tell dnsdist where to find the upstream (existing) DNS resolver. In our case, it is the PowerDNS recursor instance running on the same machine.
        • in dnsdist, you can specify any number of upstream servers with load-balancing parameters, please see the dnsdist website for documentation.
      • we create the file /etc/dnsdist/dnsdist.conf with one line of configuration that defines one upstream DNS resolver (use your favorite text editor nano, emacs, vim):
      newServer({address="127.0.0.1"})
      
    3. Configuration for DNS-over-TLS (DoT)
      • our DNS-over-TLS service will run on the (loop-back) IP-Address 127.0.0.10. In an production environment, this would be one of the external addresses of the proxy machine that is reachable from DNS clients.
        • the new configuration line for DoT defines the listen address, the x509 certificate and the private key matching the certificate
      • our configuration file /etc/dnsdist/dnsdist.conf should now look like this:
      newServer({address="127.0.0.1"})
      addTLSLocal('127.0.0.10',
            '/etc/dnsdist/dnslab.crt',
            '/etc/dnsdist/dnslab.key')
      
    4. Starting dnsdist
      • check the configuration of dnsdist for syntax errors
      % dnsdist -u dnsdist -g dnsdist --check-config
      Configuration '/etc/dnsdist/dnsdist.conf' OK!
      
      • restart the dnsdist service
      % systemctl restart dnsdist
      
      • check that the service has been started without errors:
      % systemctl status dnsdist
         ● dnsdist.service - DNS Loadbalancer
            Loaded: loaded (/usr/lib/systemd/system/dnsdist.service; enabled; vendor preset: disabled)
            Active: active (running) since Tue 2021-02-09 09:05:34 UTC; 17s ago
              Docs: man:dnsdist(1)
                    https://dnsdist.org
           Process: 111443 ExecStartPre=/usr/bin/dnsdist -u dnsdist -g dnsdist --check-config (code=exited, status=0/SUCCESS)
          Main PID: 111445 (dnsdist)
             Tasks: 19 (limit: 8192)
            Memory: 28.2M
            CGroup: /system.slice/dnsdist.service
                     └─111445 /usr/bin/dnsdist -u dnsdist -g dnsdist --supervised --disable-syslog
      
         Feb 09 09:05:34 doh01 systemd[1]: Stopped DNS Loadbalancer.
         Feb 09 09:05:34 doh01 systemd[1]: Starting DNS Loadbalancer...
         Feb 09 09:05:34 doh01 dnsdist[111445]: Added downstream server 127.0.0.1:53
         Feb 09 09:05:34 doh01 dnsdist[111445]: Listening on 127.0.0.10:853 for TLS
         Feb 09 09:05:34 doh01 dnsdist[111445]: dnsdist 1.6.0-alpha1 comes with ABSOLUTELY NO WARRANTY. This is free software, and you are we>
         Feb 09 09:05:34 doh01 dnsdist[111445]: ACL allowing queries from: 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0>
         Feb 09 09:05:34 doh01 dnsdist[111445]: Console ACL allowing connections from: 127.0.0.0/8, ::1/128
         Feb 09 09:05:34 doh01 dnsdist[111445]: Marking downstream 127.0.0.1:53 as 'up'
         Feb 09 09:05:34 doh01 systemd[1]: Started DNS Loadbalancer.
         Feb 09 09:05:35 doh01 dnsdist[111445]: Polled security status of version 1.6.0-alpha1 at startup, no known issues reported: OK
      
    5. Testing the DoT setup
      • we use kdig, the DNS query tool from the Knot DNS Server, to send DNS over TLS queries to our server. But first we install kdig
      % apt install knot-dnsutils
      
      • and now we test DNS-over-TLS
      % kdig @127.0.0.10 powerdns.com +tls
      ;; TLS session (TLS1.3)-(ECDHE-SECP256R1)-(ECDSA-SECP256R1-SHA256)-(AES-256-GCM)
      ;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 13574
      ;; Flags: qr rd ra; QUERY: 1; ANSWER: 1; AUTHORITY: 0; ADDITIONAL: 1
      
      ;; EDNS PSEUDOSECTION:
      ;; Version: 0; flags: ; UDP size: 512 B; ext-rcode: NOERROR
      
      ;; QUESTION SECTION:
      ;; powerdns.com.                IN      A
      
      ;; ANSWER SECTION:
      powerdns.com.           2450    IN      A       188.166.104.92
      
      ;; Received 57 B
      ;; Time 2021-11-02 22:12:47 UTC
      ;; From 127.0.0.10@853(TCP) in 0.0 ms
      
      • kdig will print information on the TLS connection in the first line:
      ;; TLS session (TLS1.3)-(ECDHE-SECP256R1)-(RSA-PSS-RSAE-SHA256)-(AES-256-GCM)
      
    6. Configuration for DNS-over-HTTPS (DoH)
      • the configuration for DNS-over-HTTPS is very similar to the DoT configuration. Please add the following line (replace the XXX with your participant number) to the file /etc/dnsdist/dnsdist.conf:
      addDOHLocal('127.0.0.10:8443',
          '/etc/dnsdist/dnslab.crt',
          '/etc/dnsdist/dnslab.key')
      
      • check the configuration file for errors
      % dnsdist -u dnsdist -g dnsdist --check-config
      
      • and if no errors are reported, restart the dnsdist service
      % systemctl restart dnsdist
      
      • check that the service has been (re-)started
      % systemctl status dnsdist
         ● dnsdist.service - DNS Loadbalancer
            Loaded: loaded (/usr/lib/systemd/system/dnsdist.service; enabled; vendor preset: disabled)
            Active: active (running) since Tue 2021-02-09 09:12:03 UTC; 5s ago
              Docs: man:dnsdist(1)
                    https://dnsdist.org
           Process: 112038 ExecStartPre=/usr/bin/dnsdist -u dnsdist -g dnsdist --check-config (code=exited, status=0/SUCCESS)
          Main PID: 112040 (dnsdist)
             Tasks: 21 (limit: 8192)
            Memory: 31.2M
            CGroup: /system.slice/dnsdist.service
                    └─112040 /usr/bin/dnsdist -u dnsdist -g dnsdist --supervised --disable-syslog
      
         Feb 09 09:12:02 doh01 systemd[1]: Starting DNS Loadbalancer...
         Feb 09 09:12:03 doh01 dnsdist[112040]: Added downstream server 127.0.0.1:53
         Feb 09 09:12:03 doh01 dnsdist[112040]: Listening on 127.0.0.10:853 for TLS
         Feb 09 09:12:03 doh01 dnsdist[112040]: Listening on 127.0.0.10:443 for DoH
         Feb 09 09:12:03 doh01 dnsdist[112040]: dnsdist 1.6.0-alpha1 comes with ABSOLUTELY NO WARRANTY. This is free software, and you are we>
         Feb 09 09:12:03 doh01 dnsdist[112040]: ACL allowing queries from: 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0>
         Feb 09 09:12:03 doh01 dnsdist[112040]: Console ACL allowing connections from: 127.0.0.0/8, ::1/128
         Feb 09 09:12:03 doh01 dnsdist[112040]: Marking downstream 127.0.0.1:53 as 'up'
         Feb 09 09:12:03 doh01 systemd[1]: Started DNS Loadbalancer.
         Feb 09 09:12:03 doh01 dnsdist[112040]: Polled security status of version 1.6.0-alpha1 at startup, no known issues reported: OK
      
    7. Testing DNS-over-HTTPS
      • Again we use the kdig tool to test our new DNS-over-HTTPS service:
      % kdig -p 8443 @127.0.0.10 powerdns.com +https
      ;; TLS session (TLS1.3)-(ECDHE-SECP256R1)-(ECDSA-SECP256R1-SHA256)-(AES-256-GCM)
      ;; HTTP session (HTTP/2-POST)-(127.0.0.10/dns-query)-(status: 200)
      ;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 0
      ;; Flags: qr rd ra; QUERY: 1; ANSWER: 1; AUTHORITY: 0; ADDITIONAL: 1
      
      ;; EDNS PSEUDOSECTION:
      ;; Version: 0; flags: ; UDP size: 512 B; ext-rcode: NOERROR
      
      ;; QUESTION SECTION:
      ;; powerdns.com.                IN      A
      
      ;; ANSWER SECTION:
      powerdns.com.           2159    IN      A       188.166.104.92
      
      ;; Received 57 B
      ;; Time 2021-11-02 22:17:38 UTC
      ;; From 127.0.0.10@8443(TCP) in 0.1 ms
      
      • kdig print information about the TLS and HTTPS connection in the first two lines:
      ;; TLS session (TLS1.3)-(ECDHE-SECP256R1)-(RSA-PSS-RSAE-SHA256)-(AES-256-GCM)
      ;; HTTPS session (HTTP/2-POST)-(127.0.0.10/dns-query)-(status: 200)
      

6.2 Response Rate Limiting

  • Response Rate Limiting (RRL) reduces query responses sent by a DNS server.
    • RRL is a defense against reflection/amplification DoS attacks
    • Clients IPs are grouped into buckets. (e.g. 256 IPv4's)
    • Identical responses to the same bucket are tracked.
    • If identical responses go over a set rate, RRL kicks in.
    • RRL significantly reduces the effect of using a domain name from a zone the server is authoritative for in a reflection attack.
    • RRL is applicable to UDP queries, not those over TCP.
  • A server drops or truncates when queries exceed its set rate.
    • A valid client will likely re-query in response to a drop.
    • Truncation prevents amplification but not reflection.
    • Legitimate clients will re-query with TCP and get a reply.
    • A valid client is only negatively effected, if its query is identical to the attacks, and is in a bucket being spoofed.
  • RRL Info Website http://www.redbarn.org/dns/ratelimits

6.2.1 PowerDNS Authoritative

6.2.2 DNSdist

6.2.3 PowerDNS Recursor

  • The PowerDNS recursor implements a query rate limiting when it detects that a upstream authoritative server becomes unresponsive
    • This prevents that the upstream authoritative DNS server get more overloaded by repeated queries from the DNS resolver
    • non-resolving-ns-max-fails - Number of failed address resolves of a nameserver name to start throttling it, 0 is disabled. Default: 5
      • dont-throttle-names exclude name server from throttling, can be set dynamically with rec_control add-dont-throttle-names NAME [NAME…]
      • dont-throttle-netmasks exclude name servers from these networks from throttling, can be set dynamically with rec_control add-dont-throttle-netmasks NETMASK [NETMASK…]
      • non-resolving-ns-max-throttle-time Number of seconds to throttle a nameserver with a name failing to resolve
    • server-down-max-fails If a server has not responded in any way this many times in a row, no longer send it any queries for server-down-throttle-time seconds. Afterwards, the resolver will try a new packet, and if that also gets no response at all, it will again throttle for server-down-throttle-time seconds. Even a single response packet will clear the block.
    • Controlling the throttle lists
      • rec_control get-dont-throttle-names will print out the throttle exceptions for name server
      • rec_control get-dont-throttle-netmasks will print out the throttle exceptions for networks
      • rec_control dump-throttlemap FILENAME will write the throttle list to a file
      • rec_control clear-dont-throttle-names NAME [NAME…] will remove a server from the throttle lust
      • rec_control clear-dont-throttle-netmasks NETMASK [NETMASK…] will remove a network from a throttle list

6.3 Cryptography in DNS (Symmetric / Asymmetric), Transaction Signatures (TSIG)

6.3.1 Cryptography for DNS Admins

  • Cryptography has four purposes:
    • Confidentiality – keeping data secret
    • Integrity – Is it "as sent"?
    • Authentication – Did it come from the right place?
    • Non-Repudiation – Don’t tell me you didn't say that.
  • DNSSEC implements: Authentication & Integrity
  • The IETF has added confidentiality since 2016:
  • DNS uses different authenticity and integrity techniques depending on the application.
  • Symmetric Cryptography
    • Message Digests (aka: hashes, hash values, fingerprints)
    • Message Authentication Codes
  • Asymmetric Cryptography
    • Digital Signatures

6.3.2 Symmetric Cryptography

  • Symmetric cryptography provides both integrity and authenticity.
  • A single key is stored and used by both (all) parties.
    • The key encrypts and decrypts.
    • The key is a shared secret.
    • The system is known as pre-shared key (PSK).
    • Securely getting the key to all parties can be a challenge.
  • Symmetric cryptography requires mutual trust.
    • "My security is good, but what about the other person's?"
    • If all sides are administered by one party, trust is a non-issue.
    • For DNS, Pre-Shared-Keys (PSK) work well:
      • between primary and secondary servers (TSIG).
      • for dynamic DNS updates (TSIG).
      • for controlling BIND 9 with rndc (TSIG).
    • For DNS, PSKs do not work well:
      • between DNS Resolver servers and auth servers (DNSSEC).
      • between stub resolvers & DNS Resolver servers (DNSSEC amongst other).

6.3.3 Confidentiality: Not the Goal

  • A Pre-Shared Key (PSK) could be used to encrypt a message.
  • If it decrypts, confidentially, integrity, and authenticity are assured.
  • However, confidentiality was not a design goal (of DNSSEC).
  • Encrypting everything is computationally expensive.
  • The alternative is more complicated but less expensive.

6.3.4 Message Digest

  • Creating a hash of the message is a light-weight alternative to encrypting everything.
    • A hash is also known as a hash value, a message digest (MD) and a fingerprint.
  • The sender runs a cryptographic hashing algorithm on the message to produce a fixed-length hash.
    • The message and hash are sent over an insecure path.
  • As the sender did, the receiver hashes the message.
  • If the hashes match, the message was not modified. Message integrity is proven.
  • However, the receiver does not know if the message and hash were both replaced: Message authenticity is unknown.
  • Confidentiality is not provided.

6.3.5 Message Authentication Codes

  • Hashing, with a symmetric key added to the input, efficiently provides integrity and authenticity.
    • There is no confidentiality.
    • A MAC is a fingerprint (MD, hash) created with the message and a PSK as input.
    • The MAC described here, is a keyed HMAC (Hash-based message authentication code).
      • It is used by DNS.

HMAC.png

  • Although HMACs efficiently assure both the sender's authenticity, and the message's integrity, not all applications can use (pre)shared keys.
    • "Am I really seeing the website mybank.example?"
    • "Is the email I'm reading really from Edward Snowden?"
    • "Is this RRSet actually for theguardian.com?"

6.3.6 Asymmetric Cryptography

  • In DNS, asymmetric cryptography is used for DNSSEC.
  • This asymmetric cryptography section is a short overview.
  • Asymmetric cryptography uses two keys, a pair.
    • Data encrypted with one key can only be decrypted by the other.
    • A key cannot decrypt what it encrypted!
    • One key of a pair is declared as public, the other as private.
    • The private key is highly sensitive, never shared, and must be well protected.
    • The public key is made widely available without concern for who knows it.
    • The technique is known as public key encryption.

      Asymmetric-crypto.png

6.3.7 Two Applications for public key (PK) Encryption

  • PK encryption is used for privacy, to assure only the intended receiver can read a message.
    • Data integrity is also assured.
    • used in DNS-over-TLS and DNS-over-HTTPS
  • PK encryption is used for authenticity, assuring the recipient, that the message came from a specific sender.
    • This is known as signing a message.
    • Data integrity is also assured.
    • used in DNSSEC, as well in DNS-over-TLS and DNS-over-HTTPS

6.3.8 PK Application 2: Encryption for Authenticity

  • To assure authenticity, a sender encrypts a message with her private key.
    • Anyone decrypting the message with the public key is assured it came from the holder of the private key.
  • The message is encrypted, but there is no privacy. Asymmetric-crypto.png

6.3.9 PK Application 2: Encryption for Authenticity: Digital Signatures

  • For efficiency, the message itself is not encrypted.
    • The message is first hashed to create a fingerprint.
    • The fingerprint is encrypted.
    • The signed fingerprint is a digital signature (aka encrypted fingerprint and encrypted hash).

A fingerprint is also known as a hash, digest, or message digest. A signature is not the same thing. However, the terms are often used interchangeably.

6.3.10 Digital Signatures in DNSSEC

Signatures-in-DNSSEC.png

6.4 Transaction Signatures (TSIG)

  • TSIGs secure the communication of two endpoints.
    • TSIGs uses HMAC (i.e. symmetric encryption).
    • Trust is required between all systems (all endpoints).
    • Securely installing the key on all systems is external to DNS.
    • The endpoints must have reasonably accurate clocks.
  • TSIG is independent of DNSSEC.
  • TSIG use cases:
    • DNS dynamic updates (client / dhcp-server <-> server)
    • BIND server control messages (rndc <-> server)
    • Server communication (zone transfers, notifies, queries, …)
    • Queries (client <-> server): Impractical and rare.

      tsig-message.png

  • A TSIG is a dynamically generated pseudo-RR.
    • TSIG RRs are not found in zone files, but do have the standard format of RRs.
    • TSIGs are never cached (TTL=0).
    • A TSIG RR is sent in the additional section.
    • A TSIG assures the integrity and authenticity of the entire DNS message.

      tsig-overview.png

  • TSIG offers a choice of HMAC algorithms:
    • hmac-md5 (deprecated)
    • hmac-sha1 (deprecated)
    • hmac-sha224
    • hmac-sha256
    • hmac-sha384
    • hmac-sha512
  • All the algorithms take a random length input and create a fixed length fingerprint.
    Algorithm fingerprint length
    MD5 16 byte
    SHA1 20 byte
    SHA256 32 byte
    SHA512 64 byte

6.4.1 TSIG with PowerDNS

  • TSIG is based on symmetric crypto
    • The same TSIG key for a zone should be configured on the primary and on the secondary
    • Zone can share keys, but it is recommended to have one key per zone
      • Or even one key per communication (primary -> secondary)
  • TSIG signatures are time sensitive: the TSIG signature on DNS messages contain a timestamp
    • TSIG only allows little skew between the clocks of both communication endpoints (~ 5 Minutes)
    • Make sure your DNS server always have the up-to-date time using a time synchronization protocol such as NTP
  • On the primary (master) generate a new TSIG key. By convention, the key is named <primary-hostname>-<secondary-hostname>, but can have any name. It is important that the key name has the same name on both endpoints of the communication
[primary]% pdnsutil generate-tsig-key pdns010a-pdns010b hmac-sha512
Create new TSIG key pdns010a-pdns010b hmac-sha512 L5jN+m3yTSfwoU2A43M0C/+0m7afqO1wL4OLd2auFEcA3MYyvJHixwHa0l0gZWRec10MQSw5bUByygkbJyQ/BA==
  • On the primary (master), the key is activated to be used for the outgoing NOTIFY messages
[primary]% pdnsutil activate-tsig-key zoneNNN.dnslab.org pdns010a-pdns010b master
Enabled TSIG key pdns010a-pdns010b for zoneNNN.dnslab.org
  • On the secondary (slave), import the same key (same name!)
[secondary]% pdnsutil import-tsig-key pdns010a-pdns010b hmac-sha512 L5jN+m3yTSfwoU2A43M0C/+0m7afqO1wL4OLd2auFEcA3MYyvJHixwHa0l0gZWRec10MQSw5bUByygkbJyQ/BA==
Imported TSIG key pdns010a-pdns010b hmac-sha512
  • On the secondary, the is used to sign the AXFR (Zone-transfer) requests. Once the TSIG keys are in place and activated, the allow-axfr-ips configuration is not required anymore
[secondary]% pdnsutil activate-tsig-key zoneNNN.dnslab.org pdns010a-pdns010b slave
Enabled TSIG key pdns010a-pdns010b for zoneNNN.dnslab.org
  • Log output on the primary server for a TSIG signed AXFR request
Nov 03 21:29:26 pdnsa010 pdns_server[59737]: Remote 142.93.145.28 wants 'zoneNNN.dnslab.org|SOA', do = 0, bufsize = 512: packetcache MISS
Nov 03 21:29:26 pdnsa010 pdns_server[59737]: AXFR-out zone 'zoneNNN.dnslab.org', client '142.93.145.28:56771', transfer initiated
Nov 03 21:29:26 pdnsa010 pdns_server[59737]: AXFR-out zone 'zoneNNN.dnslab.org', client '142.93.145.28:56771', allowed: TSIG signed request with authorized key 'pdns010a-pdns010b' and algorithm 'hmac-sha512'
  • Log on the secondary server
Nov 03 21:29:26 pdnsb010 pdns_server[34111]: AXFR-in zone: 'zoneNNN.dnslab.org', primary: '46.101.218.115', zone committed with serial 1635974966
  • When using the autoprimary/supermaster function of PowerDNS, after deploying TSIG keys, the setting allow-unsigned-autoprimary / allow-unsigned-supermaster should be set to no to only allow TSIG signed NOTIFY to create new zones
  • On the secondary, the setting allow-unsigned-notify should be set to no to only allow TSIG signed NOTIFY

6.4.2 Exercise

  • Create a new TSIG key (on the primary machine) to secure the zone transfer between the primary and the secondary
  • Import the TSIG key on the secondary
  • Mark the TSIG key as active for the zone zoneNNN.dnslab.org on both sides (see above=
  • Increment the SOA serial with pdnsutil
  • Check that NOTIFY messages and AXFR requests are coming, and that the AXFR is TSIG secured (check the log files)

6.5 Negative Trust Anchor in PowerDNS recursor

6.5.1 Dealing with DNSSEC resolver issues

  • often DNSSEC validation issues are caused by operational issues (expired DNSSEC signatures, DS record and DNSKEY KSK mismatch etc)
    • Negative Trust Anchors can be used to disable DNSSEC validation for mis-configured domains
  • Negative Trust Anchors are defined in RFC 7646 Definition and Use of DNSSEC Negative Trust Anchors
  • negative trust anchors (nta) disable DNSSEC validation for a specific domain for a certain amount of time
    • NTA can be used by operators in case a misconfiguration for a remote DNSSEC signed zone is detected. Care should be take to check that the DNSSEC validation failure is indeed a misconfiguration and not attack
  • domains with an NTA are processed as if there is no trust-anchor for that domain
  • NTAs should always have an operational lifetime
    • Don't add a NTA and forget about it
    • Re-evaluate the NTA every few days
    • Having an NTA configured should flag a warning in the monitoring system
    • Remove the NTA as soon as the DNSSEC issue is fixed
  • Example: adding an NTA:
% rec_control add-nta example.com 'Signatures expired'
  • Example: list active NTAs in the PowerDNS recursor
% rec_control get-ntas
  • Example: removing an NTA
% rec_control clear-nta example.com
  • Removing all NTAs (be careful!)
% rec_control clear-nta '*'

6.5.2 Exercise: negative trust anchor for failNN.dnssec.works

  • Work on the DNS resolver (PowerDNS recursor) machine
  • There are the broken DNS zones fail01.dnssec.works to fail05.dnssec.works
  • Create negative trust anchor (NTA) for fail01 to fail03 in your DNSSEC validating resolver machine dnsrNNN
  • Check that a client can now retrieve DNS data from these zones
    $ dig @127.0.0.1 fail01.dnssec.works A
    
  • Remove the NTA for fail01.dnssec.works. Check that the zone now does not validate and return SERVFAIL

6.6 DNSSEC signing with PowerDNS

6.6.1 Add DNSSEC to an existing zone

  • To sign DNS zone inside PowerDNS, a basic DNSSEC configuration must be added to the configuration
    • For the MySQL/MariaDB backend, the backend needs to have DNSSEC enabled with gmysql-dnssec
    • It is a good idea to have a basic DNSSEC signing policy (default key algorithms and sizes, NSEC3 iterations and how the SOA serial is incremented). Increment the SOA serial is important in a primary/secondary setup with classic DNS zone transfer.
# DNSSEC
gmysql-dnssec
default-ksk-algorithm=rsasha256
default-ksk-size=2048
default-zsk-algorithm=rsasha256
default-zsk-size=1024
max-nsec3-iterations=100
default-soa-edit-signed=EPOCH
  • First step of signing a zone is to create a zone signing key (ZSK). For RSA keys, the ZSK usually is smaller than the KSK.
% pdnsutil add-zone-key zoneNNN.dnslab.org ZSK active published 1536 rsasha256
Added a ZSK with algorithm = 8, active=1
Requested specific key size of 1536 bits
1
  • Next step is the creation of the key signing key (KSK)
% pdnsutil add-zone-key zoneNNN.dnslab.org KSK active published 2048 rsasha256
Added a KSK with algorithm = 8, active=1
Requested specific key size of 2048 bits
2
  • The command pdnsutil show-zone <zone-name> will show the zone keys, including the delegation signer (DS) record that need to go into the parent zone
% pdnsutil show-zone zoneNNN.dnslab.org
This is a Master zone
Last SOA serial number we notified: 1012 == 1012 (serial in the database)
Metadata items: None
Zone has NSEC semantics
keys:
ID = 1 (ZSK), flags = 256, tag = 37441, algo = 8, bits = 1536     Active         Published  ( RSASHA256 )
ID = 2 (KSK), flags = 257, tag = 26177, algo = 8, bits = 2048     Active         Published  ( RSASHA256 )
KSK DNSKEY = zoneNNN.dnslab.org. IN DNSKEY 257 3 8 AwEAAdmaHnizfuBb89XXhYBoQBnsJ/d+K7zkelu8rAvbsk3pzgwWMEufNXEqBxyQxxKYmqk/m+Wcq2UtuGnRugMfk2iaCod9DHp2iJj9qZ6C2Gqv9jVzwK1OE3yHq9xTuzq408ibgrxQvhZwYcH4mbqTlopFz/qACNKYdr52zCFnmK3cjHSphNqo3pGlBBGFLrXdLS8oHW6Ec+G7DObTqk+rGUuKHCStG0qPKoKj20L0j2frmcG5h5X0aH+7vHyBeikwuJoyqiwmEg0PYmknAnicuh3ubcPB5P+5ZcItpe6xY52eKqWIjsjcZI0aUmlOqI/ISuwP5b7UhYPgEc8JWlu6T9E= ; ( RSASHA256 )
DS = zoneNNN.dnslab.org. IN DS 26177 8 1 2416dc421e6debc0c0fd75b8742086df862f054f ; ( SHA1 digest )
DS = zoneNNN.dnslab.org. IN DS 26177 8 2 5993bff9c0f53af0162495f9b5c72a8fc5d05b24602e3905d3f4641da55a6f2c ; ( SHA256 digest )
DS = zoneNNN.dnslab.org. IN DS 26177 8 4 2810a931cf90eb4977eafdaaa3cfc8d90bb439ab836b3e05b23aef88ea0368f200a1b145472d36efc1b40c3567af3e71 ; ( SHA-384 digest )
  • As the keys are active, PowerDNS will start signing the responses with RRSIG records
# dig @localhost zoneNNN.dnslab.org soa +dnssec +multi

; <<>> DiG 9.16.22-Debian <<>> @localhost zoneNNN.dnslab.org soa +dnssec +multi
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44805
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
;; QUESTION SECTION:
;zoneNNN.dnslab.org.    IN SOA

;; ANSWER SECTION:
zoneNNN.dnslab.org.     60 IN SOA pdns010a.dnslab.org. hostmaster.zoneNNN.dnslab.org. (
                                1012       ; serial
                                3600       ; refresh (1 hour)
                                1800       ; retry (30 minutes)
                                3542400    ; expire (5 weeks 6 days)
                                60         ; minimum (1 minute)
                                )
zoneNNN.dnslab.org.     60 IN RRSIG SOA 8 3 60 (
                                20211111000000 20211021000000 37441 zoneNNN.dnslab.org.
                                InqX6esX3pl2GdGratuae544DO41egiVRLaLIPa41c9H
                                JqJjr2uMH5IcUtRtfDX4q296SSq5nNL9aouDtrvw+zNN
                                xGc/0qJ/aVr/uTqEXJBLGVbdZnCjpfvYNrDh3IIMBcSm
                                2TVifrT6JuGvIRUB/GskXvTYIDZW5DQ3YVP131sp4u9t
                                SgKWDvdt93N43maqy0imqJKwU7mV+t9Rx+El37c/CQZD
                                V+ERB5enFiqUr8e08wjc7rvDLAMFzBYbnc+3 )

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Nov 03 19:48:02 UTC 2021
;; MSG SIZE  rcvd: 345

  • The default authenticated denial of existence is NSEC, so there are NSEC records
% dig @localhost zoneNNN.dnslab.org srv +dnssec +multi

; <<>> DiG 9.16.22-Debian <<>> @localhost zoneNNN.dnslab.org srv +dnssec +multi
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39295
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 4, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
;; QUESTION SECTION:
;zoneNNN.dnslab.org.    IN SRV

;; AUTHORITY SECTION:
zoneNNN.dnslab.org.     60 IN SOA pdns010a.dnslab.org. hostmaster.zoneNNN.dnslab.org. (
                                1012       ; serial
                                3600       ; refresh (1 hour)
                                1800       ; retry (30 minutes)
                                3542400    ; expire (5 weeks 6 days)
                                60         ; minimum (1 minute)
                                )
zoneNNN.dnslab.org.     60 IN RRSIG SOA 8 3 60 (
                                20211111000000 20211021000000 37441 zoneNNN.dnslab.org.
                                InqX6esX3pl2GdGratuae544DO41egiVRLaLIPa41c9H
                                JqJjr2uMH5IcUtRtfDX4q296SSq5nNL9aouDtrvw+zNN
                                xGc/0qJ/aVr/uTqEXJBLGVbdZnCjpfvYNrDh3IIMBcSm
                                2TVifrT6JuGvIRUB/GskXvTYIDZW5DQ3YVP131sp4u9t
                                SgKWDvdt93N43maqy0imqJKwU7mV+t9Rx+El37c/CQZD
                                V+ERB5enFiqUr8e08wjc7rvDLAMFzBYbnc+3 )
zoneNNN.dnslab.org.     60 IN NSEC zoneNNN.dnslab.org. A NS SOA RRSIG NSEC DNSKEY
zoneNNN.dnslab.org.     60 IN RRSIG NSEC 8 3 60 (
                                20211111000000 20211021000000 37441 zoneNNN.dnslab.org.
                                QYedsQarfZicH7Pbawra6TAUH2XPK6zuH+jaVjKVffOe
                                GFyCDNwTxIx8U8MT7ntR1mJxUjuFf+byftkS3WkNxxNa
                                Fs+73xLeWgro+J3zY2t+M4rozZBdHKX0zsU0b/XMDYl+
                                PW5w+0zgcIoTs7aTexwsHg587TwaluBZI6sQhxLJ0tsB
                                wPOEu7BoIBhCaTqrgI4aQiK6uO3R9k2f5pieXrxtDHNC
                                lDf/3cdgIhMPQkpIeB7Pph1f+5bHfZ01JBPd )

;; Query time: 7 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Nov 03 19:48:52 UTC 2021
;; MSG SIZE  rcvd: 628

  • After making changes to a DNSSEC signed zone, it is always advised to execute pdnsutil rectify-zone <zone-name>. rectify-zone will recreate missing signatures and NSEC/NSEC3 records. rectify-zone is important when making changes to the zone on the database level or through the API. For zones that are managed through the API, set the API-RECTIFY meta-data on the zone, or make sure that default-api-rectify is set to yes in the configuration
% pdnsutil rectify-zone zoneNNN.dnslab.org
Adding NSEC ordering information
  • Send the DS-Record or the DNSKEY record of the KSK to the operator of the parent zone. The DS-Record(s) and the DNSKEY-Record can be listed with pdnsutil show-zone <zonename>
  • Add a new record
% pdnsutil add-record zoneNNN.dnslab.org test TXT 60 '"Hello PowerDNS"'
New rrset:
test.zoneNNN.dnslab.org. 60 IN TXT "Hello PowerDNS"
test.zoneNNN.dnslab.org. 60 IN TXT "Hello DNSSEC"
  • The new record (set) is immediately signed
% dig @localhost test.zoneNNN.dnslab.org.  txt +dnssec

; <<>> DiG 9.16.22-Debian <<>> @localhost test.zoneNNN.dnslab.org. txt +dnssec
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10652
;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
;; QUESTION SECTION:
;test.zoneNNN.dnslab.org.       IN      TXT

;; ANSWER SECTION:
test.zoneNNN.dnslab.org. 60     IN      RRSIG   TXT 8 4 60 20211111000000 20211021000000 37441 zoneNNN.dnslab.org. H0MNWJ/xP9xfLYxaTaqEyhe+jLszDxZ4MP6AR6pz1S3GsHhMktR3/P6u DrBihkZlNMi+7ZhTWHFmndCwd9vK/nnaHZXNV2JL72oMPS4vhXWgw6AP T+mUsOkRyHudJRoASpyOOPhqGxjDVUXanDdpbVAfoEjhWnZ6a+NWC47C 04zT/4NSaIpZPtCIYKftbiPB0CjEFPsViloRNAUFwbYHZ4o9TZYdDekQ nOXAapLooAh0DFk21ijjrVV1jbigS6oV
test.zoneNNN.dnslab.org. 60     IN      TXT     "Hello PowerDNS"
test.zoneNNN.dnslab.org. 60     IN      TXT     "Hello DNSSEC"

;; Query time: 3 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Nov 03 20:03:34 UTC 2021
;; MSG SIZE  rcvd: 346

  • After making changes to a DNSSEC signed zone, it is a good idea to increment the SOA serial a last time and fix the DNSSEC NSEC(3) chain in the zone with rectify-zone
% pdnsutil increase-serial zoneNNN.dnslab.org
% pdnsutil rectify-zone zoneNNN.dnslab.org
  • Check for a successful zone transfer to all secondary DNS server of the zone

6.6.2 Exercise

  • Add the required DNSSEC configuration statements to the PowerDNS configuration, check and reload the PowerDNS service
  • Add a ZSK and KSK with the ECDSA algorithm to the zone zoneNNN.dnslab.org
  • Rectify the zone and increment the SOA serial number
  • Show the DS-Record for the zone, send it by email to the trainer (use cs@sys4.de)
  • Wait for the DS-Record to arrive in the parent zone (dnslab.org)
  • Query a record from this zone on the PowerDNS recursor machine, check for the AD-Flag that indicates successful DNSSEC validation

6.7 DNSSEC Key-Rollover

6.7.1 ZSK rollover with pre-publication

  • To start a ZSK key rollover for a zone on PowerDNS, create and publish (but don't activate) a new ZSK. The new key should have the same algorithm then the previous key. The size can be different.
% pdnsutil add-zone-key zoneNNN.dnslab.org ZSK inactive published 1536 rsasha256
Added a ZSK with algorithm = 8, active=1
Requested specific key size of 1536 bits
3
  • The zone should now have 2 ZSK DNSKEY records published
% pdnsutil show-zone zoneNNN.dnslab.org
This is a Master zone
Last SOA serial number we notified: 1635970166 == 1635970166 (serial in the database)
Metadata items: None
Zone has NSEC semantics
keys:
ID = 1 (ZSK), flags = 256, tag = 37441, algo = 8, bits = 1536     Active         Published  ( RSASHA256 )
ID = 4 (ZSK), flags = 256, tag = 14634, algo = 8, bits = 1536   Inactive         Published  ( RSASHA256 )
ID = 2 (KSK), flags = 257, tag = 26177, algo = 8, bits = 2048     Active         Published  ( RSASHA256 )
KSK DNSKEY = zoneNNN.dnslab.org. IN DNSKEY 257 3 8 AwEAAdmaHnizfuBb89XXhYBoQBnsJ/d+K7zkelu8rAvbsk3pzgwWMEufNXEqBxyQxxKYmqk/m+Wcq2UtuGnRugMfk2iaCod9DHp2iJj9qZ6C2Gqv9jVzwK1OE3yHq9xTuzq408ibgrxQvhZwYcH4mbqTlopFz/qACNKYdr52zCFnmK3cjHSphNqo3pGlBBGFLrXdLS8oHW6Ec+G7DObTqk+rGUuKHCStG0qPKoKj20L0j2frmcG5h5X0aH+7vHyBeikwuJoyqiwmEg0PYmknAnicuh3ubcPB5P+5ZcItpe6xY52eKqWIjsjcZI0aUmlOqI/ISuwP5b7UhYPgEc8JWlu6T9E= ; ( RSASHA256 )
DS = zoneNNN.dnslab.org. IN DS 26177 8 1 2416dc421e6debc0c0fd75b8742086df862f054f ; ( SHA1 digest )
DS = zoneNNN.dnslab.org. IN DS 26177 8 2 5993bff9c0f53af0162495f9b5c72a8fc5d05b24602e3905d3f4641da55a6f2c ; ( SHA256 digest )
DS = zoneNNN.dnslab.org. IN DS 26177 8 4 2810a931cf90eb4977eafdaaa3cfc8d90bb439ab836b3e05b23aef88ea0368f200a1b145472d36efc1b40c3567af3e71 ; ( SHA-384 digest )
  • Rectify the zone so that all signatures and NSEC/NSEC3 records are present
% pdnsutil rectify-zone zoneNNN.dnslab.org
  • Increment the SOA serial number to trigger NOTIFY for zone-transfer
% pdnsutil increase-serial zoneNNN.dnslab.org
  • The new ZSK is now visible in the DNS zone
% dig dnskey zoneNNN.dnslab.org +multi

; <<>> DiG 9.16.22-Debian <<>> dnskey zoneNNN.dnslab.org +multi
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59184
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;zoneNNN.dnslab.org.    IN DNSKEY

;; ANSWER SECTION:
zoneNNN.dnslab.org.     38 IN DNSKEY 256 3 8 (
                                AwEAAa56Jv3sjwd2yKNbbdcoTNMViBFDv3StAD1Kif7+
                                G/X993ac8cwevgp77dgGx/gmdLTu9/sV3df5/Y31l9j/
                                55QzquNU4Svxnkbf+4onN9dB0Vzh+ASUzrCTfu592tso
                                xpM6YxQUbjgYDI8308u/dgcBSsl5uaJjIcxUNUaP/oC0
                                qn2l4x7TtmHsoMXlrjJB5/oChdvyuU10i0ts3GOpJmka
                                vuynXawWuE5LQAXxNS+POXbKCHf7dzbtUzAQjFBXAw==
                                ) ; ZSK; alg = RSASHA256 ; key id = 14634
zoneNNN.dnslab.org.     38 IN DNSKEY 256 3 8 (
                                AwEAAdSEeKfBK/EXKfKtwB1rpSForHhwVBekz2ZyOd+F
                                uHdNXlCRyhRlok3zUq9BOQLPpqPFm+GGdFttACu3sAeO
                                aq7NIrpFHVijWwXMX0zBeak7ujwFKlC4cKszfEVB6kaq
                                m62JyAGQF6Z6mzDz4q/iW8gq1LmtdMwG+ked3lp5zQk/
                                0MZUBfJcqrya1biDnfOteCv/InoTrydYbFvUNVBe2VlA
                                FZG7pUhQcZs+CQn8y71GU+pepogCM8IJOiE7Fw+7zQ==
                                ) ; ZSK; alg = RSASHA256 ; key id = 37441
zoneNNN.dnslab.org.     38 IN DNSKEY 257 3 8 (
                                AwEAAdmaHnizfuBb89XXhYBoQBnsJ/d+K7zkelu8rAvb
                                sk3pzgwWMEufNXEqBxyQxxKYmqk/m+Wcq2UtuGnRugMf
                                k2iaCod9DHp2iJj9qZ6C2Gqv9jVzwK1OE3yHq9xTuzq4
                                08ibgrxQvhZwYcH4mbqTlopFz/qACNKYdr52zCFnmK3c
                                jHSphNqo3pGlBBGFLrXdLS8oHW6Ec+G7DObTqk+rGUuK
                                HCStG0qPKoKj20L0j2frmcG5h5X0aH+7vHyBeikwuJoy
                                qiwmEg0PYmknAnicuh3ubcPB5P+5ZcItpe6xY52eKqWI
                                jsjcZI0aUmlOqI/ISuwP5b7UhYPgEc8JWlu6T9E=
                                ) ; KSK; alg = RSASHA256 ; key id = 26177

;; Query time: 3 msec
;; SERVER: 67.207.67.3#53(67.207.67.3)
;; WHEN: Wed Nov 03 20:28:06 UTC 2021
;; MSG SIZE  rcvd: 747
  • Wait for the TTL of the DNSKEY record set (60 seconds in our example)
  • Activate the new key, deactivate the old key, rectify zone and increment the SOA serial. The new ZSK is now active
% pdnsutil activate-zone-key zoneNNN.dnslab.org 4
% pdnsutil deactivate-zone-key zoneNNN.dnslab.org 1
% pdnsutil rectify-zone zoneNNN.dnslab.org
Adding NSEC ordering information
% pdnsutil increase-serial zoneNNN.dnslab.org
SOA serial for zone zoneNNN.dnslab.org set to 1635971832
  • Check that the signatures on the SOA record are now created by the new ZSK (Keytag 14634 in this example)
% dig soa zoneNNN.dnslab.org +multi +dnssec

; <<>> DiG 9.16.22-Debian <<>> soa zoneNNN.dnslab.org +multi +dnssec
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27737
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;zoneNNN.dnslab.org.    IN SOA

;; ANSWER SECTION:
zoneNNN.dnslab.org.     60 IN SOA pdns010a.dnslab.org. hostmaster.zoneNNN.dnslab.org. (
                                1635971879 ; serial
                                3600       ; refresh (1 hour)
                                1800       ; retry (30 minutes)
                                3542400    ; expire (5 weeks 6 days)
                                60         ; minimum (1 minute)
                                )
zoneNNN.dnslab.org.     60 IN RRSIG SOA 8 3 60 (
                                20211111000000 20211021000000 14634 zoneNNN.dnslab.org.
                                NwewpF4JnrwWOj6TInXN4mcczGySQ21uVZJXkCzQcLnH
                                GrA8sZwG16yM97YjYSIUf2HqRSlAs1e7sxWwI+QACLg5
                                BG9W3qelTjeczV3aQex5r2dsjOofPuAPTth8FmOJslPB
                                9klh3RDUtWLTmeDzr82lucc4NtvU0zFUpvL1UOwLWg0x
                                J/N/EshkZBwN9odpGcZU+FIyaci7hs/FYXSnJS0FD3Tp
                                MJcsSjt9u4aNtwQbBzWe/jIteyDlZxcmk0lH )

;; Query time: 27 msec
;; SERVER: 67.207.67.3#53(67.207.67.3)
;; WHEN: Wed Nov 03 20:37:59 UTC 2021
;; MSG SIZE  rcvd: 345
  • Wait for the maximum TTL in the zone
  • Remove the old ZSK from the zone
% pdnsutil remove-zone-key zoneNNN.dnslab.org 1
% pdnsutil rectify-zone zoneNNN.dnslab.org
Adding NSEC ordering information
% pdnsutil increase-serial zoneNNN.dnslab.org
SOA serial for zone zoneNNN.dnslab.org set to 1635972173
  • The zone should now only have one ZSK left in the DNSKEY record set
% pdnsutil show-zone zoneNNN.dnslab.org
Nov 03 20:41:31 gmysql Connection successful. Connected to database 'powerdns' on '/run/mysqld/mysqld.sock'.
Nov 03 20:41:31 gmysql Connection successful. Connected to database 'powerdns' on '/run/mysqld/mysqld.sock'.
This is a Master zone
Last SOA serial number we notified: 1635971832 == 1635971832 (serial in the database)
Metadata items: None
Zone has NSEC semantics
keys:
ID = 4 (ZSK), flags = 256, tag = 14634, algo = 8, bits = 1536     Active         Published  ( RSASHA256 )
ID = 2 (KSK), flags = 257, tag = 26177, algo = 8, bits = 2048     Active         Published  ( RSASHA256 )
KSK DNSKEY = zoneNNN.dnslab.org. IN DNSKEY 257 3 8 AwEAAdmaHnizfuBb89XXhYBoQBnsJ/d+K7zkelu8rAvbsk3pzgwWMEufNXEqBxyQxxKYmqk/m+Wcq2UtuGnRugMfk2iaCod9DHp2iJj9qZ6C2Gqv9jVzwK1OE3yHq9xTuzq408ibgrxQvhZwYcH4mbqTlopFz/qACNKYdr52zCFnmK3cjHSphNqo3pGlBBGFLrXdLS8oHW6Ec+G7DObTqk+rGUuKHCStG0qPKoKj20L0j2frmcG5h5X0aH+7vHyBeikwuJoyqiwmEg0PYmknAnicuh3ubcPB5P+5ZcItpe6xY52eKqWIjsjcZI0aUmlOqI/ISuwP5b7UhYPgEc8JWlu6T9E= ; ( RSASHA256 )
DS = zoneNNN.dnslab.org. IN DS 26177 8 1 2416dc421e6debc0c0fd75b8742086df862f054f ; ( SHA1 digest )
DS = zoneNNN.dnslab.org. IN DS 26177 8 2 5993bff9c0f53af0162495f9b5c72a8fc5d05b24602e3905d3f4641da55a6f2c ; ( SHA256 digest )
DS = zoneNNN.dnslab.org. IN DS 26177 8 4 2810a931cf90eb4977eafdaaa3cfc8d90bb439ab836b3e05b23aef88ea0368f200a1b145472d36efc1b40c3567af3e71 ; ( SHA-384 digest )
  • The new DNSKEY record set should also be seen in the DNS zone
% dig dnskey zoneNNN.dnslab.org +multi

; <<>> DiG 9.16.22-Debian <<>> dnskey zoneNNN.dnslab.org +multi
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16831
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;zoneNNN.dnslab.org.    IN DNSKEY

;; ANSWER SECTION:
zoneNNN.dnslab.org.     60 IN DNSKEY 256 3 8 (
                                AwEAAa56Jv3sjwd2yKNbbdcoTNMViBFDv3StAD1Kif7+
                                G/X993ac8cwevgp77dgGx/gmdLTu9/sV3df5/Y31l9j/
                                55QzquNU4Svxnkbf+4onN9dB0Vzh+ASUzrCTfu592tso
                                xpM6YxQUbjgYDI8308u/dgcBSsl5uaJjIcxUNUaP/oC0
                                qn2l4x7TtmHsoMXlrjJB5/oChdvyuU10i0ts3GOpJmka
                                vuynXawWuE5LQAXxNS+POXbKCHf7dzbtUzAQjFBXAw==
                                ) ; ZSK; alg = RSASHA256 ; key id = 14634
zoneNNN.dnslab.org.     60 IN DNSKEY 257 3 8 (
                                AwEAAdmaHnizfuBb89XXhYBoQBnsJ/d+K7zkelu8rAvb
                                sk3pzgwWMEufNXEqBxyQxxKYmqk/m+Wcq2UtuGnRugMf
                                k2iaCod9DHp2iJj9qZ6C2Gqv9jVzwK1OE3yHq9xTuzq4
                                08ibgrxQvhZwYcH4mbqTlopFz/qACNKYdr52zCFnmK3c
                                jHSphNqo3pGlBBGFLrXdLS8oHW6Ec+G7DObTqk+rGUuK
                                HCStG0qPKoKj20L0j2frmcG5h5X0aH+7vHyBeikwuJoy
                                qiwmEg0PYmknAnicuh3ubcPB5P+5ZcItpe6xY52eKqWI
                                jsjcZI0aUmlOqI/ISuwP5b7UhYPgEc8JWlu6T9E=
                                ) ; KSK; alg = RSASHA256 ; key id = 26177

;; Query time: 135 msec
;; SERVER: 67.207.67.3#53(67.207.67.3)
;; WHEN: Wed Nov 03 20:43:36 UTC 2021
;; MSG SIZE  rcvd: 535

  1. Exercise

    • Perform a ZSK rollover for your zone
    • Verify after each step that the zone still validates

6.7.2 KSK rollover with double-signing

  • To start a KSK rollover with PowerDNS, create, publish and activate a new KSK (same algorithm as existing KSK, size can differ)
% pdnsutil add-zone-key zoneNNN.dnslab.org KSK active published 2048 rsasha256
Added a KSK with algorithm = 8, active=1
Requested specific key size of 2048 bits
5
% pdnsutil rectify-zone zoneNNN.dnslab.org
% pdnsutil increase-serial zoneNNN.dnslab.org
  • The zone should now have 2 KSK DNSKEY records
% pdnsutil show-zone zoneNNN.dnslab.org
This is a Master zone
Last SOA serial number we notified: 1635972173 != 1635972638 (serial in the database)
Metadata items: None
Zone has NSEC semantics
keys:
ID = 4 (ZSK), flags = 256, tag = 14634, algo = 8, bits = 1536     Active         Published  ( RSASHA256 )
ID = 2 (KSK), flags = 257, tag = 26177, algo = 8, bits = 2048     Active         Published  ( RSASHA256 )
KSK DNSKEY = zoneNNN.dnslab.org. IN DNSKEY 257 3 8 AwEAAdmaHnizfuBb89XXhYBoQBnsJ/d+K7zkelu8rAvbsk3pzgwWMEufNXEqBxyQxxKYmqk/m+Wcq2UtuGnRugMfk2iaCod9DHp2iJj9qZ6C2Gqv9jVzwK1OE3yHq9xTuzq408ibgrxQvhZwYcH4mbqTlopFz/qACNKYdr52zCFnmK3cjHSphNqo3pGlBBGFLrXdLS8oHW6Ec+G7DObTqk+rGUuKHCStG0qPKoKj20L0j2frmcG5h5X0aH+7vHyBeikwuJoyqiwmEg0PYmknAnicuh3ubcPB5P+5ZcItpe6xY52eKqWIjsjcZI0aUmlOqI/ISuwP5b7UhYPgEc8JWlu6T9E= ; ( RSASHA256 )
DS = zoneNNN.dnslab.org. IN DS 26177 8 1 2416dc421e6debc0c0fd75b8742086df862f054f ; ( SHA1 digest )
DS = zoneNNN.dnslab.org. IN DS 26177 8 2 5993bff9c0f53af0162495f9b5c72a8fc5d05b24602e3905d3f4641da55a6f2c ; ( SHA256 digest )
DS = zoneNNN.dnslab.org. IN DS 26177 8 4 2810a931cf90eb4977eafdaaa3cfc8d90bb439ab836b3e05b23aef88ea0368f200a1b145472d36efc1b40c3567af3e71 ; ( SHA-384 digest )
ID = 5 (KSK), flags = 257, tag = 45824, algo = 8, bits = 2048     Active         Published  ( RSASHA256 )
KSK DNSKEY = zoneNNN.dnslab.org. IN DNSKEY 257 3 8 AwEAAaicwPSEdFMZAfofnKAVbAb6nzZyRqYW+1GLNIMKFRw/YZ97Gi+ZfAjkJWOkeVLbNmeKgZSMz185NkoSwlWFdrJv8hR43Hu1UJgMdKr3EzKti7W8U3YwEnBl7W1yv518LhOPFata3H5i082/qiP2c9j4JXmH1fC1TqtwTDGDpS9myPgidRgMPqeqtZ+5aQYfcEo+Kw0EJT0xD1lUURGwUztEdM4nfjIcaMf6o3//Te5KJZEhhesBgUvpbYN13ZQjA3EmzcQqoFj8HW9QZ8lC7JlYxHucA+SluGgg4BmkefAlUhuPAuF9cLvri720DVATqSQwezTIgJNromdhfjnpvec= ; ( RSASHA256 )
DS = zoneNNN.dnslab.org. IN DS 45824 8 1 c2eff1df58bf152036fd8d556553c1096136f0d0 ; ( SHA1 digest )
DS = zoneNNN.dnslab.org. IN DS 45824 8 2 33509b6659026377b337b7009442f45ae0d2a08b21e3ba726094bbac0f121635 ; ( SHA256 digest )
DS = zoneNNN.dnslab.org. IN DS 45824 8 4 213c2eba14d47e7418feea186ff0c565accd81cc65353524bff2c9894fb203995fea8b868046932a7d3bedb20351ee99 ; ( SHA-384 digest )
  • Two KSK DNSKEY records are in the zone
% dig dnskey zoneNNN.dnslab.org +multi

; <<>> DiG 9.16.22-Debian <<>> dnskey zoneNNN.dnslab.org +multi
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3417
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;zoneNNN.dnslab.org.    IN DNSKEY

;; ANSWER SECTION:
zoneNNN.dnslab.org.     60 IN DNSKEY 256 3 8 (
                                AwEAAa56Jv3sjwd2yKNbbdcoTNMViBFDv3StAD1Kif7+
                                G/X993ac8cwevgp77dgGx/gmdLTu9/sV3df5/Y31l9j/
                                55QzquNU4Svxnkbf+4onN9dB0Vzh+ASUzrCTfu592tso
                                xpM6YxQUbjgYDI8308u/dgcBSsl5uaJjIcxUNUaP/oC0
                                qn2l4x7TtmHsoMXlrjJB5/oChdvyuU10i0ts3GOpJmka
                                vuynXawWuE5LQAXxNS+POXbKCHf7dzbtUzAQjFBXAw==
                                ) ; ZSK; alg = RSASHA256 ; key id = 14634
zoneNNN.dnslab.org.     60 IN DNSKEY 257 3 8 (
                                AwEAAaicwPSEdFMZAfofnKAVbAb6nzZyRqYW+1GLNIMK
                                FRw/YZ97Gi+ZfAjkJWOkeVLbNmeKgZSMz185NkoSwlWF
                                drJv8hR43Hu1UJgMdKr3EzKti7W8U3YwEnBl7W1yv518
                                LhOPFata3H5i082/qiP2c9j4JXmH1fC1TqtwTDGDpS9m
                                yPgidRgMPqeqtZ+5aQYfcEo+Kw0EJT0xD1lUURGwUztE
                                dM4nfjIcaMf6o3//Te5KJZEhhesBgUvpbYN13ZQjA3Em
                                zcQqoFj8HW9QZ8lC7JlYxHucA+SluGgg4BmkefAlUhuP
                                AuF9cLvri720DVATqSQwezTIgJNromdhfjnpvec=
                                ) ; KSK; alg = RSASHA256 ; key id = 45824
zoneNNN.dnslab.org.     60 IN DNSKEY 257 3 8 (
                                AwEAAdmaHnizfuBb89XXhYBoQBnsJ/d+K7zkelu8rAvb
                                sk3pzgwWMEufNXEqBxyQxxKYmqk/m+Wcq2UtuGnRugMf
                                k2iaCod9DHp2iJj9qZ6C2Gqv9jVzwK1OE3yHq9xTuzq4
                                08ibgrxQvhZwYcH4mbqTlopFz/qACNKYdr52zCFnmK3c
                                jHSphNqo3pGlBBGFLrXdLS8oHW6Ec+G7DObTqk+rGUuK
                                HCStG0qPKoKj20L0j2frmcG5h5X0aH+7vHyBeikwuJoy
                                qiwmEg0PYmknAnicuh3ubcPB5P+5ZcItpe6xY52eKqWI
                                jsjcZI0aUmlOqI/ISuwP5b7UhYPgEc8JWlu6T9E=
                                ) ; KSK; alg = RSASHA256 ; key id = 26177

;; Query time: 215 msec
;; SERVER: 1.1.1.1#53(1.1.1.1)
;; WHEN: Wed Nov 03 20:54:11 UTC 2021
;; MSG SIZE  rcvd: 811
  • Send the DS-Record or the DNSKEY record of the new KSK to the operator of the parent zone
  • Wait for the new DS record to appear in the parent zone
  • Remove the old KSK from the zone
% pdnsutil remove-zone-key zoneNNN.dnslab.org 2
% pdnsutil rectify-zone zoneNNN.dnslab.org
Adding NSEC ordering information
% pdnsutil increase-serial zoneNNN.dnslab.org
SOA serial for zone zoneNNN.dnslab.org set to 1635973094
  • KSK rollover completed
  1. Exercise

    • Perform a KSK rollover for your zone
    • Send the new DS-Record to the trainer (cs@sys4.de)
    • Wait for the new DS-Record in the parent zone, then continue with the roll-over
    • Verify after each step that the zone still validates

6.8 PowerDNS and NSEC3 signing

  • Zones can switch from NSEC to NSEC3 and back at any time
  • Use pdnsutil set-nsec3 <zone-name> <nsec3-parameter> to switch to NSEC3
  • Use pdnsutil unset-nsec3 <zone-name> to switch back to NSEC
% pdnsutil set-nsec3 zoneNNN.dnslab.org "1 0 10 -"
NSEC3 set, please rectify your zone if your backend needs it
% pdnsutil rectify-zone zoneNNN.dnslab.org
Adding NSEC3 hashed ordering information for 'zoneNNN.dnslab.org'
% pdnsutil increase-serial zoneNNN.dnslab.org
SOA serial for zone zoneNNN.dnslab.org set to 1635973224
  • The zone is now secured with NSEC3
# dig @localhost xyz.zoneNNN.dnslab.org +dnssec +multi +norec

; <<>> DiG 9.16.22-Debian <<>> @localhost xyz.zoneNNN.dnslab.org +dnssec +multi +norec
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 33387
;; flags: qr aa; QUERY: 1, ANSWER: 0, AUTHORITY: 6, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
;; QUESTION SECTION:
;xyz.zoneNNN.dnslab.org.        IN A

;; AUTHORITY SECTION:
zoneNNN.dnslab.org.     60 IN SOA pdns010a.dnslab.org. hostmaster.zoneNNN.dnslab.org. (
                                1636009907 ; serial
                                3600       ; refresh (1 hour)
                                1800       ; retry (30 minutes)
                                3542400    ; expire (5 weeks 6 days)
                                60         ; minimum (1 minute)
                                )
zoneNNN.dnslab.org.     60 IN RRSIG SOA 8 3 60 (
                                20211118000000 20211028000000 14634 zoneNNN.dnslab.org.
                                QOtJT7bfN6OvuVbWBTn326PwCuqJ717jQ+kTo61Nymhe
                                ReOKa6IvIyiUBCKXxyrvzhASxR3CAw0x3CukL3Gwdm4F
                                kS3nILwsyKIv/IeREpXLcU1KrUK4fxAXQ81IJh1R96IH
                                s0xAeurl4hdzGgYeydLqGlRdhAics8vGpuqPtnzBybDp
                                5SImpw7KGI50229jpdbgA67c89E4nAkBszLYI8IfhJKM
                                rN0zj7JXNJPHGmA+oeCQnBy5yh+E/6IeTlA2 )
6egermavujrtij09ssmf3r4kg1bhbihl.zoneNNN.dnslab.org. 60 IN NSEC3 1 0 10 - (
                                6TNSMUD7JF5CKL4QMPHMSJ1VCVNIGP2I
                                A NS SOA RRSIG DNSKEY NSEC3PARAM )
6egermavujrtij09ssmf3r4kg1bhbihl.zoneNNN.dnslab.org. 60 IN RRSIG NSEC3 8 4 60 (
                                20211118000000 20211028000000 14634 zoneNNN.dnslab.org.
                                VXf8bF+/EqVndIzWhbUlsuJJ1lNHaF7bYnOpZ3bm9Ij9
                                XOFtG8Oa+YBg4bAr82B2Ra565jVK4uAZ5tL1/69H7xlj
                                BIkZ74KSRgoeI69yjT1fzN04l7V1RHDEjZtz6/NFy1qG
                                9R+J9/vVZXdhJBPhlia6+A5x5+RDdLlZcB2wrWjdvjpR
                                z4hfoy5T4p3MHx4rXRDp3zNQrRMkcdW3Kg/mK1+a5rYA
                                1/WJl+pCVaWLTspwY6wnybNnmx/eBf6H0bO5 )
6tnsmud7jf5ckl4qmphmsj1vcvnigp2i.zoneNNN.dnslab.org. 60 IN NSEC3 1 0 10 - (
                                34KQL2SE77RDH2S50C8DR19DI2OB75VD
                                TXT RRSIG )
6tnsmud7jf5ckl4qmphmsj1vcvnigp2i.zoneNNN.dnslab.org. 60 IN RRSIG NSEC3 8 4 60 (
                                20211118000000 20211028000000 14634 zoneNNN.dnslab.org.
                                fl0z50DIEOtombxYRST2ANGsLtxUSX2Yo6ceMPYTHnvS
                                5gvw3m7+TDkTRVB39Ezcw/W9y7aPMp6HNCk0+ZCytWHI
                                4E4tV0uzrN/dVYSCv1+ooX54JbF23Zk7C76MYKjYO33V
                                cOarWoA8VYiy3uKaKyE752tUWGhVW6X8iQYQbQ0oZmXM
                                z2gOVlPnxLsrV5IRyhRIaFhKTFfcu4TA54l+Dpgz7rd4
                                x3/eHepeaPPlFsBclKZ3rmZ+gIQ1YqAPzqpz )

;; Query time: 3 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Nov 04 07:11:47 UTC 2021
;; MSG SIZE  rcvd: 992

  • The NSEC3PARAM record in the zone
% dig @localhost nsec3param zoneNNN.dnslab.org +dnssec +multi +norec

; <<>> DiG 9.16.22-Debian <<>> @localhost nsec3param zoneNNN.dnslab.org +dnssec +multi +norec
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35689
;; flags: qr aa; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
;; QUESTION SECTION:
;zoneNNN.dnslab.org.    IN NSEC3PARAM

;; ANSWER SECTION:
zoneNNN.dnslab.org.     60 IN NSEC3PARAM 1 0 10 -
zoneNNN.dnslab.org.     60 IN RRSIG NSEC3PARAM 8 3 60 (
                                20211118000000 20211028000000 14634 zoneNNN.dnslab.org.
                                JTPUqdF6YqfhcpUBHMomhqspp5ijzDCOiNMXwRbQm1Xp
                                VGTOo8CNRWNCbCnYgpjILz5itUcLSnJPzz6gdKXGuGVI
                                sxFVR/3OKLweaj+pWrlgSkRG1mskYiFN58Y2PRL42P6j
                                oYCXJOyj/J5VcQBJyKWoJWP801t+581hBNEkZOVaELeQ
                                HjH2shbKX5un/0Bc2f4pKM/8W4a2O/K/0avSeFGKklIK
                                g3C4NZKaYFkAxaGapAMQp5CXrpilt7moAXmp )

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Nov 04 07:12:54 UTC 2021
;; MSG SIZE  rcvd: 306

6.8.1 NSEC3 "narrow" mode

  • PowerDNS supports a special NSEC3 mode called the narrow mode
    • In this mode, it will create NSEC3 records on the fly that cover just the minimal gap in the zone from the requested domain name
    • NSEC3 narrow prevents zone walking
    • NSEC3 narrow mode requires life-signing, which demands that all authoritative server have access to the private DNSSEC keys (a potential security risk)
      • All PowerDNS server authoritative for a NSEC3 narrow signed zone should operate in native mode (not master / slave mode)
      • narrow mode is recommended for zones that contain sensitive data (such as email addresses -> SMIMEA or OPENPGPKEY data)
  • To switch to NSEC3 narrow mode
% pdnsutil set-nsec3 zoneNNN.dnslab.org "1 0 10 -" narrow
% pdnsutil rectify-zone zoneNNN.dnslab.org
% pdnsutil increase-serial zoneNNN.dnslab.org
  • Narrow-Mode NSEC3 records
% dig srv zoneNNN.dnslab.org +dnssec @1.1.1.1 +multi

; <<>> DiG 9.16.22-Debian <<>> srv zoneNNN.dnslab.org +dnssec @1.1.1.1 +multi
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19702
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 4, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
;; QUESTION SECTION:
;zoneNNN.dnslab.org.    IN SRV

;; AUTHORITY SECTION:
zoneNNN.dnslab.org.     60 IN SOA pdns010a.dnslab.org. hostmaster.zoneNNN.dnslab.org. (
                                1635973813 ; serial
                                3600       ; refresh (1 hour)
                                1800       ; retry (30 minutes)
                                3542400    ; expire (5 weeks 6 days)
                                60         ; minimum (1 minute)
                                )
zoneNNN.dnslab.org.     60 IN RRSIG SOA 8 3 60 (
                                20211111000000 20211021000000 14634 zoneNNN.dnslab.org.
                                SYfqwgtasVpUhKpBPAutbNTeXdGuY3A2F8Nv0cYFwqVI
                                uJDeJiRpUVk9HbqPqh6b7Q7QNFt7c5lD9onT+kegkqHR
                                5DEKAzPMPcNTdqx9ZjQrYXZrDpin7Zo/Mf+kEPCMArgC
                                opDlfppFhEcUSZL3mHU/WPJlj1Zr9JwIq+Ll+TCiaJ02
                                tY4a59LTEcB10HNrD5KHdURU7EE9uwg6BhEFXzvNAnW7
                                uHTYbd6v8K7yj2bukDAn3qfHTwBpgcgRKE3u )
6egermavujrtij09ssmf3r4kg1bhbihl.zoneNNN.dnslab.org. 60 IN NSEC3 1 0 10 - (
                                6EGERMAVUJRTIJ09SSMF3R4KG1BHBIHM
                                A NS SOA RRSIG DNSKEY NSEC3PARAM )
6egermavujrtij09ssmf3r4kg1bhbihl.zoneNNN.dnslab.org. 60 IN RRSIG NSEC3 8 4 60 (
                                20211111000000 20211021000000 14634 zoneNNN.dnslab.org.
                                MHO22RkxtdJmcXsDeij7JuKVHMLVF1SwvreztmCVAebK
                                /dGv98g+843LoCXi2yDRmYWeKtVodsATmr5+SI3JV4a5
                                TGG9JMThzcJ5ytHHYXp+17DoSygx0ppI8y8mbAYFBhLM
                                1HLpSBWHw9YzTzJhRqkeG7R0E6hTSX1y0fSJt58ov+hU
                                MyiwZwN9HMw+ulDLDa5DxEUXfNar+PS9WC08EAemiitZ
                                6a2xgH0fHCHWky+go2DddRrQvM6BkTIMsvc9 )

;; Query time: 39 msec
;; SERVER: 1.1.1.1#53(1.1.1.1)
;; WHEN: Wed Nov 03 21:10:23 UTC 2021
;; MSG SIZE  rcvd: 667

6.9 DNSSEC Troubleshooting

6.9.1 Checking DNS resolution issues

  1. dig

    The DNS name resolution tool dig can be used to test the general function of a DNS resolver, or to test if an error condition exist at the remote DNS authoritative servers of a domain.

    1. testing one DNS resolver over UDP

      To test the general connectivity and operation of a DNS resolver, a query for well known DNS data can be sent, such as for the list of name-server (NS records) of the root zone ".". The answer should contain the list of all 13 root name server in the Internet (with the names a-m.root-servers.net)

      $ dig @IP-of-DNS-resolver NS .
      

      • what are reasons we recommend using the IP address of a resolver instead of its name?

    2. Testing one DNS resolver over TCP

      The DNS resolvers must also be reachable over TCP. To send a query via TCP, add the +tcp flag to queries.

      $ dig @IP-of-DNS-resolver NS . +tcp
      

      • you can save 33% typing by using +vc instead of +tcp. What does vc do? Check the manual page for dig(1).

    3. Testing reachability of all authoritative DNS servers

      The dig function +nssearch will first query all NS records for a given domain and then will try to query directly (without going to a DNS-resolver) the authoritative DNS servers of that domain:

      $ dig @IP-of-DNS-resolver example.com +nssearch
      

      The function will print out the SOA record of the zone (here example.com) for each DNS server that has send an answer to the query, including the SOA serial, the IPv4 and/or IPv6 address and the round-trip-time (RTT) of the query.

      All SOA serial numbers should show the same number, else there might be an issue with zone synchronization via zone transfer which might be a possible cause for DNS lookup problems.

      • Which type of DNS servers (authoritative, recursive, primary, secondary) are at fault if the SOA serial numbers of a zone are not in sync? Who can correct the fault?

    4. Testing the resolution chain

      The function +trace in dig will trace the DNS name resolution starting from the root DNS server system down to the requested name.

      $ dig @IP-of-DNS-resolver example.com +trace
      

      Only the very first query to find the root-server addresses will be done towards the DNS resolver given in the command, all other queries will be sent directly to the authoritative DNS servers. This function tests and prints one of usually many possible DNS resolution paths. A successful return of the command does not indicate that the resolution path is without errors, it is only an indication that at least one successful path exists.

    5. Testing for DNSSEC validation issues

      If a DNS query returns a SERVFAIL answer, it can be a DNSSEC validation issue at the DNS resolver, or it can be some kind of server malfunction on the DNS resolver or the remote authoritative server.

      In order the check for DNSSEC validation issues, the administrator can send a DNS query with the +cd flag (Checking Disabled). With this flag set, the DNS resolver will skip DNSSEC validation and will return the DNS data to dig even in case the DNSSEC validation would fail.

      So if a DNS query returns data when +cd is set, but returns SERVFAIL when +cd is not set, this indicates a DNSSEC validation issue. If the answer is always SERVFAIL, it is some other kind of problem (usually not DNSSEC).

  2. External web services to check DNS

    Several website services exist that help DNS administrators to check the health of a DNS system

    1. Zonemaster

      The website Zonemaster https://zonemaster.net is a collaboration between the French TLD registry AFNIC and the Swedish registry IIS. The website takes a domain name and will generate a report of errors and best practice recommendations of the setup of this domain name.

    2. DNSViz

      DNSViz https://dnsviz.net is a tool for visualizing the status of a DNS zone. It provides a visual analysis of the DNSSEC authentication chain for a domain name and its resolution path in the DNS namespace, and it lists configuration errors detected by the tool.

6.9.2 Looking into DNSSEC validation issues

DNSSEC validation issues are often a problem with misconfiguration at the authoritative DNS server side of the domain, not an issue of the DNS resolver system. However to be able to debug DNSSEC issues, for example to decide if an NTA (negative trust anchor) should be inserted into the DNS resolver system to temporarily disable DNSSEC validation for a specific domain, the DNSSEC validation issue should be investigated first.

  1. DNSSEC validation troubleshooting with "delv"

    The tool delv is part of the BIND 9 DNS server and implements a full DNS resolver and DNSSEC validator inside the command line tool. This tool works very similarly to dig (and shares the same command line syntax), but where dig always needs a DNS resolver to get the DNS information, delv can query the data and can validate the DNSSEC information itself.

  2. Message trace

    The flag +mtrace enables the message tracing in delv, the tool will print all DNS queries and answers during the processing of the query.

    $ delv example.com +mtrace
    
  3. Validation trace

    The flag +vtrace will print a debug trace of all DNSSEC validation steps the tool will do in order to validate the received DNS answers

    $ delv example.com +vtrace
    
  4. DNSSEC path validation with drill

    The tool drill is part of the LDNS tools (Debian/Ubuntu package ldnsutils) and is a dig lookalike tool with additional features. One notable feature is the function to trace the DNSSEC validation and to print the DNSSEC chain-of-trust together with the DNSSEC key information.

    drill requires the current DNSSEC root trust anchor in a file to be able to work. This trust anchor can be received with drill, but also with dig or delve:

    $ dig @a.root-servers.net . DNSKEY | grep 257 > root.key
    

    This DNSSEC root trust-anchor key can be used to do a DNSSEC chain chase with drill:

    $ drill -SD -k root.key example.com
    

    • In the example above we fetched the root DNSKEY with dig. Is this method for obtaining the root DNSKEY record foolproof, and do you consider it secure?

6.10 Response Policy Zones (RPZ)

  • RPZ is an RDNS security mechanism to protect queriers from Internet dangers.
    • It is like a firewall. RPZ prevents access to domain names identified as disreputable.
  • A domain name identified as disreputable triggers a policy with an action that denies normal resolution.
    • E.G. a domain name in a URL known for having malware, gets an NXDOMAIN response.
  • RPZs are already being widely implemented, but are still only a draft RFC: https://tools.ietf.org/html/draft-vixie-dnsop-dns-rpz (expired 12/2018)
  • other RPZ implementations: Bind 9, Unbound 1.11+, policy.rpz (Knot) - partial support, commercial DNS products, …
  • RPZ policies are implemented in zone files.
    • RPZs have some unique values, but conform to Master File Format.
    • The RPZ zones are deployed on DNS resolver, not on auth servers.
    • A DNS resolver is usually the secondary to a central RPZ management server that hosts the primary RPZ zones
    • There is no delegation and the NS RRs are unused.
    • An RPZ typically has policies for unrelated names. E.G.:
      www.verybad.org 30 IN CNAME google.com.
      evilstuff.net   30 IN CNAME google.com.
      
      • Note: the owner names in the example above are not fully qualified (FQDN)
  • There are five triggers for an RPZ policy.
    • Two are based on the query.
    • Three are based on the RDATA of the response.
  • For some of the triggers, special labels are required in the RR owner name.
  • There are six actions that a policy can trigger.
    • NXDOMAIN is one, the others are covered soon.

6.10.1 Policy Triggers Based on The Query

  • QNAME: The queried domain-name triggers the policy.
    • This is the most common trigger.
    • No special label is required for the owner name.
  • Client IP: The client's address triggers the policy.
    • The label .rpz-client-ip is used in the owner name.

RPZ-01.png

6.10.2 Policy Triggers Based on The Response

  • Response IP: The IP address in the RR triggers the policy.
    • This is only applicable to A & AAAA RRs.
    • It is only applicable to the Answer section of the DNS message.
    • The label .rpz-ip is used in the owner name.

RPZ-02.png

  • NSDNAME: Any NS referral in the path to getting a final response triggers the policy.
    • The label .rpz-nsdname is used in the owner name.
  • NSIP: An IP address of a NS in the path of getting a final response triggers the policy.
    • The label .rpz-nsip is used in the owner name.

6.10.3 Policy Actions

  • Six actions are available when a policy is triggered:
    • Respond with local data trapping the query in a walled garden. (Most commonly this is a CNAME.)
    • Respond NXDOMAIN
    • Respond NOERROR/NODATA
    • Respond normally (passthru)
    • Respond with the TC flag
    • Drop the query
  • The bold actions are most common.
  • When more than one action could apply (e.g. NXDOMAIN and passthru), precedence rules select which is used. The rules are beyond the scope of this course.

6.10.4 PowerDNS recursor RPZ configuration

  • PowerDNS can load RPZ zones from files or transfer a RPZ zone via standard DNS zone transfer
  • See PowerDNS documentation on RPZ for the details
  • Example: loading an RPZ zone from a file inside the PowerDNS recursor Lua configuration file /etc/powerdns/recursor.lua
-- RPZ from file
rpzFile("/etc/powerdns/rpz/malware.rpz", {defpol=Policy.NXDOMAIN})
  • Loading a RPZ zone via zone transfer
-- RPZ via Zone transfer
rpzPrimary({"192.0.2.4","192.0.2.5:5301"}, "policy.rpz", {defpol=Policy.Drop})

6.10.5 RPZ: Zone File

  • The response policy zone is not delegated and NS RRs are unused.
    • The draft RFC recommends the convention of using localhost.
  • Other than the MNAME, all fields in the SOA should be valid and reasonable for the sake of any secondary using the RPZ.
$TTL 1h
$ORIGIN rpz-z01.
@  SOA localhost. pm.example.com. 1 4h 1h 8w 1h
   NS  localhost.
  • The domain name below is being declared disreputable.
    • The owner names should NOT be FQDNs!
  • A CNAME to the root, ., is RPZ's code for an NXDOMAIN action.
    $TTL 1h
    $ORIGIN rpz-z01.
    @                     SOA localhost. pm.example.com. 1 4h 1h 8w 1h
                          NS  localhost.
    evilstuff.com         CNAME        .      ; NXDOMAIN
    
  • Wildcards usage in RPZ files is common.
    • Also match everything under evilstuff.com.
    *.evilstuff.com       CNAME .      ; NXDOMAIN
    
  • A CNAME to *. is RPZ's code for a NODATA action.
    badplace.us           CNAME *.     ; NOERROR/NODATA
    *.badplace.us         CNAME *.     ; NOERROR/NODATA
    
  • Local Data is a standard RR without any special RPZ encoding. Most commonly, a CNAME is used to point to a walled garden.
    vile.org              CNAME fbi.gov. ; redirect
    *.vile.org            CNAME fbi.gov. ; redirect
    
  • A CNAME to the RPZ special target rpz-drop. makes the RDNS server to simply drop the query (no response is sent).
    • The querier will eventually time-out.
    yuck.reddit.com       CNAME rpz-drop.     ; drop
    
  • A CNAME to the RPZ special target rpz-tcp-only. makes the DNS resolver server set the TC flag (truncated) in the response.
    • A legitimate querier will re-query over TCP. This is tool to mitigate reflection attacks.
    innocent.com          CNAME rpz-tcp-only. ; truncate
    *.innocent.com        CNAME rpz-tcp-only. ; truncate
    

6.10.6 Client IP Address Trigger

  • To trigger on the querier's IP, use the .rpz-client-ip encoding. The IPv4 address is reversed like in a PTR RR, but an additional first label indicates the netmask.
    16.0.0.31.172.rpz-client-ip        CNAME   rpz-passthru.
    12.0.0.16.172.rpz-client-ip        CNAME   rpz-drop.
    32.1.0.0.127.rpz-client-ip         CNAME   rpz-passthru.
    
    • Drop traffic from all class B private clients 172.16/12 except the 172.31/16 block which is not subject to any policies. The 127.0.0.1 host is also except for policies, which is useful for testing.
  • IPv6 addresses are reversed per four hex-digit field. Colons are replaced by periods. The double-colon for zero compression with "zz". Zero suppression and zero compression are required. The addresses shown are: 2001:db8:bad::/64 ::1/128
    64.zz.bad.db8.2001.rpz-client-ip   CNAME   rpz-drop.
    128.1.zz.rpz-client-ip             CNAME   rpz-passthru.
    

6.10.7 Response IP Address Trigger

  • If the given IP addresses appear in A or AAAA answer sections, an action is triggered.
    • In the example, the IPs are associated with dangers on the Internet, and get an NXDOMAIN response. 192.0.2.99/32 2001:db8:ea::/48
    32.99.2.0.192.rpz-ip               CNAME   .   ; NXDOMAIN
    48.zz.ea.db8.2001.rpz-ip           CNAME   .   ; NXDOMAIN
    

6.10.8 NS Domain-Name and NS IP Triggers

  • If a referral contains ns1.badactor.ch or a referral's A RR is 198.51.100.1, the response will be NXDOMAIN.
    ns1.badActor.ch.rpz-nsdname        CNAME   .   ; NXDOMAIN
    32.1.100.51.198.rpz-nsip           CNAME   .   ; NXDOMAIN
    

6.10.9 RPZ - the full example

  • the full RPZ zone with different trigger and actions
$TTL 1h
$ORIGIN rpz-z01.
@ SOA localhost. pm.example.com. 1 4h 1h 8w 1h
  NS  localhost.
evilstuff.com         CNAME .                             ; NXDOMAIN
*.evilstuff.com       CNAME .                             ; NXDOMAIN
badplace.us           CNAME *.                            ; NOERROR/NODATA
*.badplace.us         CNAME *.                            ; NOERROR/NODATA
vile.org              CNAME fbi.gov.                      ; redirect
*.vile.org            CNAME fbi.gov.                      ; redirect
yuck.reddit.com       CNAME rpz-drop.                     ; drop
innocent.com          CNAME rpz-tcp-only.                 ; truncate
*.innocent.com        CNAME rpz-tcp-only.                 ; truncate
16.0.0.31.172.rpz-client-ip        CNAME   rpz-passthru.  ; permit
12.0.0.16.172.rpz-client-ip        CNAME   rpz-drop.      ; drop
32.1.0.0.127.rpz-client-ip         CNAME   rpz-passthru.  ; permit
64.zz.bad.db8.2001.rpz-client-ip   CNAME   rpz-drop.      ; drop
128.1.zz.rpz-client-ip             CNAME   rpz-passthru.  ; permit
32.99.2.0.192.rpz-ip               CNAME   .              ; NXDOMAIN
48.zz.ea.db8.2001.rpz-ip           CNAME   .              ; NXDOMAIN
ns1.badActor.ch.rpz-nsdname        CNAME   .              ; NXDOMAIN
32.1.100.51.198.rpz-nsip           CNAME   .              ; NXDOMAIN

6.10.10 RPZ Data Feeds

  • The site https://dnsrpz.info maintains a list of providers of reputation data.
    • Different techniques are used to access the feed.
    • For example SpamHaus makes it available via zone transfer (AXFR/IXFR).
  • Prices vary. Since 2018-02 SpamHaus has a free but very limited service: https://www.spamhaus.org/news/article/669

6.10.11 Response-Policies without RPZ

  • Limited RPZ functionality is available without RPZ.
    • A DNS resolver server can be authoritative for zones to block or wall garden.
    • If there are 1000 zones, the server must be authoritative for all 1000.
    • With RPZ, only one zone is required.

6.10.12 RPZ Notes

  • The following types must not be RPZ data:
    • SOA, NS, DNAME, all DNSSEC related records

6.10.13 Exercise

  • Download the RPZ generator from https://raw.githubusercontent.com/ohrrkan/bind-rpz/main/bind-rpz.py
    • This Python script will generate a RPZ zone from public available ad-blocking lists
  • Execute the Python script to generate the zone-file. Inspect the zone file
  • Load the RPZ file into the PowerDNS recursor from the Lua configuration file, restart the PowerDNS recursor
  • Dump the RPZ file from the running PowerDNS memory into a new file to validate that the RPZ zone is loaded
  • Query the name ad-channel.wikawika.xyz from your PowerDNS recursor and from Quad9/Cloudflare public DNS. You should see a NOERROR/NODATA answer from your PowerDNS recursor, and a regular answer from the public DNS services
  • Change the RPZ Policy for this zone from NODATA to NXDOMAIN
  • Use dig to verify that the return status is now NXDOMAIN

6.10.14 Solution

  • Download Python script
wget https://raw.githubusercontent.com/ohrrkan/bind-rpz/main/bind-rpz.py
  • Execute Python scrip to crate the RPZ zone file
% python3 bind-rpz.py
% ls -l
total 2320
-rw-r--r-- 1 root root    1536 Nov  3 22:08 bind-rpz.py
-rw-r--r-- 1 root root 2370166 Nov  3 22:08 db.banlist
  • Inspect the RPZ zone
% head db.banlist
$TTL    1H

@       SOA     LOCALHOST. localhost (1 1h 15m 30d 2h)
        NS      LOCALHOST.

0.le4net00.net  CNAME   *.
0.weathdata.nu  CNAME   *.
00-gov.cn       CNAME   *.
000.gaysexe.free.fr     CNAME   *.
000007.ru       CNAME   *.
  • Load the RPZ zone into the PowerDNS recursor
-- RPZ
rpzFile("/etc/powerdns/rpz/db.banlist")
  • Dump the RPZ zone from memory into a file
% rec_control dump-rpz rpzFile /tmp/rpz.out
  • This is how to overwrite the policy
rpzFile("/etc/powerdns/rpz/db.banlist", {defpol=Policy.NXDOMAIN})

6.11 Security Best Practices

6.11.1 Separating authoritative and recursive DNS

  • authoritative DNS server and DNS resolver are separate functions in the DNS infrastructure
    • they have different security requirements
  • benefits of separate authoritative and recursive DNS
    • required for DNSSEC validation of own zones
    • security configuration optimised for the function (for example query ACLs)
    • helps troubleshooting (logging)
    • easier maintenance (Updates)

6.11.2 Process isolation

  • isolate the PowerDNS DNS server process from the operating system and other applications
    • reduces the impact of a security breach
    • classic Unix operating systems offer the chroot function to isolate a process into its own filesystem-tree
      • while many security tutorials still explain chroot, it might not be the best option available today
      • modern systems offer much richer isolation functions:
        • Linux container (LXC/LXD, Docker, Podman, systemd-nspawn, Firejail)
        • FreeBSD jails

6.11.3 Firewalls Architectures

  1. Packet Filter
    • A packet filter is a simple firewall, examining only fields in the IP header.
      • It filters on IP source and destination, and on TCP/UDP ports.
      • With low latency, it protects a DNS server, but provides no protection to the DNS process.
      • Packet filters are typical in low-end routers and home-use network hardware.
  2. Application Gateway
    • An application gateway intercept DNS packets from internal clients heading externally, and generates new packets.
      • Clients are typically resolvers.
      • Returning data is send to the client by the application gateway.
      • An application gateway examines DNS packets to detect anomalies (e.g. DNS tunneling), but the latency is far greater than that of a packet filter.
      • If an application gateway doesn't support a feature, it fails (EDNS0, DNSSEC, ENUM, IPv6 as transport protocol, random src port, etc. ).
  3. Statefull Packet Filter
    • Stateful Firewalls, like packet filters, examine IP header fields, but additionally track the connection in both directions.
      • They offer little advantage over packet filters for DNS.
      • Most DNS traffic is UDP, which is fundamentally stateless.
      • They can detect some, but not all, IP address spoofing.
      • The latency is generally low, but it depends on the quality of the firewall's internal state-table.
  4. Stateful Firewalls Issues
    • Detecting state for UDP traffic, including DNS, is a challenge:
      • Each query must be entered in the firewalls state-table.
      • The state-table becomes huge for busy DNS servers.
      • Some stateful firewalls fail on high DNS traffic load.
    • If NAT is run on the firewall, some firewalls can run out of NAT-Table space because of very busy DNS servers.
    • It is highly recommended to avoid having DNS NATed if possible.
  5. Content Inspection
    • Inspect the payload of IP packets on the Application Level (Layer 7)
      • Often combined with stateful packet-filter
      • Can detect some DNS misuse and protocol attacks (e.g. buffer overflow)
      • Can be the "least common denominator" for DNS (EDNS0, DNSSEC, IPv6, ENUM …)
      • Latency is implementation dependent, but is usually high
      • Content Inspection Algorithms can be single point of failure

6.11.4 DNS and fragmentation

  • if a EDNS maximum message size of 1232 is advertised from the DNS resolver server (recommendation from DNS Flag Day 2020), there should be no UDP fragmentation seen (as most of the Internet is on Ethernet with an MTU of 1500 byte)
    • all incoming fragmented DNS messages towards a DNS resolver are most likely mis-configuration or attack
    • to prevent attacks on the DNS cache of a DNS resolver, it is possible to drop all incoming fragmented UDP traffic towards a DNS resolver
      • it is recommended to run such a configuration in permissive mode for some time (log, but not drop fragmentation) before activating