1use std::{
3 io::{Cursor, Read, Write},
4 time::{SystemTime, SystemTimeError},
5};
6
7use crate::{
8 Version,
9 byte_order::{Endianness, ReadExt, WriteExt},
10 pcap::PcapParseError,
11};
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
14pub struct PacketTimestamp {
15 pub seconds: u32,
17 pub usec: u32,
20}
21impl TryFrom<SystemTime> for PacketTimestamp {
22 type Error = SystemTimeError;
23
24 fn try_from(value: SystemTime) -> Result<Self, Self::Error> {
25 let duration_since_epoch = value.duration_since(SystemTime::UNIX_EPOCH)?;
26 Ok(Self {
27 seconds: duration_since_epoch.as_secs() as u32,
28 usec: duration_since_epoch.subsec_nanos(),
29 })
30 }
31}
32#[cfg(feature = "chrono")]
33mod _chrono_impl {
34 use chrono::{DateTime, NaiveDateTime};
35
36 use crate::pcap::file_header::MagicNumber;
37
38 use super::PacketTimestamp;
39 impl PacketTimestamp {
40 pub fn to_chrono_naive_datetime(&self, resolution: MagicNumber) -> Option<NaiveDateTime> {
41 match resolution {
42 MagicNumber::Microsecond => {
43 DateTime::from_timestamp(self.seconds as i64, self.usec * 1000)
44 .map(|x| x.naive_utc())
45 }
46 MagicNumber::Nanosecond => {
47 DateTime::from_timestamp(self.seconds as i64, self.usec).map(|x| x.naive_utc())
48 }
49 }
50 }
51 }
52}
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub struct PacketHeader {
55 pub timestamp: PacketTimestamp,
56 pub include_len: u32,
58 pub orig_len: u32,
60}
61
62impl PacketHeader {
63 pub fn new(timestamp: PacketTimestamp, incl_len: u32, orig_len: u32) -> Self {
64 Self {
65 timestamp,
66 include_len: incl_len,
67 orig_len,
68 }
69 }
70 #[inline(always)]
75 pub fn read<R: Read>(
76 reader: &mut R,
77 endianness: Endianness,
78 version: &Version,
79 ) -> Result<Self, PcapParseError> {
80 let mut header = [0u8; 16];
81 reader.read_exact(&mut header)?;
82 Self::parse_bytes(&header, endianness, version)
83 }
84 #[inline(always)]
85 pub fn parse_bytes(
86 bytes: &[u8; 16],
87 endianness: Endianness,
88 version: &Version,
89 ) -> Result<Self, PcapParseError> {
90 let mut cursor = Cursor::new(bytes);
91 let ts = cursor.read_u32(endianness)?;
92 let ts_usec = cursor.read_u32(endianness)?;
93 let (include_len, orig_len) = if version < &Version::PCAP_VERSION_2_3 {
94 let orig_len = cursor.read_u32(endianness)?;
95 let include_len = cursor.read_u32(endianness)?;
96 (include_len, orig_len)
97 } else {
98 let include_len = cursor.read_u32(endianness)?;
99 let orig_len = cursor.read_u32(endianness)?;
100 (include_len, orig_len)
101 };
102 Ok(Self {
103 timestamp: PacketTimestamp {
104 seconds: ts,
105 usec: ts_usec,
106 },
107 include_len,
108 orig_len,
109 })
110 }
111 pub fn write<W: Write>(
112 &self,
113 writer: &mut W,
114 endianness: Endianness,
115 version: &Version,
116 ) -> Result<(), std::io::Error> {
117 writer.write_u32(self.timestamp.seconds, endianness)?;
118 writer.write_u32(self.timestamp.usec, endianness)?;
119 if version < &Version::PCAP_VERSION_2_3 {
120 writer.write_u32(self.orig_len, endianness)?;
121 writer.write_u32(self.include_len, endianness)?;
122 return Ok(());
123 } else {
124 writer.write_u32(self.include_len, endianness)?;
125 writer.write_u32(self.orig_len, endianness)?;
126 }
127
128 Ok(())
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use std::io::Cursor;
135
136 use chrono::{TimeZone, Utc};
137
138 use crate::{
139 Version,
140 byte_order::Endianness,
141 pcap::packet_header::{PacketHeader, PacketTimestamp},
142 };
143
144 #[test]
145 fn write_test() -> anyhow::Result<()> {
146 let specific_datetime_utc = Utc.with_ymd_and_hms(2025, 11, 27, 10, 30, 0).unwrap();
147
148 let duration_since_epoch =
149 specific_datetime_utc.signed_duration_since(Utc.timestamp_opt(0, 0).unwrap());
150
151 let as_secs = duration_since_epoch.num_seconds() as u32;
152 let num_nanos = duration_since_epoch.subsec_nanos() as u32;
153 let mut target: [u8; 16] = [0; 16];
154 let header = PacketHeader {
155 timestamp: crate::pcap::packet_header::PacketTimestamp {
156 seconds: as_secs,
157 usec: num_nanos,
158 },
159 include_len: 100,
160 orig_len: 100,
161 };
162 {
163 let mut writer: Cursor<&mut [u8]> = Cursor::new(&mut target);
164 header.write(
165 &mut writer,
166 Endianness::BigEndian,
167 &Version::PCAP_VERSION_2_4,
168 )?;
169 }
170
171 let result =
172 PacketHeader::parse_bytes(&target, Endianness::BigEndian, &Version::PCAP_VERSION_2_4)?;
173 println!("{result:?}");
174 assert_eq!(result, header);
175 Ok(())
176 }
177
178 #[test]
179 fn test_len_order() {
180 let packet_header = PacketHeader {
181 timestamp: PacketTimestamp::default(),
182 include_len: 1500,
183 orig_len: 2000,
184 };
185 let mut buffer: [u8; 16] = [0; 16];
186 {
187 let mut writer: Cursor<&mut [u8]> = Cursor::new(&mut buffer);
188 packet_header
189 .write(
190 &mut writer,
191 Endianness::LittleEndian,
192 &Version::PCAP_VERSION_2_4,
193 )
194 .unwrap();
195 }
196 let parsed_header = PacketHeader::parse_bytes(
197 &buffer,
198 Endianness::LittleEndian,
199 &Version::PCAP_VERSION_2_4,
200 )
201 .unwrap();
202 assert_eq!(parsed_header.include_len, 1500);
203 assert_eq!(parsed_header.orig_len, 2000);
204
205 let parsed_header_v2_2 = PacketHeader::parse_bytes(
206 &buffer,
207 Endianness::LittleEndian,
208 &Version { major: 2, minor: 2 },
209 )
210 .unwrap();
211 assert_eq!(parsed_header_v2_2.orig_len, 1500);
212 assert_eq!(parsed_header_v2_2.include_len, 2000);
213 }
214 #[test]
215 fn test_len_order_older() {
216 let packet_header = PacketHeader {
217 timestamp: PacketTimestamp::default(),
218 include_len: 1500,
219 orig_len: 2000,
220 };
221 let version = Version { major: 2, minor: 2 };
222 let mut buffer: [u8; 16] = [0; 16];
223 {
224 let mut writer: Cursor<&mut [u8]> = Cursor::new(&mut buffer);
225 packet_header
226 .write(&mut writer, Endianness::LittleEndian, &version)
227 .unwrap();
228 }
229 let parsed_header = PacketHeader::parse_bytes(
230 &buffer,
231 Endianness::LittleEndian,
232 &Version::PCAP_VERSION_2_4,
233 )
234 .unwrap();
235 assert_eq!(parsed_header.include_len, 2000);
236 assert_eq!(parsed_header.orig_len, 1500);
237
238 let parsed_header_v2_2 =
239 PacketHeader::parse_bytes(&buffer, Endianness::LittleEndian, &version).unwrap();
240 assert_eq!(parsed_header_v2_2.include_len, 1500);
241 assert_eq!(parsed_header_v2_2.orig_len, 2000);
242 }
243}