代理有应答,请求也完成了,但目的端记录的仍是局域网地址。代理日志里看不出任何异常,而你改动的那一行正是文档让你改的那一行。在同时拥有局域网地址和隧道地址的主机上,三条指令决定哪个地址出现在哪一侧,其中只有一条与出站方向有关。顺序读错,就会无谓地翻进路由表。

症状:目的端看到的是局域网地址

客户端通过局域网地址连接代理,代理再从自己这边建立到目的端的连接。第二条连接按内核规则挑选源地址,默认就是路由查询选中的那个。于是尽管每个字节都经过了代理,目的端记录的仍是主机的主地址。从转发角度看并没有坏掉,这也正是代理日志无话可说的原因。

这个故障的反面更容易察觉:把出站源地址钉在隧道地址上,局域网客户端就完全够不到监听端。那一版会自己报警,而第一版藏在一条成功的请求背后。两者都源于把一条指令当成能同时回答两个问题。

三条指令,三个不同的地址

Listen 指定接受代理客户端的本地地址。Bind 为代理向外发起的连接提供源地址,BindSame 则要求复用刚接受的那条连接的本地地址。这是三个彼此独立的问题,而一行配置只回答其中一个。把它们混为一谈,正是改动看起来毫无效果的最常见原因。

What you observeCheck first
A client cannot connect at allListen: the local address the listener binds
The request works but the far side logs the LAN addressBind: the outgoing source is not being applied
A configured Bind appears to have no effectBindSame yes: the accepted local address overrides the Bind list
The lookup names the LAN interfaceThe route, not the proxy: the source cannot reach that destination

请阅读随所装版本一起提供的带注释的配置,因为默认值和可接受的语法会随版本变化。项目的示例配置把每条指令并排写在一起。拿那份文件与磁盘上的文件对照,而不是与一份为别的发行版写的指南对照。

分别设定监听地址与出站源地址

取一台局域网地址为 192.168.50.10、隧道地址为 10.90.0.3 的主机。如果局域网客户端要能访问代理,而它们的请求要从隧道出去,这就是两个彼此独立的决定,两件都得写下来。下面这一段只表达这件事,不多不少。

Listen 192.168.50.10
Bind 10.90.0.3
BindSame no

这不是完整配置,所以保留已批准的端口、认证、客户端访问控制和目的端限制。两个地址都必须在 Tinyproxy 的网络命名空间内属于本机,因为进程无法拥有的 Bind 值会在连接时失败,而不是在启动时失败。BindSame yes 描述的是另一种策略:被接受连接的本地地址成为出站源地址。在当前的发行版里,这个分支优先于 Bind 列表,配置好的源地址正是这样无声消失的。

核对源地址所隐含的路由

选定源地址并不会创造路径,所以要问内核:用这个源地址和这个目的端它会怎么做。查询结果指向隧道接口,才算最起码的证据;指向局域网接口,就说明这个源地址按字面是走不通的。查询带有上下文:它评估的是该命名空间内生效的策略规则和路由表。它不是一条连接,也不说明下游的 NAT 会对服务呈现成什么样。

ip -4 route get 203.0.113.25 from 10.90.0.3

示例中使用文档用途的地址,并替换成你有权测试的服务。代理运行在容器里时,要在代理的命名空间内执行查询,因为主机的规则并不是进程看到的规则。若预期的隧道路由不存在,应让网络负责人去修,而不是在代理主机上追加针对目的端的规则。不要为了查询成功去清空主机路由或关闭服务端下推的路由,即使较旧的指南那样做过,因为这类改动会为了修一条代理路径而挪动整台主机已获批准的 VPN 行为。

在目的端确认源地址

在请求到达的地方读源地址,而不是在它离开的地方。目的端的应用日志,或它前面的边缘设备,记录的是实际看到的地址;代理只能告诉你它打算做什么。改动之后,通过预期的监听地址发一条新请求,因为缓存里的连接对新绑定什么都证明不了。然后把记录的地址与你配置的地址作对比。

ss -ltnp | grep tinyproxy
curl -x http://192.168.50.10:8888 https://example.com -o /dev/null -sS

curl 只是流量生成器;值得核对的地址是远端记录下来的那个,而不是 curl 碰巧连上的对端。两者不一致时,要判断差异来自源地址选择,还是来自更后面的转换,因为这两类问题修的地方不同。把地址变更和代理重启放在一起规划,因为绑定隧道已不再持有的地址,会在重连之后悄悄失败。DNS 与 IPv6 的行为也要单独定义,因为上面那段 IPv4 对两者都说明不了什么。

相关文章