Re: IP cheksum and libnet_pblock_coalesce
Jari Lansio <[email protected]> Fri, 24 Sep 2004 15:27:56 +0300
| Newsgroups | gmane.comp.security.libnet |
|---|---|
| Message-ID | <[email protected]> |
Hello,
I think my problem _was_ just a misunderstanding from my part. The
pressure is on word "was", because now I think I have found a genuine
bug in checksum code.
This is function libnet_in_cksum() from libnet_checksum.c:
41 int
42 libnet_in_cksum(u_int16_t *addr, int len)
43 {
44 int sum;
45
46 sum = 0;
47
48 while (len > 1)
49 {
50 sum += *addr++;
51 len -= 2;
52 }
53 if (len == 1)
54 {
55 sum += *(u_int16_t *)addr;
56 }
57
58 return (sum);
59 }
Since the type of argument 'addr' is pointer to u_int16_t, it would seem
like this is function is supposed to work only with memory blocks that
have even length.
However, the code at line 53 checks if buffer has odd length. This is
important, because this function is used to calculate checksum for UDP
and TCP too, and they can have odd lengths.
I think that there is bug in on line 55, where 'addr' is casted to
u_int16_t*, the type it already is!!! The problem is that this code
reads 2 bytes from address 'addr', while it should read only one byte.
I changed to line 55 to read like this:
55 sum += *(u_int8_t *)addr;
Now only one byte is read (as the 'len' indicates) and everything seems
to work just fine.
How this bug has not caused any problems before? The only explanation is
that the compilers add 'padding' bytes right after buffers with odd
length, and that padding is always '0', and thus including this padding
to checksum calculation do not change the checksum. However, I used this
code on Symbian platform and guess what, there was no padding and it
failed to get correct checksums for packets that had odd length.
The rfc-1071 has example C code for checksum calculation, and it looks
very similar. It's not perfect example, since it has a bug that prevents
it to compile (missing '*' on line 381), but the relevant lines are:
385 /* Add left-over byte, if any */
386 if( count > 0 )
387 sum += * (unsigned char *) addr;
Notice the cast to u_int8_t.
Am I right? Have I found a real bug, or did I just made myself look
stupid :) I'm on holidays the next week and I won't read my mails until
4th of October.
-jarppe
> Hi jarppe
>
>> Hello everybody,
>>
>> Should libnet_pblock_coalesce() set the IP checksum correctly? I'm
using libnet 1.1.2.1, compiled with GCC 3.2.2 20030222 on Linux.
>>
>> When I create packet using libnet_build_[udp|tcp]() +
libnet_build_ip(), then get the packet using libnet_pblock_coalesce()
and then call libnet_ip_check() over the returned buffer, I get non-zero
reply, indicating wrong IP checksum.
>>
>> Interestingly enough, if I create the packet with
libnet_build_icmpv4_echo() + libnet_build_ip(), then libnet_ip_check()
returns zero (checksum ok).
>>
>> Am I doing something wrong, or is there a bug?
>>
>> -jarppe
>
>
> I had something similar situation. I'm also using libnet 1.1.2.1 with
> GCC (Redhat9).
>
> I also found some wrong checksum packets created by libnet.
> So, I replace the function libnet_in_checksum() (libnet_checksum.c) with
> the same name function of libnet-1.0.2a, there is no wrong packet.
>
> -Kenichi
>