ICMP 协议完全图解

IP 协议的“报警与查询系统”——不传数据,只传“出了什么事”

网络层协议 IP 协议号 = 1 无端口概念 差错报告 + 查询 ping / traceroute / PMTUD

①一句话:ICMP 是什么

ICMP(Internet Control Message Protocol,网际控制报文协议)是 TCP/IP 协议族的网络层协议,用来在主机与路由器之间传递控制信息与差错报告。它不承载用户数据,唯一职责是:当 IP 数据报出问题或需要探询时,给发送方一个回话。

为什么非要它不可——因为 IP 是“哑巴”

IP 协议的设计哲学是尽力而为(best effort):它只管把包往链路上扔,丢了就丢了,不确认、不重传、不通知。这就带来三个盲区:

盲区一:包丢了没人说

发送方不知道包是到了还是丢了,更不知道丢在哪一跳。

盲区二:出错没人解释

路由器丢包可能是没路由、TTL 归零、MTU 太小、端口没进程……原因不同,处置完全不同。

盲区三:路径不可知

无法知道包走了哪条路、经过多少跳、哪一段慢。

ICMP 就是补这三个盲区的:报差错、答查询、探路径。它运行在 IP 之上、服务于 IP,是IP 协议不可分割的配套件——RFC 792 把它定义为“IP 的组成部分,任何实现 IP 的模块都必须实现 ICMP”。

没有 ICMP vs 有 ICMP 只有 IP:单向哑传输 发送方 路由器 包丢了 ✕ 发送方:??? 一直重传 有 ICMP:出错会回话 发送方 路由器 ICMP 差错报文回送 发送方:知道原因,正确处置
图 1 · ICMP 补上了 IP「只发不回」的短板
关键认知:ICMP 不传输用户数据,也不负责可靠性(不重传、不排序、不流控)。它只是报告——至于收到报告后要不要重传、怎么重试,那是 TCP 或应用程序自己的事。

②它在协议栈的哪个位置

这是最容易答错的一问。ICMP 报文被 IP 数据报封装(IP 头部的「协议号」字段填 1),看上去像被 IP 承载、和 TCP/UDP 平级,但从功能定位上它是网络层协议,是 IP 的辅助协议,不是传输层。

ICMP 在 TCP/IP 模型中的位置与封装关系 应用层 ping / traceroute 传输层 TCP / UDP ICMP ← 网络层(IP 的辅助) IP(网络层)· 协议号字段:1 = ICMP,6 = TCP,17 = UDP 数据链路层(以太网 / Wi-Fi) 注:ICMP 与 TCP/UDP 同被 IP 承载,但 ICMP 无端口、 无连接、不传数据 封装顺序:以太帧头 → IP 头 → ICMP 报文(ICMP 无 TCP/UDP 头这一层)
图 2 · ICMP 是网络层里「IP 的助手」,不是传输层

封装结构(一图看清谁包着谁)

以太网帧头(源 MAC / 目的 MAC / 类型 0x0800) IP 头部(20 字节)· 协议号 Protocol = 1 ICMP 报文:8 字节固定头 + 数据部分 类型(8b) · 代码(8b) · 校验和(16b) · 可变字段(32b) · 数据(Echo 为标识符+序号+填充;差错为原始 IP 头+前 8 字节) 以太网帧尾(FCS 校验)
图 3 · ICMP 报文封装位置:直接躺在 IP 数据区里,没有 TCP/UDP 头
面试高频陷阱:“ping 一下 80 端口通不通”这句话是错的。ICMP 没有端口概念,ping 通只能说明三层可达,与 80/443 端口开不开没有直接关系。要测端口得用 telnet / nc / tcpping(走 TCP)。反过来,禁 ping 的服务器端口照样开着。

③ICMP 报文格式:8 字节定长头

所有 ICMP 报文的前 4 个字节格式统一(类型、代码、校验和),第 5~8 字节随类型变化,后面跟数据部分。

ICMP 报文通用格式(单位:bit) 类型 Type(8 bit) 大分类:0 回显应答 / 8 回显请求 / 3 不可达 / 11 超时 代码 Code(8 bit) 细分原因:3 之下的 0~15 种不可达 校验和 Checksum(16 bit) 覆盖整个 ICMP 报文(头 + 数据),16 位反码求和再取反;与 IP 头校验和算法相同但范围不同 可变字段(32 bit)—— 内容由类型决定 Echo:标识符(16b) + 序号(16b) | 差错:全 0 未使用(历史原因) | PMTU:下一跳 MTU 数据部分(长度可变):Echo 为时间戳+填充字节;差错为「原始 IP 头 + 原始数据前 8 字节」
图 4 · ICMP 报文格式:前 4 字节固定,第 5~8 字节「看类型下菜」

点开每个字段看说明

类型8 bit
代码8 bit
校验和16 bit
可变字段32 bit
数据部分可变
👆 点击上方任意字段,查看它的含义与作用。

以 ping(Echo)报文为例,标识符与序号的妙用

Echo Request / Reply 报文(Type 8 / Type 0) Type 8 或 0 Code 0 Checksum 反码和 标识符 Identifier 通常 = 进程 PID 序号 Sequence 从 0 递增 数据:发送时间戳(8 字节)+ 填充字节(通常 48 字节) 总长度 64 字节 = 8(头)+ 56(数据),这就是 ping 默认的 64 bytes 标识符区分「哪个进程发的 ping」,序号区分「第几个包」→ 配对收发、统计丢包与乱序
图 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
两类报文的交互模式对比 差错报告:单向报告 主机 A 路由器 数据包 Type 3 不可达 A 知道原因,自行处理 (不回应差错报文) 查询:一问一答 主机 A 主机 B Type 8 请求 Type 0 应答 A 用标识符+序号配对 算出 RTT,识别丢包 区分窍门:成对出现(8/0、13/14)的是查询类;单独出现(3、5、11、12)的是差错类
图 6 · 差错类单向报告,查询类一问一答

⑤为什么差错报文要“夹带”原始报文

这是 ICMP 设计里最精妙的一处。差错报文的数据部分不是随便填的,而是固定携带出错数据报的 IP 头 + 其数据区的前 8 字节,总共 28 字节。

差错报文的数据区 = 原始出错 IP 头(20B)+ 原始数据前 8 字节 ICMP 前 8 字节:Type 3 · Code 3 · Checksum · 未用(全 0) 原始 IP 头(20 字节):源 IP、目的 IP、协议号 原始数据前 8 字节:TCP/UDP 的「源端口 + 目的端口 + 序号/长度…」 → 知道是哪个「连接」出的问题 → 交给对应的 socket 处理
图 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 的关键。

⑥类型与代码速查全表

差错报告类

TypeCode含义谁发
30~15目的不可达:0 网络不可达 / 1 主机不可达 / 2 协议不可达 / 3 端口不可达 / 4 需要分片但 DF 置位 / 9 网络被禁 / 10 主机被禁 / 13 被过滤路由器或目标主机
40源抑制(Source Quench)—— 拥塞通知,已被 RFC 6633 弃用路由器(现代已不发)
50~3重定向:0 网络重定向 / 1 主机重定向(告诉你「有更近的路」)同网段路由器
110 / 1超时:0 = TTL 减到 0(traceroute 靠它);1 = 分片重组超时路由器
120~2参数错误:0 IP 头字段错 / 1 缺必需选项 / 2 长度错路由器或主机

查询类

TypeCode含义状态
00Echo Reply(回显应答,ping 的返回)在用
80Echo Request(回显请求,ping 的发出)在用
9 / 100路由器通告 / 请求(Router Advertisement / Solicitation)少用(IPv4)
13 / 140时间戳请求 / 应答少用
15 / 160信息请求 / 应答已废弃
17 / 180地址掩码请求 / 应答已废弃(被 DHCP 取代)
300Traceroute已废弃(被 TTL 递增法取代)
42 / 43—扩展 Echo 请求 / 应答(RFC 8335,可指定用谁的地址回)较新
只需死记 4 组:8 / 0(ping 一问一答)、3(目的不可达,Code 3 端口不可达最常见)、11(TTL 超时,traceroute 的命脉)、3 的 Code 4(需要分片,PMTUD 的命脉)。

⑦五大工作场景:ICMP 到底干了什么

ICMP 的五个典型工作场景 ① ping:Echo 8 → 0,测通断与 RTT Type 8 请求 → Type 0 应答 RTT = t2 − t1 结果:网络是否可达、延迟多少、丢包率多少 ② 目的不可达:Type 3,Code 细分原因 UDP 到无进程端口 → Type 3 / Code 3 端口不可达 价值:立刻知道「主机在,但那个服务没开」,不用傻等超时 ③ traceroute:TTL 从 1 递增,靠 Type 11 套出每一跳 TTL=1 第1跳 TTL=2 第2跳 TTL=3 …直到目的 每跳路由器把 TTL 减到 0 就丢包并回 Type 11,源主机凭此记下该跳 IP 与耗时 ④ 重定向:Type 5,路由器说「你走错了,下次直接找它」 主机发给 R1 → R1 回 Type 5 → 改走 R2 效果:主机路由表被动态优化,少绕一跳(现代网络出于安全常禁用) ⑤ PMTU 发现:Type 3 / Code 4,包太大又不许分片 1500B,DF=1 → 回 Code 4 + 下一跳 MTU 价值:源主机据此调小 MSS,避免分片;若此报文被防火墙拦 → PMTU 黑洞
图 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 差错报文:

ICMP 差错报文的「五不发」 ① ICMP 差错报文本身出错 → 不再发 ICMP 差错(斩断无限循环) ② 目的地是广播 / 多播地址的数据报 → 不发(否则全网一起回,放大攻击) ③ 链路层广播的数据报 → 不发 ④ 不是第一个分片的分片 → 不发(只有首片带端口信息,才有报告价值) ⑤ 源地址不唯一(0.0.0.0、环回、广播、多播)→ 不发(不知道该回给谁)
图 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,携带下一跳 MTUType 3 Code 4(且 IPv6 禁止中间路由器分片,PMTUD 成刚需)
3 超时跳数限制(Hop Limit)归零 / 重组超时Type 11
128 / 129Echo 请求 / 应答(ping6)Type 8 / 0
133 / 134路由器请求 RS / 路由器通告 RA路由器发现 + 部分 DHCP
135 / 136邻居请求 NS / 邻居通告 NA取代 ARP(地址解析 + 重复地址检测 DAD)
137 重定向更优下一跳Type 5
IPv4 用 ARP 解析 MAC,IPv6 用 ICMPv6 的 NS/NA IPv4:ARP(独立协议) 主机 A 全网广播 ARP Request 广播问「谁的 IP 是 X」 IPv6:ICMPv6 NS/NA 主机 A 主机 B NS(Type 135) NA(Type 136) 组播询问 + 单播应答 后果:IPv6 里禁掉 ICMPv6 = 断网(拿不到 MAC、发现不了 MTU、收不到路由通告)
图 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 requestType 8 / Code 0ping 发出
echo replyType 0 / Code 0ping 返回
udp port X unreachableType 3 / Code 3端口无进程监听
host X unreachableType 3 / Code 1主机不可达(ARP 失败 / 无路由)
time exceeded in-transitType 11 / Code 0TTL 归零(traceroute 的回包)
redirectType 5路由重定向
frag needed and DF setType 3 / Code 4需要分片但 DF 置位(带 MTU)
Wireshark 过滤小技巧:icmp 看全部;icmp.type == 8 只看请求;icmp.type == 3 && icmp.code == 3 只看端口不可达;icmp.type == 11 只看 TTL 超时。

⑪安全风险:ICMP 被怎么用坏

ICMP 设计于互联网早期(1981 年),当时假设网络里都是可信节点。这个信任假设后来催生了多类攻击。

Smurf 攻击:把源地址伪造成受害者,向广播地址发 Echo 攻击者 伪造源 = 受害者 IP 广播地址 一个请求 → N 台主机 受害者 被 N 倍流量淹没 Echo Request N 份 Echo Reply 放大倍数 = 网络内主机数(可达数百倍) 防护:路由器关闭「IP 定向广播」(no ip directed-broadcast) 主机不响应发往广播地址的 ICMP;入口过滤(BCP 38)阻断伪造源地址
图 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 里它是基础设施,禁不得。