侧边栏壁纸
博主头像
liveJQ博主等级

沒有乐趣,何来开始

  • 累计撰写 180 篇文章
  • 累计创建 68 个标签
  • 累计收到 2 条评论

使用 PowerDNS 作为权威 DNS 并且支持 ECS 功能

liveJQ
2022-09-15 / 0 评论 / 0 点赞 / 48 阅读 / 8,094 字

环境:Ubuntu 20.04

PowerDNS 提供的三个产品 Authoritative Server、Recursor、dnsdist 可以分别用做权威DNS、递归DNS和DNS负载均衡,这里使用第一个。

安装

先停止占用 53 端口的服务

systemctl disable systemd-resolved
systemctl stop systemd-resolved

然后编辑/etc/resolv.conf,按如下注释掉本地服务地址,添加一条公共 DNS,这样才能恢复本地域名解析服务。

#nameserver 127.0.0.53
nameserver 223.6.6.6

PDNS

sudo apt update
sudo apt install -y curl gnupg2 software-properties-common
curl -fsSL https://repo.powerdns.com/FD380FBB-pub.asc | sudo tee /etc/apt/trusted.gpg.d/powerdns.asc
echo "deb [arch=amd64] http://repo.powerdns.com/ubuntu focal-auth-44 main" | sudo tee /etc/apt/sources.list.d/powerdns.list

sudo apt update
sudo apt install -y pdns-server

查看版本,确保在 4.x 及以上

pdns_server --version

PowerDNS Authoritative Server 4.4.3 (C) 2001-2020 PowerDNS.COM BV

建议参考文章底部链接,使用官方推荐安装最新稳定版本。

配置 MySQL 作为后端

安装后端

apt install -y pdns-backend-mysql

添加配置,编辑/etc/powerdns/pdns.conf

launch=gmysql
gmysql-host=localhost
gmysql-port=3306
gmysql-user=pdns
gmysql-password=yourpassword
gmysql-dbname=pdns

这里使用 launch 参数配置 pdns 后端(Backend)数据库。虽然可以使用 += 语法增量配置,例如:launch+=bind 配置多一个 bind 作为后端,配置了多个后端会同时加载,先加载成功的默认作为主后端,其他作为备用,所有后端的配置需要相同才有意义。因此不管配置了多少个后端,使用上还是只有一个,建议只配置一个就可以了,主备功能还是建议直接使用第三个 dnsdist 产品。

搭配 MySQL

前面配置了 mysql 作为后端数据库,所以需要安装和创建对应的数据库和用户。

sudo apt install -y mariadb-server
sudo systemctl enable --now mariadb

登录 mysql

mysql -u root -p

创建 pdns 数据库并授权 pdns 用户

CREATE DATABASE pdns;
GRANT ALL ON pdns.* TO 'pdns'@'localhost' IDENTIFIED BY 'yourpassword';
FLUSH PRIVILEGES;
EXIT;

导入 PowerDNS 所需的数据库表

mysql -u pdns -p pdns < /usr/share/pdns-backend-mysql/schema/schema.mysql.sql

验证域名解析

查询结果正常返回“status: REFUSED”,因为不存在该域名记录。

dig a www.example.com @127.0.0.1

使用 pdnsutil 工具添加些记录,然后再尝试查询。

sudo -u pdns pdnsutil create-zone example.com ns1.example.com
sudo -u pdns pdnsutil add-record example.com '' MX '25 mail.example.com'
sudo -u pdns pdnsutil add-record example.com. www A 192.0.2.1

dig +short www.example.com @127.0.0.1

建议使用 pdnsutil 工具进行区域配置等操作,而不是直接操作数据库,它能对添加的配置进行检查和验证,确保不会产生问题。

现在可以进一步编辑区域,添加更多的配置。

pdnsutil edit-zone example.com

报错

pdns_server[2043790]: Fatal error: Trying to set unknown parameter 'ecs-add-for'
pdns_server[2046447]: Fatal error: Trying to set unknown parameter 'ecs-scope-mask'

尝试添加上面两个参数到配置文件时报错,因为这些参数是和 PowerDNS Recursor (作为递归DNS)扩展模块 ECS (EDNS Client Subnet) 一起使用的。ECS 是 DNS 扩展的一部分,用于在 DNS 查询中传递客户端的 IP 地址的子网信息,这通常用于更准确的地理定位和内容分发。

因此,使用 MySQL 作为 pdns 后端,常用于作为单纯的权威DNS来使用。

配置 GeoIP 作为后端

PowerDNS 可以使用 geoip 作为后端,允许基于 MaxMind GeoIP 数据库进行地理位置解析,并结合 ECS(EDNS Client Subnet),返回基于客户端 IP 位置的最优解析结果。

安装

apt install -y pdns-backend-geoip geoip-bin geoip-database

下载 GeoLite2 数据库

mkdir -p /var/lib/GeoIP
cd /var/lib/GeoIP

# 下载 GeoLite2 数据库(需要 MaxMind 账户和 License Key,到官网先注册再创建 License Key,也可以不创建直接下载数据库文件并上传解压)
wget "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key=Your_License_Key&suffix=tar.gz" -O GeoLite2-City.tar.gz

# 解压
tar -xzf GeoLite2-City.tar.gz --strip-components=1

安装 mmdb 工具验证 GeoLite2 数据库可用性

apt install -y mmdb-bin

mmdblookup --file /var/lib/GeoIP/GeoLite2-City.mmdb --ip 8.8.8.8

配置文件

配置 /etc/powerdns/pdns.conf

#################################
# local-address	Local IP addresses to which we bind
#
local-address=0.0.0.0:53

#################################
# include-dir	Include *.conf files from this directory
#
# include-dir=
include-dir=/etc/powerdns/pdns.d

#################################
# log-dns-details	If PDNS should log DNS non-erroneous details
#
log-dns-details=yes

#################################
# log-dns-queries	If PDNS should log all incoming DNS queries
#
log-dns-queries=yes

#################################
# log-timestamp	Print timestamps in log lines
#
log-timestamp=yes

#################################
# logging-facility	Log under a specific facility
#
#logging-facility=0

#################################
# loglevel	Amount of logging. Higher is more. Do not set below 3
#
loglevel=7

#################################
# loglevel-show	Include log level indicator in log output
# 
#loglevel-show=yes

#################################
# webserver	Start a webserver for monitoring (api=yes also enables the HTTP listener)
#
#webserver=yes

#################################
# webserver-address	IP Address of webserver/API to listen on
#
#webserver-address=0.0.0.0

#################################
# webserver-port	Port of webserver/API to listen on
#
#webserver-port=8081

#################################
# webserver-allow-from	Webserver/API access is only allowed from these subnets
#
#webserver-allow-from=0.0.0.0/0

#################################
# api	Enable/disable the REST API (including HTTP listener)
#
#api=yes

#################################
# api-key	Static pre-shared authentication key for access to the REST API
#
#api-key=mykey

新增配置 /etc/powerdns/pdns.d/pdns.backend.geoip.conf

launch=geoip

geoip-database-files=/var/lib/GeoIP/GeoLite2-City.mmdb
geoip-zones-file=/etc/powerdns/geoip.yaml
edns-subnet-processing=yes

新增配置 /etc/powerdns/geoip.yaml

domains:
- domain: example.com
  ttl: 30
  records:
# Default NS
    ns1.example.com:
      - a:
         content: 10.0.0.1
         ttl: 86400
    ns2.example.com:
      - a:
         content: 10.0.0.2
         ttl: 86400
    example.com:
      - soa: ns1.example.com hostmaster.example.com 2014090125 7200 3600 1209600 3600
      - ns: ns1.example.com
      - ns: ns2.example.com
      - mx: 5 mx.example.com
      - a: 192.0.2.1
    default.geo.example.com:
      - a: 192.0.2.2
      - txt: hello world
      - aaaa: 2001:DB8::12:34DE:3
    ip.info.example.com:
      - txt: "IP%af: %ip, Continent: %cn, Country: %co, ASn: %as, Region: %re, Organisation: %na, City: %ci"
    beijing-server.example.com: &beijing
      - a:
         content: 192.1.1.1
         weight: 90
      - a: 
         content: 192.2.2.2
         weight: 10
    shenzhen-server.example.com: &shenzhen
      - a: 192.3.3.3
    guangzhou-server.example.com: &guangzhou
      - a: 192.4.4.4
    shanghai-server.example.com: &shanghai
      - a: 192.5.5.5
    unknown.unknown.geo.example.com: *beijing
    unknown.gd.geo.example.com: *shenzhen
    guangzhou.gd.geo.example.com: *guangzhou
    shanghai.sh.geo.example.com: *shanghai
  services:
    www.example.com:
      default: [ '%ci.%re.geo.example.com', 'unknown.%re.geo.example.com', 'unknown.unknown.geo.example.com']
      101.227.102.0/24: 'beijing-server.example.com'
      116.31.96.0/24:
        - 'guangzhou-server.example.com'
        - 'shenzhen-server.example.com'
mapping_lookup_formats: ['%ci-%re', '%re']
custom_mapping:
  fr: eu-central
  us-ca: us-south

使用占位符另一个作用是可以避免使用到 Packet Cache 和 Query Cache 产生缓存记录。

重启服务

systemctl restart pdns

或者

pdns_control reload

验证 ECS 功能

# 查看客户端IP GeoIP2 信息
dig +subnet=202.120.224.58 +short ip.info.example.com @127.0.0.1 txt

# 自定义区域-广州IP
dig +subnet=116.31.96.1 www.example.com @127.0.0.1

# 自定义区域-上海IP
dig +subnet=101.227.102.1 www.example.com @127.0.0.1

# 动态匹配客户端-上海IP
dig +subnet=202.120.224.58 www.example.com @127.0.0.1

# 动态匹配客户端-匹配不到位置的IP
dig +subnet=103.116.76.58 www.example.com @127.0.0.1

pdns.conf 常用参数

缓存相关参数:

  • cache-ttl:单位秒,默认 20,Packet Cache。
  • query-cache-ttl:单位秒,默认 20,Query Cache。
  • negquery-cache-ttl:单位秒,默认 20,与上面相反,存储无结果的 Query Cache。
  • zone-cache-refresh-interval:单位秒,默认 300,存储所有已知的 zones。

日志相关参数:

  • log-dns-details:字面意思,使日志记录的 DNS 更详细,而不只是结果。
  • log-dns-queries:记录所有传入的 DNS 查询请求。
  • log-timestamp:字面意思,每条日志前面都会添加时间戳。
  • logging-facility:用于指定日志消息所属的类别或“设施”,通常配合 syslog 或 rsyslog(增强版)使用。例如:user 表示用户级程序;syslog 是系统日志;local0 至 local7 是用户自定义日志类别。
  • loglevel:对应 syslog 级别,数字越大日志输出越详细。(e.g. 0 = emergency, 1 = alert, 2 = critical, 3 = error, 4 = warning, 5 = notice, 6 = info, 7 = debug)
  • loglevel-show:需要 4.9.x 以上版本。启用后会格式化日志输出。

开启 REST API 服务

通常搭配某些管理程序,例如:PowerDNS-Admin。

配置文件 /etc/powerdns/pdns.conf

#################################
# webserver	Start a webserver for monitoring (api=yes also enables the HTTP listener)
#
webserver=yes

#################################
# webserver-address	IP Address of webserver/API to listen on
#
webserver-address=0.0.0.0

#################################
# webserver-port	Port of webserver/API to listen on
#
webserver-port=8081

#################################
# webserver-allow-from	Webserver/API access is only allowed from these subnets
#
webserver-allow-from=0.0.0.0/0

#################################
# api	Enable/disable the REST API (including HTTP listener)
#
api=yes

#################################
# api-key	Static pre-shared authentication key for access to the REST API
#
api-key=mykey

重启服务后,查看 8081 端口是否监听

root@pdns:~# netstat -tunlp | grep 8081
tcp        0      0 0.0.0.0:8081            0.0.0.0:*               LISTEN      2392446/pdns_server 

验证请求是否成功响应

curl -v -H 'X-API-Key: mykey' http://127.0.0.1:8081/api/v1/servers/localhost | jq .

查看日志排查错误

配置 local0 作为 pdns 日志类别,添加配置到 /etc/powerdns/pdns.conf

#################################
# logging-facility	Log under a specific facility
#
logging-facility=0

保存日志到自定义文件

cat << EOF >/etc/rsyslog.d/51-pdns.conf
local0.* /var/log/pdns.log
EOF

重启服务

systemctl restart rsyslog && systemctl restart pdns

查看 pdns 服务启动日志

journalctl -u pdns

实时跟踪 pdns_server 进程响应信息

strace -fp $(pgrep pdns_server)

相关资料

  1. Binary Packages
  2. Authoritative Server Settings
  3. PowerDNS Recursor Settings
  4. 131hub/pdns
  5. Backends
  6. Migrating to PowerDNS
0

评论区