外观
11 - 加密传输指南
概述
TDNS 支持两种加密 DNS 传输协议,在传统 UDP/TCP DNS 之上提供加密和隐私保护:
| 协议 | RFC | 端口 | 传输层 | 特点 |
|---|---|---|---|---|
| DNS-over-TLS (DoT) | RFC 7858 | 853 | TLS over TCP | 长连接、低开销 |
| DNS-over-HTTPS (DoH) | RFC 8484 | 443 | TLS + HTTP/2 | 浏览器兼容、穿透防火墙 |
加密传输功能需要启用
tlsfeature flag(默认启用)。
重要:DoT 和 DoH 共用
[tls]段的证书和私钥(cert和key)。DoH 不需要单独配证书,复用[tls]的即可。监听 IP 统一使用server.listen-addrs,各协议通过自己的listen-port指定端口。
快速上手:五步开启加密传输
1. 获取 TLS 证书
bash
# 方式一:Let's Encrypt(免费,推荐)
certbot certonly --standalone -d dns.example.com
# 证书路径:
# /etc/letsencrypt/live/dns.example.com/fullchain.pem
# /etc/letsencrypt/live/dns.example.com/privkey.pem
# 方式二:自签名证书(仅测试用)
openssl req -x509 -newkey rsa:2048 -keyout key.pem \
-out cert.pem -days 365 -nodes \
-subj "/CN=dns.example.com" \
-addext "subjectAltName=DNS:dns.example.com"2. 放置证书文件
bash
sudo mkdir -p /etc/tdns
sudo cp fullchain.pem /etc/tdns/cert.pem
sudo cp privkey.pem /etc/tdns/key.pem
sudo chown tdns:tdns /etc/tdns/cert.pem /etc/tdns/key.pem
sudo chmod 640 /etc/tdns/cert.pem /etc/tdns/key.pem3. 配置
toml
# /etc/tdns/tdns.toml
[server]
listen-addrs = ["0.0.0.0", "::"] # DoT/DoH 复用此地址
listen-port = 53
mode = "recursive" # 任意模式均可
[recursion]
enabled = true
[access-control]
allow-query = ["any"]
allow-recursion = ["any"]
# DNS-over-TLS
[tls]
enabled = true
listen-port = 853
cert = "/etc/tdns/cert.pem" # 必填
key = "/etc/tdns/key.pem" # 必填
# DNS-over-HTTPS(复用 [tls] 的证书)
[doh]
enabled = true
listen-port = 443
path = "/dns-query"4. 开放防火墙
bash
# firewalld
sudo firewall-cmd --permanent --add-port=853/tcp # DoT
sudo firewall-cmd --permanent --add-port=443/tcp # DoH
sudo firewall-cmd --reload
# 或 iptables
sudo iptables -A INPUT -p tcp --dport 853 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT5. 验证配置 + 启动
bash
# 验证配置
tdns --validate --config /etc/tdns/tdns.toml
# 启动
sudo systemctl start tdns
# 测试 DoT
kdig @dns.example.com example.com +tls
# 测试 DoH
curl -s -H "Content-Type: application/dns-message" \
--data-binary @query.bin \
https://dns.example.com/dns-query
# 或用 kdig
kdig @dns.example.com example.com +httpsDNS-over-TLS (DoT)
工作原理
DoT 在 TCP DNS 的基础上增加 TLS 加密层。使用 2 字节长度前缀 + TLS 加密的 DNS 消息格式,支持单连接多查询(长连接复用)。
连接管理
| 参数 | 默认值 | 说明 |
|---|---|---|
| 最大并发连接 | 1024(TCP Semaphore) | 超限拒绝新连接 |
| 空闲超时 | 120 秒 | 空闲连接超过此时间自动断开 |
| 最大消息大小 | 65535 字节 | 与 TCP DNS 一致 |
| TCP_NODELAY | 启用 | 禁用 Nagle 算法,降低延迟 |
TLS 实现
- 密码库:rustls + ring(无 OpenSSL 依赖)
- 协议版本:TLS 1.2 / TLS 1.3(safe default)
- 证书格式:PEM(支持证书链)
- 私钥格式:PEM(RSA / ECDSA / Ed25519)
- ALPN:
dot(RFC 8310) - 客户端认证:不需要(
with_no_client_auth)
客户端配置
bash
# 使用 kdig (Knot DNS) 测试 DoT
kdig -d @dns.example.com example.com +tls
# dig 原生不支持 DoT,需第三方工具
# Android / iOS 设备
# 设置 → 网络 → 私人 DNS → dns.example.comDNS-over-HTTPS (DoH)
工作原理
DoH 将 DNS 消息封装在 HTTPS 请求中,使用 HTTP/2 over TLS 传输。支持 GET 和 POST 两种方法。
请求方法
| 方法 | URL | 请求体 | 内容类型 |
|---|---|---|---|
| POST | https://dns.example.com/dns-query | DNS wire-format 二进制 | application/dns-message |
| GET | https://dns.example.com/dns-query?dns=<base64url> | 无(参数编码) | application/dns-message |
GET 方法的 dns 参数使用 base64url 编码(无 padding),RFC 8484 §4.1 规定。
响应格式
- 状态码:200(成功)+
Content-Type: application/dns-message - 响应体:DNS wire-format 二进制数据
- 错误处理:
- 400 Bad Request:DNS 消息格式错误
- 413 Payload Too Large:请求体超过 65535+512 字节
- 500 Internal Server Error:响应编码失败
HTTP/2 强制
DoH 强制使用 HTTP/2(通过 TLS ALPN 协商 h2 协议)。不支持 HTTP/1.1 降级。
CORS 支持
DoH 端点启用 CorsLayer::permissive(),允许浏览器跨域请求。适合前端应用直接调用 DoH 端点。
客户端配置
bash
# 使用 curl 测试 DoH POST
curl -s -H "Content-Type: application/dns-message" \
--data-binary @query.bin \
https://dns.example.com/dns-query
# 使用 curl 测试 DoH GET(需 base64url 编码查询)
curl -s "https://dns.example.com/dns-query?dns=AAABAAABAAAAAAAAB2V4YW1wbGUDY29tAA==" \
-H "Accept: application/dns-message"
# 使用 kdig
kdig @dns.example.com example.com +https共享 TLS 配置
DoT 和 DoH 共用同一套证书和私钥:
toml
[tls]
enabled = true
listen-port = 853
cert = "/etc/tdns/cert.pem"
key = "/etc/tdns/key.pem"
[doh]
enabled = true
listen-port = 443
path = "/dns-query"
# DoH 自动复用 [tls] 的 cert 和 key,无需重复配置证书需包含正确的 Subject Alternative Name (SAN),覆盖 DoT 和 DoH 使用的域名。
证书自动续期
certbot + cron
bash
# 续期脚本
echo "0 3 * * * certbot renew --quiet --deploy-hook 'systemctl reload tdns'" | crontab -续期成功后通过 --deploy-hook 触发 TDNS 热重载(SIGHUP),无需停机。
证书路径权限
确保 TDNS 进程用户对证书文件有读权限:
bash
# 将 tdns 用户加入 ssl-cert 组(Debian/Ubuntu)
sudo usermod -aG ssl-cert tdns
sudo chmod 640 /etc/letsencrypt/live/*/privkey.pem
sudo chmod 644 /etc/letsencrypt/live/*/fullchain.pem证书管理日常操作
bash
# 查看证书有效期
openssl x509 -in /etc/tdns/cert.pem -noout -dates
# 检查证书 SAN
openssl x509 -in /etc/tdns/cert.pem -noout -text | grep -A1 "Subject Alternative Name"
# 证书过期告警(过期前 30 天提醒)
echo "0 9 * * * openssl x509 -in /etc/tdns/cert.pem -checkend 2592000 -noout || echo 'Certificate expiring soon!'" | crontab -
# 手动续期
sudo certbot renew --quiet
sudo systemctl reload tdns端口与防火墙
| 协议 | 端口 | 防火墙规则 |
|---|---|---|
| UDP DNS | 53/udp | iptables -A INPUT -p udp --dport 53 -j ACCEPT |
| TCP DNS | 53/tcp | iptables -A INPUT -p tcp --dport 53 -j ACCEPT |
| DoT | 853/tcp | iptables -A INPUT -p tcp --dport 853 -j ACCEPT |
| DoH | 443/tcp | iptables -A INPUT -p tcp --dport 443 -j ACCEPT |
DoT 和 DoH 可与标准 DNS 同时运行,客户端按需选择协议。
协议选择建议
| 场景 | 推荐协议 | 原因 |
|---|---|---|
| 移动设备隐私 DNS | DoT | 低开销、Android 原生支持 |
| 浏览器应用 | DoH | HTTP/2 兼容、穿透防火墙 |
| 企业内部加密 DNS | DoT | 长连接高效、运维简单 |
| 穿透限制 53 端口的网络 | DoH | 使用 443 端口 |
| 高性能加密 DNS | DoT | TLS 握手开销低于 HTTPS |
| 需要 CORS 的 Web 应用 | DoH | 内置 CORS 支持 |
生产环境建议同时启用 DoT(端口 853)和 DoH(端口 443),覆盖所有客户端类型。
指标监控
加密传输相关 Prometheus 指标:
bash
# 查看加密连接指标
curl -s http://localhost:9090/metrics | grep -E "connections|traffic"| 指标 | 标签 | 说明 |
|---|---|---|
tdns_active_connections | protocol="dot" / "doh" | 当前活跃连接数 |
tdns_connections_total | protocol="dot" / "doh" | 累计连接数 |
tdns_traffic_bytes_total | protocol, direction="rx"/"tx" | 收发字节数 |
tdns_queries_total | protocol="dot" / "doh" | 查询计数 |
详细监控配置见 15-监控与可观测性。