这个问题听起来像一次查询,实际却是三个决定。绑定请求走哪条路由,内核对这条路由选择哪个源地址,以及途中是否有东西改写这个源地址。改变其中任何一个,STUN 服务器报告的地址都会随之改变。所以「VPN 在路由器上」这句话本身几乎说明不了什么。

决定取决于三个事实

第一是路由:策略规则和路由表决定请求从隧道还是从普通 WAN 出去,而被排除的目的地即使隧道已建立也会走第二条路径。第二是源地址:内核为选定的路由选择源地址,这一选择取决于该路由的首选源地址以及任何匹配的规则。第三是转换:途中的 NAT 会替换被选定的源地址。反射出的地址是三者的乘积,而不是隧道的属性。

改变三者之一,答案就会改变,而每个组件在自己的日志里看起来仍然健康。这就是这类诊断卡住的常见原因。

开始之前,先为你要测试的流写下三个事实。接口、路由和转换规则足以预测结果,而正是这种预测让意外变得有信息量。如果三者中有一个填不出来,那个空白就是真正的发现。

沿路径跟踪一个绑定请求

STUN 绑定请求要求服务器报告它观测到的源传输地址。回复描述的是请求走过的路径,而不是客户端机器上的接口清单。两条路径上的两个请求会诚实地报告两个不同的地址。

Path takenSource the reflector seesWhat it means
Tunnel to a public exit that translatesThe exit's public addressThe reflector learns nothing about the LAN
Tunnel to a private reflector, translated to the tunnel address, no later translationThat tunnel addressAn internal identifier is disclosed to that reflector
Excluded flow over the ordinary WANThe WAN addressThe tunnel was not used at all

把那张表读成一组条件,而不是供应商菜单。中间一行要求私有反射器在隧道自身的路由和对等策略下可达;这是可以核实的配置事实,而不是账户层级所暗示的东西。最后一行通常才是策略上重要的,因为那部分流量本该留在隧道里。两者之间是常见情形:出口做转换,反射器只看到出口。

主机候选和服务器反射候选来自不同机制,所以候选列表并不能说明媒体实际走了哪条路径。想知道会话去了哪里,要读被选中的配对,而不是收集日志。

路由器的隧道地址不是什么

分配给路由器的隧道地址属于路由器上的一个接口。LAN 主机上的浏览器有自己的接口地址,也无法直接看到路由器的隧道接口。把两者当成可以互换,就会对网页能了解到什么给出自信而错误的答案。

转发把两者连起来。请求作为被路由的流量穿过路由器,它的源地址是路由和转换产生的结果。

如果隧道路径保留 LAN 源地址,私有反射器就能得知那个 LAN 地址,这是真正的泄露,且不同于隧道地址。如果路径转换为隧道地址,反射器得知的就是隧道地址。两种结果都与同一主机上的同一浏览器相容,所以观测必须绑定到特定的流。在责怪应用之前,先问内核会使用哪个源地址。

泄露与绕过:两个发现,两种修复

被反射的隧道地址在你允许的路径上泄露了内部标识符。直接走 WAN 的请求绕过了你本想强制的路径。前者是信息问题,后者是执行问题,修复的位置不同。把两者合成一个词,得到的修复哪个都不解决。

WebRTC 让这一点更明显,却没有让它变错,因为收集候选并不等于选择候选。

ip route get 203.0.113.7 from 192.0.2.25
ip rule show

对你允许的每个反射器地址运行路由查询,使用你预期该流携带的源地址,然后对排除的网段再运行一次,看看回退选择什么。把两个答案与你写下的策略对比。当它们以你并未预期的方向不一致时,你就找到了修复点,而不必去解释浏览器的候选列表。

相关文章