我想补充一点,你也可以使用原始套接字。
scapy是一个很好的抽象层,它为你做了很多神奇的事情,但平心而论,如果你要走低,你可以一直走下去以获得学习体验。(请注意,在大多数现代操作系统中,原始套接字需要提升权限,并且随着您的深入,实现可能会因 Windows 和 Linux 而异。)
import socket
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003))
这将为您提供一个基于原始数据包的套接字,该套接字实际上为您提供所有帧。Windows 和 Linux 之间有所不同,但我会在这个答案中坚持使用 Linux。另请注意,此套接字可能不会拾取所有传出数据包,如果您需要该功能(嗅探内容),请考虑搜索与混杂模式相关的命中。
您现在需要做的就是将每个数据包视为它们进入或进入的段,例如 - 解包以太网和 IP 帧将如下所示:
frame, meta = s.recvfrom(65565)
print(frame, meta)
ethernet = frame[0:14]
ethernet_segments = struct.unpack("!6s6s2s", ethernet)
mac_source, mac_dest = (binascii.hexlify(mac) for mac in ethernet_segments[:2])
ip = frame[14:34]
ip_segments = struct.unpack("!12s4s4s", ip)
ip_source, ip_dest = (socket.inet_ntoa(section) for section in ip_segments[1:3])
print('MAC Source:', b':'.join(mac_source[i:i+2] for i in range(0, len(mac_source), 2)))
print('MAC Dest:', b':'.join(mac_dest[i:i+2] for i in range(0, len(mac_dest), 2)))
print('IP Source:', ip_source)
print('IP Dest:', ip_dest)
考虑到您自己构建数据包,有效负载将是“容易的”。
不管它不是最传统的方式或最初最快的方式,但你可以实现你想要的任何东西。
发送同样简单,使用struct并查看许多 ICMP 示例,包括具有校验和计算的示例:
关于 MTU,这是您必须自己实现的逻辑,因为据我所知,没有预先构建的库可以做到这一点。
但这是我对使用 Python 发送原始 IP 流量的贡献。