← 全部文章

软路由连不上外网?一个内核参数 route_localnet 背的锅

📖 9 分钟 · 4247 字

症状

家里一台 iStoreOS 软路由,装 PassWall2(sing-box)做透明代理。某天发现一个问题:

软路由自己 curl https://www.google.com 超时,但手机、台式机走同一个代理却能正常翻墙。

# 路由器本机
curl -s -o /dev/null -w '%{http_code}' --connect-timeout 10 https://www.google.com
# => 000 (连接超时,等了 10 秒)

# 局域网设备(手机/台式机):完全正常

这看起来像"网络的锅",但仔细一想不对劲——局域网设备明明走的就是这台软路由的代理,它们能通,说明节点、规则、DNS 分流都没问题。那问题大概率出在"路由器自身流量"这条路上。

初判:先排除"网络断了"

按老规矩先确认基础设施,一次性把可排除的排掉:

ping -c 2 -w 3 223.5.5.5                    # WAN 通
curl -s -o /dev/null -w '%{http_code}' https://www.baidu.com   # 国内 200
nslookup www.google.com                      # DNS 解析正常,返回真实海外 IP
ps | grep -iE 'sing-box|chinadns' | grep -v grep   # 核心进程都在跑

结果全正常:WAN 通、国内站 200、DNS 能解析到真实 IP、sing-box / chinadns 进程都在。排除断网,问题 100% 出在"本机流量"这条链上。

关键一步:用 sing-box 自己的 Socks 测一下

这是整个排查里最重要的一步。PassWall2 同时开了 socks 端口(socks_enabled=11070),而 socks 流量走的是同一套分流规则。所以让本机通过 socks 访问目标站:

curl -s -o /dev/null -w '%{http_code}' \
  --socks5-hostname 127.0.0.1:1070 https://www.google.com
# => 200 !!! (直接访问是 000,走 socks 却 200)

结论瞬间锁定:sing-box 节点健康、分流规则正确、代理链畅通。目标站通过代理完全可达。那唯一的解释就是——路由器自己发起的外部流量没有进入 sing-box。既然流量没进代理,就被当作普通直连发去了 WAN,然后被墙。

深入 iptables:本机 TCP 和 UDP 走的是两条链

PassWall2 对本机流量的处理,TCP 和 UDP 是分开的,容易让人踩坑:

# mangle 表 OUTPUT 链 —— 本机 UDP 走这里(TPROXY)
iptables -t mangle -L OUTPUT -n -v
#   RETURN    all  lo
#   PSW2_OUTPUT  udp        <-- 只有 udp!
#   RETURN    all  mark match 0x50535732

# nat 表 OUTPUT 链 —— 本机 TCP 走这里
iptables -t nat -L OUTPUT -n -v
#   REDIRECT  tcp  lo dpt:53 -> 11400     (DNS)
#   PSW2_OUTPUT  tcp        <-- TCP 在这条链!

关键就是:本机 TCP 走 nat OUTPUT -> PSW2_OUTPUT,本机 UDP 走 mangle OUTPUT -> PSW2_OUTPUT,是两条不同链路。很多人只查 mangle 那条,就漏了 TCP。接着看 nat 的 PSW2_OUTPUT 链末尾兜底规则:

iptables -t nat -L PSW2_OUTPUT -n -v | grep 'redir ports 1041'
#   REDIRECT  tcp  multiport dports 22,25,53,...,80,443 redir ports 1041

这条兜底会把本机所有走代理端口的 TCP 连接重定向到 sing-box 的 1041redirect_tcp inbound)。理论上 curl google:443 应该命中它。

决定性证据:包确实重定向了,但 sing-box 没收到

为了抓现行,我盯着这条兜底规则的计数器,同时跑一次 curl:

# 记下计数器 -> curl google -> 再看计数器
iptables -t nat -L PSW2_OUTPUT -n -v | grep 'redir ports 1041'
#   1 packets -> 2 packets    <-- curl 的 SYN 真命中了 REDIRECT,被重定向了!

# 但 sing-box 日志却一片空白
tail /tmp/etc/passwall2/acl/default/global.log
#   (空)  <-- 没有任何连接记录!

这里就是破案点:包明明被 REDIRECT 到了 1041,计数器也涨了,但 sing-box 完全没收到这个连接。 流量在"被送往 1041"的半路上就消失了。

根因:route_localnet = 0

REDIRECT 本质是 DNAT,本机 OUTPUT 链把目的地址改写成了回环地址 127.0.0.1:1041。但 Linux 内核有个默认参数:

sysctl net.ipv4.conf.all.route_localnet
# => 0

route_localnet 控制能否把数据包路由到 127.0.0.0/8 回环网段。默认是 0,意思是:任何发往 127.0.0.0/8 的包视为非法目标,内核直接丢弃

于是链路是:

  1. 本机 curl google:443 → 路由决策(走 main 表 pppoe-wan 直连)
  2. nat OUTPUT 兜底规则命中 → REDIRECT 127.0.0.1:1041
  3. 内核发现目标是 127.0.0.1,而 route_localnet=0拒绝,包被丢,连 TCP 三次握手都建立不起来
  4. sing-box 收不到连接(日志空)→ 客户端干等 10 秒超时 → 000

那为什么手机、台式机没这个问题? 因为它们走的是 mangle/nat PREROUTING(进站流量),REDIRECT 的目标是局域网 IP(比如 192.168.100.1:1041),不是回环地址,所以根本不涉及 route_localnet。这就是"设备正常、唯独路由器自身连不上"的机械原理。

修复:打开 route_localnet 并持久化

一条命令临时生效:

echo 1 > /proc/sys/net/ipv4/conf/all/route_localnet
echo 1 > /proc/sys/net/ipv4/conf/lo/route_localnet

curl -s -o /dev/null -w '%{http_code}' --connect-timeout 10 https://www.google.com
# => 200 (0.3 秒,立刻通了!)

echo 1 > /proc 重启就没了,必须持久化。OpenWrt/iStoreOS 有两个配置位置,我都写上(防止被 /etc/sysctl.d/* 里的默认文件覆盖):

# 1) /etc/sysctl.conf 一份
echo 'net.ipv4.conf.all.route_localnet=1' >> /etc/sysctl.conf
echo 'net.ipv4.conf.lo.route_localnet=1'  >> /etc/sysctl.conf

# 2) 高序号 sysctl.d 文件一份 —— 数字越大越后加载,保证最后生效
printf 'net.ipv4.conf.all.route_localnet=1\nnet.ipv4.conf.lo.route_localnet=1\n' \
  > /etc/sysctl.d/99-route-localnet.conf

# 重新应用并验证
/etc/init.d/sysctl restart 2>/dev/null || sysctl -p
sysctl net.ipv4.conf.all.route_localnet   # => 1

这样重启路由器也能保持。

一个容易误判的坑:别把"节点问题"当成"修好了"

修好 route_localnet 之后,我又多测了几次,发现 google稳定 200 但是偶发 000,而 wikipediabingtwitterfacebook 全都是稳定 200,一次超时都没有。注意:

# 用 socks 连续测多个境外站,避开本机链路的干扰
for s in https://www.google.com https://www.wikipedia.org https://www.bing.com; do
  curl -s -o /dev/null -w "%{http_code}" --socks5-hostname 127.0.0.1:1070 $s; echo " <- $s"
done
# => google 偶发 000,wikipedia/bing 稳定 200

如果只是 google/youtube 这类 Google 系 IP 偶发超时,而其他境外站稳定,那说明本机代理链路已经完全通了,剩下的抖动是当前节点对 Google 系 IP 的访问不稳定(节点质量问题),跟 route_localnet 无关。这时候别再怀疑配置了,要么换个节点,要么等节点稳定。

复盘

  1. 设备正常 ≠ 路由没问题。凡是"某台机器走代理正常、路由器自身却不行"的,第一反应要想到本机出站走的是 OUTPUT 链,不是 PREROUTING,两者是独立的代理通道。
  2. 用 socks 测 sing-box 是最快的二分法。socks 走同一套分流规则,能 200 就立刻把"节点/规则"和"本机流量通道"切开,直接把排查范围缩小 50%。
  3. REDIRECT 到回环需要 route_localnet=1。这是透明代理(尤其 sing-box/PassWall)里最容易忽略的内核参数,记它一次,省下次半天时间。
  4. 计数器涨但日志空,是典型的"流量死在路上"——重定向规则匹配了,但承接方没收到,优先查内核路由参数,而不是 rule 本身。

这次的经验就是一句话:透明代理的本机流量,先查 route_localnet,再查 iptables。


2026-09-08 · 写于深夜

💬 评论 (0)

💬

还没有评论,来抢沙发吧