通过 VPN 的 ping:为什么回声应答规则会漏掉回程路径
回声应答改变的是 ICMP 类型,而不是服务端口。在开放端口之前,应沿着转发、NAT 和有状态过滤器追踪内层报文。
从 VPN 另一端 ping 一台主机时,请求以一种 ICMP 类型发出,却以另一种类型返回,仅此一点就足以让任何按端口书写的规则失灵。回声交换里根本没有可抄进回程规则的目的服务端口,而期待对称的过滤器会在请求顺利通过的同时丢弃应答。修正要从按报文真实面貌去读它开始,然后判断路径上哪一道边界在做出决定。通常是两层在工作,第三层却悄悄把应答丢掉。下面各节按报文遇到它们的顺序把这些层分开。
报文换的是类型,不是端口
回声请求是 ICMP 类型 8、代码 0,携带一个标识符和一个序列号。应答是类型 0、代码 0,标识符与序列号相同,IP 两端互换。这些字段由 RFC 792 定义,而正是标识符让发送方能把应答与自己的请求对应起来。
缺席的东西同样重要:没有 TCP 或 UDP 头部,因此没有任何端口可供放行。为回声应答指定端口的规则,描述的是一个永远不会存在的报文。这是 VPN ping 工单里最常见的错误。规则看上去很具体,却什么也不适用于,故障也就留在原处。
三种上下文决定报文
如果 ping 指向远端 LAN 上的主机,请求必须由网关转发。如果指向属于网关自身的地址,它就在本地输入路径终止。如果由网关自己发起 ping,报文从它自己的输出路径起步,根本不经过转发判断。
这三种上下文拥有不同的规则链和不同的计数器,把它们当成一种,正是「防火墙放行了 ICMP」却仍然 ping 不通的原因。外层隧道是第四种上下文:放行 VPN 监听并不等于自动放行解封装后的内层请求,而内层的放行也无法说明外层隧道是否在线。
有状态与无状态过滤器对回包的处理不同
看到请求外出的有状态防火墙可以把应答关联到该流,无需第二条规则就予以放行。 无状态过滤器没有这样的记忆,因此回程方向需要自己的显式放行,并把源与目的对调。
在写下任何东西之前,先确认产品实际实现的是哪种模型。针对回声请求的规则未必覆盖回声应答,而跟踪 ICMP 查询的产品,对从另一个接口到达的应答仍可能套用不同策略。
给放行范围划定边界。允许来自任何地方的每一条回声应答,并不等于完成一次有状态关联,而类型编号并不认证发送者。
地址转换也会改动标识符
如果源地址转换是有意为之,远端的元组就与客户端发出的不一致。NAT 可以在转换地址的同时转换 ICMP 查询标识符,所以坚持两侧必须出现同一个编号,只会得出虚假的不一致。
应当改为与转换器报告的映射建立关联。改写标识符的转换器不会保留客户端记录的编号,因此要把映射当作身份,而不是编号。然后沿路径跟踪一个可识别的请求:确认它带着预期的源到达目的,确认目的确实发出了应答, 追踪该应答的回程路由,并确认客户端收到了它,而不是只看到网关计数器在上涨。
不要把 ICMP 差错并入回声策略
路径 MTU 发现所使用的「需要分片」报文并不是回声应答,它的载荷引用了触发它的那个报文。只放行回声的规则若悄悄丢弃这些差错,就会把尺寸问题变成挂起的连接,这恰恰与有用相反。
同样的谨慎也适用于地址族。ICMPv6 使用不同的报文类型,并承载 IPv4 所没有的必要功能,把这些编号照搬进 IPv6 规则就是错的。
回声交换可用之后,要单独测试真正的应用。一次成功的 ping 只证明某一种协议在某一种尺寸下到达某一目的可以往返,并不是假定 HTTPS、SMB 或任何其他流已被放行的许可证。