C中的TCP校验和

时间:2017-08-17 17:44:54

标签: c networking tcp tshark

我一直在尝试计算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 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头的校验和。

感谢您提供任何帮助或建议。

1 个答案:

答案 0 :(得分:0)

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