我阅读了很多文章,发现可以使用socket(AF_INET, SOCK_RAW, IPPROTO_RAW)发送基于IP的自定义数据包。但是我想要从以太网头开始发送完全自定义的数据包。如果我无法形成以太网头,就无法发送ARP数据包,因为ARP不基于IP。请帮忙! P.S. 我在Windows 7上,不是Linux :(
我阅读了很多文章,发现可以使用socket(AF_INET, SOCK_RAW, IPPROTO_RAW)发送基于IP的自定义数据包。但是我想要从以太网头开始发送完全自定义的数据包。如果我无法形成以太网头,就无法发送ARP数据包,因为ARP不基于IP。请帮忙! P.S. 我在Windows 7上,不是Linux :(
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:00”
ether.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
当然,没有跨平台的方法可以做到你想要的。
Python只是将这些值传递给底层的C API。因此,在具有完整BSD套接字API(包括packet
接口)的平台上,您可以使用AF_PACKET
和其他适当的标志。(我认为您应该使用ETH_P_ALL
或ETH_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和其他任何用户模式工具所需的协议(因为它们显然不能围绕原始数据包编写)。我只是不确定如何访问它们。
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"))
SOCK_RAW
只是BSD原始套接字API的一部分笨拙模拟,仅足以发送自定义IP头。如果我没记错的话,实现你想要的功能的推荐方法是使用DDK编写协议并通过Winsock公开它,然后你的应用程序代码就可以像处理TCPv4或其他协议一样处理它——除了我认为Winsock已经带有ARP和其他协议,所以你不必再编写它们。但是我已经过时了,对这些东西也有点模糊。 - abarnert
socket.AF_PACKET
是你要找的,它是否可用取决于你的操作系统,至少过去是这样。 - jedwards