Re: IP cheksum and libnet_pblock_coalesce

Wu Yongwei <[email protected]> Thu, 30 Sep 2004 09:23:13 +0800
Newsgroups gmane.comp.security.libnet
Organization Kingnet Security, Inc.
Message-ID <[email protected]>
Unless the checksumming is not intended upon the raw packet content, you
have the wrong test case.  I think it should be like:

main()
{
      char i[] = "\x01\x02\x03";
      unsigned short last = 0, sum, *s = (unsigned short*)i;
      unsigned char *sum_p = (unsigned char*)&sum;

      *(unsigned char*)&last = *(unsigned char*)s;

      printf("last=0x%04x\n", last);

      sum_p[0] = 0x44;
      sum_p[1] = 0x55;
      sum += last;
      printf("sum=0x%.2x%.2x\n", sum_p[0], sum_p[1]);

      sum_p[0] = 0x44;
      sum_p[1] = 0x55;
      sum += (*(unsigned char*)s & 0xff)<<8;
      printf("sum=0x%.2x%.2x\n", sum_p[0], sum_p[1]);
}

This will not change the result on big-endian machines, but will give

last=0x0001
sum=0x4555
sum=0x4456

on little-endian machines.

I did my test on a real packet.  I chose a captured odd-sized UDP packet
and calculated its UDP checksum, and verified that the result should be
zero.  My method passed the test but David's one failed it.

Best regards,

Yongwei

--- Original Message from Frédéric Raynal ---

 > >Hi,
 > >
 > >That is a known (but tricky) bug reported some times ago. David
 > >Baroso proposed something like :
 > >
 > >sum += ((*(u_int8_t *)addr & 0xFF)<<8);
 > >
 > >The difficulty is to find something working on both big and little
 > >endian systems.
 >
 > The expression above seems to work only on big-endian machines and
 > proves wrong in my test on x86 (contrary to Mr David Barroso's
 > statement). The third edition of UNIX Network Programming has
 > something like this (adapted):
 >
 > u_int16_t last_byte = 0;
 > ...
 > if (nleft == 1) {
 >     *(u_int8_t*)&last_byte = *(u_int8_t*)addr;
 >     sum += last_byte;
 > }
 >
 > I feel this is good.
 >

Hi,

I like it ... but I feel there is a problem. Thus, I coded this small
example:

main()
{
		 char i[] = "\x01\x02\x03";
		 unsigned short last = 0, sum = 0x4455, *s = (unsigned
		 		 		 short*)i;


		 *(unsigned char*)&last = *(unsigned char*)s;

		 printf("last=0x%04x\n", last);
		 sum += last;
		 printf("sum=0x%04x\n", sum);

		 sum = 0x4455;
		 sum += (*(unsigned char*)s & 0xff)<<8;
		 printf("sum=0x%04x\n", sum);
}


And here are the results:


On Mac OS X (big endian) :
last=0x0100
sum=0x4555
sum=0x4555

On x86 (little endian):
last=0x0001
sum=0x4456
sum=0x4555

And checksm must be big endian (network ordered) ...

I am not in position to perform tests here, so if some people could do
it, that will be very helpful.

		 Fred Raynal