1

我在计算我的数据包的正确 ip 校验和时遇到了麻烦。这是代码,我将解释我在做什么以及出了什么问题..

u_short checkSum(u_short *data, int byteCount){
int i, sum = 0;

for(i = 0; i < byteCount/2; i++){
    if(i == 5) continue;
    sum += *data++;
}

while(sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
return (u_short)~sum;
}

首先,我的函数一般用于计算发送数据的 16 位校验和。甚至假设字节数仅用于测试目的。sum 是我保存 32 位和的变量(当 16 位和溢出时,我可以将溢出保持在高 16 位一半)。随着 for i 循环遍历数据的 16 位块并将它们相加,增加数据指针(增加 16 位它是 u_short),有一个 if 测试来跳过标头的校验和部分.. 可以看出在 rfc 791 中,校验和部分是标头中的第 6 个 16 位块(在我的情况下为 5,因为我从 0 开始计数)。数据相加后,我将高 16 位添加到低 16 位,并将 32 位 int 折叠成 16 位短。最后,我反转位(一个补码)并将 32 位缩短为 16 位并将其返回给调用者函数。

这没有提供从 pcap 发送给我的正确校验和(我用它来嗅探数据包)。这就是我调用我的函数来比较结果的方式..

if(etherHdr->ether_type == 8){
    ipHdr = (struct ip*) (packet + sizeof(struct ether_header));
    printf("chck: %04x mychck: %04x\n\n", ipHdr->ip_sum, checkSum((u_short*)ipHdr, sizeof(struct ip)));
}

if 仅过滤掉 IP 数据包(以太网标头类型字段中的代码 8)..

这是我运行程序时的输出..

chck:ef66 mychck:06ee

查克:3db8 查克:0264

查克:9615 查克:0000

chck:edef mychck:ff64

查克:59f1 查克:0164

查克:49f1 查克:0264

查克:a3d4 查克:0c77

查克:e36b 查克:0264

chck:aad4 mychck:0c77

查克:46d1 查克:0c77

查克:f40b 查克:0264

查克:a8d4 查克:0c77

我下载了在网上运行的其他代码示例,当 pcap 将数据包转发到我的代码时,这些示例都没有给出每个 IP 标头包含的结果。

可以的话请帮忙,谢谢。

4

2 回答 2

1

正确的方法在RFC 1071中给出。你已经接近了,但还没有雪茄。

于 2012-09-11T00:26:35.173 回答
0

也许试试这个计算校验和的源代码,我正在使用它,它对我的​​软件很有用。

            int
checksum
            (unsigned short *   data,
            int         length)
{
    register int                nleft   = length;
    register unsigned short     *   w   = data;
    register int                sum = 0;
    unsigned short              answer  = 0;

    while (nleft > 1)
    {
        sum     += *w++;
        nleft   -= 2;
    }

    if (nleft == 1)
    {
        *(unsigned char *)(&answer) = *(unsigned char *)w;
        sum+=answer;
    }

    sum = (sum>>16) + (sum & 0xffff);
    sum += (sum>>16);
    answer = ~sum;

    return answer;
}
于 2012-09-11T14:04:51.270 回答