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