前言

这是几年前写的一份txt,大概内容忘了,应该是求证icmp的校验和

文字部分(流程)

发送端
1)将发送的IP头部中的检验和字段设置为0,然后以16位为一个间隔,将IP头部分成许多个16位的字段
2)将第1步获得的所有字段进行二进制相加求和
3)把最终结果取反,也就是0置位1,1置位0,就得到检验和,再将该值填充到IP头部。

接收端
把接收到的IP头部分成16位的间隔
所有字段进行二进制相加求和
结果取反
如果结果为0,说明校验正确

接收方进行校验时,也是对每16位进行二进制反码求和。
接收方计算校验和时的首部与发送方计算校验和时的首部相比,多了一个发送方计算出来的校验和。
因此,如果首部在传输过程中没有发生差错,那么接收方计算的结果应该为全一,因为接收方计算除校验和以外的部分得到值是校验和的反码,再加多出来的校验和当然是全一了。

代码部分

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


unsigned short checksum(unsigned short *buffer, int size)
{
    unsigned long cksum=0;                          //初始化要校验的校验和
    while(size >1) {                                //将IP首部的内容以16位为单位相加
        cksum+=*buffer++; 
        size-=sizeof(unsigned short);
    }
    if(size) cksum+=*(unsigned short*)buffer;      
    cksum=(cksum >> 16)+(cksum&0xffff);            //高16位移位到低16位,低16位相加
    cksum+=(cksum >>16);                           //再次移位相加避免进位
    return (unsigned short)(~cksum);               //返回取反值
}

测试

第一段ICMP包的16进制数值为以下的值,其中00B8为校验和。

4500 003C A5D0 0000 8001 0000
C0A8 0009 C0A8 00B8

第二段ICMP包的16进制数值为以下的值,其中00B8为校验和。

4500 003C A5D0 0000 8001 12DF
C0A8 0009 C0A8 00B8


计算过程如下

4500+003C+A5D0+0000+8001+0000+C0A8+0009+C0A8+00B8=2 ED1E
0002+ED1E
0002+ED1E=ED20 = 1110 1101 0010 0000
~ED20 = 0001 0010 1101 1111 =12DF

4500+003C+A5D0+0000+8001+12DF+C0A8+0009+C0A8+00B8=2 FFFD
0002+FFFD
0002+FFFD=FFFF =1111 1111 1111 1111
~FFFF = 0000 0000 0000 0000


人贵有自知之明。