rusty_pcap/pcap_ng/blocks/
interface.rs1use std::io::{Cursor, Read};
2
3use crate::{
4 byte_order::{Endianness, ReadExt, UndertminedByteOrder},
5 link_type::LinkType,
6 pcap_ng::{
7 PcapNgParseError,
8 blocks::{Block, BlockHeader},
9 options::{BlockOptions, define_options_enum},
10 },
11};
12define_options_enum! {
13 enum InterfaceOptionCodes {
15 IfName = 2,
17 IfDescription = 3,
19 IfIPv4Address = 4,
20 IfIPv6Address = 5,
21 IfMACAddress = 6,
22 IfEuiAddr = 7,
23 IfSpeed = 8,
25 IfTimestampResolution = 9,
26 IfTZone = 10,
27 IfFilter = 11,
28 IfOS = 12,
29 IfFcsLength = 13,
30 IfTsOffset = 14,
31 IfHardware = 15,
32 IfTxSpeed = 16,
33 IfRxSpeed = 17,
34 }
35}
36
37#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct InterfaceDescriptionBlock {
39 pub block_length: u32,
40 pub link_type: LinkType,
41 pub reserved: [u8; 2],
42 pub snap_length: u32,
43 pub options: Option<BlockOptions>,
44}
45impl Block for InterfaceDescriptionBlock {
46 fn block_id() -> u32 {
47 1
48 }
49 fn block_id_le() -> [u8; 4] {
50 [0x01, 0x00, 0x00, 0x00] }
52 fn block_id_be() -> [u8; 4] {
53 [0x00, 0x00, 0x00, 0x01] }
55 fn minimum_size() -> usize {
56 20
58 }
59
60 fn read_with_header<R: Read>(
61 reader: &mut R,
62 header: &BlockHeader,
63 byte_order: Option<Endianness>,
64 ) -> Result<Self, PcapNgParseError>
65 where
66 Self: Sized,
67 {
68 header.matches_block_id::<Self>()?;
69 let byte_order = byte_order
70 .or(header.endianness_from_block::<Self>())
71 .ok_or(UndertminedByteOrder)?;
72 let mut cursor = Cursor::new(reader.read_bytes::<8>()?);
73
74 let link_type = LinkType::try_from(cursor.read_u16(byte_order)?)?;
75 let reserved = cursor.read_bytes::<2>()?;
76 let snap_length = cursor.read_u32(byte_order)?;
77
78 let block_length = header.block_length_as_u32(byte_order);
79 let options_space = block_length as usize - Self::minimum_size();
80
81 let options = if options_space > 0 {
82 BlockOptions::read_option(reader, byte_order)?
83 } else {
84 None
85 };
86
87 reader.read_bytes::<4>()?;
88 Ok(Self {
89 block_length,
90 link_type,
91 reserved,
92 snap_length,
93 options,
94 })
95 }
96}
97impl InterfaceDescriptionBlock {
98 pub fn read<R: Read>(reader: &mut R, byte_order: Endianness) -> Result<Self, PcapNgParseError> {
99 let header = BlockHeader::read(reader)?;
100 Self::read_with_header::<_>(reader, &header, Some(byte_order))
101 }
102}
103
104#[cfg(test)]
105mod tests {
106
107 use crate::{
108 byte_order::Endianness,
109 pcap_ng::blocks::{InterfaceOptionCodes, interface::InterfaceDescriptionBlock},
110 };
111 #[test]
112 fn parse_bytes() -> anyhow::Result<()> {
113 let content = [
114 1, 0, 0, 0, 52, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 24, 0, 115, 105, 108, 108, 121,
115 32, 101, 116, 104, 101, 114, 110, 101, 116, 32, 105, 110, 116, 101, 114, 102, 97, 99,
116 101, 0, 0, 0, 0, 52, 0, 0, 0,
117 ];
118 let mut reader = std::io::Cursor::new(&content);
119 let interface = InterfaceDescriptionBlock::read(&mut reader, Endianness::LittleEndian)?;
120
121 assert_eq!(interface.block_length, 52);
122 assert_eq!(interface.link_type, crate::link_type::LinkType::Ethernet);
123 assert_eq!(interface.reserved, [0, 0]);
124 assert_eq!(interface.snap_length, 0);
125 assert!(interface.options.is_some());
126 let options = interface.options.unwrap();
127 assert_eq!(options.0.len(), 1);
128 assert_eq!(options.0[0].code, 2);
129 assert_eq!(
130 InterfaceOptionCodes::try_from(options.0[0].code),
131 Ok(InterfaceOptionCodes::IfName)
132 );
133 assert_eq!(options.0[0].length, 24);
134 assert_eq!(options.0[0].value, b"silly ethernet interface");
135
136 assert_eq!(reader.position(), 52);
137 Ok(())
138 }
139}