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