原文地址:反向路径过滤——reverse path filter 作者:pwp_cu
反向路径过滤——reverse path filter一、原理先介绍个非对称路由的概念参考《Understanding Linux Network Internals》三十章,30.2. Essential Elements of RoutingSymmetric routes and asymmetric routesUsually, the route taken from Host A to Host B is the same as the route used to get back from Host B to Host A; the route is then called symmetric . In complex setups, the route back may be different; in this case, it is asymmetric.关于反向路径过滤,参考《Understanding Linux Network Internals》三十一章,31.7. Reverse Path FilteringWe saw what an asymmetric route is in the section "Essential Elements of Routing in Chapter 30. Asymmetric routes are not common, but may be necessary in certain cases. The default behavior of Linux is to consider asymmetric routing suspicious and therefore to drop any packet whose source IP address is not reachable through the device the packet was received from, according to the routing table.However, this behavior can be tuned via /proc on a per-device basis, as we will see in Chapter 36. See also the section "Input Routing" in Chapter 35.二、检查流程如果一台主机(或路由器)从接口A收到一个包,其源地址和目的地址分别是10.3.0.2和10.2.0.2,即, 如果启用反向路径过滤功能,它就会以为关键字去查找路由表,如果得到的输出接口不为A,则认为反向路径过滤检查失败,它就会丢弃该包。关于反向路径过滤,ipv4中有个参数,这个参数的说明在Documentation/networking/ip-sysctl.txt中。rp_filter - INTEGER 0 - No source validation. 1 - Strict mode as defined in RFC3704 Strict Reverse Path Each incoming packet is tested against the FIB and if the interface is not the best reverse path the packet check will fail. By default failed packets are discarded. 2 - Loose mode as defined in RFC3704 Loose Reverse Path Each incoming packet's source address is also tested against the FIB and if the source address is not reachable via any interface the packet check will fail. Current recommended practice in RFC3704 is to enable strict mode to prevent IP spoofing from DDos attacks. If using asymmetric routing or other complicated routing, then loose mode is recommended. The max value from conf/{all,interface}/rp_filter is used when doing source validation on the {interface}. Default value is 0. Note that some distributions enable it in startup scripts.三、源代码分析git commit 373da0a2a33018d560afcb2c77f8842985d79594net/ipv4/fib_frontend.c 192 int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, u8 tos, 193 int oif, struct net_device *dev, __be32 *spec_dst, 194 u32 *itag) 195 { // 是否启用反向路径过滤 216 /* Ignore rp_filter for packets protected by IPsec. */ 217 rpf = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(in_dev); // 检查路由表 // 注意这里的源地址贺目的地址是反过来的, // 看看其他函数是如何调用fib_validate_source()就明白了。 227 if (fib_lookup(net, &fl4, &res)) 228 goto last_resort; // 运行到这里,说明反向路由是可达的 // 下面分成两种情况检查输出设备是否就是输入设备 237 #ifdef CONFIG_IP_ROUTE_MULTIPATH // 启用多路径时,任意一个匹配,就用它了 238 for (ret = 0; ret < res.fi->fib_nhs; ret++) { 239 struct fib_nh *nh = &res.fi->fib_nh[ret]; 240 241 if (nh->nh_dev == dev) { 242 dev_match = true; 243 break; 244 } 245 } 246 #else 247 if (FIB_RES_DEV(res) == dev) 248 dev_match = true; 249 #endif 250 if (dev_match) { // 反向路径过滤检查成功了,返回 251 ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; 252 return ret; 253 } 254 if (no_addr) 255 goto last_resort; // 运行到这里,说明反向路径检查是失败的, // 如果rpf为1,表示反向路径检查必须成功才能正常返回, // 否则只好返回错误。 256 if (rpf == 1) 257 goto e_rpf; 278 e_rpf: 279 return -EXDEV;四、实例本网络有三台机器,R1, R2 和PC,子网掩码都是255.255.0.0。R2 (10.1.0.2) ---- (10.1.0.1) R1 (10.3.0.1) ---- (10.3.0.2) PCR2 (10.2.0.2) ---- (10.2.0.1) R1注意,设置R2的默认路由为10.1.0.1现在,从PC上能够ping通10.1.0.2,但是ping不通10.2.0.2。tcpdump显示,R2接到icmp request,但是不发送icmp reply。PC$ ip ainet 10.3.0.2/16 brd 10.3.255.255 scope global eth0$ ip r10.3.0.0/16 dev eth0 proto kernel scope link src 10.3.0.2default via 10.3.0.1 dev eth0R1$ ip ainet 10.1.0.1/16 brd 10.1.255.255 scope global eth1inet 10.2.0.1/16 brd 10.2.255.255 scope global eth2inet 10.3.0.1/16 brd 10.3.255.255 scope global eth3$ ip r10.1.0.0/16 dev eth1 proto kernel scope link src 10.1.0.110.2.0.0/16 dev eth2 proto kernel scope link src 10.2.0.110.3.0.0/16 dev eth3 proto kernel scope link src 10.3.0.1R2$ ip ainet 10.1.0.2/16 brd 10.1.255.255 scope global eth1inet 10.2.0.2/16 brd 10.2.255.255 scope global eth2$ ip r10.1.0.0/16 dev eth1 proto kernel scope link src 10.1.0.210.2.0.0/16 dev eth2 proto kernel scope link src 10.2.0.2default via 10.1.0.1 dev eth1请问这是什么原因?你可以返回去细细思考5分钟......我的回答:假设R2的两个接口分别为A(10.1.0.2)、B(10.2.0.2)。从PC ping 10.2.0.2时,包的路径是PC-->10.3.0.1-->10.2.0.2,此时包的 ,以进行反向路径检查, 得到输出设备是A,因为目的地址是10.3.0.2,只能使用默认路由。A!=B,反向路径检查失败,丢弃该包!五、如何解决两种方法:1 On R2:ip route add 10.3.0.0/16 via 10.2.0.2增加一条关于10.3.0.0/16子网的路由。2 On R2:/etc/sysctl.confnet.ipv4.conf.default.rp_filter = 0禁用反向路径检查。