1use std::borrow::Cow;
4use std::io::{Result as IoResult, Write};
5
6use byteorder_slice::byteorder::WriteBytesExt;
7use byteorder_slice::result::ReadSlice;
8use byteorder_slice::{BigEndian, ByteOrder, LittleEndian};
9use derive_into_owned::IntoOwned;
10
11use super::enhanced_packet::EnhancedPacketBlock;
12use super::interface_description::InterfaceDescriptionBlock;
13use super::interface_statistics::InterfaceStatisticsBlock;
14use super::name_resolution::NameResolutionBlock;
15use super::packet::PacketBlock;
16use super::section_header::SectionHeaderBlock;
17use super::simple_packet::SimplePacketBlock;
18use super::systemd_journal_export::SystemdJournalExportBlock;
19use super::unknown::UnknownBlock;
20use crate::errors::PcapError;
21use crate::PcapResult;
22
23
24pub const SECTION_HEADER_BLOCK: u32 = 0x0A0D0D0A;
26pub const INTERFACE_DESCRIPTION_BLOCK: u32 = 0x00000001;
28pub const PACKET_BLOCK: u32 = 0x00000002;
30pub const SIMPLE_PACKET_BLOCK: u32 = 0x00000003;
32pub const NAME_RESOLUTION_BLOCK: u32 = 0x00000004;
34pub const INTERFACE_STATISTIC_BLOCK: u32 = 0x00000005;
36pub const ENHANCED_PACKET_BLOCK: u32 = 0x00000006;
38pub const SYSTEMD_JOURNAL_EXPORT_BLOCK: u32 = 0x00000009;
40
41#[derive(Clone, Debug)]
55pub struct RawBlock<'a> {
56 pub type_: u32,
58 pub initial_len: u32,
60 pub body: Cow<'a, [u8]>,
62 pub trailer_len: u32,
64}
65
66impl<'a> RawBlock<'a> {
67 pub fn from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> Result<(&'a [u8], Self), PcapError> {
69 if slice.len() < 12 {
70 return Err(PcapError::IncompleteBuffer);
71 }
72
73 let type_ = slice.read_u32::<B>().unwrap();
74
75 if type_ == SECTION_HEADER_BLOCK {
77 let initial_len = slice.read_u32::<BigEndian>().unwrap();
78
79 let mut tmp_slice = slice;
81 let magic = tmp_slice.read_u32::<BigEndian>().unwrap();
82 let res = match magic {
83 0x1A2B3C4D => inner_parse::<BigEndian>(slice, type_, initial_len),
84 0x4D3C2B1A => inner_parse::<LittleEndian>(slice, type_, initial_len.swap_bytes()),
85 _ => Err(PcapError::InvalidField("SectionHeaderBlock: invalid magic number")),
86 };
87
88 return res;
89 }
90 else {
91 let initial_len = slice.read_u32::<B>().map_err(|_| PcapError::IncompleteBuffer)?;
92 return inner_parse::<B>(slice, type_, initial_len);
93 };
94
95 fn inner_parse<B: ByteOrder>(slice: &[u8], type_: u32, initial_len: u32) -> Result<(&[u8], RawBlock<'_>), PcapError> {
97 if (initial_len % 4) != 0 {
98 return Err(PcapError::InvalidField("Block: (initial_len % 4) != 0"));
99 }
100
101 if initial_len < 12 {
102 return Err(PcapError::InvalidField("Block: initial_len < 12"));
103 }
104
105 if slice.len() < initial_len as usize - 8 {
107 return Err(PcapError::IncompleteBuffer);
108 }
109
110 let body_len = initial_len - 12;
111 let body = &slice[..body_len as usize];
112
113 let mut rem = &slice[body_len as usize..];
114
115 let trailer_len = rem.read_u32::<B>().unwrap();
116
117 if initial_len != trailer_len {
118 return Err(PcapError::InvalidField("Block: initial_length != trailer_length"));
119 }
120
121 let block = RawBlock { type_, initial_len, body: Cow::Borrowed(body), trailer_len };
122
123 Ok((rem, block))
124 }
125 }
126
127 pub fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
131 writer.write_u32::<B>(self.type_)?;
132 writer.write_u32::<B>(self.initial_len)?;
133 writer.write_all(&self.body[..])?;
134 writer.write_u32::<B>(self.trailer_len)?;
135
136 Ok(self.body.len() + 6)
137 }
138
139 pub fn try_into_block<B: ByteOrder>(self) -> PcapResult<Block<'a>> {
141 Block::try_from_raw_block::<B>(self)
142 }
143}
144
145#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
147pub enum Block<'a> {
148 SectionHeader(SectionHeaderBlock<'a>),
150 InterfaceDescription(InterfaceDescriptionBlock<'a>),
152 Packet(PacketBlock<'a>),
154 SimplePacket(SimplePacketBlock<'a>),
156 NameResolution(NameResolutionBlock<'a>),
158 InterfaceStatistics(InterfaceStatisticsBlock<'a>),
160 EnhancedPacket(EnhancedPacketBlock<'a>),
162 SystemdJournalExport(SystemdJournalExportBlock<'a>),
164 Unknown(UnknownBlock<'a>),
166}
167
168impl<'a> Block<'a> {
169 pub fn from_slice<B: ByteOrder>(slice: &'a [u8]) -> Result<(&'a [u8], Self), PcapError> {
171 let (rem, raw_block) = RawBlock::from_slice::<B>(slice)?;
172 let block = Self::try_from_raw_block::<B>(raw_block)?;
173
174 Ok((rem, block))
175 }
176
177 pub fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
179 return match self {
180 Self::SectionHeader(b) => inner_write_to::<B, _, W>(b, SECTION_HEADER_BLOCK, writer),
181 Self::InterfaceDescription(b) => inner_write_to::<B, _, W>(b, INTERFACE_DESCRIPTION_BLOCK, writer),
182 Self::Packet(b) => inner_write_to::<B, _, W>(b, PACKET_BLOCK, writer),
183 Self::SimplePacket(b) => inner_write_to::<B, _, W>(b, SIMPLE_PACKET_BLOCK, writer),
184 Self::NameResolution(b) => inner_write_to::<B, _, W>(b, NAME_RESOLUTION_BLOCK, writer),
185 Self::InterfaceStatistics(b) => inner_write_to::<B, _, W>(b, INTERFACE_STATISTIC_BLOCK, writer),
186 Self::EnhancedPacket(b) => inner_write_to::<B, _, W>(b, ENHANCED_PACKET_BLOCK, writer),
187 Self::SystemdJournalExport(b) => inner_write_to::<B, _, W>(b, SYSTEMD_JOURNAL_EXPORT_BLOCK, writer),
188 Self::Unknown(b) => inner_write_to::<B, _, W>(b, b.type_, writer),
189 };
190
191 fn inner_write_to<'a, B: ByteOrder, BL: PcapNgBlock<'a>, W: Write>(block: &BL, block_code: u32, writer: &mut W) -> IoResult<usize> {
192 let data_len = block.write_to::<B, _>(&mut std::io::sink()).unwrap();
194 let pad_len = (4 - (data_len % 4)) % 4;
195
196 let block_len = data_len + pad_len + 12;
197
198 writer.write_u32::<B>(block_code)?;
199 writer.write_u32::<B>(block_len as u32)?;
200 block.write_to::<B, _>(writer)?;
201 writer.write_all(&[0_u8; 3][..pad_len])?;
202 writer.write_u32::<B>(block_len as u32)?;
203
204 Ok(block_len)
205 }
206 }
207
208 pub fn try_from_raw_block<B: ByteOrder>(raw_block: RawBlock<'a>) -> Result<Block<'a>, PcapError> {
212 let body = match raw_block.body {
213 Cow::Borrowed(b) => b,
214 _ => panic!("The raw block is not borrowed"),
215 };
216
217 match raw_block.type_ {
218 SECTION_HEADER_BLOCK => {
219 let (_, block) = SectionHeaderBlock::from_slice::<BigEndian>(body)?;
220 Ok(Block::SectionHeader(block))
221 },
222 INTERFACE_DESCRIPTION_BLOCK => {
223 let (_, block) = InterfaceDescriptionBlock::from_slice::<B>(body)?;
224 Ok(Block::InterfaceDescription(block))
225 },
226 PACKET_BLOCK => {
227 let (_, block) = PacketBlock::from_slice::<B>(body)?;
228 Ok(Block::Packet(block))
229 },
230 SIMPLE_PACKET_BLOCK => {
231 let (_, block) = SimplePacketBlock::from_slice::<B>(body)?;
232 Ok(Block::SimplePacket(block))
233 },
234 NAME_RESOLUTION_BLOCK => {
235 let (_, block) = NameResolutionBlock::from_slice::<B>(body)?;
236 Ok(Block::NameResolution(block))
237 },
238 INTERFACE_STATISTIC_BLOCK => {
239 let (_, block) = InterfaceStatisticsBlock::from_slice::<B>(body)?;
240 Ok(Block::InterfaceStatistics(block))
241 },
242 ENHANCED_PACKET_BLOCK => {
243 let (_, block) = EnhancedPacketBlock::from_slice::<B>(body)?;
244 Ok(Block::EnhancedPacket(block))
245 },
246 SYSTEMD_JOURNAL_EXPORT_BLOCK => {
247 let (_, block) = SystemdJournalExportBlock::from_slice::<B>(body)?;
248 Ok(Block::SystemdJournalExport(block))
249 },
250 type_ => Ok(Block::Unknown(UnknownBlock::new(type_, raw_block.initial_len, body))),
251 }
252 }
253
254 pub fn into_enhanced_packet(self) -> Option<EnhancedPacketBlock<'a>> {
256 match self {
257 Block::EnhancedPacket(a) => Some(a),
258 _ => None,
259 }
260 }
261
262 pub fn into_interface_description(self) -> Option<InterfaceDescriptionBlock<'a>> {
264 match self {
265 Block::InterfaceDescription(a) => Some(a),
266 _ => None,
267 }
268 }
269
270 pub fn into_interface_statistics(self) -> Option<InterfaceStatisticsBlock<'a>> {
272 match self {
273 Block::InterfaceStatistics(a) => Some(a),
274 _ => None,
275 }
276 }
277
278 pub fn into_name_resolution(self) -> Option<NameResolutionBlock<'a>> {
280 match self {
281 Block::NameResolution(a) => Some(a),
282 _ => None,
283 }
284 }
285
286 pub fn into_packet(self) -> Option<PacketBlock<'a>> {
288 match self {
289 Block::Packet(a) => Some(a),
290 _ => None,
291 }
292 }
293
294 pub fn into_section_header(self) -> Option<SectionHeaderBlock<'a>> {
296 match self {
297 Block::SectionHeader(a) => Some(a),
298 _ => None,
299 }
300 }
301
302 pub fn into_simple_packet(self) -> Option<SimplePacketBlock<'a>> {
304 match self {
305 Block::SimplePacket(a) => Some(a),
306 _ => None,
307 }
308 }
309
310 pub fn into_systemd_journal_export(self) -> Option<SystemdJournalExportBlock<'a>> {
312 match self {
313 Block::SystemdJournalExport(a) => Some(a),
314 _ => None,
315 }
316 }
317}
318
319
320pub trait PcapNgBlock<'a> {
322 fn from_slice<B: ByteOrder>(slice: &'a [u8]) -> Result<(&[u8], Self), PcapError>
324 where
325 Self: std::marker::Sized;
326
327 fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize>;
329
330 fn into_block(self) -> Block<'a>;
332}