同一台机器上,一个应用走 VPN 出去,另一个却没有,而两位用户都坚称自己什么都没改。差别往往来自应用自己做出的绑定决定:套接字绑定到某个设备、在连接前选定源地址,或使用带独立路由表的命名空间。每一种都会改变生效的路径,而它们都不会出现在浏览器里那种通用 IP 检查中。

三种不同的绑定,三种不同的影响

绑定到设备与绑定到源地址是相关但后果不同的操作。设备绑定可以强制流量从某个接口出去,并绕过该套接字的常规路由查找。源地址绑定仍然要经过路由选择,但所选源地址可能匹配某条策略规则,从而把数据包送到别处。这种区分听起来很学术,直到某条规则按源地址选路,那时它就决定了一切。

网络命名空间是第三种情况。它有自己的接口和路由表,所以其中的应用完全不受宿主机默认值的影响。把三者当作同一回事,只会得出经不起第一次测试的自信解释。

确定应用实际设置了什么

在改动路由之前,先阅读应用的网络配置或其有文档记录的行为。如果它提供接口选择、源地址字段或命名空间选项,那么这项设置就是首先要检查的内容。如果没有,绑定可能是内部的,只能通过跟踪或它自己的诊断看到。

在 Linux 上,SO_BINDTODEVICE 之类的套接字选项有明确记录的范围和权限要求,非特权进程可能根本无法设置。这个限制是有用的线索:如果该选项无法应用,应用很可能不是差异的来源。

策略路由会读取源地址

配置了策略路由后,规则可以根据数据包的源地址来选择表。因此,绑定源地址的套接字可能遵循默认路径根本不会触及的规则,即使没有明确指定任何接口。

用与应用相同的地址族、源地址和命名空间复现这次查找。在宿主机命名空间的 shell 里做通用路由查找,回答的是另一个问题,而这种不一致正是正常路由看起来像坏掉的最常见原因。

分离隧道与辅助进程

按应用分离隧道又增加了一层。客户端可能按应用包或进程来匹配,而自行打开套接字的辅助程序是另一个主体。启动器及其后台服务可能在同一可见名称下产生不同的连接。

检查分离隧道规则是否覆盖了真正发起连接的进程。如果应用绑定到特定接口,而 VPN 客户端按包匹配,那么两个决定可能相互矛盾,却都不算错。

测试应用自己的路径

每次改动后都从应用发出新请求。浏览器显示出你想要的出口,并不等于另一个绑定到其他接口的程序也有同样的证据,而缓存的连接可能在设置改变很久之后仍在使用旧路径。先关闭旧会话,再判断新规则,否则测试测的是过去。

Linux 套接字参考手册记录了 SO_BINDTODEVICE 及其要求。先读应用自己的配置,在同一上下文中复现查找,然后才决定该改路由还是改绑定。

相关文章