我想补充一点,你也可以使用原始套接字。
scapy 是一个很好的抽象层,它为你做了很多魔法,但公平地说,如果你打算走低你可以一路走来获得学习经验。 (请注意,在大多数现代操作系统中,原始套接字需要提升权限,并且随着您的深入,Windows 和 Linux 的实现可能会有所不同。)
import socket
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003))
这将为您提供一个基于原始数据包的套接字,该套接字实际上会为您提供所有帧。它在 Windows 和 Linux 之间有所不同,但我会在这个答案中坚持使用 Linux。另请注意,此套接字可能不会接收所有传出数据包,如果您需要该功能(嗅探内容),请考虑搜索 promiscuous mode 相关命中。
您现在需要做的就是将每个数据包视为它们进入或进入的段,例如 - 解压缩以太网和 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 流量的贡献。