IP首部校验和算法

一、校验和概念

  报头校验和(Header Checksum)是针对IP报头的纠错字段。校验和不计算被封装的数据,UDP、TCP和ICMP都有各自的校验和。报头校验和字段包含一个16位二进制补码和,这是由数据包发送者计算得到的。接受者将连同原始校验和重新进行16位二进制补码和的计算。如果数据包传输中没有发生错误,那么结果应该16位全部为1。

二、校验和算法

   IP校验和主要是用来保证数据(IP报头)的完整性的,就是反码求和校验。需要注意的是反码求和又叫1的补码,而2的补码就是我们通常说的补码求和了。校验算法具体如下。

1、发送方

  i)将校验和字段置为0,然后将IP报头按16比特分成多个单元,如包头长度不是16比特的倍数,则用0比特填充到16比特的倍数;

  ii)对各个单元采用反码加法运算(即高位溢出位会加到低位,通常的补码运算是直接丢掉溢出的高位),将得到的和的反码填入校验和字段;

  iii)发送数据包。

2、接收方

  i)IP包头按16比特分成多个单元,如包头长度不是16比特的倍数,则用0比特填充到16比特的倍数;

  ii)对各个单元采用反码加法运算,检查得到的和是否符合是全1(有的实现可能对得到的和会取反码,然后判断最终值是不是全0)

       iii如果是全1则进行下步处理,否则意味着包已变化从而丢弃之。需要强调的是反码和是采用高位溢出加到低位的,如3比特的反码和运算:100b+101b=010b(因为100b+101b=1001b,高位溢出1,其应该加到低位,即001b+1b(高位溢出位)=010b)

3、示例

IP首部中的校验和为例,计算过程可分为三个步骤:

1.把校验和字段以全零填充;

2.对每 16 位(2 Byte)进行二进制反码求和;

(这里说的反码求和,不是说先对每 16 位求反码然后求和,而是说把每16 位当做反码求和。所有数据反码求和结束后,将最高位的进位进到最低位。)

3.对得到的结果取反即得校验和数据。

示例:

对如下十六进制数据求反码校验和:

0x4500,0x003C,0xCA2C,0x0000,0x8001,0x0000,0xC0A8,0x04FD,0xC0A8,0x0405

对以上数据直接相加得结果:0x0319BB

按照2中规则,对此数据的处理应该是将16位数最高位的进位0x030x19BB相加,即得到中间结果:0x19BE

按照3中规则对其取反即得校验和:0xE641

关于接收时的验证:

2中所述,将所有16位数据直接相加,并将进位数据加到最低位,此时与计算过程相比,数据中多了一个反码数据,因此如果传输途中没有差错,此时的计算结果应当是16位全1数据。

下面结合上面的示例说明计算原理,由校验和的计算过程可知,所有数据(含校验和数据)的代数和应当小于0x03FFFF,其中最高位的0x0316位数据的进位数据。因此对于发送时计算校验和的过程和接收时根据校验和校验的过程这两个过程中的求和运算,16位的进位数据是完全相同的,因此在接收校验时可直接把所有数据相加并把最终的进位数据加到最低位,若传输无误则结果必然是全1


三、校验和算法源码:

unsigned short csum(unsigned char *addr,int count)
{
  /* ComputeInternet Checksum for "count" bytes beginning at location"addr". */
  registerlong sum = 0;
 
  while( count> 1 )
  {
        /* This is the inner loop */
        sum += * (unsigned short) addr++;
        count -= 2;
  }
 
/* Add leftover byte,if any */
if(count>0)      // 奇数字节,考虑CPU大端还是小端模式
#if BIG_ENDIAN
sum+=(*(unsigned char *)addr)<<8;
#else
sum+=*(unsigned char *)addr;
#endif
 
  /* Fold32-bit sum to 16 bits */
  while(sum>>16)
        sum = (sum & 0xffff) + (sum >>16);
 
  return ~sum;
}


你可能感兴趣的:(网络)