【问题标题】:calculating ip checksum gives very strange values. Is it addition of all words in iphdr and taking complement of it. What am I missing?计算 ip 校验和给出了非常奇怪的值。是否添加了 iphdr 中的所有单词并对其进行补充。我错过了什么?
【发布时间】:2022-01-24 08:01:05
【问题描述】:

因此,到目前为止,此函数只是在将 0 设置为校验和后将 struct iphdr 对象中的每个单词相加并进行补码。但是有一些问题,因为我收到的 ip 数据包校验和字段是完全不同的。我计算的结果是负值

所以这是我的校验和函数,下面是简单的

uint16_t ip_checksum(void* vdata,size_t length) {
    // Cast the data pointer to one that can be indexed.
    char* data=(char*)vdata;    
    uint32_t acc=0;    
    // Handle complete 16-bit blocks.
    for (size_t i=0;i+1<length;i+=2) {
        uint16_t word;
        memcpy(&word,data+i,2);
        acc+=ntohs(word);
        /*if (acc>0xffff) {
            acc-=0xffff;
        }*/
    }
  return (~acc);
}

所以这个循环

for (size_t i=0;i+1<length;i+=2) {
            uint16_t word;
            memcpy(&word,data+i,2);
            acc+=ntohs(word);
            /*if (acc>0xffff) {
                acc-=0xffff;
            }*/
        }

只是对接收到的对象指针的每个 16 位字进行操作,并进行加法并将其存储在 acc 变量中,

然后我用~ 来补充它

return (~acc);

所以基本上,如果我是正确的,我在互联网上确切地告诉计算它。但是当我这样做时

printf("checksum = %d\n",ntohs(iph->check));
    iph->check=0;
    int16_t i=ip_checksum(iph,sizeof(iph)); 
    printf("------------------------------------------>%d\n",(i));

它在上面的两个 printf 中打印完全不同的校验和值。 所以我想知道我做错了什么

【问题讨论】:

  • 如果你的数据大小不是2的倍数,那么memcpy(&amp;word,data+i,2)就是麻烦的来源。
  • 如果它是 2 的倍数(总是),那么你最好用 i&lt;length 替换 i+1&lt;length(我的意思是,也许它可以完成工作,也许它错过了最后一个2 个字符;如果我是你,那我宁愿不用问自己这个问题)。
  • @bbbbbbbbb 我在校验和函数中尝试了这个printf("))))))))))))))))))))))%zu\n",length);,它的打印是 8 它是 2 的倍数你是什么意思。
  • 最后,memcpy(&amp;word,data+i,2) 始终按照 Little Endian 顺序完成,而 uint16_t word 则受制于您平台的字节顺序。这意味着你会在不同的平台上得到不同的结果,这使得你的程序的行为没有很好的定义。
  • 编辑问题以提供minimal reproducible example,包括重现问题的数据、观察到的输出和所需的输出。解释为什么您注释掉了0xffff 部分,而这是校验和的必要部分。说明长度是字节数还是字数。

标签: c networking tcp ip checksum


【解决方案1】:

这是工作功能,我之前做过这个检查if (sum &gt;= 0x10000) {我不知道为什么它当时不起作用。现在它的话解决了

所以我想知道 tcp 校验和是否也一样,我只想将 *tcph 传递给以下校验和函数。

uint16_t csum(const void *data, const int length)
{
    /*  Checksum Algorithm (http://www.microhowto.info/howto/calculate_an_internet_protocol_checksum_in_c.html)
    1. Set the sum to 0,
    2. Pad the data to an even number of bytes,
    3. Reinterpret the data as a sequence of 16-bit unsigned integers that are
        in network byte order,
    4. Calculate the sum of the integers, subtracting 0xffff whenever
        the sum => 0x10000, and
    5. Calculate the bitwise complement of the sum and set it as the checksum.
    */
    printf("[[[[[[[[%d]]]]]]]]\n",length);
    uint16_t *accumalator = (uint16_t *)data;
    uint64_t sum = 0;

    /* Take care of the first 16-bit even blocks */
    for (int i = 0; i < length/2; ++i) {
        sum += *(accumalator+i);
        if (sum >= 0x10000) {
            sum -= 0xffff;
        }
    }

    /* Handle the ending partial block */
    if (length % 2 != 0) {
        accumalator = accumalator+ length/2; /* Point accumalator to the end block */
        uint16_t end_block = 0;
        memcpy(&end_block, accumalator, sizeof(length));
        sum += ntohs(end_block);
        if (sum >= 0x10000) {
            sum -= 0xffff;
        }
    }
    /* Return the one's complement of the checksum in network byte order */
    return htons(~sum);
}

【讨论】:

  • 它是同一个函数,但是tcp校验和是在整个tcp段上计算的,而不仅仅是header,而且这个字节长度可能不均匀。
  • 证明,TCP 校验和是在整个 tcp 段 + 伪标头上计算的,其中包括 IP 地址
  • 写在rfc793的第16页
  • @Effie 这是什么意思pseudoheader, which includes IP addresses 你的意思是我需要对 tcphdr 对象加上 ip.saddr 和 ip.daddr 进行 tcp 校验和。请澄清
  • 链接到上面的标准,同样,不是 tcphdr,tcphdr + 所有的有效载荷
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-06
  • 2022-01-12
  • 1970-01-01
  • 1970-01-01
  • 2017-11-29
  • 1970-01-01
相关资源
最近更新 更多