1use std::io::Read;
3
4use crate::{
5 byte_order::{ByteOrder, Endianness, ReadExt, UnexpectedSize},
6 pcap_ng::PcapNgParseError,
7};
8
9mod enhanced_packet;
10mod generic;
11mod header;
12mod interface;
13mod name_resolution;
14mod simple_packet;
15pub use enhanced_packet::EnhancedPacket;
16pub use generic::GenericBlock;
17pub use header::{SHBOptionCodes, SectionHeaderBlock};
18pub use interface::{InterfaceDescriptionBlock, InterfaceOptionCodes};
19pub use name_resolution::NameResolutionBlock;
20pub use simple_packet::SimplePacket;
21pub trait Block {
22 fn block_id() -> u32
24 where
25 Self: Sized;
26 fn block_id_le() -> [u8; 4]
28 where
29 Self: Sized,
30 {
31 Self::block_id().to_le_bytes()
32 }
33 fn block_id_be() -> [u8; 4]
35 where
36 Self: Sized,
37 {
38 Self::block_id().to_be_bytes()
39 }
40 fn minimum_size() -> usize {
44 12 }
46 fn read_with_header<R: Read>(
52 reader: &mut R,
53 header: &BlockHeader,
54 byte_order: Option<Endianness>,
55 ) -> Result<Self, PcapNgParseError>
56 where
57 Self: Sized;
58}
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub struct BlockHeader {
61 pub block_id: [u8; 4],
62 pub block_length: [u8; 4],
63}
64impl BlockHeader {
65 pub fn new(block_id: [u8; 4], block_length: [u8; 4]) -> Self {
66 Self {
67 block_id,
68 block_length,
69 }
70 }
71 pub fn block_id_as_u32(&self, endianness: impl ByteOrder) -> u32 {
73 endianness.u32_from_bytes(self.block_id)
74 }
75 pub fn block_length_as_u32(&self, endianness: impl ByteOrder) -> u32 {
77 endianness.u32_from_bytes(self.block_length)
78 }
79 pub fn read<R: Read>(reader: &mut R) -> Result<Self, PcapNgParseError> {
80 let block_id = reader.read_bytes::<4>()?;
81 let block_length = reader.read_bytes::<4>()?;
82 Ok(Self::new(block_id, block_length))
83 }
84 pub fn parse_from_bytes(bytes: &[u8]) -> Result<Self, PcapNgParseError> {
85 if bytes.len() < 8 {
86 return Err(PcapNgParseError::UnexpectedSize(UnexpectedSize {
87 name: "BlockHeader",
88 expected: 8,
89 got: bytes.len(),
90 }));
91 }
92 let block_id = [bytes[0], bytes[1], bytes[2], bytes[3]];
93 let block_length = [bytes[4], bytes[5], bytes[6], bytes[7]];
94 Ok(Self::new(block_id, block_length))
95 }
96 pub(crate) fn matches_block_id<B: Block>(&self) -> Result<(), PcapNgParseError> {
98 if self.block_id != B::block_id_le() && self.block_id != B::block_id_be() {
99 return Err(PcapNgParseError::UnexpectedBlockId {
100 expected_be: B::block_id().to_be_bytes(),
101 expected_le: B::block_id().to_le_bytes(),
102 got: self.block_id,
103 });
104 }
105 Ok(())
106 }
107 pub(crate) fn endianness_from_block<B: Block>(&self) -> Option<Endianness> {
109 debug_assert_ne!(
110 B::block_id_be(),
111 B::block_id_le(),
112 "Unable to determine endianness for {}",
113 std::any::type_name::<B>()
114 );
115 if self.block_id == B::block_id_le() {
116 Some(Endianness::LittleEndian)
117 } else if self.block_id == B::block_id_be() {
118 Some(Endianness::BigEndian)
119 } else {
120 None
121 }
122 }
123}
124#[derive(Debug, Clone, PartialEq, Eq)]
125pub enum PcapNgBlock {
126 SectionHeader(SectionHeaderBlock),
127 InterfaceDescription(InterfaceDescriptionBlock),
128 SimplePacket(SimplePacket),
129 EnhancedPacket(EnhancedPacket),
130 NameResolution(NameResolutionBlock),
131 Generic(GenericBlock),
132}
133impl PcapNgBlock {
134 pub fn read<R: Read>(
135 reader: &mut R,
136 header: &BlockHeader,
137 byte_order: Endianness,
138 ) -> Result<Self, PcapNgParseError> {
139 let block_id = header.block_id_as_u32(byte_order);
140 match block_id {
141 168627466 => Ok(PcapNgBlock::SectionHeader(
142 SectionHeaderBlock::read_with_header(reader, header, Some(byte_order))?,
143 )),
144 1 => Ok(PcapNgBlock::InterfaceDescription(
145 InterfaceDescriptionBlock::read_with_header(reader, header, Some(byte_order))?,
146 )),
147 3 => Ok(PcapNgBlock::SimplePacket(SimplePacket::read_with_header(
148 reader,
149 header,
150 Some(byte_order),
151 )?)),
152 4 => Ok(PcapNgBlock::NameResolution(
153 NameResolutionBlock::read_with_header(reader, header, Some(byte_order))?,
154 )),
155 6 => Ok(PcapNgBlock::EnhancedPacket(
156 EnhancedPacket::read_with_header(reader, header, Some(byte_order))?,
157 )),
158
159 _ => Ok(PcapNgBlock::Generic(GenericBlock::read_with_header(
160 reader, header, byte_order,
161 )?)),
162 }
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169 #[cfg(debug_assertions)]
170 #[test]
171 #[should_panic]
172 fn endianness_from_block_panics() {
173 let block = BlockHeader {
174 block_id: SectionHeaderBlock::block_id_le(),
175 block_length: [0; 4],
176 };
177 block.endianness_from_block::<SectionHeaderBlock>();
178 }
179
180 #[test]
181 fn endianness_from_block() {
182 let block = BlockHeader {
183 block_id: InterfaceDescriptionBlock::block_id_le(),
184 block_length: [0; 4],
185 };
186 assert_eq!(
187 block.endianness_from_block::<InterfaceDescriptionBlock>(),
188 Some(Endianness::LittleEndian)
189 );
190 let block = BlockHeader {
191 block_id: InterfaceDescriptionBlock::block_id_be(),
192 block_length: [0; 4],
193 };
194 assert_eq!(
195 block.endianness_from_block::<InterfaceDescriptionBlock>(),
196 Some(Endianness::BigEndian)
197 );
198 }
199}