以Python发送自定义帧/数据包

4

我阅读了很多文章,发现可以使用socket(AF_INET, SOCK_RAW, IPPROTO_RAW)发送基于IP的自定义数据包。但是我想要从以太网头开始发送完全自定义的数据包。如果我无法形成以太网头,就无法发送ARP数据包,因为ARP不基于IP。请帮忙! P.S. 我在Windows 7上,不是Linux :(


socket.AF_PACKET 是你要找的,它是否可用取决于你的操作系统,至少过去是这样。 - jedwards
2个回答

3
在Python中,最简单的方法是使用跨平台的Scapy库。它因此而闻名。 Scapy 您可以嗅探、发送... 大量数据包,添加自己的协议,使用现有的协议... 它可以在几乎所有平台上运行。(在Windows上,它使用Npcap/Winpcap)
然后,您可以使用该库构建一个ARP数据包。
from scapy.all import *
pkt = ARP()
pkt.show()
sendp(Ether(dst=..., src=...)/pkt)

这将创建这样的数据包。
###[ ARP ]###
hwtype= 0x1
ptype= 0x800
hwlen= 6
plen= 4
op= who-has
hwsrc= 00:50:56:00:1e:3d
psrc= 212.83.148.19
hwdst= 00:00:00:00:00:00
pdst= 0.0.0.0

构建数据包,使用 / 运算符。
ether = Ether()
ether.src = “00:00:00:00:00:00ether.dst = “ff:ff:ff:ff:ff:ff”
arp = ARP()
[edit arp.psrc, arp.pdst, arp.hwsrc, arp.hwdst]
packet = ether/arp
sendp(packet) # sens packet on layer 2

请查看它的Scapy文档

谢谢!我已经使用过Scapy,但是我没有尝试在我的程序中导入它。 - Denys Malovanyi

0

当然,没有跨平台的方法可以做到你想要的。

Python只是将这些值传递给底层的C API。因此,在具有完整BSD套接字API(包括packet接口)的平台上,您可以使用AF_PACKET和其他适当的标志。(我认为您应该使用ETH_P_ALLETH_P_802_2而不是IPPROTO_RAW,或者您可能需要SOCK_DGRAM...无论如何,请阅读您平台的man packet并根据实际需要进行设置。)在Linux上,至少大多数这些标志应该在SOCKET模块上可用;在其他Unix上,它们通常不会被捡起,因此您必须手动查找系统头文件中的标志并在代码中使用硬编码的常量int。

不幸的是,如果你使用的是Windows系统,这并没有什么好处。虽然WinSock有一个称为TCP/IP原始套接字的功能,通过SOCK_RAW访问,而且Python的最新版本确实公开了这个功能,但它只是对实际BSD套接字实现的一小部分进行仿真,并且没有提供任何进入IP层以下的方法(因此该功能被命名为这个名称)。

微软的解决方案曾经是,你可以使用DDK编写一个TDI提供程序,该提供程序将实现您想要公开的任何协议作为另一个WinSock协议,然后您的应用程序级代码就可以像使用TCP等协议一样使用该协议。从上面链接的文档中看来,这已经过时了,但替代方案似乎是相同的想法,只是缩写不同(并且可能有不同的API)。

另一方面,我很确定Windows已经配备了ARP、ICMP和其他任何用户模式工具所需的协议(因为它们显然不能围绕原始数据包编写)。我只是不确定如何访问它们。


据我所知,通常的替代方法是使用WinPcap
尽管最初设计为数据包捕获库,但其也实现了完整的链路层套接字接口,您可以用于发送和接收原始帧。
而且,它还有Python的包装器,比如WinPcapy
所以,只要你能要求安装WinPcap驱动程序,在Windows上使用Python编写ARP代码等都是可以的。这只是与在Unix上进行的不同。
事实上,WinPcapY首页上的一个示例,“Easy Packet Sending”,应该可以让您开始:
from winpcapy import WinPcapUtils
# Build a packet buffer
# This example-code is built for tutorial purposes, for actual packet crafting use modules like dpkt
arp_request_hex_template = "%(dst_mac)s%(src_mac)s08060001080006040001" \
                           "%(sender_mac)s%(sender_ip)s%(target_mac)s%(target_ip)s" + "00" * 18
packet = arp_request_hex_template % {
    "dst_mac": "aa"*6,
    "src_mac": "bb"*6,
    "sender_mac": "bb"*6,
    "target_mac": "cc"*6,
    # 192.168.0.1
    "sender_ip": "c0a80001",
    # 192.168.0.2
    "target_ip": "c0a80002"
}
# Send the packet (ethernet frame with an arp request) on the interface
WinPcapUtils.send_packet("*Ethernet*", packet.decode("hex"))

谢谢!但我在Windows 7上:( 当我发现AF_PACKET不支持Windows时,我非常失望。我能在C语言上做我想做的吗? - Denys Malovanyi
Windows在底层处理这些事情的方式完全不同,它的SOCK_RAW只是BSD原始套接字API的一部分笨拙模拟,仅足以发送自定义IP头。如果我没记错的话,实现你想要的功能的推荐方法是使用DDK编写协议并通过Winsock公开它,然后你的应用程序代码就可以像处理TCPv4或其他协议一样处理它——除了我认为Winsock已经带有ARP和其他协议,所以你不必再编写它们。但是我已经过时了,对这些东西也有点模糊。 - abarnert
@ДенисМальований 或者,与其走微软的路线,我认为很多人使用WinPcap(https://www.winpcap.org/docs/default.htm)。 - abarnert
经过一番调查,我相信WinCapy是你想要的,而不是挖掘微软的ARP协议或类似的东西。请参见编辑后的答案。 - abarnert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接