Skip to main content

crafter/
packet.rs

1//! Packet stack, raw payload layer, and protocol-neutral encode/decode plumbing.
2
3use core::any::Any;
4use core::fmt;
5use core::net::{Ipv4Addr, Ipv6Addr};
6use core::ops::Div;
7
8use crate::checksum::{ipv4_pseudo_header_checksum, ipv6_pseudo_header_checksum};
9use crate::error::Result;
10use crate::protocols::icmp::{Icmpv4, Icmpv4QuotedIp, Icmpv6, NeighborSolicitation};
11use crate::protocols::igmp::Igmp;
12use crate::protocols::ip::{v4::Ipv4, v6::Ipv6};
13use crate::protocols::link::{Arp, Ethernet, Vlan};
14use crate::protocols::transport::{Tcp, Udp};
15use crate::registry::ProtocolRegistry;
16
17/// Pseudo-header context used by transport layers when auto-filling checksums.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19pub enum TransportChecksumContext {
20    /// IPv4 pseudo-header checksum inputs.
21    Ipv4 {
22        /// IPv4 source address.
23        source: Ipv4Addr,
24        /// IPv4 destination address.
25        destination: Ipv4Addr,
26        /// IPv4 protocol number encoded in the pseudo-header.
27        protocol: u8,
28    },
29    /// IPv6 pseudo-header checksum inputs.
30    Ipv6 {
31        /// IPv6 source address.
32        source: Ipv6Addr,
33        /// IPv6 destination address.
34        destination: Ipv6Addr,
35        /// IPv6 next-header value encoded in the pseudo-header.
36        next_header: u8,
37    },
38}
39
40impl TransportChecksumContext {
41    /// Compute the checksum for an encoded transport segment.
42    pub fn checksum(self, transport: &[u8]) -> u16 {
43        match self {
44            Self::Ipv4 {
45                source,
46                destination,
47                protocol,
48            } => ipv4_pseudo_header_checksum(source, destination, protocol, transport),
49            Self::Ipv6 {
50                source,
51                destination,
52                next_header,
53            } => ipv6_pseudo_header_checksum(source, destination, next_header, transport),
54        }
55    }
56}
57
58/// A protocol or payload layer that can live in a [`Packet`] stack.
59///
60/// Protocol implementations are expected to encode only their own bytes. The
61/// packet compiler provides neighboring layer context so future protocols can
62/// fill dependent fields without hidden global state.
63pub trait Layer: fmt::Debug + Send + Sync + 'static {
64    /// Stable layer name used by summaries and generated tools.
65    fn name(&self) -> &'static str;
66
67    /// A one-line layer summary.
68    fn summary(&self) -> String {
69        self.name().to_string()
70    }
71
72    /// Stable field/value pairs used by packet inspection output.
73    fn inspection_fields(&self) -> Vec<(&'static str, String)> {
74        Vec::new()
75    }
76
77    /// Encoded length for this layer before dependent auto-fill.
78    fn encoded_len(&self) -> usize;
79
80    /// Encoded length for this layer once neighboring-layer context is known.
81    ///
82    /// Defaults to [`Layer::encoded_len`]. Layers whose on-wire size depends on
83    /// adjacent layers, for example RFC 4884 ICMP extensions, which zero pad
84    /// the preceding original datagram up to a length the previous header
85    /// declares — override this so enclosing length fields stay accurate. The
86    /// context-free [`Layer::encoded_len`] remains the capacity hint.
87    fn encoded_len_with_context(&self, _ctx: &LayerContext<'_>) -> usize {
88        self.encoded_len()
89    }
90
91    /// Encode this layer into `out`.
92    fn compile(&self, ctx: &LayerContext<'_>, out: &mut Vec<u8>) -> Result<()>;
93
94    /// Whether this layer's `compile()` emits all following layers itself.
95    ///
96    /// Most layers encode only their own bytes and let the packet compiler walk
97    /// on to the next layer. An encapsulating layer such as ESP, however, gathers
98    /// the following layers, encrypts them, and emits them inside its own body
99    /// (see [`crate::protocols::ipsec::Esp`]). When this returns `true`,
100    /// [`Packet::compile_into`] must **not** also emit the following layers — they
101    /// have already been consumed — so the cleartext tail is not double-emitted
102    /// after the encrypted body. Defaults to `false` for every ordinary layer.
103    fn consumes_following(&self) -> bool {
104        false
105    }
106
107    /// Return pseudo-header data for a following transport layer, when present.
108    fn transport_checksum_context(
109        &self,
110        _transport_protocol: u8,
111    ) -> Option<TransportChecksumContext> {
112        None
113    }
114
115    /// Clone this layer behind a trait object.
116    fn clone_layer(&self) -> Box<dyn Layer>;
117
118    /// Return this layer as [`Any`] for typed packet access.
119    fn as_any(&self) -> &dyn Any;
120
121    /// Return this layer mutably as [`Any`] for typed packet access.
122    fn as_any_mut(&mut self) -> &mut dyn Any;
123
124    /// Convert an owned trait object into [`Any`] for downcasting.
125    fn into_any(self: Box<Self>) -> Box<dyn Any>;
126}
127
128impl Clone for Box<dyn Layer> {
129    fn clone(&self) -> Self {
130        self.clone_layer()
131    }
132}
133
134/// Context supplied to each layer while a packet is being compiled.
135#[derive(Debug, Clone, Copy)]
136pub struct LayerContext<'a> {
137    packet: &'a Packet,
138    index: usize,
139}
140
141impl<'a> LayerContext<'a> {
142    /// Create a compile context for a layer index.
143    pub const fn new(packet: &'a Packet, index: usize) -> Self {
144        Self { packet, index }
145    }
146
147    /// The packet being compiled.
148    pub const fn packet(self) -> &'a Packet {
149        self.packet
150    }
151
152    /// The zero-based index of the layer being compiled.
153    pub const fn index(self) -> usize {
154        self.index
155    }
156
157    /// The previous layer in the packet stack.
158    pub fn previous(self) -> Option<&'a dyn Layer> {
159        self.index
160            .checked_sub(1)
161            .and_then(|index| self.packet.get(index))
162    }
163
164    /// The next layer in the packet stack.
165    pub fn next(self) -> Option<&'a dyn Layer> {
166        self.packet.get(self.index + 1)
167    }
168}
169
170/// Opaque link-layer decode entrypoint.
171#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
172pub enum LinkType {
173    /// Decode bytes as an unsupported or caller-defined raw link payload.
174    Raw,
175    /// Ethernet frames.
176    Ethernet,
177    /// Bare IEEE 802.11 MAC frames without radiotap metadata.
178    Ieee80211,
179    /// Radiotap metadata followed by an IEEE 802.11 MAC frame.
180    Radiotap,
181    /// BLE LE Link Layer with radio pseudo-header; pcap DLT 256.
182    BluetoothLeLl,
183    /// Bare IEEE 802.15.4 MAC frame with FCS; pcap DLT 195 (with-FCS) / 230 (no-FCS).
184    Ieee802154,
185    /// IEEE 802.15.4 TAP pseudo-header followed by a MAC frame; pcap DLT 283.
186    Ieee802154Tap,
187    /// Linux cooked capture frames.
188    LinuxCooked,
189    /// Linux cooked capture frames.
190    LinuxSll,
191    /// BSD null/loopback frames.
192    NullLoopback,
193}
194
195/// Opaque network-layer decode entrypoint.
196#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
197pub enum NetworkLayer {
198    /// Decode bytes as an unsupported or caller-defined raw network payload.
199    Raw,
200    /// IPv4 packets. Protocol-specific decoding is added in later steps.
201    Ipv4,
202    /// IPv6 packets. Protocol-specific decoding is added in later steps.
203    Ipv6,
204}
205
206/// Raw payload bytes or an unsupported decoded tail.
207#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
208pub struct Raw {
209    bytes: Vec<u8>,
210}
211
212impl Raw {
213    /// Create an empty raw layer.
214    pub const fn new() -> Self {
215        Self { bytes: Vec::new() }
216    }
217
218    /// Create a raw layer by copying bytes.
219    pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Self {
220        Self {
221            bytes: bytes.as_ref().to_vec(),
222        }
223    }
224
225    /// Borrow the raw bytes.
226    pub fn as_bytes(&self) -> &[u8] {
227        &self.bytes
228    }
229
230    /// Mutably borrow the raw bytes.
231    pub fn as_bytes_mut(&mut self) -> &mut Vec<u8> {
232        &mut self.bytes
233    }
234
235    /// Append bytes to this raw layer.
236    pub fn extend_from_slice(&mut self, bytes: &[u8]) -> &mut Self {
237        self.bytes.extend_from_slice(bytes);
238        self
239    }
240
241    /// Consume the layer and return its bytes.
242    pub fn into_bytes(self) -> Vec<u8> {
243        self.bytes
244    }
245
246    /// Number of raw bytes.
247    pub fn len(&self) -> usize {
248        self.bytes.len()
249    }
250
251    /// Return true when this raw layer contains no bytes.
252    pub fn is_empty(&self) -> bool {
253        self.bytes.is_empty()
254    }
255
256    /// Return a canonical hex dump of the raw bytes.
257    pub fn hexdump(&self) -> String {
258        hexdump(self.as_bytes())
259    }
260
261    /// Return raw bytes as a lossy UTF-8 string.
262    pub fn raw_string_lossy(&self) -> String {
263        String::from_utf8_lossy(self.as_bytes()).into_owned()
264    }
265}
266
267impl Layer for Raw {
268    fn name(&self) -> &'static str {
269        "Raw"
270    }
271
272    fn summary(&self) -> String {
273        format!("Raw(len={})", self.bytes.len())
274    }
275
276    fn inspection_fields(&self) -> Vec<(&'static str, String)> {
277        vec![
278            ("len", self.bytes.len().to_string()),
279            ("bytes", hex_bytes(&self.bytes)),
280            ("text_lossy", quoted_lossy_text(self.as_bytes())),
281        ]
282    }
283
284    fn encoded_len(&self) -> usize {
285        self.bytes.len()
286    }
287
288    fn compile(&self, _ctx: &LayerContext<'_>, out: &mut Vec<u8>) -> Result<()> {
289        out.extend_from_slice(&self.bytes);
290        Ok(())
291    }
292
293    fn clone_layer(&self) -> Box<dyn Layer> {
294        Box::new(self.clone())
295    }
296
297    fn as_any(&self) -> &dyn Any {
298        self
299    }
300
301    fn as_any_mut(&mut self) -> &mut dyn Any {
302        self
303    }
304
305    fn into_any(self: Box<Self>) -> Box<dyn Any> {
306        self
307    }
308}
309
310impl From<Vec<u8>> for Raw {
311    fn from(bytes: Vec<u8>) -> Self {
312        Self { bytes }
313    }
314}
315
316impl From<&[u8]> for Raw {
317    fn from(bytes: &[u8]) -> Self {
318        Self::from_bytes(bytes)
319    }
320}
321
322impl<const N: usize> From<&[u8; N]> for Raw {
323    fn from(bytes: &[u8; N]) -> Self {
324        Self::from_bytes(bytes)
325    }
326}
327
328impl<const N: usize> From<[u8; N]> for Raw {
329    fn from(bytes: [u8; N]) -> Self {
330        Self::from_bytes(bytes)
331    }
332}
333
334impl From<&str> for Raw {
335    fn from(value: &str) -> Self {
336        Self::from_bytes(value.as_bytes())
337    }
338}
339
340impl From<String> for Raw {
341    fn from(value: String) -> Self {
342        Self::from_bytes(value.as_bytes())
343    }
344}
345
346#[derive(Debug, Clone)]
347enum PacketLayer {
348    Boxed(Box<dyn Layer>),
349    Raw(Raw),
350    Ethernet(Ethernet),
351    Vlan(Vlan),
352    Arp(Arp),
353    Ipv4(Ipv4),
354    Ipv6(Ipv6),
355    Tcp(Tcp),
356    Udp(Udp),
357    Icmpv4(Icmpv4),
358    Icmpv4QuotedIp(Icmpv4QuotedIp),
359    Icmpv6(Icmpv6),
360    Igmp(Igmp),
361    NeighborSolicitation(NeighborSolicitation),
362}
363
364impl PacketLayer {
365    fn as_layer(&self) -> &dyn Layer {
366        match self {
367            Self::Boxed(layer) => layer.as_ref(),
368            Self::Raw(layer) => layer,
369            Self::Ethernet(layer) => layer,
370            Self::Vlan(layer) => layer,
371            Self::Arp(layer) => layer,
372            Self::Ipv4(layer) => layer,
373            Self::Ipv6(layer) => layer,
374            Self::Tcp(layer) => layer,
375            Self::Udp(layer) => layer,
376            Self::Icmpv4(layer) => layer,
377            Self::Icmpv4QuotedIp(layer) => layer,
378            Self::Icmpv6(layer) => layer,
379            Self::Igmp(layer) => layer,
380            Self::NeighborSolicitation(layer) => layer,
381        }
382    }
383
384    fn as_layer_mut(&mut self) -> &mut dyn Layer {
385        match self {
386            Self::Boxed(layer) => layer.as_mut(),
387            Self::Raw(layer) => layer,
388            Self::Ethernet(layer) => layer,
389            Self::Vlan(layer) => layer,
390            Self::Arp(layer) => layer,
391            Self::Ipv4(layer) => layer,
392            Self::Ipv6(layer) => layer,
393            Self::Tcp(layer) => layer,
394            Self::Udp(layer) => layer,
395            Self::Icmpv4(layer) => layer,
396            Self::Icmpv4QuotedIp(layer) => layer,
397            Self::Icmpv6(layer) => layer,
398            Self::Igmp(layer) => layer,
399            Self::NeighborSolicitation(layer) => layer,
400        }
401    }
402
403    fn into_box(self) -> Box<dyn Layer> {
404        match self {
405            Self::Boxed(layer) => layer,
406            Self::Raw(layer) => Box::new(layer),
407            Self::Ethernet(layer) => Box::new(layer),
408            Self::Vlan(layer) => Box::new(layer),
409            Self::Arp(layer) => Box::new(layer),
410            Self::Ipv4(layer) => Box::new(layer),
411            Self::Ipv6(layer) => Box::new(layer),
412            Self::Tcp(layer) => Box::new(layer),
413            Self::Udp(layer) => Box::new(layer),
414            Self::Icmpv4(layer) => Box::new(layer),
415            Self::Icmpv4QuotedIp(layer) => Box::new(layer),
416            Self::Icmpv6(layer) => Box::new(layer),
417            Self::Igmp(layer) => Box::new(layer),
418            Self::NeighborSolicitation(layer) => Box::new(layer),
419        }
420    }
421
422    fn encoded_len_with_context(&self, ctx: &LayerContext<'_>) -> usize {
423        match self {
424            Self::Boxed(layer) => layer.encoded_len_with_context(ctx),
425            Self::Raw(layer) => layer.encoded_len_with_context(ctx),
426            Self::Ethernet(layer) => layer.encoded_len_with_context(ctx),
427            Self::Vlan(layer) => layer.encoded_len_with_context(ctx),
428            Self::Arp(layer) => layer.encoded_len_with_context(ctx),
429            Self::Ipv4(layer) => layer.encoded_len_with_context(ctx),
430            Self::Ipv6(layer) => layer.encoded_len_with_context(ctx),
431            Self::Tcp(layer) => layer.encoded_len_with_context(ctx),
432            Self::Udp(layer) => layer.encoded_len_with_context(ctx),
433            Self::Icmpv4(layer) => layer.encoded_len_with_context(ctx),
434            Self::Icmpv4QuotedIp(layer) => layer.encoded_len_with_context(ctx),
435            Self::Icmpv6(layer) => layer.encoded_len_with_context(ctx),
436            Self::Igmp(layer) => layer.encoded_len_with_context(ctx),
437            Self::NeighborSolicitation(layer) => layer.encoded_len_with_context(ctx),
438        }
439    }
440
441    fn compile(&self, ctx: &LayerContext<'_>, out: &mut Vec<u8>) -> Result<()> {
442        match self {
443            Self::Boxed(layer) => layer.compile(ctx, out),
444            Self::Raw(layer) => layer.compile(ctx, out),
445            Self::Ethernet(layer) => layer.compile(ctx, out),
446            Self::Vlan(layer) => layer.compile(ctx, out),
447            Self::Arp(layer) => layer.compile(ctx, out),
448            Self::Ipv4(layer) => layer.compile(ctx, out),
449            Self::Ipv6(layer) => layer.compile(ctx, out),
450            Self::Tcp(layer) => layer.compile(ctx, out),
451            Self::Udp(layer) => layer.compile(ctx, out),
452            Self::Icmpv4(layer) => layer.compile(ctx, out),
453            Self::Icmpv4QuotedIp(layer) => layer.compile(ctx, out),
454            Self::Icmpv6(layer) => layer.compile(ctx, out),
455            Self::Igmp(layer) => layer.compile(ctx, out),
456            Self::NeighborSolicitation(layer) => layer.compile(ctx, out),
457        }
458    }
459
460    fn consumes_following(&self) -> bool {
461        match self {
462            Self::Boxed(layer) => layer.consumes_following(),
463            Self::Raw(layer) => layer.consumes_following(),
464            Self::Ethernet(layer) => layer.consumes_following(),
465            Self::Vlan(layer) => layer.consumes_following(),
466            Self::Arp(layer) => layer.consumes_following(),
467            Self::Ipv4(layer) => layer.consumes_following(),
468            Self::Ipv6(layer) => layer.consumes_following(),
469            Self::Tcp(layer) => layer.consumes_following(),
470            Self::Udp(layer) => layer.consumes_following(),
471            Self::Icmpv4(layer) => layer.consumes_following(),
472            Self::Icmpv4QuotedIp(layer) => layer.consumes_following(),
473            Self::Icmpv6(layer) => layer.consumes_following(),
474            Self::Igmp(layer) => layer.consumes_following(),
475            Self::NeighborSolicitation(layer) => layer.consumes_following(),
476        }
477    }
478}
479
480/// Ordered stack of packet layers.
481#[derive(Debug, Clone, Default)]
482pub struct Packet {
483    layers: Vec<PacketLayer>,
484}
485
486impl Packet {
487    /// Create an empty packet.
488    pub const fn new() -> Self {
489        Self { layers: Vec::new() }
490    }
491
492    /// Create an empty packet with room for `capacity` layers.
493    pub(crate) fn with_capacity(capacity: usize) -> Self {
494        Self {
495            layers: Vec::with_capacity(capacity),
496        }
497    }
498
499    /// Create a packet containing one layer.
500    pub fn from_layer<L>(layer: L) -> Self
501    where
502        L: Layer,
503    {
504        Self::new().push(layer)
505    }
506
507    /// Append a concrete layer and return the packet for builder chaining.
508    pub fn push<L>(mut self, layer: L) -> Self
509    where
510        L: Layer,
511    {
512        self.layers.push(PacketLayer::Boxed(Box::new(layer)));
513        self
514    }
515
516    /// Append a boxed layer and return the packet for builder chaining.
517    pub fn push_box(mut self, layer: Box<dyn Layer>) -> Self {
518        self.layers.push(PacketLayer::Boxed(layer));
519        self
520    }
521
522    /// Mutably append a concrete layer.
523    pub fn push_mut<L>(&mut self, layer: L) -> &mut Self
524    where
525        L: Layer,
526    {
527        self.layers.push(PacketLayer::Boxed(Box::new(layer)));
528        self
529    }
530
531    /// Mutably append a boxed layer.
532    pub fn push_box_mut(&mut self, layer: Box<dyn Layer>) -> &mut Self {
533        self.layers.push(PacketLayer::Boxed(layer));
534        self
535    }
536
537    pub(crate) fn push_raw(mut self, layer: Raw) -> Self {
538        self.layers.push(PacketLayer::Raw(layer));
539        self
540    }
541
542    pub(crate) fn push_raw_mut(&mut self, layer: Raw) -> &mut Self {
543        self.layers.push(PacketLayer::Raw(layer));
544        self
545    }
546
547    pub(crate) fn push_ethernet(mut self, layer: Ethernet) -> Self {
548        self.layers.push(PacketLayer::Ethernet(layer));
549        self
550    }
551
552    pub(crate) fn push_ethernet_mut(&mut self, layer: Ethernet) -> &mut Self {
553        self.layers.push(PacketLayer::Ethernet(layer));
554        self
555    }
556
557    pub(crate) fn push_vlan(mut self, layer: Vlan) -> Self {
558        self.layers.push(PacketLayer::Vlan(layer));
559        self
560    }
561
562    pub(crate) fn push_arp_mut(&mut self, layer: Arp) -> &mut Self {
563        self.layers.push(PacketLayer::Arp(layer));
564        self
565    }
566
567    pub(crate) fn push_ipv4(mut self, layer: Ipv4) -> Self {
568        self.layers.push(PacketLayer::Ipv4(layer));
569        self
570    }
571
572    pub(crate) fn push_ipv4_mut(&mut self, layer: Ipv4) -> &mut Self {
573        self.layers.push(PacketLayer::Ipv4(layer));
574        self
575    }
576
577    pub(crate) fn push_ipv6(mut self, layer: Ipv6) -> Self {
578        self.layers.push(PacketLayer::Ipv6(layer));
579        self
580    }
581
582    pub(crate) fn push_tcp(mut self, layer: Tcp) -> Self {
583        self.layers.push(PacketLayer::Tcp(layer));
584        self
585    }
586
587    pub(crate) fn push_udp(mut self, layer: Udp) -> Self {
588        self.layers.push(PacketLayer::Udp(layer));
589        self
590    }
591
592    pub(crate) fn push_icmpv4_mut(&mut self, layer: Icmpv4) -> &mut Self {
593        self.layers.push(PacketLayer::Icmpv4(layer));
594        self
595    }
596
597    pub(crate) fn push_icmpv4_quoted_ip_mut(&mut self, layer: Icmpv4QuotedIp) -> &mut Self {
598        self.layers.push(PacketLayer::Icmpv4QuotedIp(layer));
599        self
600    }
601
602    pub(crate) fn push_icmpv6(mut self, layer: Icmpv6) -> Self {
603        self.layers.push(PacketLayer::Icmpv6(layer));
604        self
605    }
606
607    pub(crate) fn push_igmp(mut self, layer: Igmp) -> Self {
608        self.layers.push(PacketLayer::Igmp(layer));
609        self
610    }
611
612    pub(crate) fn push_neighbor_solicitation(mut self, layer: NeighborSolicitation) -> Self {
613        self.layers.push(PacketLayer::NeighborSolicitation(layer));
614        self
615    }
616
617    /// Append all layers from another packet.
618    pub fn concat(mut self, other: impl IntoPacket) -> Self {
619        self.layers.extend(other.into_packet().layers);
620        self
621    }
622
623    /// Mutably append all layers from another packet.
624    pub fn extend(&mut self, other: impl IntoPacket) -> &mut Self {
625        self.layers.extend(other.into_packet().layers);
626        self
627    }
628
629    /// Remove and return the final layer.
630    pub fn pop(&mut self) -> Option<Box<dyn Layer>> {
631        self.layers.pop().map(PacketLayer::into_box)
632    }
633
634    /// Remove and return the final layer when it has type `T`.
635    pub fn pop_typed<T>(&mut self) -> Option<T>
636    where
637        T: Layer,
638    {
639        let layer = self.pop()?;
640        if layer.as_any().is::<T>() {
641            let any = layer.into_any();
642            Some(*any.downcast::<T>().ok()?)
643        } else {
644            self.layers.push(PacketLayer::Boxed(layer));
645            None
646        }
647    }
648
649    /// Number of layers in the packet.
650    pub fn len(&self) -> usize {
651        self.layers.len()
652    }
653
654    /// Return true when the packet contains no layers.
655    pub fn is_empty(&self) -> bool {
656        self.layers.is_empty()
657    }
658
659    /// Return the encoded byte length implied by the current layers.
660    pub fn encoded_len(&self) -> usize {
661        let mut total = 0;
662        for (index, layer) in self.layers.iter().enumerate() {
663            let ctx = LayerContext::new(self, index);
664            total += layer.encoded_len_with_context(&ctx);
665            // An encapsulating layer accounts for the following layers inside its
666            // own body; stop summing so the consumed tail is not counted twice.
667            if layer.consumes_following() {
668                break;
669            }
670        }
671        total
672    }
673
674    /// Positional layer access.
675    pub fn get(&self, index: usize) -> Option<&dyn Layer> {
676        self.layers.get(index).map(PacketLayer::as_layer)
677    }
678
679    /// Mutable positional layer access.
680    pub fn get_mut(&mut self, index: usize) -> Option<&mut dyn Layer> {
681        self.layers.get_mut(index).map(PacketLayer::as_layer_mut)
682    }
683
684    pub(crate) fn single_raw_layer_after(&self, index: usize) -> Option<&Raw> {
685        let next = index.checked_add(1)?;
686        if self.layers.len() != next.checked_add(1)? {
687            return None;
688        }
689        match self.layers.get(next)? {
690            PacketLayer::Raw(raw) => Some(raw),
691            PacketLayer::Boxed(layer) => layer.as_any().downcast_ref::<Raw>(),
692            _ => None,
693        }
694    }
695
696    /// First layer of type `T`.
697    pub fn layer<T>(&self) -> Option<&T>
698    where
699        T: Layer,
700    {
701        self.layers
702            .iter()
703            .find_map(|layer| layer.as_layer().as_any().downcast_ref::<T>())
704    }
705
706    /// First mutable layer of type `T`.
707    pub fn layer_mut<T>(&mut self) -> Option<&mut T>
708    where
709        T: Layer,
710    {
711        self.layers
712            .iter_mut()
713            .find_map(|layer| layer.as_layer_mut().as_any_mut().downcast_mut::<T>())
714    }
715
716    /// All layers of type `T`, preserving packet order.
717    pub fn layers<T>(&self) -> impl Iterator<Item = &T>
718    where
719        T: Layer,
720    {
721        self.layers
722            .iter()
723            .filter_map(|layer| layer.as_layer().as_any().downcast_ref::<T>())
724    }
725
726    /// All mutable layers of type `T`, preserving packet order.
727    pub fn layers_mut<T>(&mut self) -> impl Iterator<Item = &mut T>
728    where
729        T: Layer,
730    {
731        self.layers
732            .iter_mut()
733            .filter_map(|layer| layer.as_layer_mut().as_any_mut().downcast_mut::<T>())
734    }
735
736    /// Ordered layer iteration.
737    pub fn iter(&self) -> impl Iterator<Item = &dyn Layer> {
738        self.layers.iter().map(PacketLayer::as_layer)
739    }
740
741    /// Ordered mutable layer iteration.
742    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut dyn Layer> {
743        self.layers.iter_mut().map(PacketLayer::as_layer_mut)
744    }
745
746    /// Compile the packet into deterministic bytes.
747    pub fn compile(&self) -> Result<CompiledPacket> {
748        let mut bytes = Vec::with_capacity(self.encoded_len());
749        self.compile_into(&mut bytes)?;
750        Ok(CompiledPacket::new(bytes))
751    }
752
753    /// Append compiled bytes into an existing buffer.
754    pub fn compile_into(&self, out: &mut Vec<u8>) -> Result<()> {
755        for (index, layer) in self.layers.iter().enumerate() {
756            let ctx = LayerContext::new(self, index);
757            layer.compile(&ctx, out)?;
758            // An encapsulating layer (e.g. ESP) emits all following layers inside
759            // its own body. Stop here so the consumed tail is not re-emitted as a
760            // cleartext duplicate after the encrypted body.
761            if layer.consumes_following() {
762                break;
763            }
764        }
765        Ok(())
766    }
767
768    pub(crate) fn compile_layers_after_into(&self, index: usize, out: &mut Vec<u8>) -> Result<()> {
769        for (layer_index, layer) in self.layers.iter().enumerate().skip(index + 1) {
770            let ctx = LayerContext::new(self, layer_index);
771            layer.compile(&ctx, out)?;
772            if layer.consumes_following() {
773                break;
774            }
775        }
776        Ok(())
777    }
778
779    pub(crate) fn compile_all_layers_after_into(
780        &self,
781        index: usize,
782        out: &mut Vec<u8>,
783    ) -> Result<()> {
784        for (layer_index, layer) in self.layers.iter().enumerate().skip(index + 1) {
785            let ctx = LayerContext::new(self, layer_index);
786            layer.compile(&ctx, out)?;
787        }
788        Ok(())
789    }
790
791    pub(crate) fn encoded_len_after(&self, index: usize) -> usize {
792        let mut total = 0;
793        for (layer_index, layer) in self.layers.iter().enumerate().skip(index + 1) {
794            let ctx = LayerContext::new(self, layer_index);
795            total += layer.encoded_len_with_context(&ctx);
796            if layer.consumes_following() {
797                break;
798            }
799        }
800        total
801    }
802
803    /// Decode bytes as raw payload.
804    pub fn decode_raw(bytes: impl AsRef<[u8]>) -> Result<Self> {
805        Ok(Self::new().push(Raw::from_bytes(bytes)))
806    }
807
808    /// Decode bytes from a link-layer entrypoint.
809    pub fn decode_from_link(link_type: LinkType, bytes: impl AsRef<[u8]>) -> Result<Self> {
810        ProtocolRegistry::builtin().decode_from_link(link_type, bytes)
811    }
812
813    /// Decode bytes from a link-layer entrypoint using an explicit registry.
814    pub fn decode_from_link_with_registry(
815        registry: &ProtocolRegistry,
816        link_type: LinkType,
817        bytes: impl AsRef<[u8]>,
818    ) -> Result<Self> {
819        registry.decode_from_link(link_type, bytes)
820    }
821
822    /// Decode bytes from a network-layer entrypoint.
823    pub fn decode_from_l3(network_layer: NetworkLayer, bytes: impl AsRef<[u8]>) -> Result<Self> {
824        ProtocolRegistry::builtin().decode_from_l3(network_layer, bytes)
825    }
826
827    /// Decode bytes from a network-layer entrypoint using an explicit registry.
828    pub fn decode_from_l3_with_registry(
829        registry: &ProtocolRegistry,
830        network_layer: NetworkLayer,
831        bytes: impl AsRef<[u8]>,
832    ) -> Result<Self> {
833        registry.decode_from_l3(network_layer, bytes)
834    }
835
836    /// One-line packet summary.
837    pub fn summary(&self) -> String {
838        if self.layers.is_empty() {
839            "Packet(empty)".to_string()
840        } else {
841            self.layers
842                .iter()
843                .map(|layer| layer.as_layer().summary())
844                .collect::<Vec<_>>()
845                .join(" / ")
846        }
847    }
848
849    /// Multi-line packet tree intended for display in examples and tools.
850    pub fn show(&self) -> String {
851        if self.layers.is_empty() {
852            return "Packet(empty)".to_string();
853        }
854
855        let mut output = format!(
856            "Packet(len={}, layers={})",
857            self.encoded_len(),
858            self.layers.len()
859        );
860        for (index, layer) in self.layers.iter().enumerate() {
861            let layer = layer.as_layer();
862            output.push_str(&format!("\n  [{index}] {}", layer.name()));
863            for (name, value) in layer.inspection_fields() {
864                output.push_str(&format!("\n      {name}: {value}"));
865            }
866        }
867        output
868    }
869
870    /// Compile and return a canonical hex dump.
871    pub fn hexdump(&self) -> Result<String> {
872        Ok(hexdump(self.compile()?.as_bytes()))
873    }
874
875    /// Compile and return raw bytes as a lossy UTF-8 string.
876    pub fn raw_string_lossy(&self) -> Result<String> {
877        Ok(String::from_utf8_lossy(self.compile()?.as_bytes()).into_owned())
878    }
879}
880
881/// Conversion into a packet stack used by composition helpers.
882pub trait IntoPacket {
883    /// Convert this value into a packet.
884    fn into_packet(self) -> Packet;
885}
886
887impl IntoPacket for Packet {
888    fn into_packet(self) -> Packet {
889        self
890    }
891}
892
893impl<T> IntoPacket for T
894where
895    T: Layer,
896{
897    fn into_packet(self) -> Packet {
898        Packet::from_layer(self)
899    }
900}
901
902impl IntoPacket for Box<dyn Layer> {
903    fn into_packet(self) -> Packet {
904        Packet::new().push_box(self)
905    }
906}
907
908impl<R> Div<R> for Packet
909where
910    R: IntoPacket,
911{
912    type Output = Packet;
913
914    fn div(self, rhs: R) -> Self::Output {
915        self.concat(rhs)
916    }
917}
918
919impl<R> Div<R> for Raw
920where
921    R: IntoPacket,
922{
923    type Output = Packet;
924
925    fn div(self, rhs: R) -> Self::Output {
926        Packet::from_layer(self).concat(rhs)
927    }
928}
929
930/// Compiled packet bytes.
931#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
932pub struct CompiledPacket {
933    bytes: Vec<u8>,
934}
935
936impl CompiledPacket {
937    /// Create a compiled packet from bytes.
938    pub fn new(bytes: Vec<u8>) -> Self {
939        Self { bytes }
940    }
941
942    /// Borrow compiled bytes.
943    pub fn as_bytes(&self) -> &[u8] {
944        &self.bytes
945    }
946
947    /// Consume and return compiled bytes.
948    pub fn into_bytes(self) -> Vec<u8> {
949        self.bytes
950    }
951
952    /// Number of compiled bytes.
953    pub fn len(&self) -> usize {
954        self.bytes.len()
955    }
956
957    /// Return true when there are no compiled bytes.
958    pub fn is_empty(&self) -> bool {
959        self.bytes.is_empty()
960    }
961
962    /// Return a canonical hex dump.
963    pub fn hexdump(&self) -> String {
964        hexdump(self.as_bytes())
965    }
966
967    /// Return compiled bytes as a lossy UTF-8 string.
968    pub fn raw_string_lossy(&self) -> String {
969        String::from_utf8_lossy(self.as_bytes()).into_owned()
970    }
971}
972
973impl AsRef<[u8]> for CompiledPacket {
974    fn as_ref(&self) -> &[u8] {
975        self.as_bytes()
976    }
977}
978
979impl core::ops::Deref for CompiledPacket {
980    type Target = [u8];
981
982    fn deref(&self) -> &Self::Target {
983        self.as_bytes()
984    }
985}
986
987impl From<CompiledPacket> for Vec<u8> {
988    fn from(packet: CompiledPacket) -> Self {
989        packet.into_bytes()
990    }
991}
992
993/// Return a stable hex dump with 16 bytes per line.
994pub fn hexdump(bytes: &[u8]) -> String {
995    let mut output = String::new();
996
997    for (offset, chunk) in bytes.chunks(16).enumerate() {
998        if offset > 0 {
999            output.push('\n');
1000        }
1001
1002        output.push_str(&format!("{:04x}: ", offset * 16));
1003        for (index, byte) in chunk.iter().enumerate() {
1004            if index > 0 {
1005                output.push(' ');
1006            }
1007            output.push_str(&format!("{byte:02x}"));
1008        }
1009    }
1010
1011    output
1012}
1013
1014fn hex_bytes(bytes: &[u8]) -> String {
1015    let mut output = String::new();
1016
1017    for (index, byte) in bytes.iter().enumerate() {
1018        if index > 0 {
1019            output.push(' ');
1020        }
1021        output.push_str(&format!("{byte:02x}"));
1022    }
1023
1024    output
1025}
1026
1027fn quoted_lossy_text(bytes: &[u8]) -> String {
1028    let text = String::from_utf8_lossy(bytes);
1029    let mut output = String::from("\"");
1030
1031    for ch in text.chars() {
1032        match ch {
1033            '\0' => output.push_str("\\0"),
1034            '\n' => output.push_str("\\n"),
1035            '\r' => output.push_str("\\r"),
1036            '\t' => output.push_str("\\t"),
1037            '"' => output.push_str("\\\""),
1038            '\\' => output.push_str("\\\\"),
1039            ch if ch.is_control() => output.extend(ch.escape_default()),
1040            ch if ch.is_ascii() => output.push(ch),
1041            ch => output.extend(ch.escape_default()),
1042        }
1043    }
1044
1045    output.push('"');
1046    output
1047}
1048
1049#[cfg(test)]
1050mod raw_layer {
1051    use super::{Layer, Packet, Raw};
1052
1053    #[test]
1054    fn raw_layer_preserves_bytes() {
1055        let raw = Raw::from_bytes(b"hello");
1056
1057        assert_eq!(raw.name(), "Raw");
1058        assert_eq!(raw.len(), 5);
1059        assert_eq!(raw.as_bytes(), b"hello");
1060        assert_eq!(raw.clone().into_bytes(), b"hello".to_vec());
1061        assert_eq!(raw.summary(), "Raw(len=5)");
1062    }
1063
1064    #[test]
1065    fn raw_layer_compiles_to_its_payload() {
1066        let packet = Packet::new().push(Raw::from("hello"));
1067
1068        assert_eq!(packet.compile().unwrap().as_bytes(), b"hello");
1069        assert_eq!(packet.raw_string_lossy().unwrap(), "hello");
1070    }
1071
1072    #[test]
1073    fn raw_decode_preserves_unknown_bytes() {
1074        let decoded = Packet::decode_raw([0xde, 0xad, 0xbe, 0xef]).unwrap();
1075        let raw = decoded.layer::<Raw>().unwrap();
1076
1077        assert_eq!(decoded.len(), 1);
1078        assert_eq!(raw.as_bytes(), [0xde, 0xad, 0xbe, 0xef]);
1079    }
1080}
1081
1082#[cfg(test)]
1083mod igmp_packet_storage {
1084    use super::{Packet, Raw};
1085    use crate::protocols::igmp::{append_igmp_packet, Igmp};
1086    use core::net::Ipv4Addr;
1087
1088    #[test]
1089    fn helper_storage_clones_downcasts_inspects_encodes_and_pops_igmp() {
1090        let group = Ipv4Addr::new(224, 0, 0, 251);
1091        let mut packet = Packet::new().push_igmp(
1092            Igmp::v2_membership_report(group)
1093                .with_code(0x05)
1094                .checksum(0x1234),
1095        );
1096
1097        let igmp = packet.layer::<Igmp>().expect("typed IGMP layer");
1098        assert_eq!(igmp.group_address_value(), group);
1099        assert_eq!(igmp.code_value(), 0x05);
1100        assert_eq!(packet.get(0).expect("first layer").name(), "Igmp");
1101        assert_eq!(
1102            packet.summary(),
1103            "Igmp(version=IGMPv2, type=0x16 (IGMPv2 Membership Report), code=0x05 (No registered code), group=224.0.0.251 (multicast), checksum=0x1234, checksum_status=not_checked)"
1104        );
1105
1106        let show = packet.show();
1107        assert!(show.contains("Packet(len=8, layers=1)"), "{show}");
1108        assert!(show.contains("[0] Igmp"), "{show}");
1109        assert!(
1110            show.contains("type: 0x16 (IGMPv2 Membership Report)"),
1111            "{show}"
1112        );
1113        assert!(show.contains("checksum: 0x1234"), "{show}");
1114
1115        let cloned = packet.clone();
1116        assert_eq!(
1117            cloned
1118                .layer::<Igmp>()
1119                .expect("cloned typed IGMP layer")
1120                .checksum_value(),
1121            Some(0x1234)
1122        );
1123        assert_eq!(
1124            packet.compile().expect("compile stored IGMP").as_bytes(),
1125            &[0x16, 0x05, 0x12, 0x34, 224, 0, 0, 251]
1126        );
1127
1128        let popped = packet.pop_typed::<Igmp>().expect("pop typed IGMP");
1129        assert_eq!(popped.group_address_value(), group);
1130        assert!(packet.is_empty());
1131    }
1132
1133    #[test]
1134    fn decoded_igmp_uses_typed_storage_and_preserves_raw_tail() {
1135        let bytes = [0x16, 0x00, 0xab, 0xcd, 224, 0, 0, 251, 0xde, 0xad];
1136
1137        let decoded =
1138            append_igmp_packet(Packet::new(), &bytes).expect("append decoded IGMP packet");
1139        let igmp = decoded.layer::<Igmp>().expect("typed decoded IGMP");
1140        let raw = decoded.layer::<Raw>().expect("preserved raw IGMP tail");
1141
1142        assert_eq!(decoded.len(), 2);
1143        assert_eq!(decoded.get(0).expect("first layer").name(), "Igmp");
1144        assert_eq!(igmp.igmp_type_value(), 0x16);
1145        assert_eq!(igmp.checksum_value(), Some(0xabcd));
1146        assert_eq!(igmp.group_address_value(), Ipv4Addr::new(224, 0, 0, 251));
1147        assert_eq!(raw.as_bytes(), &[0xde, 0xad]);
1148        assert_eq!(
1149            decoded
1150                .compile()
1151                .expect("roundtrip decoded IGMP")
1152                .as_bytes(),
1153            &bytes
1154        );
1155    }
1156}
1157
1158#[cfg(test)]
1159mod packet_stack {
1160    use super::{hexdump, Layer, LinkType, NetworkLayer, Packet, Raw};
1161
1162    #[test]
1163    fn builder_push_preserves_layer_order() {
1164        let packet = Packet::new()
1165            .push(Raw::from("first"))
1166            .push(Raw::from("second"));
1167
1168        let layers: Vec<_> = packet.layers::<Raw>().map(Raw::as_bytes).collect();
1169
1170        assert_eq!(packet.len(), 2);
1171        assert_eq!(layers, vec![b"first".as_slice(), b"second".as_slice()]);
1172        assert_eq!(packet.summary(), "Raw(len=5) / Raw(len=6)");
1173    }
1174
1175    #[test]
1176    fn slash_composition_builds_packets() {
1177        let packet = Raw::from("a") / Raw::from("b") / Packet::new().push(Raw::from("c"));
1178
1179        assert_eq!(packet.len(), 3);
1180        assert_eq!(packet.compile().unwrap().as_bytes(), b"abc");
1181    }
1182
1183    #[test]
1184    fn concat_and_pop_keep_stack_predictable() {
1185        let mut packet = Packet::new()
1186            .push(Raw::from("a"))
1187            .concat(Packet::new().push(Raw::from("b")));
1188
1189        assert_eq!(packet.compile().unwrap().as_bytes(), b"ab");
1190
1191        let popped = packet.pop_typed::<Raw>().unwrap();
1192
1193        assert_eq!(popped.as_bytes(), b"b");
1194        assert_eq!(packet.compile().unwrap().as_bytes(), b"a");
1195    }
1196
1197    #[test]
1198    fn typed_access_supports_mutation_and_ordered_iteration() {
1199        let mut packet = Packet::new().push(Raw::from("one")).push(Raw::from("two"));
1200
1201        packet.layer_mut::<Raw>().unwrap().extend_from_slice(b"!");
1202
1203        let names: Vec<_> = packet.iter().map(Layer::name).collect();
1204        let bytes: Vec<_> = packet.layers::<Raw>().map(Raw::as_bytes).collect();
1205
1206        assert_eq!(names, vec!["Raw", "Raw"]);
1207        assert_eq!(bytes, vec![b"one!".as_slice(), b"two".as_slice()]);
1208    }
1209
1210    #[test]
1211    fn raw_decode_entrypoints_are_lossless_raw_packets() {
1212        let link = Packet::decode_from_link(LinkType::Raw, b"frame").unwrap();
1213        let l3 = Packet::decode_from_l3(NetworkLayer::Raw, b"packet").unwrap();
1214
1215        assert_eq!(link.compile().unwrap().as_bytes(), b"frame");
1216        assert_eq!(l3.compile().unwrap().as_bytes(), b"packet");
1217    }
1218
1219    #[test]
1220    fn inspection_helpers_are_stable() {
1221        let packet = Packet::new().push(Raw::from([0x41, 0x42, 0x43].as_slice()));
1222
1223        assert_eq!(
1224            packet.show(),
1225            "Packet(len=3, layers=1)\n  [0] Raw\n      len: 3\n      bytes: 41 42 43\n      text_lossy: \"ABC\""
1226        );
1227        assert_eq!(packet.hexdump().unwrap(), "0000: 41 42 43");
1228        assert_eq!(hexdump(&[]), "");
1229    }
1230}
1231
1232#[cfg(test)]
1233mod formatting {
1234    use super::{hexdump, Layer, Packet, Raw};
1235
1236    const RAW_ONLY_SUMMARY: &str = fixture_str!("summaries/raw-hello-agents.summary.txt");
1237
1238    fn raw_only_packet() -> Packet {
1239        Packet::new().push(Raw::from("Hello, agents!"))
1240    }
1241
1242    fn raw_only_snapshot() -> String {
1243        let packet = raw_only_packet();
1244
1245        format!(
1246            "summary:\n{}\n\nshow:\n{}\n\nhexdump:\n{}\n\nraw_string_lossy_debug:\n{:?}\n",
1247            packet.summary(),
1248            packet.show(),
1249            packet.hexdump().unwrap(),
1250            packet.raw_string_lossy().unwrap()
1251        )
1252    }
1253
1254    #[test]
1255    fn formatting_raw_only_packet_matches_summary_fixture() {
1256        assert_eq!(raw_only_snapshot(), RAW_ONLY_SUMMARY);
1257    }
1258
1259    #[test]
1260    fn formatting_empty_packet_is_stable() {
1261        let packet = Packet::new();
1262
1263        assert_eq!(packet.summary(), "Packet(empty)");
1264        assert_eq!(packet.show(), "Packet(empty)");
1265        assert_eq!(packet.hexdump().unwrap(), "");
1266        assert_eq!(packet.raw_string_lossy().unwrap(), "");
1267    }
1268
1269    #[test]
1270    fn formatting_raw_layer_helpers_are_stable() {
1271        let raw = Raw::from([0x48, 0x69, 0xff, 0x00].as_slice());
1272
1273        assert_eq!(raw.summary(), "Raw(len=4)");
1274        assert_eq!(raw.hexdump(), "0000: 48 69 ff 00");
1275        assert_eq!(raw.raw_string_lossy(), "Hi\u{fffd}\0");
1276        assert_eq!(
1277            raw.inspection_fields(),
1278            vec![
1279                ("len", "4".to_string()),
1280                ("bytes", "48 69 ff 00".to_string()),
1281                ("text_lossy", "\"Hi\\u{fffd}\\0\"".to_string()),
1282            ]
1283        );
1284    }
1285
1286    #[test]
1287    fn formatting_hexdump_chunks_sixteen_bytes_per_line() {
1288        let bytes: Vec<u8> = (0x00..=0x11).collect();
1289
1290        assert_eq!(
1291            hexdump(&bytes),
1292            "0000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n0010: 10 11"
1293        );
1294    }
1295}