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
: