pcap_file_tokio/pcapng/blocks/
section_header.rs

1//! Section Header Block.
2
3use std::borrow::Cow;
4use std::io::Result as IoResult;
5
6use byteorder::{ByteOrder, BigEndian, LittleEndian};
7use derive_into_owned::IntoOwned;
8use tokio::io::AsyncWrite;
9use tokio_byteorder::{AsyncReadBytesExt, AsyncWriteBytesExt};
10
11use super::block_common::{Block, PcapNgBlock};
12use super::opt_common::{CustomBinaryOption, CustomUtf8Option, PcapNgOption, UnknownOption, WriteOptTo};
13use crate::errors::PcapError;
14use crate::Endianness;
15
16
17/// Section Header Block: it defines the most important characteristics of the capture file.
18#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
19pub struct SectionHeaderBlock<'a> {
20    /// Endianness of the section.
21    pub endianness: Endianness,
22
23    /// Major version of the format.
24    /// Current value is 1.
25    pub major_version: u16,
26
27    /// Minor version of the format.
28    /// Current value is 0.
29    pub minor_version: u16,
30
31    /// Length in bytes of the following section excluding this block.
32    ///
33    /// This block can be used to skip the section for faster navigation in
34    /// large files. Length of -1i64 means that the length is unspecified.
35    pub section_length: i64,
36
37    /// Options
38    pub options: Vec<SectionHeaderOption<'a>>,
39}
40
41#[async_trait::async_trait]
42impl<'a> PcapNgBlock<'a> for SectionHeaderBlock<'a> {
43    async fn from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> Result<(&'a [u8], SectionHeaderBlock<'a>), PcapError> {
44        if slice.len() < 16 {
45            return Err(PcapError::InvalidField("SectionHeaderBlock: block length < 16"));
46        }
47
48        let magic = slice.read_u32::<BigEndian>().await.unwrap();
49        let endianness = match magic {
50            0x1A2B3C4D => Endianness::Big,
51            0x4D3C2B1A => Endianness::Little,
52            _ => return Err(PcapError::InvalidField("SectionHeaderBlock: invalid magic number")),
53        };
54
55        let (rem, major_version, minor_version, section_length, options) = match endianness {
56            Endianness::Big => parse_inner::<BigEndian>(slice).await?,
57            Endianness::Little => parse_inner::<LittleEndian>(slice).await?,
58        };
59
60        let block = SectionHeaderBlock { endianness, major_version, minor_version, section_length, options };
61
62        return Ok((rem, block));
63
64        #[allow(clippy::type_complexity)]
65        async fn parse_inner<B: ByteOrder + Send>(mut slice: &[u8]) -> Result<(&[u8], u16, u16, i64, Vec<SectionHeaderOption>), PcapError> {
66            let maj_ver = slice.read_u16::<B>().await.unwrap();
67            let min_ver = slice.read_u16::<B>().await.unwrap();
68            let sec_len = slice.read_i64::<B>().await.unwrap();
69            let (rem, opts) = SectionHeaderOption::opts_from_slice::<B>(slice).await?;
70
71            Ok((rem, maj_ver, min_ver, sec_len, opts))
72        }
73    }
74
75    async fn write_to<B: ByteOrder, W: AsyncWrite + Unpin + Send>(&self, writer: &mut W) -> IoResult<usize> {
76        match self.endianness {
77            Endianness::Big => writer.write_u32::<BigEndian>(0x1A2B3C4D).await?,
78            Endianness::Little => writer.write_u32::<LittleEndian>(0x1A2B3C4D).await?,
79        };
80
81        writer.write_u16::<B>(self.major_version).await?;
82        writer.write_u16::<B>(self.minor_version).await?;
83        writer.write_i64::<B>(self.section_length).await?;
84
85        let opt_len = SectionHeaderOption::write_opts_to::<B, W>(&self.options, writer).await?;
86
87        Ok(16 + opt_len)
88    }
89
90    fn into_block(self) -> Block<'a> {
91        Block::SectionHeader(self)
92    }
93}
94
95impl Default for SectionHeaderBlock<'static> {
96    fn default() -> Self {
97        Self {
98            endianness: Endianness::Big,
99            major_version: 1,
100            minor_version: 0,
101            section_length: -1,
102            options: vec![],
103        }
104    }
105}
106
107
108/// Section Header Block options
109#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
110pub enum SectionHeaderOption<'a> {
111    /// Comment associated with the current block
112    Comment(Cow<'a, str>),
113
114    /// Description of the hardware used to create this section
115    Hardware(Cow<'a, str>),
116
117    /// Name of the operating system used to create this section
118    OS(Cow<'a, str>),
119
120    /// Name of the application used to create this section
121    UserApplication(Cow<'a, str>),
122
123    /// Custom option containing binary octets in the Custom Data portion
124    CustomBinary(CustomBinaryOption<'a>),
125
126    /// Custom option containing a UTF-8 string in the Custom Data portion
127    CustomUtf8(CustomUtf8Option<'a>),
128
129    /// Unknown option
130    Unknown(UnknownOption<'a>),
131}
132
133#[async_trait::async_trait]
134impl<'a> PcapNgOption<'a> for SectionHeaderOption<'a> {
135    async fn from_slice<B: ByteOrder + Send>(code: u16, length: u16, slice: &'a [u8]) -> Result<SectionHeaderOption<'a>, PcapError> {
136        let opt = match code {
137            1 => SectionHeaderOption::Comment(Cow::Borrowed(std::str::from_utf8(slice)?)),
138            2 => SectionHeaderOption::Hardware(Cow::Borrowed(std::str::from_utf8(slice)?)),
139            3 => SectionHeaderOption::OS(Cow::Borrowed(std::str::from_utf8(slice)?)),
140            4 => SectionHeaderOption::UserApplication(Cow::Borrowed(std::str::from_utf8(slice)?)),
141
142            2988 | 19372 => SectionHeaderOption::CustomUtf8(CustomUtf8Option::from_slice::<B>(code, slice).await?),
143            2989 | 19373 => SectionHeaderOption::CustomBinary(CustomBinaryOption::from_slice::<B>(code, slice).await?),
144
145            _ => SectionHeaderOption::Unknown(UnknownOption::new(code, length, slice)),
146        };
147
148        Ok(opt)
149    }
150
151    async fn write_to<B: ByteOrder, W: AsyncWrite + Unpin + Send>(&self, writer: &mut W) -> IoResult<usize> {
152        match self {
153            SectionHeaderOption::Comment(a) => a.write_opt_to::<B, W>(1, writer).await,
154            SectionHeaderOption::Hardware(a) => a.write_opt_to::<B, W>(2, writer).await,
155            SectionHeaderOption::OS(a) => a.write_opt_to::<B, W>(3, writer).await,
156            SectionHeaderOption::UserApplication(a) => a.write_opt_to::<B, W>(4, writer).await,
157            SectionHeaderOption::CustomBinary(a) => a.write_opt_to::<B, W>(a.code, writer).await,
158            SectionHeaderOption::CustomUtf8(a) => a.write_opt_to::<B, W>(a.code, writer).await,
159            SectionHeaderOption::Unknown(a) => a.write_opt_to::<B, W>(a.code, writer).await,
160        }
161    }
162}