環境
- Time 2022-11-24
- 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 793
目標
瞭解 TCP 協議頭中的欄位,其也是基於 IP 協議的。
配置 TUN
IP 地址不要和主機的網路卡地址在一個段,以便選擇這個網路卡進行路由。
root@jiangbo12490:~# ip tuntap add tun0 mode tun
root@jiangbo12490:~# ip addr add 192.168.44.144/24 dev tun0
root@jiangbo12490:~# ip link set up dev tun0
root@jiangbo12490:~# ip add 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 192.168.44.144/24 scope global tun0
valid_lft forever preferred_lft forever
main.rs
use pnet::packet::ip::IpNextHeaderProtocols;
use pnet::packet::{ipv4::Ipv4Packet, tcp::TcpPacket};
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::Tcp {
println!("not tcp packet, continue");
continue;
}
// 因為頭部長度的單位是 4 位元組
let length = packet.get_header_length() as usize * 4;
let packet = TcpPacket::new(&buffer[length..]).unwrap();
// 2 位元組的源埠
println!("source {}", packet.get_source());
// 2 位元組的目的埠
println!("destination {}", packet.get_destination());
// 4 位元組的序列號號
println!("sequence {}", packet.get_sequence());
// 4 位元組的確認號
println!("acknowledgement {}", packet.get_acknowledgement());
// 4 位 TCP 首部長度,單位是 4 位元組,最長 60 位元組
println!("data_offset {}", packet.get_data_offset());
// 3 位的保留位
println!("reserved {}", packet.get_reserved());
// 9 位的控制位,標誌位
println!("flags {}", packet.get_flags());
// 2 位元組的視窗大小
println!("window {}", packet.get_window());
// 2 位元組的校驗和
println!("checksum {}", packet.get_checksum());
// 2 位元組的緊急指標
println!("urgent_ptr {}", packet.get_urgent_ptr());
// TCP 20 位元組的首部,可以加上最長 40 個位元組的選項
println!("options {:?}", packet.get_options());
println!("length: {}, {:?}", size, &buffer[..size]);
}
}
傳送 TCP 請求
當想建立連線時,會發起握手請求,傳送第一個 TCP 資料包。
root@jiangbo12490:~# nc 192.168.44.244 4444
程式輸出
source 35788
destination 4444
sequence 3640119208
acknowledgement 0
data_offset 10
reserved 0
flags 2
window 64240
checksum 41834
urgent_ptr 0
options [TcpOption { number: TcpOptionNumber(2), length: [4], data: [5, 180] }, TcpOption { number: TcpOptionNumber(4), length: [2], data: [] }, TcpOption { number: TcpOptionNumber(8), length: [10], data: [188, 204, 204, 53, 0, 0, 0, 0] }, TcpOption { number: TcpOptionNumber(1), length: [], data: [] }, TcpOption { number: TcpOptionNumber(3), length: [3], data: [7] }]
length: 60, [69, 0, 0, 60, 99, 220, 64, 0, 64, 6, 252, 10, 192, 168, 44, 144, 192, 168, 44, 244, 139, 208, 17, 92, 216, 247, 207, 168, 0, 0, 0, 0, 160, 2, 250, 240, 163, 106, 0, 0, 2, 4, 5, 180, 4, 2, 8, 10, 188, 204, 204, 53, 0, 0, 0, 0, 1, 3, 3, 7]
tcpdump 抓包
root@jiangbo12490:~# tcpdump -A -n -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
20:22:54.371126 IP 192.168.44.144.35788 > 192.168.44.244.4444: Flags [S], seq 3383309069, win 64240, options [mss 1460,sackOK,TS val 3167330987 ecr 0,nop,wscale 7], length 0
E..<q.@.@..B..,...,....\..3.........x..........
............
其中的 flags 和 options 欄位,之後再看。
Wireshark
總結
瞭解了 TCP 協議的欄位,該協議基於 IP 協議。