1use std::net::Ipv4Addr;
2
3use serde::{Deserialize, Serialize};
4
5use crate::error::{Error, Result};
6
7pub const DEFAULT_VPN_MTU: u16 = 1346;
8pub const LEGACY_VPN_PREFIX_LEN: u8 = 24;
9pub const LEGACY_SERVER_VPN_IP: Ipv4Addr = Ipv4Addr::new(10, 0, 0, 1);
10
11fn default_server_vpn_ip() -> Ipv4Addr {
12 LEGACY_SERVER_VPN_IP
13}
14
15fn default_prefix_len() -> u8 {
16 LEGACY_VPN_PREFIX_LEN
17}
18
19fn default_mtu() -> u16 {
20 DEFAULT_VPN_MTU
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
24pub struct VpnNetworkConfig {
25 #[serde(default = "default_server_vpn_ip")]
26 pub server_vpn_ip: Ipv4Addr,
27 #[serde(default = "default_prefix_len")]
28 pub prefix_len: u8,
29 #[serde(default = "default_mtu")]
30 pub mtu: u16,
31}
32
33impl Default for VpnNetworkConfig {
34 fn default() -> Self {
35 Self {
36 server_vpn_ip: default_server_vpn_ip(),
37 prefix_len: default_prefix_len(),
38 mtu: default_mtu(),
39 }
40 }
41}
42
43impl VpnNetworkConfig {
44 pub fn validate(&self) -> Result<()> {
45 if !(1..=30).contains(&self.prefix_len) {
46 return Err(Error::InvalidPacket(
47 "VPN prefix length must be in range 1..=30",
48 ));
49 }
50 if self.server_vpn_ip == self.network_addr() || self.server_vpn_ip == self.broadcast_addr()
51 {
52 return Err(Error::InvalidPacket(
53 "Server VPN IP must be a usable host address",
54 ));
55 }
56 Ok(())
57 }
58
59 pub fn netmask(&self) -> Ipv4Addr {
60 prefix_len_to_netmask(self.prefix_len)
61 }
62
63 pub fn network_addr(&self) -> Ipv4Addr {
64 Ipv4Addr::from(ipv4_to_u32(self.server_vpn_ip) & self.mask_u32())
65 }
66
67 pub fn broadcast_addr(&self) -> Ipv4Addr {
68 Ipv4Addr::from(self.network_u32() | !self.mask_u32())
69 }
70
71 pub fn contains(&self, ip: Ipv4Addr) -> bool {
72 (ipv4_to_u32(ip) & self.mask_u32()) == self.network_u32()
73 }
74
75 pub fn cidr_string(&self) -> String {
76 format!("{}/{}", self.network_addr(), self.prefix_len)
77 }
78
79 pub fn server_ip_string(&self) -> String {
80 self.server_vpn_ip.to_string()
81 }
82
83 pub fn netmask_string(&self) -> String {
84 self.netmask().to_string()
85 }
86
87 pub fn host_offset(&self, ip: Ipv4Addr) -> u32 {
88 ipv4_to_u32(ip) & !self.mask_u32()
89 }
90
91 pub fn max_host_offset(&self) -> u32 {
92 let host_mask = !self.mask_u32();
93 host_mask.saturating_sub(1)
94 }
95
96 pub fn is_usable_host(&self, ip: Ipv4Addr) -> bool {
97 self.contains(ip) && ip != self.network_addr() && ip != self.broadcast_addr()
98 }
99
100 pub fn ip_for_host_offset(&self, host_offset: u32) -> Option<Ipv4Addr> {
101 if host_offset == 0 || host_offset > self.max_host_offset() {
102 return None;
103 }
104 Some(Ipv4Addr::from(self.network_u32() | host_offset))
105 }
106
107 pub fn client_config(&self, client_ip: Ipv4Addr) -> Result<ClientNetworkConfig> {
108 if !self.is_usable_host(client_ip) {
109 return Err(Error::InvalidPacket(
110 "Client VPN IP is outside configured VPN subnet",
111 ));
112 }
113 if client_ip == self.server_vpn_ip {
114 return Err(Error::InvalidPacket(
115 "Client VPN IP cannot equal server VPN IP",
116 ));
117 }
118 Ok(ClientNetworkConfig {
119 client_ip,
120 server_vpn_ip: self.server_vpn_ip,
121 prefix_len: self.prefix_len,
122 mtu: self.mtu,
123 mdh_len: default_mdh_len(),
124 })
125 }
126
127 fn network_u32(&self) -> u32 {
128 ipv4_to_u32(self.server_vpn_ip) & self.mask_u32()
129 }
130
131 fn mask_u32(&self) -> u32 {
132 if self.prefix_len == 0 {
133 0
134 } else {
135 u32::MAX << (32 - self.prefix_len)
136 }
137 }
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
141pub struct ClientNetworkConfig {
142 pub client_ip: Ipv4Addr,
143 pub server_vpn_ip: Ipv4Addr,
144 pub prefix_len: u8,
145 #[serde(default = "default_mtu")]
146 pub mtu: u16,
147 #[serde(default = "default_mdh_len")]
151 pub mdh_len: u16,
152}
153
154fn default_mdh_len() -> u16 {
155 20
156}
157
158impl ClientNetworkConfig {
159 pub const WIRE_SIZE: usize = 12;
160 const WIRE_VERSION: u8 = 1;
161
162 pub fn validate(&self) -> Result<()> {
163 VpnNetworkConfig {
164 server_vpn_ip: self.server_vpn_ip,
165 prefix_len: self.prefix_len,
166 mtu: self.mtu,
167 }
168 .client_config(self.client_ip)
169 .map(|_| ())
170 }
171
172 pub fn netmask(&self) -> Ipv4Addr {
173 prefix_len_to_netmask(self.prefix_len)
174 }
175
176 pub fn cidr_string(&self) -> String {
177 format!("{}/{}", self.client_ip, self.prefix_len)
178 }
179
180 pub fn netmask_string(&self) -> String {
181 self.netmask().to_string()
182 }
183
184 pub fn encode_wire(&self) -> [u8; Self::WIRE_SIZE] {
185 let mut buf = [0u8; Self::WIRE_SIZE];
186 buf[0] = Self::WIRE_VERSION;
187 buf[1] = self.prefix_len;
188 buf[2..4].copy_from_slice(&self.mtu.to_le_bytes());
189 buf[4..8].copy_from_slice(&self.server_vpn_ip.octets());
190 buf[8..12].copy_from_slice(&self.client_ip.octets());
191 buf
192 }
193
194 pub fn decode_wire(data: &[u8]) -> Result<Self> {
195 if data.len() != Self::WIRE_SIZE {
196 return Err(Error::InvalidPacket(
197 "Client network config has invalid wire length",
198 ));
199 }
200 if data[0] != Self::WIRE_VERSION {
201 return Err(Error::InvalidPacket(
202 "Unsupported client network config wire version",
203 ));
204 }
205
206 let config = Self {
207 prefix_len: data[1],
208 mtu: u16::from_le_bytes([data[2], data[3]]),
209 server_vpn_ip: Ipv4Addr::new(data[4], data[5], data[6], data[7]),
210 client_ip: Ipv4Addr::new(data[8], data[9], data[10], data[11]),
211 mdh_len: default_mdh_len(),
212 };
213 config.validate()?;
214 Ok(config)
215 }
216}
217
218pub fn prefix_len_to_netmask(prefix_len: u8) -> Ipv4Addr {
219 if prefix_len == 0 {
220 return Ipv4Addr::new(0, 0, 0, 0);
221 }
222
223 Ipv4Addr::from(u32::MAX << (32 - prefix_len))
224}
225
226pub fn netmask_to_prefix_len(netmask: Ipv4Addr) -> Result<u8> {
227 let mask = ipv4_to_u32(netmask);
228 let prefix_len = mask.leading_ones() as u8;
229 let expected = if prefix_len == 0 {
230 0
231 } else {
232 u32::MAX << (32 - prefix_len)
233 };
234 if mask != expected {
235 return Err(Error::InvalidPacket("VPN netmask must be contiguous"));
236 }
237 Ok(prefix_len)
238}
239
240fn ipv4_to_u32(ip: Ipv4Addr) -> u32 {
241 u32::from(ip)
242}
243
244#[cfg(test)]
245mod tests {
246 use super::*;
247
248 #[test]
249 fn wire_roundtrip_preserves_client_network_config() {
250 let config = ClientNetworkConfig {
251 client_ip: Ipv4Addr::new(10, 150, 0, 2),
252 server_vpn_ip: Ipv4Addr::new(10, 150, 0, 1),
253 prefix_len: 24,
254 mtu: 1346,
255 mdh_len: 20,
256 };
257
258 let decoded = ClientNetworkConfig::decode_wire(&config.encode_wire()).unwrap();
259 assert_eq!(decoded, config);
260 }
261
262 #[test]
263 fn network_helpers_compute_addresses() {
264 let config = VpnNetworkConfig {
265 server_vpn_ip: Ipv4Addr::new(10, 150, 0, 1),
266 prefix_len: 24,
267 mtu: 1346,
268 };
269
270 assert_eq!(config.network_addr(), Ipv4Addr::new(10, 150, 0, 0));
271 assert_eq!(config.broadcast_addr(), Ipv4Addr::new(10, 150, 0, 255));
272 assert_eq!(config.netmask(), Ipv4Addr::new(255, 255, 255, 0));
273 assert!(config.is_usable_host(Ipv4Addr::new(10, 150, 0, 10)));
274 assert!(!config.is_usable_host(Ipv4Addr::new(10, 150, 0, 0)));
275 }
276}