pub mod handlers;
pub mod protocol_handler;
use crate::protocol_handler::ProtocolHandler;
use netgauze_pcap_reader::PcapIter;
use std::collections::HashMap;
use std::fs::File;
use std::io::{self, BufWriter, Write};
use std::net::IpAddr;
use std::path::PathBuf;
pub const PCAP_BUFFER_SIZE: usize = 165536;
#[derive(Debug, Clone)]
pub struct Config {
pub dest_ports: Vec<u16>,
pub input_size: Option<usize>,
pub pcap_path: PathBuf,
pub output_path: Option<PathBuf>,
pub show_frame_number: bool,
}
pub use handlers::{
bgp::BgpProtocolHandler, bmp::BmpProtocolHandler, flow::FlowProtocolHandler,
udp_notif::UdpNotifProtocolHandler,
};
pub fn load_pcap_and_process<M, C, E, H>(
config: &Config,
handler: &H,
) -> Result<(), Box<dyn std::error::Error>>
where
C: Default,
H: ProtocolHandler<M, C, E>,
{
let pcap_file = File::open(config.pcap_path.as_path()).expect("Failed to open pcap file");
let pcap_reader = Box::new(pcap_parser::LegacyPcapReader::new(
PCAP_BUFFER_SIZE,
pcap_file,
)?);
let mut exporter_peers: HashMap<(IpAddr, u16, IpAddr, u16), (C, bytes::BytesMut)> =
HashMap::new();
let mut writer: Box<dyn Write> = if let Some(output_path_ref) = &config.output_path {
let output_file = File::create(output_path_ref).map_err(|e| {
format!(
"Failed to create output file '{}': {}",
output_path_ref.display(),
e
)
})?;
Box::new(BufWriter::new(output_file))
} else {
Box::new(BufWriter::new(io::stdout()))
};
let mut iter = PcapIter::new(pcap_reader);
while let Some((src_ip, src_port, dst_ip, dst_port, protocol, packet_data)) = iter.next() {
let frame_counter = iter.frame_counter();
if let Some(max_packets) = config.input_size
&& frame_counter > max_packets
{
break;
}
let flow_key = (src_ip, src_port, dst_ip, dst_port);
if let Some(message) = handler.decode(flow_key, protocol, &packet_data, &mut exporter_peers)
{
for result in message {
let serialized_data = handler.serialize(result)?;
let output = if config.show_frame_number {
serde_json::json!({
"frame_number": frame_counter,
"data": serialized_data,
})
} else {
serialized_data
};
writer.write_all(serde_json::to_string(&output)?.as_bytes())?;
writer.write_all(b"\n")?;
}
}
}
writer.flush()?;
Ok(())
}