Skip to main content

stackforge_core/
packet.rs

1//! Zero-copy packet representation and manipulation.
2//!
3//! This module implements the core `Packet` struct using a "Lazy Zero-Copy View"
4//! architecture. Packets are represented as:
5//!
6//! 1. A contiguous buffer of raw bytes (`Bytes`)
7//! 2. A lightweight index of layer boundaries (`SmallVec<LayerIndex>`)
8//!
9//! Field access is lazy - values are read directly from the buffer only when
10//! requested, avoiding the allocation overhead of eager parsing.
11
12use bytes::{Bytes, BytesMut};
13use smallvec::SmallVec;
14
15use crate::error::{PacketError, Result};
16use crate::layer::{
17    DnsLayer, HttpLayer, IcmpLayer, Icmpv6Layer, Ipv6Layer, LayerEnum, LayerIndex, LayerKind,
18    RawLayer, SshLayer, TcpLayer, TlsLayer, UdpLayer,
19    arp::ArpLayer,
20    ethernet::{Dot3Layer, ETHERNET_HEADER_LEN, EthernetLayer},
21    ethertype,
22    ftp::{FTP_CONTROL_PORT, is_ftp_payload},
23    http,
24    http2::{Http2Layer, is_http2_payload},
25    icmp,
26    imap::{IMAP_PORT, is_imap_payload},
27    ip_protocol,
28    ipv4::Ipv4Layer,
29    pop3::{POP3_PORT, is_pop3_payload},
30    smtp::{SMTP_PORT, SMTP_SUBMISSION_PORT, SMTPS_PORT, is_smtp_payload},
31    ssh::{SSH_PORT, is_ssh_payload},
32    tftp::{TFTP_PORT, is_tftp_payload},
33    tls::is_tls_payload,
34};
35
36/// Maximum number of layers to store inline before heap allocation.
37const INLINE_LAYER_CAPACITY: usize = 4;
38
39/// A network packet with zero-copy buffer storage.
40///
41/// # Architecture
42///
43/// The `Packet` struct implements a "Lazy Zero-Copy View" model:
44///
45/// - **Zero-Copy**: The `data` field uses `Bytes`, a reference-counted buffer.
46/// - **Lazy**: Fields are not parsed until accessed.
47/// - **Copy-on-Write**: Mutation triggers cloning only when buffer is shared.
48#[derive(Debug, Clone)]
49pub struct Packet {
50    data: Bytes,
51    layers: SmallVec<[LayerIndex; INLINE_LAYER_CAPACITY]>,
52    is_dirty: bool,
53}
54
55impl Packet {
56    // ========================================================================
57    // Constructors
58    // ========================================================================
59
60    /// Creates an empty packet with no data.
61    #[inline]
62    #[must_use]
63    pub fn empty() -> Self {
64        Self {
65            data: Bytes::new(),
66            layers: SmallVec::new(),
67            is_dirty: false,
68        }
69    }
70
71    /// Creates a packet from raw bytes without parsing.
72    #[inline]
73    pub fn from_bytes(data: impl Into<Bytes>) -> Self {
74        Self {
75            data: data.into(),
76            layers: SmallVec::new(),
77            is_dirty: false,
78        }
79    }
80
81    /// Creates a packet from a byte slice by copying the data.
82    #[inline]
83    #[must_use]
84    pub fn from_slice(data: &[u8]) -> Self {
85        Self {
86            data: Bytes::copy_from_slice(data),
87            layers: SmallVec::new(),
88            is_dirty: false,
89        }
90    }
91
92    /// Creates a new packet with pre-allocated capacity.
93    #[inline]
94    #[must_use]
95    pub fn with_capacity(capacity: usize) -> Self {
96        Self {
97            data: Bytes::from(BytesMut::with_capacity(capacity)),
98            layers: SmallVec::new(),
99            is_dirty: false,
100        }
101    }
102
103    // ========================================================================
104    // Basic Properties
105    // ========================================================================
106
107    #[inline]
108    pub fn len(&self) -> usize {
109        self.data.len()
110    }
111    #[inline]
112    pub fn is_empty(&self) -> bool {
113        self.data.is_empty()
114    }
115    #[inline]
116    pub fn is_dirty(&self) -> bool {
117        self.is_dirty
118    }
119    #[inline]
120    pub fn layer_count(&self) -> usize {
121        self.layers.len()
122    }
123    #[inline]
124    pub fn is_parsed(&self) -> bool {
125        !self.layers.is_empty()
126    }
127
128    // ========================================================================
129    // Raw Data Access
130    // ========================================================================
131
132    #[inline]
133    pub fn as_bytes(&self) -> &[u8] {
134        &self.data
135    }
136    #[inline]
137    pub fn bytes(&self) -> Bytes {
138        self.data.clone()
139    }
140    #[inline]
141    pub fn into_bytes(self) -> Bytes {
142        self.data
143    }
144
145    // ========================================================================
146    // Layer Access
147    // ========================================================================
148
149    #[inline]
150    pub fn layers(&self) -> &[LayerIndex] {
151        &self.layers
152    }
153
154    #[inline]
155    pub fn get_layer(&self, kind: LayerKind) -> Option<&LayerIndex> {
156        self.layers.iter().find(|l| l.kind == kind)
157    }
158
159    /// Returns the bytes for a specific layer.
160    pub fn layer_bytes(&self, kind: LayerKind) -> Result<&[u8]> {
161        self.get_layer(kind)
162            .map(|idx| &self.data[idx.range()])
163            .ok_or(PacketError::LayerNotFound(kind))
164    }
165
166    /// Returns the payload (data after all parsed headers).
167    #[inline]
168    pub fn payload(&self) -> &[u8] {
169        self.layers
170            .last()
171            .map_or(&self.data, |l| &self.data[l.end..])
172    }
173
174    // ========================================================================
175    // Typed Layer Access
176    // ========================================================================
177
178    /// Get the Ethernet layer view if present.
179    pub fn ethernet(&self) -> Option<EthernetLayer> {
180        self.get_layer(LayerKind::Ethernet)
181            .map(|idx| EthernetLayer::new(idx.start, idx.end))
182    }
183
184    /// Get the IPv4 layer view if present.
185    pub fn ipv4(&self) -> Option<Ipv4Layer> {
186        self.get_layer(LayerKind::Ipv4)
187            .map(|idx| Ipv4Layer::new(idx.start, idx.end))
188    }
189
190    /// Get the ARP layer view if present.
191    pub fn arp(&self) -> Option<ArpLayer> {
192        self.get_layer(LayerKind::Arp)
193            .map(|idx| ArpLayer::new(idx.start, idx.end))
194    }
195
196    /// Get the ICMP layer view if present.
197    pub fn icmp(&self) -> Option<IcmpLayer> {
198        self.get_layer(LayerKind::Icmp)
199            .map(|idx| IcmpLayer { index: *idx })
200    }
201
202    /// Get the TCP layer view if present.
203    pub fn tcp(&self) -> Option<TcpLayer> {
204        self.get_layer(LayerKind::Tcp)
205            .map(|idx| TcpLayer::new(idx.start, idx.end))
206    }
207
208    /// Get the UDP layer view if present.
209    pub fn udp(&self) -> Option<UdpLayer> {
210        self.get_layer(LayerKind::Udp)
211            .map(|idx| UdpLayer { index: *idx })
212    }
213
214    /// Get the DNS layer view if present.
215    pub fn dns(&self) -> Option<DnsLayer> {
216        self.get_layer(LayerKind::Dns)
217            .map(|idx| DnsLayer { index: *idx })
218    }
219
220    /// Get the TLS layer view if present.
221    pub fn tls(&self) -> Option<TlsLayer> {
222        self.get_layer(LayerKind::Tls)
223            .map(|idx| TlsLayer { index: *idx })
224    }
225
226    /// Get the MQTT layer view if present.
227    pub fn mqtt(&self) -> Option<crate::layer::mqtt::MqttLayer> {
228        self.get_layer(LayerKind::Mqtt)
229            .map(|idx| crate::layer::mqtt::MqttLayer::new(*idx))
230    }
231
232    /// Get the MQTT-SN layer view if present.
233    pub fn mqttsn(&self) -> Option<crate::layer::mqttsn::MqttSnLayer> {
234        self.get_layer(LayerKind::MqttSn)
235            .map(|idx| crate::layer::mqttsn::MqttSnLayer::new(*idx))
236    }
237
238    /// Get the Modbus layer view if present.
239    pub fn modbus(&self) -> Option<crate::layer::modbus::ModbusLayer> {
240        self.get_layer(LayerKind::Modbus)
241            .map(|idx| crate::layer::modbus::ModbusLayer::new(*idx))
242    }
243
244    /// Get the Z-Wave layer view if present.
245    pub fn zwave(&self) -> Option<crate::layer::zwave::ZWaveLayer> {
246        self.get_layer(LayerKind::ZWave)
247            .map(|idx| crate::layer::zwave::ZWaveLayer::new(*idx))
248    }
249
250    /// Get the FTP layer view if present.
251    pub fn ftp(&self) -> Option<crate::layer::ftp::FtpLayer> {
252        self.get_layer(LayerKind::Ftp)
253            .map(|idx| crate::layer::ftp::FtpLayer::new(*idx))
254    }
255
256    /// Get the TFTP layer view if present.
257    pub fn tftp(&self) -> Option<crate::layer::tftp::TftpLayer> {
258        self.get_layer(LayerKind::Tftp)
259            .map(|idx| crate::layer::tftp::TftpLayer::new(*idx))
260    }
261
262    /// Get the SMTP layer view if present.
263    pub fn smtp(&self) -> Option<crate::layer::smtp::SmtpLayer> {
264        self.get_layer(LayerKind::Smtp)
265            .map(|idx| crate::layer::smtp::SmtpLayer::new(*idx))
266    }
267
268    /// Get the POP3 layer view if present.
269    pub fn pop3(&self) -> Option<crate::layer::pop3::Pop3Layer> {
270        self.get_layer(LayerKind::Pop3)
271            .map(|idx| crate::layer::pop3::Pop3Layer::new(*idx))
272    }
273
274    /// Get the IMAP layer view if present.
275    pub fn imap(&self) -> Option<crate::layer::imap::ImapLayer> {
276        self.get_layer(LayerKind::Imap)
277            .map(|idx| crate::layer::imap::ImapLayer::new(*idx))
278    }
279
280    /// Get a `LayerEnum` for a given `LayerIndex`.
281    pub fn layer_enum(&self, idx: &LayerIndex) -> LayerEnum {
282        match idx.kind {
283            LayerKind::Ethernet => LayerEnum::Ethernet(EthernetLayer::new(idx.start, idx.end)),
284            LayerKind::Dot3 => LayerEnum::Dot3(Dot3Layer::new(idx.start, idx.end)),
285            LayerKind::Arp => LayerEnum::Arp(ArpLayer::new(idx.start, idx.end)),
286            LayerKind::Ipv4 => LayerEnum::Ipv4(Ipv4Layer::new(idx.start, idx.end)),
287            LayerKind::Ipv6 => LayerEnum::Ipv6(Ipv6Layer { index: *idx }),
288            LayerKind::Icmp => LayerEnum::Icmp(IcmpLayer { index: *idx }),
289            LayerKind::Icmpv6 => LayerEnum::Icmpv6(Icmpv6Layer { index: *idx }),
290            LayerKind::Tcp => LayerEnum::Tcp(TcpLayer::new(idx.start, idx.end)),
291            LayerKind::Udp => LayerEnum::Udp(UdpLayer { index: *idx }),
292            LayerKind::Dns => LayerEnum::Dns(DnsLayer { index: *idx }),
293            LayerKind::Ssh => LayerEnum::Ssh(SshLayer { index: *idx }),
294            LayerKind::Tls => LayerEnum::Tls(TlsLayer { index: *idx }),
295            LayerKind::Dot15d4 => {
296                LayerEnum::Dot15d4(crate::layer::dot15d4::Dot15d4Layer::new(idx.start, idx.end))
297            },
298            LayerKind::Dot15d4Fcs => LayerEnum::Dot15d4Fcs(
299                crate::layer::dot15d4::Dot15d4FcsLayer::new(idx.start, idx.end),
300            ),
301            LayerKind::Dot11 => {
302                LayerEnum::Dot11(crate::layer::dot11::Dot11Layer::new(idx.start, idx.end))
303            },
304            LayerKind::Http => LayerEnum::Http(HttpLayer { index: *idx }),
305            LayerKind::Http2 => LayerEnum::Http2(Http2Layer::new(idx.start, idx.end, false)),
306            LayerKind::Quic => LayerEnum::Quic(crate::layer::quic::QuicLayer::from_index(*idx)),
307            LayerKind::L2tp => LayerEnum::L2tp(crate::layer::l2tp::L2tpLayer::new(*idx)),
308            LayerKind::Mqtt => LayerEnum::Mqtt(crate::layer::mqtt::MqttLayer::new(*idx)),
309            LayerKind::MqttSn => LayerEnum::MqttSn(crate::layer::mqttsn::MqttSnLayer::new(*idx)),
310            LayerKind::Modbus => LayerEnum::Modbus(crate::layer::modbus::ModbusLayer::new(*idx)),
311            LayerKind::ZWave => LayerEnum::ZWave(crate::layer::zwave::ZWaveLayer::new(*idx)),
312            LayerKind::Ftp => LayerEnum::Ftp(crate::layer::ftp::FtpLayer::new(*idx)),
313            LayerKind::Tftp => LayerEnum::Tftp(crate::layer::tftp::TftpLayer::new(*idx)),
314            LayerKind::Smtp => LayerEnum::Smtp(crate::layer::smtp::SmtpLayer::new(*idx)),
315            LayerKind::Pop3 => LayerEnum::Pop3(crate::layer::pop3::Pop3Layer::new(*idx)),
316            LayerKind::Imap => LayerEnum::Imap(crate::layer::imap::ImapLayer::new(*idx)),
317            LayerKind::Raw
318            | LayerKind::Dot1Q
319            | LayerKind::Dot1AD
320            | LayerKind::Dot1AH
321            | LayerKind::LLC
322            | LayerKind::SNAP
323            | LayerKind::Generic => LayerEnum::Raw(RawLayer { index: *idx }),
324        }
325    }
326
327    /// Get all layers as `LayerEnum` objects.
328    pub fn layer_enums(&self) -> Vec<LayerEnum> {
329        self.layers.iter().map(|idx| self.layer_enum(idx)).collect()
330    }
331
332    // ========================================================================
333    // Parsing (Index-Only)
334    // ========================================================================
335
336    /// Parses the packet to identify layer boundaries.
337    pub fn parse(&mut self) -> Result<()> {
338        self.layers.clear();
339
340        if self.data.len() < ETHERNET_HEADER_LEN {
341            return Ok(());
342        }
343
344        // Parse Ethernet header
345        let eth_end = ETHERNET_HEADER_LEN;
346        self.layers
347            .push(LayerIndex::new(LayerKind::Ethernet, 0, eth_end));
348
349        let etype = u16::from_be_bytes([self.data[12], self.data[13]]);
350
351        match etype {
352            ethertype::IPV4 => self.parse_ipv4(eth_end)?,
353            ethertype::IPV6 => self.parse_ipv6(eth_end)?,
354            ethertype::ARP => self.parse_arp(eth_end)?,
355            _ => {
356                if eth_end < self.data.len() {
357                    self.layers
358                        .push(LayerIndex::new(LayerKind::Raw, eth_end, self.data.len()));
359                }
360            },
361        }
362
363        Ok(())
364    }
365
366    fn parse_ipv4(&mut self, offset: usize) -> Result<()> {
367        let min_size = 20;
368        if offset + min_size > self.data.len() {
369            return Err(PacketError::BufferTooShort {
370                expected: offset + min_size,
371                actual: self.data.len(),
372            });
373        }
374
375        let ihl = (self.data[offset] & 0x0F) as usize;
376        let header_len = ihl * 4;
377
378        if header_len < min_size {
379            return Err(PacketError::ParseError {
380                offset,
381                message: format!("invalid IHL: {ihl}"),
382            });
383        }
384
385        let ip_end = offset + header_len;
386        if ip_end > self.data.len() {
387            return Err(PacketError::BufferTooShort {
388                expected: ip_end,
389                actual: self.data.len(),
390            });
391        }
392
393        self.layers
394            .push(LayerIndex::new(LayerKind::Ipv4, offset, ip_end));
395
396        let protocol = self.data[offset + 9];
397        match protocol {
398            ip_protocol::TCP => self.parse_tcp(ip_end)?,
399            ip_protocol::UDP => self.parse_udp(ip_end)?,
400            ip_protocol::ICMP => self.parse_icmp(ip_end)?,
401            _ => {
402                if ip_end < self.data.len() {
403                    self.layers
404                        .push(LayerIndex::new(LayerKind::Raw, ip_end, self.data.len()));
405                }
406            },
407        }
408
409        Ok(())
410    }
411
412    fn parse_ipv6(&mut self, offset: usize) -> Result<()> {
413        let min_size = 40;
414        if offset + min_size > self.data.len() {
415            return Err(PacketError::BufferTooShort {
416                expected: offset + min_size,
417                actual: self.data.len(),
418            });
419        }
420
421        let ip_end = offset + min_size;
422        self.layers
423            .push(LayerIndex::new(LayerKind::Ipv6, offset, ip_end));
424
425        let next_header = self.data[offset + 6];
426        match next_header {
427            ip_protocol::TCP => self.parse_tcp(ip_end)?,
428            ip_protocol::UDP => self.parse_udp(ip_end)?,
429            ip_protocol::ICMPV6 => self.parse_icmpv6(ip_end)?,
430            _ => {
431                if ip_end < self.data.len() {
432                    self.layers
433                        .push(LayerIndex::new(LayerKind::Raw, ip_end, self.data.len()));
434                }
435            },
436        }
437
438        Ok(())
439    }
440
441    fn parse_arp(&mut self, offset: usize) -> Result<()> {
442        // First check if we have enough bytes for hwlen/plen fields
443        if offset + 5 > self.data.len() {
444            return Err(PacketError::BufferTooShort {
445                expected: offset + 5,
446                actual: self.data.len(),
447            });
448        }
449
450        let hwlen = self.data[offset + 4] as usize;
451        let plen = self.data[offset + 5] as usize;
452        let total_len = 8 + 2 * hwlen + 2 * plen;
453
454        if offset + total_len > self.data.len() {
455            return Err(PacketError::BufferTooShort {
456                expected: offset + total_len,
457                actual: self.data.len(),
458            });
459        }
460
461        let arp_end = offset + total_len;
462        self.layers
463            .push(LayerIndex::new(LayerKind::Arp, offset, arp_end));
464
465        if arp_end < self.data.len() {
466            self.layers
467                .push(LayerIndex::new(LayerKind::Raw, arp_end, self.data.len()));
468        }
469
470        Ok(())
471    }
472
473    fn parse_tcp(&mut self, offset: usize) -> Result<()> {
474        let min_size = 20;
475        if offset + min_size > self.data.len() {
476            return Err(PacketError::BufferTooShort {
477                expected: offset + min_size,
478                actual: self.data.len(),
479            });
480        }
481
482        let data_offset = ((self.data[offset + 12] >> 4) & 0x0F) as usize;
483        let header_len = data_offset * 4;
484
485        let tcp_end = (offset + header_len).min(self.data.len());
486        self.layers
487            .push(LayerIndex::new(LayerKind::Tcp, offset, tcp_end));
488
489        if tcp_end < self.data.len() {
490            // Check for SSH on port 22
491            let src_port = u16::from_be_bytes([self.data[offset], self.data[offset + 1]]);
492            let dst_port = u16::from_be_bytes([self.data[offset + 2], self.data[offset + 3]]);
493
494            let payload = &self.data[tcp_end..];
495            if (src_port == SSH_PORT || dst_port == SSH_PORT) && is_ssh_payload(payload) {
496                self.parse_ssh(tcp_end)?;
497            } else if (src_port == 502 || dst_port == 502)
498                && crate::layer::modbus::is_modbus_tcp_payload(payload)
499            {
500                self.layers
501                    .push(LayerIndex::new(LayerKind::Modbus, tcp_end, self.data.len()));
502            } else if (src_port == 1883 || dst_port == 1883)
503                && crate::layer::mqtt::is_mqtt_payload(payload)
504            {
505                self.layers
506                    .push(LayerIndex::new(LayerKind::Mqtt, tcp_end, self.data.len()));
507            } else if (src_port == FTP_CONTROL_PORT || dst_port == FTP_CONTROL_PORT)
508                && is_ftp_payload(payload)
509            {
510                self.layers
511                    .push(LayerIndex::new(LayerKind::Ftp, tcp_end, self.data.len()));
512            } else if (src_port == SMTP_PORT
513                || dst_port == SMTP_PORT
514                || src_port == SMTP_SUBMISSION_PORT
515                || dst_port == SMTP_SUBMISSION_PORT
516                || src_port == SMTPS_PORT
517                || dst_port == SMTPS_PORT)
518                && is_smtp_payload(payload)
519            {
520                self.layers
521                    .push(LayerIndex::new(LayerKind::Smtp, tcp_end, self.data.len()));
522            } else if (src_port == POP3_PORT || dst_port == POP3_PORT) && is_pop3_payload(payload) {
523                self.layers
524                    .push(LayerIndex::new(LayerKind::Pop3, tcp_end, self.data.len()));
525            } else if (src_port == IMAP_PORT || dst_port == IMAP_PORT) && is_imap_payload(payload) {
526                self.layers
527                    .push(LayerIndex::new(LayerKind::Imap, tcp_end, self.data.len()));
528            } else if is_tls_payload(payload) {
529                self.parse_tls(tcp_end)?;
530            } else if is_http2_payload(payload) {
531                self.layers
532                    .push(LayerIndex::new(LayerKind::Http2, tcp_end, self.data.len()));
533            } else if http::detection::is_http(payload) {
534                self.layers
535                    .push(LayerIndex::new(LayerKind::Http, tcp_end, self.data.len()));
536            } else {
537                self.layers
538                    .push(LayerIndex::new(LayerKind::Raw, tcp_end, self.data.len()));
539            }
540        }
541
542        Ok(())
543    }
544
545    fn parse_udp(&mut self, offset: usize) -> Result<()> {
546        let min_size = 8;
547        if offset + min_size > self.data.len() {
548            return Err(PacketError::BufferTooShort {
549                expected: offset + min_size,
550                actual: self.data.len(),
551            });
552        }
553
554        let udp_end = offset + min_size;
555        self.layers
556            .push(LayerIndex::new(LayerKind::Udp, offset, udp_end));
557
558        // Check for DNS
559        let dst_port = u16::from_be_bytes([self.data[offset + 2], self.data[offset + 3]]);
560        let src_port = u16::from_be_bytes([self.data[offset], self.data[offset + 1]]);
561
562        if (dst_port == 53 || src_port == 53 || dst_port == 5353 || src_port == 5353)
563            && udp_end + 12 <= self.data.len()
564        {
565            self.layers
566                .push(LayerIndex::new(LayerKind::Dns, udp_end, self.data.len()));
567        } else if (dst_port == 443 || src_port == 443 || dst_port == 4433 || src_port == 4433)
568            && udp_end < self.data.len()
569            && is_quic_payload(&self.data[udp_end..])
570        {
571            self.layers
572                .push(LayerIndex::new(LayerKind::Quic, udp_end, self.data.len()));
573        } else if (dst_port == 1701 || src_port == 1701)
574            && udp_end + 2 <= self.data.len()
575            && (self.data[udp_end + 1] & 0x0F) == 2
576        {
577            // L2TPv2: version nibble (low 4 bits of second byte) must be 2
578            self.layers
579                .push(LayerIndex::new(LayerKind::L2tp, udp_end, self.data.len()));
580        } else if (dst_port == 1883 || src_port == 1883)
581            && udp_end < self.data.len()
582            && crate::layer::mqttsn::is_mqttsn_payload(&self.data[udp_end..])
583        {
584            self.layers
585                .push(LayerIndex::new(LayerKind::MqttSn, udp_end, self.data.len()));
586        } else if (dst_port == TFTP_PORT || src_port == TFTP_PORT)
587            && udp_end < self.data.len()
588            && is_tftp_payload(&self.data[udp_end..])
589        {
590            self.layers
591                .push(LayerIndex::new(LayerKind::Tftp, udp_end, self.data.len()));
592        } else if udp_end < self.data.len() {
593            self.layers
594                .push(LayerIndex::new(LayerKind::Raw, udp_end, self.data.len()));
595        }
596
597        Ok(())
598    }
599
600    fn parse_icmp(&mut self, offset: usize) -> Result<()> {
601        if offset + 8 > self.data.len() {
602            return Err(PacketError::BufferTooShort {
603                expected: offset + 8,
604                actual: self.data.len(),
605            });
606        }
607
608        // Add ICMP layer
609        self.layers
610            .push(LayerIndex::new(LayerKind::Icmp, offset, self.data.len()));
611
612        // Check if this is an ICMP error message that contains an embedded packet
613        // Error types: 3 (dest unreach), 4 (source quench), 5 (redirect), 11 (time exceeded), 12 (param problem)
614        if offset < self.data.len() {
615            let icmp_type = self.data[offset];
616            if icmp::is_error_type(icmp_type) {
617                // ICMP error messages have 8-byte header, then embedded IP packet
618                let embedded_offset = offset + 8;
619                if embedded_offset < self.data.len() {
620                    // Try to parse the embedded IP packet
621                    // Silently ignore errors since the embedded packet might be truncated
622                    let _ = self.parse_ipv4(embedded_offset);
623                }
624            }
625        }
626
627        Ok(())
628    }
629
630    fn parse_icmpv6(&mut self, offset: usize) -> Result<()> {
631        if offset + 8 > self.data.len() {
632            return Err(PacketError::BufferTooShort {
633                expected: offset + 8,
634                actual: self.data.len(),
635            });
636        }
637        self.layers
638            .push(LayerIndex::new(LayerKind::Icmpv6, offset, self.data.len()));
639        Ok(())
640    }
641
642    fn parse_ssh(&mut self, offset: usize) -> Result<()> {
643        let remaining = &self.data[offset..];
644
645        if remaining.len() >= 4 && &remaining[..4] == b"SSH-" {
646            // SSH version exchange - spans until \r\n
647            let end = remaining
648                .windows(2)
649                .position(|w| w == b"\r\n")
650                .map_or(self.data.len(), |p| offset + p + 2);
651            self.layers
652                .push(LayerIndex::new(LayerKind::Ssh, offset, end));
653            if end < self.data.len() {
654                self.layers
655                    .push(LayerIndex::new(LayerKind::Raw, end, self.data.len()));
656            }
657        } else if remaining.len() >= 5 {
658            // SSH binary packet
659            let pkt_len =
660                u32::from_be_bytes([remaining[0], remaining[1], remaining[2], remaining[3]])
661                    as usize;
662            let end = (offset + 4 + pkt_len).min(self.data.len());
663            self.layers
664                .push(LayerIndex::new(LayerKind::Ssh, offset, end));
665            if end < self.data.len() {
666                self.layers
667                    .push(LayerIndex::new(LayerKind::Raw, end, self.data.len()));
668            }
669        } else {
670            self.layers
671                .push(LayerIndex::new(LayerKind::Raw, offset, self.data.len()));
672        }
673
674        Ok(())
675    }
676
677    fn parse_tls(&mut self, offset: usize) -> Result<()> {
678        use crate::layer::tls::TLS_RECORD_HEADER_LEN;
679
680        let remaining = self.data.len() - offset;
681        if remaining < TLS_RECORD_HEADER_LEN {
682            self.layers
683                .push(LayerIndex::new(LayerKind::Raw, offset, self.data.len()));
684            return Ok(());
685        }
686
687        // Read the TLS record header
688        let frag_len = u16::from_be_bytes([self.data[offset + 3], self.data[offset + 4]]) as usize;
689        let record_end = (offset + TLS_RECORD_HEADER_LEN + frag_len).min(self.data.len());
690
691        self.layers
692            .push(LayerIndex::new(LayerKind::Tls, offset, record_end));
693
694        // If there's more data after this record, treat as Raw
695        // (could be additional TLS records, but we parse one for now)
696        if record_end < self.data.len() {
697            self.layers
698                .push(LayerIndex::new(LayerKind::Raw, record_end, self.data.len()));
699        }
700
701        Ok(())
702    }
703
704    // ========================================================================
705    // Mutation Support (Copy-on-Write)
706    // ========================================================================
707
708    /// Applies a mutation function to the packet data.
709    pub fn with_data_mut<F, R>(&mut self, f: F) -> R
710    where
711        F: FnOnce(&mut [u8]) -> R,
712    {
713        let bytes = std::mem::take(&mut self.data);
714        let mut bytes_mut = bytes
715            .try_into_mut()
716            .unwrap_or_else(|b| BytesMut::from(b.as_ref()));
717        let result = f(&mut bytes_mut);
718        self.data = bytes_mut.freeze();
719        self.is_dirty = true;
720        result
721    }
722
723    pub fn set_byte(&mut self, offset: usize, value: u8) {
724        self.with_data_mut(|data| data[offset] = value);
725    }
726
727    pub fn set_bytes(&mut self, offset: usize, values: &[u8]) {
728        self.with_data_mut(|data| data[offset..offset + values.len()].copy_from_slice(values));
729    }
730
731    #[inline]
732    pub fn mark_dirty(&mut self) {
733        self.is_dirty = true;
734    }
735    #[inline]
736    pub fn mark_clean(&mut self) {
737        self.is_dirty = false;
738    }
739
740    pub fn add_layer(&mut self, index: LayerIndex) {
741        self.layers.push(index);
742    }
743
744    pub fn set_data(&mut self, data: BytesMut) {
745        self.data = data.freeze();
746        self.is_dirty = true;
747    }
748}
749
750impl Default for Packet {
751    fn default() -> Self {
752        Self::empty()
753    }
754}
755
756impl From<Vec<u8>> for Packet {
757    fn from(data: Vec<u8>) -> Self {
758        Self::from_bytes(data)
759    }
760}
761
762impl From<&[u8]> for Packet {
763    fn from(data: &[u8]) -> Self {
764        Self::from_slice(data)
765    }
766}
767
768impl AsRef<[u8]> for Packet {
769    fn as_ref(&self) -> &[u8] {
770        self.as_bytes()
771    }
772}
773
774/// Detect a QUIC payload by checking that the Fixed Bit (bit 6) is set.
775/// RFC 9000 ยง17: all QUIC packets have the Fixed Bit set to 1.
776fn is_quic_payload(buf: &[u8]) -> bool {
777    !buf.is_empty() && (buf[0] & 0x40) != 0
778}
779
780#[cfg(test)]
781mod tests {
782    use super::*;
783    use crate::ARP_HEADER_LEN;
784    use crate::layer::field::MacAddress;
785
786    fn sample_arp_packet() -> Vec<u8> {
787        vec![
788            // Ethernet header (14 bytes)
789            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // dst: broadcast
790            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, // src
791            0x08, 0x06, // type: ARP
792            // ARP header (28 bytes)
793            0x00, 0x01, // hwtype: Ethernet
794            0x08, 0x00, // ptype: IPv4
795            0x06, 0x04, // hwlen, plen
796            0x00, 0x01, // op: request
797            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, // hwsrc
798            0xc0, 0xa8, 0x01, 0x01, // psrc: 192.168.1.1
799            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // hwdst
800            0xc0, 0xa8, 0x01, 0x02, // pdst: 192.168.1.2
801        ]
802    }
803
804    #[test]
805    fn test_packet_parse_arp() {
806        let data = sample_arp_packet();
807        let mut packet = Packet::from_bytes(data);
808        packet.parse().unwrap();
809
810        assert_eq!(packet.layer_count(), 2); // Ethernet + ARP
811
812        let eth = packet.ethernet().unwrap();
813        assert!(eth.is_broadcast(packet.as_bytes()));
814        assert_eq!(eth.ethertype(packet.as_bytes()).unwrap(), ethertype::ARP);
815
816        let arp = packet.arp().unwrap();
817        assert!(arp.is_request(packet.as_bytes()));
818    }
819
820    #[test]
821    fn test_packet_layer_access() {
822        let data = sample_arp_packet();
823        let mut packet = Packet::from_bytes(data);
824        packet.parse().unwrap();
825
826        let eth_bytes = packet.layer_bytes(LayerKind::Ethernet).unwrap();
827        assert_eq!(eth_bytes.len(), ETHERNET_HEADER_LEN);
828
829        let arp_bytes = packet.layer_bytes(LayerKind::Arp).unwrap();
830        assert_eq!(arp_bytes.len(), ARP_HEADER_LEN);
831    }
832
833    #[test]
834    fn test_packet_modify_through_layer() {
835        let data = sample_arp_packet();
836        let mut packet = Packet::from_bytes(data);
837        packet.parse().unwrap();
838
839        // Modify source MAC through ethernet layer
840        let eth = packet.ethernet().unwrap();
841        packet.with_data_mut(|buf| {
842            eth.set_src(buf, MacAddress::new([0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]))
843                .unwrap();
844        });
845
846        assert!(packet.is_dirty());
847        let eth = packet.ethernet().unwrap();
848        assert_eq!(
849            eth.src(packet.as_bytes()).unwrap(),
850            MacAddress::new([0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff])
851        );
852    }
853
854    #[test]
855    fn test_icmp_error_packet_parsing() {
856        // ICMP Destination Unreachable with embedded UDP packet
857        let data = vec![
858            // Ethernet header (14 bytes)
859            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, // dst
860            0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, // src
861            0x08, 0x00, // ethertype: IPv4
862            // Outer IPv4 header (20 bytes) - ICMP error message from router
863            0x45, 0x00, 0x00, 0x38, // ver/ihl, tos, total len = 56
864            0x00, 0x01, 0x00, 0x00, // id, flags, frag offset
865            0x40, 0x01, 0x00, 0x00, // ttl=64, proto=ICMP, checksum
866            192, 168, 1, 1, // src: router
867            192, 168, 1, 100, // dst: original sender
868            // ICMP Destination Unreachable (8 bytes)
869            0x03, // type = 3 (dest unreachable)
870            0x03, // code = 3 (port unreachable)
871            0x00, 0x00, // checksum
872            0x00, 0x00, 0x00, 0x00, // unused
873            // Embedded original IPv4 header (20 bytes)
874            0x45, 0x00, 0x00, 0x1c, // ver/ihl, tos, total len = 28
875            0xab, 0xcd, 0x00, 0x00, // id, flags, frag offset
876            0x40, 0x11, 0x00, 0x00, // ttl=64, proto=UDP, checksum
877            192, 168, 1, 100, // src: original sender
878            8, 8, 8, 8, // dst: 8.8.8.8 (where packet was sent)
879            // Embedded UDP header (first 8 bytes)
880            0x04, 0xd2, // sport = 1234
881            0x00, 0x35, // dport = 53 (DNS)
882            0x00, 0x14, // length = 20
883            0x00, 0x00, // checksum
884        ];
885
886        let mut packet = Packet::from_bytes(data);
887        packet.parse().unwrap();
888
889        // Should have: Ethernet, IP (outer), ICMP, IP (embedded), UDP (embedded)
890        assert_eq!(packet.layer_count(), 5);
891
892        // Verify outer IP layer
893        assert!(packet.ethernet().is_some());
894        assert!(packet.ipv4().is_some());
895        assert!(packet.icmp().is_some());
896
897        // Verify ICMP error type
898        let icmp = packet.icmp().unwrap();
899        let icmp_type = icmp.icmp_type(packet.as_bytes()).unwrap();
900        assert_eq!(icmp_type, 3); // Destination unreachable
901
902        // Verify embedded packet layers exist
903        // The second IP layer is the embedded one
904        let layers = packet.layers();
905        let _embedded_ip_idx = layers
906            .iter()
907            .rposition(|idx| idx.kind == LayerKind::Ipv4)
908            .unwrap();
909
910        // Verify embedded UDP exists
911        assert!(packet.udp().is_some());
912    }
913
914    #[test]
915    fn test_icmp_time_exceeded_with_tcp() {
916        // ICMP Time Exceeded with embedded TCP packet
917        // Note: ICMP error messages typically only include first 8 bytes of transport header
918        let data = vec![
919            // Ethernet header
920            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
921            // Outer IPv4 header
922            0x45, 0x00, 0x00, 0x4c, // total len = 76 (longer to include full embedded packet)
923            0x00, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 10, 0, 0, 1, // src: router
924            192, 168, 1, 100, // dst: original sender
925            // ICMP Time Exceeded
926            0x0b, // type = 11 (time exceeded)
927            0x00, // code = 0 (TTL exceeded)
928            0x00, 0x00, // checksum
929            0x00, 0x00, 0x00, 0x00, // unused
930            // Embedded original IPv4 header (20 bytes)
931            0x45, 0x00, 0x00, 0x28, // total len = 40 (20 IP + 20 TCP)
932            0x12, 0x34, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, // ttl=1, proto=TCP
933            192, 168, 1, 100, // src
934            93, 184, 216, 34, // dst
935            // Embedded TCP header (full 20 bytes for proper parsing)
936            0x04, 0xd2, // sport = 1234
937            0x00, 0x50, // dport = 80 (HTTP)
938            0x00, 0x00, 0x00, 0x01, // seq
939            0x00, 0x00, 0x00, 0x00, // ack
940            0x50, 0x02, 0x20, 0x00, // data offset=5, flags=SYN, window
941            0x00, 0x00, // checksum
942            0x00, 0x00, // urgent pointer
943        ];
944
945        let mut packet = Packet::from_bytes(data);
946        packet.parse().unwrap();
947
948        // Should have: Ethernet, IP (outer), ICMP, IP (embedded), TCP (embedded)
949        assert_eq!(packet.layer_count(), 5);
950
951        // Verify layers exist
952        assert!(packet.icmp().is_some());
953        assert!(packet.tcp().is_some());
954
955        // Verify ICMP type
956        let icmp = packet.icmp().unwrap();
957        assert_eq!(icmp.icmp_type(packet.as_bytes()).unwrap(), 11);
958    }
959
960    #[test]
961    fn test_icmp_with_extensions() {
962        // ICMP Time Exceeded with RFC 4884 extensions (Interface Information)
963        let data = vec![
964            // Ethernet header
965            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // dst
966            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, // src
967            0x08, 0x00, // ethertype = IPv4
968            // IPv4 header (outer)
969            0x45, 0x00, 0x00, 0xa0, // version, ihl, tos, total_length (160 bytes)
970            0x00, 0x01, 0x00, 0x00, // id, flags, fragment offset
971            0x40, 0x01, 0x00, 0x00, // ttl=64, proto=ICMP, checksum
972            0xc0, 0xa8, 0x01, 0x01, // src = 192.168.1.1
973            0xc0, 0xa8, 0x01, 0x64, // dst = 192.168.1.100
974            // ICMP header
975            0x0b, // type = Time Exceeded
976            0x00, // code = TTL exceeded
977            0x00, 0x00, // checksum (will be wrong, but OK for parsing test)
978            0x00, 0x00, 0x00, 0x00, // unused
979            // Embedded IP packet (padded to 128 bytes per RFC 4884)
980            0x45, 0x00, 0x00, 0x3c, // Embedded IPv4 header
981            0x12, 0x34, 0x40, 0x00, // id, flags
982            0x01, 0x11, 0x00, 0x00, // ttl=1, proto=UDP, checksum
983            0xc0, 0xa8, 0x01, 0x64, // src = 192.168.1.100
984            0x08, 0x08, 0x08, 0x08, // dst = 8.8.8.8
985            // Embedded UDP header (first 8 bytes)
986            0x04, 0xd2, 0x00, 0x35, // sport=1234, dport=53 (DNS)
987            0x00, 0x28, 0x00, 0x00, // length, checksum
988            // Padding to reach 128 bytes total (from start of embedded IP)
989            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
990            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
991            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
992            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
993            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
994            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
995            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
996            // ICMP Extension Header (4 bytes)
997            0x20, 0x00, // version=2, reserved=0
998            0x00, 0x00, // checksum (simplified, would need proper calculation)
999            // ICMP Extension Object - Interface Information (classnum=2)
1000            0x00, 0x10, // length = 16 bytes
1001            0x02, // classnum = Interface Information
1002            0x19, // flags: has_ifindex=1, has_ipaddr=1, has_mtu=1
1003            0x00, 0x00, 0x00, 0x02, // ifindex = 2
1004            0x00, 0x01, 0x00, 0x00, // AFI = IPv4 (1), reserved
1005            0xc0, 0xa8, 0x01, 0x01, // IP = 192.168.1.1
1006        ];
1007
1008        let mut packet = Packet::from_bytes(data.clone());
1009        packet.parse().unwrap();
1010
1011        // Verify ICMP layer exists
1012        assert!(packet.icmp().is_some());
1013        let icmp = packet.icmp().unwrap();
1014
1015        // Verify ICMP type
1016        assert_eq!(
1017            icmp.icmp_type(packet.as_bytes()).unwrap(),
1018            crate::layer::icmp::types::types::TIME_EXCEEDED
1019        );
1020
1021        // Test extension detection
1022        use crate::layer::icmp;
1023        let icmp_offset = packet.layers()[1].end; // After outer IP
1024        let icmp_payload = &data[icmp_offset + 8..]; // After ICMP header
1025
1026        assert!(icmp::has_extensions(
1027            crate::layer::icmp::types::types::TIME_EXCEEDED,
1028            icmp_payload.len()
1029        ));
1030
1031        // Parse extension header
1032        let ext_offset = icmp_offset + 8 + 128; // ICMP header + padded payload
1033        if let Some((version, _checksum)) = icmp::parse_extension_header(&data, ext_offset) {
1034            assert_eq!(version, 2);
1035
1036            // Parse extension object
1037            let obj_offset = ext_offset + 4;
1038            if let Some((len, classnum, _classtype, data_offset)) =
1039                icmp::parse_extension_object(&data, obj_offset)
1040            {
1041                assert_eq!(len, 16);
1042                assert_eq!(
1043                    classnum,
1044                    icmp::extensions::class_nums::INTERFACE_INFORMATION
1045                );
1046
1047                // Parse Interface Information
1048                let data_len = (len as usize) - 4; // Object length minus header
1049                if let Some(info) = icmp::parse_interface_information(&data, data_offset, data_len)
1050                {
1051                    assert!(info.flags.has_ifindex);
1052                    assert!(info.flags.has_ipaddr);
1053                    assert_eq!(info.ifindex, Some(2));
1054                    if let Some(icmp::IpAddr::V4(ip)) = info.ip_addr {
1055                        assert_eq!(ip.to_string(), "192.168.1.1");
1056                    } else {
1057                        panic!("Expected IPv4 address");
1058                    }
1059                }
1060            }
1061        }
1062    }
1063}