📜  路径 mtu 发现 (1)

📅  最后修改于: 2023-12-03 15:12:15.424000             🧑  作者: Mango

路径 MTU 发现

在计算机网络中,MTU(最大传输单元)是指一个通信协议的数据包能够传输的最大长度,通常以字节为单位。MTU 的大小是由链路层和网络层共同协商决定的,但在某些情况下,需要进行路径 MTU 发现,以确定路径上能够正常传输的最大 MTU 大小。

背景

首先,我们需要知道,当 TCP/IP 协议栈在发送数据报时,IP 层会对数据报进行分片(fragmentation),将其分成若干个 MTU 以下的小数据包进行传输,然后再在接收端重新组装。这个过程较为费时、占用带宽,而且可能会造成 IP 包重组失败,从而导致数据丢失。

为了避免这个问题,TCP/IP 协议栈需要限制每个数据报的大小,以尽量避免分片。而这个大小等于路径上能够正常传输的最大 MTU 大小减去 IP 头的长度和 TCP 头的长度,也就是说:

数据报大小 ≤ 最大 MTU - IP 头长度 - TCP 头长度

如果我们能够确定路径上能够正常传输的最大 MTU 大小,就可以避免分片问题,提高传输效率。

路径 MTU 发现原理

路径 MTU 发现就是一种通过探测路径上的 MTU 大小来确定最大 MTU 大小的技术。这个过程大致如下:

  1. 发送端发送一个标志位设置为“禁止分片”的 IP 数据包到目的地。
  2. 如果 MTU 大小小于数据包的大小,则该数据包会被路由器捕获并且发回一个“ICMP需要分片”,同时返回其 MTU 大小。
  3. 发送端接收到这个"ICMP需要分片",就知道 MTU 大小,并通过不断调整数据包的大小来逼近路径上所能支持的最大 MTU 大小。
示例

在 Python 中,我们可以使用scapy库来编写路径 MTU 发现的代码。下面是一个简单的示例:

from scapy.all import *

# 目的地 IP 地址
dst = "www.google.com"

# Ping 命令的负载内容,可以根据需要修改
payload = b"ABCDEFGHIJKLMNOPQRSTUVWXYYZ"

# 发送 IP 数据包,探测路径上的 MTU 大小
for i in range(1400, 1500):
    p = IP(dst=dst, flags="DF")/ICMP()/Raw(load=payload)
    send(p, verbose=False, mtu=i)
    time.sleep(0.1)

我们可以通过逐渐递增数据包的大小,来探测路径上的 MTU 大小。当程序输出结果时,我们可以找到一个 MTU 大小,其后的数据包开始出现“ICMP需要分片”的错误,就可以确定路径上能够正常传输的最大 MTU 大小了。

详细的代码和运行结果可以参考这个代码片段