Skip to main content

stackforge_core/layer/
bindings.rs

1//! Layer binding system for automatic field setting when stacking layers.
2//!
3//! For example, when stacking `Ether() / ARP()`, the Ethernet type field
4//! should automatically be set to 0x0806 (ARP).
5
6use crate::layer::{LayerKind, ethertype, ip_protocol};
7
8/// Describes a binding between two layers.
9///
10/// When the upper layer is placed on top of the lower layer,
11/// the specified field of the lower layer should be set to the given value.
12#[derive(Debug, Clone, Copy)]
13pub struct LayerBinding {
14    /// The layer being placed on top
15    pub upper: LayerKind,
16    /// The layer below
17    pub lower: LayerKind,
18    /// The field name in the lower layer to set
19    pub field_name: &'static str,
20    /// The value to set (as u16 for simplicity; can be cast)
21    pub field_value: u16,
22}
23
24impl LayerBinding {
25    pub const fn new(
26        lower: LayerKind,
27        upper: LayerKind,
28        field_name: &'static str,
29        field_value: u16,
30    ) -> Self {
31        Self {
32            upper,
33            lower,
34            field_name,
35            field_value,
36        }
37    }
38}
39
40/// Static table of layer bindings.
41///
42/// Format: (lower_layer, upper_layer, field_name, field_value)
43pub static LAYER_BINDINGS: &[LayerBinding] = &[
44    // Ethernet -> *
45    LayerBinding::new(LayerKind::Ethernet, LayerKind::Arp, "type", ethertype::ARP),
46    LayerBinding::new(
47        LayerKind::Ethernet,
48        LayerKind::Ipv4,
49        "type",
50        ethertype::IPV4,
51    ),
52    LayerBinding::new(
53        LayerKind::Ethernet,
54        LayerKind::Ipv6,
55        "type",
56        ethertype::IPV6,
57    ),
58    LayerBinding::new(
59        LayerKind::Ethernet,
60        LayerKind::Dot1Q,
61        "type",
62        ethertype::VLAN,
63    ),
64    LayerBinding::new(
65        LayerKind::Ethernet,
66        LayerKind::Dot1AD,
67        "type",
68        ethertype::DOT1AD,
69    ),
70    LayerBinding::new(
71        LayerKind::Ethernet,
72        LayerKind::Dot1AH,
73        "type",
74        ethertype::DOT1AH,
75    ),
76    LayerBinding::new(LayerKind::Ethernet, LayerKind::LLC, "type", 122), // LLC over Ethernet
77    // Dot3 -> LLC
78    LayerBinding::new(LayerKind::Dot3, LayerKind::LLC, "len", 0), // Auto-calculated
79    // Dot1Q -> *
80    LayerBinding::new(LayerKind::Dot1Q, LayerKind::Arp, "type", ethertype::ARP),
81    LayerBinding::new(LayerKind::Dot1Q, LayerKind::Ipv4, "type", ethertype::IPV4),
82    LayerBinding::new(LayerKind::Dot1Q, LayerKind::Ipv6, "type", ethertype::IPV6),
83    LayerBinding::new(LayerKind::Dot1Q, LayerKind::Dot1Q, "type", ethertype::VLAN),
84    LayerBinding::new(
85        LayerKind::Dot1Q,
86        LayerKind::Dot1AD,
87        "type",
88        ethertype::DOT1AD,
89    ),
90    LayerBinding::new(
91        LayerKind::Dot1Q,
92        LayerKind::Dot1AH,
93        "type",
94        ethertype::DOT1AH,
95    ),
96    // Dot1AD -> *
97    LayerBinding::new(
98        LayerKind::Dot1AD,
99        LayerKind::Dot1AD,
100        "type",
101        ethertype::DOT1AD,
102    ),
103    LayerBinding::new(LayerKind::Dot1AD, LayerKind::Dot1Q, "type", ethertype::VLAN),
104    LayerBinding::new(
105        LayerKind::Dot1AD,
106        LayerKind::Dot1AH,
107        "type",
108        ethertype::DOT1AH,
109    ),
110    // IPv4 -> *
111    LayerBinding::new(
112        LayerKind::Ipv4,
113        LayerKind::Tcp,
114        "proto",
115        ip_protocol::TCP as u16,
116    ),
117    LayerBinding::new(
118        LayerKind::Ipv4,
119        LayerKind::Udp,
120        "proto",
121        ip_protocol::UDP as u16,
122    ),
123    LayerBinding::new(
124        LayerKind::Ipv4,
125        LayerKind::Icmp,
126        "proto",
127        ip_protocol::ICMP as u16,
128    ),
129    // TCP -> * (port-based, dport field)
130    LayerBinding::new(LayerKind::Tcp, LayerKind::Tls, "dport", 443),
131    LayerBinding::new(LayerKind::Tcp, LayerKind::Dns, "dport", 53),
132    LayerBinding::new(LayerKind::Tcp, LayerKind::Http, "dport", 80),
133    LayerBinding::new(LayerKind::Tcp, LayerKind::Http, "dport", 8080),
134    LayerBinding::new(LayerKind::Tcp, LayerKind::Http, "dport", 8000),
135    LayerBinding::new(LayerKind::Tcp, LayerKind::Http, "dport", 8008),
136    LayerBinding::new(LayerKind::Tcp, LayerKind::Http, "dport", 8888),
137    // UDP -> * (port-based, dport field)
138    LayerBinding::new(LayerKind::Udp, LayerKind::Dns, "dport", 53),
139    LayerBinding::new(LayerKind::Udp, LayerKind::Quic, "dport", 443),
140    LayerBinding::new(LayerKind::Udp, LayerKind::Quic, "dport", 4433),
141    LayerBinding::new(LayerKind::Udp, LayerKind::L2tp, "dport", 1701),
142    // IPv6 -> *
143    LayerBinding::new(
144        LayerKind::Ipv6,
145        LayerKind::Tcp,
146        "nh",
147        ip_protocol::TCP as u16,
148    ),
149    LayerBinding::new(
150        LayerKind::Ipv6,
151        LayerKind::Udp,
152        "nh",
153        ip_protocol::UDP as u16,
154    ),
155    LayerBinding::new(
156        LayerKind::Ipv6,
157        LayerKind::Icmpv6,
158        "nh",
159        ip_protocol::ICMPV6 as u16,
160    ),
161];
162
163/// Find the binding for a given layer pair.
164pub fn find_binding(lower: LayerKind, upper: LayerKind) -> Option<&'static LayerBinding> {
165    LAYER_BINDINGS
166        .iter()
167        .find(|b| b.lower == lower && b.upper == upper)
168}
169
170/// Find all bindings where the given layer is the lower layer.
171pub fn find_bindings_from(lower: LayerKind) -> impl Iterator<Item = &'static LayerBinding> {
172    LAYER_BINDINGS.iter().filter(move |b| b.lower == lower)
173}
174
175/// Find all bindings where the given layer is the upper layer.
176pub fn find_bindings_to(upper: LayerKind) -> impl Iterator<Item = &'static LayerBinding> {
177    LAYER_BINDINGS.iter().filter(move |b| b.upper == upper)
178}
179
180/// Determine the upper layer kind based on field value.
181///
182/// For example, if lower=Ethernet and field_name="type" and value=0x0806,
183/// returns Some(LayerKind::Arp).
184pub fn infer_upper_layer(lower: LayerKind, field_name: &str, value: u16) -> Option<LayerKind> {
185    LAYER_BINDINGS
186        .iter()
187        .find(|b| b.lower == lower && b.field_name == field_name && b.field_value == value)
188        .map(|b| b.upper)
189}
190
191/// Get the expected upper layer kinds for a given lower layer.
192pub fn expected_upper_layers(lower: LayerKind) -> Vec<LayerKind> {
193    find_bindings_from(lower).map(|b| b.upper).collect()
194}
195
196/// Registry for custom bindings (runtime-defined).
197#[derive(Debug, Clone, Default)]
198pub struct BindingRegistry {
199    bindings: Vec<LayerBinding>,
200}
201
202impl BindingRegistry {
203    pub fn new() -> Self {
204        Self::default()
205    }
206
207    /// Create a registry pre-populated with static bindings.
208    pub fn with_defaults() -> Self {
209        Self {
210            bindings: LAYER_BINDINGS.to_vec(),
211        }
212    }
213
214    /// Register a new binding.
215    pub fn register(
216        &mut self,
217        lower: LayerKind,
218        upper: LayerKind,
219        field_name: &'static str,
220        field_value: u16,
221    ) {
222        // Remove any existing binding for this pair
223        self.bindings
224            .retain(|b| !(b.lower == lower && b.upper == upper));
225        self.bindings
226            .push(LayerBinding::new(lower, upper, field_name, field_value));
227    }
228
229    /// Find a binding in this registry.
230    pub fn find(&self, lower: LayerKind, upper: LayerKind) -> Option<&LayerBinding> {
231        self.bindings
232            .iter()
233            .find(|b| b.lower == lower && b.upper == upper)
234    }
235
236    /// Find all bindings from a lower layer.
237    pub fn find_from(&self, lower: LayerKind) -> impl Iterator<Item = &LayerBinding> {
238        self.bindings.iter().filter(move |b| b.lower == lower)
239    }
240
241    /// Infer upper layer from field value.
242    pub fn infer_upper(&self, lower: LayerKind, field_name: &str, value: u16) -> Option<LayerKind> {
243        self.bindings
244            .iter()
245            .find(|b| b.lower == lower && b.field_name == field_name && b.field_value == value)
246            .map(|b| b.upper)
247    }
248}
249
250/// Apply binding to set the appropriate field when stacking layers.
251///
252/// Returns the field name and value that should be set, if a binding exists.
253pub fn apply_binding(lower: LayerKind, upper: LayerKind) -> Option<(&'static str, u16)> {
254    find_binding(lower, upper).map(|b| (b.field_name, b.field_value))
255}
256
257#[cfg(test)]
258mod tests {
259    use super::*;
260
261    #[test]
262    fn test_find_binding() {
263        let binding = find_binding(LayerKind::Ethernet, LayerKind::Arp);
264        assert!(binding.is_some());
265        let b = binding.unwrap();
266        assert_eq!(b.field_name, "type");
267        assert_eq!(b.field_value, 0x0806);
268    }
269
270    #[test]
271    fn test_find_bindings_from() {
272        let bindings: Vec<_> = find_bindings_from(LayerKind::Ethernet).collect();
273        assert!(bindings.len() >= 3); // At least ARP, IPv4, IPv6
274    }
275
276    #[test]
277    fn test_infer_upper_layer() {
278        assert_eq!(
279            infer_upper_layer(LayerKind::Ethernet, "type", 0x0800),
280            Some(LayerKind::Ipv4)
281        );
282        assert_eq!(
283            infer_upper_layer(LayerKind::Ethernet, "type", 0x0806),
284            Some(LayerKind::Arp)
285        );
286        assert_eq!(
287            infer_upper_layer(LayerKind::Ipv4, "proto", 6),
288            Some(LayerKind::Tcp)
289        );
290    }
291
292    #[test]
293    fn test_apply_binding() {
294        let result = apply_binding(LayerKind::Ethernet, LayerKind::Ipv6);
295        assert_eq!(result, Some(("type", 0x86DD)));
296    }
297
298    #[test]
299    fn test_binding_registry() {
300        let mut registry = BindingRegistry::with_defaults();
301
302        // Add a custom binding
303        registry.register(LayerKind::Ethernet, LayerKind::Raw, "type", 0x1234);
304
305        let binding = registry.find(LayerKind::Ethernet, LayerKind::Raw);
306        assert!(binding.is_some());
307        assert_eq!(binding.unwrap().field_value, 0x1234);
308    }
309
310    #[test]
311    fn test_expected_upper_layers() {
312        let uppers = expected_upper_layers(LayerKind::Ethernet);
313        assert!(uppers.contains(&LayerKind::Arp));
314        assert!(uppers.contains(&LayerKind::Ipv4));
315        assert!(uppers.contains(&LayerKind::Ipv6));
316    }
317}