资讯动态

ICMP协议深度解析:从报文结构到PMTU黑洞实战排障

发布时间:2026/10/21 15:12:05 来源:尧图企业网站定制
上周值班时遇到一个跨机房的数据库主从同步告警应用侧报错packet too big主从链路直接中断。我第一反应是MTU问题于是ping大包并加上DF标记去探测结果1500字节的普通包完全正常超过某个长度后包全部发不出去。沿着路径一路查看最后发现不是哪台设备配置错了而是某段链路的安全策略把ICMP的需要分片通知报文过滤掉了源端根本不知道包在中途被丢弃。这类故障在现网里算得上最隐蔽的一种。ICMP协议听起来简单两个字报错但真正用起来几十种类型和代码、各种组合场景和边界行为足以把排障过程拖到怀疑人生。这篇文章把我这些年跟ICMP打交道的理解完整整理了一遍从报文结构、类型含义到ping、traceroute的落地原理再到实际排障和安全策略覆盖网络工程师日常最用得上的部分。不管你是刚学网络的新人还是已经在一线摸爬滚打多年的运维读完都能把ICMP那点事真正串起来。1. 一个报信机制的诞生IP协议为什么需要ICMP1.1 IP是尽力而为的协议但错误总得有人报告IP协议在今天所有网络里几乎是根基一样的存在。但它设计之初就有一个非常朴素的前提只负责把数据报从源地址送到目的地址至于路径上发生了什么它一概不管。路由器发现没有可用路径直接把包丢掉TTL减到0直接丢掉分片重组超时直接丢掉。丢完之后呢源端完全不知情。这就产生了一个很尴尬的局面。TCP可以靠超时重传判断大概出问题了但UDP这种没有反馈的协议几乎没有感知。更重要的是即使TCP知道超时了它也只能知道某个路径出问题了却不知道具体原因可能是网络不可达可能是设备被管理策略拒绝也可能是包太大被丢弃。这种信息缺口是协议栈本身无法自动弥补的。ICMP就是为了把这个信息缺口堵上。它不负责传输用户数据只负责在网络节点之间传递控制消息比如报告目的地不可达、报告TTL耗尽、提示路由可以有更优选择。你可以把它想成是IP协议配备的反馈系统。就像寄快递时快递员会打电话告诉你包裹丢了、送达了、地址不对——包裹本身是IP报文而那个电话就是ICMP。1.2 ICMP报文本身也被封装在IP报文里传输有一点初学者经常绕晕ICMP虽然是IP协议的辅助协议但它自己同样要坐在IP报文里走。也就是说一个ICMP错误消息发出时外层是一份新的IP报文IP头部的协议字段值为1表示承载的内容是ICMP。链路层看到的是一份完整的IP包跟其他数据报文没有本质区别。这说明了一个重要事实ICMP本身也是可能丢的。它没有可靠性机制也不重传。如果一条链路拥塞到连控制报文都丢那源端只会得到超时这类间接结果不能假设ICMP一定会到达。投递ICMP的优先级是另一条独立的策略问题有些网络里还需要对控制流量单独做QoS保障避免拥塞时把错误报告全挤掉。1.3 别把ICMP当成传输层它没有端口概念ICMP经常被拿来和TCP、UDP并列讨论这其实不准确。TCP和UDP是传输层协议有端口用于区分应用进程ICMP工作在网络层这个缝隙里没有端口的概念。它不承载应用数据只报告网络自身状态。这也解释了为什么很多安全策略对ICMP的处理方式会跟TCP/UDP完全不同。做访问控制列表时可以对tcp 80端口精确放行但对ICMP只能按type和code来放行没有端口这种维度。很多人在排障时纠结为什么我能ping通其他机器却ping不通某台机器原因往往就在这里——对方安全策略对ICMP的处理粒度不同或者干脆禁了某种type。2. ICMP报文拆解8字节头部里的三条线索2.1 Type和Code错误类型的两级索引ICMP报文的结构非常紧凑。最前面是4字节固定头部然后跟着的是消息体。头部前两个字节分别叫Type和Code它们是理解ICMP消息的关键索引。Type决定了这条消息的大类Code则在大类里做细分。用目的不可达来举例Type 3表示目的地不可达但具体是网络不可达、主机不可达、端口不可达、还是因分片问题不可达就要看Code字段。所以排障时只看Type是不够的必须Type和Code一起看。还有一个字段叫Checksum占2字节。它跟IP头部校验和的覆盖范围完全不同——IP校验只覆盖IP头部ICMP校验覆盖整个ICMP报文。接收方收到报文后会把校验和字段置零再对整个ICMP报文按16位为单位累加结果是0就说明报文在传输中没有被改坏。虽然以太网链路层有CRC校验但对于经过路由器转发、可能被中间设备修改的场景ICMP自己的校验还是必要的。2.2 Rest of Header一个4字节区域的多重身份头部里Type、Code、Checksum后面的4字节统称Rest of Header。这个区域很特殊它的内容取决于Type。以最常用的回声请求和回声应答Type 8和Type 0为例这4字节被拆成Identifier标识符和Sequence Number序号两个16位字段。Identifier用来区分是哪个进程发出的pingSequence Number用来匹配请求和应答的顺序。但到了目的不可达Type 3这类差错报文里这4字节的用途就不一样了。前16位通常是0后16位在Code为4时承载下一跳MTU——也就是路径上真正的MTU值。这个值在PMTUD路径MTU发现机制里是救命的信息。到了时间戳请求Type 13和时间戳应答Type 14里这4字节又拆成三个时间戳字段分别表示发起时间、接收时间和发送时间。一个位置三种身份这正是ICMP报文设计紧凑但不简单的地方。2.3 数据段藏着一份出故障当时的原始IP头差错类ICMP消息在4字节头部之后通常会附带触发这条报错消息的原始IP报文头部以及该IP报文数据部分的前8字节。这不是多余的设计它让接收方能够在收到错误报告后找到到底哪份数据包出了问题。为什么只附带前8字节而不是整个原包因为对于TCP和UDP来说前8字节已经包含了源端口、目的端口和序号等关键信息足够源端主机定位到具体是哪个套接字、哪个连接。如果要附带完整原包会产生可怕的放大效应——一个小ICMP报文承载着一个大IP报文的完整副本在网络上会造成带宽浪费。所以标准选择截取前8字节兼顾诊断信息和传输效率。3. ICMP全谱从差错报告到查询请求的类型地图3.1 差错类消息目的地不可达、超时、重定向、参数问题ICMP消息可以粗略分成两大类差错类和查询类。差错类消息是被动响应用来反馈传输过程中遇到的问题查询类消息是主动发起用来探询网络状态。差错类里第一个要重点说的是目的地不可达Type 3。它的Code细分非常多最常遇到的是Code 1主机不可达表示路由表里有目的地所在网络的路由但找不到该目的主机的路径或者主机对ARP请求无响应Code 2协议不可达表示目的主机收到了IP包但上层协议如某个特定协议号没有被实现Code 3端口不可达典型的UDP场景——目的主机上没有进程监听对应端口于是UDP层返回这个报文Code 4需要分片但设置了DF标志表示包被丢弃是因为超过路径MTU且不能分片Code 9和Code 10分别表示与目的网络、目的主机的通信被管理性禁止——这在现网中非常常见往往不是故障而是安全策略在起作用。另一个差错类是超时Type 11。Code 0表示TTL耗尽Code 1表示分片重组超时。TTL耗尽正是traceroute工作的基石后面会详细说。重定向Type 5在现网中已经不太常见了。它表示路由器发现自己收到的包本应该从另一条更优的路径发出。由于IPv4时代的内网路由通常配置得相对稳定加上重定向报文本身存在安全隐患很多现代网络默认关闭了ICMP重定向的处理。参数问题Type 12表示IP报文头部或选项字段出现了错误。其中Code 0表示指针指向出错位置报文里会带一个指针字段标明偏移量。这类消息在现网里比较少见遇到时往往意味着设备实现存在缺陷或IP分片被篡改。3.2 查询类消息回声、时间戳、掩码请求查询类消息中最出名的就是回声请求和回声应答Type 8和Type 0也就是ping的基础。它由一方发起请求另一方收到后原样把数据返回。回声消息的Identifier和Sequence Number让发起方可以准确匹配每次请求和响应。时间戳请求和应答Type 13和Type 14曾经用于测量网络延迟和时钟偏移但如今已经很少使用。现代主机一般都有更精确的时间同步手段这类消息更多出现在老旧文档和教科书里。地址掩码请求和应答Type 17和Type 18用于无DHCP环境下获取子网掩码同样早已退出实际使用。IPv4时代之所以保留它们是因为在早期网络配置自动化不完善时主机需要一种轻量方式来发现子网掩码。除了这些每个Type在IANA注册表里还有更多条目比如IPv6的邻居发现等但IPv4场景下日常真正用到的基本就是我上面列出的这些。3.3 常用Type/Code速查表与字段说明下面这张表是按我的排障频率从高到低排列的建议收藏TypeCode含义典型场景80回声请求ping发送方向00回声应答ping接收方回包31主机不可达目标主机离线或ARP失败32协议不可达目标机不支持某种上层协议33端口不可达UDP端口没人监听34需要分片且DF置位MTU过小PMTU黑洞39目的网络的通信被管理禁止ACL或安全策略拦截310目的主机的通信被管理禁止ACL或安全策略拦截313通信被管理禁止设备配置了过滤110TTL超时traceroute中间跳111分片重组超时分片包未收齐51主机重定向路由可优化建议慎用120IP头参数错误报文头出错13—时间戳请求延迟测量少见14—时间戳应答延迟测量少见4. ping与traceroute两个工具一套ICMP逻辑4.1 ping的RTT、TTL和丢包字面意思与实际含义ping是最常用的ICMP工具它通过发送Type 8回声请求、接收Type 0回声应答来确认目标是否可达。当前主机在线、路径通畅、策略允许三层就通了。这三件事缺一样表现在用户眼里都是ping不通。RTT往返时间是发送请求到收到应答的总耗时它包含了传播延迟、处理延迟和排队延迟。如果RTT突然从1毫秒飙升到100毫秒优先怀疑路径是否绕行、是否存在拥塞。TTL则是每一跳路由器都会减1的字段从最终TTL值可以反推目标设备大概隔了多少跳。丢包率这个指标要谨慎解读。ping丢包不代表业务流量一定丢包。很多设备对ICMP的处理优先级低于业务转发尤其在CPU保护策略生效时ICMP回声请求会被有意丢弃而数据流量却正常转发。反过来ping通也绝不代表业务一定没故障因为业务报文走的路由可能与ICMP不同或者业务依赖的TCP端口被策略拦截。把ping当全通判据是在排障中最容易踩的坑。4.2 traceroute逐跳追踪的原理与两种探测包姿势traceroute的原理很巧妙地利用了ICMP超时消息。它从TTL1开始向目的地址发送探测包每路过一个路由器TTL减1减到0时路由器丢弃该包并返回一个Type 11 Code 0的超时报文。这个报文的源IP地址恰好就是那台路由器的接口地址。于是traceroute再从TTL2、TTL3依次发包就能逐步勾勒出从源端到目的端的完整路径。Linux下的traceroute默认使用UDP探测包目的端口从高位开始递增Windows下的tracert默认使用ICMP回声请求。两种方式在行为上有区别UDP探测到达最终目的主机时由于没有对应的UDP服务目的主机会回一个Type 3 Code 3端口不可达消息表示我到了但端口没监听ICMP探测到达最终目的主机时则直接回Type 0回声应答。了解这一点对读懂traceroute结果很有帮助。中间某跳显示星号并不代表路径断了。可能是该路由器不回ICMP超时报文也可能是它的控制平面策略丢弃了这类包。只要下一跳仍然能继续探测整条路径大概率是可用的。4.3 用抓包还原一次回声交互在Linux下用tcpdump看ICMP字段一目了然tcpdump -i eth0 icmp -nn一次典型ping交互的抓包结果是12:03:22.501001 IP 192.0.2.10 192.0.2.20: ICMP echo request, id 5, seq 1, length 64 12:03:22.501234 IP 192.0.2.20 192.0.2.10: ICMP echo reply, id 5, seq 1, length 64id和seq正好对应我前面讲的Identifier和Sequence Number。id用于区分不同进程seq用于匹配请求和应答。抓包时如果只有request没有reply说明请求到达了目的端或某台中间设备但应答没有回来如果连request都看不到说明请求在更早就被拦截了。5. 实战排障用ICMP的Type/Code反推故障点5.1 目的不可达Code细分主机、端口、管理禁止和分片排障时看到Type 3不可达消息先看Code再动手。Code 1主机不可达先确认目标主机是否在线、ARP解析是否正常Code 3端口不可达目标主机在线但UDP端口没监听通常说明服务没起来Code 9、10、13管理禁止路径上某个安全设备明确拒绝了你优先找链路上的ACL策略而不是怀疑设备故障。有一个最常见的场景是客户端从内网向外网发起UDP通信回包带Type 3 Code 3。很多刚入门的朋友以为这是目标不可达故障实际上这往往证明了UDP包已经到达目标主机只是目标主机上没有对应端口在监听。这条信息本身说明网络路径是通的问题出在服务端口没有监听。5.2 PMTU黑洞为什么网络会半通不通PMTU黑洞是ICMP排障中最头疼的问题之一。它的机制是路径中某段链路的MTU小于源端发送的报文长度路由器需要丢弃该包并按RFC 1191返回Type 3 Code 4告诉源端这条链路只支持这么大的包。TCP源端收到后就会降低发送包大小。但如果中间设备把Type 3 Code 4过滤掉了源端永远不知道包在途中被丢弃只能靠TCP超时重传导致业务表现为大包通不了小包正常。判断方法很简单在源发端执行带DF标记的ping逐渐增大包长观察哪个长度开始不通。例如以太网默认MTU是1500如果你发现1472字节的ping1500减去IP头和ICMP头共28字节能通1473就不通说明路径MTU就在1500附近。如果发现某个中间长度开始丢包则很可能是路径上有更小的MTU而且相关ICMP报文被拦截了。知道了MTU黑洞的存在下一步就是对相应链路上放行Type 3 Code 4并且确保源端启用PMTUD。很多现代数据中心里还是直接给TCP开启MSS钳制避免依赖ICMP反馈因为ICMP在跨域场景下太容易被过滤。5.3 防火墙过滤ICMP带来的健康假象我在不同项目里都见过类似现象业务通了但ping不通或者反向ping通了业务却连不上。前者多半是防火墙只放行业务端口禁掉了ICMP后者则是业务端口被策略拦截但ICMP被放行。这些都说明ICMP的可达性与业务的可达性不是一回事。有一种健康假象更迷惑主机防火墙禁掉了ICMP回声应答但其他类型ICMP放行了。结果ping时显示丢包或超时用户立刻觉得网络断了可实际业务流量完全正常。处理这类问题我的经验是不要只看ping直接用TCP连接测试工具或者业务自身的健康检查去验证端口连通性然后再回到ICMP侧看是什么类型的消息被拦了。5.4 广播、回环口、多路径下ICMP行为差异对广播地址发ICMP回声请求理想情况下子网内所有主机都会回应答这在早期被用于Smurf攻击。如今大多数网络设备和操作系统默认不回广播地址的ICMP所以现在即使向子网广播地址发ping也常常只得到自己的回环应答或没有应答。排障时不要把广播地址ping不通当成故障。回环口是另一个容易出意外的地方。很多网络设备的管理地址是Loopback接口它始终在线不受物理接口状态影响。从业务网络ping它通了只能说明三层路由和策略允许不能说明某个物理接口的正常性。要结合接口状态、光功率等物理层指标综合判断。多路径环境下每次ping可能走不同路径导致RTT呈现明显的阶梯状分布丢包率也忽高忽低。这种情况下不能简单得出线路质量差的结论要看是不是等价路由或者负载均衡策略造成的路径差异。必要时可以在源端指定源IP在目的端做策略路由把探测流量固定到某一条路径上。6. 安全护栏哪些ICMP该放行哪些该拦6.1 基于ICMP的经典攻击以及为什么它们现在难成大器ICMP天然可以用来做攻击向量。最出名的是Smurf攻击攻击者伪造受害者的IP作为源地址向某个网络的广播地址发送ICMP回声请求导致该网络内大量主机同时向受害者回复回声应答形成流量放大。现代操作系统和路由器普遍默认不响应发往广播地址的回声请求这种攻击基本失去了舞台。ICMP洪泛是另一种常见攻击通过大量回声请求或不可达报文耗尽目标设备的CPU或带宽。对付这类攻击依靠的是速率限制和流量清洗而不是简单禁掉所有ICMP。此外还有利用ICMP隧道隐蔽传输数据的做法把数据藏在回声请求的数据区里实现隐蔽通道。对于企业的边界网络限制ICMP隧道的常见手法是设置只允许特定大小的ICMP数据包并对请求频率做限制。6.2 防火墙策略的常见误区全禁和全放都是坑最偷懒的做法是直接把ICMP全部禁掉理由是少一类协议少一分风险。但这个方案会让很多基础排障手段失效ping不通、traceroute看不到路径、PMTU黑洞无法发现。业务一旦出现问题排查成本成倍增加。更合理的做法是区分对待对于面向互联网的接口可以限制ICMP的类型和速率对于内网管理接口ICMP通常应当放行因为内网流量相对可控。还有一个误区是把允许ping等同于允许全部ICMP入口。实际上ICMP的type非常多回声请求只是其中之一。如果策略只放行了Type 8却没有放行Type 11超时和Type 3 Code 4traceroute和PMTUD依然会失效。安全策略要做到的是精准放行而不是一刀切。6.3 一套可落地的ICMP放行清单以下是我在多数网络环境中默认采用的ICMP策略思路按场景区分内网管理平面允许回声请求、回声应答Type 8/0用于日常探测允许超时消息Type 11保障traceroute可用允许目的不可达Type 3保障PMTUD和端口探测允许参数问题Type 12便于协议异常排查允许重定向Type 5建议谨慎现代网络基本可以关闭对外服务接口允许出方向的回声请求、入方向的回声应答允许入方向的Type 3 Code 4避免外部路由设备返回MTU消息丢失允许入方向的Type 11方便外部用户做traceroute诊断对入方向回声请求做速率限制并按需选择是否响应禁止对广播地址发送回声请求通常在路由器上关闭IP directed-broadcast这套思路的核心是让ICMP继续发挥诊断作用同时避免被滥用。做了这么多年网络排障我的个人体会是ICMP协议本身很少出“故障”大多数问题出在两侧要么是策略把它错误地拦了要么是排障的人忽略了Type和Code的含义。现在每次拿到报错我都会在ping之前先想清楚——我要用这个工具确认什么我期望看到哪一种Type和Code这个习惯让我少走了非常多的弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑