IPv4_checksum_Linux

ZC: 貌似 Linux内核里面有 计算何种协议的checksum的函数,但是 应用层 我没有找到现成的函数可供调用...

ZC: IP头的checksum 和 UDP头的checksum 来自于“<<Windows 网络与通信程序设计>> (第2版)  第6章 6.3.3、原始UDP封包发送实例” (6.5 中也有 TCP头checksum的计算方式,不过它是通过TCP伪头来计算的...我没用它...)

ZC: “<<Windows 网络与通信程序设计>> (第2版)  第9章 9.4、互联网计算机扫描”中 有 TCP头checksum的计算方式

 

1、ip checksum

2、udp checksum

3、tcp checksum

4、代码 来源为<<Windows 网络与通信程序设计>> (第2版) ,从VC6的代码修改而来,实际测试过 下面两个函数是OK的

#include <stdlib.h>
#include <string.h>
#include <netinet/ip.h>
#include <netinet/udp.h>

unsigned short checksum(unsigned short* _buff, int _size)
{
    unsigned long cksum = 0;
    while(_size>1)
    {
        cksum += *_buff++;
        _size -= sizeof(unsigned short);
    }
    // 是奇数
    if(_size)
    {
        cksum += *(unsigned char*)_buff;
    }
    // 将32位的chsum高16位和低16位相加,然后取反
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >> 16);            
    return (unsigned short)(~cksum);
}


/* 
计算UDP伪头校验和。UDP校验和基于如下几个域:
    源IP地址
    目的IP地址
    8位0域
    8位协议域
    16位UDP长度
    16位源端口号
    16位目的端口号
    16位UDP封包长度
    16位UDP校验和(0)
    UDP净荷
 */
void ComputeUdpPseudoHeaderChecksum(
    struct iphdr  *_pIphdr,
    struct udphdr *_pUdphdr,
    char    *_payload,
    int      _payloadlen
    )
{
    char buff[1024];
    char *ptr = buff;
    int chksumlen = 0;
    unsigned long zero = 0;
    
    // 包含源IP地址和目的IP地址
    memcpy(ptr, &_pIphdr->saddr, sizeof(_pIphdr->saddr));
    ptr += sizeof(_pIphdr->saddr);
    chksumlen += sizeof(_pIphdr->saddr);

    memcpy(ptr, &_pIphdr->daddr, sizeof(_pIphdr->daddr));
    ptr += sizeof(_pIphdr->daddr);
    chksumlen += sizeof(_pIphdr->daddr);

    // 包含8位0域
    memcpy(ptr, &zero, 1);
    ptr += 1;
    chksumlen += 1;

    // 协议
    memcpy(ptr, &_pIphdr->protocol, sizeof(_pIphdr->protocol));
    ptr += sizeof(_pIphdr->protocol);
    chksumlen += sizeof(_pIphdr->protocol);

    // UDP长度
    memcpy(ptr, &_pUdphdr->len, sizeof(_pUdphdr->len));
    ptr += sizeof(_pUdphdr->len);
    chksumlen += sizeof(_pUdphdr->len);

    // UDP源端口号
    memcpy(ptr, &_pUdphdr->source, sizeof(_pUdphdr->source));
    ptr += sizeof(_pUdphdr->source);
    chksumlen += sizeof(_pUdphdr->source);

    // UDP目的端口号
    memcpy(ptr, &_pUdphdr->dest, sizeof(_pUdphdr->dest));
    ptr += sizeof(_pUdphdr->dest);
    chksumlen += sizeof(_pUdphdr->dest);

    // 又是UDP长度
    memcpy(ptr, &_pUdphdr->len, sizeof(_pUdphdr->len));
    ptr += sizeof(_pUdphdr->len);
    chksumlen += sizeof(_pUdphdr->len);

    // 16位的UDP校验和,置为0
    memcpy(ptr, &zero, sizeof(unsigned short));
    ptr += sizeof(unsigned short);
    chksumlen += sizeof(unsigned short);

    // 净荷
    memcpy(ptr, _payload, _payloadlen);
    ptr += _payloadlen;
    chksumlen += _payloadlen;

    // 补齐到下一个16位边界
    for(int i=0; i<_payloadlen%2; i++)
    {
        *ptr = 0;
        ptr++;
        chksumlen++;
    }
    // 计算这个校验和,将结果填充到UDP头
    _pUdphdr->check = checksum((unsigned short*)buff, chksumlen);
}

5、代码 来源为<<Windows 网络与通信程序设计>> (第2版) 第9章,从VC6的代码修改而来,编译通过 但是 没有 实际测试过 ...(待测试)

/* 
计算TCP伪头校验和。TCP校验和基于如下几个域:
    源IP地址
    目的IP地址
    8位0域
    8位协议域
    16位TCP长度
    TCP头
    TCP数据
 */
void ComputeTcpPseudoHeaderChecksum(
    struct iphdr  *_pIphdr,
    struct tcphdr *_pTcphdr,
    char *_payload,
    int _payloadlen
    )
{
    char buff[1024];
    char *ptr = buff;
    int chksumlen = 0;
    unsigned long zero = 0;
    
        // 伪头
    // 包含源IP地址和目的IP地址
    memcpy(ptr, &_pIphdr->saddr, sizeof(_pIphdr->saddr));
    ptr += sizeof(_pIphdr->saddr);
    chksumlen += sizeof(_pIphdr->saddr);

    memcpy(ptr, &_pIphdr->daddr, sizeof(_pIphdr->daddr));
    ptr += sizeof(_pIphdr->daddr);
    chksumlen += sizeof(_pIphdr->daddr);

    // 包含8位0域
    memcpy(ptr, &zero, 1);
    ptr += 1;
    chksumlen += 1;

    // 协议
    memcpy(ptr, &_pIphdr->protocol, sizeof(_pIphdr->protocol));
    ptr += sizeof(_pIphdr->protocol);
    chksumlen += sizeof(_pIphdr->protocol);

    // TCP长度
    unsigned short tcp_len = htons(sizeof(struct tcphdr) + _payloadlen);
    memcpy(ptr, &tcp_len, sizeof(tcp_len));
    ptr += sizeof(tcp_len);
    chksumlen += sizeof(tcp_len);

    // TCP头
    memcpy(ptr, _pTcphdr, sizeof(struct tcphdr));
    ptr += sizeof(struct tcphdr);
    chksumlen += sizeof(struct tcphdr);

        // 净荷
    memcpy(ptr, _payload, _payloadlen);
    ptr += _payloadlen;
    chksumlen += _payloadlen;

    // 补齐到下一个16位边界
    for(int i=0; i<_payloadlen%2; i++)
    {
        *ptr = 0;
        ptr++;
        chksumlen++;
    }

    // 计算这个校验和,将结果填充到TCP头
    _pTcphdr->check = checksum((unsigned short*)buff, chksumlen);
}

 

6、

7、

8、

 

转载于:https://www.cnblogs.com/LinuxCode/p/5816769.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值