Skip to main content

zlayer_overlay/
config.rs

1//! Overlay network configuration
2
3#[cfg(feature = "nat")]
4use crate::nat::NatConfig;
5use serde::{Deserialize, Serialize};
6use std::net::{IpAddr, Ipv4Addr, SocketAddr};
7use std::time::Duration;
8
9/// Overlay network configuration
10#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
11pub struct OverlayConfig {
12    /// Local overlay endpoint (`WireGuard` protocol)
13    pub local_endpoint: SocketAddr,
14
15    /// Private key (x25519)
16    pub private_key: String,
17
18    /// Public key (derived from private key)
19    #[serde(default = "OverlayConfig::default_public_key")]
20    pub public_key: String,
21
22    /// Overlay network CIDR (supports both IPv4 e.g. "10.0.0.0/8" and IPv6 e.g. "`fd00::/48`")
23    #[serde(default = "OverlayConfig::default_cidr")]
24    pub overlay_cidr: String,
25
26    /// Peer discovery interval
27    #[serde(default = "OverlayConfig::default_discovery")]
28    pub peer_discovery_interval: Duration,
29
30    /// NAT traversal configuration (requires "nat" feature)
31    #[cfg(feature = "nat")]
32    #[serde(default)]
33    pub nat: NatConfig,
34}
35
36impl OverlayConfig {
37    fn default_public_key() -> String {
38        String::new()
39    }
40
41    fn default_cidr() -> String {
42        "10.0.0.0/8".to_string()
43    }
44
45    fn default_discovery() -> Duration {
46        Duration::from_secs(30)
47    }
48}
49
50impl Default for OverlayConfig {
51    fn default() -> Self {
52        Self {
53            local_endpoint: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 51820),
54            private_key: String::new(),
55            public_key: String::new(),
56            overlay_cidr: "10.0.0.0/8".to_string(),
57            peer_discovery_interval: Duration::from_secs(30),
58            #[cfg(feature = "nat")]
59            nat: NatConfig::default(),
60        }
61    }
62}
63
64/// Peer information
65#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
66pub struct PeerInfo {
67    /// Peer public key
68    pub public_key: String,
69
70    /// Endpoint address
71    pub endpoint: SocketAddr,
72
73    /// Allowed IPs
74    pub allowed_ips: String,
75
76    /// Persistent keepalive interval
77    pub persistent_keepalive_interval: Duration,
78}
79
80impl PeerInfo {
81    /// Create a new peer info
82    #[must_use]
83    pub fn new(
84        public_key: String,
85        endpoint: SocketAddr,
86        allowed_ips: &str,
87        persistent_keepalive_interval: Duration,
88    ) -> Self {
89        Self {
90            public_key,
91            endpoint,
92            allowed_ips: allowed_ips.to_string(),
93            persistent_keepalive_interval,
94        }
95    }
96
97    /// Create a peer config block (`WireGuard` protocol format)
98    #[must_use]
99    pub fn to_peer_config(&self) -> String {
100        format!(
101            "[Peer]\n\
102             PublicKey = {}\n\
103             Endpoint = {}\n\
104             AllowedIPs = {}\n\
105             PersistentKeepalive = {}\n",
106            self.public_key,
107            self.endpoint,
108            self.allowed_ips,
109            self.persistent_keepalive_interval.as_secs()
110        )
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn test_peer_info_to_peer_config() {
120        let peer = PeerInfo::new(
121            "public_key_here".to_string(),
122            SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 51820),
123            "10.0.0.2/32",
124            Duration::from_secs(25),
125        );
126
127        let config = peer.to_peer_config();
128        assert!(config.contains("PublicKey = public_key_here"));
129        assert!(config.contains("Endpoint = 192.168.1.1:51820"));
130    }
131
132    #[test]
133    fn test_overlay_config_default() {
134        let config = OverlayConfig::default();
135        assert_eq!(config.local_endpoint.port(), 51820);
136        assert_eq!(config.overlay_cidr, "10.0.0.0/8");
137    }
138
139    #[test]
140    fn test_peer_info_to_peer_config_v6() {
141        use std::net::Ipv6Addr;
142
143        let peer = PeerInfo::new(
144            "public_key_here".to_string(),
145            SocketAddr::new(IpAddr::V6(Ipv6Addr::LOCALHOST), 51820),
146            "fd00::2/128",
147            Duration::from_secs(25),
148        );
149
150        let config = peer.to_peer_config();
151        assert!(config.contains("PublicKey = public_key_here"));
152        assert!(config.contains("Endpoint = [::1]:51820"));
153        assert!(config.contains("AllowedIPs = fd00::2/128"));
154    }
155
156    #[test]
157    fn test_overlay_config_accepts_ipv6_cidr() {
158        let config = OverlayConfig {
159            overlay_cidr: "fd00:200::/48".to_string(),
160            ..OverlayConfig::default()
161        };
162        assert_eq!(config.overlay_cidr, "fd00:200::/48");
163    }
164}