ipv4校验和的计算

原理:

计算方法一:除去校验和的两位,将其他的位相加:45+00+00+3c+55+81+00+00+40+01+ac+1c

0f+0d+ac+1c+0f+0e=

计算方法二:


校验和(checksum)算法,简单的说就是16位累加的反码运算:

计算函数如下:

我们在计算时是主机字节序,计算的结果封装成IP包时是网络字节序,注意这两者之间的区别,我们在从IP包里读取要转化为主机字节序,往IP包里存入时要转化为网络字节序在存入。

UINT32 Checksum(UINT32 cksum, VOID*pBuffer, UINT32 size)

{

   INT8 num = 0;

   UINT8 *p = (UINT8 *)pBuffer;

 

   if ((NULL == pBuffer) || (0 == size))

    {

       return cksum;

    }

  

   while (size > 1)

    {

       cksum += ((UINT16)p[num] << 8 & 0xff00) | (UINT16)p[num + 1]& 0x00FF;

/*2个字节累加,先取网络字节序低位左移8位(变成主机字节序高位),与(加)上 网络字节序中的高位(主机字节序地位),即网络字节序要先变成主机字节序在进行累加,*/

       size  -= 2;

       num   += 2;

    }

  

if (size > 0)

//如果长度为奇数

    {

       cksum += ((UINT16)p[num] << 8) & 0xFFFF;

//如果总的字节数为奇数,则最后一个字节单独相加

       num += 1;

    }

 

   while (cksum >> 16)

    {

       cksum = (cksum & 0xFFFF) + (cksum >> 16);

//累加完毕将结果中高16位再加到低16位上,重复这一过程直到高16位为全0

    }

  

   return cksum;

}

 

注意:UINT32 cksum的类型,这里是4个字节的,防止在累加的过程中,数据溢出,(例如 0xFF 累加时就会内存溢出)

 

详细的计算过程和原理如下

一:ip 头 的计算:

直接对头部数据进行累加(不包括原来的checksum值):

1、ipv4包头

 

       ipHeadLen  =(pIpHeader->ver_ihl & 0x0F) << 2;

在ipv4 头中,版本类型和头长度加在一起是1 个字节(8位),各占4位,版本类型在前,长度在后,所以要取长度只能取低4 位,

       pIpHeader->chksum = 0;

因为不包括原来的checksum值,所以在每次计算前先把checksum的值置0,然后计算

       sum = Checksum(0, (VOID *)pIpHeader, ipHeadLen);

对整个ip包头的累加

       pIpHeader->chksum = HTONS((UINT16)(~sum));

结果为计算值的反码,(别忘转化为网络字节序)