本文完整阅读约需 13 分钟,如时间较长请考虑收藏后慢慢阅读~

实习的单位由于需要加速教育网访问,在已有电信网络的基础上,接入了教育网,并采用了双交换机、双网卡、双IP、单出口网关的配置,通常来说,在硬件部署完毕之后,只需要在Linux里面配置教育网IP信息,就可以同时通过电信和教育网访问服务器。但是在配置完之后,却出现了电信能通,教育网不能通的BUG。
在解决该问题的过程中,我逐渐了解到了反向路由检测机制与静态路由机制的相关知识,该文章旨在记录我的收获,同时向大家分享我遇到的问题以及解决步骤,并且粗略的介绍反向路由检测这一相对『冷门』的概念。

TroubleShooting

故障出现后,我立刻修改域名解析,以免故障扩大化,造成教育网用户无法访问服务。

在修改解析后,我便开始着手排查故障。

最开始,我将注意力放在了教育网所属网卡的配置上,然而在多次配置后,发现并不奏效,通过ping -I em1指定教育网所在网卡,发现无法连通外网,而通过traceroute命令也无法获取任何有用的信息。

这时候我发现同样配置的一台Windows Server居然可以在正常配置下同时连通教育网和电信,因此可以基本判断,故障与下游网络设备无关。

在查阅资料之后,我找到了这样一篇文章:Linux内核的反向路由检查机制

按照文章的介绍,我依次执行了以下的shell命令:

echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter # 关闭所有网卡的反向路由检测
echo 0 > /proc/sys/net/ipv4/conf/deafult/rp_filter # 关闭默认网卡(未指定情况下)的反向路由检测
echo 0 > /proc/sys/net/ipv4/conf/em1/rp_filter # 关闭教育网所属网卡的反向路由检测
echo 0 > /proc/sys/net/ipv4/conf/em2/rp_filter # 关闭电信所属网卡的反向路由检测
service network restart # 重启网络服务

在命令执行完毕后,再次尝试指定网卡对外网进行ping,发现均能ping通,而从外网对电信/教育网进行ping,也都可以ping通,问题随之解决。

BUT WHY?

通过实际的硬件排查,我惊奇的发现尽管网关配置了教育网出口,却配置了奇葩的静态路由:所有网络流量均从电信网络所属交换机进出(包括教育网流量),这就造成了以下的情况:

正常:

电信交换机->em2:你好,我要向你发送一个IP单播数据包,我的源地址是电信网关IP
em2->电信交换机:好的,我收到了,这个源地址确实存在,我会在处理完数据后按照源地址将数据寄回

异常:

电信交换机->em2:你好,我要向你发送一个IP单播数据包,我的源地址是教育网网关IP
em2->电信交换机:???,通过这个网口我找不到教育网网关IP,那按照这个网口的rp_filter策略(值为1),我要DROP掉这个包

这就是Linux的反向路由检测机制,该机制的目的有多个:
– 避免出现意料之外的结果(从一个网卡进,从另一个网卡出),形成循环
– 安全考虑,避免出现IP单播数据包的欺骗
– 避免在较复杂的网络拓扑环境下,因为路由器错误的路径规划,造成反向路径过于复杂,降低网络性能

而根据Linux内核的官方文档,rp_filter可能的值有以下几种:

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.

大概翻译过来就是:
– 模式0:不进行反向路由检测。
– 模式1:进行反向路由检测,如果“传入”接口不是最佳反向路径,则数据包检查失败。默认情况下,失败的数据包被丢弃。
– 模式2:进行反向路由检测,每个进入的单播数据包的来源地址同样会被检查。如果来源地址是无经由该接口的路径到达,检查将失败。

这就不难解释,为什么会出现教育网无法连通的情况了:上游网关的不正确设置,导致了

End

根据RFC 3704的建议,通常应该使用最严格的反向路由检测策略,然而在我遇到的这种奇葩上游网关情况下,关闭反向路由检测能够花更少的时间,起到更显著的作用,目前看来,严格反向路由检测所顾及的风险在这一业务情景下并未出现,因此关闭反向路由检测是合理的。

而除了关闭反向路由检测策略以外,还有一种相对比较复杂的方式可以解决这一问题:配置静态路由表。在这里不再赘述,但是相对于关闭反向路由检测,配置静态路由表显得更加『优雅』,却更加复杂,具体选用哪种方案,还要看具体的业务需求以及实现难度。

附上反向路由检测策略以及静态路由的相关链接以供查阅:
反向路由检测-Wikipedia
静态路由-华为官方文档
双IP情况下的静态路由配置-新浪博客

而至于那台Windows服务器,经过后期的检查,发现已经配置了静态路由,这进一步说明了无论是关闭反向路由检测(将错就错),还是配置静态路由(修改错误),都能够解决这一问题。
尽管关闭反向路由检测并不是一个最优解决方案,但是能够借由这次机会,学习到这个通常没人会注意的细节,也是一件很有成就感的事情。

希望这篇博客能够帮到遇到同样问题的人。