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