隧道建立起来,客户端能 ping 通网关,但经过代理路径的每个网页请求都失败。redsocks 进程在运行,端口也在监听,所以从网关本身看服务是健康的。真正失败的是投递环节:从隧道重定向出来的数据包没有落到你启动的那个套接字上。绑定地址和重定向目标必须一致,而通常只检查其中一项。

重定向后的数据包究竟落在哪里

网关上的透明代理在 PREROUTING 的 nat 表里使用 REDIRECT,把入站连接的目标改写到本地端口。改写后的目标是数据包进入的那个接口所看到的本地地址,而不是在别处启动的进程的回环地址。只绑定 127.0.0.1 的监听器只会接受本来就是主机本地地址的连接,而这恰恰是隧道流量失败时仍然正常的那一种情况。客户端自己的回环是第三个地址,永远不是网关规则的改写目标。

因此在改动上游凭据之前,先确认两件事:规则改写到哪个本地地址,代理套接字绑定在哪个地址上。

把监听器和重定向规则放在一起看

在同一次输出里打印套接字表和 nat 规则,因为指向无人拥有的端口的规则,与指向错误地址的规则看起来一模一样。sudo ss -ltnp | grep redsocks 显示绑定地址和占用该端口的进程。sudo iptables -t nat -S PREROUTING 显示 REDIRECT 目标,sudo iptables -t nat -L PREROUTING -v -n 显示是否有流量匹配到它。

跳到名为 REDSOCKS 的自定义链本身什么也不做,除非该链确实存在,并带有预期的排除项和 REDIRECT 动作。要用 sudo iptables -t nat -S REDSOCKS 读出它跳转到的那条链,而不是假定名字就能完成任务。

然后比较这两个值。如果规则重定向到端口 12345 上的网关地址,而监听器报告的是 127.0.0.1:12345,那么这种不一致无需再做更多诊断就能解释故障。

只绑定必要的地址,再限制谁能够访问它

上游示例配置默认把监听器放在回环上是有充分理由的:透明代理会代表任何能访问它的人接受连接。把绑定改成 0.0.0.0 虽然修好了投递,但同时会在所有接口上开放端口,这是安全性变更,而不是中立的修复。更稳妥的做法是绑定到重定向所指向的那个具体本地地址,并在不可信接口上保持端口关闭。如果不得不放宽绑定,就加一条主机防火墙规则,只放行隧道来源网段和网关自身的本地流量。

对于被重定向的 VPN 流量,从来不需要在公网接口上开放端口,因为改写之后连接会在本地终结。不要为了让本地重定向生效而把代理暴露到互联网。

用客户端发起的新连接来验证

要从真实的 VPN 客户端发起全新的 TCP 连接来测试,而不是在网关的 shell 里测试。客户端上的 curl -sS -o /dev/null -w '%{http_code}\n' http://example.com 会端到端地走一遍被重定向的路径。

然后确认:从不可信网络直接连接监听器仍然被拒绝,并且代理自身的上游连接没有被同一条规则再次捕获。递归捕获表现为代理连接到自己、请求永远无法完成。把代理的目标地址加入排除集合,或者给它的出站数据包打上标记,让规则链跳过它们。

最后,记住这条路径没有覆盖什么。普通的 redsocks TCP 重定向不会把 UDP、QUIC 或 DNS 变成 SOCKS 流量,私有目标通常还需要显式排除。一次成功的本地测试,只能证明那条从来就不是问题的回环路径。

相关文章