环境
- Time 2022-11-20
- WSL-Ubuntu 22.04
- Rust 1.65.0
- pnet 0.31.0
- tun-tap 0.1.3
前言
说明
参考:https://docs.rs/pnet/latest/pnet/index.html
目标
通过 ping 命令来认识网络层中的分片。
查看 MTU
可以看到最大的 MTU 为 1500。
root@jiangbo12490:~# ip addr show dev tun0
7: tun0: <NO-CARRIER,POINTOPOINT,MULTICAST,NOARP,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 500
link/none
inet 172.24.49.244/20 scope global tun0
valid_lft forever preferred_lft forever
不分片
其中的 t 参数指定的是生存期,I 参数指定的网卡。
s 指定的是发送数据包的大小,M do 表示禁止分片。
禁止分片的情况下,如果超出了最大的 MTU,会提示错误。
root@jiangbo12490:~# ping -t 44 -I tun0 172.24.49.106 -s 9999 -M do
PING 172.24.49.106 (172.24.49.106) from 172.24.49.244 tun0: 9999(10027) bytes of data.
ping: local error: message too long, mtu=1500
ping: local error: message too long, mtu=1500
ping: local error: message too long, mtu=1500
main.rs
use pnet::packet::ipv4::Ipv4Packet;
use tun_tap::{Iface, Mode};
fn main() -> std::io::Result<()> {
let iface = Iface::without_packet_info("tun0", Mode::Tun)?;
let mut buffer = vec![0; 1500];
loop {
let _size = iface.recv(&mut buffer)?;
let packet = Ipv4Packet::new(&buffer).unwrap();
if packet.get_version() == 6 {
println!("IPv6 packet, continue");
continue;
}
// 第五六个字节,分片标识
println!("Identification: {}", packet.get_identification());
// 第七八个字节,处理分片
// 3 位的标志
// Bit 0: reserved, must be zero 第一位必须为 0
// 可以分片还是不可以分片
// Bit 1: (DF) 0 = May Fragment, 1 = Don’t Fragment.
// 是否还有其余分片还是最后一个分片
// Bit 2: (MF) 0 = Last Fragment, 1 = More Fragments.
// 13 位的偏移,单位是 8 字节
println!(
"Flags: {}, Fragment Offset: {}",
packet.get_flags(),
packet.get_fragment_offset()
);
// 第九个字节,存活周期,为 0 则不被转发
println!("Time to Live: {}", packet.get_ttl());
}
}
程序输出
命令中指定的 ttl 生效了。
所有的包的表示都是 54589,表示它们是同一个包,只是被分片了。
Flags 为 1 表示还有剩余的分片,不是最后一个。最后一个的 Flags 为 0。
第一个分片的偏移从 0 开始,MTU 1500,减去 20 字节的 IP 协议头。
剩下 1480 字节,所以第二个分片的偏移应该从 1480 开始算。
185 * 8 = 1480 刚刚是算出来的偏移量。
Identification: 54589
Flags: 1, Fragment Offset: 0
Time to Live: 44
Identification: 54589
Flags: 1, Fragment Offset: 185
Time to Live: 44
Identification: 54589
Flags: 1, Fragment Offset: 370
Time to Live: 44
Identification: 54589
Flags: 1, Fragment Offset: 555
Time to Live: 44
Identification: 54589
Flags: 1, Fragment Offset: 740
Time to Live: 44
Identification: 54589
Flags: 1, Fragment Offset: 925
Time to Live: 44
Identification: 54589
Flags: 0, Fragment Offset: 1110
Time to Live: 44
抓包
抓包并保存到文件:tcpdump -i tun0 -w ping.pcap
,然后通过 Wireshark 打开。
可以看到分片和重组的信息,其中 Wireshark 的显示偏移是计算后的,不是报文中原始内容。
总结
了解了网络层的分片,分片从网络层开始算,不包含链路层的物理地址和类型。