libnet创建了带有无效校验和的UDP数据包

1 投票
3 回答
2689 浏览
提问于 2025-04-15 17:00

我正在使用pylibnet来构建和发送UDP数据包。但是,我用这种方式构建的UDP数据包似乎都有无效的校验和。比如:

# 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() 

在发送主机上捕获到上面的数据包时,发现校验和是无效的:

# 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

我是不是做错了什么?

3 个回答

1

我更新了pylibnet这个库,让它可以自动判断大多数头部信息中长度字段的大小。这样,如果你忘记为需要指定长度的头部设置长度,它会试着自动计算出来。这样可以省去你去搞清楚为什么校验和出错的烦恼;)

1

计算校验和的工作通常不是在用户空间的库中完成,而是在设备驱动程序或硬件中进行。我认为你看到的情况是“校验和卸载”,也就是说,物理设备会在发送的数据包上计算校验和,这样可以节省主机的CPU资源。许多(如果不是全部的话)现代以太网适配器都是这样做的,驱动程序并不计算校验和。因为tcpdump是在驱动程序中捕获数据包的,这些数据包在到达物理设备之前,所以它在校验和字段中得到的只是一些垃圾数据(可能是缓冲区中剩下的内容),因此会出现错误。

在2005到2008年间,有几个关于Wireshark的“错误”被报告,涉及到这个问题。Wireshark(其实就是tcpdump或其Windows版本的图形界面)现在有一个选项,可以在校验和卸载的情况下禁用校验和验证。

http://wiki.wireshark.org/TCP_Checksum_Verification

无论如何,我不认为pylibnet(或libnet)会负责校验和的计算。

另见 http://www.wireshark.org/docs/wsug_html_chunked/ChAdvChecksums.html#id4744523

3

这跟tcpdump的错误或者校验和的卸载没关系。Libnet在用户模式下也会计算校验和(顺便提一下)。问题在于你没有为UDP头指定长度。在pylibnet或libnet中,这个长度不会自动计算,所以你必须自己指定。下面是你代码的修正版本。我会在rc6中对pylibnet进行一个补丁,让它能够自动检测头的长度。请关注http://sourceforge.net/projects/pylibnet以获取更新。我会发布一个新的版本来解决这个问题。对了,如果你有bug或者功能请求,欢迎通过sourceforge的pylibnet页面联系我。我很乐意听到使用我软件的开发者的反馈 :)


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()

撰写回答