![0117566a9de9444e26dbcdfb183114f5.png](https://i-blog.csdnimg.cn/blog_migrate/f2e8d6ac4c66be6dd8043ccd09fe4d29.jpeg)
序言
架构IP网络时需要特别注意两点:确认网络是否正常工作,以及遇到异常时进行问题诊断。
例如,一个刚刚搭建好的网络,需要验证该网络的设置是否正确。此外,为了确保网络能够按照预期正常工作,一旦遇到什么问题需要立即制止问题的蔓延。为了减轻网络管理员的负担,这些都是必不可少的功能。ICMP正是提供这类功能的一种协议。
ICMP
ICMP的主要功能包括,确认IP包是否成功送达目标地址,通知在发送过程当中IP包被废弃的具体原因,改善网络设置等。
有了这些功能以后,就可以获得网络是否正常、设置是否有误以及设备有何异常等信息,从而便于进行网络上的问题诊断。在IP通信中如果某个IP包因为某种原因未能达到目标地址,那么这个具体的原因将由ICMP负责通知。
如下案例:主机A向主机B发送了数据包,由于某种原因,途中的路由器2未能发现主机B的存在,这时,路由器2就会向主机A发送一个ICMP包,说明发往主机B的包未能成功。
ICMP的这种通知消息会使用IP进行发送。因此,从路由器2返回的ICMP包会按照往常的路由控制先经过路由器1再转发给主机A。收到该ICMP包的主机A则分解ICMP的首部和数据域以后得知具体发生问题的原因。
![b23151a48de3997d12fff3f39c947271.png](https://i-blog.csdnimg.cn/blog_migrate/53ceb7d508a812ae890193b2a0654fed.jpeg)
报文格式
ICMP经常被认为是IP层的一个组成部分。它传递差错报文以及其他需要注意的信息。ICMP报文通常被IP层或更高层协议(TCP或UDP)使用。一些ICMP报文把差错报文返回给用户进。ICMP报文是在IP数据报内部被传输的。
![3c1e7b28237505e02d5ccf75ede8fc2a.png](https://i-blog.csdnimg.cn/blog_migrate/6e6c84b981d88062fcf5e299a86c8927.png)
ICMP报文的格式如下所示。所有报文的前4个字节都是一样的,但是剩下的其他字节则互不相同。下面我们将逐个介绍各种报文格式。类型字段可以有15个不同的值,以描述特定类型的ICMP报文。某些ICMP报文还使用代码字段的值来进一步描述不同的条件。检验和字段覆盖整个ICMP报文。
![f0d3ed267c2b89a11a95334e95f49c1c.png](https://i-blog.csdnimg.cn/blog_migrate/891001f9b269c0c7756677971143356f.png)
ICMP报文类型
ICMP的消息大致可以分为两类:一类是通知出错原因的错误消息,另一类是用于诊断的查询消息。
![1779db56e364bab7159360592a0379a9.png](https://i-blog.csdnimg.cn/blog_migrate/a76e7187343609d7a9dc5365229f808b.jpeg)
主要的ICMP消息
- ICMP目标不可达消息(类型3)
IP路由器无法将IP数据包发送给目标地址时,会给发送端主机返回一个目标不可达(Destination Unreachable Message)的ICMP消息,并在这个消息中显示不可达的具体原因。
![17ca94f129d06c5e9018975ff73e583f.png](https://i-blog.csdnimg.cn/blog_migrate/f00ca05e57ad1dd9db4a54e67efe5a29.jpeg)
在实际通信当中经常会遇到的错误代码是1,表示主机不可达(Host Unreachable),它是指路由表中没有该主机的信息,或者该主机没有连接到网络的意思。
此外,错误代码4(Fragmentation Needed and Don't Fragment was Set)则用于MTU探索。由此,根据ICMP不可达的具体消息,发送端主机也就可以了解此次发送不可达的具体原因。
案例:我们用TFTP来强制生成一个端口不可达报文,然后使用Wireshark抓包来分析:
8888
tftp> get hello.txt
Transfer timed out.
connect命令首先指定要连接的主机名及其端口号,接着用get命令来取文件。敲入get命令后,一份UDP数据报就发送到10.95.55.78上的8888端口。Wireshark抓到的报文结果如下:
![1d4a18bed42975f2a25dfbd33fb2a46f.png](https://i-blog.csdnimg.cn/blog_migrate/3ea108228dadb15b465f16d5087ad27f.jpeg)
![4ffc34a23081f7642d680e3193e4f640.png](https://i-blog.csdnimg.cn/blog_migrate/704131c407bc963652e03e575516eda4.jpeg)
2. ICMP重定向消息(类型5)
如果路由器发现发送端主机使用了次优的路径发送数据,那么它会返回一个ICMP重定向(ICMP Redirect Message)的消息给这个主机。在这个消息中包含了最合适的路由信息和源数据。这主要发生在路由器持有更好的路由信息的情况下。路由器会通过这样的ICMP消息给发送端主机一个更合适的发送路由。
![1a43206cce30ecfc42081fe695931cbe.png](https://i-blog.csdnimg.cn/blog_migrate/8dd10c6234d7bdd068f9a2ae911a8a81.jpeg)
3. ICMP超时消息(类型11)
IP包中有一个字段叫做TTL(Time To Live,生存周期),它的值随着每经过一次路由器就会减1,直到减到0时该IP包会被丢弃。此时,IP路由器将会发送一个ICMP超时的消息(ICMP Time Exceeded Message,错误号0)给发送端主机,并通知该包已被丢弃。
设置IP包生存周期的主要目的,是为了在路由控制遇到问题发生循环状况时,避免IP包无休止地在网络上被转发。此外,有时可以用TTL控制包的到达范围,例如设置一个较小的TTL值。
4. ICMP回送消息(类型0、8)
用于进行通信的主机或路由器之间,判断所发送的数据包是否已经成功到达对端的一种消息。可以向对端主机发送回送请求的消息(ICMP Echo Request Message,类型8),也可以接收对端主机发回来的回送应答消息(ICMP Echo Reply Message,类型0)。网络上最常用的ping命令就是利用这个消息实现的。
案例:我们使用ping命令,然后使用Wireshark抓包分析下:
% ping 10.95.55.78
PING 10.95.55.78 (10.95.55.78): 56 data bytes
64 bytes from 10.95.55.78: icmp_seq=0 ttl=63 time=36.028 ms
64 bytes from 10.95.55.78: icmp_seq=1 ttl=63 time=58.204 ms
64 bytes from 10.95.55.78: icmp_seq=2 ttl=63 time=82.974 ms
64 bytes from 10.95.55.78: icmp_seq=3 ttl=63 time=105.764 ms
64 bytes from 10.95.55.78: icmp_seq=4 ttl=63 time=27.297 ms
Wireshark抓包报文如下所示:
![f9e95644f6b5ec845668c8b693fbbfc5.png](https://i-blog.csdnimg.cn/blog_migrate/7268fc30d420f1809f74f1b3ace15b84.png)
![beb27237938b0ee35fd82d03f7faf4c2.png](https://i-blog.csdnimg.cn/blog_migrate/8fabae68c7fbabdbde7b8465107a24af.jpeg)
6. 时间戳请求消息(13)
我们可以写一个简单程序(取名为icmptime),给某个主机发送ICMP时间戳请求,并打印出返回的应答。
#include
编译完运行:
./icmptime 10.95.45.202
ai_flags = 2
ai_family = 2
ai_socktype = 3
ai_protocol = 1
ai_addrlen = 16
ai_addr.sin_family = 2, sin_port = 0, sin_addr.s_addr = 10.95.45.202
ai_canonname = 10.95.45.202
使用tcmpdump抓包:
# tcpdump -vv -i wlan0 icmp -w /sdcard/capture.pcap
tcpdump: listening on wlan0, link-type EN10MB (Ethernet), capture size 262144 bytes
Got 1
使用Wireshark打开:
![75a491844097d1b1ffc9a83df6e67ee1.png](https://i-blog.csdnimg.cn/blog_migrate/5082263c368b1692a474a3c658b56389.png)
![1182db242185330a367b62c010861f9e.png](https://i-blog.csdnimg.cn/blog_migrate/38fed23995ce015041e8500954e91fed.jpeg)
5. ICMP其他类型消息
还有很多ICMP类型,如下所示:
![69ac7b59416ed4b936f6d149c8350b8b.png](https://i-blog.csdnimg.cn/blog_migrate/0b3987fda2a14f5cfc853e93b42e1e1c.jpeg)
ICMPv6
IPv4中ICMP仅作为一个辅助作用支持IPv4。也就是说,在IPv4时期,即使没有ICMP,仍然可以实现IP通信。然而,在IPv6中,ICMP的作用被扩大,如果没有ICMPv6,IPv6就无法进行正常通信。
尤其在IPv6中,从IP地址定位MAC地址的协议从ARP转为ICMP的邻居探索消息(Neighbor Discovery)。这种邻居探索消息融合了IPv4的ARP、ICMP重定向以及ICMP路由器选择消息等功能于一体,甚至还提供自动设置IP地址的功能。
ICMPv6中将ICMP大致分为两类:一类是错误消息,另一类是信息消息。类型0~127属于错误消息,128~255属于信息消息。
![c155493d5048ba21e2e7ef2ad5f0ee1f.png](https://i-blog.csdnimg.cn/blog_migrate/12622182755804ff127da1191bdb20af.png)
![533f72b8e7c8cebe978ddccb3c451ab7.png](https://i-blog.csdnimg.cn/blog_migrate/b63cdbd6be4bab44236d54255c08e6ad.jpeg)
- 邻居探索
ICMPv6中从类型133至类型137的消息叫做邻居探索消息。这种邻居探索消息对于IPv6通信起着举足轻重的作用。邻居请求消息用于查询IPv6的地址与MAC地址的对应关系,并由邻居宣告消息得知MAC地址。邻居请求消息利用IPv6的多播地址实现传输。
![ce4dce4345903798482bea07f88092cf.png](https://i-blog.csdnimg.cn/blog_migrate/5bc14d246d57eba2ba90b11cd2c11410.jpeg)
此外,由于IPv6中实现了即插即用的功能,所以在没有DHCP服务器的环境下也能实现IP地址的自动获取。如果是一个没有路由器的网络,就使用MAC地址作为链路本地单播地址。而在一个有路由器的网络环境中,可以从路由器获得IPv6地址的前面部分,后面部分则由MAC地址进行设置。此时可以利用路由器请求消息和路由器宣告消息进行设置。
![02a22c4475629789b90130d184a8afef.png](https://i-blog.csdnimg.cn/blog_migrate/0bee927e44c5f10ed53d40ddbc2e2341.jpeg)