使用Python发送原始IP流量:检测MTU

6
如何用Python实现手动MTU发现?
从:https://networkengineering.stackexchange.com/a/28988/23983 发送一个ping到目标,以我的示例为例,我将使用Google的DNS服务器(8.8.8.8)。在ping中设置DF位为on,以防止您的ping被分段。将数据包大小设置为一些较大的数字或标准MTU 1500。请注意,一些ping实现仅设置有效负载的大小,这意味着您必须考虑8字节的ICMP头和20字节的IP头。
2个回答

3

我想补充一下,您也可以使用原始套接字来实现这一点。
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)

考虑到你自己构建数据包,因此负载成型将会很“容易”。尽管这不是最常规的方式或者最初的最快的方式,但你可以实现任何你想要的东西。

发送同样很容易,使用结构体并查看网上的许多ICMP示例,包括那些带有校验和计算的示例:

关于MTU,这是您需要自己实现的逻辑,因为我所知道的没有预构建的库可以实现这一点。
但这是我对使用Python发送原始IP流量的贡献。

1
发送任何原始数据在Python中,您需要使用scapy。关于如何发送ping消息的信息:

http://www.secdev.org/projects/scapy/doc/usage.html#icmp-ping

设置 DF 标志:

IP(flags='DF')

如何调整特定大小以模拟分段:

在数据包中添加负载(Scapy)

将所有内容组合在一起:

data = "x" * 1473
ans,unans = sr(IP(dst="<target_ip>", flags='DF' )/ICMP() / Raw(load=data))

如果您对原始创作并不是非常感兴趣,那么这个问题就是一个重复的问题: 如何通过代码(使用Python)找到网络的MTU值?

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