理解ICMP协议

Last Updated: 2023-04-21 10:09:00 Friday

-- TOC --

ICMP,Internet Control Message Protocol,互联网控制消息协议,它是互联网协议族的核心协议之一。

ICMP协议用于在TCP/IP网络中发送控制消息,提供可能发生在通信环境中的各种问题反馈,通过这些信息,使网络管理者可以对所发生的问题作出诊断,然后采取适当的措施。我们常用的ping和traceroute工具,都是基于ICMP协议实现的。

在socket编程时,有可能UDP或者raw socket接口会遇到返回connection refused这样的错误,这时就是协议栈收到了ICMP相关控制报文。比如iptables执行了REJECT,发出了ICMP Destination Port Unreachable,对端调用recvfrom接口就会有这个异常信息输出。

可以把ICMP协议看做是IP协议的带外控制协议

ICMP协议与IP协议同层,在IP报头中,协议号为1,IP报头之后紧跟着ICMP协议报文!

ICMP RFCs:

Ping

不同的ICMP type,有不同的结构定义,具体参考RFC792,下面是ICMP type为0和8是的结构,就是我们最常用的ping报文:

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Type      |     Code      |          Checksum             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Identifier          |        Sequence Number        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Optional Data ...
+-+-+-+-+-

struct icmp_head {
        uint8_t icmp_type;
        uint8_t icmp_code;
        uint16_t icmp_cksum;
        uint16_t icmp_id;
        uint16_t icmp_seq;
    };

ICMP报头长度为8bytes!

ICMP校验和,RFC1071。(ICMP校验和的计算方式,与IP header,TCP,UDP等协议checksum的计算方式都一样,具体请看internet checksum计算

有的程序将Identifier设置为自己的PID,这样设置在收到回应的时候,能够识别出请求是本进程发出的,但也不一定都这样。Seq一般从1开始增加。

对应ping程序使用查询报文:

ping的一个细节:ICMP报文data部分会原样被返回,就像一个message echo!因此很多实现都将发送ping的时间放在里面,当接收到回应的时候,可以用这个数据计算RTT(Round Trip Time)!

把发送ping报文的timestamp放在optional data里面,是个良好的设计,应该用这个信息来判断是否超时!发送和接收应该是两个线程,各自独立工作,回应报文到来时,才能尽可能及时的处理。

如果ping的时候,看到timeout,这是一种unknown error,可能是没有回来的路径!

Cisco's 4 steps for ip address trouble-shoot:

  1. ping 127.0.0.1 to check host's TCP/IP stack;
  2. ping ip address of it's own to check NIC;
  3. ping default gateway;
  4. ping remote server;

第1,2步比较有意思!~

Timestamp

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Type      |      Code     |          Checksum             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Identifier          |        Sequence Number        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Originate Timestamp                                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Receive Timestamp                                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Transmit Timestamp                                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Type

Code = 0 for both 13 and 14

timestampe是32位的milliseconds since midnight UT.

The Originate Timestamp is the time the sender last touched the message before sending it, the Receive Timestamp is the time the echoer first touched it on receipt, and the Transmit Timestamp is the time the echoer last touched the message on sending it.

就像ping一样,只是timestamp来回传递的是几个时间信息。协议并没有强制要求时间必须正确,似乎填0也OK。下面是在执行nmap -sn时,用tcpdump命令抓包打印出来的一点信息:

16:46:47.536238 IP 192.168.16.104 > 114.215.183.12: ICMP time stamp query id 57181 seq 0, length 20
16:46:47.556244 IP 114.215.183.12 > 192.168.16.104: ICMP time stamp reply id 57181 seq 0: org 00:00:00.000, recv 08:46:47.553, xmit 08:46:47.553, length 20

Destination Unreachable

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Type      |     Code      |          Checksum             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             unused                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Internet Header + 64 bits of Original Data Datagram      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Type = 3

Code

Here's a list of all the ICMP unreachable type and code:

Network Unreachable (Type 3, Code 0)
Host Unreachable (Type 3, Code 1)
Protocol Unreachable (Type 3, Code 2)
Port Unreachable (Type 3, Code 3)
Fragmentation Needed and Don't Fragment was Set (Type 3, Code 4)
Source Route Failed (Type 3, Code 5)
Destination Network Unknown (Type 3, Code 6)
Destination Host Unknown (Type 3, Code 7)
Source Host Isolated (Type 3, Code 8)
Communication with Destination Network is Administratively Prohibited (Type 3, Code 9)
Communication with Destination Host is Administratively Prohibited (Type 3, Code 10)
Destination Network Unreachable for Type of Service (Type 3, Code 11)
Destination Host Unreachable for Type of Service (Type 3, Code 12)
Communication Administratively Prohibited (Type 3, Code 13)
Host Precedence Violation (Type 3, Code 14)
Precedence cutoff in effect (Type 3, Code 15)

Address Mask

这是定义在RFC950中的一个ICMP消息,nmap有一个参数可以控制发送这种icmp报文来进行host discovery:

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Type      |      Code     |          Checksum             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Identifier          |       Sequence Number         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Address Mask                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

The ICMP address mask request is intended for a diskless system to obtain its subnet mask at bootstrap time.

Type

Code = 0

一般host都不支持这类ICMP消息。

Time Exceeded

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Type      |     Code      |          Checksum             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             unused                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Internet Header + 64 bits of Original Data Datagram      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Type == 11

Code

Code=0可能来自中间的路由器,Code=1可能来自Host。

traceroute的实现,就是基于收到的这类ICMP报文。traceroute程序构造的报文,TTL从1开始增加,每一台中间路由器将TTL减小到0后,回应ICMP(type=11,code=0),这样traceroute就拿到中间路径的ip地址。如果是基于UDP实现的traceroute,预期是最后的目的Host返回一个Unreachable的ICMP报文。如果是基于ICMP ping实现的traceroute,预期是最后收到ping回应。当然,互联网情况复杂,收不到回应的情况非常多。

Parameter Problem

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Type      |     Code      |          Checksum             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|    Pointer    |                   unused                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Internet Header + 64 bits of Original Data Datagram      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Type == 11

Code == 0

IPv4报文头解析失败的时候发出。Pointer指向出错的位置。

这种在报文中提供一个Pointer字段的设计,IPv4头的LSRR和SSRR选项也有使用。

本文链接:https://cs.pynote.net/net/ip/202112045/

-- EOF --

-- MORE --