1use ipnet::{IpNet, Ipv4Net, Ipv6Net};
4use serde::{Deserialize, Serialize};
5use std::collections::HashSet;
6use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
7
8use crate::{CoreError, Result};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub struct VpnAddress {
13 pub ipv4: Option<Ipv4Addr>,
15 pub ipv6: Option<Ipv6Addr>,
17}
18
19impl VpnAddress {
20 pub fn v4(addr: Ipv4Addr) -> Self {
22 Self {
23 ipv4: Some(addr),
24 ipv6: None,
25 }
26 }
27
28 pub fn v6(addr: Ipv6Addr) -> Self {
30 Self {
31 ipv4: None,
32 ipv6: Some(addr),
33 }
34 }
35
36 pub fn dual(ipv4: Ipv4Addr, ipv6: Ipv6Addr) -> Self {
38 Self {
39 ipv4: Some(ipv4),
40 ipv6: Some(ipv6),
41 }
42 }
43
44 pub fn primary(&self) -> Option<IpAddr> {
46 self.ipv4
47 .map(IpAddr::V4)
48 .or_else(|| self.ipv6.map(IpAddr::V6))
49 }
50}
51
52#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
54pub struct Route {
55 pub network: IpNet,
57 pub gateway: Option<IpAddr>,
59 pub metric: u32,
61}
62
63impl Route {
64 pub fn new(network: IpNet) -> Self {
66 Self {
67 network,
68 gateway: None,
69 metric: 0,
70 }
71 }
72
73 pub fn default_v4() -> Self {
75 Self {
76 network: "0.0.0.0/0".parse().unwrap(),
77 gateway: None,
78 metric: 0,
79 }
80 }
81
82 pub fn default_v6() -> Self {
84 Self {
85 network: "::/0".parse().unwrap(),
86 gateway: None,
87 metric: 0,
88 }
89 }
90
91 pub fn with_gateway(mut self, gateway: IpAddr) -> Self {
93 self.gateway = Some(gateway);
94 self
95 }
96
97 pub fn with_metric(mut self, metric: u32) -> Self {
99 self.metric = metric;
100 self
101 }
102}
103
104pub struct AddressPool {
106 ipv4_net: Option<Ipv4Net>,
108 ipv6_net: Option<Ipv6Net>,
110 allocated_v4: parking_lot::RwLock<HashSet<Ipv4Addr>>,
112 allocated_v6: parking_lot::RwLock<HashSet<Ipv6Addr>>,
114 reserved_v4: HashSet<Ipv4Addr>,
116 reserved_v6: HashSet<Ipv6Addr>,
118}
119
120impl AddressPool {
121 pub fn new(ipv4_net: Option<Ipv4Net>, ipv6_net: Option<Ipv6Net>) -> Self {
127 let mut reserved_v4 = HashSet::new();
128 let mut reserved_v6 = HashSet::new();
129
130 if let Some(net) = &ipv4_net {
132 reserved_v4.insert(net.network());
133 reserved_v4.insert(net.broadcast());
134 let gateway = Ipv4Addr::from(u32::from(net.network()) + 1);
136 reserved_v4.insert(gateway);
137 }
138
139 if let Some(net) = &ipv6_net {
141 let gateway = Ipv6Addr::from(u128::from(net.network()) + 1);
142 reserved_v6.insert(gateway);
143 }
144
145 Self {
146 ipv4_net,
147 ipv6_net,
148 allocated_v4: parking_lot::RwLock::new(HashSet::new()),
149 allocated_v6: parking_lot::RwLock::new(HashSet::new()),
150 reserved_v4,
151 reserved_v6,
152 }
153 }
154
155 pub fn gateway_v4(&self) -> Option<Ipv4Addr> {
157 self.ipv4_net.map(|net| {
158 Ipv4Addr::from(u32::from(net.network()) + 1)
159 })
160 }
161
162 pub fn gateway_v6(&self) -> Option<Ipv6Addr> {
164 self.ipv6_net.map(|net| {
165 Ipv6Addr::from(u128::from(net.network()) + 1)
166 })
167 }
168
169 pub fn allocate(&self) -> Result<VpnAddress> {
171 let ipv4 = if let Some(net) = &self.ipv4_net {
172 Some(self.allocate_v4(net)?)
173 } else {
174 None
175 };
176
177 let ipv6 = if let Some(net) = &self.ipv6_net {
178 Some(self.allocate_v6(net)?)
179 } else {
180 None
181 };
182
183 if ipv4.is_none() && ipv6.is_none() {
184 return Err(CoreError::ConfigError("No address pools configured".into()));
185 }
186
187 Ok(VpnAddress { ipv4, ipv6 })
188 }
189
190 fn allocate_v4(&self, net: &Ipv4Net) -> Result<Ipv4Addr> {
191 let mut allocated = self.allocated_v4.write();
192
193 let start = u32::from(net.network()) + 2;
195 let end = u32::from(net.broadcast());
196
197 for addr_u32 in start..end {
198 let addr = Ipv4Addr::from(addr_u32);
199 if !self.reserved_v4.contains(&addr) && !allocated.contains(&addr) {
200 allocated.insert(addr);
201 return Ok(addr);
202 }
203 }
204
205 Err(CoreError::AddressPoolExhausted)
206 }
207
208 fn allocate_v6(&self, net: &Ipv6Net) -> Result<Ipv6Addr> {
209 let mut allocated = self.allocated_v6.write();
210
211 let start = u128::from(net.network()) + 2;
213 let end = start + 65534;
215
216 for addr_u128 in start..end {
217 let addr = Ipv6Addr::from(addr_u128);
218 if !self.reserved_v6.contains(&addr) && !allocated.contains(&addr) {
219 allocated.insert(addr);
220 return Ok(addr);
221 }
222 }
223
224 Err(CoreError::AddressPoolExhausted)
225 }
226
227 pub fn allocate_specific(&self, addr: VpnAddress) -> Result<VpnAddress> {
229 if let Some(v4) = addr.ipv4 {
230 let mut allocated = self.allocated_v4.write();
231 if let Some(net) = &self.ipv4_net {
232 if !net.contains(&v4) {
233 return Err(CoreError::InvalidAddress(format!(
234 "{} not in pool {}",
235 v4, net
236 )));
237 }
238 }
239 if self.reserved_v4.contains(&v4) || allocated.contains(&v4) {
240 return Err(CoreError::InvalidAddress(format!(
241 "{} is reserved or already allocated",
242 v4
243 )));
244 }
245 allocated.insert(v4);
246 }
247
248 if let Some(v6) = addr.ipv6 {
249 let mut allocated = self.allocated_v6.write();
250 if let Some(net) = &self.ipv6_net {
251 if !net.contains(&v6) {
252 return Err(CoreError::InvalidAddress(format!(
253 "{} not in pool {}",
254 v6, net
255 )));
256 }
257 }
258 if self.reserved_v6.contains(&v6) || allocated.contains(&v6) {
259 return Err(CoreError::InvalidAddress(format!(
260 "{} is reserved or already allocated",
261 v6
262 )));
263 }
264 allocated.insert(v6);
265 }
266
267 Ok(addr)
268 }
269
270 pub fn release(&self, addr: &VpnAddress) {
272 if let Some(v4) = addr.ipv4 {
273 self.allocated_v4.write().remove(&v4);
274 }
275 if let Some(v6) = addr.ipv6 {
276 self.allocated_v6.write().remove(&v6);
277 }
278 }
279
280 pub fn available_v4(&self) -> usize {
282 if let Some(net) = &self.ipv4_net {
283 let total = net.hosts().count();
284 let reserved = self.reserved_v4.len();
285 let allocated = self.allocated_v4.read().len();
286 total.saturating_sub(reserved).saturating_sub(allocated)
287 } else {
288 0
289 }
290 }
291
292 pub fn available_v6(&self) -> usize {
294 if self.ipv6_net.is_some() {
295 let allocated = self.allocated_v6.read().len();
297 65534usize.saturating_sub(allocated)
298 } else {
299 0
300 }
301 }
302
303 pub fn stats(&self) -> PoolStats {
305 PoolStats {
306 ipv4_total: self.ipv4_net.map(|n| n.hosts().count()).unwrap_or(0),
307 ipv4_allocated: self.allocated_v4.read().len(),
308 ipv4_available: self.available_v4(),
309 ipv6_allocated: self.allocated_v6.read().len(),
310 ipv6_available: self.available_v6(),
311 }
312 }
313}
314
315#[derive(Debug, Clone, Serialize, Deserialize)]
317pub struct PoolStats {
318 pub ipv4_total: usize,
320 pub ipv4_allocated: usize,
322 pub ipv4_available: usize,
324 pub ipv6_allocated: usize,
326 pub ipv6_available: usize,
328}
329
330#[derive(Debug, Clone, Serialize, Deserialize)]
332pub struct DnsConfig {
333 pub servers: Vec<IpAddr>,
335 pub search_domains: Vec<String>,
337}
338
339impl Default for DnsConfig {
340 fn default() -> Self {
341 Self {
342 servers: vec![
343 "1.1.1.1".parse().unwrap(), "1.0.0.1".parse().unwrap(),
345 ],
346 search_domains: vec![],
347 }
348 }
349}
350
351#[cfg(test)]
352mod tests {
353 use super::*;
354
355 #[test]
356 fn test_address_pool() {
357 let pool = AddressPool::new(
358 Some("10.8.0.0/24".parse().unwrap()),
359 None,
360 );
361
362 let addr1 = pool.allocate().unwrap();
364 assert_eq!(addr1.ipv4, Some("10.8.0.2".parse().unwrap()));
365
366 let addr2 = pool.allocate().unwrap();
368 assert_eq!(addr2.ipv4, Some("10.8.0.3".parse().unwrap()));
369
370 pool.release(&addr1);
372
373 let addr3 = pool.allocate().unwrap();
375 assert_eq!(addr3.ipv4, Some("10.8.0.2".parse().unwrap()));
376 }
377
378 #[test]
379 fn test_gateway_address() {
380 let pool = AddressPool::new(
381 Some("10.8.0.0/24".parse().unwrap()),
382 Some("fd00::/64".parse().unwrap()),
383 );
384
385 assert_eq!(pool.gateway_v4(), Some("10.8.0.1".parse().unwrap()));
386 assert_eq!(pool.gateway_v6(), Some("fd00::1".parse().unwrap()));
387 }
388
389 #[test]
390 fn test_route() {
391 let route = Route::new("192.168.1.0/24".parse().unwrap())
392 .with_gateway("10.8.0.1".parse().unwrap())
393 .with_metric(100);
394
395 assert_eq!(route.metric, 100);
396 assert_eq!(route.gateway, Some("10.8.0.1".parse().unwrap()));
397 }
398}