C编程TCP校验和

我几天来一直无法为TCP做校验和。 我在互联网上查看了很多来源,但我见过的所有例子都没有向您展示如何进行TCP校验和。 我也查看了RFC文档但仍遇到问题:

下面是我用来生成校验和的代码:

unsigned short checksum(unsigned short * buffer, int bytes) { unsigned long sum = 0; unsigned short answer = 0; int i = bytes; while(i>0) { sum+=*buffer; buffer+=1; i-=2; } sum = (sum >> 16) + (sum & htonl(0x0000ffff)); sum += (sum >> 16); return ~sum; } 

此function适用于IP校验和。

下面是我为TCP标头制作的结构:

 struct tcp_header { unsigned short tcp_sprt; unsigned short tcp_dprt; unsigned int tcp_seq; unsigned int tcp_ack; unsigned char tcp_res:4; unsigned char tcp_off:4; unsigned char tcp_flags; unsigned short tcp_win; unsigned short tcp_csum; unsigned short tcp_urp; }; 

我一直在使用Wireshark来测试这些数据包,唯一不对的就是校验和。

最后,这里是伪标头结构,我加载了TCP标头和来自IP标头的信息:

 struct pseudoTcpHeader { unsigned int ip_src; unsigned int ip_dst; unsigned char zero;//always zero unsigned char protocol;// = 6;//for tcp unsigned short tcp_len; struct tcp_header tcph; }; 

一旦我用正确的信息加载这个结构,我就在整个伪头结构上使用校验和函数,并将TCP校验和分配给该值。 你看到我提供的东西有什么问题吗? 如果问题不在这里,可能是我看不到的粗心错误。

我在winpcap-users邮件列表上找到了一个相当不错的例子,该列表应该解决Greg关于奇数长度数据的评论,并给你一些比较代码的东西。

 USHORT CheckSum(USHORT *buffer, int size) { unsigned long cksum=0; while(size >1) { cksum+=*buffer++; size -=sizeof(USHORT); } if(size) cksum += *(UCHAR*)buffer; cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >>16); return (USHORT)(~cksum); } 

我看到了几件事:

  • 您没有通过填充零来计算奇数长度数据。
  • 从数据包中读取每个字时,您需要考虑网络字节顺序。
  • 你对htonl(0x0000ffff)似乎很可疑。 为什么要将常量转换为网络字节顺序以将其与主机字节顺序中的数据相结合?

RFC 793说“如果一个段包含要校验和的奇数个头和文本八位字节,则最后一个八位字节用零填充在右边,形成一个16位字用于校验和。” 上面的代码不处理这种情况。 我认为循环条件应该是i> 1然后检查循环外的i == 1并对最后一个八位字节进行特殊处理。

我也很难找到计算它的c ++ / c代码,直到我找到了如何计算IP / TCP / UDP校验和 – 第2部分实现 – roman10 ,并且它有效! 使用Wireshark的validation进行测试。