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 flow;
55pub mod layer;
56pub mod packet;
57pub mod pcap;
58pub mod utils;
59
60// Re-export commonly used types at the crate root
61pub use error::{PacketError, Result};
62pub use layer::arp::{ARP_FIXED_HEADER_LEN, ARP_HEADER_LEN, ArpRoute, HardwareAddr, ProtocolAddr};
63pub use layer::bindings::{
64    BindingRegistry, apply_binding, expected_upper_layers, find_binding, find_bindings_from,
65    find_bindings_to, infer_upper_layer,
66};
67pub use layer::ethernet::{
68    DOT3_MAX_LENGTH, ETHERNET_HEADER_LEN, EthernetFrameType, dispatch_hook, is_dot3, is_ethernet_ii,
69};
70pub use layer::neighbor::{
71    ArpCache, CacheEntry, NdpCache, ipv4_multicast_mac, ipv6_multicast_mac, is_ipv4_multicast,
72    is_ipv6_multicast, solicited_node_multicast,
73};
74pub use layer::quic::builder::QuicBuilder;
75pub use layer::{
76    // Builders
77    ArpBuilder,
78    // Layer types
79    ArpLayer,
80    // Field types
81    BytesField,
82    DnsLayer,
83    Dot3Builder,
84    Dot3Layer,
85    EthernetBuilder,
86    EthernetLayer,
87    Field,
88    FieldDesc,
89    FieldError,
90    FieldType,
91    FieldValue,
92    Http2Builder,
93    Http2FrameBuilder,
94    HttpRequestBuilder,
95    HttpResponseBuilder,
96    ICMPV6_MIN_HEADER_LEN,
97    IPV6_HEADER_LEN,
98    IcmpBuilder,
99    IcmpLayer,
100    Icmpv6Builder,
101    Icmpv6Layer,
102    // Stacking
103    IntoLayerStackEntry,
104    Ipv4Builder,
105    Ipv4Flags,
106    Ipv4Layer,
107    Ipv6Builder,
108    Ipv6Layer,
109    L2TP_FIELD_NAMES,
110    L2TP_MIN_HEADER_LEN,
111    L2TP_PORT,
112    L2tpBuilder,
113    L2tpLayer,
114    LAYER_BINDINGS,
115    // Core traits and enums
116    Layer,
117    // Bindings
118    LayerBinding,
119    LayerEnum,
120    LayerIndex,
121    LayerKind,
122    LayerStack,
123    LayerStackEntry,
124    MacAddress,
125    // Neighbor resolution
126    NeighborCache,
127    NeighborResolver,
128    RAW_FIELDS,
129    RawBuilder,
130    RawLayer,
131    SSH_BINARY_HEADER_LEN,
132    SSH_PORT,
133    SshBuilder,
134    SshLayer,
135    TcpBuilder,
136    TcpFlags,
137    TcpLayer,
138    TlsRecordBuilder,
139    UdpBuilder,
140    UdpLayer,
141    icmpv6_checksum,
142    verify_icmpv6_checksum,
143};
144pub use packet::Packet;
145pub use pcap::{
146    CapturedPacket, LinkType, PcapIterator, PcapMetadata, rdpcap, wrpcap, wrpcap_packets,
147};
148
149// Flow extraction re-exports
150pub use flow::{
151    CanonicalKey, ConversationState, ConversationStatus, ConversationTable, DirectionStats,
152    FlowConfig, FlowDirection, FlowError, ProtocolState, TransportProtocol, extract_flows,
153    extract_flows_with_config,
154};
155
156// Utils re-exports
157pub use utils::{
158    align_to, ethernet_min_frame, extract_bits, hexdump, hexstr, hexstr_sep, internet_checksum,
159    pad_to, parse_hex, set_bits, transport_checksum, verify_checksum,
160};
161
162/// Protocol constants for EtherType field.
163pub mod ethertype {
164    pub use crate::layer::ethertype::*;
165}
166
167/// Protocol constants for IP protocol numbers.
168pub mod ip_protocol {
169    pub use crate::layer::ip_protocol::*;
170}
171
172/// ARP operation codes.
173pub mod arp_opcode {
174    pub use crate::layer::arp::opcode::*;
175}
176
177/// ARP hardware types.
178pub mod arp_hardware {
179    pub use crate::layer::arp::hardware_type::*;
180}
181
182/// ARP protocol types.
183pub mod arp_protocol {
184    pub use crate::layer::arp::protocol_type::*;
185}
186
187/// Prelude module for convenient imports.
188pub mod prelude {
189    pub use crate::arp_hardware;
190    pub use crate::arp_opcode;
191    pub use crate::ethertype;
192    pub use crate::{
193        ARP_HEADER_LEN,
194        ArpBuilder,
195        ArpCache,
196        // ARP
197        ArpLayer,
198        BindingRegistry,
199        BytesField,
200        Dot3Builder,
201        Dot3Layer,
202        ETHERNET_HEADER_LEN,
203        EthernetBuilder,
204        // Ethernet
205        EthernetLayer,
206        Field,
207        FieldDesc,
208        FieldError,
209        FieldType,
210        FieldValue,
211        HardwareAddr,
212        // Stacking
213        IntoLayerStackEntry,
214        Ipv4Builder,
215        Ipv4Flags,
216        Layer,
217        // Bindings
218        LayerBinding,
219        LayerEnum,
220        LayerIndex,
221        LayerKind,
222        LayerStack,
223        LayerStackEntry,
224        // Fields
225        MacAddress,
226        NdpCache,
227        // Neighbor
228        NeighborCache,
229        // Core types
230        Packet,
231        PacketError,
232        ProtocolAddr,
233        // Raw
234        RawBuilder,
235        RawLayer,
236        Result,
237        TcpBuilder,
238        TcpFlags,
239        apply_binding,
240        find_binding,
241        ipv4_multicast_mac,
242        ipv6_multicast_mac,
243        is_dot3,
244        is_ethernet_ii,
245    };
246    pub use std::net::{Ipv4Addr, Ipv6Addr};
247}
248
249/// Version information
250pub const VERSION: &str = env!("CARGO_PKG_VERSION");
251
252/// Get library version
253pub fn version() -> &'static str {
254    VERSION
255}
256
257#[cfg(test)]
258mod tests {
259    use super::prelude::*;
260
261    #[test]
262    fn test_basic_packet_creation() {
263        // Build Ethernet header
264        let eth = EthernetBuilder::new()
265            .dst(MacAddress::BROADCAST)
266            .src(MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]))
267            .build_with_payload(LayerKind::Arp);
268
269        // Build ARP payload
270        let arp = ArpBuilder::who_has(Ipv4Addr::new(192, 168, 1, 100))
271            .hwsrc(MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]))
272            .psrc(Ipv4Addr::new(192, 168, 1, 1))
273            .build();
274
275        // Combine
276        let mut packet_data = eth;
277        packet_data.extend_from_slice(&arp);
278
279        // Parse and verify
280        let mut packet = Packet::from_bytes(packet_data);
281        packet.parse().unwrap();
282
283        assert_eq!(packet.layer_count(), 2);
284
285        let eth_layer = packet.ethernet().unwrap();
286        assert_eq!(
287            eth_layer.ethertype(packet.as_bytes()).unwrap(),
288            ethertype::ARP
289        );
290
291        let arp_layer = packet.arp().unwrap();
292        assert!(arp_layer.is_request(packet.as_bytes()));
293    }
294
295    #[test]
296    fn test_layer_bindings() {
297        // Test that bindings are correctly defined
298        let binding = find_binding(LayerKind::Ethernet, LayerKind::Arp);
299        assert!(binding.is_some());
300        assert_eq!(binding.unwrap().field_value, 0x0806);
301
302        // Test apply_binding helper
303        let (field, value) = apply_binding(LayerKind::Ethernet, LayerKind::Ipv4).unwrap();
304        assert_eq!(field, "type");
305        assert_eq!(value, 0x0800);
306    }
307
308    #[test]
309    fn test_neighbor_resolution() {
310        let _cache = NeighborCache::new();
311
312        // Test multicast resolution
313        let mcast_ip = Ipv4Addr::new(224, 0, 0, 1);
314        let mcast_mac = ipv4_multicast_mac(mcast_ip);
315        assert!(mcast_mac.is_multicast());
316        assert!(mcast_mac.is_ipv4_multicast());
317    }
318
319    #[test]
320    fn test_frame_type_dispatch() {
321        // Ethernet II frame (type > 1500)
322        let eth2 = vec![
323            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x08,
324            0x00, // IPv4 = 0x0800
325        ];
326        assert!(!is_dot3(&eth2, 0));
327        assert!(is_ethernet_ii(&eth2, 0));
328
329        // 802.3 frame (length <= 1500)
330        let dot3 = vec![
331            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x00,
332            0x64, // Length = 100
333        ];
334        assert!(is_dot3(&dot3, 0));
335        assert!(!is_ethernet_ii(&dot3, 0));
336    }
337}