Skip to main content

stackforge_core/
lib.rs

1//! # Stackforge Core
2//!
3//! High-performance, zero-copy network packet manipulation library.
4//!
5//! This crate provides the core networking primitives for the Stackforge
6//! framework, implementing a "Lazy Zero-Copy View" architecture for efficient
7//! packet processing.
8//!
9//! ## Architecture
10//!
11//! Unlike traditional packet parsing libraries that eagerly deserialize all
12//! fields into objects, Stackforge Core uses a lazy evaluation model:
13//!
14//! 1. **Zero-Copy Buffers**: Packets are stored as contiguous byte buffers
15//!    using the `bytes` crate's reference-counted `Bytes` type.
16//!
17//! 2. **Index-Only Parsing**: When parsing a packet, we only identify layer
18//!    boundaries (where each protocol header starts and ends).
19//!
20//! 3. **On-Demand Access**: Field values are read directly from the buffer
21//!    only when explicitly requested.
22//!
23//! 4. **Copy-on-Write**: Mutation triggers buffer cloning only when shared.
24//!
25//! ## Example
26//!
27//! ```rust
28//! use stackforge_core::{Packet, LayerKind, EthernetLayer, ArpBuilder};
29//! use stackforge_core::layer::field::MacAddress;
30//! use std::net::Ipv4Addr;
31//!
32//! // Build an ARP request
33//! let arp = ArpBuilder::who_has(Ipv4Addr::new(192, 168, 1, 100))
34//!     .hwsrc(MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]))
35//!     .psrc(Ipv4Addr::new(192, 168, 1, 1))
36//!     .build();
37//!
38//! // Parse an existing packet
39//! let raw_bytes = vec![
40//!     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  // Destination MAC (broadcast)
41//!     0x00, 0x11, 0x22, 0x33, 0x44, 0x55,  // Source MAC
42//!     0x08, 0x06,                          // EtherType: ARP
43//! ];
44//!
45//! let eth = EthernetLayer::at_start();
46//! assert_eq!(eth.ethertype(&raw_bytes).unwrap(), 0x0806);
47//! ```
48
49#![warn(clippy::all)]
50#![warn(clippy::pedantic)]
51#![allow(clippy::module_name_repetitions)]
52
53pub mod error;
54pub mod layer;
55pub mod packet;
56pub mod pcap;
57pub mod utils;
58
59// Re-export commonly used types at the crate root
60pub use error::{PacketError, Result};
61pub use layer::arp::{ARP_FIXED_HEADER_LEN, ARP_HEADER_LEN, ArpRoute, HardwareAddr, ProtocolAddr};
62pub use layer::bindings::{
63    BindingRegistry, apply_binding, expected_upper_layers, find_binding, find_bindings_from,
64    find_bindings_to, infer_upper_layer,
65};
66pub use layer::ethernet::{
67    DOT3_MAX_LENGTH, ETHERNET_HEADER_LEN, EthernetFrameType, dispatch_hook, is_dot3, is_ethernet_ii,
68};
69pub use layer::neighbor::{
70    ArpCache, CacheEntry, NdpCache, ipv4_multicast_mac, ipv6_multicast_mac, is_ipv4_multicast,
71    is_ipv6_multicast, solicited_node_multicast,
72};
73pub use layer::quic::builder::QuicBuilder;
74pub use layer::{
75    // Builders
76    ArpBuilder,
77    // Layer types
78    ArpLayer,
79    // Field types
80    BytesField,
81    DnsLayer,
82    Dot3Builder,
83    Dot3Layer,
84    EthernetBuilder,
85    EthernetLayer,
86    Field,
87    FieldDesc,
88    FieldError,
89    FieldType,
90    FieldValue,
91    Http2Builder,
92    Http2FrameBuilder,
93    HttpRequestBuilder,
94    HttpResponseBuilder,
95    ICMPV6_MIN_HEADER_LEN,
96    IPV6_HEADER_LEN,
97    IcmpBuilder,
98    IcmpLayer,
99    Icmpv6Builder,
100    Icmpv6Layer,
101    // Stacking
102    IntoLayerStackEntry,
103    Ipv4Builder,
104    Ipv4Flags,
105    Ipv4Layer,
106    Ipv6Builder,
107    Ipv6Layer,
108    L2TP_FIELD_NAMES,
109    L2TP_MIN_HEADER_LEN,
110    L2TP_PORT,
111    L2tpBuilder,
112    L2tpLayer,
113    LAYER_BINDINGS,
114    // Core traits and enums
115    Layer,
116    // Bindings
117    LayerBinding,
118    LayerEnum,
119    LayerIndex,
120    LayerKind,
121    LayerStack,
122    LayerStackEntry,
123    MacAddress,
124    // Neighbor resolution
125    NeighborCache,
126    NeighborResolver,
127    RAW_FIELDS,
128    RawBuilder,
129    RawLayer,
130    SSH_BINARY_HEADER_LEN,
131    SSH_PORT,
132    SshBuilder,
133    SshLayer,
134    TcpBuilder,
135    TcpFlags,
136    TcpLayer,
137    TlsRecordBuilder,
138    UdpBuilder,
139    UdpLayer,
140    icmpv6_checksum,
141    verify_icmpv6_checksum,
142};
143pub use packet::Packet;
144pub use pcap::{
145    CapturedPacket, LinkType, PcapIterator, PcapMetadata, rdpcap, wrpcap, wrpcap_packets,
146};
147
148// Utils re-exports
149pub use utils::{
150    align_to, ethernet_min_frame, extract_bits, hexdump, hexstr, hexstr_sep, internet_checksum,
151    pad_to, parse_hex, set_bits, transport_checksum, verify_checksum,
152};
153
154/// Protocol constants for EtherType field.
155pub mod ethertype {
156    pub use crate::layer::ethertype::*;
157}
158
159/// Protocol constants for IP protocol numbers.
160pub mod ip_protocol {
161    pub use crate::layer::ip_protocol::*;
162}
163
164/// ARP operation codes.
165pub mod arp_opcode {
166    pub use crate::layer::arp::opcode::*;
167}
168
169/// ARP hardware types.
170pub mod arp_hardware {
171    pub use crate::layer::arp::hardware_type::*;
172}
173
174/// ARP protocol types.
175pub mod arp_protocol {
176    pub use crate::layer::arp::protocol_type::*;
177}
178
179/// Prelude module for convenient imports.
180pub mod prelude {
181    pub use crate::arp_hardware;
182    pub use crate::arp_opcode;
183    pub use crate::ethertype;
184    pub use crate::{
185        ARP_HEADER_LEN,
186        ArpBuilder,
187        ArpCache,
188        // ARP
189        ArpLayer,
190        BindingRegistry,
191        BytesField,
192        Dot3Builder,
193        Dot3Layer,
194        ETHERNET_HEADER_LEN,
195        EthernetBuilder,
196        // Ethernet
197        EthernetLayer,
198        Field,
199        FieldDesc,
200        FieldError,
201        FieldType,
202        FieldValue,
203        HardwareAddr,
204        // Stacking
205        IntoLayerStackEntry,
206        Ipv4Builder,
207        Ipv4Flags,
208        Layer,
209        // Bindings
210        LayerBinding,
211        LayerEnum,
212        LayerIndex,
213        LayerKind,
214        LayerStack,
215        LayerStackEntry,
216        // Fields
217        MacAddress,
218        NdpCache,
219        // Neighbor
220        NeighborCache,
221        // Core types
222        Packet,
223        PacketError,
224        ProtocolAddr,
225        // Raw
226        RawBuilder,
227        RawLayer,
228        Result,
229        TcpBuilder,
230        TcpFlags,
231        apply_binding,
232        find_binding,
233        ipv4_multicast_mac,
234        ipv6_multicast_mac,
235        is_dot3,
236        is_ethernet_ii,
237    };
238    pub use std::net::{Ipv4Addr, Ipv6Addr};
239}
240
241/// Version information
242pub const VERSION: &str = env!("CARGO_PKG_VERSION");
243
244/// Get library version
245pub fn version() -> &'static str {
246    VERSION
247}
248
249#[cfg(test)]
250mod tests {
251    use super::prelude::*;
252
253    #[test]
254    fn test_basic_packet_creation() {
255        // Build Ethernet header
256        let eth = EthernetBuilder::new()
257            .dst(MacAddress::BROADCAST)
258            .src(MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]))
259            .build_with_payload(LayerKind::Arp);
260
261        // Build ARP payload
262        let arp = ArpBuilder::who_has(Ipv4Addr::new(192, 168, 1, 100))
263            .hwsrc(MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]))
264            .psrc(Ipv4Addr::new(192, 168, 1, 1))
265            .build();
266
267        // Combine
268        let mut packet_data = eth;
269        packet_data.extend_from_slice(&arp);
270
271        // Parse and verify
272        let mut packet = Packet::from_bytes(packet_data);
273        packet.parse().unwrap();
274
275        assert_eq!(packet.layer_count(), 2);
276
277        let eth_layer = packet.ethernet().unwrap();
278        assert_eq!(
279            eth_layer.ethertype(packet.as_bytes()).unwrap(),
280            ethertype::ARP
281        );
282
283        let arp_layer = packet.arp().unwrap();
284        assert!(arp_layer.is_request(packet.as_bytes()));
285    }
286
287    #[test]
288    fn test_layer_bindings() {
289        // Test that bindings are correctly defined
290        let binding = find_binding(LayerKind::Ethernet, LayerKind::Arp);
291        assert!(binding.is_some());
292        assert_eq!(binding.unwrap().field_value, 0x0806);
293
294        // Test apply_binding helper
295        let (field, value) = apply_binding(LayerKind::Ethernet, LayerKind::Ipv4).unwrap();
296        assert_eq!(field, "type");
297        assert_eq!(value, 0x0800);
298    }
299
300    #[test]
301    fn test_neighbor_resolution() {
302        let _cache = NeighborCache::new();
303
304        // Test multicast resolution
305        let mcast_ip = Ipv4Addr::new(224, 0, 0, 1);
306        let mcast_mac = ipv4_multicast_mac(mcast_ip);
307        assert!(mcast_mac.is_multicast());
308        assert!(mcast_mac.is_ipv4_multicast());
309    }
310
311    #[test]
312    fn test_frame_type_dispatch() {
313        // Ethernet II frame (type > 1500)
314        let eth2 = vec![
315            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x08,
316            0x00, // IPv4 = 0x0800
317        ];
318        assert!(!is_dot3(&eth2, 0));
319        assert!(is_ethernet_ii(&eth2, 0));
320
321        // 802.3 frame (length <= 1500)
322        let dot3 = vec![
323            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x00,
324            0x64, // Length = 100
325        ];
326        assert!(is_dot3(&dot3, 0));
327        assert!(!is_ethernet_ii(&dot3, 0));
328    }
329}