作者:闌珊脃_ | 来源:互联网 | 2023-08-20 11:48
我想读取由 tcpdump 生成的 pcap 文件,该文件包含经过IPV4 分片的大型 UDP 数据包。原始数据包的大小约为 22000 字节。
在 C++ 中,我会使用 libtins 和它的 IPV4Reassembler。有没有办法在 Rust 中做类似的事情?
目前在 Rust 中,这是我到目前为止所写的内容:高度不完整的第一次尝试(使用 crate pnet
):
use pnet::packet::{
ethernet::{EtherTypes, EthernetPacket},
ip::IpNextHeaderProtocols,
ipv4::Ipv4Packet,
udp::UdpPacket,
Packet,
};
struct Ipv4Reassembler {
cap: pcap::Capture,
}
impl Iterator for Ipv4Reassembler {
type Item = Vec;
fn next(&mut self) -> Option {
let mut payload = Vec::::new();
while let Some(packet) = self.cap.next().ok() {
// todo: handle packets other than Ethernet packets
let ethernet = EthernetPacket::new(packet.data).unwrap();
match ethernet.get_ethertype() {
EtherTypes::Ipv4 => {
let ipv4_packet = Ipv4Packet::new(ethernet.payload()).unwrap();
// dbg!(&ipv4_packet);
// todo: discard incomplete packets
// todo: construct header for reassembled packet
// todo: check id, etc
let off: usize = 8 * ipv4_packet.get_fragment_offset() as usize;
let end = off + ipv4_packet.payload().len();
if payload.len() payload.resize(end, 0);
}
payload[off..end].clone_from_slice(ipv4_packet.payload());
if ipv4_packet.get_flags() & 1 == 0 {
return Some(payload);
}
}
_ => {}
}
}
None
}
}
fn main() {
let pcap_path = "os-992114000702.pcap";
let reass = Ipv4Reassembler {
cap: pcap::Capture::from_file(&pcap_path).unwrap(),
};
for payload in reass {
let udp_packet = UdpPacket::new(&payload).unwrap();
dbg!(&udp_packet);
dbg!(&udp_packet.payload().len());
}
}
在 C++ 中,这是我将使用的代码(使用 libtins):
#include
#include
#include
#include
#include
#include
#include
#include
void read_packets(const std::string &pcap_filename) {
Tins::IPv4Reassembler reassembler;
Tins::FileSniffer sniffer(pcap_filename);
while (Tins::Packet packet = sniffer.next_packet()) {
auto &pdu = *packet.pdu();
const Tins::Timestamp ×tamp = packet.timestamp();
if (reassembler.process(pdu) != Tins::IPv4Reassembler::FRAGMENTED) {
const Tins::UDP *udp = pdu.find_pdu();
if (!udp) {
continue;
}
const Tins::RawPDU *raw = pdu.find_pdu();
if (!raw) {
continue;
}
const Tins::RawPDU::payload_type &payload = raw->payload();
std::cout <<"Packet: " < // do something with the reassembled packet here
}
}
}
int main() {
const std::string pcap_path = "os-992114000702.pcap";
read_packets(pcap_path);
}
g++ -O3 -o pcap pcap.cpp -ltins
似乎一种解决方案是实现RFC815,但我不确定如何在 Rust 中做到这一点。我已经找到:
- 这个旧的 smolltcp 拉取请求,但它似乎已被放弃。
- Fuschia reassembly.rs但我不知道如何在 Fuschia 之外使用它。