ICMP checksum怎么计算
时间: 2024-06-04 14:09:43 浏览: 357
ICMP是一种网络协议,用于在IP网络中传输控制消息。在ICMP消息中,有一个字段叫做校验和(checksum),用于检测消息是否在传输过程中被修改或损坏。ICMP校验和的计算方法如下:
1. 将ICMP消息中的所有16位字(即2个字节)拆分成两个8位字节。
2. 将所有拆分后的字节依次相加,得到一个16位的累加和(checksum sum)。
3. 如果累加和的高16位不为0,则将高16位和低16位相加,直到高16位为0。
4. 将最终得到的16位结果取反,得到校验和。
例如,假设ICMP消息为:0101010101010101 0011001100110011 1111000011110000,将其拆分为8位字节为:01010101 01010101 00110011 00110011 11110000 11110000。将这些字节相加得到累加和为:00000111 00000111 11110100。由于高16位不为0,需要将高16位和低16位相加,得到:00000111 11111011。最终将结果取反,得到校验和为:11111000 00000100。
计算ICMP校验和的算法可以保证如果消息在传输过程中被修改或损坏,那么接收方计算出的校验和一定与发送方计算出的校验和不同,从而可以检测出消息的损坏。
相关问题
icmp checksum的计算
ICMP(Internet Control Message Protocol)是一种互联网协议,用于在网络层传输控制信息。ICMP数据报中包含了一个16比特的校验和字段,用于检测ICMP数据报是否在传输过程中发生了错误。
ICMP校验和的计算方法如下:
1. 将ICMP消息按16比特分组,如果长度为奇数,则将最后一个字节填充为0。
2. 将所有16比特分组相加,得到一个32比特的结果。
3. 将32比特结果的高16比特与低16比特相加,再取反,即得到ICMP校验和。
例如,对于以下ICMP消息:
```
4500 003c 1c46 4000 4001 b861 c0a8 0101 c0a8 0102 0800 9384 0001 0002 0003 0004 0005 0006 0007 0008 0009 000a 000b 000c 000d 000e 000f 0010 0011
```
首先将其按16比特分组:
```
4500 003c 1c46 4000
4001 b861 c0a8 0101
c0a8 0102 0800 9384
0001 0002 0003 0004
0005 0006 0007 0008
0009 000a 000b 000c
000d 000e 000f 0010
0011
```
然后将所有16比特分组相加,得到一个32比特的结果:
```
4500 + 003c + 1c46 + 4000 + 4001 + b861 + c0a8 + 0101 + c0a8 + 0102 + 0800 + 9384 + 0001 + 0002 + 0003 + 0004 + 0005 + 0006 + 0007 + 0008 + 0009 + 000a + 000b + 000c + 000d + 000e + 000f + 0010 + 0011 = 6bf5e
```
将32比特结果的高16比特与低16比特相加,得到一个16比特的结果:
```
6b + f5e = 1019
```
最后取反得到ICMP校验和:
```
01018
```
因此,ICMP校验和为01018。
if (PREDICT_TRUE (inner_ip4->protocol == IP_PROTOCOL_TCP)) { inner_L4_checksum = &((tcp_header_t *) (inner_ip4 + 1))->checksum; *inner_L4_checksum = ip_csum_fold (ip_csum_sub_even (*inner_L4_checksum, *((u64 *) (&inner_ip4->src_address)))); } else if (PREDICT_TRUE (inner_ip4->protocol == IP_PROTOCOL_UDP)) { inner_L4_checksum = &((udp_header_t *) (inner_ip4 + 1))->checksum; if (*inner_L4_checksum) *inner_L4_checksum = ip_csum_fold (ip_csum_sub_even (*inner_L4_checksum, *((u64 *) (&inner_ip4->src_address)))); } else if (inner_ip4->protocol == IP_PROTOCOL_ICMP) { //We have an ICMP inside an ICMP //It needs to be translated, but not for error ICMP messages icmp46_header_t *inner_icmp = (icmp46_header_t *) (inner_ip4 + 1); //Only types ICMP4_echo_request and ICMP4_echo_reply are handled by icmp_to_icmp6_header inner_icmp->type = (inner_icmp->type == ICMP4_echo_request) ? ICMP6_echo_request : ICMP6_echo_reply; inner_L4_checksum = &inner_icmp->checksum; inner_ip4->protocol = IP_PROTOCOL_ICMP6; } else { /* To shut up Coverity */ os_panic (); }
根据提供的代码片段,在给定的条件下,`inner_ip4` 结构中的协议字段被检查,并根据不同的协议类型执行不同的操作。
1. 如果 `inner_ip4->protocol` 等于 `IP_PROTOCOL_TCP`,则进入第一个条件语句块。在这里,通过指针操作找到内部 TCP 头部,并计算校验和。校验和的计算使用了 `ip_csum_sub_even()` 函数,并通过 `ip_csum_fold()` 函数进行折叠。同时,源地址字段也与校验和进行了异或运算。
2. 如果 `inner_ip4->protocol` 等于 `IP_PROTOCOL_UDP`,则进入第二个条件语句块。在这里,通过指针操作找到内部 UDP 头部,并进行与 TCP 类似的校验和计算。与 TCP 不同的是,只有当校验和非零时才进行计算。
3. 如果 `inner_ip4->protocol` 等于 `IP_PROTOCOL_ICMP`,则进入第三个条件语句块。在这里,将 ICMP 类型转换为对应的 ICMPv6 类型,并将协议字段 `inner_ip4->protocol` 设置为 `IP_PROTOCOL_ICMP6`。同时,获取内部 ICMP 头部,并将内部 ICMP 校验和指针指向相应字段。
4. 如果以上条件均不满足,则执行 `os_panic()` 函数,这可能是一个紧急错误处理机制,用于处理未预期的协议类型。
请注意,根据上下文,该代码片段可能是某个网络协议栈或网络处理程序的一部分,并且可能需要更多的代码和上下文来完整地理解其功能和用途。
阅读全文