一台笔记本通过以太网接在办公室的 /24 网段上,同时又加入了一个位于同一 /24 网段的 OpenVPN 服务器。同事去 ping 隧道地址;请求明明到了,却什么都没有回来。隧道日志干干净净,上网也照常,所以隧道是错的怀疑对象。接收端机器上的 IPv4 源地址校验在任何人读到这个包之前就把它丢掉了。

丢弃发生在任何代码读到包之前

源地址校验会对每个入站包问一个问题:如果这台主机要回那个源,这个回包会不会从刚才进来的那块网卡出去?当答案是否定时,内核在到达那一刻就把包丢掉。既没有套接字、也没有转发路径会看到它,所以隧道上的抓包仍然会记录下一个应用永远收不到的请求。

这里的客户端在隧道上持有 10.66.0.9,而 OpenVPN 服务器在办公室前缀内以 192.168.80.10 应答。位于 192.168.80.25 的同事去 ping 隧道地址,于是请求穿过局域网,服务器把它送进隧道,它带着办公室源地址抵达客户端的隧道网卡。在那台机器的路由表里,办公室前缀属于以太网设备,而不属于隧道。校验拿到达网卡和路由比对,发现不一致就把包丢掉,于是同事看到完全丢包,而两端都报告隧道正常。

镜像方向也是同样的形状:当客户端主动发往办公室时,回包可能在办公室一侧因为完全相同的原因被丢掉。只在一个方向上验证过的修复,往往会变成第二张工单。

动任何 sysctl 之前,先证明当前生效的模式

读实际值,而不是相信发行版的默认值,因为每个网卡的设置只是决定的一半。生效的模式取网卡值与 all 值中较高的那个,所以在 all 为一时,隧道网卡上的零毫无意义。严格模式的判断是路由判断,所以要跑内核实际执行的那次查询,并把结果与包真正到达的网卡对照。

tcpdump -ni tun0 icmp and host 192.168.80.25
ip route get 192.168.80.25
sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.tun0.rp_filter

然后重复 ping,同时盯住错误计数。抓包已经显示的请求旁边计数在涨,就是这次丢弃的特征,而不是缺路由的特征。顺手打开火星包日志,让内核说出它拒掉的源和网卡。两者合起来就能把加密、防火墙和缺少 iroute 排除在解释之外。

改动之前先写下基线:两个值、查询选中的设备,以及你盯的那个计数。事后正是这条记录告诉你,改动是否做成了你以为的事。

每一种 rp_filter 模式究竟接受什么

内核为每个网卡暴露三个值,而它们不是同一条规则的三种深浅。零关闭检查。一是严格模式,要求源地址能经到达网卡反向路由出去。二是宽松模式,只要求表里存在通往该源的某条路由,不管它指向哪里。

ValueNameAcceptsStill rejects
0offany source at allnothing on this check
1stricta source routed back out the arrival interfacea source whose route points elsewhere
2loosea source with any route in the tablea source with no route at all

这里要紧的是宽松那一行,以及它仍然拒绝的东西。一个能在表里任何地方路由的伪造源可以通过,而完全没有路由的源仍会被拒绝。在笔记本上这是很小的让步;在替别人转发流量的路由器上,这就是很大的让步。模式属于主机,所以同一个数字在两处分量完全不同。

这个拓扑需要哪一行,是从表里推出来的,不是从习惯来的。包是合法的,它的源也是可路由的,所以宽松模式接受它,严格模式不接受。这件事里没有哪一处需要零,而选零会去掉一个在这里毫无代价的检查。

选能消除歧义的最小改动

宽松模式是能用的最小改动,而且是实打实地放宽,不是无害的开关。只要拓扑允许,就有更好的选择:去掉重叠,歧义自然消失。

如果办公室前缀只需要走以太网,就把它从配置文件拉取的路由里去掉,地址就只剩一条路径可达。如果两条路径确实必须共存,就用策略规则把源和设备钉住,而不是在每个网卡上放宽校验。这样机器上其他一切仍然保持严格过滤,例外也写在下一个工程师会去找的地方。

无论选哪条路,都写进 sysctl drop-in,而不是敲一条临时命令。把 all 和 default 两个键一起设置,这样重连就不会悄悄把严格模式恢复回来。

# /etc/sysctl.d/99-rp-filter.conf
net.ipv4.conf.default.rp_filter = 2
net.ipv4.conf.all.rp_filter = 2
sysctl --system

宽松模式放弃了什么,又在哪里

宽松模式仍然拒绝一个任何路由都到不了的源,同时不再拒绝一个碰巧可路由的伪造源。在笔记本上这是很小的让步。在替别人转发流量的设备上,同样的选择就宽得多。所以同一个设置,跑在不同地方含义完全不同。

在替别人转发流量的主机上彻底关掉检查,是唯一该避免的修法。零会把宽松模式小心保留的那道校验扔掉。如果主机替别人转发,那就去争取上一节里的策略规则方案。

留一条备注,写清两块网卡、重叠的前缀,以及现在能通过的那次确切探测。对下一个工程师来说,这比一句“过滤已调整”有用得多。

相关文章