Ping 的“往返时间”存储在 IP 标头中的何处?

网络工程 协议理论 国际会议
2021-07-26 19:49:30

如果我们使用 ICMP's ping,我们知道 TTL 并round-trip time存储在 IP 标头中。在下面的 IP 标头映射中,我们知道 TTL 的位置,但往返时间在哪里?

在此处输入图片说明

它存储在Options?

2个回答

往返时间实际上并未存储在任何地方。发送主机使用 ICMP 的 16 位标识符和序列字段记住它发送每个 ICMP Echo Request 消息的时间。当它得到ICMP Echo Reply时,记下当前时间,找到它发送该回复标识的匹配Request报文的时间,计算差值,并上报。

通常 ping 使用 ICMP 的标识字段来区分多个同时进行的 ping,并使用序列字段来区分单个数据包。

由实现决定将给定数据包的传出时间存储在何处:而不是将其存储在主机上的表中,它通常在传出请求中发送它,并在回复中使用副本来计算时间。(感谢评论者指出这一点。)它以任何便于实施的方式发送,当然必须信任远端和任何介入设备,以正确复制数据。已知一些系统以 16 字节的微秒分辨率表示时间,有些系统以毫秒的分辨率表示 8 字节。

dataIP 数据包部分内部的格式是 ICMP Echo Request/Reply 消息,从RFC 792 “Internet 控制消息格式”(p14)复制到此处

Type请求为 8,回复为 0;Code是 0。

    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             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Identifier          |        Sequence Number        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     Data ...
   +-+-+-+-+-

附注。需要说明的是,IP 报头的标识字段通常设置为任意值,每个传出数据包都不同,用于重组任何碎片,并且与 ICMP 正文中的任何值都不相同。

此外,虽然定义了一种将时间戳作为选项放入 IP 报头的机制,但这不是 ping 的正常机制,因为很多路由器被配置为不传递某些 IP 选项。请参阅Internet 协议时间戳选项的RFC 781规范。

最后,尽管这里的所有内容都是从 IPv4 的角度编写的,但根据原始问题;但是 IPv6 中的 ping 非常相似,请参阅 ICMPv6 RFC 4443

至少ping对于 Linux上的通用实用程序,发送数据包的时间存储在回显请求数据包的数据部分中,即在 IP 和 ICMP 标头之后。当接收方以回声回复回复时,数据部分保持完整,因此发送方可以计算往返时间。

实用程序手册页中ping对此进行了描述(在“ICMP PACKET DETAILS”下):

如果数据空间至少是struct timevalping的大小,则使用该空间的开始字节来包括它在计算往返时间时使用的时间戳。如果数据空间较短,则不会给出往返时间。

在我的机器上sizeof(struct timeval)是 16,因此将数据包数据大小设置为 15 可以防止ping显示往返时间:

$ ping -s 15 8.8.8.8 
PING 8.8.8.8 (8.8.8.8) 15(43) bytes of data.
23 bytes from 8.8.8.8: icmp_seq=1 ttl=121

当然,正如@jonathanjo 的回答所描述的那样,将发送时间戳存储在实用程序中也是一种可能的实现。甚至 Linux 实用程序也需要一些内部簿记,因为它会检测重复的数据包。