pcap_file/pcapng/blocks/
interface_description.rs

1#![allow(clippy::cast_lossless)]
2
3//! Interface Description Block (IDB).
4
5use 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/// An Interface Description Block (IDB) is the container for information describing an interface
20/// on which packet data is captured.
21#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
22pub struct InterfaceDescriptionBlock<'a> {
23    /// A value that defines the link layer type of this interface.
24    /// 
25    /// The list of Standardized Link Layer Type codes is available in the
26    /// [tcpdump.org link-layer header types registry.](http://www.tcpdump.org/linktypes.html).
27    pub linktype: DataLink,
28
29    /// Maximum number of octets captured from each packet.
30    /// 
31    /// The portion of each packet that exceeds this value will not be stored in the file.
32    /// A value of zero indicates no limit.
33    pub snaplen: u32,
34
35    /// Options
36    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    /// Creates a new [`InterfaceDescriptionBlock`]
76    pub fn new(linktype: DataLink, snaplen: u32) -> Self {
77        Self { linktype, snaplen, options: vec![] }
78    }
79}
80
81/// The Interface Description Block (IDB) options
82#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
83pub enum InterfaceDescriptionOption<'a> {
84    /// The opt_comment option is a UTF-8 string containing human-readable comment text
85    /// that is associated to the current block.
86    Comment(Cow<'a, str>),
87
88    /// The if_name option is a UTF-8 string containing the name of the device used to capture data.
89    IfName(Cow<'a, str>),
90
91    /// The if_description option is a UTF-8 string containing the description of the device used to capture data.
92    IfDescription(Cow<'a, str>),
93
94    /// The if_IPv4addr option is an IPv4 network address and corresponding netmask for the interface.
95    IfIpv4Addr(Cow<'a, [u8]>),
96
97    /// The if_IPv6addr option is an IPv6 network address and corresponding prefix length for the interface.
98    IfIpv6Addr(Cow<'a, [u8]>),
99
100    /// The if_MACaddr option is the Interface Hardware MAC address (48 bits), if available.
101    IfMacAddr(Cow<'a, [u8]>),
102
103    /// The if_EUIaddr option is the Interface Hardware EUI address (64 bits), if available.
104    IfEuIAddr(u64),
105
106    /// The if_speed option is a 64-bit number for the Interface speed (in bits per second).
107    IfSpeed(u64),
108
109    /// The if_tsresol option identifies the resolution of timestamps.
110    IfTsResol(u8),
111
112    /// The if_tzone option identifies the time zone for GMT support.
113    IfTzone(u32),
114
115    /// The if_filter option identifies the filter (e.g. "capture only TCP traffic") used to capture traffic.
116    IfFilter(Cow<'a, [u8]>),
117
118    /// The if_os option is a UTF-8 string containing the name of the operating system
119    /// of the machine in which this interface is installed.
120    IfOs(Cow<'a, str>),
121
122    /// The if_fcslen option is an 8-bit unsigned integer value that specifies
123    /// the length of the Frame Check Sequence (in bits) for this interface.
124    IfFcsLen(u8),
125
126    /// The if_tsoffset option is a 64-bit integer value that specifies an offset (in seconds)
127    /// that must be added to the timestamp of each packet to obtain the absolute timestamp of a packet.
128    IfTsOffset(u64),
129
130    /// The if_hardware option is a UTF-8 string containing the description of the interface hardware.
131    IfHardware(Cow<'a, str>),
132
133    /// Custom option containing binary octets in the Custom Data portion
134    CustomBinary(CustomBinaryOption<'a>),
135
136    /// Custom option containing a UTF-8 string in the Custom Data portion
137    CustomUtf8(CustomUtf8Option<'a>),
138
139    /// Unknown option
140    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}