欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

TCP/UDP的checksum校检算法实现,亲测与wireshark一致

程序员文章站 2022-07-10 18:39:01
...
typedef unsigned short u_short;
typedef unsigned int u_int;
u_short swapI16(u_short v)
{
    return ((v & 0x00FF) << 8) |
            ((v & 0xFF00) >> 8);
}

//1.UDP校检的数据有三块,伪头部(12Bytes)+UDP头(8Bytes)+数据
//2.伪头部包括,IP源地址+IP目的地址+mbz(0x0)+协议类型(UDP:17,TCP:6)+UDP长度
//  长度为4+4+1+1+2=12 Bytes
//3.UDP头包括,源端口+目的端口+UDP长度+checksum
//  长度为2+2+2+2=8 Bytes
//4.注意:
//     a)伪头部中UDP长度为时间UDP头+数据的长度,UDP头部中UDP长度为0x0000
//     b)如果数据长度不是2的整数倍,则必须在最后补一个字节数据,即padding
u_int udp_checksum(void *input, int len)
{
    u_short* tmp = (u_short*)input;
    u_int sum = 0;
    for (int i=0; i<len/2; i++) {
        sum += swapI16(*(tmp+i));
    }
    if (len % 2 == 1) {
        sum += (*((unsigned char*)input+len-1) << 8);
    }
    if (sum > 0xFFFF) {
        sum = (sum & 0xFFFF) + (sum >> 16);
    }

    u_short ret = sum;
    return swapI16(~ret);
}

//1.ip校检只校验IP头20字节
//2.ip校检字段必须为0
u_int ip_checksum(void *input, int len)
{
    if (len != 20) return 0;
    //ip校检置0
    memset((char*)input+10, 0, 2);
    u_short* tmp = (u_short*)input;
    u_int sum = 0;
    for (int i=0; i<len/2; i++) {
        sum += swapI16(*(tmp+i));
    }
    if (sum > 0xFFFF) {
        sum = (sum & 0xFFFF) + (sum >> 16);
    }

    u_short ret = sum;
    return swapI16(~ret);
}