Skip to main content

netget/protocol/
binding_defaults.rs

1//! Protocol binding defaults
2//!
3//! Provides a flexible system for protocols to specify default binding parameters.
4//! Each protocol can define defaults for MAC address, network interface, host, and port.
5
6/// Default binding parameters for a protocol
7///
8/// Protocols can return `Some(BindingDefaults)` from `default_binding()` to opt into
9/// the flexible binding system. Protocols that return `None` use the legacy listen_addr system.
10///
11/// User-provided values override protocol defaults.
12#[derive(Debug, Clone)]
13pub struct BindingDefaults {
14    /// MAC address for Layer 2 protocols (e.g., ARP spoofing with specific MAC)
15    pub mac_address: Option<String>,
16
17    /// Network interface for raw protocols (e.g., "lo", "eth0", "en0")
18    pub interface: Option<String>,
19
20    /// Host address (IPv4, IPv6, or hostname) for socket-based protocols
21    /// Examples: "127.0.0.1", "0.0.0.0", "::", "localhost"
22    pub host: Option<String>,
23
24    /// Port number for socket-based protocols
25    /// Use Some(0) for automatic port assignment
26    pub port: Option<u16>,
27}
28
29impl BindingDefaults {
30    /// Create binding defaults for port-based protocols (TCP, UDP, HTTP, DNS, etc.)
31    ///
32    /// # Arguments
33    /// * `default_host` - Host to bind (e.g., "127.0.0.1", "0.0.0.0")
34    /// * `default_port` - Port to bind (use 0 for automatic assignment)
35    ///
36    /// # Example
37    /// ```ignore
38    /// // TCP: bind to loopback by default, auto-assign port
39    /// BindingDefaults::port_based("127.0.0.1", 0)
40    /// ```
41    pub fn port_based(default_host: &str, default_port: u16) -> Self {
42        Self {
43            mac_address: None,
44            interface: None,
45            host: Some(default_host.to_string()),
46            port: Some(default_port),
47        }
48    }
49
50    /// Create binding defaults for interface-based protocols (ICMP, ARP, DataLink, etc.)
51    ///
52    /// # Arguments
53    /// * `default_interface` - Interface to bind (e.g., "lo", "eth0")
54    ///
55    /// # Example
56    /// ```ignore
57    /// // ICMP: bind to loopback interface by default
58    /// BindingDefaults::interface_based("lo")
59    /// ```
60    pub fn interface_based(default_interface: &str) -> Self {
61        Self {
62            mac_address: None,
63            interface: Some(default_interface.to_string()),
64            host: None,
65            port: None,
66        }
67    }
68
69    /// Apply user-provided values, falling back to protocol defaults
70    ///
71    /// User values take precedence over defaults. Returns the final binding
72    /// configuration with all fields resolved.
73    ///
74    /// # Arguments
75    /// * `user_mac` - User-provided MAC address (overrides default)
76    /// * `user_interface` - User-provided interface (overrides default)
77    /// * `user_host` - User-provided host (overrides default)
78    /// * `user_port` - User-provided port (overrides default)
79    ///
80    /// # Returns
81    /// Tuple of (final_mac, final_interface, final_host, final_port)
82    pub fn apply(
83        &self,
84        user_mac: Option<String>,
85        user_interface: Option<String>,
86        user_host: Option<String>,
87        user_port: Option<u16>,
88    ) -> (Option<String>, Option<String>, Option<String>, Option<u16>) {
89        (
90            user_mac.or_else(|| self.mac_address.clone()),
91            user_interface.or_else(|| self.interface.clone()),
92            user_host.or_else(|| self.host.clone()),
93            user_port.or(self.port),
94        )
95    }
96}