IP/TCP/UDP校验和的计算

来源:互联网 发布:六小龄童 知乎 编辑:程序博客网 时间:2024/05/09 22:12

1. 校验和

ICMP,IP,UDP,TCP报头部分都有checksum(检验和)字段。IP 首部里的校验和只校验首部;ICMP、IGMP、TCP和UDP首部中的校验和校验首部和数据。

1)IP头长度为20字节,IP校验和只对IP协议头进行计算。

UDP协议头为8字节:

0        7 8      15 16     23 24     31
+--------+--------+--------+--------+
|   source port   |destination port  |
+--------+--------+--------+--------+
|    UDP length   | UDP checksum |
+--------+--------+--------+--------+

TCP协议头为20到60字节:

UDP和TCP的校验和不仅要对整个IP协议负载(包括UDP/TCP协议头和UDP/TCP协议负载)进行计算,还要先对一个伪协议头进行计算:先要填充伪首部各个字段,然后再将UDP/TCP报头及之后的数据附加到伪首部的后面,再对位首部使用校验和计算,所得到的值才是UDP/TCP报头部分的校验和。

伪首部结构如下:

0        7 8      15 16     23 24     31
+--------+--------+--------+--------+
|           source address               |
+--------+--------+--------+--------+
|        destination address            |
+--------+--------+--------+--------+
| zero    | proto  |   udp/tcp len    |
+--------+--------+--------+--------+

 伪首部可以用如下的结构体表示:

struct pseudo_head {     uint32_t    saddr;      //源IP地址      uint32_t    daddr;      //目的IP地址      char         zero;       //置空(0)      char         proto;     //协议类型      unsigned short  len;    //TCP/UDP数据包的长度(即从TCP/UDP报头算起到数据包结束的长度,单位:字节)};


 

2. 校验和的计算方法

以IP首部中的校验和为例。

1)首先把校验和字段清零;

2)然后对每 16 位(2 字节)进行二进制反码求和;

这里说的反码求和,不是说先对每 16 位求反码然后求和,而是说把每 16 位当做反码求和;

反码求和时,最高位的进位要进到最低位,也就是循环进位。

求校验和的C代码实现:

short checksum(short *buffer, int size) {    unsigned long cksum=0;    while(size >1)    {        cksum+=*buffer++;        size -=sizeof(short);    }    if(size )    {        cksum += *(char*)buffer;    }      cksum = (cksum >> 16) + (cksum & 0xffff);    cksum += (cksum >>16);    return (short)(~cksum);}


 

3. 校验原理
同样以IP首部中的校验和为例。接收方进行校验时,也是对每16位(2字节)进行二进制反码求和。接收方计算校验和时的首部与发送方计算校验和时的首部相比,多了一个发送方计算出来的校验和的反码。因此,如果首部在传输过程中没有发生差错,那么接收方计算的结果应该为全一。
 
说明:
由于IP报文在网络中传输时TTL是在变化的(每经过一个路由器减一),因此在路由器中要对 IP 首部重新校验。这也解释了为什么IP首部里的校验和只校验首部而不校验数据,因为如果数据也校验,那将给路由器增加巨大的负担。因此对数据校验的任务交给上层协议(TCP或UDP)。

=====================end========================

原创粉丝点击