ICMP 协议的格式
ICMP全称Internet Control Message Protocol, 互联网控制报文协议。
ICMP报文是封装在IP报文里面的。
ICMP属于网络层(IP)协议. 发送不涉及到传输层,没有端口的概念。ping 是基于 ICMP 协议工作的。
ICMP包有一个8字节长的包头, 其中前4个字节是固定的格式:
-
包含8位类型字段
-
8位代码字段
-
16位的校验和
-
后4个字节根据ICMP包的类型而取不同的值
ICMP报文有很多类型, 常用的:
-
主动请求为8
-
主动请求的应答为0
查询报文类型
ping就是查询报文, 是一种主动请求, 并且获得主动应答的ICMP协议。
ping发的包也是符合ICMP协议格式的, 只不过它在后面增加了自己的格式。
ping的主动请求, 网络抓包, 称为ICMP ECHO REQUEST。主动请求的回复, 称为ICMP ECHO REPLY。
与原生的ICMP相比多了个两个字段:(见上图)
- 标识符(用作区分)
- 序号(比如派出去10个, 回来10, 就说明前方不错. 如果派出去10个, 回来2个, 说明情况不妙)
- 选项数据中: 还会发送请求的时间值
差错报文类型
异常情况发起的, 来报告发生了不好的事情.** ICMP的差错报文类型**
除了前面还是IP, ICMP的前8字节不变, 后面则跟上出错的那个IP包的IP头和IP正文的前8个字节,参看图片ICMP 协议格式
常见类型:
- 3 终点不可达
- 4 源抑制
- 11 超时
- 5 重定向
终点不可达 3
具体不可达原因代码:
-
0: 网络不可达: 找不到地方
-
1: 主机不可达: 找到地方没这个人
-
2: 协议不可达: 找到地方, 找到人, 口号没对上
-
3: 端口不可达:找到地方, 找到人, 口号对上, 事情没对上.
-
4: 需要进行分片, 但设置了不分片位:走到一半, 山路狭窄, 想换小车, 但是禁止换小车, 没法送到了.
源站抑制 4
让源站放慢发送速度。
时间超时 11
超过网络包的生存时间还是没到。
路由重定向 5
让下次发给另一个路由器,不需要绕路。
ping: 查询报文类的使用
-
主机A的IP地址是192.168.1.1
-
主机B的IP地址是192.168.1.2
-
在主机A上运行ping 192.168.1.2
-
源主机构建一个ICMP请求数据包
-
ICMP数据包内包含多个字段:
-
类型字段, 这里为8
-
顺序号, 用于区分连续ping的时候发出的多个数据包. 每发出一个请求数据包, 顺序号就会自动加1. 为了能够计算往返时间RTT, 它会在报文的数据部分插入发送时间.
-
-
ICMP协议将这个数据包连同地址192.168.1.2一起交给IP层. IP层将以如下信息构建一个IP数据包
-
192.168.1.2作为目的地址
-
本机IP地址作为源地址
-
加上一些其他控制信息
-
-
接着,需要加入MAC头
-
如果在本机ARP映射表中查找出IP地址192.168.1.2所对应的MAC地址, 则可以直接使用.
-
如果没有, 需要发送ARP协议查询MAC地址
-
-
获得MAC地址后, 由数据链路层构建一个数据帧, 依据以太网的介质访问规则, 将它们传送出去.
-
目的地址是IP层传过来的MAC地址
-
源地址是本机的MAC地址
-
附加一些控制信息
-
-
-
主机B收到这个数据帧
- 先检查它的目的 MAC 地址,并和本机的 MAC 地址对比,如符合,则接收,否则就丢弃。
- 接收后检查该数据帧,将 IP 数据包从帧中提取出来,交给本机的 IP 层。
- IP 层检查后,将有用的信息提取后交给 ICMP 协议。
- 主机 B 会构建一个 ICMP 应答包,应答数据包的类型字段为 0,顺序号为接收到的请求数据包中的顺序号,然后再发送出去给主机 A。
在规定的时候间内,源主机A如果没有接到 ICMP 的应答包,则说明目标主机不可达;如果接收到了 ICMP 应答包,则说明目标主机可达。此时,源主机A会检查,用当前时刻减去该数据包最初从源主机上发出的时刻,就是 ICMP 数据包的时间延迟。
这只是最简单的,同一个局域网里面的情况。如果跨网段的话,还会涉及网关的转发、路由器的转发等等。但是对于 ICMP 的头来讲,是没什么影响的。
Traceroute:差错报文类型的使用
程序 Traceroute,是个“大骗子”。它会使用 ICMP 的规则,故意制造一些能够产生错误的场景。
Traceroute 的故意设置特殊的 TTL,来追踪去往目的地时沿途经过的路由器。
Traceroute 的参数指向某个目的 IP 地址,它会发送一个 UDP 的数据包。将 TTL 设置成 1,也就是说一旦遇到一个路由器或者一个关卡,就表示它“牺牲”了。接下来,将 TTL 设置为 2。第一关过了,第二关就“牺牲”了,那我就知道第二关有多远。如此反复,直到到达目的主机。这样,Traceroute 就拿到了所有的路由器 IP。
Traceroute 程序会选择一个不可能的值作为 UDP 端口号(大于 30000)发送一份 UDP 数据报给目的主机,当该数据报到达时,将使目的主机的 UDP 模块产生一份“端口不可达”错误 ICMP 报文。如果数据报没有到达,则可能是超时。UDP 是无连接的,如果不让目的主机返回一份 ICMP 报文,我们压根不知道数据报中间发生了什么。
Traceroute 还有一个作用是故意设置不分片,从而确定路径的 MTU。如果中间遇到窄的关口会被卡住,会发送 ICMP 网络差错包,类型为“需要进行分片但设置了不分片位”。每次收到 ICMP“不能分片”差错时就减小分组的长度,直到到达目标主机。
参考资料:
趣谈网络协议(极客时间)链接:
http://gk.link/a/106nW
GitHub链接:
https://github.com/lichangke/LeetCode
知乎个人首页:
https://www.zhihu.com/people/lichangke/
CSDN首页:
https://me.csdn.net/leacock1991
欢迎大家来一起交流学习