Skip to content

07 - 权威 DNS 服务 ​

概述 ​

权威模式(authoritative)下,TDNS 作为区域数据的权威来源,应答自身管理区域的 DNS 查询。对非自身管理区域的查询返回 REFUSED。

适用场景:公网权威 DNS、CDN/GSLB 分发、内网域名解析、自有域名管理。


快速上手:三步跑通权威服务 ​

1. 配置区域 ​

toml
# /etc/tdns/tdns.toml
[server]
mode = "authoritative"
listen-addrs = ["0.0.0.0", "::"]
listen-port = 53

[[zones]]
name = "example.com"
file = "/etc/tdns/zones/example.com.zone"
type = "master"

[access-control]
allow-query = ["any"]        # 公网可查
allow-recursion = ["none"]   # 不提供递归

2. 编写 Zone 文件 ​

text
; /etc/tdns/zones/example.com.zone
$TTL 3600
@       IN  SOA ns1.example.com. admin.example.com. (
            2026081001  ; Serial    —— 每次改记录递增,辅 DNS 据此拉取
            3600        ; Refresh
            1800        ; Retry
            604800      ; Expire
            86400 )     ; Minimum TTL

; 名称服务器
        IN  NS      ns1.example.com.
        IN  NS      ns2.example.com.
ns1     IN  A       192.0.2.1
ns2     IN  A       192.0.2.2

; 主域名记录
@       IN  A       192.0.2.10
@       IN  AAAA    2001:db8::10
@       IN  MX  10  mail.example.com.

; 子域名
www     IN  CNAME   @
api     IN  A       192.0.2.11
mail    IN  A       192.0.2.12

; 通配符(未明确的一级子域名都走这里)
*       IN  A       192.0.2.10

; 文本与 CA 授权
@       IN  TXT     "v=spf1 include:_spf.example.com ~all"
@       IN  CAA     0 issue "letsencrypt.org"

3. 热重载 + 验证 ​

bash
# 验证配置
tdns --validate --config /etc/tdns/tdns.toml

# 启动或热重载
sudo systemctl reload tdns
# 或直接发信号
sudo kill -HUP $(cat /var/run/tdns/tdns.pid)

# 验证解析
dig @127.0.0.1 example.com SOA
dig @127.0.0.1 www.example.com
dig @127.0.0.1 example.com MX

SOA 的 Serial 每次改记录记得递增,方便辅 DNS 同步。推荐格式 YYYYMMDDNN(年月日+当日序号)。


多区域配置 ​

支持正向解析区域和反向解析区域(in-addr.arpa):

toml
[[zones]]
name = "example.com"
file = "/etc/tdns/zones/example.com.zone"
type = "master"

[[zones]]
name = "0.168.192.in-addr.arpa"
file = "/etc/tdns/zones/rev-192.168.0.zone"
type = "master"

Zone 文件格式详解 ​

支持的指令 ​

指令说明示例
$TTL默认 TTL(秒)$TTL 3600
$ORIGIN区域起始域(影响相对名称解析)$ORIGIN example.com.

支持的记录类型 ​

类型说明Zone 文件示例
AIPv4 地址www IN A 192.0.2.10
AAAAIPv6 地址www IN AAAA 2001:db8::10
NS名称服务器@ IN NS ns1.example.com.
CNAME别名www IN CNAME @
SOA起始授权@ IN SOA ns1... admin... ( ... )
PTR反向指针10 IN PTR host.example.com.
MX邮件交换@ IN MX 10 mail.example.com.
TXT文本@ IN TXT "v=spf1 ..."
SRV服务定位_sip._tcp IN SRV 10 60 5060 sip.example.com.
CAACA 授权@ IN CAA 0 issue "letsencrypt.org"
SVCB / HTTPS服务绑定(RFC 9460)_https IN HTTPS 1 . alpn="h2,h3"

记录类型与添加方式 ​

类型Zone 文件REST API说明
A / AAAA✅✅IPv4 / IPv6 地址
CNAME / NS / PTR✅✅别名 / 名称服务器 / 反向指针
TXT✅✅文本(SPF、验证等)
SVCB / HTTPS✅✅服务绑定(RFC 9460)
MX / SOA / SRV✅❌需通过 Zone 文件添加
CAA✅❌CA 授权,需通过 Zone 文件添加

通过 REST API 管理记录 ​

先在配置中开启 API:

toml
[api]
enabled = true
listen = "127.0.0.1:8080"
auth-token = "your-secret-token"   # 启用 API 时必填

启动后用 curl 管理记录:

bash
TOKEN="your-secret-token"
BASE="http://127.0.0.1:8080"

# 列出已有区域
curl -s -H "Authorization: Bearer $TOKEN" $BASE/api/v1/zones | jq

# 添加 A 记录(区域不存在会自动创建 example.com.)
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"www.example.com","type":"A","ttl":300,"data":"192.0.2.10"}' \
  $BASE/api/v1/zones/example.com/records | jq

# 添加 AAAA
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"www.example.com","type":"AAAA","ttl":300,"data":"2001:db8::10"}' \
  $BASE/api/v1/zones/example.com/records | jq

# 添加 TXT
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"example.com","type":"TXT","ttl":3600,"data":"v=spf1 -all"}' \
  $BASE/api/v1/zones/example.com/records | jq

# 列出区域所有记录
curl -s -H "Authorization: Bearer $TOKEN" \
  $BASE/api/v1/zones/example.com/records | jq

# 删除记录
curl -s -X DELETE -H "Authorization: Bearer $TOKEN" \
  $BASE/api/v1/zones/example.com/records/www.example.com/A | jq

# 验证
dig @127.0.0.1 www.example.com A

API 适合自动化和 GSLB 动态调度:健康检查通过就 POST 加节点,失败就 DELETE 删节点。完整 API 参考见 13-REST-API参考。


通过 TSIG 认证的 DDNS 动态更新 ​

1. 配置 TSIG 密钥 ​

toml
# /etc/tdns/tdns.toml
[[keys]]
name = "update-key."
algorithm = "hmac-sha256"
secret = "<base64-encoded-secret>"

[[zones]]
name = "example.com"
file = "/etc/tdns/zones/example.com.zone"
allow-update = ["update-key."]    # 允许此密钥执行 DDNS

生成密钥:

bash
# 使用 tsig-keygen(BIND 工具)
tsig-keygen -a HMAC-SHA256 update-key

# 或手动生成
echo -n "your-secret" | base64

2. 使用 nsupdate 发送动态更新 ​

bash
nsupdate -k Kupdate-key.+157+12345.key << EOF
server 127.0.0.1 53
zone example.com
update add www.example.com 300 A 192.0.2.100
show
send
EOF

3. 验证 ​

bash
dig @127.0.0.1 www.example.com A +short
# 应返回 192.0.2.100

详细 TSIG 配置见 12-安全与访问控制。


查询匹配规则 ​

精确匹配 ​

查询 www.example.com 的 A 记录,直接在区域中查找 (www, A) 条目。

通配符匹配 ​

通配符 *.example.com 匹配所有未明确定义的一级子域名。更具体的记录优先于通配符(掩蔽规则,RFC 4592)。

CNAME 链追踪 ​

查询目标存在 CNAME 记录时,自动追踪 CNAME 链获取最终 A/AAAA 记录。最大追踪深度由 recursion.max-depth 控制(默认 16),超过深度或检测到循环则返回错误。

胶水记录 ​

在权威响应的 Additional Section 中附加相关 NS 记录对应的 A/AAAA 记录。

委托处理 ​

区域中存在子域 NS 记录时,返回 Referral 响应(Authority Section 包含子域 NS 记录,Additional Section 包含胶水记录)。


修改后何时生效 ​

  • Zone 文件改完 → 发 SIGHUP 或 POST /api/v1/reload 热重载,原子替换区域
  • REST API 增删 → 立即生效,无需重载
  • 配置文件结构变(加新区域、改端口等) → 热重载
bash
# 热重载
sudo systemctl reload tdns
# 或
sudo kill -HUP $(cat /var/run/tdns/tdns.pid)
# 或
tdnsctl reload
# 或
curl -s -X POST -H "Authorization: Bearer $TOKEN" $BASE/api/v1/reload | jq

热重载会重新读取配置文件和 Zone 文件,原子替换区域目录。缓存和 ACL 等其他配置保持不变。