libnet creates UDP packets with invalid checksums

2.6k views Asked by At

I'm using pylibnet to construct and send UDP packets. The UDP packets I construct in this way all seem to have invalid checksums. Example:

# python
Python 2.4.3 (#1, Sep  3 2009, 15:37:12)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-46)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 
>>> import libnet
>>> from libnet.constants import *
>>> 
>>> net = libnet.context(RAW4, 'venet0:0')
>>> ip = net.name2addr4('www.stackoverflow.com', RESOLVE)
>>> data = 'This is my payload.'
>>> udptag = net.build_udp(sp=54321, dp=54321, payload=data)
>>> packetlen = IPV4_H + UDP_H + len(data)
>>> iptag = net.autobuild_ipv4(len=packetlen, prot=IPPROTO_UDP, dst=ip)
>>> 
>>> net.write() 

Capturing the above packet on the sending host reveals an invalid checksum:

# tcpdump -i venet0:0 -n -v -v port 54321
tcpdump: WARNING: arptype 65535 not supported by libpcap - falling back to cooked socket
tcpdump: listening on venet0:0, link-type LINUX_SLL (Linux cooked), capture size 96 bytes
08:16:10.303719 IP (tos 0x0, ttl  64, id 1, offset 0, flags [none], proto: UDP (17), length: 47) 192.168.55.10.54321 > 69.59.196.211.54321: [bad udp cksum 50c3!] UDP, length 0

Am I doing something wrong here?

3

There are 3 answers

0
Nadeem Douba On BEST ANSWER

It's nothing to do with tcpdump bugs or checksum offloading. Libnet calculates the checksum in user mode as well (FYI). The problem has to do with the fact that you did not specify a length for the UDP header. This is not automagically calculated in pylibnet or libnet so you have to specify it for the time being. Below is the corrected version of your code. I will apply a patch to pylibnet to automagically detect the header length in rc6. Stay tuned to http://sourceforge.net/projects/pylibnet for updates. I will be pushing a new release fixing this issue. By the way, please feel free to contact me via sourceforge's pylibnet page if you have bug or feature requests. I love to hear from developers using my software :)


import libnet
from libnet.constants import *

net = libnet.context(RAW4, 'venet0:0')
ip = net.name2addr4('www.stackoverflow.com', RESOLVE)
data = 'This is my payload.'
udptag = net.build_udp(len=UDP_H+len(data), sp=54321, dp=54321, payload=data)
packetlen = IPV4_H + UDP_H + len(data)
iptag = net.autobuild_ipv4(len=packetlen, prot=IPPROTO_UDP, dst=ip)

net.write()
2
Jim Garrison On

The job of calculating checksums is usually not performed in the user-space library but at the device driver or in hardware. I believe you are seeing the result of "checksum offloading", where the physical device calculates the checksums on outgoing packets, saving CPU cycles on the host. Many (if not all) modern Ethernet adapters do this, and the drivers do not calculate the checksum. Since tcpdump is capturing the packets in the driver, before they get to the physical device, it just gets garbage in the checksum field (probably what's left over in the buffer) and complains.

There were several "bugs" reported against Wireshark in the 2005-2008 timeframe covering this, and Wireshark (which is just a GUI wrapper on tcpdump or its Windoze equivalent) now has an option to disable checksum validation for the offload case.

http://wiki.wireshark.org/TCP_Checksum_Verification

In any event, I would not expect pylibnet (or libnet) to be responsible for the checksums.

See also http://www.wireshark.org/docs/wsug_html_chunked/ChAdvChecksums.html#id4744523

0
Nadeem Douba On

I have updated pylibnet to include an auto size determination for the length fields in most headers. This way if you forget to specify the length of the header for any of the headers that require it, it will attempt to automagically determine it. Saves you the headache of figuring out why your checksum is bad;)