简体   繁体   中英

My TCP checksum function returns 0 for most of the packets

I'm writing a small program to sniff the traffic and recalculate TCP checksum to verify. For most of the HTTP packets, my program returns checksum as zero.

What I had done is construct a buffer by PSEUDO_TCP_HEADER | TCP_HEADER | TCP_PAYLOAD. The Pseudo TCP Header is a struct defined by:

struct pseudo_tcp
{
    unsigned long saddr, daddr;
    unsigned char mbz;
    unsigned char ptcl;
    unsigned short tcpl;
};

Then I call this function to calculate the checksum (I believe this function does the right job as it had been used by a lot of projects):

unsigned short in_cksum(unsigned short *addr,int len)
{
    register int sum = 0;
    u_short answer = 0;
    register u_short *w = addr;
    register int nleft = len;

        /*!
    * 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);
}

To make it easier to test, I managed to dump the buffers into file, and here are two samples of buffer that leads the checksum to 0:

$ hexdump -C buffer.out
00000000  c0 a8 01 2c ad c2 26 92  00 06 00 a5 d5 90 00 50  |...,..&........P|
00000010  fa 2a 96 7b 56 9c 7c 27  50 18 40 00 ab 9f 00 00  |.*.{V.|'P.@.....|
00000020  47 45 54 20 2f 20 48 54  54 50 2f 31 2e 31 0d 0a  |GET / HTTP/1.1..|
00000030  55 73 65 72 2d 41 67 65  6e 74 3a 20 63 75 72 6c  |User-Agent: curl|
00000040  2f 37 2e 32 34 2e 30 20  28 78 38 36 5f 36 34 2d  |/7.24.0 (x86_64-|
00000050  61 70 70 6c 65 2d 64 61  72 77 69 6e 31 32 2e 30  |apple-darwin12.0|
00000060  29 20 6c 69 62 63 75 72  6c 2f 37 2e 32 34 2e 30  |) libcurl/7.24.0|
00000070  20 4f 70 65 6e 53 53 4c  2f 30 2e 39 2e 38 72 20  | OpenSSL/0.9.8r |
00000080  7a 6c 69 62 2f 31 2e 32  2e 35 0d 0a 48 6f 73 74  |zlib/1.2.5..Host|
00000090  3a 20 77 77 77 2e 67 6f  6f 67 6c 65 2e 63 6f 6d  |: www.google.com|
000000a0  0d 0a 41 63 63 65 70 74  3a 20 2a 2f 2a 0d 0a 0d  |..Accept: */*...|
000000b0  0a                                                |.|
000000b1

$ hexdump -C buffer1.out 
00000000  c0 a8 01 2c c7 3b 96 07  00 06 00 a2 de 35 00 50  |...,.;.......5.P|
00000010  a1 95 ce 03 c4 f9 f0 1a  50 18 ff ff e7 7a 00 00  |........P....z..|
00000020  47 45 54 20 2f 20 48 54  54 50 2f 31 2e 31 0d 0a  |GET / HTTP/1.1..|
00000030  55 73 65 72 2d 41 67 65  6e 74 3a 20 63 75 72 6c  |User-Agent: curl|
00000040  2f 37 2e 32 34 2e 30 20  28 78 38 36 5f 36 34 2d  |/7.24.0 (x86_64-|
00000050  61 70 70 6c 65 2d 64 61  72 77 69 6e 31 32 2e 30  |apple-darwin12.0|
00000060  29 20 6c 69 62 63 75 72  6c 2f 37 2e 32 34 2e 30  |) libcurl/7.24.0|
00000070  20 4f 70 65 6e 53 53 4c  2f 30 2e 39 2e 38 72 20  | OpenSSL/0.9.8r |
00000080  7a 6c 69 62 2f 31 2e 32  2e 35 0d 0a 48 6f 73 74  |zlib/1.2.5..Host|
00000090  3a 20 74 77 69 74 74 65  72 2e 63 6f 6d 0d 0a 41  |: twitter.com..A|
000000a0  63 63 65 70 74 3a 20 2a  2f 2a 0d 0a 0d 0a        |ccept: */*....|
000000ae

In the first buffer, first four bytes represent source IP address (c0 a8 01 2c -> 192.168.1.44), next four bytes represent destination IP address (ad c2 26 92 -> 173.194.38.146) and so on ...

Is there anything wrong in the calculation or the way I construct the buffer ?

UPDATE : This is the testing code that I use to read from the file and calculate the TCP checksum

  int c,i=0;
  char buffer[1000];
  FILE *file; 
  file = fopen("buffer.out", "r");
  if (file) 
  {
    while ((c = getc(file)) != EOF)
        buffer[i++] = c;
    fclose(file);
  }
  printf("CSUM = %hu\n", in_chksum((unsigned short *  ) buffer, i));

The code looks correct except I don't see that you are zeroing out the checksum in the header. Here is some code to do the same thing from the winpcap mailing list and you can see in the TCPCheckSum() function they are zeroing out the tcp header checksum field first: tcph->Chksum=0 :

[Winpcap-users] TCP Checksum Calculation

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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