Я прочитал много статей и нашел, как отправлять пользовательские пакеты на основе IP, используя сокет (AF_INET, SOCK_RAW, IPPROTO_RAW). Но я хочу отправить полностью настраиваемый пакет, начиная с заголовка Ethernet. Я не могу отправить пакет ARP, если я не могу сформировать заголовок Ethernet, поскольку ARP не использует IP. Пожалуйста помоги! PS Я на Windows 7, а не на Linux :(
В python самым простым способом является использование кросс-платформенной библиотеки scapy. Хорошо известно, что
Вы можете нюхать, отправлять... много пакетов, добавлять свои собственные протоколы, использовать существующие... и работает почти на всех платформах. (В окнах используется 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: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
Взгляните на документацию Scapy
Конечно, нет кросс-платформенного способа делать то, что вы хотите.
Python просто передает эти значения в базовый C API. Таким образом, на платформе с полным API-интерфейсом BSD, включая packet
интерфейс, вы можете просто использовать AF_PACKET
и другие соответствующие флаги. (Я думаю, вы бы хотели ETH_P_ALL
или ETH_P_802_2
а не IPPROTO_RAW
, или вы могли бы хотеть SOCK_DGRAM
... в любом случае, прочитайте свой man packet
платформы и определите его на основе того, что вам действительно нужно делать.) В Linux по крайней мере большинство этих флагов должен быть доступен в модуле SOCKET
; на других Unix, их часто не получают, поэтому вы должны вручную искать их в заголовках системы и использовать жестко закодированные константы в вашем коде.
К сожалению, если вы работаете в Windows, это не приносит пользы. В то время как у WinSock есть функция, они называют TCP/IP Raw Sockets, доступ к которым осуществляется через SOCK_RAW
, а последние версии Python действительно раскрывают это, это просто эмуляция небольшого подмножества того, что могут делать реальные реализации сокетов BSD, и никоим образом не предлагает идти ниже уровня IP (отсюда и название функции).
Решение Microsoft для этого заключалось в том, что вы должны написать провайдер TDI с DDK, который будет реализовывать любой протокол, который вы хотели бы представить в качестве другого протокола WinSock, а затем ваш код на уровне приложения мог бы использовать этот протокол так же, как и использовать, например, TCP. Из связанного документа выше, похоже, что это устарело, но замена похожа на ту же идею, но с разными аббревиатурами (и, предположительно, с разными API).
С другой стороны, я уверен, что Windows уже поставляется с протоколами ARP, ICMP и любыми другими протоколами, необходимыми для его инструментов usermode (потому что они, очевидно, не могут быть написаны вокруг сырых пакетов). Я просто не знаю, как получить к ним доступ.
Насколько я знаю, обычной альтернативой является использование WinPcap.
Хотя это было первоначально разработано как библиотека захвата пакетов, в нем также реализован полный интерфейс сокета уровня ссылки, который вы можете использовать для отправки и приема необработанных кадров.
И для него есть обертки Python, такие как WinPcapy.
Поэтому, пока вы можете потребовать установки драйвера WinPcap, вы можете написать код ARP и т.д. В Windows на Python. Это просто отличает его от Unix.
На самом деле, один из примеров на первой странице WinPcapY, "Easy Packet send", должен начать вас:
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
- это просто неуклюжая эмуляция части API-интерфейса raw сокетов BSD, которой достаточно для отправки пользовательских заголовков IP. IIRC, рекомендуемый способ сделать то, что вы хотите, это использовать DDK для написания протокола и предоставления его через Winsock, а затем код вашего приложения просто обрабатывает его так же, как они обращались бы с TCPv4 или чем-то еще, за исключением того, что я думаю, что Winsock уже поставляется с ARP и другими протоколами, поэтому вам не нужно их писать. Но я уже давно устарел и запутался в этом.