为什么 DNS 回复会在无状态 VPN 边缘防火墙上失败
发往 VPN 主机的 DNS 查询,其入站回复携带的是源端口 53,而不是目的端口 53。把规则限定在真正的解析器和路径上的边缘设备上。
隧道已经建立,客户端可以访问 VPN 主机,但主机却什么都解析不了。主机自己的出站查询能干净地离开接口,所以故障出在回程:在上游边缘,它过滤入站流量,却完全不记得主机刚刚发过什么。放行隧道端口根本描述不了这次交互。对 DNS 查询的回复是另一条独立流,如果边缘是无状态的,就没有任何东西授权它返回。
两次交互并不是同一次交互
把元组写出来,错误就一目了然。请求的目的端口会变成回复的源端口,这跟大多数人添加 53 端口入站规则时的想象正好相反:
query: 203.0.113.10:53018 -> 198.51.100.53:53
reply: 198.51.100.53:53 -> 203.0.113.10:53018要求目的端口为 53 的入站规则描述的是发往主机上 DNS 监听器的流量,那完全是另一种服务。这些地址只是文档示例,而源端口由客户端为每次查询自行选择,所以你无法把它抄进规则里还指望它一直有效。
无状态边缘与有状态主机防火墙
无状态边缘过滤器背后没有连接表,只能拿每条入站报文去比对规则列表。一条成功发出的出站查询不会为它的入站回复创造任何许可,因为设备上根本没有曾经发生过查询的记录。有状态主机防火墙正好相反:它的连接跟踪能识别被允许交互的返回流量,无需为回复单独写规则就能放行。典型路径上两种边界都存在,而且两者都必须放行目标报文。
之所以要比较,是因为两类设备的失败方式不同。有状态防火墙拒绝回复会记录丢弃;无状态边缘则是静默拒绝,所以主机只是超时。
要围绕协议而不是端口号来构建放行规则
把规则限定在实际解析器地址、目标主机以及产品支持的接收端口策略上。也要考虑 DNS 的 TCP 路径,因为大响应或截断回退会把交互转到 TCP,只针对 UDP 的规则覆盖不到。如果边缘支持对已定义流做有状态检查,优先用它而不是手写回复规则,因为有状态路径会自动跟随客户端选定的端口。
然后确认路径上究竟是哪个产品在过滤流量。文档中写明的 IPv4 边缘范围并不等于 IPv6 策略,而提供商内部流量可能根本不会经过同一个过滤器。
为什么放行任意源端口 53 不是解决办法
接受任何自称源端口为 53 的流量的规则,等于接受发送方在头部字段里随便写的内容。端口号既不能证明发送方身份,也不能证明载荷是有效回复,所以这条规则只会扩大主机的暴露面,并不会让解析更可靠。应当保留来源限制,保留客户端自身的回复校验(包括源端口随机化),而不是为了简化访问列表把它们关掉。
如果解析器是你自己控制的服务,限制到它的地址就够了。如果是公共解析器,就限制到你批准的地址,并在规则注释里写明。
在正确的边界、正确的方向上验证
在同一次查询上分别于主机和边缘抓包,比较元组而不是报文计数。两侧都看得到、但主机侧看不到回复的查询,指向入站过滤器;只在主机侧看得到的查询,指向路由或解析器本身。如果只放行了 UDP,就用 TCP 查询再试一次,因为那正是第一次测试看不到的缺口。
修复这一点只是补全主机真正需要的 DNS 交互。它不会把主机变成公共解析器,不会授权被转发的 VPN 流,也不能证明某个不相干的隧道问题就是 DNS 造成的。