关于python:如何从ICMP Time Exceeded数据包中恢复数据?

How to get data back from ICMP Time Exceeded packet?

我想做的就是尝试在python中创建自己的小traceroute ...
实际上,我已经做了那么多工作。我想要做的是异步地将traceroutes累积到多个主机。为了做到这一点,我发送包含单个字节的数据包,服务器作为每个跟踪器的唯一ID。问题是,我没有在响应中的任何地方看到这个id。

这是一个简单的测试MCVE我写的用来演示使用一个数据包发送到一个TTL为1的主机:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import socket

# I need two sockets, because I'm sending datagrams
# (to avoid manual packet construction)
# but I'm receiving raw icmp packets
sender = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, proto=socket.IPPROTO_UDP)
receiver = socket.socket(socket.AF_INET, socket.SOCK_RAW, proto=1) # 1 is icmp

sender.setsockopt(socket.SOL_IP, socket.IP_TTL, 1)
sender.sendto(bytes([42]), ("8.8.8.8", 1)) #using google public dns for testing

pkt, addr = receiver.recvfrom(65536)

# The following line raises ValueError
print( pkt.index(42) )

# ... and so would this one
print( pkt.index(bytes([42])) )

所以你看,我只是试图将一个数据包发送到一个TTL为1的主机。我得到一个响应,我已经手动解析了它,足以知道第21个字节是11,并且第22个字节是0 - 表示正确的ttl超过ICMP数据包。它返回的地址也是我在普通traceroute到8.8.8.8中看到的第一个地址

但是,在响应中的任何位置都找不到值为42的字节。我的数据怎么了?根据多个来源,我的原始数据报的数据部分的前8个字节应该包含在响应中,但我似乎无法找到它们中的任何一个。

如果重要的话,我在MacOSX High Sierra上运行Python 3.6.3,我给脚本提供了打开套接字所需的root权限。


我觉得你对返回的内容感到困惑。 返回IP有效载荷的前八个八位字节(IP包中包含的数据报)。 这足够大,包括UDP头(八个八位字节),但没有UDP有效载荷。 包含八个八位字节的目标是,您将拥有TCP或UDP端口号,以便识别发送超出TTL的原始数据包的进程。 这允许IP将消息发送到正确的进程。 这在RFC 792,Internet控制消息协议中有详细说明:

Time Exceeded Message

1
2
3
4
5
6
7
8
9
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Type      |     Code      |          Checksum             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             unused                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Internet Header + 64 bits of Original Data Datagram      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

IP Fields:

Destination Address

The source network and address from the original datagram's data.

ICMP Fields:

Type

11

Code

0 = time to live exceeded in transit;

1 = fragment reassembly time exceeded.

Checksum

The checksum is the 16-bit ones's complement of the one's complement
sum of the ICMP message starting with the ICMP Type. For computing the
checksum , the checksum field should be zero. This checksum may be
replaced in the future.

Internet Header + 64 bits of Data Datagram

The internet header plus the first 64 bits of the original datagram's
data. This data is used by the host to match the message to the
appropriate process. If a higher level protocol uses port numbers,
they are assumed to be in the first 64 data bits of the original
datagram's data.

Description

If the gateway processing a datagram finds the time to live field is
zero it must discard the datagram. The gateway may also notify the
source host via the time exceeded message.

If a host reassembling a fragmented datagram cannot complete the
reassembly due to missing fragments within its time limit it discards
the datagram, and it may send a time exceeded message.

If fragment zero is not available then no time exceeded need be sent
at all.

Code 0 may be received from a gateway. Code 1 may be received from a
host.