1#![allow(clippy::cast_lossless)]
2
3use std::borrow::Cow;
6use std::io::{Result as IoResult, Write};
7
8use byteorder_slice::byteorder::WriteBytesExt;
9use byteorder_slice::result::ReadSlice;
10use byteorder_slice::ByteOrder;
11use derive_into_owned::IntoOwned;
12
13use super::block_common::{Block, PcapNgBlock};
14use super::opt_common::{CustomBinaryOption, CustomUtf8Option, PcapNgOption, UnknownOption, WriteOptTo};
15use crate::errors::PcapError;
16use crate::DataLink;
17
18
19#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
22pub struct InterfaceDescriptionBlock<'a> {
23 pub linktype: DataLink,
28
29 pub snaplen: u32,
34
35 pub options: Vec<InterfaceDescriptionOption<'a>>,
37}
38
39impl<'a> PcapNgBlock<'a> for InterfaceDescriptionBlock<'a> {
40 fn from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> Result<(&'a [u8], Self), PcapError> {
41 if slice.len() < 8 {
42 return Err(PcapError::InvalidField("InterfaceDescriptionBlock: block length < 8"));
43 }
44
45 let linktype = (slice.read_u16::<B>().unwrap() as u32).into();
46
47 let reserved = slice.read_u16::<B>().unwrap();
48 if reserved != 0 {
49 return Err(PcapError::InvalidField("InterfaceDescriptionBlock: reserved != 0"));
50 }
51
52 let snaplen = slice.read_u32::<B>().unwrap();
53 let (slice, options) = InterfaceDescriptionOption::opts_from_slice::<B>(slice)?;
54
55 let block = InterfaceDescriptionBlock { linktype, snaplen, options };
56
57 Ok((slice, block))
58 }
59
60 fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
61 writer.write_u16::<B>(u32::from(self.linktype) as u16)?;
62 writer.write_u16::<B>(0)?;
63 writer.write_u32::<B>(self.snaplen)?;
64
65 let opt_len = InterfaceDescriptionOption::write_opts_to::<B, W>(&self.options, writer)?;
66 Ok(8 + opt_len)
67 }
68
69 fn into_block(self) -> Block<'a> {
70 Block::InterfaceDescription(self)
71 }
72}
73
74impl InterfaceDescriptionBlock<'static> {
75 pub fn new(linktype: DataLink, snaplen: u32) -> Self {
77 Self { linktype, snaplen, options: vec![] }
78 }
79}
80
81#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
83pub enum InterfaceDescriptionOption<'a> {
84 Comment(Cow<'a, str>),
87
88 IfName(Cow<'a, str>),
90
91 IfDescription(Cow<'a, str>),
93
94 IfIpv4Addr(Cow<'a, [u8]>),
96
97 IfIpv6Addr(Cow<'a, [u8]>),
99
100 IfMacAddr(Cow<'a, [u8]>),
102
103 IfEuIAddr(u64),
105
106 IfSpeed(u64),
108
109 IfTsResol(u8),
111
112 IfTzone(u32),
114
115 IfFilter(Cow<'a, [u8]>),
117
118 IfOs(Cow<'a, str>),
121
122 IfFcsLen(u8),
125
126 IfTsOffset(u64),
129
130 IfHardware(Cow<'a, str>),
132
133 CustomBinary(CustomBinaryOption<'a>),
135
136 CustomUtf8(CustomUtf8Option<'a>),
138
139 Unknown(UnknownOption<'a>),
141}
142
143impl<'a> PcapNgOption<'a> for InterfaceDescriptionOption<'a> {
144 fn from_slice<B: ByteOrder>(code: u16, length: u16, mut slice: &'a [u8]) -> Result<Self, PcapError> {
145 let opt = match code {
146 1 => InterfaceDescriptionOption::Comment(Cow::Borrowed(std::str::from_utf8(slice)?)),
147 2 => InterfaceDescriptionOption::IfName(Cow::Borrowed(std::str::from_utf8(slice)?)),
148 3 => InterfaceDescriptionOption::IfDescription(Cow::Borrowed(std::str::from_utf8(slice)?)),
149 4 => {
150 if slice.len() != 8 {
151 return Err(PcapError::InvalidField("InterfaceDescriptionOption: IfIpv4Addr length != 8"));
152 }
153 InterfaceDescriptionOption::IfIpv4Addr(Cow::Borrowed(slice))
154 },
155 5 => {
156 if slice.len() != 17 {
157 return Err(PcapError::InvalidField("InterfaceDescriptionOption: IfIpv6Addr length != 17"));
158 }
159 InterfaceDescriptionOption::IfIpv6Addr(Cow::Borrowed(slice))
160 },
161 6 => {
162 if slice.len() != 6 {
163 return Err(PcapError::InvalidField("InterfaceDescriptionOption: IfMacAddr length != 6"));
164 }
165 InterfaceDescriptionOption::IfMacAddr(Cow::Borrowed(slice))
166 },
167 7 => {
168 if slice.len() != 8 {
169 return Err(PcapError::InvalidField("InterfaceDescriptionOption: IfEuIAddr length != 8"));
170 }
171 InterfaceDescriptionOption::IfEuIAddr(slice.read_u64::<B>().map_err(|_| PcapError::IncompleteBuffer)?)
172 },
173 8 => {
174 if slice.len() != 8 {
175 return Err(PcapError::InvalidField("InterfaceDescriptionOption: IfSpeed length != 8"));
176 }
177 InterfaceDescriptionOption::IfSpeed(slice.read_u64::<B>().map_err(|_| PcapError::IncompleteBuffer)?)
178 },
179 9 => {
180 if slice.len() != 1 {
181 return Err(PcapError::InvalidField("InterfaceDescriptionOption: IfTsResol length != 1"));
182 }
183 InterfaceDescriptionOption::IfTsResol(slice.read_u8().map_err(|_| PcapError::IncompleteBuffer)?)
184 },
185 10 => {
186 if slice.len() != 1 {
187 return Err(PcapError::InvalidField("InterfaceDescriptionOption: IfTzone length != 1"));
188 }
189 InterfaceDescriptionOption::IfTzone(slice.read_u32::<B>().map_err(|_| PcapError::IncompleteBuffer)?)
190 },
191 11 => {
192 if slice.is_empty() {
193 return Err(PcapError::InvalidField("InterfaceDescriptionOption: IfFilter is empty"));
194 }
195 InterfaceDescriptionOption::IfFilter(Cow::Borrowed(slice))
196 },
197 12 => InterfaceDescriptionOption::IfOs(Cow::Borrowed(std::str::from_utf8(slice)?)),
198 13 => {
199 if slice.len() != 1 {
200 return Err(PcapError::InvalidField("InterfaceDescriptionOption: IfFcsLen length != 1"));
201 }
202 InterfaceDescriptionOption::IfFcsLen(slice.read_u8().map_err(|_| PcapError::IncompleteBuffer)?)
203 },
204 14 => {
205 if slice.len() != 8 {
206 return Err(PcapError::InvalidField("InterfaceDescriptionOption: IfTsOffset length != 8"));
207 }
208 InterfaceDescriptionOption::IfTsOffset(slice.read_u64::<B>().map_err(|_| PcapError::IncompleteBuffer)?)
209 },
210 15 => InterfaceDescriptionOption::IfHardware(Cow::Borrowed(std::str::from_utf8(slice)?)),
211
212 2988 | 19372 => InterfaceDescriptionOption::CustomUtf8(CustomUtf8Option::from_slice::<B>(code, slice)?),
213 2989 | 19373 => InterfaceDescriptionOption::CustomBinary(CustomBinaryOption::from_slice::<B>(code, slice)?),
214
215 _ => InterfaceDescriptionOption::Unknown(UnknownOption::new(code, length, slice)),
216 };
217
218 Ok(opt)
219 }
220
221 fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
222 match self {
223 InterfaceDescriptionOption::Comment(a) => a.write_opt_to::<B, W>(1, writer),
224 InterfaceDescriptionOption::IfName(a) => a.write_opt_to::<B, W>(2, writer),
225 InterfaceDescriptionOption::IfDescription(a) => a.write_opt_to::<B, W>(3, writer),
226 InterfaceDescriptionOption::IfIpv4Addr(a) => a.write_opt_to::<B, W>(4, writer),
227 InterfaceDescriptionOption::IfIpv6Addr(a) => a.write_opt_to::<B, W>(5, writer),
228 InterfaceDescriptionOption::IfMacAddr(a) => a.write_opt_to::<B, W>(6, writer),
229 InterfaceDescriptionOption::IfEuIAddr(a) => a.write_opt_to::<B, W>(7, writer),
230 InterfaceDescriptionOption::IfSpeed(a) => a.write_opt_to::<B, W>(8, writer),
231 InterfaceDescriptionOption::IfTsResol(a) => a.write_opt_to::<B, W>(9, writer),
232 InterfaceDescriptionOption::IfTzone(a) => a.write_opt_to::<B, W>(10, writer),
233 InterfaceDescriptionOption::IfFilter(a) => a.write_opt_to::<B, W>(11, writer),
234 InterfaceDescriptionOption::IfOs(a) => a.write_opt_to::<B, W>(12, writer),
235 InterfaceDescriptionOption::IfFcsLen(a) => a.write_opt_to::<B, W>(13, writer),
236 InterfaceDescriptionOption::IfTsOffset(a) => a.write_opt_to::<B, W>(14, writer),
237 InterfaceDescriptionOption::IfHardware(a) => a.write_opt_to::<B, W>(15, writer),
238 InterfaceDescriptionOption::CustomBinary(a) => a.write_opt_to::<B, W>(a.code, writer),
239 InterfaceDescriptionOption::CustomUtf8(a) => a.write_opt_to::<B, W>(a.code, writer),
240 InterfaceDescriptionOption::Unknown(a) => a.write_opt_to::<B, W>(a.code, writer),
241 }
242 }
243}