使用 tcpdump 进行分段和数据包大小

使用 tcpdump 进行分段和数据包大小

我试图理解碎片的概念:

我有两台具有公共 IP 的虚拟机,连接到交换机。

tracepath 显示数据包未通过网关

来自 vm1:尝试向 vm2 发送 65507 字节的 icmp。

ping -M want -s 65507 vm2 

但在 vm2 上的 tcpdump 输出中显示

tcpdump -evvv icmp

12:48:44.635551 42:43:30:b4:89:0c (oui Unknown) > b6:7a:6b:7d:54:32 (oui Unknown), ethertype IPv4 (0x0800), length 1514: (tos 0x0, ttl 64, id 10843, offset 1480, flags [+], proto ICMP (1), length 1500)
VM1 > VM2: icmp
12:48:44.635568 42:43:30:b4:89:0c (oui Unknown) > b6:7a:6b:7d:54:32 (oui Unknown), ethertype IPv4 (0x0800), length 1514: (tos 0x0, ttl 64, id 10843, offset 2960, flags [+], proto ICMP (1), length 1500)
VM1 > Vm2: icmp
12:48:44.635572 42:43:30:b4:89:0c (oui Unknown) > b6:7a:6b:7d:54:32 (oui Unknown), ethertype IPv4 (0x0800), length 1514: (tos 0x0, ttl 64, id 10843, offset 4440, flags [+], proto ICMP (1), length 1500)
VM1>VM2 icmp
12:48:44.635575 42:43:30:b4:89:0c (oui Unknown) > b6:7a:6b:7d:54:32 (oui Unknown), ethertype IPv4 (0x0800), length 1514: (tos 0x0, ttl 64, id 10843, offset 5920, flags [+], proto ICMP (1), length 1500)
VM1>VM2: icmp
12:48:44.635578 42:43:30:b4:89:0c (oui Unknown) > b6:7a:6b:7d:54:32 (oui Unknown), ethertype IPv4 (0x0800), length 1514: (tos 0x0, ttl 64, id 10843, offset 7400, flags [+], proto ICMP (1), length 1500)
**Vm1 > VM2**: icmp
12:48:44.635581 42:43:30:b4:89:0c (oui Unknown) > b6:7a:6b:7d:54:32 (oui Unknown), ethertype IPv4 (0x0800), length 1514: (tos 0x0, ttl 64, id 10843, offset 8880, flags [+], proto ICMP (1), length 1500)

重复此操作 31 次,直到完全收到。完整粘贴:http://pastebin.com/cnQhn8dK

那么为什么看起来接收的总数据量是1500*31=46500 字节发生了什么事65507-46500=19007 字节

有人可以澄清这一点吗?

答案1

是的,使用带 -s 选项的 tcpdump,结果现在正确了。正如您的结果,我们计算了 45 个数据包。44 个数据包有 1500 字节,1 个数据包有 415 字节。

44*1500+415=66415

66415-65507 = 908

908/45=20加8

您可以看到,每个数据包为第一个数据包添加 20 字节的 ip 头 + 8 字节的 icmp 头。

答案2

补充一下Gnouc 的回答。

您正在发送65507字节数据。这不包括 8 个字节的 ICMP 标头。

最常见的 MTU 大小是1500。此大小占第 3 层大小,这就是您所看到的,ethertype IPv4 (0x0800), length 1514:这意味着总帧大小实际上是 1514 字节。这 14 个字节占以太网报头。每个 mac 地址 12 个字节 + 2 个用于类型。

IP 标头的最小和最常见大小为 20 字节(最大为 60 字节)。

因此我们有

1514 bytes - Ethernet header = 1500 bytes
1500 - IP header = 1480 bytes
1480 - ICMP header = 1472 bytes

您最多可以发送 1472 个字节而不会产生碎片。

但是 IP 对数据包进行分段的方式不需要为每个数据包发送报头,而只需要发送第一个数据包的报头。

经过分段后,在 MTU 为 1500 的情况下您可以发送的最大字节数为 1480 字节。

我们知道您的数据的总大小以及您可以发送的最大数据量。

因此,至少需要65507 / 1480 ~= 44.2 packets。即 44 个 1514 的数据包,然后最后一个数据包的大小小于其一半。

其余的数据包怎么样了?

但为什么是 31 个数据包?这全在于你捕获的缓冲区大小。在 tcpdump 的末尾,你应该看到

31 packets captured 
57 packets received by filter
14 packets dropped by kernel

如果您添加捕获的数据包 + 内核丢弃的数据包,您将得到正确的答案,这就是-s它改变快照长度的原因。

来自tcpdump 手册

-s 从每个数据包中截取 snaplen 字节的数据,而不是默认的 65535 字节。由于快照有限而被截断的数据包在输出中用“[|proto]”表示,其中 proto 是发生截断的协议级别的名称。请注意,获取更大的快照会增加处理数据包所需的时间,并有效地减少数据包缓冲量。这可能会导致数据包丢失。您应该将 snaplen 限制为可捕获您感兴趣的协议信息的最小数字。将 snaplen 设置为 0 会将其设置为默认值 65535,以便与最近的旧版本的 tcpdump 向后兼容。

为什么内核首先丢弃数据包?

再次引用 tcpdump 手册页

内核丢弃的数据包(这是由于缓冲区空间不足而由运行 tcpdump 的操作系统中的数据包捕获机制丢弃的数据包数量,如果操作系统将该信息报告给应用程序;如果没有,则将报告为 0)。

相关内容