pcap_file/pcapng/blocks/
packet.rs

1//! Packet Block.
2
3use std::borrow::Cow;
4use std::io::{Result as IoResult, Write};
5
6use byteorder_slice::byteorder::WriteBytesExt;
7use byteorder_slice::result::ReadSlice;
8use byteorder_slice::ByteOrder;
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;
14
15/// The Packet Block is obsolete, and MUST NOT be used in new files.
16/// Use the Enhanced Packet Block or Simple Packet Block instead.
17#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
18pub struct PacketBlock<'a> {
19    /// It specifies the interface this packet comes from.
20    pub interface_id: u16,
21
22    /// Local drop counter.
23    /// 
24    /// It specifies the number of packets lost (by the interface and the operating system)
25    /// between this packet and the preceding one.
26    pub drop_count: u16,
27
28    /// The timestamp is a single 64-bit unsigned integer that represents the number of units of time
29    /// that have elapsed since 1970-01-01 00:00:00 UTC.
30    pub timestamp: u64,
31
32    /// Number of octets captured from the packet (i.e. the length of the Packet Data field).
33    pub captured_len: u32,
34
35    /// Actual length of the packet when it was transmitted on the network.
36    pub original_len: u32,
37
38    /// The data coming from the network, including link-layer headers.
39    pub data: Cow<'a, [u8]>,
40
41    /// Options
42    pub options: Vec<PacketOption<'a>>,
43}
44
45impl<'a> PcapNgBlock<'a> for PacketBlock<'a> {
46    fn from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> Result<(&'a [u8], Self), PcapError> {
47        if slice.len() < 20 {
48            return Err(PcapError::InvalidField("EnhancedPacketBlock: block length length < 20"));
49        }
50
51        let interface_id = slice.read_u16::<B>().unwrap();
52        let drop_count = slice.read_u16::<B>().unwrap();
53        let timestamp = slice.read_u64::<B>().unwrap();
54        let captured_len = slice.read_u32::<B>().unwrap();
55        let original_len = slice.read_u32::<B>().unwrap();
56
57        let pad_len = (4 - (captured_len as usize % 4)) % 4;
58        let tot_len = captured_len as usize + pad_len;
59
60        if slice.len() < tot_len {
61            return Err(PcapError::InvalidField("EnhancedPacketBlock: captured_len + padding > block length"));
62        }
63
64        let data = &slice[..captured_len as usize];
65        slice = &slice[tot_len..];
66
67        let (slice, options) = PacketOption::opts_from_slice::<B>(slice)?;
68        let block = PacketBlock {
69            interface_id,
70            drop_count,
71            timestamp,
72            captured_len,
73            original_len,
74            data: Cow::Borrowed(data),
75            options,
76        };
77
78        Ok((slice, block))
79    }
80
81    fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
82        writer.write_u16::<B>(self.interface_id)?;
83        writer.write_u16::<B>(self.drop_count)?;
84        writer.write_u64::<B>(self.timestamp)?;
85        writer.write_u32::<B>(self.captured_len)?;
86        writer.write_u32::<B>(self.original_len)?;
87        writer.write_all(&self.data)?;
88
89        let pad_len = (4 - (self.captured_len as usize % 4)) % 4;
90        writer.write_all(&[0_u8; 3][..pad_len])?;
91
92        let opt_len = PacketOption::write_opts_to::<B, _>(&self.options, writer)?;
93
94        Ok(20 + self.data.len() + pad_len + opt_len)
95    }
96
97    fn into_block(self) -> Block<'a> {
98        Block::Packet(self)
99    }
100}
101
102/// Packet Block option
103#[derive(Clone, Debug, IntoOwned, Eq, PartialEq)]
104pub enum PacketOption<'a> {
105    /// Comment associated with the current block
106    Comment(Cow<'a, str>),
107
108    /// 32-bit flags word containing link-layer information.
109    Flags(u32),
110
111    /// Contains a hash of the packet.
112    Hash(Cow<'a, [u8]>),
113
114    /// Custom option containing binary octets in the Custom Data portion
115    CustomBinary(CustomBinaryOption<'a>),
116
117    /// Custom option containing a UTF-8 string in the Custom Data portion
118    CustomUtf8(CustomUtf8Option<'a>),
119
120    /// Unknown option
121    Unknown(UnknownOption<'a>),
122}
123
124impl<'a> PcapNgOption<'a> for PacketOption<'a> {
125    fn from_slice<B: ByteOrder>(code: u16, length: u16, mut slice: &'a [u8]) -> Result<Self, PcapError> {
126        let opt = match code {
127            1 => PacketOption::Comment(Cow::Borrowed(std::str::from_utf8(slice)?)),
128            2 => {
129                if slice.len() != 4 {
130                    return Err(PcapError::InvalidField("PacketOption: Flags length != 4"));
131                }
132                PacketOption::Flags(slice.read_u32::<B>().map_err(|_| PcapError::IncompleteBuffer)?)
133            },
134            3 => PacketOption::Hash(Cow::Borrowed(slice)),
135
136            2988 | 19372 => PacketOption::CustomUtf8(CustomUtf8Option::from_slice::<B>(code, slice)?),
137            2989 | 19373 => PacketOption::CustomBinary(CustomBinaryOption::from_slice::<B>(code, slice)?),
138
139            _ => PacketOption::Unknown(UnknownOption::new(code, length, slice)),
140        };
141
142        Ok(opt)
143    }
144
145    fn write_to<B: ByteOrder, W: Write>(&self, writer: &mut W) -> IoResult<usize> {
146        match self {
147            PacketOption::Comment(a) => a.write_opt_to::<B, W>(1, writer),
148            PacketOption::Flags(a) => a.write_opt_to::<B, W>(2, writer),
149            PacketOption::Hash(a) => a.write_opt_to::<B, W>(3, writer),
150            PacketOption::CustomBinary(a) => a.write_opt_to::<B, W>(a.code, writer),
151            PacketOption::CustomUtf8(a) => a.write_opt_to::<B, W>(a.code, writer),
152            PacketOption::Unknown(a) => a.write_opt_to::<B, W>(a.code, writer),
153        }
154    }
155}