networking - 如何读取 tcpdump 生成的包含大型 UDP 数据包的 pcap 文件并重新组装 IP 分段数据包?
问题描述
我想读取一个由 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<pcap::Offline>,
}
impl Iterator for Ipv4Reassembler {
type Item = Vec<u8>;
fn next(&mut self) -> Option<Self::Item> {
let mut payload = Vec::<u8>::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() < end {
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 <tins/ip_reassembler.h>
#include <tins/packet.h>
#include <tins/rawpdu.h>
#include <tins/sniffer.h>
#include <tins/tins.h>
#include <tins/udp.h>
#include <iostream>
#include <string>
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<Tins::UDP>();
if (!udp) {
continue;
}
const Tins::RawPDU *raw = pdu.find_pdu<Tins::RawPDU>();
if (!raw) {
continue;
}
const Tins::RawPDU::payload_type &payload = raw->payload();
std::cout << "Packet: " << payload.size() << std::endl;
// 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 之外使用它。
解决方案
推荐阅读
- python - 如何检查变量是否是python中的代码对象
- sql - 我如何编写sql查询来获取结果集,从最大时间获取结果集
- progressive-web-apps - 单击按钮时,如何从渐进式 Web 应用程序切换设备屏幕投射选项?可能吗
- ruby-on-rails - 有没有办法断开控制台消息与 Hyperstack 消息队列的连接?
- javascript - 如何生成具有多个字段作为输入的 Solr 查询
- css - 有没有办法从 CSS 模块导入规则集?
- firebase - 无法在 Firebase Web 中发送或检索数据
- javascript - iframe 不会在生产中加载其所有样式
- elasticsearch - 在elasticsearch中停止节点间通信(不使用防火墙阻止端口)
- json - Flutter:为 Http GET 请求发送 JSON 正文