pcaparse/pcapng/blocks/
opt_common.rs

1use std::borrow::Cow;
2use std::io::Result as IoResult;
3use std::io::Write;
4
5use byteorder::ReadBytesExt;
6use byteorder::WriteBytesExt;
7use derive_into_owned::IntoOwned;
8
9use byteorder::ByteOrder;
10#[cfg(feature = "tokio")]
11use tokio::io::AsyncWrite;
12#[cfg(feature = "tokio")]
13use tokio_byteorder::{AsyncReadBytesExt, AsyncWriteBytesExt};
14
15use crate::errors::PcapError;
16
17/// Common fonctions of the PcapNg options
18pub(crate) trait PcapNgOption<'a> {
19    /// Parse an option from a slice
20    fn from_slice<B: ByteOrder>(code: u16, length: u16, slice: &'a [u8]) -> Result<Self, PcapError>
21    where
22        Self: std::marker::Sized;
23
24    /// Parse all options in a block
25    fn opts_from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> Result<(&'a [u8], Vec<Self>), PcapError>
26    where
27        Self: std::marker::Sized,
28    {
29        let mut options = vec![];
30
31        // If there is nothing left in the slice, it means that there is no option
32        if slice.is_empty() {
33            return Ok((slice, options));
34        }
35
36        while !slice.is_empty() {
37            if slice.len() < 4 {
38                return Err(PcapError::InvalidField("Option: slice.len() < 4"));
39            }
40
41            let code = ReadBytesExt::read_u16::<B>(&mut slice).unwrap();
42            let length = ReadBytesExt::read_u16::<B>(&mut slice).unwrap() as usize;
43            let pad_len = (4 - (length % 4)) % 4;
44
45            if code == 0 {
46                return Ok((slice, options));
47            }
48
49            if slice.len() < length + pad_len {
50                return Err(PcapError::InvalidField("Option: length + pad.len() > slice.len()"));
51            }
52
53            let tmp_slice = &slice[..length];
54            let opt = Self::from_slice::<B>(code, length as u16, tmp_slice)?;
55
56            // Jump over the padding
57            slice = &slice[length + pad_len..];
58
59            options.push(opt);
60        }
61
62        Err(PcapError::InvalidField("Invalid option"))
63    }
64
65    /// Write the option to a writer
66    fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize>;
67
68    /// Write all options in a block
69    fn write_opts_to<B: ByteOrder, W: Write>(opts: &[Self], writer: &mut W) -> IoResult<usize>
70    where
71        Self: std::marker::Sized,
72    {
73        let mut have_opt = false;
74        let mut written = 0;
75        for opt in opts {
76            written += opt.write_to::<B, W>(writer)?;
77            have_opt = true;
78        }
79
80        if have_opt {
81            writer.write_u16::<B>(0)?;
82            writer.write_u16::<B>(0)?;
83            written += 4;
84        }
85
86        Ok(written)
87    }
88}
89
90#[cfg(feature = "tokio")]
91#[async_trait::async_trait]
92pub(crate) trait AsyncPcapNgOption<'a> {
93    /// Parse an option from a slice
94    async fn async_from_slice<B: ByteOrder + Send>(code: u16, length: u16, slice: &'a [u8]) -> Result<Self, PcapError>
95    where
96        Self: std::marker::Sized;
97
98    /// Parse all options in a block
99    async fn async_opts_from_slice<B: ByteOrder + Send>(mut slice: &'a [u8]) -> Result<(&'a [u8], Vec<Self>), PcapError>
100    where
101        Self: std::marker::Sized,
102    {
103        let mut options = vec![];
104
105        // If there is nothing left in the slice, it means that there is no option
106        if slice.is_empty() {
107            return Ok((slice, options));
108        }
109
110        while !slice.is_empty() {
111            if slice.len() < 4 {
112                return Err(PcapError::InvalidField("Option: slice.len() < 4"));
113            }
114
115            let code = AsyncReadBytesExt::read_u16::<B>(&mut slice).await.unwrap();
116            let length = AsyncReadBytesExt::read_u16::<B>(&mut slice).await.unwrap() as usize;
117            let pad_len = (4 - (length % 4)) % 4;
118
119            if code == 0 {
120                return Ok((slice, options));
121            }
122
123            if slice.len() < length + pad_len {
124                return Err(PcapError::InvalidField("Option: length + pad.len() > slice.len()"));
125            }
126
127            let tmp_slice = &slice[..length];
128            let opt = Self::async_from_slice::<B>(code, length as u16, tmp_slice).await?;
129
130            // Jump over the padding
131            slice = &slice[length + pad_len..];
132
133            options.push(opt);
134        }
135
136        Err(PcapError::InvalidField("Invalid option"))
137    }
138
139    /// Write the option to a writer
140    async fn async_write_to<B: ByteOrder, W: AsyncWrite + Unpin + Send>(&self, writer: &mut W) -> IoResult<usize>;
141
142    /// Write all options in a block
143    async fn async_write_opts_to<B: ByteOrder, W: AsyncWrite + Unpin + Send>(opts: &[Self], writer: &mut W) -> IoResult<usize>
144    where
145        Self: std::marker::Sized + Sync,
146    {
147        let mut have_opt = false;
148        let mut written = 0;
149        for opt in opts {
150            written += opt.async_write_to::<B, W>(writer).await?;
151            have_opt = true;
152        }
153
154        if have_opt {
155            writer.write_u16::<B>(0).await?;
156            writer.write_u16::<B>(0).await?;
157            written += 4;
158        }
159
160        Ok(written)
161    }
162}
163
164/// Unknown options
165#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
166pub struct UnknownOption<'a> {
167    /// Option code
168    pub code: u16,
169    /// Option length
170    pub length: u16,
171    /// Option value
172    pub value: Cow<'a, [u8]>,
173}
174
175impl<'a> UnknownOption<'a> {
176    /// Creates a new [`UnknownOption`]
177    pub fn new(code: u16, length: u16, value: &'a [u8]) -> Self {
178        UnknownOption { code, length, value: Cow::Borrowed(value) }
179    }
180}
181
182/// Custom binary option
183#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
184pub struct CustomBinaryOption<'a> {
185    /// Option code
186    pub code: u16,
187    /// Option PEN identifier
188    pub pen: u32,
189    /// Option value
190    pub value: Cow<'a, [u8]>,
191}
192
193impl<'a> CustomBinaryOption<'a> {
194    /// Parse an [`CustomBinaryOption`] from a slice
195    pub fn from_slice<B: ByteOrder>(code: u16, mut src: &'a [u8]) -> Result<Self, PcapError> {
196        let pen = ReadBytesExt::read_u32::<B>(&mut src).map_err(|_| PcapError::IncompleteBuffer)?;
197        let opt = CustomBinaryOption { code, pen, value: Cow::Borrowed(src) };
198        Ok(opt)
199    }
200
201    #[cfg(feature = "tokio")]
202    pub async fn async_from_slice<B: ByteOrder>(code: u16, mut src: &'a [u8]) -> Result<CustomBinaryOption<'a>, PcapError> {
203        let pen = AsyncReadBytesExt::read_u32::<B>(&mut src).await.map_err(|_| PcapError::IncompleteBuffer)?;
204        let opt = CustomBinaryOption { code, pen, value: Cow::Borrowed(src) };
205        Ok(opt)
206    }
207}
208
209/// Custom string (UTF-8) option
210#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
211pub struct CustomUtf8Option<'a> {
212    /// Option code
213    pub code: u16,
214    /// Option PEN identifier
215    pub pen: u32,
216    /// Option value
217    pub value: Cow<'a, str>,
218}
219
220impl<'a> CustomUtf8Option<'a> {
221    /// Parse a [`CustomUtf8Option`] from a slice
222    pub fn from_slice<B: ByteOrder>(code: u16, mut src: &'a [u8]) -> Result<Self, PcapError> {
223        let pen = ReadBytesExt::read_u32::<B>(&mut src).map_err(|_| PcapError::IncompleteBuffer)?;
224        let opt = CustomUtf8Option { code, pen, value: Cow::Borrowed(std::str::from_utf8(src)?) };
225        Ok(opt)
226    }
227
228    #[cfg(feature = "tokio")]
229    pub async fn async_from_slice<B: ByteOrder>(code: u16, mut src: &'a [u8]) -> Result<CustomUtf8Option<'a>, PcapError> {
230        let pen = AsyncReadBytesExt::read_u32::<B>(&mut src).await.map_err(|_| PcapError::IncompleteBuffer)?;
231        let opt = CustomUtf8Option { code, pen, value: Cow::Borrowed(std::str::from_utf8(src)?) };
232        Ok(opt)
233    }
234}
235
236pub(crate) trait WriteOptTo {
237    fn write_opt_to<B: ByteOrder, W: Write>(&self, code: u16, writer: &mut W) -> IoResult<usize>;
238}
239
240impl<'a> WriteOptTo for Cow<'a, [u8]> {
241    fn write_opt_to<B: ByteOrder, W: Write>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
242        let len = self.len();
243        let pad_len = (4 - len % 4) % 4;
244
245        writer.write_u16::<B>(code)?;
246        writer.write_u16::<B>(len as u16)?;
247        writer.write_all(self)?;
248        writer.write_all(&[0_u8; 3][..pad_len])?;
249
250        Ok(len + pad_len + 4)
251    }
252}
253
254impl<'a> WriteOptTo for Cow<'a, str> {
255    fn write_opt_to<B: ByteOrder, W: Write>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
256        let len = self.as_bytes().len();
257        let pad_len = (4 - len % 4) % 4;
258
259        writer.write_u16::<B>(code)?;
260        writer.write_u16::<B>(len as u16)?;
261        writer.write_all(self.as_bytes())?;
262        writer.write_all(&[0_u8; 3][..pad_len])?;
263
264        Ok(len + pad_len + 4)
265    }
266}
267
268impl WriteOptTo for u8 {
269    fn write_opt_to<B: ByteOrder, W: Write>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
270        writer.write_u16::<B>(code)?;
271        writer.write_u16::<B>(1)?;
272        writer.write_u8(*self)?;
273        writer.write_all(&[0_u8; 3])?;
274
275        Ok(8)
276    }
277}
278
279impl WriteOptTo for u16 {
280    fn write_opt_to<B: ByteOrder, W: Write>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
281        writer.write_u16::<B>(code)?;
282        writer.write_u16::<B>(2)?;
283        writer.write_u16::<B>(*self)?;
284        writer.write_all(&[0_u8; 2])?;
285
286        Ok(8)
287    }
288}
289
290impl WriteOptTo for u32 {
291    fn write_opt_to<B: ByteOrder, W: Write>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
292        writer.write_u16::<B>(code)?;
293        writer.write_u16::<B>(4)?;
294        writer.write_u32::<B>(*self)?;
295
296        Ok(8)
297    }
298}
299
300impl WriteOptTo for u64 {
301    fn write_opt_to<B: ByteOrder, W: Write>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
302        writer.write_u16::<B>(code)?;
303        writer.write_u16::<B>(8)?;
304        writer.write_u64::<B>(*self)?;
305
306        Ok(12)
307    }
308}
309
310impl<'a> WriteOptTo for CustomBinaryOption<'a> {
311    fn write_opt_to<B: ByteOrder, W: Write>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
312        let len = &self.value.len() + 4;
313        let pad_len = (4 - len % 4) % 4;
314
315        writer.write_u16::<B>(code)?;
316        writer.write_u16::<B>(len as u16)?;
317        writer.write_u32::<B>(self.pen)?;
318        writer.write_all(&self.value)?;
319        writer.write_all(&[0_u8; 3][..pad_len])?;
320
321        Ok(len + pad_len + 4)
322    }
323}
324
325impl<'a> WriteOptTo for CustomUtf8Option<'a> {
326    fn write_opt_to<B: ByteOrder, W: Write>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
327        let len = &self.value.len() + 4;
328        let pad_len = (4 - len % 4) % 4;
329
330        writer.write_u16::<B>(code)?;
331        writer.write_u16::<B>(len as u16)?;
332        writer.write_u32::<B>(self.pen)?;
333        writer.write_all(self.value.as_bytes())?;
334        writer.write_all(&[0_u8; 3][..pad_len])?;
335
336        Ok(len + pad_len + 4)
337    }
338}
339
340impl<'a> WriteOptTo for UnknownOption<'a> {
341    fn write_opt_to<B: ByteOrder, W: Write>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
342        let len = self.value.len();
343        let pad_len = (4 - len % 4) % 4;
344
345        writer.write_u16::<B>(code)?;
346        writer.write_u16::<B>(len as u16)?;
347        writer.write_all(&self.value)?;
348        writer.write_all(&[0_u8; 3][..pad_len])?;
349
350        Ok(len + pad_len + 4)
351    }
352}
353
354#[cfg(feature = "tokio")]
355#[async_trait::async_trait]
356pub(crate) trait AsyncWriteOptTo {
357    async fn async_write_opt_to<B: ByteOrder, W: AsyncWrite + Unpin + Send>(&self, code: u16, writer: &mut W) -> IoResult<usize>;
358}
359
360#[cfg(feature = "tokio")]
361#[async_trait::async_trait]
362impl<'a> AsyncWriteOptTo for Cow<'a, [u8]> {
363    async fn async_write_opt_to<B: ByteOrder, W: AsyncWrite + Unpin + Send>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
364        let len = self.len();
365        let pad_len = (4 - len % 4) % 4;
366
367        writer.write_u16::<B>(code).await?;
368        writer.write_u16::<B>(len as u16).await?;
369        tokio::io::AsyncWriteExt::write_all(writer, self).await?;
370        tokio::io::AsyncWriteExt::write_all(writer, &[0_u8; 3][..pad_len]).await?;
371
372        Ok(len + pad_len + 4)
373    }
374}
375
376#[cfg(feature = "tokio")]
377#[async_trait::async_trait]
378impl<'a> AsyncWriteOptTo for Cow<'a, str> {
379    async fn async_write_opt_to<B: ByteOrder, W: AsyncWrite + Unpin + Send>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
380        let len = self.as_bytes().len();
381        let pad_len = (4 - len % 4) % 4;
382
383        writer.write_u16::<B>(code).await?;
384        writer.write_u16::<B>(len as u16).await?;
385        tokio::io::AsyncWriteExt::write_all(writer, self.as_bytes()).await?;
386        tokio::io::AsyncWriteExt::write_all(writer, &[0_u8; 3][..pad_len]).await?;
387
388        Ok(len + pad_len + 4)
389    }
390}
391
392#[cfg(feature = "tokio")]
393#[async_trait::async_trait]
394impl AsyncWriteOptTo for u8 {
395    async fn async_write_opt_to<B: ByteOrder, W: AsyncWrite + Unpin + Send>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
396        writer.write_u16::<B>(code).await?;
397        writer.write_u16::<B>(1).await?;
398        writer.write_u8(*self).await?;
399        tokio::io::AsyncWriteExt::write_all(writer, &[0_u8; 3]).await?;
400
401        Ok(8)
402    }
403}
404
405#[cfg(feature = "tokio")]
406#[async_trait::async_trait]
407impl AsyncWriteOptTo for u16 {
408    async fn async_write_opt_to<B: ByteOrder, W: AsyncWrite + Unpin + Send>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
409        writer.write_u16::<B>(code).await?;
410        writer.write_u16::<B>(2).await?;
411        writer.write_u16::<B>(*self).await?;
412        tokio::io::AsyncWriteExt::write_all(writer, &[0_u8; 2]).await?;
413
414        Ok(8)
415    }
416}
417
418#[cfg(feature = "tokio")]
419#[async_trait::async_trait]
420impl AsyncWriteOptTo for u32 {
421    async fn async_write_opt_to<B: ByteOrder, W: AsyncWrite + Unpin + Send>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
422        writer.write_u16::<B>(code).await?;
423        writer.write_u16::<B>(4).await?;
424        writer.write_u32::<B>(*self).await?;
425
426        Ok(8)
427    }
428}
429
430#[cfg(feature = "tokio")]
431#[async_trait::async_trait]
432impl AsyncWriteOptTo for u64 {
433    async fn async_write_opt_to<B: ByteOrder, W: AsyncWrite + Unpin + Send>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
434        writer.write_u16::<B>(code).await?;
435        writer.write_u16::<B>(8).await?;
436        writer.write_u64::<B>(*self).await?;
437
438        Ok(12)
439    }
440}
441
442#[cfg(feature = "tokio")]
443#[async_trait::async_trait]
444impl<'a> AsyncWriteOptTo for CustomBinaryOption<'a> {
445    async fn async_write_opt_to<B: ByteOrder, W: AsyncWrite + Unpin + Send>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
446        let len = &self.value.len() + 4;
447        let pad_len = (4 - len % 4) % 4;
448
449        writer.write_u16::<B>(code).await?;
450        writer.write_u16::<B>(len as u16).await?;
451        writer.write_u32::<B>(self.pen).await?;
452        tokio::io::AsyncWriteExt::write_all(writer, &self.value).await?;
453        tokio::io::AsyncWriteExt::write_all(writer, &[0_u8; 3][..pad_len]).await?;
454
455        Ok(len + pad_len + 4)
456    }
457}
458
459#[cfg(feature = "tokio")]
460#[async_trait::async_trait]
461impl<'a> AsyncWriteOptTo for CustomUtf8Option<'a> {
462    async fn async_write_opt_to<B: ByteOrder, W: AsyncWrite + Unpin + Send>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
463        let len = &self.value.len() + 4;
464        let pad_len = (4 - len % 4) % 4;
465
466        writer.write_u16::<B>(code).await?;
467        writer.write_u16::<B>(len as u16).await?;
468        writer.write_u32::<B>(self.pen).await?;
469        tokio::io::AsyncWriteExt::write_all(writer, self.value.as_bytes()).await?;
470        tokio::io::AsyncWriteExt::write_all(writer, &[0_u8; 3][..pad_len]).await?;
471
472        Ok(len + pad_len + 4)
473    }
474}
475
476#[cfg(feature = "tokio")]
477#[async_trait::async_trait]
478impl<'a> AsyncWriteOptTo for UnknownOption<'a> {
479    async fn async_write_opt_to<B: ByteOrder, W: AsyncWrite + Unpin + Send>(&self, code: u16, writer: &mut W) -> IoResult<usize> {
480        let len = self.value.len();
481        let pad_len = (4 - len % 4) % 4;
482
483        writer.write_u16::<B>(code).await?;
484        writer.write_u16::<B>(len as u16).await?;
485        tokio::io::AsyncWriteExt::write_all(writer, &self.value).await?;
486        tokio::io::AsyncWriteExt::write_all(writer, &[0_u8; 3][..pad_len]).await?;
487
488        Ok(len + pad_len + 4)
489    }
490}