pcap_file/pcapng/blocks/
packet.rs1use std::borrow::Cow;
4use std::io::{Result as IoResult, Write};
5
6use byteorder_slice::byteorder::WriteBytesExt;
7use byteorder_slice::result::ReadSlice;
8use byteorder_slice::ByteOrder;
9use derive_into_owned::IntoOwned;
10
11use super::block_common::{Block, PcapNgBlock};
12use super::opt_common::{CustomBinaryOption, CustomUtf8Option, PcapNgOption, UnknownOption, WriteOptTo};
13use crate::errors::PcapError;
14
15#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
18pub struct PacketBlock<'a> {
19 pub interface_id: u16,
21
22 pub drop_count: u16,
27
28 pub timestamp: u64,
31
32 pub captured_len: u32,
34
35 pub original_len: u32,
37
38 pub data: Cow<'a, [u8]>,
40
41 pub options: Vec<PacketOption<'a>>,
43}
44
45impl<'a> PcapNgBlock<'a> for PacketBlock<'a> {
46 fn from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> Result<(&'a [u8], Self), PcapError> {
47 if slice.len() < 20 {
48 return Err(PcapError::InvalidField("EnhancedPacketBlock: block length length < 20"));
49 }
50
51 let interface_id = slice.read_u16::<B>().unwrap();
52 let drop_count = slice.read_u16::<B>().unwrap();
53 let timestamp = slice.read_u64::<B>().unwrap();
54 let captured_len = slice.read_u32::<B>().unwrap();
55 let original_len = slice.read_u32::<B>().unwrap();
56
57 let pad_len = (4 - (captured_len as usize % 4)) % 4;
58 let tot_len = captured_len as usize + pad_len;
59
60 if slice.len() < tot_len {
61 return Err(PcapError::InvalidField("EnhancedPacketBlock: captured_len + padding > block length"));
62 }
63
64 let data = &slice[..captured_len as usize];
65 slice = &slice[tot_len..];
66
67 let (slice, options) = PacketOption::opts_from_slice::<B>(slice)?;
68 let block = PacketBlock {
69 interface_id,
70 drop_count,
71 timestamp,
72 captured_len,
73 original_len,
74 data: Cow::Borrowed(data),
75 options,
76 };
77
78 Ok((slice, block))
79 }
80
81 fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
82 writer.write_u16::<B>(self.interface_id)?;
83 writer.write_u16::<B>(self.drop_count)?;
84 writer.write_u64::<B>(self.timestamp)?;
85 writer.write_u32::<B>(self.captured_len)?;
86 writer.write_u32::<B>(self.original_len)?;
87 writer.write_all(&self.data)?;
88
89 let pad_len = (4 - (self.captured_len as usize % 4)) % 4;
90 writer.write_all(&[0_u8; 3][..pad_len])?;
91
92 let opt_len = PacketOption::write_opts_to::<B, _>(&self.options, writer)?;
93
94 Ok(20 + self.data.len() + pad_len + opt_len)
95 }
96
97 fn into_block(self) -> Block<'a> {
98 Block::Packet(self)
99 }
100}
101
102#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
104pub enum PacketOption<'a> {
105 Comment(Cow<'a, str>),
107
108 Flags(u32),
110
111 Hash(Cow<'a, [u8]>),
113
114 CustomBinary(CustomBinaryOption<'a>),
116
117 CustomUtf8(CustomUtf8Option<'a>),
119
120 Unknown(UnknownOption<'a>),
122}
123
124impl<'a> PcapNgOption<'a> for PacketOption<'a> {
125 fn from_slice<B: ByteOrder>(code: u16, length: u16, mut slice: &'a [u8]) -> Result<Self, PcapError> {
126 let opt = match code {
127 1 => PacketOption::Comment(Cow::Borrowed(std::str::from_utf8(slice)?)),
128 2 => {
129 if slice.len() != 4 {
130 return Err(PcapError::InvalidField("PacketOption: Flags length != 4"));
131 }
132 PacketOption::Flags(slice.read_u32::<B>().map_err(|_| PcapError::IncompleteBuffer)?)
133 },
134 3 => PacketOption::Hash(Cow::Borrowed(slice)),
135
136 2988 | 19372 => PacketOption::CustomUtf8(CustomUtf8Option::from_slice::<B>(code, slice)?),
137 2989 | 19373 => PacketOption::CustomBinary(CustomBinaryOption::from_slice::<B>(code, slice)?),
138
139 _ => PacketOption::Unknown(UnknownOption::new(code, length, slice)),
140 };
141
142 Ok(opt)
143 }
144
145 fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
146 match self {
147 PacketOption::Comment(a) => a.write_opt_to::<B, W>(1, writer),
148 PacketOption::Flags(a) => a.write_opt_to::<B, W>(2, writer),
149 PacketOption::Hash(a) => a.write_opt_to::<B, W>(3, writer),
150 PacketOption::CustomBinary(a) => a.write_opt_to::<B, W>(a.code, writer),
151 PacketOption::CustomUtf8(a) => a.write_opt_to::<B, W>(a.code, writer),
152 PacketOption::Unknown(a) => a.write_opt_to::<B, W>(a.code, writer),
153 }
154 }
155}