C 中的 TCP 校验和



我一直在尝试计算 C 中 TCP 标头的校验和。就我而言,TCP 标头的长度为 20 字节,没有额外的数据或选项。此外,据我所知,TCP 校验和计算为 1 个标头中 16 位字的补码和的补码。因此,考虑到我上面提到的条件,我编写了一个函数来计算 TCP 校验和。但是,当我在计算校验和后检查发送的数据包时,我得到:

1 0.000000   10.0.2.15 -> 127.0.0.1    TCP 74 24131->8000 [SYN] Seq=0 Win=13273 [TCP CHECKSUM INCORRECT] Len=20

我使用tshark检查了数据包。但是,我也用Wireshark检查了数据包,它也说了同样的话。除了,在括号中,它说,"可能是由TCP校验和卸载引起的?这,我不完全明白。

这是我用来计算校验和的代码:

unsigned short tcp_checksum(struct tcphdr* tcph,struct iphdr* iph)  {
/* Calculate TCP checksum */
struct pseudo_hdr* pseudo_hdr;
u_char* buffer;
u_char* segment;
u_char* pseudo_segment;
unsigned int count = 32; 
unsigned long sum = 0;
unsigned short mask = 0xffff;
unsigned long long* hdr;
pseudo_hdr = malloc(sizeof(struct pseudo_hdr)); // allocate memory
buffer = malloc(32); // allocate for 32 bytes of information 
if (pseudo_hdr == NULL || buffer == NULL) { // if memory wasn't allocated properly
err();
if (pseudo_hdr != NULL) free(pseudo_hdr);
if (buffer != NULL) free(buffer);
return 0;
}

pseudo_hdr->saddr = (unsigned long)iph->saddr; // we add the cast because the fields if of type u_int_32
pseudo_hdr->daddr = (unsigned long)iph->daddr; // same reason for adding the cast as above
bzero(&pseudo_hdr->reserved,sizeof(pseudo_hdr->reserved)); // zero header 
pseudo_hdr->proto = IPPROTO_TCP; // this will always be 6
pseudo_hdr->len = htons(tcph->doff*4); // length of tcp header
/* Place both headers into a buffer */
segment = (u_char*)tcph; 
pseudo_segment = (u_char*)pseudo_hdr; 
/* Concactenate */
memcpy((char*)buffer,(char*)pseudo_segment,sizeof(struct pseudo_hdr)); // first the pseudo header 
memcpy((char*)buffer+12,(char*)segment,sizeof(struct tcphdr)); // then the TCP segment 
/* Calculate checksum just like IP checksum (RFC C implementation) */
hdr = (unsigned long long*)buffer;
while (count > 1) {
sum += *(unsigned short*)hdr++;
count -= 2;
}
// Add left over bytes, if any 
if (count > 0) sum += * (u_char*) hdr;
// Fold 32-bit sum to 16 bits 
while (sum>>16) sum = (sum & mask) + (sum >> 16);
sum = ~sum; // bitwise NOT operation
/* Discard headers and buffer */
free(buffer);
free(pseudo_hdr);
return sum;

}

struct iphdrstruct tcphdr<netinet/ip.h><netinet/tcp.h>中定义。这是我对struct pseudo_hdr的定义:

struct pseudo_hdr {
unsigned long saddr; // 4 bytes
unsigned long daddr; // 4 bytes
unsigned char reserved; // 1 byte
unsigned char proto; // 1 byte
unsigned short len; // 2 bytes
};
/* Total = 4+4+1+1+2 = 12 bytes */

正如我所说,出于我的目的,此函数计算 20 字节长的 TCP 标头的校验和。

感谢您的任何帮助或建议。

@RonMaupin关于查看RFC的建议以及其他所有人对进一步理解TCP(以及一般的C!(的贡献帮助我解决了我的问题。谢谢!

最新更新