pcap_file_tokio/pcapng/blocks/
section_header.rs1use 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#[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
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#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
110pub enum SectionHeaderOption<'a> {
111 Comment(Cow<'a, str>),
113
114 Hardware(Cow<'a, str>),
116
117 OS(Cow<'a, str>),
119
120 UserApplication(Cow<'a, str>),
122
123 CustomBinary(CustomBinaryOption<'a>),
125
126 CustomUtf8(CustomUtf8Option<'a>),
128
129 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}