WireGuard DNS DNAT:让回程路径保持可用
DNAT 改写的是目的地址,不是源地址。在添加规则之前先决定上游解析器如何应答,并让每条匹配保持收窄。
把 WireGuard 客户端的 DNS 查询指向另一个解析器,看起来只是一条规则,实际却像三个决定。必须改写目的地址,必须转发数据包,应答还必须沿着网关创建的转换状态找到回程。跳过第三件事,查询会干净地离开,而客户端永远等下去。
以 10.77.0.0/24 中的已授权客户端为例:它们经 wg0 到达,查询对外通告的地址 10.77.0.1,并需要 203.0.113.53 上的解析器。上游地址只是文档占位符,并不是可用服务。
重定向查询只改变它的目的地址
PREROUTING 中的目的地址 NAT 规则会在路由决策之前改写地址,因此数据包随后被路由到新目的地址而不是旧地址。客户端的源地址不会被该操作触动。这就是为什么看起来完整的规则仍可能只带来沉默:请求现在发往一个从未听说过客户端私有网段的解析器。网关只转换了一个字段,却把第二个问题一并继承下来。
两种 DNS 传输都需要匹配的规则,因为应答被截断时客户端会回退到 TCP。
下面的规则只选择一个入站接口、一个客户端网段和一个原始目的地址。网关上其他任何东西都不受影响,而网关自身发出的查询完全不会匹配。
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -i wg0 -s 10.77.0.0/24 -d 10.77.0.1 -p udp --dport 53 -j DNAT --to-destination 203.0.113.53:53
iptables -t nat -A PREROUTING -i wg0 -s 10.77.0.0/24 -d 10.77.0.1 -p tcp --dport 53 -j DNAT --to-destination 203.0.113.53:53
回程路径是另一个决定
有两种安排可以让应答返回,早点选定一种就能省下一次排查。要么上游解析器有一条经此网关返回 10.77.0.0/24 的路由,要么网关在出口处转换源地址,使应答到达上游已经知道的地址。两者都能工作;只有一种符合你对上游的控制程度。
路由值得先试,因为它让客户端地址对解析器保持可见,并避免第二层转换。当上游不在你的控制之内时,在特定出口接口上做源地址转换是务实的选择。
把这项转换限定得和重定向一样紧,否则规则就会变成对任何恰好匹配它的流量都生效的通用 NAT:
iptables -t nat -A POSTROUTING -s 10.77.0.0/24 -d 203.0.113.53 -o eth0 -p udp --dport 53 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 10.77.0.0/24 -d 203.0.113.53 -o eth0 -p tcp --dport 53 -j MASQUERADE
连接跟踪让映射保持成对,因此应答在返回时会改回客户端最初的五元组。没有出口规则时,解析器会把应答发往它无法到达的私有地址,客户端看到的不是错误而是超时。
规则要写得比任务看起来更窄
转发权限属于同一范围。放行客户端到解析器的流量以及 conntrack 已经识别的回程流量,而不是接受机器上的每一条 DNAT 连接。全盘放行还会授权与 DNS 毫无关系的端口转发。
网关自身的解析器是另一条代码路径。本地发出的查询走 OUTPUT,所以从网关 shell 测试既不会走到 PREROUTING 规则,也不会走到转发策略。这就是本地测试能通过、而每个客户端都失败的原因,反过来也同样常见。
这里不涉及 443 端口上的 DNS over HTTPS,也不涉及 853 端口上的 DNS over TLS,更不涉及 IPv6。配置了 IPv6 解析器的客户端会欣然忽略整套安排。
新查询能证明什么
连接跟踪会记住早先的映射,因此在规则变更之前发出的查询可能按旧状态得到应答,让新规则看起来是坏的。请从新的源端口开始;在客户端缓存应答的地方,还要用新的域名。
dig @10.77.0.1 example.com A +short
conntrack -L -p udp --dport 53 | head
第一条命令显示客户端路径到底能不能解析,第二条显示网关实际安装的转换,包括五元组的两个方向。指向正确解析器、但应答计数器卡在零的映射,是回程路径问题而不是过滤问题。
在重定向任何东西之前,先确认解析器认识你期望的域名。能应答公网域名、却不能应答你的私有区域的替代方案 会把本来可用的查询变成看似隧道故障的 NXDOMAIN。在客户端路径参与之前,先从网关直接测试解析器。而 iptables 扩展参考 记录了这些规则所依赖的 DNAT 与 masquerade 语义。