1use std::borrow::Cow;
4use std::io::{Result as IoResult, Write};
5
6use byteorder_slice::byteorder::WriteBytesExt;
7use byteorder_slice::result::ReadSlice;
8use byteorder_slice::{BigEndian, ByteOrder, LittleEndian};
9use derive_into_owned::IntoOwned;
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#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
19pub struct SectionHeaderBlock<'a> {
20 pub endianness: Endianness,
22
23 pub major_version: u16,
26
27 pub minor_version: u16,
30
31 pub section_length: i64,
36
37 pub options: Vec<SectionHeaderOption<'a>>,
39}
40
41impl<'a> PcapNgBlock<'a> for SectionHeaderBlock<'a> {
42 fn from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> Result<(&'a [u8], Self), PcapError> {
43 if slice.len() < 16 {
44 return Err(PcapError::InvalidField("SectionHeaderBlock: block length < 16"));
45 }
46
47 let magic = slice.read_u32::<BigEndian>().unwrap();
48 let endianness = match magic {
49 0x1A2B3C4D => Endianness::Big,
50 0x4D3C2B1A => Endianness::Little,
51 _ => return Err(PcapError::InvalidField("SectionHeaderBlock: invalid magic number")),
52 };
53
54 let (rem, major_version, minor_version, section_length, options) = match endianness {
55 Endianness::Big => parse_inner::<BigEndian>(slice)?,
56 Endianness::Little => parse_inner::<LittleEndian>(slice)?,
57 };
58
59 let block = SectionHeaderBlock { endianness, major_version, minor_version, section_length, options };
60
61 return Ok((rem, block));
62
63 #[allow(clippy::type_complexity)]
64 fn parse_inner<B: ByteOrder>(mut slice: &[u8]) -> Result<(&[u8], u16, u16, i64, Vec<SectionHeaderOption>), PcapError> {
65 let maj_ver = slice.read_u16::<B>().unwrap();
66 let min_ver = slice.read_u16::<B>().unwrap();
67 let sec_len = slice.read_i64::<B>().unwrap();
68 let (rem, opts) = SectionHeaderOption::opts_from_slice::<B>(slice)?;
69
70 Ok((rem, maj_ver, min_ver, sec_len, opts))
71 }
72 }
73
74 fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
75 match self.endianness {
76 Endianness::Big => writer.write_u32::<BigEndian>(0x1A2B3C4D)?,
77 Endianness::Little => writer.write_u32::<LittleEndian>(0x1A2B3C4D)?,
78 };
79
80 writer.write_u16::<B>(self.major_version)?;
81 writer.write_u16::<B>(self.minor_version)?;
82 writer.write_i64::<B>(self.section_length)?;
83
84 let opt_len = SectionHeaderOption::write_opts_to::<B, W>(&self.options, writer)?;
85
86 Ok(16 + opt_len)
87 }
88
89 fn into_block(self) -> Block<'a> {
90 Block::SectionHeader(self)
91 }
92}
93
94impl Default for SectionHeaderBlock<'static> {
95 fn default() -> Self {
96 Self {
97 endianness: Endianness::Big,
98 major_version: 1,
99 minor_version: 0,
100 section_length: -1,
101 options: vec![],
102 }
103 }
104}
105
106
107#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
109pub enum SectionHeaderOption<'a> {
110 Comment(Cow<'a, str>),
112
113 Hardware(Cow<'a, str>),
115
116 OS(Cow<'a, str>),
118
119 UserApplication(Cow<'a, str>),
121
122 CustomBinary(CustomBinaryOption<'a>),
124
125 CustomUtf8(CustomUtf8Option<'a>),
127
128 Unknown(UnknownOption<'a>),
130}
131
132impl<'a> PcapNgOption<'a> for SectionHeaderOption<'a> {
133 fn from_slice<B: ByteOrder>(code: u16, length: u16, slice: &'a [u8]) -> Result<Self, PcapError> {
134 let opt = match code {
135 1 => SectionHeaderOption::Comment(Cow::Borrowed(std::str::from_utf8(slice)?)),
136 2 => SectionHeaderOption::Hardware(Cow::Borrowed(std::str::from_utf8(slice)?)),
137 3 => SectionHeaderOption::OS(Cow::Borrowed(std::str::from_utf8(slice)?)),
138 4 => SectionHeaderOption::UserApplication(Cow::Borrowed(std::str::from_utf8(slice)?)),
139
140 2988 | 19372 => SectionHeaderOption::CustomUtf8(CustomUtf8Option::from_slice::<B>(code, slice)?),
141 2989 | 19373 => SectionHeaderOption::CustomBinary(CustomBinaryOption::from_slice::<B>(code, slice)?),
142
143 _ => SectionHeaderOption::Unknown(UnknownOption::new(code, length, slice)),
144 };
145
146 Ok(opt)
147 }
148
149 fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
150 match self {
151 SectionHeaderOption::Comment(a) => a.write_opt_to::<B, W>(1, writer),
152 SectionHeaderOption::Hardware(a) => a.write_opt_to::<B, W>(2, writer),
153 SectionHeaderOption::OS(a) => a.write_opt_to::<B, W>(3, writer),
154 SectionHeaderOption::UserApplication(a) => a.write_opt_to::<B, W>(4, writer),
155 SectionHeaderOption::CustomBinary(a) => a.write_opt_to::<B, W>(a.code, writer),
156 SectionHeaderOption::CustomUtf8(a) => a.write_opt_to::<B, W>(a.code, writer),
157 SectionHeaderOption::Unknown(a) => a.write_opt_to::<B, W>(a.code, writer),
158 }
159 }
160}