运维笔记:一次IPsec隧道惨遭“心跳断绝”分手的诡异现场

76 阅读6分钟

【导语】

工程师小李盯着监控屏上频繁闪红的告警图标,指尖无意识地敲打着桌面,“刚牵上的线,说断就断?”他喃喃自语。屏幕上,那条本该恒稳如磐的IPsec隧道,此刻却如同反复无常的渣男——隧道协商时信誓旦旦“I'm here”,待到热情的DPD“心跳包”发出后,迎来的却只有令人窒息的沉默与无视。尤其是日志里那句冰冷的控诉:“DPD check timed out, enforcing DPD action”,仿佛设备在声嘶力竭地哭诉:“我的心跳,你为何没有回应!”

图1.jpg

小李深吸一口气,这哪里是简单的网络中断?分明是一场技术围城,“响应者”满腔热忱地维持着心跳连线,而“发起者”却默然无应,酿成一桩不知缘由的“单相思”惨案。


【事件回溯:甜蜜连接与莫名“失联”】

用户现场IPsec隧道明明已经顺利“牵手”(主模式协商通过,快速模式交换成功),加密通道已然铺就,ESP流量数据本应如同热恋期的密语般在隧道内安全流通。然而,“蜜月期”短暂得让人措手不及。

隧道就像得了怪病,总是毫无征兆地“快速分手”(断开连接)。查看设备日志,一条刺眼的报错赫然在目:

DPD check timed out, enforcing DPD action

DPD(Dead Peer Detection)探测,是IPsec维持连接的“生命信号灯”:它如同情侣间定时发送的心跳消息:“嘿,你还活着吗?还爱我吗?”(DPD探测报文); 如果一方长时间收不到对方的“心跳包”(DPD响应报文),便会心灰意冷地认定对方已“死”(连接失效),果断执行DPD Action操作(指定为关闭隧道)。

图3.jpg

乍看之下,似乎问题出在网络:可能是中间链路不稳,导致心跳信号“送丢了”?于是,资深“网络侦探”小李祭出终极法宝:在隧道两端同时进行抓包分析。


【悬案侦破:谁的心跳石沉大海?】

分析过程像是一场精心布置的技术审问。小李分别审视隧道发起者(172.16.1.79)和响应者(192.168.1.188)的抓包(Initiator.pcap & Responder.pcapng)。

发起者未响应DPD.png

  • 阶段一:甜蜜的“结合” 双方抓包显示,IPsec隧道协商阶段堪称完美:

    • Main Mode (主模式): 双方你来我往,相互完成身份认证与IKE密钥协商,在身份可靠的基础上为IPsec密钥协商保驾护航。
    • Quick Mode (快速模式): 协商出IPsec密钥,确保后续业务数据的安全传输。

    一切迹象表明,隧道在“意识层面”(协议层)成功建立。

    发起者未响应DPD-响应者视角.png

  • 阶段二:失衡的“心跳”

    然而,当目光转向维持连接的Informational包后(DPD活动通常以此类消息承载),侦探小李敏锐地捕捉到关键差异:

    • 发起者(Initiator)侧抓包(Initiator.pcap):

      关键发现:从时间上可以看出,发起者(172.16.1.79)自己发出去的Informational包(DPD探测请求)均有回复,然而看不到它对来自响应者Informational包(DPD探测请求)的有效回复!响应者的DPD请求如同石沉大海,发起者仿佛压根没看见!

    • 响应者(Responder)侧抓包(Responder.pcapng):

      与发起侧的现象相同:响应者(192.168.1.188)在固定间隔主动向发起者发出的Informational包(DPD探测请求,如12号包、15号包、18号包、21号包、24号包),均无回应。

图5.png

至此,已能明确问题出在端侧设备:

1️⃣ 问题并非中间网络: 如果中间网络有问题,响应者的DPD探测请求送达不到发起者设备才对,然而事实上发起者已经收到了响应者的DPD探测请求。 2️⃣  问题锁定发起者设备: 是发起者(172.16.1.79),接收到了来自响应者(192.168.1.188)的DPD“心跳”请求,但自己选择视而不见(未回复)! 这才是导致响应者苦等无果,最终心死断开隧道。响应者像个痴情的追求者,一次次发送爱的呼唤,却始终得不到回应,只能绝望分手(关闭隧道)。


【根因追踪:无情的“门卫”——rp_filter】

既然凶手锁定在发起端,小李的排查矛头直指发起端Linux网络栈。经验与线索指向了那个著名的“严格模式门卫”——rp_filter(Reverse Path Filtering,反向路径过滤)。

图2.png

案发现场还原:

1️⃣ 响应者发送DPD探测包: 发自192.168.1.188,目的地址是发起者172.16.1.79

2️⃣ 发起者收到包: 包进入其网卡

3️⃣ rp_filter严格审查: 发起者系统的rp_filter(设置为严格模式)开始工作。它要检查:回复包(172.16.1.79到192.168.1.188)该从哪个网卡出去?它会查系统路由表,由于在隧道协商成功后会添加ipsec0相关的路由,此时发现回复路径(到192.168.1.188)最优的出口应该是网卡ipsec0

4️⃣ 比对入站接口: DPD包实际是从发起者eth0网卡进来的,发现这个包进来时走的网卡和最佳回复路径的出口网卡不一致(包是从网卡eth0进来的,而最佳回复路径则是网卡ipsec0),rp_filter冷酷地做出判决:此包路径异常,有欺诈嫌疑,Drop(丢弃)

5️⃣ 丢弃DPD探测请求包,心跳被掐断:因此,发起者内核的网络栈根本没能把这个“心跳”(DPD探测请求)交给用户态的IPsec守护进程去处理,自然也就不会有DPD回复发送给响应者。一度被视为渣男的IPsec守护进程表示自己也很冤枉:“我没收到请求啊”

6️⃣ 响应者等待超时: 响应者等啊等,心慢慢变凉,直到DPD探测超时:“他果然不爱我了(Dead Peer)...再见吧!”

7️⃣ 隧道被关闭: 响应者单方面宣布“分手”(关闭隧道)。

图4.png


【解决方案:让“门卫”睁一只眼闭一只眼】

只需在端侧设备上,对接收DPD请求的网络接口,关闭rp_filter或使用宽松模式即可。


【后记】

IPsec建立起的安全隧道,是两台设备在网络洪流中划定的私密航线。DPD探测如同维系航线的灯塔信号,一旦光芒熄灭,信任即告瓦解。工程师如同解码爱意的侦探,从冷漠的报错日志与沉默的抓包洪流中,拼凑出“信号明明送达,对方却为何不应”的真相。当rp_filter的铜墙铁壁被调低一个刻度,设备间的心跳得以重新同频。网络协议为连接而生,而生之证明,系于系统规则对某个比特的裁决之间。我们终于明白:最坚固的加密堡垒,也会因一粒沙的错位而崩塌——在这由代码构筑的世界里,最深的连接永远是:我发出的心跳,你允许它到达;你需要的应答,我从未让它沉没。


【更多精彩内容】

公众号.png