我一直在尝试计算C中TCP标头的校验和。出于我的目的,TCP标头长20个字节,没有额外的数据或选项。另外,据我所知,TCP校验和计算为头中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 iphdr
和struct 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头的校验和。
感谢您提供任何帮助或建议。
答案 0 :(得分:0)
@ RonMaupin关于检查RFC的建议以及其他所有人的贡献,以进一步理解TCP(以及一般的C语言),这帮助我解决了我的问题。谢谢!