pcap_parser/pcapng/
option.rs1use std::borrow::Cow;
2use std::convert::TryFrom;
3
4use nom::combinator::{complete, map_parser};
5use nom::multi::many0;
6use nom::IResult;
7use nom::{bytes::streaming::take, error::ParseError};
8use rusticata_macros::{align32, newtype_enum};
9
10use crate::endianness::{PcapBE, PcapEndianness, PcapLE};
11
12#[derive(Clone, Copy, Eq, PartialEq)]
13pub struct OptionCode(pub u16);
14
15newtype_enum! {
16impl debug OptionCode {
17 EndOfOpt = 0,
18 Comment = 1,
19 ShbHardware = 2,
20 ShbOs = 3,
21 ShbUserAppl = 4,
22 IfTsresol = 9,
23 IfTsoffset = 14,
24 Custom2988 = 2988,
25 Custom2989 = 2989,
26 Custom19372 = 19372,
27 Custom19373 = 19373,
28}
29}
30
31#[derive(Debug)]
32pub struct PcapNGOption<'a> {
33 pub code: OptionCode,
34 pub len: u16,
35 pub value: Cow<'a, [u8]>,
36}
37
38impl<'a> PcapNGOption<'a> {
39 #[inline]
41 pub fn value(&self) -> &[u8] {
42 self.value.as_ref()
43 }
44
45 pub fn as_bytes(&self) -> Option<&[u8]> {
47 let len = usize::from(self.len);
48 if len <= self.value.len() {
49 Some(&self.value[..len])
50 } else {
51 None
52 }
53 }
54
55 pub fn as_i32_le(&self) -> Option<i32> {
59 if self.len == 8 && self.value.len() == 8 {
60 <[u8; 4]>::try_from(self.value())
61 .ok()
62 .map(i32::from_le_bytes)
63 } else {
64 None
65 }
66 }
67
68 pub fn as_u32_le(&self) -> Option<u32> {
72 if self.len == 8 && self.value.len() == 8 {
73 <[u8; 4]>::try_from(self.value())
74 .ok()
75 .map(u32::from_le_bytes)
76 } else {
77 None
78 }
79 }
80
81 pub fn as_i64_le(&self) -> Option<i64> {
85 if self.len == 8 && self.value.len() == 8 {
86 <[u8; 8]>::try_from(self.value())
87 .ok()
88 .map(i64::from_le_bytes)
89 } else {
90 None
91 }
92 }
93
94 pub fn as_u64_le(&self) -> Option<u64> {
98 if self.len == 8 && self.value.len() == 8 {
99 <[u8; 8]>::try_from(self.value())
100 .ok()
101 .map(u64::from_le_bytes)
102 } else {
103 None
104 }
105 }
106}
107
108#[inline]
110pub fn parse_option_le<'i, E: ParseError<&'i [u8]>>(
111 i: &'i [u8],
112) -> IResult<&'i [u8], PcapNGOption, E> {
113 parse_option::<PcapLE, E>(i)
114}
115
116#[inline]
118pub fn parse_option_be<'i, E: ParseError<&'i [u8]>>(
119 i: &'i [u8],
120) -> IResult<&'i [u8], PcapNGOption, E> {
121 parse_option::<PcapBE, E>(i)
122}
123
124pub(crate) fn parse_option<'i, En: PcapEndianness, E: ParseError<&'i [u8]>>(
125 i: &'i [u8],
126) -> IResult<&'i [u8], PcapNGOption, E> {
127 let (i, code) = En::parse_u16(i)?;
128 let (i, len) = En::parse_u16(i)?;
129 let (i, value) = take(align32!(len as u32))(i)?;
130 let option = PcapNGOption {
131 code: OptionCode(code),
132 len,
133 value: Cow::Borrowed(value),
134 };
135 Ok((i, option))
136}
137
138pub(crate) fn opt_parse_options<'i, En: PcapEndianness, E: ParseError<&'i [u8]>>(
139 i: &'i [u8],
140 len: usize,
141 opt_offset: usize,
142) -> IResult<&'i [u8], Vec<PcapNGOption>, E> {
143 if len > opt_offset {
144 map_parser(
145 take(len - opt_offset),
146 many0(complete(parse_option::<En, E>)),
147 )(i)
148 } else {
149 Ok((i, Vec::new()))
150 }
151}