《TCP/IP 详解 卷1:协议》第 8 章:Internet 控制报文协议
路由器是 Internet 的重要组成部分,严密监视 Internet 的操作。IP 协议未给发送失败的 IP 数据包提供一种错误处理,也没有给端系统提供直接的方法来发现错误。为了解决这一不足之处,ICMP(Internet Control Message Protocol,Internet 控制报文协议) 被设计出来,与 IP 结合使用。当路由器处理一个数据包的过程中发生了意外,就是通过 ICMP(向发送数据包的源端来报告相关事件的。ICMP 封装在 IP 数据包中,提供 IP 层配置和 IP 数据包相关的诊断、控制信息。
ICMP 报文通常是由 IP 层本身、上层传输协议、某些用户进程触发的。ICMP 负责传递的是可能需要被注意的差错和控制报文、查询、信息类报文。要注意的是,ICMP 没有为 IP 网络提供可靠性。最常见的丢包(路由器缓冲区溢出)并不会触发任何的 ICMP 信息。为网络提供可靠性的问题是由 TCP 来处理的。
ICMP 术语指一般的 ICMP,用 ICMPv4 和 ICMPv6 代表专门用于 IPv4 和 IPv6 的版本。
鉴于 ICMP 报文能够影响重要的系统功能操作和获取配置信息,黑客们在大量的攻击中专门利用了 ICMP 报文。因此网络管理员常常配置防火墙封阻 ICMP 报文,尤其是在边界路由器上。
格式
ICMP 报文被封装在 IP 数据报内。
- IPv4 中协议(Protocol)字段的值为
1
表示该报文携带 ICMPv4. - IPv6 的 ICMPv6 头部之前一个扩展头部的下一个头部(Next Header)字段的值为
58
ICMP 报文格式、 ICMP 报文数据内容如下图所示:
字段 | 长度(bits) | 内容 | 含义 or 注释 |
---|---|---|---|
类型(Type) | 8 | ICMPv4 中保留了 42 个不同的值,约有 8 个常用 | 用于确定特定类型的报文 |
代码(Code) | 8 | 略 | 进一步制定报文的含义 |
检验和(Checksum) | 16 | 略 | 覆盖整个 ICMP 报文的校验和计算 |
有效内容(Content) | 可变 | 略 | 略 |
ICMP 校验和采用的算法和用在 IPv4 中的算法相同。与 IPv4 有区别的是,ICMP 是一个端到端检验和的例子,检验和从发送发发出的 ICMP 报文一直被携带到最终的接收方。而 IPv4 的头部校验和在经过每一跳路由器由于 TTL 值的改变,每一跳都要重新计算。ICMP 的校验和如果不正确,则会被接收方丢弃,因为报文内容不正确可能导致错误的系统行为。
类型
一般来说,ICMP 报文分为两大类:
- 差错报文(Error Message),主要是有关 IP 数据包传递的。
- 查询(query)、信息类报文(informational Message),有关信息采集和配置。
常用的 ICMP 报文消息类型:
消息类型 | 描述 |
---|---|
目的地不可达 | 数据包无法传递 |
超时 | TTL 字段减到了 0 |
参数问题 | 无效 header |
源抑制 | 抑制包,表示拥塞,弃用 |
重定向 | 告知路由器有关信息 |
回显及回显应答(ping) | 检查一台机器是否存活 |
请求应答时间戳 | 与 ping 一样的功能,且要求加时间戳 |
路由器通告/请求 | 发现附近的路由器 |
详细的类型号如下,更详细的代码不在此处贴出。
处理 ICMP 报文
对传入的 ICMP 报文的处理方式随着系统的不同而不同。一般而言:
- 传入的信息类请求被操作系统处理。
- 传入的差错类报文传递给用户进程或者传输层协议。
- 也有例外情况,如重定向报文就是导致路由表的更新,等等。
ICMPv6 的处理更为严格:
- 未知的 ICMPv6 差错报文必须传递给上层产生差错报文的进程。
- 未知的 ICMPv6 信息类报文会被丢弃。
- 差错报文要求尽可能多的包含原始“出错” IPv6 报文。处理错误时,提取原始“违规”数据包中的上层协议类型,使用适当的上层进程。
- IPv6 节点必须限制其发送 ICMPv6 报文的速率等。
差错报文
上面提到的两大类 ICMP 报文,差错报文和信息类报文,它们之间的区别非常重要。先来讲差错报文。
ICMP 差错报文不会对以下报文进行响应;
- 另一个 ICMP 差错报文。(如果没有这一条限制,处理某条差错报文时又可以产出另一个差错报文的话,将有可能导致死循环)
- 链路层广播数据报。
- 不是第一个分片的其他分片。
- 源地址不是单个主机地址的数据报。(零地址、环回地址、广播组播地址)
ICMP 的 Content 中包含原来那个“违规”的“原始”数据报的头部副本,且包含一些有效载荷区的有效数据,但要确保总长度小于 MTU。在以前,ICMP 规范仅要求包含违规 IP 数据报的头 8 个字节(因为这样足以确定 TCP or UDP)的端口号,但随着现在协议越来越复杂,需要更多的信息来诊断问题。
发送速率的限制
除了上述控制 ICMP 报文产生的条件,还要限制单一发送者发出的 ICMP 总体流量水平。[RFC4443] 推荐的方法是令牌桶。每个桶保存了最大数量为 B 的令牌,每个令牌允许一定数量的报文被发送。桶定期以速率 N 填充新的令牌,每发送一个报文 N 就自减 1。所以,令牌桶可以用参数(B, N) 刻画。
查询/信息类报文
很多 ICMP 定义的一些查询报文的功能都被其他的特殊协议取代。例如地址、掩码请求/应答(类型17/18)、时间戳请求/应答(类型13/14)等等,被一些例如 DHCP 等特殊协议取代了。现在保留下来唯一一个广泛使用的 ICMP 查询/信息类报文是回显请求/应答类报文,就是我们熟知的ping。
还有一个就是路由器发现报文,尽管 IPv4 中未广泛使用路由器发现机制,而在 IPv6 中非常基本的邻居发现中被普遍采用。
几种常见的 ICMP 消息
回显请求/应答类报文 ping
ICMPv4 类型 0/8(请求/应答),ICMPv6 类型 129/128(请求/应答)。
ping = packet Internet Groper,是直接使用网络层 ICMP 的重要例子,没有经过 TCP or UDP 这样的传输层协议。
接收到 ICMP 回显请求报文后,ICMP 的实现就是要求将任何收到的数据返回给发送者。这种报文是通过 ping 程序发送的,ping 的功能被用于确定 Internet 上一台主机是否可达的。一般来说,如果能“ping通”一台主机,那么几乎可以确定能够通过其他的方法(登录、其他服务等)访问到它。
请求和应答是一一对应的,所以 ICPM ping 消息就包含了两个额外的字段:标识符(Identifier)和序列号(Sequence Number)
- 标识符存放例如进程 ID 这样的内容,如果有多个 ping 程序在同一台主机运行,就能正确区分应答。
- 序列号就是从 0 开始,每多一次 ping 就加一。方便查看是否丢包、重排、遗失。
目的不可达 Destination Unreachable (主机/端口不可达、禁止通行、目的无路由等)
ICMPv4 类型 3,ICMPv6 类型 1。
目的不可达,是一种比较常见的 ICMP 报文类型,直观地表示数据报无法送达目的地。ICMPv4 还为此类型定义了 16 个代码,表示更详细的内容,但只有 4 个比较常用,分别是:
- 主机不可达,code = 1
- 端口不可达,code = 3
- 需要分片,code = 4
- 管理禁止通信,code = 13
主机不可达是由路由器或主机产生的,出现情况是在使用直接交付发送一个 IP 数据报到一个主机时,由于某些原因无法到达目的地。例如试图发送 ARP 请求到不存在或关闭的主机。
目的无路由就是数据报要路由时却没有任何一条合适的路由条目来指定下一跳。
管理禁止通信通常是因为防火墙导致的故意丢弃流量。
端口不可达就是目标应用程序还没准备好接受它时,就会产生一个端口不可达报文,在使用 UDP 时常见。还有就是一个报文发往了一个没有被任何服务器进程所使用的端口号时,UDP 也会回应一个 ICMP 端口不可达报文。
下图是一个 ICMPv4 目的不可达-端口不可达 消息的例子。红框里违规数据报头部的 IP 协议字段为 17 指 UDP。如前所述,ICMP 差错报文包含违规数据包的头部、有效载荷,有助于解析后面的字节,学习到源和目的端口号,将差错与特定进程相关联。
Packet Too Big(PTB),ICMPv6 中,由一个Packet Too Big(PTB)替代了 ICMPv4 中 type = 3,code = 4 的消息。就是所谓的“数据报太大(需要分片)”。如果一个路由器收到一个打算转发的数据报,而数据报的大小大于传出网络接口的 MTU 则该数据报需要分片。若“Don't Fragment”字段被设置,则会被丢弃。此时产生 ICMP 目的不可达 PTB 报文,而且携带 MUT 值在差错报文中,以便让原来的发送方路由器知道下一跳的 MTU。
此报文本来是设计用来诊断网络的,但被用于路径 MTU 发现:当进行通信时为了避免分片,PTB 消息用于确定合适的包大小,通常与 TCP 一起使用。
超时 Time Exceed
ICMPv4 类型 11,ICMPv6 类型 3。
IPv4 头部有 TTL 字段来限制数据报在网络中存留的时间。当由于报文是因为 TTL 减至 0 被丢弃时,触发一个 ICMP 超时。这个错误信息被巧妙地运用在了 Traceroute 工具上。该工具由 Van Jacobson 在 1987 年开发,用于发现从主机到目的地址路径上的 IP 地址。方法其实很简单:给目的地址发送一系列 TTL 设置为 1,2,3 …… 的数据包,依次类推。根据这一系列带有特殊 TTL 值而导致路由器触发的 ICMP 超时消息,就可以确定沿途的路由器 IP 地址。
这不是 ICMP 超时消息设计的本意,却被设计成了最有用的网络调试工具。
重定向 Redirect
ICMPv4 类型 5,ICMPv6 类型 137。
一个路由器收到一个数据报,但确定自身并不是该数据报应该被投递到的合适下一跳。则该路由器发送一个重定向报文给原来的主机,并把该报文发送到正确的下一跳路由器(或主机)。即:如果路由器在接受到数据报时,确定存在一个比自己更好的下一跳,则会触发 ICMP 重定向消息,使原来的发送方更新其转发表。
不过,路由器主要还是通过动态路由协议来获得可达目的地的最佳下一跳节点。
)
Wireshark 抓包
- ping request
- ping reply
- port unreachable