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