PowerDNS的部署与使用
PowerDNS简介
PowerDNS成立于上世纪90年代后期,是开源DNS的主要供应商
目前主要产品有Authoritative Server、Recursor和Dnsdist产品,目前是完全开源的
PowerDNS也有商业化的产品支持,其用户和客户包括了全球领先的电信服务供应商、大型集成商及财富500强软件公司,在斯堪的纳维亚、德国和荷兰,PowerDNS是域名服务器软件的第一大供应商。
与bind不同,powerDNS的权威和递归服务是分开的服务

作为权威域名服务器
安装
#这里以mysql作为后端存储服务,所以这里安装的是pdns-backend-mysql
yum install pdns pdns-backend-mysql
#也可以指定版本安装,例如,要安装4.6版本的
yum install -y epel-release yum-plugin-priorities &&
curl -o /etc/yum.repos.d/powerdns-auth-46.repo https://repo.powerdns.com/repo-files/el-auth-46.repo &&
yum install pdns -y
可以通过 yum list pdns-backend* | grep 4.6 来查看可用的4.6版本的后端所有存储驱动
安装存储数据库
这里以mysql作为例子,为了方便,这里使用docker-compose镜像部署
version: '3'
services:
mysql:
image: mysql:8.0
container_name: mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: 111111
#MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: powerdns
MYSQL_USER: powerdns
MYSQL_PASSWORD: powerdns
volumes:
- ./db:/var/lib/mysql
- ./etc/my.cnf:/etc/my.cnf
- /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime
ports:
- 3306:3306
command:
#为了能远程登录root,所以修改了验证模块,生产中建不开启
- --default-authentication-plugin=mysql_native_password
docker-compose.yaml文件同目录下的新建etc目录,用来存放mysql配置文件
配置文件内容
vim ./etc/my.cnf
[mysqld]
port = 3306
#socket = /tmp/mysql.sock
datadir = /var/lib/mysql/var
skip-external-locking
key_buffer_size = 32M
max_allowed_packet = 1M
table_open_cache = 128
sort_buffer_size = 768K
net_buffer_length = 8K
read_buffer_size = 768K
read_rnd_buffer_size = 512K
myisam_sort_buffer_size = 8M
thread_cache_size = 16
tmp_table_size = 32M
performance_schema_max_table_instances = 1000
explicit_defaults_for_timestamp = true
#skip-networking
max_connections = 500
max_connect_errors = 100
open_files_limit = 65535
log-bin=mysql-bin
binlog_format=mixed
server-id = 1
expire_logs_days = 10
early-plugin-load = ""
default_storage_engine = InnoDB
innodb_file_per_table = 1
innodb_data_home_dir = /var/lib/mysql/var
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = /var/lib/mysql/var
innodb_buffer_pool_size = 128M
innodb_log_file_size = 32M
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 50
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip_name_resolve=on
部署容器
docker-compose up -d
新建相关表
mysql -u powerdns -ppowerdns
use powerdns
CREATE TABLE domains (
id INT AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
master VARCHAR(128) DEFAULT NULL,
last_check INT DEFAULT NULL,
type VARCHAR(6) NOT NULL,
notified_serial INT DEFAULT NULL,
account VARCHAR(40) DEFAULT NULL,
PRIMARY KEY (id)
) Engine=InnoDB;
CREATE UNIQUE INDEX name_index ON domains(name);
CREATE TABLE records (
id BIGINT AUTO_INCREMENT,
domain_id INT DEFAULT NULL,
name VARCHAR(255) DEFAULT NULL,
type VARCHAR(10) DEFAULT NULL,
content BLOB(64000) DEFAULT NULL,
ttl INT DEFAULT NULL,
prio INT DEFAULT NULL,
change_date INT DEFAULT NULL,
disabled TINYINT(1) DEFAULT 0,
ordername VARCHAR(255) BINARY DEFAULT NULL,
auth TINYINT(1) DEFAULT 1,
PRIMARY KEY (id)
) Engine=InnoDB;
CREATE INDEX nametype_index ON records(name,type);
CREATE INDEX domain_id ON records(domain_id);
CREATE INDEX recordorder ON records (domain_id, ordername);
CREATE TABLE supermasters (
ip VARCHAR(64) NOT NULL,
nameserver VARCHAR(255) NOT NULL,
account VARCHAR(40) NOT NULL,
PRIMARY KEY (ip, nameserver)
) Engine=InnoDB;
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) NOT NULL,
comment BLOB(64000) NOT NULL,
PRIMARY KEY (id)
) Engine=InnoDB;
CREATE INDEX comments_domain_id_idx ON comments (domain_id);
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;
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,
content TEXT,
PRIMARY KEY(id)
) Engine=InnoDB;
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;
CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
flush privileges;
pdns配置
vim /etc/pdns/pdns.conf
#设置数据库相关的
launch=gmysql
gmysql-host=10.0.0.10
gmysql-port=3306
gmysql-dbname=powerdns
#管理数据库的相关用户和密码
gmysql-user=powerdns
gmysql-password=powerdns
#访问权限
allow-axfr-ips=0.0.0.0/0,::1
allow-dnsupdate-from=0.0.0.0/0,::1
allow-notify-from=0.0.0.0/0,::/0
allow-unsigned-notify=yes
also-notify=10.0.0.10
#daemon 启动
daemon=yes
disable-axfr=no
guardian=no
#是否master
master=yes
#是否slave
slave=no
#启动权限
setgid=pdns
setuid=pdns
#打印日志
log-dns-details=yes
log-dns-queries=no
loglevel=6
log-timestamp=yes
logging-facility=0
#开启api
api=yes
api-key=dnsadmin1syn
#启动webserver 监控
webserver=yes
webserver-address=0.0.0.0
webserver-allow-from=0.0.0.0/0
webserver-port=8081
#监听的地址端口
local-address=0.0.0.0
local-port=54
#记录query 日志
query-logging=yes
启服务
systemctl start pnds
测试
通过api来访问
#需要带上配置文件中设置的api-key
curl -v -H 'X-API-Key: dnsadmin1syn' http://10.0.0.10:8081/api/v1/servers
* About to connect() to 10.0.0.10 port 8081 (#0)
* Trying 10.0.0.10...
* Connected to 10.0.0.10 (10.0.0.10) port 8081 (#0)
> GET /api/v1/servers HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 10.0.0.10:8081
> Accept: */*
> X-API-Key: dnsadmin1syn
>
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: *
< Connection: close
< Content-Length: 250
< Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline'
< Content-Type: application/json
< Server: PowerDNS/4.1.14
< X-Content-Type-Options: nosniff
< X-Frame-Options: deny
< X-Permitted-Cross-Domain-Policies: none
< X-Xss-Protection: 1; mode=block
<
* Closing connection 0
[{"config_url": "/api/v1/servers/localhost/config{/config_setting}", "daemon_type": "authoritative", "id": "localhost", "type": "Server", "url": "/api/v1/servers/localhost", "version": "4.1.14", "zones_url": "/api/v1/servers/localhost/zones{/zone}"}]
部署powerdns-admin
用来通过web界面,来管理pdns
通过docker来部署
#这里的key就是pdns配置文件中设置的api-key
docker run -it -d \
-e SECRET_KEY='dnsadmin1syn' \
-v pda-data:/data \
-p 9191:80 \
ngoduykhanh/powerdns-admin:latest
然后直接访问http://[IP]:9191
然后注册用户,第一个注册的用户默认为管理员
进去之后,需要添加pdns的服务

连接成功的会在左边菜单栏显示PDNS,没配置成功的是无法显示的

新建域名。创建一条记录


然后测试是否生效
dig www.abc.com @10.0.0.10 -p 54
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7 <<>> www.abc.com @10.0.0.10 -p 54
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38613
;; 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: 1680
;; QUESTION SECTION:
;www.abc.com. IN A
;; ANSWER SECTION:
www.abc.com. 60 IN A 1.1.1.1
;; Query time: 0 msec
;; SERVER: 10.0.0.10#54(10.0.0.10)
;; WHEN: 一 4月 24 12:10:54 CST 2023
;; MSG SIZE rcvd: 56
已经可以正常解析
但是发现无法递归解析
这里以解析百度为例
dig www.baidu.com @10.0.0.10 -p 54
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7 <<>> www.baidu.com @10.0.0.10 -p 54
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 29256
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1680
;; QUESTION SECTION:
;www.baidu.com. IN A
;; Query time: 2 msec
;; SERVER: 10.0.0.10#54(10.0.0.10)
;; WHEN: 一 4月 24 12:12:02 CST 2023
;; MSG SIZE rcvd: 42
可以看到是被拒绝的,这是因为,pdns服务是不提供递归和转发的,如果需要有递归和转发的功能,就需要启 pdns-recursor 服务
部署pdns-recursor递归服务
安装
yum install -y pdns-recursor
修改配置文件
vim /etc/pdns-recursor/recursor.conf
#允许访问的地址
allow-from=0.0.0.0/0
#开启日志
disable-syslog=yes
#关闭dnssec 转发有用
dnssec=off
#forward-zones是只转发,不递归 少用
#forward-zones=hexug.com=127.0.0.1:54
#forward-zones-recurse是找不到就递归,找的到就转发,用逗号分隔 这里是将pdns中定义的域名,转发到pdns服务的54端口上
forward-zones-recurse=hexug.com=127.0.0.1:54,abc.com=127.0.0.1:54,.=114.114.114.114
#绑定在所有端口商
local-address=0.0.0.0
local-port=53
log-common-errors=yes
security-poll-suffix=
setgid=pdns-recursor
setuid=pdns-recursor
启服务
systemctl restart pdns-recursor
注意,这里可能会报错,因为一般本地会有服务在占用53端口,需要先kill掉
再解析测试,这个时候解析的端口就不再是54端口,而是53端口
解析本地定义的域名
dig www.abc.com @10.0.0.10 -p 53
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7 <<>> www.abc.com @10.0.0.10 -p 53
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49462
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.abc.com. IN A
;; ANSWER SECTION:
www.abc.com. 52 IN A 1.1.1.1
;; Query time: 0 msec
;; SERVER: 10.0.0.10#53(10.0.0.10)
;; WHEN: 一 4月 24 12:21:10 CST 2023
;; MSG SIZE rcvd: 56
解析其他互联网域名
dig www.baidu.com @10.0.0.10 -p 53
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7 <<>> www.baidu.com @10.0.0.10 -p 53
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52182
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.baidu.com. IN A
;; ANSWER SECTION:
www.baidu.com. 125 IN CNAME www.a.shifen.com.
www.a.shifen.com. 125 IN A 14.119.104.254
www.a.shifen.com. 125 IN A 14.119.104.189
;; Query time: 28 msec
;; SERVER: 10.0.0.10#53(10.0.0.10)
;; WHEN: 一 4月 24 12:22:03 CST 2023
;; MSG SIZE rcvd: 101
就可以正常解析
WEB&API
前文提到递归服务器并没有图形化的配置界面,但仍然提供了web服务及api服务,可以通过向配置文件中添加以下内容来完成web服务的开启:
修改配置文件 /etc/pdns-recursor/recursor.conf
添加下面这段,开启web服务
webserver=yes
webserver-allow-from=0.0.0.0/0
webserver-address=0.0.0.0
webserver-port=8082
#开启webserver,允许所有ip访问,web服务监听IP为所有接口IP,web服务器监听端口号8082
web开启后,则可通过 http://<服务器IP>:8082 访问web服务,可看到当下服务器的工作状态:

创建 /var/zones 文件夹,用于放置配置文件,并将所有者授权给pdns-recursor:
mkdir /var/zones
chown pdns-recursor:pdns-recursor /var/zones
修改递归服务器配置文件 /etc/pdns-recursor/recursor.conf ,加入以下内容
api-key=abcd.1234
api-config-dir=/var/zones/
include-dir=/var/zones
#加入api-key,api配置文件位置/var/zones,将/var/zones文件夹包含进配置文件
#api部分就是使用web的端口,就是上面的定义的8082
修改完成后,需要对服务进行重启。
使用以下命令进行验证(若有(23) Failed writing body报错,请先 yum -y install jq )
curl -v -H 'X-API-Key: abcd.1234' http://127.0.0.1:8082/api/v1/servers/localhost | jq .
返回以下结果,则表示API启用成功:
<---此处省略若干字符--->
{
"config_url": "/api/v1/servers/localhost/config{/config_setting}",
"daemon_type": "recursor",
"id": "localhost",
"type": "Server",
"url": "/api/v1/servers/localhost",
"version": "4.6.0",
"zones_url": "/api/v1/servers/localhost/zones{/zone}"
}
此时我们添加 http://sina.cn 的解析,到 10.0.0.10:54 ,并且允许其递归:

数据部分
{
"kind": "Forwarded",
"name": "sina.com.",
"servers": ["10.0.0.10:54"],
#转发的同时是否允许递归
"recursion_desired": true,
"type": "zone"
}
添加完成后,到递归服务器的 /var/zones 文件夹下会发现一个 zone-sina.cn..conf 的文件,查看内容,显示如下:
cat /var/zones/zone-sina.cn..conf
# Generated by pdns-recursor REST API, DO NOT EDIT
forward-zones-recurse+=sina.com.=10.0.0.10:54
再次尝试将 http://qq.com 的解析递归只 10.1.1.1 ,并且不允许递归:

body部分
{
"kind": "Forwarded",
"name": "qq.com.",
"servers": ["10.1.1.1:53"],
"recursion_desired": false,
"type": "zone"
}
虽然显示的是422,并且返回的消息是无法找到域名
{
"error": "Could not find domain 'qq.com.'"
}
但是,查看 /var/zones 目录下,还是多了一个 zone-qq.com..conf 文件,说明创建已经成功,文件内容如下:
cat /var/zones/zone-qq.com..conf
# Generated by pdns-recursor REST API, DO NOT EDIT
forward-zones+=qq.com.=10.1.1.1:53
但是解析的时候还是解析出了公网的,说明,其实没有生效,而且重启pdns-recursor会报错

就是没有定义forward-zones字段
所以,需要在配置文件中添加上
vim /etc/pdns-recursor/recursor.conf
forward-zones=
不用加任何值,只要有这个字段就行
然后再添加

会显示已存在,这个时候,只需要重启服务就好了
然后再添加一个别的,正确添加的返回结果如下

将以上内容转换成Python代码,如下:
import requests , json
def set_forwarded_zone(recursor,domainname,dns,dnsport=53,boolean = False):
url = 'http://%s:8082/api/v1/servers/localhost/zones'%recursor
headers = {'X-API-Key':'abcd.1234'}
data = {
"kind":"Forwarded",
"name":domainname+'.',
"servers":["%s:%s"%(dns,dnsport)],
"recursion_desired":boolean,
"type":"zone"
}
data = json.dumps(data)
req = requests.post(url=url,headers=headers,data=data)
print(req.text)
添加 http://sina.cn 的解析,到 10.5.22.11:53 ,并且允许其递归:
set_forwarded_zone('10.0.0.10','sina.cn','10.5.22.11',53,True)
执行后返回结果:
{"id": "sina.cn.", "kind": "Forwarded", "name": "sina.cn.", "records": [], "recursion_desired": true, "servers": ["10.5.22.11:53"], "url": "/api/v1/servers/localhost/zones/sina.cn."}
http://qq.com的解析递归到10.1.1.1,并且不允许递归,执行:
set_forwarded_zone('10.0.0.10','qq.com','10.1.1.1',53)
执行后返回结果:
{"id": "qq.com.", "kind": "Forwarded", "name": "qq.com.", "records": [], "recursion_desired": false, "servers": ["10.1.1.1:53"], "url": "/api/v1/servers/localhost/zones/qq.com."}
以上配置生效后,预期效果:10.5.22.11和10.1.1.1并非是http://sina.cn和http://qq.com的权威服务器,由于http://sina.cn允许递归,理论上可以得到解析结果,而http://qq.com由于不允许递归,则无法解析。
进行验证:
dig +short @10.0.0.10 sina.cn
dig +short @10.0.0.10 qq.com
结果都无解析结果返回,推测,可能是由于10.5.22.11和10.1.1.1都不是dns服务器导致,在此,将转发目标都指向一台dns服务器10.0.0.10:54,再次尝试。
修改 zone-sina.cn..conf和zone-qq.com..conf文件,重启递归服务再次尝试:
dig +short @10.0.0.10 sina.com
66.102.251.24
dig +short @10.0.0.10 qq.com
所以,递归转发到目标服务器,目标服务器必须是一台DNS,允许转发的选项才会生效。
接口部分
都是需要加上一个Header
X-API-Key: xxxx #就是pdns-recursor的配置文件中配置的api-key
创建转发域名
POST /api/v1/servers/localhost/zones
#data部分
{
"kind": "Forwarded",
"name": "qq.com.",
"servers": ["10.0.0.10:54"],
"recursion_desired": false,
"type": "zone"
}
获取所有域名配置
GET /api/v1/servers/localhost/zones
获取指定域名的配置
GET /api/v1/servers/localhost/zones/<zone-name>
#例如
GET http://10.0.0.10:8082/api/v1/servers/localhost/zones/qq.com
删除指定域名
DELETE /api/v1/servers/localhost/zones/<zone-name>
DNS分配器(Dnsdist)
dnsdist 是一个DNS的负载均衡器。
它本身并不提供解析服务,而是将DNS流量路由到指定服务器,为用户提供最佳解析性能,同时也可实现应用流量分摊。
安装服务
dnsdist安装非常简单,以CentOS/RH为例,以下命令即可完成安装:
yum install -y epel-release
yum install -y dnsdist
在前台运行
安装dnsdist后,开始试验的最快方法是在前台启动它:
dnsdist -l 127.0.0.1:5300 9.9.9.9 2620:fe::fe 2620:fe::9
这将使 dnsdist 侦听 IP 地址 127.0.0.1、端口 5300 并将所有查询转发到列出的三个 IP 地址,并采用合理的平衡策略。
简单配置
这里只对dnsdist的使用作简单介绍。
新建/etc/dnsdist/dnsdist.conf文件,写入以下内容:
注意:配置文件的语法是lua的语法,所以注释是 --
--设置本地监听地址为0.0.0.0的5300端口
setLocal('0.0.0.0:5300')
--允许列表内的IP来进行解析
setACL({'192.0.2.0/28', '10.194.0.0/16'})
--新增服务器114.114.114.114,qps限制为10
newServer({address="114.114.114.114", qps=10})
--新增服务器10.5.253.14,qps限制为10
newServer({address="10.5.253.14", qps=10})
--新增服务器10.5.253.15:5300,并使用本机的10.210.11.18与其进行通信
newServer({address="10.5.253.15:5300", source="10.210.11.18"})
newServer({address="2001:db8::4", name="dns1", qps=10})
newServer({address="[2001:db8::3]:5300", qps=10})
--设置服务负载方式为轮询
setServerPolicy(roundrobin)
注意,请确认newServer中的服务器均为可用的dns服务器,为能够更加直观看到效果,建议它们解析到的某一个域名为不同的IP地址。
以上配置加入后,可通过命令设置自启并立即启动dnsdist,更多的配置请参考配置指南:官方文档
#前台手动启动
dnsdist -C dnsdist.conf --local=0.0.0.0:5300
Marking downstream 114.114.114.114:53 as 'up'
Marking downstream 10.5.253.14:53 as 'up'
Marking downstream 10.5.253.15:5300 as 'up'
Marking downstream [2001:db8::4]:53 as 'up'
Marking downstream [2001:db8::3]:5300 as 'up'
Listening on 0.0.0.0:5300
>
#systemd管理启动
systemctl enable dnsdist --now
启动后,可直接在本机重复使用以下命令进行测试:
dig +short @10.210.11.18 -p 5300 s.......t.com.cn +nocookie

dnsdist具有强大功能,支持Lua脚本
请注意,dnsdist 将我们放在上面的提示中,我们可以在其中获得一些统计信息:
> showServers()
# Address State Qps Qlim Ord Wt Queries Drops Drate Lat Pools
0 114.114.114.114:53 up 0.0 1 1 1 1 0 0.0 0.0
1 10.5.253.14:53 up 0.0 1 1 1 0 0 0.0 0.0
2 [2001:db8::3]:5300 up 0.0 10 1 1 0 0 0.0 0.0
3 [2001:db8::4]:53 up 0.0 10 1 1 0 0 0.0 0.0
4 10.5.253.15:5300 up 0.0 0 1 1 0 0 0.0 0.0
showServers() 通常是您登录控制台时首先使用的命令之一。
在这里我们也可以看到我们的配置。配置了 5 个下游服务器,其中前 4 个有 QPS 限制(分别为每秒 1、1、10 和 10 次查询)
最后一个服务器没有限制,我们可以轻松测试:
for a in {0..1000}; do dig powerdns.com @127.0.0.1 -p 5300 +noall +nocookie > /dev/null; done
> showServers()
# Address State Qps Qlim Ord Wt Queries Drops Drate Lat Pools
0 114.114.114.114:53 up 1.0 1 1 1 7 0 0.0 1.6
1 10.5.253.14:53 up 1.0 1 1 1 6 0 0.0 0.6
2 [2001:db8::3]:5300 up 10.3 10 1 1 64 0 0.0 2.4
3 [2001:db8::4]:53 up 10.3 10 1 1 63 0 0.0 2.4
4 10.5.253.15:5300 up 125.8 0 1 1 671 0 0.0 0.4
All 145.0 811 0
请注意,前 4 台服务器都被限制在接近其配置的 QPS,而我们的最后一台服务器占用了大部分流量。没有查询被删除,所有服务器都保持运行。
更改服务器设置
服务器来自 showServers() 编号, getServer() 用于获取此Server对象以对其进行操作。
要强制关闭服务器,请尝试Server:setDown():
> getServer(0):setDown()
> showServers()
# Address State Qps Qlim Ord Wt Queries Drops Drate Lat Pools
0 114.114.114.114:53 up 0.0 1 1 1 8 0 0.0 0.0
...
DOWN全部大写表示它被强制关闭。
小写down意味着 dnsdist 本身已经断定服务器已关闭。
同样,Server:setUp() 强制服务器启动,并将 Server:setAuto() 其返回到默认的可用性探测。
要更改服务器的 QPS,请使用 Server:setQPS():
> getServer(0):setQPS(1000)
对解析记录自定义
查看所有自定义规则
> showRules()
# Name Matches Rule Action
0 2 qname in www.aaa.com. spoof in 2001:db8::1
1 4 (Src: ::/0) to pool ipv6root
2 0 (Src: 0.0.0.0/0) to pool ipv6root
或者带有uuid的
> showRules({showUUIDs=true})
# Name UUID Cr. Order Matches Rule Action
0 d60df1ea-0c1c-4b22-b2b8-9a5c24c8e19c 2 2 qname in www.aaa.com. spoof in 2001:db8::1
1 19c8012e-4850-4217-8d2c-d1fc211dd51c 0 4 (Src: ::/0) to pool ipv6root
2 b1a7525f-db5f-4593-ad77-9615e94a01b7 1 0 (Src: 0.0.0.0/0) to pool ipv6root
添加解析规则
> addAction({"www.bbb.com."}, SpoofAction("1.2.3.4"))
查看
> showRules({showUUIDs=true})
# Name UUID Cr. Order Matches Rule Action
0 d60df1ea-0c1c-4b22-b2b8-9a5c24c8e19c 2 2 qname in www.aaa.com. spoof in 2001:db8::1
1 19c8012e-4850-4217-8d2c-d1fc211dd51c 0 4 (Src: ::/0) to pool ipv6root
2 b1a7525f-db5f-4593-ad77-9615e94a01b7 1 0 (Src: 0.0.0.0/0) to pool ipv6root
3 1324d473-1b76-46b6-884f-bc59ef6c2c99 3 0 qname in www.bbb.com. spoof in 1.2.3.4
发现是在最下面,因为上面有两条规则是兜底的
1 19c8012e-4850-4217-8d2c-d1fc211dd51c 0 4 (Src: ::/0) to pool ipv6root
2 b1a7525f-db5f-4593-ad77-9615e94a01b7 1 0 (Src: 0.0.0.0/0) to pool ipv6root
包揽了所有的解析,如果解析规则在这两条下面,就永远也无法匹配到,所有需要移到最上面去
> mvRuleToTop()
> showRules({showUUIDs=true})
# Name UUID Cr. Order Matches Rule Action
0 1324d473-1b76-46b6-884f-bc59ef6c2c99 3 0 qname in www.bbb.com. spoof in 1.2.3.4
1 d60df1ea-0c1c-4b22-b2b8-9a5c24c8e19c 2 2 qname in www.aaa.com. spoof in 2001:db8::1
2 19c8012e-4850-4217-8d2c-d1fc211dd51c 0 4 (Src: ::/0) to pool ipv6root
3 b1a7525f-db5f-4593-ad77-9615e94a01b7 1 0 (Src: 0.0.0.0/0) to pool ipv6root
此时再解析 www.bbb.com 就会是我们设置的ip
$ dig www.bbb.com @192.168.140.71
; <<>> DiG 9.18.18-0ubuntu0.22.04.2-Ubuntu <<>> www.bbb.com @192.168.140.71
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20696
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;www.bbb.com. IN A
;; ANSWER SECTION:
www.bbb.com. 60 IN A 1.2.3.4
;; Query time: 0 msec
;; SERVER: 192.168.140.71#53(192.168.140.71) (UDP)
;; WHEN: Wed Jul 24 17:02:59 CST 2024
;; MSG SIZE rcvd: 56
删除规则
> rmRule("1324d473-1b76-46b6-884f-bc59ef6c2c99")
就删除了uuid=1324d473-1b76-46b6-884f-bc59ef6c2c99的规则
限制访问
默认情况下,dnsdist 侦听127.0.0.1(不是::1!)端口 53。
要侦听不同的地址,请使用 -l 命令行选项(对于在前台进行测试很有用),或在配置文件中使用 setLocal()and :addLocal()
setLocal('192.0.2.53') -- 监听192.0.2.53, port 53
addLocal('[::1]:5300') -- 同时也监听再 ::1, port 5300
在处理数据包之前,它们必须通过 ACL,这有助于默认为RFC 1918私有 IP 空间。这使我们无法轻易成为开放的 DNS 解析器。
将网络范围添加到ACL是使用 setACL() 和 addACL() 函数完成的:
setACL({'192.0.2.0/28', '2001:db8:1::/56'}) -- 设置acl 仅允许使用解析器的网段
addACL('2001:db8:2::/56') -- 添加网段 扩展acl 允许这个网段的使用
dnsdist 旨在几乎立即(重新)启动。
但是为了防止更改配置时停机,控制台可用于实时配置。
在控制台上发出delta()将打印自启动以来对配置所做的更改:
> delta()
-- Wed Feb 22 2017 11:31:44 CET
addLocal('127.0.0.1:5301', false)
-- Wed Feb 22 2017 12:03:48 CET
addACL('192.0.2.1/8')
-- Wed Feb 22 2017 12:05:51 CET
addACL('2001:db8::1')
使用 dnsdist 控制台
dnsdist 可以通过加密的 tcp 连接公开命令行控制台,以控制它、调试 DNS 问题和检索统计信息。
控制台可以启用controlSocket():
controlSocket('0.0.0.0:5199')
不建议在未启用加密的情况下启用控制台。请注意,加密需要在启用 libsodium 支持的情况下构建 dnsdist。
一旦你有一个启用了 libsodium 的 dnsdist,启用加密的第一步是生成一个密钥 makeKey() :
./dnsdist -l 127.0.0.1:5300
[..]
> makeKey()
setKey("ENCODED KEY")
然后将生成的 setKey() 行添加到您的 dnsdist 配置文件,以及 controlSocket():
controlSocket('0.0.0.0:5199') -- 在本机的所有IP的5199端口上侦听客户端连接
setKey("ENCODED KEY") -- 控制台的key
现在您可以运行 dnsdist -c 来连接到控制台。
这会使dnsdist读取其配置文件并使用 controlSocket() 和 setKey()语句来建立与服务器的连接。
如果要通过网络连接,请使用相同的两条语句创建一个配置文件并运行 dnsdist -C /path/to/configfile -c
或者,可以在客户端命令行上指定地址和密钥:
dnsdist -k "ENCODED KEY" -c 192.0.2.53:5199
注意:这会将密钥泄露到您的 shell 的历史记录中,因此不推荐这样做。
从 1.3.0 开始,dnsdist 支持使用 ACL 限制哪些客户端可以连接到控制台:
controlSocket('192.0.2.53:5199')
setConsoleACL('192.0.2.0/24')
默认值为“127.0.0.1”,将控制台的使用限制为本地用户。
请确保在使用 addConsoleACL() 或 setConsoleACL() 允许从远程客户端连接之前启用加密。
即使控制台仅限于本地用户使用,仍强烈建议使用加密,以防止未经授权的本地用户连接到控制台。
范例配置文件
dnsdist.conf 文件
-- 设置监听在ipv4和ipv6的5199端口上
controlSocket("192.168.1.71")
controlSocket("[2001:1:2:2::71]")
-- 允许192.168.1.0/24网络和所有ipv6地址的客户端能够远程访问到dnsdist的console
setConsoleACL({"192.168.1.0/24","::/0"})
setKey("MxxxxxxxxxxxxxxxxxxxxxNWNb+Se2eXU5+Bb74=")
-- 设置dns服务的监听地址
addLocal("[2001:1:2:2::71]:53")
addLocal("192.168.1.71:53")
-- 设置允许访问的客户端ip
setACL({"0.0.0.0/0","::/0"})
-- 导入其他lua配置
package.path = package.path .. ";/etc/dnsdist/?.lua"
require "custom"
其他lua配置
custom.lua
-- 创建缓存
ipcache = newPacketCache(50000000, { 86400, 0, 60, 120, false })
-- 设置规则 当匹配到什么地址的时候,请求发往哪个服务器池
addAction(AndRule({makeRule("::/0"),}), PoolAction("pool1"))
addAction(AndRule({makeRule("0.0.0.0/0"),}), PoolAction("pool1"))
-- 设置提供服务的服务器池 这些服务器是后端真实提供解析的服务器
newServer({name="rec-1",address="[2001:1:2:3::100]:53",sockets=16,weight=1,useClientSubnet=true,order=1, pool={"pool1",},})
newServer({name="rec-2",address="[2001:1:2:3::200]:53",sockets=16,weight=1,useClientSubnet=true,order=1, pool={"pool1",},})
getPool("pool1"):setCache(ipcache)
setUDPMultipleMessagesVectorSize(1024)
setRingBuffersSize(50000, 200)
setWHashedPertubation(1234)
setServerPolicy(whashed)
setECSSourcePrefixV6(32)
setSecurityPollSuffix("")
服务器分发策略
使用 setServerPolicy(<POLICY>) 来设置
默认自带的策略
- leastOutstanding 默认策略,按照查询最少的来匹配
简单说就是每次都分配查询次数最少的服务器- 按照查询最少的来分配
- 遇到查询一样少的,按照设置的顺序来匹配
- 在同一条设置的时候,选择具有最低测量延迟的那个(超过该服务器回答的最后 128 个查询的平均值)
- firstAvailable
匹配第一个 未超过 其 QPS 限制的可用服务器,按递增的“顺序”排序。
如果所有服务器都超过其 QPS 限制,则根据 leastOutstanding 策略选择服务器。
目前这是唯一使用 QPS 限制的策略。 - wrandom
随机分配
也可以根据权重来分配,权重是在newServer()中,有个参数weight来配置权重,不配置此参数,则默认权重为1 - whashed
whashed是一个类似的加权策略,但将具有相同哈希值的问题分配给相同的服务器,从而实现更好的缓存集中度(“粘性查询”)。
当前的散列算法是基于查询的 qname。
可以使用setWHashedPertubation(value)来明确哈希的对象,使不同的实例能得到相同的hash - chashed
chashed是一致的散列分布策略。具有相同哈希值的相同问题将分发到相同的服务器。
但与whashed策略不同的是,这种分布会随着时间的推移保持一致。
添加或删除服务器只会重新映射一小部分查询。 - roundrobin
不加区别地将每个查询发送到下一个启动的服务器。如果所有服务器都关闭,该策略仍会默认选择一台服务器。
设置setRoundRobinFailOnNoServer()为true将更改此行为。
还可以通过LUA自定义策略,这里不做介绍,可以参考 https://dnsdist.org/guides/serverselection.html#lua-server-policies
其他ui管理pdns
处理上面用容器部署的powerdns-admin容器服务
还有基于LNMP的powerdnsadmin服务,这里的唯一麻烦的点就是需要部署LNMP
可以借助 一键LNMP脚本 或者 根据另一篇博客来自己搭建LNMP服务
需要注意的是PHP版本一定要大于8.1
下载包 https://www.poweradmin.org/
解压到nginx的html文件中,然后访问 http://[IP][:port]/install 就可以安装
本文来自博客园,作者:厚礼蝎,转载请注明原文链接:https://www.cnblogs.com/guangdelw/p/17348982.html

浙公网安备 33010602011771号