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
17pub(crate) trait PcapNgOption<'a> {
19 fn from_slice<B: ByteOrder>(code: u16, length: u16, slice: &'a [u8]) -> Result<Self, PcapError>
21 where
22 Self: std::marker::Sized;
23
24 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 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 slice = &slice[length + pad_len..];
58
59 options.push(opt);
60 }
61
62 Err(PcapError::InvalidField("Invalid option"))
63 }
64
65 fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize>;
67
68 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 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 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 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 slice = &slice[length + pad_len..];
132
133 options.push(opt);
134 }
135
136 Err(PcapError::InvalidField("Invalid option"))
137 }
138
139 async fn async_write_to<B: ByteOrder, W: AsyncWrite + Unpin + Send>(&self, writer: &mut W) -> IoResult<usize>;
141
142 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#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
166pub struct UnknownOption<'a> {
167 pub code: u16,
169 pub length: u16,
171 pub value: Cow<'a, [u8]>,
173}
174
175impl<'a> UnknownOption<'a> {
176 pub fn new(code: u16, length: u16, value: &'a [u8]) -> Self {
178 UnknownOption { code, length, value: Cow::Borrowed(value) }
179 }
180}
181
182#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
184pub struct CustomBinaryOption<'a> {
185 pub code: u16,
187 pub pen: u32,
189 pub value: Cow<'a, [u8]>,
191}
192
193impl<'a> CustomBinaryOption<'a> {
194 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#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
211pub struct CustomUtf8Option<'a> {
212 pub code: u16,
214 pub pen: u32,
216 pub value: Cow<'a, str>,
218}
219
220impl<'a> CustomUtf8Option<'a> {
221 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}