1use crate::Error;
7
8pub const PCAP_MAGIC: u32 = 0xa1b2c3d4;
10pub const PCAP_MAGIC_SWAPPED: u32 = 0xd4c3b2a1;
11pub const PCAP_MAGIC_NANO: u32 = 0xa1b23c4d;
12pub const PCAP_MAGIC_NANO_SWAPPED: u32 = 0x4d3cb2a1;
13
14pub const PCAPNG_BYTE_ORDER_MAGIC: u32 = 0x1a2b3c4d;
16
17pub mod mask {
19 pub const IPV4_DF: u16 = 0x4000;
21 pub const IPV4_MF: u16 = 0x2000;
23 pub const IPV4_FRAG_OFFSET: u16 = 0x1fff;
25
26 pub const DNS_QR: u16 = 0x8000;
28 pub const DNS_OPCODE: u16 = 0x7800;
30 pub const DNS_RCODE: u16 = 0x000f;
32}
33
34fn read_u16(data: &[u8], offset: usize) -> Result<u16, Error> {
36 if data.len() < offset + 2 {
37 return Err(Error::truncated(offset + 2, data.len()));
38 }
39 Ok(u16::from_le_bytes([data[offset], data[offset + 1]]))
40}
41
42fn read_u32(data: &[u8], offset: usize) -> Result<u32, Error> {
44 if data.len() < offset + 4 {
45 return Err(Error::truncated(offset + 4, data.len()));
46 }
47 Ok(u32::from_le_bytes([
48 data[offset],
49 data[offset + 1],
50 data[offset + 2],
51 data[offset + 3],
52 ]))
53}
54
55fn read_i32(data: &[u8], offset: usize) -> Result<i32, Error> {
57 if data.len() < offset + 4 {
58 return Err(Error::truncated(offset + 4, data.len()));
59 }
60 Ok(i32::from_le_bytes([
61 data[offset],
62 data[offset + 1],
63 data[offset + 2],
64 data[offset + 3],
65 ]))
66}
67
68pub mod link_type {
70 pub const LINKTYPE_ETHERNET: u16 = 1;
71 pub const LINKTYPE_RAW: u16 = 101;
72 pub const LINKTYPE_IPV4: u16 = 228;
73 pub const LINKTYPE_IPV6: u16 = 229;
74}
75
76#[derive(Debug, Clone, Copy)]
78#[repr(C)]
79pub struct PcapHeader {
80 pub magic: u32,
82 pub version_major: u16,
84 pub version_minor: u16,
86 pub thiszone: i32,
88 pub sigfigs: u32,
90 pub snaplen: u32,
92 pub network: u32,
94}
95
96#[derive(Debug, Clone, Copy)]
98pub struct PcapTimestamp {
99 pub secs: u32,
101 pub usecs: u32,
103}
104
105impl PcapTimestamp {
106 pub fn to_ns(&self, is_nano: bool) -> u64 {
108 let frac = if is_nano {
109 self.usecs
110 } else {
111 self.usecs * 1000
112 };
113 (self.secs as u64) * 1_000_000_000 + frac as u64
114 }
115}
116
117#[derive(Debug, Clone, Copy)]
119#[repr(C)]
120pub struct PcapPacketHeader {
121 pub ts_sec: u32,
123 pub ts_usec: u32,
125 pub incl_len: u32,
127 pub orig_len: u32,
129}
130
131impl PcapHeader {
132 pub fn parse(input: &[u8]) -> Result<(Self, &[u8]), Error> {
134 if input.len() < 24 {
135 return Err(Error::truncated(24, input.len()));
136 }
137
138 let magic = read_u32(input, 0)?;
139 let version_major = read_u16(input, 4)?;
140 let version_minor = read_u16(input, 6)?;
141 let thiszone = read_i32(input, 8)?;
142 let sigfigs = read_u32(input, 12)?;
143 let snaplen = read_u32(input, 16)?;
144 let network = read_u32(input, 20)?;
145
146 let header = PcapHeader {
147 magic,
148 version_major,
149 version_minor,
150 thiszone,
151 sigfigs,
152 snaplen,
153 network,
154 };
155
156 match header.magic {
158 PCAP_MAGIC | PCAP_MAGIC_SWAPPED | PCAP_MAGIC_NANO | PCAP_MAGIC_NANO_SWAPPED => {}
159 _ => return Err(Error::InvalidMagic(header.magic)),
160 }
161
162 if header.version_major != 2 {
164 return Err(Error::InvalidVersion(header.version_major));
165 }
166
167 Ok((header, &input[24..]))
168 }
169
170 pub fn is_swapped(&self) -> bool {
172 matches!(self.magic, PCAP_MAGIC_SWAPPED | PCAP_MAGIC_NANO_SWAPPED)
173 }
174
175 pub fn is_nano(&self) -> bool {
177 matches!(self.magic, PCAP_MAGIC_NANO | PCAP_MAGIC_NANO_SWAPPED)
178 }
179}
180
181pub fn parse_packet_header(input: &[u8]) -> Result<(PcapPacketHeader, &[u8]), Error> {
183 if input.len() < 16 {
184 return Err(Error::truncated(16, input.len()));
185 }
186
187 let header = PcapPacketHeader {
188 ts_sec: read_u32(input, 0)?,
189 ts_usec: read_u32(input, 4)?,
190 incl_len: read_u32(input, 8)?,
191 orig_len: read_u32(input, 12)?,
192 };
193
194 Ok((header, &input[16..]))
195}
196
197pub fn parse_packet(input: &[u8]) -> Result<(&[u8], &[u8]), Error> {
199 let (header, rest) = parse_packet_header(input)?;
200 let data_len = header.incl_len as usize;
201
202 if rest.len() < data_len {
203 return Err(Error::truncated(data_len, rest.len()));
204 }
205
206 let (data, remaining) = rest.split_at(data_len);
207 Ok((data, remaining))
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213
214 #[test]
216 fn test_parse_pcap_header_valid() {
217 let data = vec![
219 0xd4, 0xc3, 0xb2, 0xa1, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, ];
227
228 let (header, rest) = PcapHeader::parse(&data).unwrap();
229 assert_eq!(header.magic, PCAP_MAGIC);
230 assert_eq!(header.version_major, 2);
231 assert_eq!(header.version_minor, 4);
232 assert_eq!(header.network, 1);
233 assert!(!header.is_swapped());
234 assert!(!header.is_nano());
235 assert!(rest.is_empty());
236 }
237
238 #[test]
240 fn test_parse_pcap_header_nano() {
241 let data = vec![
242 0x4d, 0x3c, 0xb2, 0xa1, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, ];
250
251 let (header, _) = PcapHeader::parse(&data).unwrap();
252 assert_eq!(header.magic, PCAP_MAGIC_NANO);
253 assert!(header.is_nano());
254 }
255
256 #[test]
258 fn test_parse_pcap_header_invalid_magic() {
259 let data = vec![
260 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, ];
268
269 let result = PcapHeader::parse(&data);
270 assert!(result.is_err());
271 }
272
273 #[test]
275 fn test_parse_pcap_header_truncated() {
276 let data = vec![0u8; 10]; let result = PcapHeader::parse(&data);
279 assert!(result.is_err());
280 }
281
282 #[test]
284 fn test_parse_packet_header() {
285 let data = vec![
287 0xd2, 0x02, 0x96, 0x49, 0x40, 0xe2, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, ];
292
293 let (header, rest) = parse_packet_header(&data).unwrap();
294 assert_eq!(header.ts_sec, 1234567890);
295 assert_eq!(header.ts_usec, 123456);
296 assert_eq!(header.incl_len, 64);
297 assert_eq!(header.orig_len, 64);
298 assert!(rest.is_empty());
299 }
300
301 #[test]
303 fn test_parse_packet_header_truncated() {
304 let data = vec![0u8; 10]; let result = parse_packet_header(&data);
307 assert!(result.is_err());
308 }
309
310 #[test]
312 fn test_parse_packet() {
313 let data = vec![
314 0xd2, 0x02, 0x96, 0x49, 0xe8, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef,
321 ];
322
323 let (data_out, _rest) = parse_packet(&data).unwrap();
324 assert_eq!(data_out, &[0xde, 0xad, 0xbe, 0xef]);
325 }
326
327 #[test]
329 fn test_parse_packet_truncated() {
330 let data = vec![
331 0xd2, 0x02, 0x96, 0x49, 0xe8, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00,
332 0x00, 0x10, 0x00, 0x00, 0x00, 0xde, 0xad,
335 ];
336
337 let result = parse_packet(&data);
338 assert!(result.is_err());
339 }
340}