PowerDNS

最後更新: 2018-03-28

目錄

介紹

pdns 一共分兩部份, 分別是

  • Authoritative Server (no way to pollute the cache): 負責本地的 Domain
  • Recursor (consult other authoritative servers): 它用來解釋其他不是本地的 Domain

由它的結構及 Source code 的行數(10,000) 可知, 它比 Bind 更為安全

GUI 介面

poweradmin(https://www.poweradmin.org)

 


安裝

 

Debian 6

apt-get install pdns-server pdns-backend-mysql mysql-server

主設定檔

  • /etc/powerdns/pdns.conf
  • /etc/powerdns/recursor.conf

 


Testing install

 

在 /etc/powerdns/pdns.conf 加入以下設定

launch=bind
bind-example-zones

執行:

/etc/init.d/pdns restart

/etc/init.d/pdns monitor

already running

測試:

netstat -nl

tcp        0      0 0.0.0.0:53
udp        0      0 0.0.0.0:53

dig www.example.com @127.0.0.1

 

 


用 Mysql 做 backend

 

/etc/powerdns/pdns.conf

#launch=gmysql

/etc/powerdns/pdns.d/pdns.local

gmysql-host=127.0.0.1
gmysql-port=3306
# gmysql-socket=/var/run/mysqld/mysqld.sock
gmysql-user=<mysql user>
gmysql-password=<mysql password>
gmysql-dbname=<powerdns database>

# 建立所需的 table

CREATE DATABASE powerdns;

mysql -u root -p <database> < mysql.sql

# Add a new zone

INSERT INTO domains (name, type) VALUES ('example.org', 'MASTER');
INSERT INTO records (domain_id, name, content, type, ttl, prio) 
  VALUES (1, 'example.org', 'ns1.example.org hostmaster.example.org 1', 'SOA', 86400, NULL);
INSERT INTO records (domain_id, name, content, type, ttl, prio) 
  VALUES (1, 'example.org', 'ns1.example.org', 'NS', 86400, NULL);
INSERT INTO records (domain_id, name, content, type, ttl, prio) 
  VALUES (1, 'example.org', 'ns2.example.org', 'NS', 86400, NULL);
INSERT INTO records (domain_id, name, content, type, ttl, prio) 
  VALUES (1, 'ns1.example.org', '10.0.0.1', 'A', 86400, NULL);
INSERT INTO records (domain_id, name, content, type, ttl, prio) 
  VALUES (1, 'ns2.example.org', '10.0.0.2', 'A', 86400, NULL);

 


設定

 

/etc/powerdns/pdns.conf

# default: 0.0.0.0
allow-recursion=192.168.0.0/24

# Only recurse if question cannot be answered locally
lazy-recursion=yes

# nameserver(pdns-recursor) to handle recursive queries
recursor=127.0.0.1:5353

daemon=yes
guardian=yes

setgid=pdns
setuid=pdns

master=no
slave=no


### DB
# backend threads to start
distributor-threads=3

# backends to launch
launch=gmysql


### Network
local-address=0.0.0.0
local-port=53
disable-tcp=no
max-tcp-connections=10

# Maximum number of milliseconds to queue a query
queue-limit=1500


chroot=/var/spool/powerdns

logfile=/var/log/pdns.log
loglevel=4

# Packet Cache (without any further processing)
cache-ttl=20
#  cache individual backend queries
# CNAME 時最有用
query-cache-ttl=20
# caching negative entries, ie, queries that have no answer.
negquery-cache-ttl=60

include=/etc/powerdns/pdns.d

說明

default-ttl

Seconds a result is valid if not set otherwise

guardian

Run within a guardian process

This guardian monitors the performance of the inner pdns_server instance.

CLI 'pdns_control' 是透過 guardian 實現某些功能 (ping, status, cycle)

 


Authoritative Server Statistic

 

/etc/init.d/pdns dump | tr ',' '\n'

corrupt-packets=0
deferred-cache-inserts=0
deferred-cache-lookup=0
latency=0
packetcache-hit=3
packetcache-miss=6
packetcache-size=0
qsize-q=1
query-cache-hit=4
query-cache-miss=19
recursing-answers=0
recursing-questions=0
servfail-packets=0
tcp-answers=0
tcp-queries=0
timedout-packets=0
udp-answers=9
udp-queries=9
udp4-answers=9
udp4-queries=9
udp6-answers=0
udp6-queries=0

 


以 IP 來認證

 

allow-2136-from=127.0.0.1

            OR

INSERT INTO domainmetadata (domain_id, kind, content) VALUES (3, 'ALLOW-2136-FROM', '127.0.0.1');

以 KEY 來認證: authorizing updates with TSIG keys

tsigkeys table:

INSERT INTO tsigkeys (name, algorithm, secret) VALUES ('rk01', 'hmac-md5', '??????????????');
INSERT INTO domainmetadata (domain_id, kind, content) VALUES (3, 'TSIG-ALLOW-2136', 'rk01');

 


pdns-recursor

 

# Start Service

/etc/init.d/pdns-recursor start                # 它 Default 是用 port 53 的, 所以必須更改

# Setting

/etc/powerdns/recursor.conf

# Support IPv6 records
aaaa-additional-processing=off

allow-from=127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12

# local-address IP addresses to listen on, 
# separated by spaces or commas. 
# Also accepts ports.
local-address=127.0.0.1
local-port=5353

# default: yes
daemon=yes

#  does not query private space IP addresses
dont-query=127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10

# /etc/hosts
export-etc-hosts=on

# Don't log queries. (default)
quiet=yes

# no matter what the original TTL specified
# max-cache-ttl
# defaults to 3600 seconds
# max-negative-ttl
# max-tcp-clients
# max-tcp-per-client
# network-timeout
# packetcache-ttl
# packetcache-servfail-ttl


# 查看 rec_control top-remotes 用,  default:0
remotes-ringbuffer-entries=300


PowerDNS recursor 3.0 uses a fresh UDP source port for each outgoing query
(making spoofing around 64000 times harder)

#  PowerDNS detects when it is being sent too many unexpected answers
spoof-nearmiss-max

Recursor Statistic

rec_control 讀取 socket /var/run/pdns_recursor.controlsocket 拿資料

i.e.

rec_control get-all

all-outqueries  9                    # UDP queries
...........................
answers-slow    1                    # after 1 second
noerror-answers 5
questions       2
cache-entries   76
cache-entries 10
cache-hits      0
cache-misses    1
unexpected-packets 0                 # spoofing

pdns support recursive queries

DNS has two type of server operations:

 - Authoritative: information can be stored in it
 - Recursive: it directs the query to each individual server in the list (+cached results)

Setting

Authoritative(pdns.conf)

recursor=127.0.0.1

Recursive(recursor.conf)

forward-zones=.=8.8.4.4;8.8.8.8

 


DNS record 的格式

 

SOA

The SOA record format is "master_server hostmaster_email serial refresh retry expire default_ttl"

Example:

ns1.datahunter.org datahunter.datahunter.org 1 10800 3600 604800 3600

Setting

# New in version 4.4.0

default-soa-content

Default: a.misconfigured.dns.server.invalid hostmaster.@ 0 10800 3600 604800 3600

# Old Version

# The setting has been removed in 4.4.0

default-soa-name            # ns1.your.domain
default-soa-mail            # admin.your.domain
soa-expire-default 604800   # 7 days
soa-minimum-ttl 3600
soa-refresh-default 10800
soa-retry-default 3600

 


Master & Slaves Server

 

Diagram:

ns1: 10.0.0.1 (Master)

ns2: 10.0.0.2 (Slave)

On The Master Server:

# SLAVE_IP. Format: IP OR IP/N
allow-axfr-ips=10.0.0.2

# yes => Do not allow zone transfers ( Default: no )
disable-axfr=no

# yes => Turn on master support ( Default: no )
master=yes

# Allow AXFR NOTIFY from these IP ranges.( Default: 0.0.0.0/0 )
# Setting this to an empty string will drop all incoming notifies
allow-notify-from=

On The Slaves Server:

slave=yes

# Master IP
allow-notify-from=10.0.0.1

Domain 所需的 record:

INSERT INTO supermasters (ip, nameserver, account) VALUES ('10.0.0.1', 'ns2.example.org', '');

P.S.

BIND:

allow-transfer {SLAVE_IP;}

More Info.

master=yes

When operating as a master, PowerDNS sends out notifications of changes to slaves.

Notifications are only sent for domains with type MASTER in your backend. (Table: domains)

Useful CMD

# This instructs PowerDNS to notify all IP addresses it considers to be slaves of this domain.

pdns_control notify <domain>

# This is truly an override and sends a notification to an arbitrary IP address.

# Can be used in also-notify situations

pdns_control notify-host <domain> <ip-address>

also-notify

# IP addresses, separated by commas

# always receive a notification. Even if they do not match the list in only-notify

Log

Slave 沒有 Permission (IP ACL) 時的 Server log

Mar 28 08:50:45 localhost pdns[7441]: AXFR of domain 'a.com' denied to s.s.s.s

成功 Server log

Mar 28 03:16:29 localhost pdns[7441]: AXFR of domain 'a.com' initiated by s.s.s.s
...
Mar 28 03:16:29 localhost pdns[7441]: AXFR of domain 'a.com' to s.s.s.s finished

Slave Log:

Master 沒有轉 SN (Slave 不用更新)

28-Mar-2018 15:06:17.556 notify: client MasterIP#37883: received notify for zone 'a.com'

Slave 成功 (SN 有更新)

28-Mar-2018 15:19:31.738 notify: client MasterIP#37883: received notify for zone 'a.com'
28-Mar-2018 15:19:31.739 general: zone a.com/IN: Transfer started.
28-Mar-2018 15:19:31.740 xfer-in: transfer of 'a.com/IN' from MasterIP#53: connected using SlaveIP#54856
28-Mar-2018 15:19:31.745 general: zone a.com/IN: transferred serial 2018032802
28-Mar-2018 15:19:31.745 xfer-in: transfer of 'a.com/IN' from MasterIP#53: 
                                  Transfer completed: 3 messages, 46 records, 
                                  1187 bytes, 0.004 secs (296750 bytes/sec)
28-Mar-2018 15:19:31.745 notify: zone a.com/IN: sending notifies (serial 2018032802)

Master notify Slave, 但 Slave 沒有 set zone 或 IP 不對

28-Mar-2018 15:11:41.618 notify: client MasterIP#37883: received notify for zone 'a.com': not authoritative

Master 的 Data 有問題

28-Mar-2018 11:24:00.613 notify: client MasterIP#37883: received notify for zone 'a.com'
28-Mar-2018 11:24:00.861 general: zone a.com/IN: Transfer started.
28-Mar-2018 11:24:00.871 xfer-in: transfer of 'a.com/IN' from MasterIP#53: connected using SlaveIP#37080
28-Mar-2018 11:24:00.877 xfer-in: transfer of 'a.com/IN' from MasterIP#53: 
                                  failed while receiving responses: CNAME and other data
28-Mar-2018 11:24:00.877 xfer-in: transfer of 'a.com/IN' from MasterIP#53: 
                                  Transfer completed: 2 messages, 52 records, 1221 bytes, 
                                  0.006 secs (203500 bytes/sec)

A CNAME record is not allowed to coexist with any other data.

In other words, if a.com is an alias for a.com, you can't also have an MX record for a.com, or an A record, or even a TXT record.

DOC

http://doc.powerdns.com/html/slave.html

 


pdns_control

 

pdns_control version

3.3

pdns_control ping

PONG

pdns_control status

1010: Child running on pid 2258

pdns_control uptime

1.3 minutes

pdns_control reload    # reload all zones

Ok

pdns_control ccounts

negative queries: 10, queries: 7, non-recursive packets: 8, recursive packets: 0

pdns_control cycle    # restart instance

ok

 


MySetting

 

# Version 3.3

/etc/powerdns/pdns.conf

master=yes

# Cache Setting
cache-ttl=20                      # entire packets cache 
negquery-cache-ttl=60             # cache individual backend queries
query-cache-ttl=20                # cache individual backend queries

disable-tcp=no

# LOG Setting
# 在新版裡, 已唔支援 use-logfile=yes, 如果仍想獨立 log file, 就要
# logging to local0
logging-facility=0
loglevel=4
query-logging=no

service pdns restart

/etc/rsyslog.d/40-pdns.conf

local0.info                       -/var/log/pdns.log

service rsyslog restart

 


Update Slave DNS record By Script

 

update-sn.sh

#!/bin/bash
#
# sync dns record to slave(i.e. ns2) by update SOA record SN
#

# mysql login
user=powerdns
pass=????
MyDoamin=????
Admin=tim@????

MySN=$(date +%y%m%d%H%M)
MyContent="ns1.$MyDoamin $Admin $MySN 1800 300 604800 600"
MySQL="update records set content=\"$MyContent\" where type=\"SOA\" and name=\"$MyDoamin\""

# run sql
echo $MySQL | mysql -u $user $user -p$pass

echo "Done"

 


其他工具

 

zone2sql

 


Web Pannel

 

 


Install from PowerDNS repos

 

yum install epel-release yum-plugin-priorities

curl -o /etc/yum.repos.d/powerdns-rec-43.repo https://repo.powerdns.com/repo-files/centos-rec-43.repo

yum install pdns                         # PowerDNS Authoritative Server - version 4.3.X

yum install pdns-recursor            # PowerDNS Recursor - version 4.3.X

 


Web API

 

The PowerDNS Authoritative Server features a built-in webserver that exposes a JSON/REST API

Port: 8081/TCP

Setting

# a webserver is launched
webserver=yes

# Defaut: 8081
webserver-port=8081
# Defaults to 127.0.0.1
webserver-address=0.0.0.0

# only allowed from these subnets
webserver-allow-from=127.0.0.1,192.168.200.0/24

# none, normal, detailed
webserver-loglevel=normal

# plaintext password
# webserver-password=123456

# API
api=yes
api-key=changeme

# Checking

curl -H 'X-API-Key: ????' http://pdns:8081/api/v1/servers/localhost | jq .

{
  "config_url": "/api/v1/servers/localhost/config{/config_setting}",
  "daemon_type": "authoritative",
  "id": "localhost",
  "type": "Server",
  "url": "/api/v1/servers/localhost",
  "version": "4.3.1",
  "zones_url": "/api/v1/servers/localhost/zones{/zone}"
}

# Add / Replace record to the zone

URL='http://pdns:8081/api/v1/servers/localhost/zones/dnslink.hk.'
ApiKey=????

MyrRecord='{
  "rrsets": [
    {
      "name": "dnslink.hk.",
      "ttl": 600,
      "type": "A",
      "changetype": "REPLACE",
      "records": [
        {
          "content": "127.0.0.1",
          "disabled": false,
          "type": "A"
        },
        {
          "content": "127.0.0.2",
          "disabled": false,
          "type": "A"
        }
      ]
    }
  ]
}'

echo $MyrRecord

curl -X PATCH --data "$MyrRecord" -H "X-API-Key: $ApiKey" $URL | jq .

 


domainmetadata

 

mysql> select * from domainmetadata;

+----+-----------+--------------+---------------------+
| id | domain_id | kind         | content             |
+----+-----------+--------------+---------------------+
| 70 |        20 | SOA-EDIT-API | DEFAULT             |
| 71 |        20 | SOA-EDIT     | INCEPTION-INCREMENT |
| 72 |        20 | API-RECTIFY  | 1                   |
+----+-----------+--------------+---------------------+

SOA-EDIT

Powerdns will always use SOA-EDIT when serving SOA records,

thus a query for the SOA record of the recently update domain,

might have an unexpected result due to a SOA-EDIT setting.

DEFAULT:

Generate a soa serial of YYYYMMDD01.

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.

INCEPTION

sets the SOA Serial to the current two-week signing period start in YYYYMMDD01 format,

EPOCH

is the number of seconds since the epoch

SOA-EDIT-API

On changes to the contents of a zone made through the API,

  the SOA record will be edited according to the SOA-EDIT-API rules.

These rules are the same as the SOA-EDIT-DNSUPDATE rules.

If not set during zone creation, a SOA-EDIT-API metadata record is created and set to DEFAULT

If this record is removed from the backend,

  the default behaviour is to not do any SOA editing based on this setting.

 


Troubleshoot

 

log

Feb 16 15:55:48 ns1 pdns[2705]: Should not get here (x.x|2): please run pdnssec rectify-zone x.x

pdns.local.gmysql.conf

gmysql-dnssec=no

 


Doc

 

 

 

Creative Commons license icon Creative Commons license icon Creative Commons license icon