Skip to main content

wireforge_app/pcap/
ng_writer.rs

1//! pcapng file writer.
2
3use std::io::Write;
4use std::time::Duration;
5
6use super::types::LinkType;
7
8pub struct PcapNgWriter<W: Write> {
9    writer: W,
10}
11
12impl<W: Write> PcapNgWriter<W> {
13    pub fn new(mut writer: W, link_type: LinkType) -> Result<Self, std::io::Error> {
14        // Write SHB
15        let shb_body = [0u8; 16]; // byte_order_magic(4) + major(2) + minor(2) + section_len(8)
16        let shb_len = 28u32; // 4(type) + 4(len) + 16(body) + 4(len)
17        writer.write_all(&0x0A0D0D0Au32.to_be_bytes())?;
18        writer.write_all(&shb_len.to_be_bytes())?;
19        writer.write_all(&shb_body)?;
20        writer.write_all(&shb_len.to_be_bytes())?;
21
22        // Write IDB
23        let lt: u16 = match link_type { LinkType::Ethernet => 1, LinkType::Raw => 101, LinkType::Unknown(v) => v as u16 };
24        let mut idb_body = vec![0u8; 16];
25        idb_body[8..10].copy_from_slice(&lt.to_le_bytes()); // link_type at offset 8
26        let idb_len = 32u32; // 4(type) + 4(len) + 16(body) + 4(len)
27        writer.write_all(&1u32.to_be_bytes())?;
28        writer.write_all(&idb_len.to_be_bytes())?;
29        writer.write_all(&idb_body)?;
30        writer.write_all(&idb_len.to_be_bytes())?;
31
32        Ok(Self { writer })
33    }
34
35    pub fn write_epb(&mut self, ts: Duration, packet: &[u8]) -> Result<(), std::io::Error> {
36        let padded_len = (packet.len() + 3) & !3;
37        let epb_body_len = 20 + padded_len;
38        let epb_total_len = 12 + epb_body_len; // 4(type) + 4(len) + body + 4(len)
39
40        self.writer.write_all(&6u32.to_be_bytes())?;
41        self.writer.write_all(&(epb_total_len as u32).to_be_bytes())?;
42        self.writer.write_all(&0u32.to_be_bytes())?; // interface_id
43        self.writer.write_all(&(ts.as_secs() as u32).to_be_bytes())?; // ts_high
44        self.writer.write_all(&ts.subsec_nanos().to_be_bytes())?; // ts_low
45        self.writer.write_all(&(packet.len() as u32).to_be_bytes())?; // captured_len
46        self.writer.write_all(&(packet.len() as u32).to_be_bytes())?; // original_len
47        self.writer.write_all(packet)?;
48        // Padding
49        if padded_len > packet.len() {
50            self.writer.write_all(&vec![0u8; padded_len - packet.len()])?;
51        }
52        self.writer.write_all(&(epb_total_len as u32).to_be_bytes())?;
53        self.writer.flush()
54    }
55}