This is Interesting: Free IT Magazines Now Free shipping to New York  
TCP/IP - tcp checksum calculation!

This is Interesting: Free IT Magazines  
Home > Archive > TCP/IP > January 2005 > tcp checksum calculation!





You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

Author tcp checksum calculation!
smahesh@gmail.com

2005-01-18, 2:55 am

hi,

i know there have been several questions on tcp hdr checksum and also
the solutions. i have read most of them if not all, but still not able
to figure out the problem. tcp pseudo header seems correct, byte order
seems correct but the checksum is not. same checksum function works for
IP header. i'm also pasting the code. thanks for any help.

pseudo header + tcp header + data segment

0a000824 8cf72212 0006 0028 044200166111aa6900000000a0c216d000000000

020405b40402080a00daf0b30000000001030300


the correct checksum from tcpdump is 7b84. and i get e96d with the
following code.

#include <stdio.h>
#include <sys/types.h>

void fill_buff(char *);

long compute_internet_checksum(unsigned short *, int);
unsigned short ip_checksum(u_short *ip, int len);

int main()
{
char bf[52];
u_short csum = 0;

fill_buff(bf);

csum = compute_internet_checksum((u_short *)bf, 52);
printf("\n csum = %x, expected: c8b1, d32c\n", csum);

csum = ip_checksum((u_short *)bf, 52);
printf("\n csum = %x, expected: c8b1, d32c\n", csum);

return 0;
}

/* calculates the ip hdr checksum */
unsigned short ip_checksum(u_short *ip, int len)
{
register long sum = 0; /* assume 32 bit long, 16 bit short */

while (len > 1) {
sum += *((unsigned short*) ip)++;
if(sum & 0x80000000) /* if high order bit set, fold */
sum = (sum & 0xFFFF) + (sum >> 16);
len -= 2;
}

if(len) /* take care of left over byte */
sum += (unsigned short) *(unsigned char *)ip;

while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);

return ~sum;
}

long compute_internet_checksum(unsigned short *addr, int count)
{
register long sum = 0;

while ( count > 1 ) {
sum += *(unsigned short *)addr++;
count -= 2;
}
if ( count > 0 ) {
sum += *(unsigned char *)addr;
}
while ( sum >> 16 ) {
sum = (sum & 0xffff) + (sum >> 16);
}

return ~sum;
}

void fill_buff(char *buff)
{
buff[0] = 0x0a; buff[1] = 0x00; buff[2] = 0x08; buff[3] = 0x24;
buff[4] = 0x8c; buff[5] = 0xf7; buff[6] = 0x22; buff[7] = 0x12;
buff[8] = 0x00; buff[9] = 0x06; buff[10] = 0x00; buff[11] = 0x28;
buff[12] = 0x04; buff[13] = 0x42; buff[14] = 0x00; buff[15] = 0x16;
buff[16] = 0x61; buff[17] = 0x11; buff[18] = 0xaa; buff[19] = 0x69;
buff[20] = 0x00; buff[21] = 0x00; buff[22] = 0x00; buff[23] = 0x00;
buff[24] = 0xa0; buff[25] = 0xc2; buff[26] = 0x16; buff[27] = 0xd0;
buff[28] = 0x00; buff[29] = 0x00; buff[30] = 0x00; buff[31] = 0x00;
buff[32] = 0x02; buff[33] = 0x04; buff[34] = 0x05; buff[35] = 0xb4;
buff[36] = 0x04; buff[37] = 0x02; buff[38] = 0x08; buff[39] = 0x0a;
buff[40] = 0x00; buff[41] = 0xda; buff[42] = 0xf0; buff[43] = 0xb3;
buff[44] = 0x00; buff[45] = 0x00; buff[46] = 0x00; buff[47] = 0x00;
buff[48] = 0x01; buff[49] = 0x03; buff[50] = 0x03; buff[51] = 0x00;
}


thanks
-mahesh

nobody

2005-01-19, 7:49 am

smahesh at gmail dot com wrote:
>thanks for the prompt reply. actually the code that i pasted has 2
>functions and the 2nd one is taken from the RFC 1071. i get the same
>result with both functions.


my results (from an ab initio calculation using my own code) agree
with yours, except for the byte order of the checksum. evidently
you are on a little-endian machine, so the lsbyte is what would be
transmitted first. so i have to suspect that the content of the
tcp segment or of the pseudo-header is wrong.

btw, the code you swiped from rfc1071 will produce a wrong result
on a big-endian machine if the buffer has an odd number of bytes.
details are left as an exercise for the reader.

nobody
Walter Roberson

2005-01-19, 7:49 am

In article <1105730617.759885.37240@f14g2000cwb.googlegroups.com>,
<smahesh@gmail.com> wrote:
:i know there have been several questions on tcp hdr checksum and also
:the solutions. i have read most of them if not all, but still not able
:to figure out the problem. tcp pseudo header seems correct, byte order
:seems correct but the checksum is not.

:the correct checksum from tcpdump is 7b84.

Is it possible that you are using a system that has offloaded checksum
calculation to the NIC? If so and you sniff on the transmitting side then
the checksum calculation won't have been done yet and the wrong
checksum might be reported.

:long compute_internet_checksum(unsigned short *, int);

That should be unsigned short not 'long'.

:unsigned short ip_checksum(u_short *ip, int len);

:u_short csum = 0;

:csum = compute_internet_checksum((u_short *)bf, 52);

See, you store the returned value into a u_short, so if a long really
were returned then the rest of it would get thrown away.

:printf("\n csum = %x, expected: c8b1, d32c\n", csum);

I don't know why you are pretting two values in the "expected" area
there?

I also don't know why the value you print out as being "expected"
differs from the value you said that tcpdump reported?

:sum += *((unsigned short*) ip)++;

Doesn't compile cleanly. With the outer () there, the value isn't
modifiable. Take out the outer (),

sum += *(unsigned short*) ip++;

:return ~sum;

Compiler warns about loss of precision. Try

return (unsigned short) ~sum;


:long compute_internet_checksum(unsigned short *addr, int count)

Again, should be unsigned short.

:return ~sum;

Ditto about loss of precision.


For what it's worth, I get the same output (except byte-swapped)
on my system with the [touched up] code.
--
Usenet is one of those "Good News/Bad News" comedy routines.
smahesh@gmail.com

2005-01-20, 6:03 pm

thanks for the prompt reply. actually the code that i pasted has 2
functions and the 2nd one is taken from the RFC 1071. i get the same
result with both functions.

Linkage






Free braindumps | Software forum | Database administration forum

Copyright 2003 - 2006 webservertalk.com