Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使用ICMP在ICMP数据字段中发送图像_Python_Scapy_Icmp_Tunneling - Fatal编程技术网

Python 如何使用ICMP在ICMP数据字段中发送图像

Python 如何使用ICMP在ICMP数据字段中发送图像,python,scapy,icmp,tunneling,Python,Scapy,Icmp,Tunneling,我正在使用scapy通过ICMP发送数据。我需要使用scapy通过ICMP发送图像和其他文件。我能够在ICMP中发送简单字符串。如何发送图像和其他文件?我想你已经发现了互联网发明者开发TCP的原因。ICMP数据包中的有效负载大小有一个限制。大多数网络对以太网数据包的大小有1500字节的总限制,因此使用20字节IP报头和8字节ICMP报头,单个数据包中的最大有效负载大小将为1472个八位字节。这对于许多图像文件来说是不够的 您需要一种方法,将图像数据流拆分为大小约为该大小的数据块,以多个ICMP数

我正在使用scapy通过ICMP发送数据。我需要使用scapy通过ICMP发送图像和其他文件。我能够在ICMP中发送简单字符串。如何发送图像和其他文件?

我想你已经发现了互联网发明者开发TCP的原因。ICMP数据包中的有效负载大小有一个限制。大多数网络对以太网数据包的大小有1500字节的总限制,因此使用20字节IP报头和8字节ICMP报头,单个数据包中的最大有效负载大小将为1472个八位字节。这对于许多图像文件来说是不够的

您需要一种方法,将图像数据流拆分为大小约为该大小的数据块,以多个ICMP数据包的形式发送它们,然后在接收器上将它们重新组装为数据流

考虑到不能保证ICMP数据包按顺序接收,也不能保证它们都按顺序接收,您需要在单个数据包中放入某种序列号,以便可以按顺序重新组装它们。您可能还需要一些超时逻辑,以便您的接收机器能够确定数据包丢失,从而使映像永远无法完成


RTP和TCP是两种在IP上分层的协议,可以实现这一点。它们都有详细的文档记录,您可以从这些文档中学习如何做您正在尝试做的事情,以及一些陷阱和性能影响。

我不知道scapy,所以我的答案将是算法和纯python

为了发送图像文件,您需要将图像分成块,记住您需要有某种机制来跟踪发送的块的顺序

首先,将图像文件作为二进制文件读取。然后,决定二进制数据应该被分割多少。如果MTU为1500,我建议使用1500-IP头-ICMP头,或1472,以避免IP碎片。此外,我建议使用16位或32位数字来跟踪发送的数据块的顺序,并将其从1500中减去。示例:1500-IP-ICMP-4=1468

使用上面的例子,我会像这样分解图像:

image = file("/path/to/file","rb").read()
chunk = []
interval = 1500 - 20 - 8 - 4
for n in range(0, len(image), interval):
    chunk.append(image[n:n + interval])
现在图像是分块的,我会将跟踪字节添加到每个块中。它可以是前缀或后缀,由您选择。我选择了前缀:

for n in range(len(chunk)):
    chunk[n] = struct.pack(">I", n) + chunk[n]
现在我们已经标记了要跟踪的块,我们需要构建ICMP头,并附加每个块。但我们使用哪种类型/代码?在这个用例中,我们将构建一个ECHO请求数据包(其他类型,如0或3是未经请求的,可能会导致接收内核不将数据包转发给您的ICMP套接字处理程序)。另外,需要注意的一点是:您需要校验和代码来计算ICMP校验和:

要重申,请注意第二个icmp头数据包中的cksum(icmp)参数。此校验和是必需的,否则,如果不正确,接收内核可能不会将数据包转发给任何ICMP套接字处理程序。还要注意第4和第5个参数为零:这些是“标识符”和“序列号”字段。通常,它们用于存储进程ID和增量编号(分别)。套接字对象这样做是为了跟踪哪个套接字发送了什么以及发送了多少。在这个用例中,由于我们正在发送一个未经请求的回音回复,您可以对接收端进行编码,以查找类型0,并在发送的块中进一步查找跟踪字节。因此,现在我将标识符和序列字段保留为零。如果您想知道为什么我构造了两个icmp头,那是因为内核将正确计算的校验和基于初始校验和字段为零

现在,我们有了icmp标头,可以发送:

for i in icmp_chunks:
    [socket].sendto(i, ("hostname-or-ip", 0))
我假定[socket]对象是scapy或您自己的socket对象

在接收端,您读回数据并查找图像有效载荷,将每个有效载荷重建回其原始顺序。然而,您仍然需要一些方法来确定是否所有接收到的块都是它们。在发送图像块之前,可以考虑如何构造一个指示总预期大小的初始字节序列

希望这有帮助

更新:我测试了向UbuntuLinux发送未经请求的Type0数据包,并注意到接收内核没有将数据包传递给我的处理程序。所以我修改了我的解释来解释这一点

for i in icmp_chunks:
    [socket].sendto(i, ("hostname-or-ip", 0))