外观
08 - 递归解析服务
概述
递归模式(recursive)下,TDNS 从 DNS 根服务器开始逐级迭代解析,不依赖上游递归服务器。客户端发送递归查询(RD=1)后,TDNS 承担完整的解析链路,直到获得最终答案返回给客户端。
适用场景:企业出口 DNS、家庭网络网关、需要完整解析链路控制的环境。
快速上手:四步跑通递归服务
1. 配置
toml
# /etc/tdns/tdns.toml
[server]
mode = "recursive"
[recursion]
enabled = true
max-concurrent-queries = 10000
query-timeout = "5s"
max-depth = 16
[cache]
enabled = true
max-size = "1GB"
min-ttl = 60
max-ttl = 86400
negative-ttl = 300
stale-ttl = 3600
max-negative-entries = 50000
[access-control]
allow-query = ["trusted"]
allow-recursion = ["trusted"] # 必填!
[acl.trusted]
addresses = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]2. 确保 root.hints 就绪
bash
# 检查文件
ls -la /etc/tdns/root.hints
# 如果不存在,从 IANA 下载
curl -o /etc/tdns/root.hints https://www.internic.net/domain/named.root
# 或用 dig 获取
dig @a.root-servers.net . NS > /etc/tdns/root.hints3. 验证配置 + 启动
bash
# 验证配置
tdns --validate --config /etc/tdns/tdns.toml
# 启动
sudo systemctl start tdns4. 测试递归解析
bash
# 测试常见域名
dig @127.0.0.1 www.google.com
dig @127.0.0.1 www.baidu.com
# 测试根服务器连通性
dig @198.41.0.4 . NS +time=5
# 查看缓存命中率
tdnsctl stats工作原理
客户端查询 www.example.com A (RD=1)
│
▼
1. 检查本地缓存 → 未命中
│
▼
2. 查询根服务器 (.) → 获取 .com TLD 的 NS 记录
│
▼
3. 查询 .com TLD 权威 → 获取 example.com 的 NS 记录
│
▼
4. 查询 example.com 权威 → 获取 www.example.com 的 A 记录
│
▼
5. 缓存结果(按 TTL),返回给客户端每级查询独立超时控制,支持重试。根服务器从 root.hints 文件获取,随机选择以分散负载。
root.hints 文件
文件查找顺序
--root-hints <path>CLI 参数(最高优先级)<working-directory>/root.hints(默认/var/lib/tdns/root.hints)etc/root.hints(相对于当前工作目录)
bash
# 通过 CLI 参数指定
tdns --config /etc/tdns/tdns.toml --root-hints /etc/tdns/root.hints格式说明
root.hints 使用 BIND 缓存文件格式(4 列,不含 IN 类字段):
. 3600000 NS a.root-servers.net.
a.root-servers.net. 3600000 A 198.41.0.4
a.root-servers.net. 3600000 AAAA 2001:503:ba3e::2:30定期更新
根提示文件会随时间过期(根服务器 IP 偶尔变更),建议每 3-6 个月更新一次:
bash
# 从 IANA 下载最新版本
curl -o /etc/tdns/root.hints https://www.internic.net/domain/named.root
# 或用 dig
dig @a.root-servers.net . NS > /etc/tdns/root.hints
# 热重载生效
sudo systemctl reload tdns缓存系统
正向缓存
成功解析的响应按 TTL 缓存。TTL 受 min-ttl 和 max-ttl 约束:
toml
[cache]
min-ttl = 60 # 响应 TTL < 60 → 使用 60(防短 TTL 放大攻击)
max-ttl = 86400 # 响应 TTL > 86400 → 使用 86400(保证数据新鲜度)负缓存
NXDOMAIN 和 NODATA 响应也缓存,TTL 由 negative-ttl 控制(默认 300 秒)。负缓存响应携带 SOA 权威记录(RFC 2308)。
toml
[cache]
negative-ttl = 300 # 负缓存 5 分钟
max-negative-entries = 50000 # 负缓存上限,防 OOMServing Stale(RFC 8767)
上游服务器全部不可用时,返回过期缓存数据(标记为 stale),而非 SERVFAIL。
toml
[cache]
stale-ttl = 3600 # 过期缓存最长保留 1 小时缓存预热
启用后,热门记录在 TTL 到期前自动刷新:
toml
[cache]
prefetch-enabled = true
prefetch-threshold = 0.8 # TTL 剩余 < 20% 时触发预热安全特性
| 防护项 | 机制 | 如何调整 |
|---|---|---|
| 开放递归防护 | 递归启用时强制要求 allow-recursion,否则拒绝启动 | 配 [access-control] allow-recursion |
| 缓存投毒防护 | 验证上游响应 TXID、源 IP 和源端口 | 自动生效,无需配置 |
| CNAME 循环检测 | HashSet 跟踪已访问名称 | recursion.max-depth 调整深度 |
| 负缓存容量限制 | 最大 50,000 条目 | cache.max-negative-entries |
| 正缓存容量保护 | 插入时二次容量检查 | cache.max-size |
| 查询深度限制 | CNAME 链最大追踪深度 16 | recursion.max-depth |
| 并发查询限制 | Semaphore 限制最大并发递归查询数 | recursion.max-concurrent-queries |
网络环境要求
递归模式需要服务器能直接访问公网 DNS 根服务器(端口 53/UDP+TCP)。
| 要求 | 说明 | 验证方法 |
|---|---|---|
| 公网出站访问 | 需访问根服务器(如 198.41.0.4 等 13 组 IP) | dig @198.41.0.4 . NS |
| UDP 出站 53 | 向根/TLD/权威发送 UDP 查询 | nc -u -w3 198.41.0.4 53 |
| TCP 出站 53 | 响应过大时降级 TCP | nc -z 198.41.0.4 53 |
| 无 NAT 限制 | UDP 不被 NAT 截断 | 实际递归测试 |
如果网络环境无法直连根服务器(如内网隔离环境),请使用转发模式代替递归模式。
性能调优
toml
# 高 QPS 递归场景推荐配置
[server]
workers = 0 # 自动检测 CPU 核心数
[cache]
max-size = "2GB" # 或 "4GB",高 QPS 场景加大缓存
prefetch-enabled = true # 启用预热减少延迟
prefetch-threshold = 0.9 # TTL 剩余 < 10% 触发
[recursion]
max-concurrent-queries = 20000 # 高并发递归
query-timeout = "5s"| 参数 | 建议值 | 说明 |
|---|---|---|
cache.max-size | "2GB" ~ "4GB" | 高 QPS 场景加大缓存 |
cache.prefetch-enabled | true | 启用预热减少延迟 |
recursion.max-concurrent-queries | 20000 | 高并发递归 |
server.workers | CPU 核心数 | 0 = 自动检测 |
内核参数调优
高 QPS 场景建议调整内核参数:
bash
# /etc/sysctl.d/tdns.conf
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.rmem_default = 4194304
net.core.wmem_default = 4194304
net.core.somaxconn = 65535
# 应用
sudo sysctl --system