环境
- 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
RFC 792
目标
了解 UDP 协议的的字段。
从这里开始,将进入第四层,传输层协议。UDP 协议基于 IP 协议。
配置 TUN
IP 地址不要和主机的网卡地址在一个段,以便选择这个网卡进行路由。
root@jiangbo12490:~# ip link delete tun0
root@jiangbo12490:~# ip tuntap add tun0 mode tun
root@jiangbo12490:~# ip addr add 192.168.144.1/24 dev tun0
root@jiangbo12490:~# ip link set up dev tun0
root@jiangbo12490:~# ip addr show dev tun0
8: tun0: <NO-CARRIER,POINTOPOINT,MULTICAST,NOARP,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 500
link/none
inet 192.168.144.1/24 scope global tun0
valid_lft forever preferred_lft forever
main.rs
use pnet::packet::{ip::IpNextHeaderProtocols, ipv4::Ipv4Packet};
use pnet::packet::{udp::UdpPacket, Packet};
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;
}
if packet.get_next_level_protocol() != IpNextHeaderProtocols::Udp {
println!("not udp packet, continue");
continue;
}
// 因为头部长度的单位是 4 字节
let length = packet.get_header_length() as usize * 4;
let packet = UdpPacket::new(&buffer[length..]).unwrap();
// 源端口
println!("source {:?}", packet.get_source());
// 目的端口
println!("get_destination {:?}", packet.get_destination());
// 长度,包含 UDP 头和数据
println!("length {:?}", packet.get_length());
// 校验和
println!("checksum {:?}", packet.get_checksum());
// 数据
let payload = String::from_utf8_lossy(packet.payload());
print!("udp say: {}", payload);
println!("length: {}, {:?}", size, &buffer[..size]);
}
}
发送 UDP 请求
root@jiangbo12490:~# nc 192.168.144.2 4444 -u
jiangbo
程序输出
source 33092
get_destination 4444
length 16
checksum 10644
udp say: jiangbo
length: 36, [69, 0, 0, 36, 164, 101, 64, 0, 64, 17, 245, 14, 192, 168, 144, 1, 192, 168, 144, 2, 129, 68, 17, 92, 0, 16, 41, 148, 106, 105, 97, 110, 103, 98, 111, 10]
源端口是 33092,目的端口 4444,长度 8 字节的 UDP 头加上 8 字节的数据(含换行),共 16 个字节。
查看源端口
root@jiangbo12490:~# ss -un
Recv-Q Send-Q Local Address:Port Peer Address:Port Process
0 0 192.168.144.1:33092 192.168.144.2:4444
tcpdump 抓包
root@jiangbo12490:~# tcpdump -An -i tun0
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
23:42:22.881236 IP 192.168.144.1.33092 > 192.168.144.2.4444: UDP, length 8
E..$.f@[email protected].\..).jiangbo
Wireshark
总结
了解了 UDP 协议的字段,该协议基于 IP 协议,是一个比较简单的协议。