互联网控制消息协议

互联网控制消息协议（，缩写：）是互联网协议族的核心协议之一。它用于网际协议（IP）中发送控制消息，提供可能发生在通信环境中的各种问题反馈。通过这些信息，使管理者可以对所发生的问题作出诊断，然后采取适当的措施解决。

ICMP 依靠IP來完成它的任务，它是IP的主要部分。它与传输协议（如TCP和UDP）显著不同：它一般不用于在两点间传输数据。它通常不由网络程序直接使用，除了 ping 和 traceroute 这两个特別的例子。
IPv4中的ICMP被称作ICMPv4，IPv6中的ICMP则被称作ICMPv6。

技術細節
ICMP是在 RFC 792 中定义的互联网协议族之一。通常用于返回的错误信息或是分析路由。ICMP错误消息总是包括了源数据并返回给发送者。
ICMP错误消息的例子之一是TTL值过期。每个路由器在转发数据报的时候都会把IP包头中的TTL值减1。如果TTL值为0，“TTL在传输中过期”的消息将会回报给源地址。
每个ICMP消息都是直接封裝在一个IP数据包中的，因此，和UDP一样，ICMP是不可靠的。

虽然ICMP是包含在IP数据包中的，但是对ICMP消息通常会特殊处理，會和一般IP數據包的處理不同，而不是作為IP的一個子協議來處理。在很多時候，需要去查看ICMP消息的內容，然後發送適當的錯誤消息到那個原來產生IP數據包的程序，即那個導致ICMP訊息被傳送的IP數據包。

很多常用的工具是基於ICMP消息的。traceroute 是通過發送包含有特殊的TTL的包，然後接收ICMP超時消息和目標不可達消息來實現的。 ping 則是用ICMP的"Echo request"（类别代码：8）和"Echo reply"（类别代码：0）消息來實現的。

ICMP报文結構

報頭 
ICMP報頭從IP報頭的第160位開始（IP首部20字节）（除非使用了IP報頭的可選部分）。

 Type - ICMP的類型,标识生成的错误报文；
 Code - 進一步劃分ICMP的類型,该字段用来查找产生错误的原因.；例如，ICMP的目標不可達類型可以把這個位設為1至15等來表示不同的意思。
 Checksum - Internet校驗和（RFC 1071），用於進行錯誤檢查，該校驗和是從ICMP頭和以該字段替換為0的數據計算得出的。
 Rest of Header - 報頭的其餘部分，四字節字段，內容根據ICMP類型和代碼而有所不同。

填充數據 
填充的數據緊接在ICMP報頭的後面（以8位為一組）：
 Linux的"ping"工具填充的ICMP除了8個8位元組的報頭以外，默认情况下還另外填充數據使得總大小為64字節。
 Windows的"ping.exe"填充的ICMP除了8個8位元組的報頭以外，默认情况下還另外填充數據使得總大小為40字節。

报文类型

源站抑制
源站抑制报文旨在请求发送方降低发往路由器或主机的报文发送速率。在接收的过程中，当接收方没有足够的接收缓冲区来处理接收到的报文，或者接收这个报文会导致临近其本身的缓冲区限制时，就会触发源站抑制报文。

数据被从一个或一群主机高速地发往网络上的一个路由器，虽然路由器有缓冲机制，但是路由器的缓冲区大小通常（由于物理内存有限的原因）被限制。因此，如果路由器的通信量过大，路由器最终会（由于内存耗尽，导致必须丢弃掉接收到的数据报）无法继续处理超过输入缓冲区限制的部分数据，直到路由器缓冲队列有空余空间可以存放新的数据报。但是由于网络层（Network Layer）缺乏確認訊息（ACK）机制，因此客户端无法获知数据是否成功抵达接收方。所以研究者提出了源站抑制这一补救措施来解决这一问题：当路由器发现流入数据速率远远高于流出数据速率时，会发送ICMP源站抑制报文给源站，通知源站应该降低其数据传输速度或等待一定时间后再尝试发送更多数据。当源站接收到ICMP源站抑制报文时会减慢数据发送的速度，或者在再次尝试发送数据前等待一定的时间，使得路由器能够（在处理完当前接收到的数据之后）清空输入缓冲队列。

但是因为有研究表明“源站抑制是一种无效的（不公平的）补救措施“，所以路由的源站抑制报文已在1995年被RFC 1812 弃用。此外，（路由）转发和回应任何形式的源站抑制报文已在2012年被RFC 6633 弃用

其中:
类型（Type） 必须设置为4
代码（Code） 必须设置为0
IP数据报头部 和其附加的数据用于发送端根据回应报文匹配对应的请求报文

重定向

重定向 报文是网关发出的，用于要求主机或路由器改变数据报的传输路径的ICMP报文。ICMP 重定向是路由器将路由信息传达给主机的机制。这种类型的报文通知主机更新它的路由信息（请求主机改变其路由）。如果一个主机在通信时将数据报发送给了路由器R1，而R1将这个数据报转发给了另一个路由器R2，且主机到路由器R2之间有一条直连的路径（也就是说，此主机和路由器R2处于同一以太网段上），那么路由器R1会发送一条重定向报文给主机，来通知它到路由器R2可用路径里有一条更短、更优化的路径。这个主机在接收到这个重定向报文之后应该改变其路由至这个优化版本的路由信息，来将抵达这个目的地的数据报直接发送到路由器R2，并且路由器仍将原始数据报发送到预期目的地。但是，如果一个数据报携带有路由信息，那么即使有更加优化的路径，路由器也不会发送重定向报文。并且，RFC 1122 指出，重定向报文应该只由网关发送，而不应该由互联网主机发送。

其中:
类型（Type） 必须设置为 5.
代码（Code） 指定重定向的原因，见下表
{|class="wikitable"
|-
! 代码（Code）
! 描述
|-
! 0
| 针对网络的重定向报文
|-
! 1
| 针对主机的重定向报文
|-
! 2
| 针对网络和服务类型的重定向报文
|-
! 3
| 针对主机和服务类型的重定向报文
|}
路由器的IP 地址（IP address） 是一个32位的网关IP地址，该地址指明了该数据报应该被重定向到的路由器地址。
激发重定向报文的数据报IP首部及其数据的前8字节（IP header） 用于收到重定向报文的主机根据回应报文匹配对应的请求报文，来确定该数据报的目的站地址。

超时
超时 报文是网关产生并发送给源站的ICMP报文，用于通知源站有数据报因为存活時間递减至0而被此网关丢弃。当主机等待数据报分片的过程中超时而无法重新组装数据报分片时也会产生该报文。

超时报文也用于traceroute工具来识别两个主机之间的路径上的网关。

其中:
类型（Type） 必须设置为 11
代码（Code） 指定重超时的原因，见下表
{| class="wikitable"
! Code || Description
|-
! 0
| 存活時間计数超时
|-
! 1
| 分片重装超时
|}
激发超时报文的数据报IP首部及其数据的前8字节 这些信息用于源站根据收到的超时报文来确定具体哪个数据报已被丢弃。对于高层协议，比如用户数据报协议 和 传输控制协议而言，额外的8字节数据指明了已被丢弃的数据报中的源端口与目的端口。

时间戳请求
时间戳请求 报文主要用于互联网机器（包括路由器和主机）之间同步时钟。起始时间戳是发送端最后一次改动该数据报的时间戳(为世界标准时午夜开始计算的毫秒数)。在该类型的报文中，接收时间戳和传输时间戳未被使用。

其中:
类型（Type） 必须设置为 13
代码（Code） 必须设置为 0
标识符（Identifier） and 序号（Sequence） 用于在时间戳请求报文和时间戳回答报文之间建立关联
起始时间戳（Originate timestamp） 为世界标准时午夜开始计算的毫秒数。 如果没有可用的世界标准时参考，则可以将最高有效位设置为1以指示这是一个非标准时间值。

时间戳回答
时间戳回答 报文是对时间戳请求报文的回答报文。 时间戳回答报文由接收到的时间戳请求报文其中的起始时间戳和接收时间戳（回应端主机接收到请求报文并创建时间戳回应报文的时间，单位为毫秒）、传输时间戳（时间戳回答报文被发送出去的时间，单位为毫秒）组成。

其中:
类型（Type） 必须设置为 14
代码（Code） 必须设置为 0
标识符（Identifier） 和 序号（Sequence number） 用于在时间戳请求报文和时间戳回答报文之间建立关联。
起始时间戳（Originate timestamp） 是发送端最后一次改动该数据报的时间戳。
接收时间戳（Receive timestamp） 是回应端主机接收到请求报文并创建时间戳回应报文的时间，单位为毫秒。
传输时间戳（Transmit timestamp） 是最后一次修改回应报文并将其发送出去的时间，单位为毫秒。

所有的时间戳都是世界标准时午夜起始的毫秒数。如果这个时间不能表示为毫秒或者没有可用的世界标准时参考值，则可以使用任何格式的时间值并将最高有效位设置为1以指示这是一个非标准时间值。

地址掩码请求
地址掩码请求 报文是主机为了得到一个合适的子网掩码而发送到路由器的ICMP请求报文。

接收到此请求报文的机器应当发送一个地址掩码回答报文给源站。

其中:
类型（Type） 必须设置为 17
代码（Code） 必须设置为 0
地址掩码（Address mask） 可以为0

由于ICMP 地址掩码请求可能会被用于嗅探攻击来收集特定网络的信息，因此该报文默认情况下被Cisco IOS禁用。

地址掩码回答
地址掩码回答 报文携带有地址掩码信息，用于回答地址掩码请求报文。

其中:
类型（Type） 必须设置为 18
代码（Code） 必须设置为 0
地址掩码（Address mask） 为待回答的地址掩码

源站不可达
源站不可达 报文是由主机或入站网关用于通知客户端出于目的站无法连接的报文。这些原因可能包括：物理连接失效（也即网络距离无限大），或指定的地址或端口处于非激活状态，或者数据报长度过长而导致必须分片但是IP首部指定了“不分片”选项导致无法分片。如果是TCP端口不可达，则会返回TCP RST，而不会返回此报文。如果是IP多播的情况，也不会返回此报文。

其中:
类型（Type） 必须设置为 3
代码（Code） 字段用于指示具体导致源站不可达的原因。见下表。
{| class="wikitable"
! 代码（Code） || 解释（Description）
|-
! 0
| 网络不可达
|-
! 1
| 主机不可达
|-
! 2
| 协议不可达
|-
! 3
| 端口不可达
|-
! 4
| 需要分片但是DF(Do not Fragment)置位
|-
! 5
| 源路由失败
|-
! 6
| 目的网络未知
|-
! 7
| 目的主机未知
|-
! 8
| 源主机被隔离
|-
! 9
| 与受到管理禁控的目的网络通信
|-
! 10
| 与受到管理禁控的目的主机通信
|-
! 11
| 对于指明的服务类型，网络不可达
|-
! 12
| 对于指明的服务类型，主机不可达
|-
! 13
| 出于管理目的禁止通信
|-
! 14
| 主机越权.
|-
! 15
| 优先权剥夺生效
|}
Next-hop MTU 当需要分片但是DF(Do not Fragment)置位的错误发生时，包含了下一跳网络的MTU的值。
IP header 用于源站根据收到的源站不可达报文来确定具体哪个数据报引起了源站不可达错误。

參考

外部連結
 RFC 792, Internet Control Message Protocol
 ICMP Sequence Diagram
 RFC 1122, Requirements for Internet Hosts -- Communication Layers
 RFC 1716, Towards Requirements for IP Router
 RFC 1812, Requirements for IP Version 4 Routers
 RFC 6633, Deprecation of ICMP Source Quench Messages
 Filtering ICMP on firewalls
 IANA

網際協議
互聯網標準
網絡層協議