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    CaptureFormat, CaptureIterator, CapturedPacket, LinkType, PcapIterator, PcapMetadata,
164    PcapNgIterator, PcapNgStreamWriter, rdpcap, wrpcap, wrpcap_packets, wrpcapng, wrpcapng_packets,
165};
166
167// Flow extraction re-exports
168pub use flow::{
169    CanonicalKey, ConversationState, ConversationStatus, ConversationTable, DirectionStats,
170    FlowConfig, FlowDirection, FlowError, ProtocolState, TransportProtocol, ZWaveFlowState,
171    ZWaveKey, extract_flows, extract_flows_from_file, extract_flows_streaming,
172    extract_flows_with_config, extract_zwave_flows,
173};
174
175// Utils re-exports
176pub use utils::{
177    align_to, ethernet_min_frame, extract_bits, hexdump, hexstr, hexstr_sep, internet_checksum,
178    pad_to, parse_hex, set_bits, transport_checksum, verify_checksum,
179};
180
181/// Protocol constants for `EtherType` field.
182pub mod ethertype {
183    pub use crate::layer::ethertype::*;
184}
185
186/// Protocol constants for IP protocol numbers.
187pub mod ip_protocol {
188    pub use crate::layer::ip_protocol::*;
189}
190
191/// ARP operation codes.
192pub mod arp_opcode {
193    pub use crate::layer::arp::opcode::*;
194}
195
196/// ARP hardware types.
197pub mod arp_hardware {
198    pub use crate::layer::arp::hardware_type::*;
199}
200
201/// ARP protocol types.
202pub mod arp_protocol {
203    pub use crate::layer::arp::protocol_type::*;
204}
205
206/// Prelude module for convenient imports.
207pub mod prelude {
208    pub use crate::arp_hardware;
209    pub use crate::arp_opcode;
210    pub use crate::ethertype;
211    pub use crate::{
212        ARP_HEADER_LEN,
213        ArpBuilder,
214        ArpCache,
215        // ARP
216        ArpLayer,
217        BindingRegistry,
218        BytesField,
219        Dot3Builder,
220        Dot3Layer,
221        ETHERNET_HEADER_LEN,
222        EthernetBuilder,
223        // Ethernet
224        EthernetLayer,
225        Field,
226        FieldDesc,
227        FieldError,
228        FieldType,
229        FieldValue,
230        HardwareAddr,
231        // Stacking
232        IntoLayerStackEntry,
233        Ipv4Builder,
234        Ipv4Flags,
235        Layer,
236        // Bindings
237        LayerBinding,
238        LayerEnum,
239        LayerIndex,
240        LayerKind,
241        LayerStack,
242        LayerStackEntry,
243        // Fields
244        MacAddress,
245        NdpCache,
246        // Neighbor
247        NeighborCache,
248        // Core types
249        Packet,
250        PacketError,
251        ProtocolAddr,
252        // Raw
253        RawBuilder,
254        RawLayer,
255        Result,
256        TcpBuilder,
257        TcpFlags,
258        apply_binding,
259        find_binding,
260        ipv4_multicast_mac,
261        ipv6_multicast_mac,
262        is_dot3,
263        is_ethernet_ii,
264    };
265    pub use std::net::{Ipv4Addr, Ipv6Addr};
266}
267
268/// Version information
269pub const VERSION: &str = env!("CARGO_PKG_VERSION");
270
271/// Get library version
272#[must_use]
273pub fn version() -> &'static str {
274    VERSION
275}
276
277#[cfg(test)]
278mod tests {
279    use super::prelude::*;
280
281    #[test]
282    fn test_basic_packet_creation() {
283        // Build Ethernet header
284        let eth = EthernetBuilder::new()
285            .dst(MacAddress::BROADCAST)
286            .src(MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]))
287            .build_with_payload(LayerKind::Arp);
288
289        // Build ARP payload
290        let arp = ArpBuilder::who_has(Ipv4Addr::new(192, 168, 1, 100))
291            .hwsrc(MacAddress::new([0x00, 0x11, 0x22, 0x33, 0x44, 0x55]))
292            .psrc(Ipv4Addr::new(192, 168, 1, 1))
293            .build();
294
295        // Combine
296        let mut packet_data = eth;
297        packet_data.extend_from_slice(&arp);
298
299        // Parse and verify
300        let mut packet = Packet::from_bytes(packet_data);
301        packet.parse().unwrap();
302
303        assert_eq!(packet.layer_count(), 2);
304
305        let eth_layer = packet.ethernet().unwrap();
306        assert_eq!(
307            eth_layer.ethertype(packet.as_bytes()).unwrap(),
308            ethertype::ARP
309        );
310
311        let arp_layer = packet.arp().unwrap();
312        assert!(arp_layer.is_request(packet.as_bytes()));
313    }
314
315    #[test]
316    fn test_layer_bindings() {
317        // Test that bindings are correctly defined
318        let binding = find_binding(LayerKind::Ethernet, LayerKind::Arp);
319        assert!(binding.is_some());
320        assert_eq!(binding.unwrap().field_value, 0x0806);
321
322        // Test apply_binding helper
323        let (field, value) = apply_binding(LayerKind::Ethernet, LayerKind::Ipv4).unwrap();
324        assert_eq!(field, "type");
325        assert_eq!(value, 0x0800);
326    }
327
328    #[test]
329    fn test_neighbor_resolution() {
330        let _cache = NeighborCache::new();
331
332        // Test multicast resolution
333        let mcast_ip = Ipv4Addr::new(224, 0, 0, 1);
334        let mcast_mac = ipv4_multicast_mac(mcast_ip);
335        assert!(mcast_mac.is_multicast());
336        assert!(mcast_mac.is_ipv4_multicast());
337    }
338
339    #[test]
340    fn test_frame_type_dispatch() {
341        // Ethernet II frame (type > 1500)
342        let eth2 = vec![
343            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x08,
344            0x00, // IPv4 = 0x0800
345        ];
346        assert!(!is_dot3(&eth2, 0));
347        assert!(is_ethernet_ii(&eth2, 0));
348
349        // 802.3 frame (length <= 1500)
350        let dot3 = vec![
351            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x00,
352            0x64, // Length = 100
353        ];
354        assert!(is_dot3(&dot3, 0));
355        assert!(!is_ethernet_ii(&dot3, 0));
356    }
357}