Loading

解决 rp_filter 反向路径过滤导致的多网卡(多WAN)服务器无法联网

背景

最近遇到一个机器接了一个以太网和一个USB网卡,在 curl 指定 USB 网卡访问互联网时发现无法收到正常的响应,使用tcpdump排查发现实际上有回包,但是应用层完全没有响应

22:43:48.730252 IP 10.121.60.168.37668 > 223.119.30.220.53: Flags [S]   ← SYN 发
22:43:48.929587 IP 223.119.30.220.53 > 10.121.60.168.37668: Flags [S.]  ← SYN-ACK 回
22:43:49.747409 IP 10.121.60.168.37668 > 223.119.30.220.53: Flags [S]   ← 在重传 SYN

凶手就是 rp_filter

rp_filter 是什么

Reverse Path Filter(反向路径过滤)是 Linux 内核的一个防 IP 欺骗机制,定义在 RFC 3704。它的逻辑是:当数据包从某个接口进入,内核需要判断——

"如果要回复这个包的源地址,应该从哪个接口发出去?"

然后与包实际进入的接口比对。三个取值:

模式 行为
0 关闭 不校验
1 strict 回程接口必须与入接口完全一致,否则丢弃
2 loose 源地址在路由表中可达即放行,不要求同接口

他解决了这个问题,典型如攻击者从公网发来源地址伪造成你内网网段的包:内核一查,"回这个地址应该走内网口,包却从公网口进来"——路径矛盾,丢弃。对单出口的服务器,这个检查零成本且有效,所以多数发行版默认开 strict。

多出口环境的问题

问题在于 strict 模式的前提是:一个目的地只有一条合理路径。多 WAN、策略路由、VPN 分流的机器上会导致严重的问题

回到开头的案例,主机的路由表是:

default via 192.168.3.1 dev eth0                    ← 主出口,metric 低
default via 10.121.60.169 dev wwan0 metric 5000     ← USB网卡,metric 高

SYN-ACK 从 wwan0 进来,内核做反向校验:"回 223.119.30.220 走哪个口?"查主路由表——eth0 的 metric 更低,答案是 eth0。但包是从 wwan0 进来的。不一致于是丢弃。

于是出现问题:tcpdump 能看到包(抓包点在校验之前),协议栈却永远收不到。这也是 rp_filter 问题最好的诊断特征——抓包有回包、但是连接无法建立

解决办法

修改内核参数为 loose 模式,仍能拦住纯伪造地址(源地址必须真实可达),但不再苛求进出同口:

sudo sysctl -w net.ipv4.conf.all.rp_filter=2
sudo sysctl -w net.ipv4.conf.wwan0.rp_filter=2

坑:内核取的是 max,不是覆盖

rp_filter 的实际生效值是:

生效值 = max(conf.all.rp_filter, conf.<接口>.rp_filter)

注意 max 比较的是数字大小,不是严格程度,而 1(strict)偏偏比 2(loose)小。这带来一个经典陷阱:

# 想彻底关闭某接口的校验
net.ipv4.conf.all.rp_filter = 1      # 全局仍是 strict
net.ipv4.conf.wwan0.rp_filter = 0   # 接口设为 0
# 生效值 = max(1, 0) = 1  ← 还是 strict,设置是不生效的

所以稳妥做法是全局和接口一起设,不依赖当前系统状态,结果确定可预测。

持久化

接口是会热插拔的,新出现的接口从 conf.default 继承初始值,所以持久化配置要写 all + default :

cat > /etc/sysctl.d/99-multiwan.conf << 'EOF'
# 多出口环境:严格反向路径校验会丢弃非对称路由的回包
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2
EOF
sudo sysctl --system
posted @ 2026-07-08 23:11  codesucks  阅读(37)  评论(0)    收藏  举报