简体   繁体   English

IP和TCP标头校验和在C中计算

[英]IP and TCP header checksum calculate in c

I'm writing a simple program to send/receive TCP packets and incorporate it into a larger project. 我正在编写一个简单的程序来发送/接收TCP数据包,并将其合并到一个较大的项目中。 I got stuck at the checksum part where the number I calculated is not matched with the wireshark number. 我卡在校验和部分,在那里我计算出的数字与wireshark数字不匹配。

For checksum function, I re-use the code from Mike Muss as below: 对于校验和功能,我重新使用了Mike Muss的代码,如下所示:

static int
in_cksum(u_short *addr, int len)
{
    register int nleft = len;
    register u_short *w = addr;
    register int sum = 0;
    u_short answer = 0;

    /*
     * Our algorithm is simple, using a 32 bit accumulator (sum), we add
     * sequential 16 bit words to it, and at the end, fold back all the
     * carry bits from the top 16 bits into the lower 16 bits.
     */
    while (nleft > 1)  {
        sum += *w++;
        nleft -= 2;
    }

    /* mop up an odd byte, if necessary */
    if (nleft == 1) {
        *(u_char *)(&answer) = *(u_char *)w ;
        sum += answer;
    }

    /* add back carry outs from top 16 bits to low 16 bits */
    sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
    sum += (sum >> 16);         /* add carry */
    answer = ~sum;              /* truncate to 16 bits */
    return(answer);
}

I received a packet and store in char buffer[2048]. 我收到一个数据包,并将其存储在char缓冲区[2048]中。 In order to get IP header, I do: 为了获得IP标头,我这样做:

struct iphdr* ip;
ip = (struct iphdr*) buffer;

From here, I can read information correctly as ip->protocol, ip->saddr, etc., and even print out the correct checksum as displayed in wireshark 从这里,我可以正确读取信息,如ip-> protocol,ip-> saddr等,甚至可以打印出wireshark中显示的正确校验和。

printf("Print checksum = 0x%x\n",ntohs(ip->check));

Then I try to calculate the checksum using the function above and print it out 然后我尝试使用上面的函数计算校验和并打印出来

printf("My calculated checksum =0x%x\n",in_cksum ((unsigned short*) ip, sizeof(struct iphdr)));

What I got is "My calculated checksym = 0x0" and it seems that there is nothing in IP header. 我得到的是“我的计算出的checksym = 0x0”,看来IP头中没有任何内容。 I guess that I might not pass in the in_cksum function parameter correctly, but I'm not sure how to fix or if there is another problem in the way that I'm doing. 我想我可能无法正确传递in_cksum函数参数,但是我不确定如何解决或我的执行方式是否存在其他问题。

IP cksum problem is SOLVED below. IP cksum问题已在下面解决。 However, I meet a similar problem when try to calculate TCP checksum. 但是,尝试计算TCP校验和时遇到类似的问题。 Below is how I get tcp header: 以下是我如何获取tcp标头:

tcp=(struct tcphdr*) (buffer+sizeof(struct iphdr);

After this, again I can read correct information about tcp header such as tcp->source, tcp->dest, and even tcp->check 之后,我可以再次读取有关tcp标头的正确信息,例如tcp-> source,tcp-> dest甚至tcp-> check

Then I tried to re-compute the checksum as below: 然后,我尝试重新计算校验和,如下所示:

tcp->check=0;
tcp->check=in_cksum((unsigned short*)tcp, ntohs(ip->tot_length)-(4*ip->ihl));

The result I got here is different from what I printed out before. 我在这里得到的结果与之前打印出的结果不同。 I think my problem could in the length that I pass in the cksum function, but am not quite sure how to fix it. 我认为我的问题可能是通过cksum函数传递的,但是我不确定如何解决它。

Any help would be greatly appreciated. 任何帮助将不胜感激。 Thank you in advance! 先感谢您!

The calculation of the IP checksum must not include the field that contains that checksum - zero should be used for that field instead. IP校验和的计算中不得包含包含该校验和的字段-应该对该字段使用零。 From RFC 791 : RFC 791开始

The checksum field is the 16 bit one's complement of the one's complement sum of all 16 bit words in the header. 校验和字段是标头中所有16位字的一个补码之和的16位一个补码。 For purposes of computing the checksum, the value of the checksum field is zero. 为了计算校验和,校验和字段的值为零。

I haven't done the math, but I suspect that getting zero is the expected consequence of recalculating the checksum over the entire header, ie it causes the calculated sum to cancel itself out. 我还没有完成数学运算,但是我怀疑得到零是重新计算整个标头的校验和的预期结果,即,它导致计算出的总和自行抵消。

[I checked - Wikipedia agrees: "The result of summing the entire IP header, including checksum, should be zero if there is no corruption" . [我检查了-Wikipedia同意: “如果没有损坏,则将整个IP标头(包括校验和)相加的结果应为零” Zero is therefore in fact the correct result when verifying the checksum] 因此,在验证校验和时,零实际上是正确的结果。

Note that an IP header can only be a multiple of 4 bytes long, so your padding code is unnecessary in this particular case, albeit potentially useful if wanting to calculate the generic ones-complement checksum of other data. 请注意,IP标头只能是4个字节的倍数,因此,在这种特殊情况下,不需要填充代码,尽管如果要计算其他数据的通用的“ 1”补码校验和,则很有用。

Also, instead of passing sizeof(struct iphdr) you should be passing 4 * ip->ihl to account for any IP options that may be in the header, having first ensured that you actually have at least that many bytes in your buffer. 另外, 应该先传递4 * ip->ihl来解释报头中可能包含的任何IP选项,而不要传递sizeof(struct iphdr) ,首先要确保缓冲区中实际上至少有这么多字节。

sum += (sum >> 16); 总和+ =(总和>> 16); /* add carry / answer = ~sum; / *加进位/答案=〜sum; / truncate to 16 bits */ /截断为16位* /

If you add carry to the lower 2 bytes and negative it . 如果将进位加到低2个字节并将其取负。

It will be obviously zero. 显然它将为零。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM