IP校验和计算

下面摘自《TCP/IP协议簇》的IP头校验和算法:

发送时:

1. 将校验和字段置为0;

2. 将整个首部分为16bit的部分,求和;

3. 取反码,填入到校验和字段中;

接收时:

1. 直接将整个首部分为16bit的部分,求和;

2. 取反码,若结果为0,取合法;否则丢弃;

这上面有两个细节没有描述清楚:

1. 计算时的字节顺序(litter endian和big endian)问题;

2. 取和溢出时的改进计算方法;

根据实验结果,及参考网络上的资料,实际上几乎现有所有的系统对校验和算法已经有点小小的补充,也许《TCP/IP协议簇》这里没有更新罢了,自我安慰吧,如下:

◆当发送IP包时,需要计算IP报头的校验和:

1、  把校验和字段置为0;

2、  对IP头部中的每16bit进行二进制求和;

3、  如果和的高16bit不为0,则将和的高16bit和低16bit反复相加,直到和的高16bit为0,从而获得一个16bit的值;

4、  将该16bit的值取反,存入校验和字段。

◆当接收IP包时,需要对报头进行确认,检查IP头是否有误,算法同上2、3步,然后判断取反的结果是否为0,是则正确,否则有错。

算法:

        unsigned short CheckSum(unsigned short *_pBuff, int _Size)
        {
            unsigned int ckSum = 0;

            unsigned short *tmpBuff = _pBuff;
            int tmpSize = _Size;

            while (tmpSize > 1)
            {
                ckSum += *tmpBuff ++;
                tmpSize -= sizeof(unsigned short);
            }

            if (tmpSize > 0)
            {
                ckSum += *(unsigned char*)tmpBuff;
            }

            ckSum = (ckSum >> 16) + (ckSum & 0xFFFF); //将高16bit与低16bit相加
            ckSum += (ckSum >> 16); //将进位到高位的16bit与低16bit 再相加

            return (unsigned short)(~ckSum);
        }

关于计算时的字节顺序,一般以网络字节顺序(big endian)为准,但仍然有个十分模糊的地方,就是为什么校验和这个字段不用进行网络转换了,如X86系统,直接以本地字节顺序(litter endian)发送就可以了,这也让我十分纠结。

下面是举例:

    char szBuf[] = {'\x45', '\x00', '\x00', '\xf4', '\x00', '\x2e', '\x00', '\x00' ,'\x80' ,'\x11',
                    '\x00', '\x00', '\xc0', '\xa8', '\x09', '\x0a', '\xc0', '\xa8', '\x09', '\xff'};
    
    unsigned short SendCkSum = 0x71a5; //这个值不用转换为网络字节顺序,直接以 A5 71填入 

    char szBuf[] = {'\x45', '\x00', '\x00', '\xf4', '\x00', '\x2e', '\x00', '\x00' ,'\x80' ,'\x11',
                    '\xa5', '\x71', '\xc0', '\xa8', '\x09', '\x0a', '\xc0', '\xa8', '\x09', '\xff'};

    unsigned short RecvCkSum = CheckSum((unsigned short*)szBuf, 20); //这里RecvCkSum为0

posted @ 2011-06-30 11:38  Capricorn.python  阅读(3712)  评论(1编辑  收藏  举报