Linux 主机只把自己的 SMTP 走隧道发出去之前,四件事必须对齐:专用表里的路由、选择流量的策略规则、对端会接受的源地址,以及能扛住非对称的回程路径。每一项都是独立配置,也有各自的失败方式。下面的顺序能让故障指向真正出错的那一环。这是按端口做的路由工作,不是申请一条 VPN 默认路由。

端口规则不是默认路由

匹配本地生成的 TCP、目的端口为 25 的规则,会把这部分流量送进你指定的表。规则本身不创建任何东西:它只做选择,表里必须有能承载数据包的路由。两者合起来只覆盖一个协议的出方向,因此面向其他主机的转发、入站邮件连接和 IPv6 都在安排之外。把它叫按端口的策略而不是 VPN 默认,才能守住这条边界。

两个 wg-quick 设置是前提条件,而不是策略的一部分。AllowedIPs = 0.0.0.0/0 让对端可以承载任意 IPv4 目的地址,Table = off 则阻止 wg-quick 为该前缀安装自己的默认路由。不要把这两条说明与自己施加路由策略的管理器混用,因为两者对主表归谁管会各执一词。

写路由、选择器和护栏

选一个别的用途都不占用的表号和一对优先级,然后按这个顺序应用路由、选择器和护栏。下面的数字只是示例,不是保留值:

ip -4 route add default dev wg0 src 10.77.0.2 table 51825
ip -4 rule add priority 10000 iif lo ipproto tcp dport 25 lookup 51825
ip -4 rule add priority 10001 iif lo ipproto tcp dport 25 unreachable

iif lo 把规则限制在本地产生的流量上,ipproto tcp dport 25 则标识连接方向;ip-rule 参考对两个选择器都有说明。它们在当前内核和 iproute2 发行版上都存在,而在较旧的系统上规则会被直接拒绝,这比一条加载成功却什么都不匹配的规则更容易判断。

下一个优先级上的 unreachable 规则就是护栏。没有它,表 51825 里缺失的路由会落到普通默认路由,隧道中断时邮件就从物理链路出去,而这正是策略要防的情况。

源地址必须一致

路由的 src 偏好只为尚未自行绑定源地址的连接补上源地址。它不是地址转换,也不会覆盖显式绑定,所以绑定到物理地址的守护进程仍会从该地址发送。如果确实如此,就改守护进程自己的设置,或者设计一套有意为之的转换策略,因为事后才做全局 masquerade 是另一种方案,后果也不同。

在网关上,客户端的对端必须授权它实际收到的源地址,即 10.77.0.2/32,而不是一个宽泛的目的前缀。把客户端的 0.0.0.0/0 复制到每个网关对端,会让人分不清哪个对端拥有哪些流量。网关还需要转发、允许该流的防火墙策略以及回程路径;当上游无法为私有隧道地址做路由时,还包括出方向转换。

检查回程,再看持久性

在相信任何东西之前先读查找结果,因为它们会显示每个方向拿到哪张表、哪个源地址。一个去往 25 端口的目的地,加上同一目的地走 443 端口,就足够了:

ip -4 route get 198.51.100.25 ipproto tcp dport 25
ip -4 route get 198.51.100.25 ipproto tcp dport 443

第一次查找应当给出 wg0 和预期的源地址,第二次应当保留普通上联。应用绑定自己的地址时,要把该地址通过 from 加进查找。到达 wg0 后又被本地丢弃的回程方向,指向 IPv4 反向路径过滤,因为只针对出端口的规则并不会让反向查找去选隧道。

在允许非对称路由的地方,可以通过 net.ipv4.conf.wg0.rp_filter=2 使用按接口限定的宽松模式,并且值得先确认 all 与接口取值的实际上限。不要把校验当成捷径全局关掉。然后把表、优先级和护栏交给配置的归属方,并在重连之后开新连接,确认选择仍然成立。请记住,本地 SMTP 监听器的应答携带的是源端口 25,而不是目的端口 25,这是另一个策略问题。

相关文章