1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use crate::errors::PcapError;
use byteorder::{BigEndian, ByteOrder, LittleEndian, ReadBytesExt};
use crate::Endianness;
use crate::pcapng::blocks::common::opts_from_slice;
use crate::pcapng::{CustomBinaryOption, CustomUtf8Option, UnknownOption};
use std::borrow::Cow;
use derive_into_owned::IntoOwned;

///Section Header Block: it defines the most important characteristics of the capture file.
#[derive(Clone, Debug, IntoOwned)]
pub struct SectionHeaderBlock<'a> {

    /// Magic number, whose value is 0x1A2B3C4D.
    /// This number can be used to distinguish sections that have been saved
    /// on little-endian machines from the ones saved on big-endian machines.
    pub magic: u32,

    /// Major version of the format.
    /// Current value is 1.
    pub major_version: u16,

    /// Minor version of the format.
    /// Current value is 0.
    pub minor_version: u16,

    /// Length in bytes of the following section excluding this block.
    ///
    /// This block can be used to skip the section for faster navigation in
    /// large files. Length of -1i64 means that the length is unspecified.
    pub section_length: i64,

    pub options: Vec<SectionHeaderOption<'a>>
}


impl<'a> SectionHeaderBlock<'a> {

    pub fn from_slice(mut slice: &'a [u8]) -> Result<(&'a [u8], Self), PcapError> {

        if slice.len() < 16 {
            return Err(PcapError::InvalidField("SectionHeaderBlock: block length < 16"));
        }

        let magic = slice.read_u32::<BigEndian>()?;

        let (rem, major_version, minor_version, section_length, options) = match magic {

            0x1A2B3C4D => parse_inner::<BigEndian>(slice)?,
            0x4D3C2B1A => parse_inner::<LittleEndian>(slice)?,

            _ => unreachable!()
        };

        let block = SectionHeaderBlock {
            magic,
            major_version,
            minor_version,
            section_length,
            options
        };

        return Ok((rem, block));

        #[allow(clippy::type_complexity)]
        fn parse_inner<B: ByteOrder>(mut slice: &[u8]) -> Result<(&[u8], u16, u16, i64, Vec<SectionHeaderOption>), PcapError> {

            let maj_ver = slice.read_u16::<B>()?;
            let min_ver = slice.read_u16::<B>()?;
            let sec_len = slice.read_i64::<B>()?;
            let (rem, opts) = SectionHeaderOption::from_slice::<B>(slice)?;

            Ok((rem, maj_ver, min_ver, sec_len, opts))
        }
    }

    pub fn endianness(&self) -> Endianness {

        match self.magic {

            0x1A2B3C4D => Endianness::Big,
            0x4D3C2B1A => Endianness::Little,
            _ => unreachable!()

        }
    }
}

#[derive(Clone, Debug, IntoOwned)]
pub enum SectionHeaderOption<'a> {

    /// Comment associated with the current block
    Comment(Cow<'a, str>),

    /// Description of the hardware used to create this section
    Hardware(Cow<'a, str>),

    /// Name of the operating system used to create this section
    OS(Cow<'a, str>),

    /// Name of the application used to create this section
    UserApplication(Cow<'a, str>),

    /// Custom option containing binary octets in the Custom Data portion
    CustomBinary(CustomBinaryOption<'a>),

    /// Custom option containing a UTF-8 string in the Custom Data portion
    CustomUtf8(CustomUtf8Option<'a>),

    /// Unknown option
    Unknown(UnknownOption<'a>)
}


impl<'a> SectionHeaderOption<'a> {

    fn from_slice<B:ByteOrder>(slice: &'a [u8]) -> Result<(&'a [u8], Vec<Self>), PcapError> {

        opts_from_slice::<B, _, _>(slice, |slice, code, length| {

            let opt = match code {

                1 => SectionHeaderOption::Comment(Cow::Borrowed(std::str::from_utf8(slice)?)),
                2 => SectionHeaderOption::Hardware(Cow::Borrowed(std::str::from_utf8(slice)?)),
                3 => SectionHeaderOption::OS(Cow::Borrowed(std::str::from_utf8(slice)?)),
                4 => SectionHeaderOption::UserApplication(Cow::Borrowed(std::str::from_utf8(slice)?)),

                2988 | 19372 => SectionHeaderOption::CustomUtf8(CustomUtf8Option::from_slice::<B>(code, slice)?),
                2989 | 19373 => SectionHeaderOption::CustomBinary(CustomBinaryOption::from_slice::<B>(code, slice)?),

                _ => SectionHeaderOption::Unknown(UnknownOption::new(code, length, slice))
            };

            Ok(opt)
        })
    }
}