veilid_tools/network_interfaces/
mod.rs1mod tools;
2
3use crate::*;
4use serde::*;
5
6cfg_if::cfg_if! {
7 if #[cfg(any(target_os = "linux", target_os = "android"))] {
8 mod netlink;
9 use self::netlink::PlatformSupportNetlink as PlatformSupport;
10 } else if #[cfg(target_os = "windows")] {
11 mod windows;
12 mod sockaddr_tools;
13 use self::windows::PlatformSupportWindows as PlatformSupport;
14 } else if #[cfg(any(target_os = "macos", target_os = "ios"))] {
15 mod apple;
16 mod sockaddr_tools;
17 use self::apple::PlatformSupportApple as PlatformSupport;
18 } else if #[cfg(target_os = "openbsd")] {
19 mod openbsd;
20 mod sockaddr_tools;
21 use self::openbsd::PlatformSupportOpenBSD as PlatformSupport;
22 } else if #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] {
23 mod wasm;
24 use self::wasm::PlatformSupportWasm as PlatformSupport;
25 } else {
26 compile_error!("No network interfaces support for this platform!");
27 }
28}
29
30#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Serialize, Deserialize)]
31pub enum IfAddr {
32 V4(Ifv4Addr),
33 V6(Ifv6Addr),
34}
35
36impl IfAddr {
37 pub fn ip(&self) -> IpAddr {
38 match *self {
39 IfAddr::V4(ref ifv4_addr) => IpAddr::V4(ifv4_addr.ip),
40 IfAddr::V6(ref ifv6_addr) => IpAddr::V6(ifv6_addr.ip),
41 }
42 }
43 pub fn netmask(&self) -> IpAddr {
44 match *self {
45 IfAddr::V4(ref ifv4_addr) => IpAddr::V4(ifv4_addr.netmask),
46 IfAddr::V6(ref ifv6_addr) => IpAddr::V6(ifv6_addr.netmask),
47 }
48 }
49 pub fn broadcast(&self) -> Option<IpAddr> {
50 match *self {
51 IfAddr::V4(ref ifv4_addr) => ifv4_addr.broadcast.map(IpAddr::V4),
52 IfAddr::V6(ref ifv6_addr) => ifv6_addr.broadcast.map(IpAddr::V6),
53 }
54 }
55}
56
57#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Serialize, Deserialize)]
59pub struct Ifv4Addr {
60 pub ip: Ipv4Addr,
62 pub netmask: Ipv4Addr,
64 pub broadcast: Option<Ipv4Addr>,
66}
67
68#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Serialize, Deserialize)]
70pub struct Ifv6Addr {
71 pub ip: Ipv6Addr,
73 pub netmask: Ipv6Addr,
75 pub broadcast: Option<Ipv6Addr>,
77}
78
79#[derive(
81 Debug, Default, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy, Serialize, Deserialize,
82)]
83pub struct InterfaceFlags {
84 pub is_loopback: bool,
85 pub is_running: bool,
86 pub is_point_to_point: bool,
87 pub has_default_route: bool,
88}
89
90#[derive(
92 Debug, Default, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy, Serialize, Deserialize,
93)]
94pub struct AddressFlags {
95 pub is_dynamic: bool,
97 pub is_temporary: bool,
99 pub is_preferred: bool,
100}
101
102#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
103pub struct InterfaceAddress {
104 pub if_addr: IfAddr,
105 pub flags: AddressFlags,
106}
107
108use core::cmp::Ordering;
109
110impl Ord for InterfaceAddress {
112 fn cmp(&self, other: &Self) -> Ordering {
113 match (&self.if_addr, &other.if_addr) {
114 (IfAddr::V4(a), IfAddr::V4(b)) => {
115 let ret = ipv4addr_is_global(&a.ip).cmp(&ipv4addr_is_global(&b.ip));
117 if ret != Ordering::Equal {
118 return ret;
119 }
120 let ret = ipv4addr_is_private(&a.ip).cmp(&ipv4addr_is_private(&b.ip));
122 if ret != Ordering::Equal {
123 return ret;
124 }
125 let ret = (!self.flags.is_dynamic).cmp(&!other.flags.is_dynamic);
127 if ret != Ordering::Equal {
128 return ret;
129 }
130 }
131 (IfAddr::V6(a), IfAddr::V6(b)) => {
132 let ret = self.flags.is_preferred.cmp(&other.flags.is_preferred);
134 if ret != Ordering::Equal {
135 return ret;
136 }
137 let ret = (!self.flags.is_temporary).cmp(&!other.flags.is_temporary);
139 if ret != Ordering::Equal {
140 return ret;
141 }
142 let ret = ipv6addr_is_global(&a.ip).cmp(&ipv6addr_is_global(&b.ip));
144 if ret != Ordering::Equal {
145 return ret;
146 }
147 let ret = ipv6addr_is_unique_local(&a.ip).cmp(&ipv6addr_is_unique_local(&b.ip));
149 if ret != Ordering::Equal {
150 return ret;
151 }
152 let ret = ipv6addr_is_unicast_site_local(&a.ip)
154 .cmp(&ipv6addr_is_unicast_site_local(&b.ip));
155 if ret != Ordering::Equal {
156 return ret;
157 }
158 let ret = ipv6addr_is_unicast_link_local(&a.ip)
160 .cmp(&ipv6addr_is_unicast_link_local(&b.ip));
161 if ret != Ordering::Equal {
162 return ret;
163 }
164 let ret = (!self.flags.is_dynamic).cmp(&!other.flags.is_dynamic);
166 if ret != Ordering::Equal {
167 return ret;
168 }
169 }
170 (IfAddr::V4(a), IfAddr::V6(b)) => {
171 if other.flags.is_preferred && !other.flags.is_temporary {
173 let ret = ipv4addr_is_global(&a.ip).cmp(&ipv6addr_is_global(&b.ip));
174 if ret != Ordering::Equal {
175 return ret;
176 }
177 }
178
179 return Ordering::Greater;
181 }
182 (IfAddr::V6(a), IfAddr::V4(b)) => {
183 if self.flags.is_preferred && !self.flags.is_temporary {
185 let ret = ipv6addr_is_global(&a.ip).cmp(&ipv4addr_is_global(&b.ip));
186 if ret != Ordering::Equal {
187 return ret;
188 }
189 }
190
191 return Ordering::Less;
193 }
194 }
195 let ret = self.if_addr.cmp(&other.if_addr);
197 if ret != Ordering::Equal {
198 return ret;
199 }
200 self.flags.cmp(&other.flags)
201 }
202}
203impl PartialOrd for InterfaceAddress {
204 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
205 Some(self.cmp(other))
206 }
207}
208
209impl InterfaceAddress {
210 pub fn new(if_addr: IfAddr, flags: AddressFlags) -> Self {
211 Self { if_addr, flags }
212 }
213
214 pub fn if_addr(&self) -> &IfAddr {
215 &self.if_addr
216 }
217
218 pub fn is_temporary(&self) -> bool {
219 self.flags.is_temporary
220 }
221 pub fn is_dynamic(&self) -> bool {
222 self.flags.is_dynamic
223 }
224 pub fn is_preferred(&self) -> bool {
225 self.flags.is_preferred
226 }
227}
228
229#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
238pub struct NetworkInterface {
239 pub name: String,
240 pub flags: InterfaceFlags,
241 pub addrs: Vec<InterfaceAddress>,
242}
243
244impl fmt::Debug for NetworkInterface {
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 f.debug_struct("NetworkInterface")
247 .field("name", &self.name)
248 .field("flags", &self.flags)
249 .field("addrs", &self.addrs)
250 .finish()?;
251 if f.alternate() {
252 writeln!(f)?;
253 writeln!(f, "// primary_ipv4: {:?}", self.primary_ipv4())?;
254 writeln!(f, "// primary_ipv6: {:?}", self.primary_ipv6())?;
255 }
256 Ok(())
257 }
258}
259impl NetworkInterface {
260 pub fn new(name: String, flags: InterfaceFlags) -> Self {
261 Self {
262 name,
263 flags,
264 addrs: Vec::new(),
265 }
266 }
267 pub fn name(&self) -> String {
268 self.name.clone()
269 }
270 pub fn is_loopback(&self) -> bool {
271 self.flags.is_loopback
272 }
273
274 pub fn is_point_to_point(&self) -> bool {
275 self.flags.is_point_to_point
276 }
277
278 pub fn is_running(&self) -> bool {
279 self.flags.is_running
280 }
281
282 pub fn has_default_route(&self) -> bool {
283 self.flags.has_default_route
284 }
285
286 pub fn primary_ipv4(&self) -> Option<InterfaceAddress> {
287 let mut ipv4addrs: Vec<&InterfaceAddress> = self
288 .addrs
289 .iter()
290 .filter(|a| matches!(a.if_addr(), IfAddr::V4(_)))
291 .collect();
292 ipv4addrs.sort();
293 ipv4addrs.last().cloned().cloned()
294 }
295
296 pub fn primary_ipv6(&self) -> Option<InterfaceAddress> {
297 let mut ipv6addrs: Vec<&InterfaceAddress> = self
298 .addrs
299 .iter()
300 .filter(|a| matches!(a.if_addr(), IfAddr::V6(_)))
301 .collect();
302 ipv6addrs.sort();
303 ipv6addrs.last().cloned().cloned()
304 }
305}
306
307pub struct NetworkInterfacesInner {
308 valid: bool,
309 interfaces: BTreeMap<String, NetworkInterface>,
310 interface_address_cache: Vec<IpAddr>,
311}
312
313#[derive(Clone)]
314pub struct NetworkInterfaces {
315 inner: Arc<Mutex<NetworkInterfacesInner>>,
316}
317
318impl fmt::Debug for NetworkInterfaces {
319 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
320 let inner = self.inner.lock();
321 f.debug_struct("NetworkInterfaces")
322 .field("valid", &inner.valid)
323 .field("interfaces", &inner.interfaces)
324 .finish()?;
325 if f.alternate() {
326 writeln!(f)?;
327 writeln!(
328 f,
329 "// stable_addresses: {:?}",
330 inner.interface_address_cache
331 )?;
332 }
333 Ok(())
334 }
335}
336
337impl Default for NetworkInterfaces {
338 fn default() -> Self {
339 Self::new()
340 }
341}
342
343impl NetworkInterfaces {
344 pub fn new() -> Self {
345 Self {
346 inner: Arc::new(Mutex::new(NetworkInterfacesInner {
347 valid: false,
348 interfaces: BTreeMap::new(),
349 interface_address_cache: Vec::new(),
350 })),
351 }
352 }
353
354 pub fn is_valid(&self) -> bool {
355 let inner = self.inner.lock();
356 inner.valid
357 }
358 pub fn clear(&self) {
359 let mut inner = self.inner.lock();
360
361 inner.interfaces.clear();
362 inner.interface_address_cache.clear();
363 inner.valid = false;
364 }
365 pub async fn refresh(&self) -> std::io::Result<bool> {
367 let mut last_interfaces = {
368 let mut last_interfaces = BTreeMap::<String, NetworkInterface>::new();
369 let mut platform_support = PlatformSupport::new();
370 platform_support
371 .get_interfaces(&mut last_interfaces)
372 .await?;
373 last_interfaces
374 };
375
376 let mut inner = self.inner.lock();
377 core::mem::swap(&mut inner.interfaces, &mut last_interfaces);
378 inner.valid = true;
379
380 if last_interfaces != inner.interfaces {
381 let old_stable_addresses = inner.interface_address_cache.clone();
383
384 Self::cache_stable_addresses(&mut inner);
386
387 if old_stable_addresses != inner.interface_address_cache {
389 return Ok(true);
390 }
391 }
392 Ok(false)
393 }
394 pub fn with_interfaces<F, R>(&self, f: F) -> R
395 where
396 F: FnOnce(&BTreeMap<String, NetworkInterface>) -> R,
397 {
398 let inner = self.inner.lock();
399 f(&inner.interfaces)
400 }
401
402 pub fn stable_addresses(&self) -> Vec<IpAddr> {
403 let inner = self.inner.lock();
404 inner.interface_address_cache.clone()
405 }
406
407 fn cache_stable_addresses(inner: &mut NetworkInterfacesInner) {
410 let mut intf_addrs = Vec::new();
412 for intf in inner.interfaces.values() {
413 if !intf.is_running() || !intf.has_default_route() || intf.is_loopback()
414 {
416 continue;
417 }
418 if let Some(pipv4) = intf.primary_ipv4() {
419 if !pipv4.is_temporary() {
421 intf_addrs.push(pipv4);
422 }
423 }
424 if let Some(pipv6) = intf.primary_ipv6() {
425 if !pipv6.is_temporary() {
427 intf_addrs.push(pipv6);
428 }
429 }
430 }
431
432 let mut addresses = intf_addrs
434 .iter()
435 .map(|x| x.if_addr().ip())
436 .collect::<Vec<_>>();
437
438 addresses.sort();
439 addresses.dedup();
440
441 inner.interface_address_cache = addresses;
443 }
444}