①一句话:ICMP 是什么
ICMP(Internet Control Message Protocol,网际控制报文协议)是 TCP/IP 协议族的网络层协议,用来在主机与路由器之间传递控制信息与差错报告。它不承载用户数据,唯一职责是:当 IP 数据报出问题或需要探询时,给发送方一个回话。
为什么非要它不可——因为 IP 是“哑巴”
IP 协议的设计哲学是尽力而为(best effort):它只管把包往链路上扔,丢了就丢了,不确认、不重传、不通知。这就带来三个盲区:
盲区一:包丢了没人说
发送方不知道包是到了还是丢了,更不知道丢在哪一跳。
盲区二:出错没人解释
路由器丢包可能是没路由、TTL 归零、MTU 太小、端口没进程……原因不同,处置完全不同。
盲区三:路径不可知
无法知道包走了哪条路、经过多少跳、哪一段慢。
ICMP 就是补这三个盲区的:报差错、答查询、探路径。它运行在 IP 之上、服务于 IP,是IP 协议不可分割的配套件——RFC 792 把它定义为“IP 的组成部分,任何实现 IP 的模块都必须实现 ICMP”。
图 1 · ICMP 补上了 IP「只发不回」的短板
关键认知:ICMP 不传输用户数据,也不负责可靠性(不重传、不排序、不流控)。它只是报告——至于收到报告后要不要重传、怎么重试,那是 TCP 或应用程序自己的事。
②它在协议栈的哪个位置
这是最容易答错的一问。ICMP 报文被 IP 数据报封装(IP 头部的「协议号」字段填 1),看上去像被 IP 承载、和 TCP/UDP 平级,但从功能定位上它是网络层协议,是 IP 的辅助协议,不是传输层。
图 2 · ICMP 是网络层里「IP 的助手」,不是传输层
封装结构(一图看清谁包着谁)
图 3 · ICMP 报文封装位置:直接躺在 IP 数据区里,没有 TCP/UDP 头
面试高频陷阱:“ping 一下 80 端口通不通”这句话是错的。ICMP 没有端口概念,ping 通只能说明三层可达,与 80/443 端口开不开没有直接关系。要测端口得用 telnet / nc / tcpping(走 TCP)。反过来,禁 ping 的服务器端口照样开着。
③ICMP 报文格式:8 字节定长头
所有 ICMP 报文的前 4 个字节格式统一(类型、代码、校验和),第 5~8 字节随类型变化,后面跟数据部分。
图 4 · ICMP 报文格式:前 4 字节固定,第 5~8 字节「看类型下菜」
点开每个字段看说明
类型8 bit
代码8 bit
校验和16 bit
可变字段32 bit
数据部分可变
👆 点击上方任意字段,查看它的含义与作用。
以 ping(Echo)报文为例,标识符与序号的妙用
图 5 · ping 报文:靠标识符 + 序号把一问一答配对起来
为什么 ping 默认 64 字节?8 字节 ICMP 头 + 56 字节数据 = 64 字节,是历史沿用的默认值(早期 BSD 实现)。加上 20 字节 IP 头,一个 ping 包在IP层是 84 字节。用 ping -s 1400 可以改数据部分大小,常用于测 MTU。
④两大类报文:差错报告 vs 查询
ICMP 报文按用途分成泾渭分明的两类,理解这个分类,后面的类型表就不会乱。
| 类别 | 差错报告报文 | 查询报文 |
| 触发方式 | 被动:有人发包出错,我才回报 | 主动:我主动发问,对方回答 |
| 通信模式 | 单向(只有报告,不需要回应) | 双向一问一答(Request / Reply) |
| 典型类型 | Type 3 目的不可达 Type 11 超时 Type 12 参数错误 Type 5 重定向 | Type 8 / 0 Echo 请求应答 Type 13 / 14 时间戳 Type 17 / 18 地址掩码(已弃用) |
| 数据区内容 | 原始出错 IP 头 + 数据前 8 字节 | 标识符 + 序号 + 时间戳 + 填充 |
| 典型应用 | traceroute、PMTUD、路由重定向 | ping |
图 6 · 差错类单向报告,查询类一问一答
⑤为什么差错报文要“夹带”原始报文
这是 ICMP 设计里最精妙的一处。差错报文的数据部分不是随便填的,而是固定携带出错数据报的 IP 头 + 其数据区的前 8 字节,总共 28 字节。
图 7 · 差错报文「夹带原文」,让源主机能定位到具体连接
为什么偏偏是前 8 字节?因为 TCP/UDP 头部的前 8 个字节正好包含源端口与目的端口(UDP 是源端口2+目的端口2+长度2+校验和2;TCP 是源端口2+目的端口2+序号4)。有了这四个字节,源主机就能把差错报文精确交给出问题的那个 socket,而不是笼统地丢给 IP 层。这是「够用就好」的经典工程取舍 —— 再多带就是浪费。
一个易错点:差错报文的可变字段(第 5~8 字节)必须全填 0,这是 RFC 792 的规定(历史遗留:早期设计想在这里放更多信息,后来没用上,就成了保留位)。只有 Type 3 Code 4(需要分片但 DF 置位)是例外 —— 它把下一跳的 MTU 填在这里,这是 PMTUD 的关键。
⑥类型与代码速查全表
差错报告类
| Type | Code | 含义 | 谁发 |
| 3 | 0~15 | 目的不可达:0 网络不可达 / 1 主机不可达 / 2 协议不可达 / 3 端口不可达 / 4 需要分片但 DF 置位 / 9 网络被禁 / 10 主机被禁 / 13 被过滤 | 路由器或目标主机 |
| 4 | 0 | 源抑制(Source Quench)—— 拥塞通知,已被 RFC 6633 弃用 | 路由器(现代已不发) |
| 5 | 0~3 | 重定向:0 网络重定向 / 1 主机重定向(告诉你「有更近的路」) | 同网段路由器 |
| 11 | 0 / 1 | 超时:0 = TTL 减到 0(traceroute 靠它);1 = 分片重组超时 | 路由器 |
| 12 | 0~2 | 参数错误:0 IP 头字段错 / 1 缺必需选项 / 2 长度错 | 路由器或主机 |
查询类
| Type | Code | 含义 | 状态 |
| 0 | 0 | Echo Reply(回显应答,ping 的返回) | 在用 |
| 8 | 0 | Echo Request(回显请求,ping 的发出) | 在用 |
| 9 / 10 | 0 | 路由器通告 / 请求(Router Advertisement / Solicitation) | 少用(IPv4) |
| 13 / 14 | 0 | 时间戳请求 / 应答 | 少用 |
| 15 / 16 | 0 | 信息请求 / 应答 | 已废弃 |
| 17 / 18 | 0 | 地址掩码请求 / 应答 | 已废弃(被 DHCP 取代) |
| 30 | 0 | Traceroute | 已废弃(被 TTL 递增法取代) |
| 42 / 43 | — | 扩展 Echo 请求 / 应答(RFC 8335,可指定用谁的地址回) | 较新 |
只需死记 4 组:8 / 0(ping 一问一答)、3(目的不可达,Code 3 端口不可达最常见)、11(TTL 超时,traceroute 的命脉)、3 的 Code 4(需要分片,PMTUD 的命脉)。
⑦五大工作场景:ICMP 到底干了什么
图 8 · 五大场景全景:ping、不可达、traceroute、重定向、PMTUD
Q:traceroute 为什么有时只看到星号 * * *?
说明那一跳的路由器
不回 ICMP Type 11(很多运营商设备出于安全或性能关闭了 ICMP 响应),或者回程报文被防火墙拦了。这
不代表路径不通——后面的跳能出来就说明包过去了。
Q:为什么 UDP 扫端口会“秒回拒绝”,TCP 却是“超时”?
因为 UDP 无连接:数据报到目标主机后没有进程监听,主机直接回
ICMP Type 3 Code 3(端口不可达),扫描器立刻知道端口关闭。而 TCP 关端口回的是
RST;如果被防火墙静默丢弃,就只能等超时。
⑧ICMP 的五条铁律(不怕风暴的秘诀)
ICMP 最大的风险是自己引发风暴:一个差错报文又在传输中出错 → 再产生一个差错报文 → 无限循环。RFC 792/1122 规定了严格的例外,以下五种情况绝不产生 ICMP 差错报文:
图 9 · 五条铁律确保 ICMP 不会自我放大成风暴
第①条最关键。注意区分:查询报文(如 Echo Reply)出错是可以报的,只有差错报文本身出错才禁止再报。这条边界是面试常考点。
⑨ICMPv6:从“可选项”变成“命根子”
IPv6 把 ICMP 升级为 ICMPv6(RFC 4443),下一个头字段值为 58。它不只是把类型号换了一遍,而是吞并了 IPv4 中 ARP、IGMP 的职责——所以在 IPv6 里绝不能随便禁 ICMPv6。
| ICMPv6 类型 | 含义 | IPv4 中的对应 |
| 1 目的不可达 | 无路由 / 被禁止 / 地址不可达 / 端口不可达 | ICMP Type 3 |
| 2 包过大 | Packet Too Big,携带下一跳 MTU | Type 3 Code 4(且 IPv6 禁止中间路由器分片,PMTUD 成刚需) |
| 3 超时 | 跳数限制(Hop Limit)归零 / 重组超时 | Type 11 |
| 128 / 129 | Echo 请求 / 应答(ping6) | Type 8 / 0 |
| 133 / 134 | 路由器请求 RS / 路由器通告 RA | 路由器发现 + 部分 DHCP |
| 135 / 136 | 邻居请求 NS / 邻居通告 NA | 取代 ARP(地址解析 + 重复地址检测 DAD) |
| 137 重定向 | 更优下一跳 | Type 5 |
图 10 · ICMPv6 接管了 ARP,地位从「辅助」升级为「基础设施」
⑩抓包实战:一眼认出 ICMP
用 tcpdump 或 Wireshark 抓的包长什么样:
# 抓本机 ping 8.8.8.8 的 ICMP 包
$ sudo tcpdump -nn -i any icmp
# 出去:Echo Request
IP 192.168.1.10 > 8.8.8.8: ICMP echo request, id 47891, seq 1, length 64
# 回来:Echo Reply
IP 8.8.8.8 > 192.168.1.10: ICMP echo reply, id 47891, seq 1, length 64
# 访问没开的 UDP 端口
IP 10.0.0.5 > 10.0.0.9: ICMP 10.0.0.9 udp port 9999 unreachable, length 68
# traceroute 途中
IP 192.168.1.1 > 192.168.1.10: ICMP time exceeded in-transit, length 56
| tcpdump 显示 | 对应 Type / Code | 含义 |
echo request | Type 8 / Code 0 | ping 发出 |
echo reply | Type 0 / Code 0 | ping 返回 |
udp port X unreachable | Type 3 / Code 3 | 端口无进程监听 |
host X unreachable | Type 3 / Code 1 | 主机不可达(ARP 失败 / 无路由) |
time exceeded in-transit | Type 11 / Code 0 | TTL 归零(traceroute 的回包) |
redirect | Type 5 | 路由重定向 |
frag needed and DF set | Type 3 / Code 4 | 需要分片但 DF 置位(带 MTU) |
Wireshark 过滤小技巧:icmp 看全部;icmp.type == 8 只看请求;icmp.type == 3 && icmp.code == 3 只看端口不可达;icmp.type == 11 只看 TTL 超时。
⑪安全风险:ICMP 被怎么用坏
ICMP 设计于互联网早期(1981 年),当时假设网络里都是可信节点。这个信任假设后来催生了多类攻击。
图 11 · Smurf 放大攻击与防护
| 攻击 / 风险 | 原理 | 现状与防护 |
| Smurf 攻击 | 伪造源地址 + 广播 Echo,放大数十至数百倍 | 关闭定向广播 + 入口过滤,已基本绝迹 |
| Ping of Death | 发送超长 ICMP 包(分片重组后 > 65535 字节),老系统缓冲区溢出崩溃 | 1990s 的老洞,现代系统已修复 |
| ICMP Flood | 海量 Echo Request 耗尽带宽 / CPU | 限速(rate-limit)、云端清洗 |
| 信息泄露 | 响应 ICMP 暴露主机存活、拓扑、操作系统指纹 | 边界禁 ping(但见下方警告) |
| ICMP 隧道 | 把数据藏在 ICMP 数据区绕过防火墙外传 | 检测异常 ICMP 频率与载荷大小 |
禁 ping 的代价(运维最容易踩的坑):如果无差别丢弃所有 ICMP,会连带丢掉 Type 3 Code 4(需要分片),导致 PMTU 黑洞 —— 表现为「小包能通、大包卡死」,网页打不开、SSH 能连但传文件就断。正确做法:只禁 Type 8(Echo Request),放行 Type 3 Code 4 与 Type 11。
⑫常见误区与一句话速记
五个高频误区
误区一:ICMP 是传输层协议
错。它
被 IP 承载这一点像传输层,但功能上是
网络层、IP 的辅助协议,且
没有端口、不建连接。判断依据看职责而非封装位置。
误区二:ping 通 = 服务可用
错。ping 通只证明
三层可达。服务是否可用取决于
四层端口与七层应用,必须另测(
nc -zv host 80 或 curl)。
误区三:ping 不通 = 网络断了
错。可能是对方
禁了 ICMP(云主机默认安全组常见),业务照样正常。也可能是中间设备丢 ICMP 但放行 TCP。
误区四:ICMP 会重传丢失的包
错。ICMP
只报告,不修复。它把「包丢了」这件事告诉源主机,重传是 TCP 或应用自己的事;UDP 应用收到 ICMP 错误后想不想重传也由自己决定。
误区五:IPv6 里也能照旧禁 ICMP
大错。IPv6 的
地址解析(NS/NA)、路由发现(RS/RA)、PMTU 发现全靠 ICMPv6,禁了等于
自断网络。只能精细放行必要类型。
一句话速记
ICMP = IP 的报警与查询系统:网络层、协议号 1、无端口、不传数据;
两类报文——差错报告(3 不可达 / 11 超时 / 5 重定向 / 12 参数错)单向回报,查询(8/0 Echo)一问一答;
差错报文夹带「原始 IP 头 + 前 8 字节」,好让源主机定位到具体 socket;
三大应用——ping 测通断、traceroute 探路径、PMTUD 调 MSS;
五不发斩断风暴;IPv6 里它是基础设施,禁不得。