一个底层的网络库,可以查看 数据链路层、网络层、传输层的内容。
use pnet::datalink::{self, Channel::Ethernet};
use pnet::packet::{
ethernet::{EtherTypes, EthernetPacket},
ip::IpNextHeaderProtocols,
ipv4::Ipv4Packet,
tcp::TcpPacket,
Packet,
};
use std::env;
fn main() {
// 从命令行接收一个网卡的名称
let interface_name = env::args().nth(1).unwrap();
// 选择指定名字的链路层显卡
let interfaces = datalink::interfaces();
let interface = interfaces
.into_iter()
.filter(|iface| iface.name == interface_name)
.next()
.expect("error get interface");
// 从链路层创建一个 channel,只使用接收端
let (_tx, mut rx) = match datalink::channel(&interface, Default::default()) {
Ok(Ethernet(tx, rx)) => (tx, rx),
Ok(_) => panic!("Other"),
Err(error) => panic!("error: {}", error),
};
loop {
// 获取链路层的包
match rx.next() {
Ok(packet) => {
let packet = EthernetPacket::new(packet).unwrap();
handle_packet(&packet);
}
Err(e) => println!("error: {}", e),
}
}
}
fn handle_packet(ethernet: &EthernetPacket) {
match ethernet.get_ethertype() {
// 解析链路层协议,忽略 ipv4 以外的其他协议
EtherTypes::Ipv4 => {
let header = Ipv4Packet::new(ethernet.payload());
if let Some(header) = header {
// 解析下一层, 网络层协议
match header.get_next_level_protocol() {
IpNextHeaderProtocols::Tcp => {
let tcp = TcpPacket::new(header.payload());
if let Some(tcp) = tcp {
println!(
"tcp packet {}:{} to {}:{}",
header.get_source(),
tcp.get_source(),
header.get_destination(),
tcp.get_destination()
);
}
}
_ => println!("ignore not tcp"),
}
}
}
_ => println!("ignore not ipv4"),
}
}
执行方式: sudo cargo run --bin pnet en0
注:
- 需要使用 root 权限
- 需要提供一个网卡名字