1 // Copyright 2022 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #![allow(clippy::unused_io_amount)] 16 17 use std::io::Write; 18 use std::path::Path; 19 use std::time::Instant; 20 21 pub struct File { 22 file: std::sync::Mutex<std::fs::File>, 23 start_time: Instant, 24 } 25 26 pub enum Direction { 27 Rx, 28 Tx, 29 } 30 31 impl File { create<P: AsRef<Path>>(path: P) -> std::io::Result<File>32 pub fn create<P: AsRef<Path>>(path: P) -> std::io::Result<File> { 33 let mut file = std::fs::File::create(path)?; 34 35 // PCAPng files must start with a Section Header Block. 36 file.write(&u32::to_le_bytes(0x0A0D0D0A))?; // Block Type 37 file.write(&u32::to_le_bytes(28))?; // Block Total Length 38 file.write(&u32::to_le_bytes(0x1A2B3C4D))?; // Byte-Order Magic 39 file.write(&u16::to_le_bytes(1))?; // Major Version 40 file.write(&u16::to_le_bytes(0))?; // Minor Version 41 file.write(&u64::to_le_bytes(0xFFFFFFFFFFFFFFFF))?; // Section Length (not specified) 42 file.write(&u32::to_le_bytes(28))?; // Block Total Length 43 44 // Write the Interface Description Block used for all 45 // UCI records. 46 file.write(&u32::to_le_bytes(0x00000001))?; // Block Type 47 file.write(&u32::to_le_bytes(20))?; // Block Total Length 48 file.write(&u16::to_le_bytes(293))?; // LinkType 49 file.write(&u16::to_le_bytes(0))?; // Reserved 50 file.write(&u32::to_le_bytes(0))?; // SnapLen (no limit) 51 file.write(&u32::to_le_bytes(20))?; // Block Total Length 52 53 Ok(File { 54 file: std::sync::Mutex::new(file), 55 start_time: Instant::now(), 56 }) 57 } 58 write(&self, packet: &[u8], _dir: Direction) -> std::io::Result<()>59 pub fn write(&self, packet: &[u8], _dir: Direction) -> std::io::Result<()> { 60 let packet_data_padding: usize = 4 - packet.len() % 4; 61 let block_total_length: u32 = packet.len() as u32 + packet_data_padding as u32 + 32; 62 let timestamp = self.start_time.elapsed().as_micros(); 63 let mut file = self.file.lock().unwrap(); 64 65 // Wrap the packet inside an Enhanced Packet Block. 66 file.write(&u32::to_le_bytes(0x00000006))?; // Block Type 67 file.write(&u32::to_le_bytes(block_total_length))?; 68 file.write(&u32::to_le_bytes(0))?; // Interface ID 69 file.write(&u32::to_le_bytes((timestamp >> 32) as u32))?; // Timestamp (High) 70 file.write(&u32::to_le_bytes(timestamp as u32))?; // Timestamp (Low) 71 file.write(&u32::to_le_bytes(packet.len() as u32))?; // Captured Packet Length 72 file.write(&u32::to_le_bytes(packet.len() as u32))?; // Original Packet Length 73 file.write(packet)?; 74 file.write(&vec![0; packet_data_padding])?; 75 file.write(&u32::to_le_bytes(block_total_length))?; // Block Total Length 76 Ok(()) 77 } 78 } 79