ICMP协议的作用
ICMP的主要功能包括,确认IP包是否成功送达目标地址,通知在发送过程当中IP包被废弃的具体原因,改善网络设置等。
(图解TCP/IP)
ICMP的报文封装
ICMP报文是使用IP数据报来封装和发送的,携带ICMP报文的IP数据报完全像其他类型数据的数据报那样在网络中被转发,没有额外的可靠性和优先级,由于IP数据报本身被放在底层物理数据帧中进行发送,因此,ICMP报文本身也可能丢失或者出现传输错误
ICMP报文格式
- 8位的类型字段标识了该ICMP报文的具体类型
- 8位的代码字段进一步指出产生这种类型ICMP报文的原因,每种类型报文的产生的原因都可能有多个,就拿目的站不可达报文来说,产生的原因可能有主机不可达、协议不可达、端口不可达等;
16位校验和字段包括整个ICMP报文,即包括ICMP首部和数据区域。首部中的剩余4个字节在每种类型的报文中有特殊的定义
ICMP报文可分为两大类:有关IP数据报传递的ICMP报文(称为差错报文(errormessage)),以及有关信息采集和配置的ICMP报文(称为查询(query)或者信息类报文(informational message) )
类型
比如在我的本地到网关抓包,就可以看到type 8
意味着这是一个 ICMP的请求
在响应中也可以看到type 0
类型与代码
说明:ICMP的类型与代码组合对应一个消息的说明
TYPE | CODE | Description (n.描述; 说明; 形容; 描写(文字); 类型;) |
Query | Error |
---|---|---|---|---|
0 | 0 | Echo Reply——回显应答(Ping应答) | ✔ | |
3 | 0 | Network Unreachable——网络不可达 | ✔ | |
3 | 1 | Host Unreachable——主机不可达 | ✔ | |
3 | 2 | Protocol Unreachable——协议不可达 | ✔ | |
3 | 3 | Port Unreachable——端口不可达 | ✔ | |
3 | 4 | Fragmentation needed but no frag. bit set——需要进行分片但设置不分片比特 | ✔ | |
3 | 5 | Source routing failed——源站选路失败 | ✔ | |
3 | 6 | Destination network unknown——目的网络未知 | ✔ | |
3 | 7 | Destination host unknown——目的主机未知 | ✔ | |
3 | 8 | Source host isolated (obsolete)——源主机被隔离(作废不用) | ✔ | |
3 | 9 | Destination network administratively prohibited——目的网络被强制禁止 | ✔ | |
3 | 10 | Destination host administratively prohibited——目的主机被强制禁止 | ✔ | |
3 | 11 | Network unreachable for TOS——由于服务类型TOS,网络不可达 | ✔ | |
3 | 12 | Host unreachable for TOS——由于服务类型TOS,主机不可达 | ✔ | |
3 | 13 | Communication administratively prohibited by filtering——由于过滤,通信被强制禁止 | ✔ | |
3 | 14 | Host precedence violation——主机越权 | ✔ | |
3 | 15 | Precedence cutoff in effect——优先中止生效 | ✔ | |
4 | 0 | Source quench——源端被关闭(基本流控制) | ||
5 | 0 | Redirect for network——对网络重定向 | ||
5 | 1 | Redirect for host——对主机重定向 | ||
5 | 2 | Redirect for TOS and network——对服务类型和网络重定向 | ||
5 | 3 | Redirect for TOS and host——对服务类型和主机重定向 | ||
8 | 0 | Echo request——回显请求(Ping请求) | ✔ | |
9 | 0 | Router advertisement——路由器通告 | ||
10 | 0 | Route solicitation——路由器请求 | ||
11 | 0 | TTL equals 0 during transit——传输期间生存时间为0 | ✔ | |
11 | 1 | TTL equals 0 during reassembly——在数据报组装期间生存时间为0 | ✔ | |
12 | 0 | IP header bad (catchall error)——坏的IP首部(包括各种差错) | ✔ | |
12 | 1 | Required options missing——缺少必需的选项 | ✔ | |
13 | 0 | Timestamp request (obsolete)——时间戳请求(作废不用) | ✔ | |
14 | Timestamp reply (obsolete)——时间戳应答(作废不用) | ✔ | ||
15 | 0 | Information request (obsolete)——信息请求(作废不用) | ✔ | |
16 | 0 | Information reply (obsolete)——信息应答(作废不用) | ✔ | |
17 | 0 | Address mask request——地址掩码请求 | ✔ | |
18 | 0 | Address mask reply——地址掩码应答 |
举个例子
在我的机器上通过wireshark抓包,可以发现一个远端地址发送ICMP的数据给我,其中TYPE:3
CODE:3
也就对应了上表的 Port Unreachable——端口不可达
至于红框框上的IPV4与UDP 我会在后续的研究中补齐说明为什么,这是隧道技术
校验和
校验和是一个从数据包计算出来的值,用来来检查其完整性。通过完整性,我们可以检查收到的数据是否没有错误。这是因为在网络上传输时,数据包可能会损坏,并且接收端必须知道数据是否已损坏。这是校验和字段添加到报文的原因。在源端,计算校验和并将其作为字段设置在报文中。在目标端,再次计算校验和,并用报文中现有的校验和值进行交叉检查,看看数据包是否正常。<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/2078172/1643963013137-a0bc4aae-4354-4da4-b111-d680b68a8f95.png#clientId=u16cf0da7-c633-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=285&id=ua4de6605&margin=%5Bobject%20Object%5D&name=image.png&originHeight=570&originWidth=1336&originalType=binary&ratio=1&rotation=0&showTitle=false&size=257200&status=done&style=none&taskId=u0291eba8-992e-4bd2-818d-7451ac1831f&title=&width=668)<br />(TCP/IP 卷一)<br />**校验和算法**<br />这一块可以参考IPV4的CRC算法。不进行详细描述了
首先,IP、ICMP、UDP和TCP报文头部都有校验和字段,大小都是16bit,算法也基本一样:
在发送数据时,为了计算数据包的校验和。应该按如下步骤:
(1)把校验和字段置为0;
(2)把需校验的数据看成以16位为单位的数字组成,依次进行二进制反码求和;
(3)把得到的结果存入校验和字段中。
在接收数据时,计算数据包的校验和相对简单,按如下步骤:
(1)把首部看成以16位为单位的数字组成,依次进行二进制反码求和,包括校验和字段;
(2)检查计算出的校验和的结果是否为0;
(3)如果等于0,说明被整除,校验是和正确。否则,校验和就是错误的,协议栈要抛弃这个数据包。
虽然上面四种报文的校验和算法一样,但在作用范围存在不同:IP校验和只校验20字节的IP报头;而ICMP校验和覆盖整个报文(ICMP报头+ICMP数据);UDP和TCP校验和不仅覆盖整个报文,而且还有12字节的IP伪首部,包括源IP地址(4字节)、目的IP地址(4字节)、协议(2字节,第一字节补0)和TCP/UDP包长(2字节)。另外UDP、TCP数据报的长度可以为奇数字节,所以在计算校验和时需要在最后增加填充字节0(注意,填充字节只是为了计算校验和,可以不被传送)。
这里还要提一点,UDP的校验和是可选的,当校验和字段为0时,表明该UDP报文未使用校验和,接收方就不需要校验和检查了!那如果UDP校验和的计算结果是0时怎么办呢?书上有这么一句话:“如果校验和的计算结果为0,则存入的值为全1(65535),这在二进制反码计算中是等效的。”
Windows & Linux Ping报文差异
这里出现了一个错误,ping是在windows或者linux上根据ICMP协议实现的程序,并不是我要去处理的ICMP隧道的最终呈现。这两者的实现差异,我实在没找到参考资料和历史原因。
不过linux和windows上的ping程序本身也是有区别的,对比一下两者的流量。主要是date字段的不同。
Linux 下的ping
我在Linux下ping baidu.com
得到如下数据包
我的date内容:56170b0000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
对上图的说明:
- 默认Data传输的是48bytes,在Date之前多了一个Timestamp from icmp data头,占用8bytes
- %%%%
(5617)
,4个%在0~f间变化,发送和返回相同,不同发送返回不同,占用2个bytes
两个不同的ping 请求
0b0000000000
,前两位%%在变动,同一次ping操作,无论发送接收多少包,此数值不变,下一次ping则此值会变动(笔者未深入研究规律和代表内容)101112131415161718191a1b1c1d1e1f20
(规律是从10开始的16进制递增,一直到20),占用17bytes!”#$%&’()+,-./01234567
,占用23bytes
windows 下的ping
windows的date内容6162636465666768696a6b6c6d6e6f7071727374757677616263646566676869