pcap_parser/pcapng/interface_description.rs
1use std::net::{Ipv4Addr, Ipv6Addr};
2
3use nom::error::{ErrorKind, ParseError};
4use nom::{Err, IResult};
5
6use crate::endianness::{PcapBE, PcapEndianness, PcapLE};
7use crate::{opt_parse_options, Linktype, PcapError, PcapNGOption, IDB_MAGIC};
8
9use super::*;
10
11/// An Interface Description Block (IDB) is the container for information
12/// describing an interface on which packet data is captured.
13#[derive(Debug)]
14pub struct InterfaceDescriptionBlock<'a> {
15 pub block_type: u32,
16 pub block_len1: u32,
17 pub linktype: Linktype,
18 pub reserved: u16,
19 pub snaplen: u32,
20 pub options: Vec<PcapNGOption<'a>>,
21 pub block_len2: u32,
22 pub if_tsresol: u8,
23 pub if_tsoffset: i64,
24}
25
26impl InterfaceDescriptionBlock<'_> {
27 /// Decode the interface time resolution, in units per second
28 ///
29 /// Return the resolution, or `None` if the resolution is invalid (for ex. greater than `2^64`)
30 #[inline]
31 pub fn ts_resolution(&self) -> Option<u64> {
32 build_ts_resolution(self.if_tsresol)
33 }
34
35 /// Return the interface timestamp offset
36 #[inline]
37 pub fn ts_offset(&self) -> i64 {
38 self.if_tsoffset
39 }
40
41 /// Return the `if_name` option value, if present
42 ///
43 /// If the option is present multiple times, the first value is returned.
44 ///
45 /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid,
46 /// or `Some(Err(_))` if value is present but invalid
47 pub fn if_name(&self) -> Option<Result<&str, PcapNGOptionError>> {
48 options_get_as_str(&self.options, OptionCode::IfName)
49 }
50
51 /// Return the `if_description` option value, if present
52 ///
53 /// If the option is present multiple times, the first value is returned.
54 ///
55 /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid,
56 /// or `Some(Err(_))` if value is present but invalid
57 pub fn if_description(&self) -> Option<Result<&str, PcapNGOptionError>> {
58 options_get_as_str(&self.options, OptionCode::IfDescription)
59 }
60
61 /// Return the `if_os` option value, if present
62 ///
63 /// If the option is present multiple times, the first value is returned.
64 ///
65 /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid,
66 /// or `Some(Err(_))` if value is present but invalid
67 pub fn if_os(&self) -> Option<Result<&str, PcapNGOptionError>> {
68 options_get_as_str(&self.options, OptionCode::IfOs)
69 }
70
71 /// Return the `if_ipv4addr` option values, if present
72 ///
73 /// This option can be multi-valued.
74 ///
75 /// Returns `None` if option is not present, `Some(Ok(Vec))` if the value is present and valid,
76 /// or `Some(Err(_))` if value is present but invalid
77 ///
78 /// Each item of the `Vec` is a pair `(IPv4Addr, IPv4Mask)`
79 pub fn if_ipv4addr(&self) -> Option<Result<Vec<(Ipv4Addr, Ipv4Addr)>, PcapNGOptionError>> {
80 let res = self.options.iter().try_fold(Vec::new(), |mut acc, opt| {
81 if opt.code == OptionCode::IfIpv4Addr {
82 let b = opt.as_bytes()?;
83 if b.len() != 8 {
84 return Err(PcapNGOptionError::InvalidLength);
85 }
86 let addr = Ipv4Addr::new(b[0], b[1], b[2], b[3]);
87 let mask = Ipv4Addr::new(b[4], b[5], b[6], b[7]);
88 acc.push((addr, mask));
89 Ok(acc)
90 } else {
91 Ok(acc)
92 }
93 });
94 if res.as_ref().map_or(false, |v| v.is_empty()) {
95 None
96 } else {
97 Some(res)
98 }
99 }
100
101 /// Return the `if_ipv6addr` option values, if present
102 ///
103 /// This option can be multi-valued.
104 ///
105 /// Returns `None` if option is not present, `Some(Ok(Vec))` if the value is present and valid,
106 /// or `Some(Err(_))` if value is present but invalid
107 ///
108 /// Each item of the `Vec` is a pair `(IPv6Addr, PrefixLen)`
109 pub fn if_ipv6addr(&self) -> Option<Result<Vec<(Ipv6Addr, u8)>, PcapNGOptionError>> {
110 let res = self.options.iter().try_fold(Vec::new(), |mut acc, opt| {
111 if opt.code == OptionCode::IfIpv4Addr {
112 let b = opt.as_bytes()?;
113 if b.len() != 17 {
114 return Err(PcapNGOptionError::InvalidLength);
115 }
116 let mut array_u16 = [0u16; 8];
117 for i in 0..8 {
118 array_u16[i] = ((b[2 * i] as u16) << 8) + b[2 * i + 1] as u16;
119 }
120 let addr = Ipv6Addr::new(
121 array_u16[0],
122 array_u16[1],
123 array_u16[2],
124 array_u16[3],
125 array_u16[4],
126 array_u16[5],
127 array_u16[6],
128 array_u16[7],
129 );
130 let mask = b[16];
131 acc.push((addr, mask));
132 Ok(acc)
133 } else {
134 Ok(acc)
135 }
136 });
137 if res.as_ref().map_or(false, |v| v.is_empty()) {
138 None
139 } else {
140 Some(res)
141 }
142 }
143
144 /// Return the `if_macaddr` option value, if present
145 ///
146 /// If the option is present multiple times, the first value is returned.
147 ///
148 /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid,
149 /// or `Some(Err(_))` if value is present but invalid
150 pub fn if_macaddr(&self) -> Option<Result<&[u8], PcapNGOptionError>> {
151 options_get_as_bytes(&self.options, OptionCode::IfMacAddr)
152 }
153
154 /// Return the `if_euiaddr` option value, if present
155 ///
156 /// If the option is present multiple times, the first value is returned.
157 ///
158 /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid,
159 /// or `Some(Err(_))` if value is present but invalid
160 pub fn if_euiaddr(&self) -> Option<Result<&[u8], PcapNGOptionError>> {
161 options_get_as_bytes(&self.options, OptionCode::IfEuiAddr)
162 }
163
164 /// Return the `if_speed` option value, if present
165 ///
166 /// If the option is present multiple times, the first value is returned.
167 ///
168 /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid,
169 /// or `Some(Err(_))` if value is present but invalid
170 pub fn if_speed(&self) -> Option<Result<u64, PcapNGOptionError>> {
171 options_get_as_u64_le(&self.options, OptionCode::IfSpeed)
172 }
173
174 /// Return the `if_tsresol` option value, if present
175 ///
176 /// If the option is present multiple times, the first value is returned.
177 ///
178 /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid,
179 /// or `Some(Err(_))` if value is present but invalid
180 pub fn if_tsresol(&self) -> Option<Result<u8, PcapNGOptionError>> {
181 options_get_as_u8(&self.options, OptionCode::IfTsresol)
182 }
183
184 /// Return the `if_filter` option value, if present
185 ///
186 /// If the option is present multiple times, the first value is returned.
187 ///
188 /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid,
189 /// or `Some(Err(_))` if value is present but invalid
190 pub fn if_filter(&self) -> Option<Result<&str, PcapNGOptionError>> {
191 options_get_as_str(&self.options, OptionCode::IfFilter)
192 }
193
194 /// Return the `if_tsoffset` option value, if present
195 ///
196 /// If the option is present multiple times, the first value is returned.
197 ///
198 /// Returns `None` if option is not present, `Some(Ok(value))` if the value is present and valid,
199 /// or `Some(Err(_))` if value is present but invalid
200 pub fn if_tsoffset(&self) -> Option<Result<i64, PcapNGOptionError>> {
201 options_get_as_i64_le(&self.options, OptionCode::IfTsoffset)
202 }
203}
204
205impl<'a, En: PcapEndianness> PcapNGBlockParser<'a, En, InterfaceDescriptionBlock<'a>>
206 for InterfaceDescriptionBlock<'a>
207{
208 const HDR_SZ: usize = 20;
209 const MAGIC: u32 = IDB_MAGIC;
210
211 fn inner_parse<E: ParseError<&'a [u8]>>(
212 block_type: u32,
213 block_len1: u32,
214 i: &'a [u8],
215 block_len2: u32,
216 ) -> IResult<&'a [u8], InterfaceDescriptionBlock<'a>, E> {
217 // caller function already tested header type(magic) and length
218 // read end of header
219 let (i, linktype) = En::parse_u16(i)?;
220 let (i, reserved) = En::parse_u16(i)?;
221 let (i, snaplen) = En::parse_u32(i)?;
222 // read options
223 let (i, options) = opt_parse_options::<En, E>(i, block_len1 as usize, 20)?;
224 if block_len2 != block_len1 {
225 return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
226 }
227 let (if_tsresol, if_tsoffset) = if_extract_tsoffset_and_tsresol(&options);
228 let block = InterfaceDescriptionBlock {
229 block_type,
230 block_len1,
231 linktype: Linktype(linktype as i32),
232 reserved,
233 snaplen,
234 options,
235 block_len2,
236 if_tsresol,
237 if_tsoffset,
238 };
239 Ok((i, block))
240 }
241}
242
243/// Parse an Interface Packet Block (little-endian)
244pub fn parse_interfacedescriptionblock_le(
245 i: &[u8],
246) -> IResult<&[u8], InterfaceDescriptionBlock<'_>, PcapError<&[u8]>> {
247 ng_block_parser::<InterfaceDescriptionBlock, PcapLE, _, _>()(i)
248}
249
250/// Parse an Interface Packet Block (big-endian)
251pub fn parse_interfacedescriptionblock_be(
252 i: &[u8],
253) -> IResult<&[u8], InterfaceDescriptionBlock<'_>, PcapError<&[u8]>> {
254 ng_block_parser::<InterfaceDescriptionBlock, PcapBE, _, _>()(i)
255}