blob: fc2d882b3bd488c7e53b57032e232a14f13ae53c [file] [log] [blame]
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![allow(clippy::unused_io_amount)]
use std::path::Path;
use std::time::Instant;
use tokio::io::AsyncWriteExt;
pub struct File {
file: tokio::fs::File,
start_time: Instant,
}
pub enum Direction {
Rx,
Tx,
}
impl File {
pub async fn create<P: AsRef<Path>>(path: P) -> std::io::Result<File> {
let mut file = tokio::fs::File::create(path).await?;
// PCAPng files must start with a Section Header Block.
file.write(&u32::to_le_bytes(0x0A0D0D0A)).await?; // Block Type
file.write(&u32::to_le_bytes(28)).await?; // Block Total Length
file.write(&u32::to_le_bytes(0x1A2B3C4D)).await?; // Byte-Order Magic
file.write(&u16::to_le_bytes(1)).await?; // Major Version
file.write(&u16::to_le_bytes(0)).await?; // Minor Version
file.write(&u64::to_le_bytes(0xFFFFFFFFFFFFFFFF)).await?; // Section Length (not specified)
file.write(&u32::to_le_bytes(28)).await?; // Block Total Length
// Write the Interface Description Block used for all
// UCI records.
file.write(&u32::to_le_bytes(0x00000001)).await?; // Block Type
file.write(&u32::to_le_bytes(20)).await?; // Block Total Length
file.write(&u16::to_le_bytes(293)).await?; // LinkType
file.write(&u16::to_le_bytes(0)).await?; // Reserved
file.write(&u32::to_le_bytes(0)).await?; // SnapLen (no limit)
file.write(&u32::to_le_bytes(20)).await?; // Block Total Length
Ok(File {
file,
start_time: Instant::now(),
})
}
pub async fn write(&mut self, packet: &[u8], _dir: Direction) -> std::io::Result<()> {
let packet_data_padding: usize = 4 - packet.len() % 4;
let block_total_length: u32 = packet.len() as u32 + packet_data_padding as u32 + 32;
let timestamp = self.start_time.elapsed().as_micros();
// Wrap the packet inside an Enhanced Packet Block.
self.file.write(&u32::to_le_bytes(0x00000006)).await?; // Block Type
self.file
.write(&u32::to_le_bytes(block_total_length))
.await?;
self.file.write(&u32::to_le_bytes(0)).await?; // Interface ID
self.file
.write(&u32::to_le_bytes((timestamp >> 32) as u32))
.await?; // Timestamp (High)
self.file.write(&u32::to_le_bytes(timestamp as u32)).await?; // Timestamp (Low)
self.file
.write(&u32::to_le_bytes(packet.len() as u32))
.await?; // Captured Packet Length
self.file
.write(&u32::to_le_bytes(packet.len() as u32))
.await?; // Original Packet Length
self.file.write(packet).await?;
self.file.write(&vec![0; packet_data_padding]).await?;
self.file
.write(&u32::to_le_bytes(block_total_length))
.await?; // Block Total Length
Ok(())
}
}