繁体   English   中英

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

[英]IP and TCP header checksum calculate in c

我正在编写一个简单的程序来发送/接收TCP数据包,并将其合并到一个较大的项目中。 我卡在校验和部分,在那里我计算出的数字与wireshark数字不匹配。

对于校验和功能,我重新使用了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);
}

我收到一个数据包,并将其存储在char缓冲区[2048]中。 为了获得IP标头,我这样做:

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

从这里,我可以正确读取信息,如ip-> protocol,ip-> saddr等,甚至可以打印出wireshark中显示的正确校验和。

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

然后我尝试使用上面的函数计算校验和并打印出来

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

我得到的是“我的计算出的checksym = 0x0”,看来IP头中没有任何内容。 我想我可能无法正确传递in_cksum函数参数,但是我不确定如何解决或我的执行方式是否存在其他问题。

IP cksum问题已在下面解决。 但是,尝试计算TCP校验和时遇到类似的问题。 以下是我如何获取tcp标头:

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

之后,我可以再次读取有关tcp标头的正确信息,例如tcp-> source,tcp-> dest甚至tcp-> check

然后,我尝试重新计算校验和,如下所示:

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

我在这里得到的结果与之前打印出的结果不同。 我认为我的问题可能是通过cksum函数传递的,但是我不确定如何解决它。

任何帮助将不胜感激。 先感谢您!

IP校验和的计算中不得包含包含该校验和的字段-应该对该字段使用零。 RFC 791开始

校验和字段是标头中所有16位字的一个补码之和的16位一个补码。 为了计算校验和,校验和字段的值为零。

我还没有完成数学运算,但是我怀疑得到零是重新计算整个标头的校验和的预期结果,即,它导致计算出的总和自行抵消。

[我检查了-Wikipedia同意: “如果没有损坏,则将整个IP标头(包括校验和)相加的结果应为零” 因此,在验证校验和时,零实际上是正确的结果。

请注意,IP标头只能是4个字节的倍数,因此,在这种特殊情况下,不需要填充代码,尽管如果要计算其他数据的通用的“ 1”补码校验和,则很有用。

另外, 应该先传递4 * ip->ihl来解释报头中可能包含的任何IP选项,而不要传递sizeof(struct iphdr) ,首先要确保缓冲区中实际上至少有这么多字节。

总和+ =(总和>> 16); / *加进位/答案=〜sum; /截断为16位* /

如果将进位加到低2个字节并将其取负。

显然它将为零。

暂无
暂无

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

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