Skip to main content

veilid_tools/network_interfaces/
mod.rs

1mod 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    #[must_use]
38    pub fn ip(&self) -> IpAddr {
39        match *self {
40            IfAddr::V4(ref ifv4_addr) => IpAddr::V4(ifv4_addr.ip),
41            IfAddr::V6(ref ifv6_addr) => IpAddr::V6(ifv6_addr.ip),
42        }
43    }
44    #[must_use]
45    pub fn netmask(&self) -> IpAddr {
46        match *self {
47            IfAddr::V4(ref ifv4_addr) => IpAddr::V4(ifv4_addr.netmask),
48            IfAddr::V6(ref ifv6_addr) => IpAddr::V6(ifv6_addr.netmask),
49        }
50    }
51    pub fn broadcast(&self) -> Option<IpAddr> {
52        match *self {
53            IfAddr::V4(ref ifv4_addr) => ifv4_addr.broadcast.map(IpAddr::V4),
54            IfAddr::V6(ref ifv6_addr) => ifv6_addr.broadcast.map(IpAddr::V6),
55        }
56    }
57
58    #[must_use]
59    pub fn network(&self) -> IfAddr {
60        match *self {
61            IfAddr::V4(ref ifv4_addr) => IfAddr::V4(ifv4_addr.network()),
62            IfAddr::V6(ref ifv6_addr) => IfAddr::V6(ifv6_addr.network()),
63        }
64    }
65
66    #[must_use]
67    pub fn contains_address(&self, addr: IpAddr) -> bool {
68        match *self {
69            IfAddr::V4(ref ifv4_addr) => match addr {
70                IpAddr::V4(ipv4_addr) => ifv4_addr.contains_address(ipv4_addr),
71                IpAddr::V6(_consensus_count) => false,
72            },
73            IfAddr::V6(ref ifv6_addr) => match addr {
74                IpAddr::V4(_) => false,
75                IpAddr::V6(ipv6_addr) => ifv6_addr.contains_address(ipv6_addr),
76            },
77        }
78    }
79}
80
81/// Details about the ipv4 address of an interface on this host.
82#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Serialize, Deserialize)]
83pub struct Ifv4Addr {
84    /// The IP address of the interface.
85    pub ip: Ipv4Addr,
86    /// The netmask of the interface.
87    pub netmask: Ipv4Addr,
88    /// The broadcast address of the interface.
89    pub broadcast: Option<Ipv4Addr>,
90}
91
92impl Ifv4Addr {
93    /// Convert ip address to the address of the network itself by applying the netmask
94    #[must_use]
95    pub fn network(&self) -> Ifv4Addr {
96        let v4 = self.ip.octets();
97        let v4mask = self.netmask.octets();
98        let ip = Ipv4Addr::new(
99            v4[0] & v4mask[0],
100            v4[1] & v4mask[1],
101            v4[2] & v4mask[2],
102            v4[3] & v4mask[3],
103        );
104        Ifv4Addr {
105            ip,
106            netmask: self.netmask,
107            broadcast: self.broadcast,
108        }
109    }
110
111    #[must_use]
112    pub fn contains_address(&self, addr: Ipv4Addr) -> bool {
113        let v4mask = self.netmask.octets();
114
115        let self_v4 = self.ip.octets();
116        let self_ip = Ipv4Addr::new(
117            self_v4[0] & v4mask[0],
118            self_v4[1] & v4mask[1],
119            self_v4[2] & v4mask[2],
120            self_v4[3] & v4mask[3],
121        );
122
123        let addr_v4 = addr.octets();
124        let addr_ip = Ipv4Addr::new(
125            addr_v4[0] & v4mask[0],
126            addr_v4[1] & v4mask[1],
127            addr_v4[2] & v4mask[2],
128            addr_v4[3] & v4mask[3],
129        );
130
131        self_ip == addr_ip
132    }
133}
134
135/// Details about the ipv6 address of an interface on this host.
136#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Serialize, Deserialize)]
137pub struct Ifv6Addr {
138    /// The IP address of the interface.
139    pub ip: Ipv6Addr,
140    /// The netmask of the interface.
141    pub netmask: Ipv6Addr,
142    /// The broadcast address of the interface.
143    pub broadcast: Option<Ipv6Addr>,
144}
145
146impl Ifv6Addr {
147    /// Convert ip address to the address of the network itself by applying the netmask
148    #[must_use]
149    pub fn network(&self) -> Ifv6Addr {
150        let v6 = self.ip.segments();
151        let v6mask = self.netmask.segments();
152        let ip = Ipv6Addr::new(
153            v6[0] & v6mask[0],
154            v6[1] & v6mask[1],
155            v6[2] & v6mask[2],
156            v6[3] & v6mask[3],
157            v6[4] & v6mask[4],
158            v6[5] & v6mask[5],
159            v6[6] & v6mask[6],
160            v6[7] & v6mask[7],
161        );
162        Ifv6Addr {
163            ip,
164            netmask: self.netmask,
165            broadcast: self.broadcast,
166        }
167    }
168
169    #[must_use]
170    pub fn contains_address(&self, addr: Ipv6Addr) -> bool {
171        let v6mask = self.netmask.segments();
172
173        let self_v6 = self.ip.segments();
174        let self_ip = Ipv6Addr::new(
175            self_v6[0] & v6mask[0],
176            self_v6[1] & v6mask[1],
177            self_v6[2] & v6mask[2],
178            self_v6[3] & v6mask[3],
179            self_v6[4] & v6mask[4],
180            self_v6[5] & v6mask[5],
181            self_v6[6] & v6mask[6],
182            self_v6[7] & v6mask[7],
183        );
184
185        let addr_v6 = addr.segments();
186        let addr_ip = Ipv6Addr::new(
187            addr_v6[0] & v6mask[0],
188            addr_v6[1] & v6mask[1],
189            addr_v6[2] & v6mask[2],
190            addr_v6[3] & v6mask[3],
191            addr_v6[4] & v6mask[4],
192            addr_v6[5] & v6mask[5],
193            addr_v6[6] & v6mask[6],
194            addr_v6[7] & v6mask[7],
195        );
196
197        self_ip == addr_ip
198    }
199}
200
201/// Some of the flags associated with an interface.
202#[derive(
203    Debug, Default, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy, Serialize, Deserialize,
204)]
205pub struct InterfaceFlags {
206    pub is_loopback: bool,
207    pub is_running: bool,
208    pub is_point_to_point: bool,
209}
210
211/// Some of the flags associated with an address.
212#[derive(
213    Debug, Default, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy, Serialize, Deserialize,
214)]
215pub struct AddressFlags {
216    // common flags
217    pub is_dynamic: bool,
218    // ipv6 flags
219    pub is_temporary: bool,
220    pub is_preferred: bool,
221}
222
223#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
224pub struct InterfaceAddress {
225    pub if_addr: IfAddr,
226    pub flags: AddressFlags,
227}
228
229use core::cmp::Ordering;
230
231// less is less preferable, greater is more preferable
232impl Ord for InterfaceAddress {
233    fn cmp(&self, other: &Self) -> Ordering {
234        match (&self.if_addr, &other.if_addr) {
235            (IfAddr::V4(a), IfAddr::V4(b)) => {
236                // global scope addresses are better
237                let ret = ipv4addr_is_global(&a.ip).cmp(&ipv4addr_is_global(&b.ip));
238                if ret != Ordering::Equal {
239                    return ret;
240                }
241                // local scope addresses are better
242                let ret = ipv4addr_is_private(&a.ip).cmp(&ipv4addr_is_private(&b.ip));
243                if ret != Ordering::Equal {
244                    return ret;
245                }
246                // non-dynamic addresses are better
247                let ret = (!self.flags.is_dynamic).cmp(&!other.flags.is_dynamic);
248                if ret != Ordering::Equal {
249                    return ret;
250                }
251            }
252            (IfAddr::V6(a), IfAddr::V6(b)) => {
253                // preferred addresses are better
254                let ret = self.flags.is_preferred.cmp(&other.flags.is_preferred);
255                if ret != Ordering::Equal {
256                    return ret;
257                }
258                // non-temporary address are better
259                let ret = (!self.flags.is_temporary).cmp(&!other.flags.is_temporary);
260                if ret != Ordering::Equal {
261                    return ret;
262                }
263                // global scope addresses are better
264                let ret = ipv6addr_is_global(&a.ip).cmp(&ipv6addr_is_global(&b.ip));
265                if ret != Ordering::Equal {
266                    return ret;
267                }
268                // unique local unicast addresses are better
269                let ret = ipv6addr_is_unique_local(&a.ip).cmp(&ipv6addr_is_unique_local(&b.ip));
270                if ret != Ordering::Equal {
271                    return ret;
272                }
273                // unicast site local addresses are better
274                let ret = ipv6addr_is_unicast_site_local(&a.ip)
275                    .cmp(&ipv6addr_is_unicast_site_local(&b.ip));
276                if ret != Ordering::Equal {
277                    return ret;
278                }
279                // unicast link local addresses are better
280                let ret = ipv6addr_is_unicast_link_local(&a.ip)
281                    .cmp(&ipv6addr_is_unicast_link_local(&b.ip));
282                if ret != Ordering::Equal {
283                    return ret;
284                }
285                // non-dynamic addresses are better
286                let ret = (!self.flags.is_dynamic).cmp(&!other.flags.is_dynamic);
287                if ret != Ordering::Equal {
288                    return ret;
289                }
290            }
291            (IfAddr::V4(a), IfAddr::V6(b)) => {
292                // If the IPv6 address is preferred and not temporary, compare if it is global scope
293                if other.flags.is_preferred && !other.flags.is_temporary {
294                    let ret = ipv4addr_is_global(&a.ip).cmp(&ipv6addr_is_global(&b.ip));
295                    if ret != Ordering::Equal {
296                        return ret;
297                    }
298                }
299
300                // Default, prefer IPv4 because many IPv6 addresses are not actually routed
301                return Ordering::Greater;
302            }
303            (IfAddr::V6(a), IfAddr::V4(b)) => {
304                // If the IPv6 address is preferred and not temporary, compare if it is global scope
305                if self.flags.is_preferred && !self.flags.is_temporary {
306                    let ret = ipv6addr_is_global(&a.ip).cmp(&ipv4addr_is_global(&b.ip));
307                    if ret != Ordering::Equal {
308                        return ret;
309                    }
310                }
311
312                // Default, prefer IPv4 because many IPv6 addresses are not actually routed
313                return Ordering::Less;
314            }
315        }
316        // stable sort
317        let ret = self.if_addr.cmp(&other.if_addr);
318        if ret != Ordering::Equal {
319            return ret;
320        }
321        self.flags.cmp(&other.flags)
322    }
323}
324impl PartialOrd for InterfaceAddress {
325    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
326        Some(self.cmp(other))
327    }
328}
329
330impl InterfaceAddress {
331    #[must_use]
332    pub fn new(if_addr: IfAddr, flags: AddressFlags) -> Self {
333        Self { if_addr, flags }
334    }
335
336    #[must_use]
337    pub fn if_addr(&self) -> &IfAddr {
338        &self.if_addr
339    }
340
341    #[must_use]
342    pub fn is_temporary(&self) -> bool {
343        self.flags.is_temporary
344    }
345
346    #[must_use]
347    pub fn is_dynamic(&self) -> bool {
348        self.flags.is_dynamic
349    }
350
351    #[must_use]
352    pub fn is_preferred(&self) -> bool {
353        self.flags.is_preferred
354    }
355}
356
357// #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
358// enum NetworkInterfaceType {
359//     Mobile,     // Least preferable, usually metered and slow
360//     Unknown,    // Everything else if we can't detect the type
361//     Wireless,   // Wifi is usually free or cheap and medium speed
362//     Wired,      // Wired is usually free or cheap and high speed
363// }
364
365#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
366pub struct NetworkInterface {
367    pub name: String,
368    pub flags: InterfaceFlags,
369    pub gateways: Vec<IpAddr>,
370    pub addrs: Vec<InterfaceAddress>,
371}
372
373impl fmt::Debug for NetworkInterface {
374    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
375        let alt = f.alternate();
376        let mut ds = f.debug_struct("NetworkInterface");
377        ds.field("name", &self.name)
378            .field("flags", &self.flags)
379            .field("gateways", &self.gateways)
380            .field("addrs", &self.addrs);
381        if alt {
382            ds.field("// primary_ipv4", &self.primary_ipv4());
383            ds.field("// primary_ipv6", &self.primary_ipv6());
384        }
385        ds.finish()
386    }
387}
388impl NetworkInterface {
389    #[must_use]
390    pub fn new(name: String, flags: InterfaceFlags) -> Self {
391        Self {
392            name,
393            flags,
394            gateways: Vec::new(),
395            addrs: Vec::new(),
396        }
397    }
398    #[must_use]
399    pub fn name(&self) -> String {
400        self.name.clone()
401    }
402    #[must_use]
403    pub fn is_loopback(&self) -> bool {
404        self.flags.is_loopback
405    }
406
407    #[must_use]
408    pub fn is_point_to_point(&self) -> bool {
409        self.flags.is_point_to_point
410    }
411
412    #[must_use]
413    pub fn is_running(&self) -> bool {
414        self.flags.is_running
415    }
416
417    pub fn add_address(&mut self, addr: InterfaceAddress) {
418        self.addrs.push(addr);
419        self.addrs.sort();
420        self.addrs.dedup();
421    }
422
423    #[must_use]
424    pub fn addresses(&self) -> &[InterfaceAddress] {
425        &self.addrs
426    }
427
428    pub fn add_gateway(&mut self, gateway: IpAddr) {
429        self.gateways.push(gateway);
430        self.gateways.sort();
431        self.gateways.dedup();
432    }
433
434    #[must_use]
435    pub fn gateways(&self) -> &[IpAddr] {
436        &self.gateways
437    }
438
439    #[must_use]
440    pub fn primary_ipv4(&self) -> Option<InterfaceAddress> {
441        let mut ipv4addrs: Vec<&InterfaceAddress> = self
442            .addrs
443            .iter()
444            .filter(|a| matches!(a.if_addr(), IfAddr::V4(_)))
445            .collect();
446        ipv4addrs.sort();
447        ipv4addrs.last().cloned().cloned()
448    }
449
450    #[must_use]
451    pub fn primary_ipv6(&self) -> Option<InterfaceAddress> {
452        let mut ipv6addrs: Vec<&InterfaceAddress> = self
453            .addrs
454            .iter()
455            .filter(|a| matches!(a.if_addr(), IfAddr::V6(_)))
456            .collect();
457        ipv6addrs.sort();
458        ipv6addrs.last().cloned().cloned()
459    }
460}
461
462#[derive(Clone, Default, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
463pub struct NetworkInterfaceAddressState {
464    pub gateway_addresses: Vec<IpAddr>,
465    pub interface_addresses: Vec<IfAddr>,
466}
467
468pub struct NetworkInterfacesInner {
469    valid: bool,
470    interfaces: BTreeMap<String, NetworkInterface>,
471    interface_address_state_cache: Arc<NetworkInterfaceAddressState>,
472}
473
474#[derive(Clone)]
475pub struct NetworkInterfaces {
476    inner: Arc<Mutex<NetworkInterfacesInner>>,
477}
478
479impl fmt::Debug for NetworkInterfaces {
480    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
481        let inner = self.inner.lock();
482        f.debug_struct("NetworkInterfaces")
483            .field("valid", &inner.valid)
484            .field("interfaces", &inner.interfaces)
485            .finish()?;
486        if f.alternate() {
487            writeln!(f)?;
488            writeln!(
489                f,
490                "// interface_address_state_cache: {:?}",
491                inner.interface_address_state_cache
492            )?;
493        }
494        Ok(())
495    }
496}
497
498impl Default for NetworkInterfaces {
499    fn default() -> Self {
500        Self::new()
501    }
502}
503
504impl NetworkInterfaces {
505    #[must_use]
506    pub fn new() -> Self {
507        Self {
508            inner: Arc::new(Mutex::new(NetworkInterfacesInner {
509                valid: false,
510                interfaces: BTreeMap::new(),
511                interface_address_state_cache: Arc::new(NetworkInterfaceAddressState::default()),
512            })),
513        }
514    }
515
516    #[must_use]
517    pub fn is_valid(&self) -> bool {
518        let inner = self.inner.lock();
519        inner.valid
520    }
521    pub fn clear(&self) {
522        let mut inner = self.inner.lock();
523
524        inner.interfaces.clear();
525        inner.interface_address_state_cache = Arc::new(NetworkInterfaceAddressState::default());
526        inner.valid = false;
527    }
528    // returns false if refresh had no changes, true if changes were present
529    pub async fn refresh(&self) -> std::io::Result<bool> {
530        let mut last_interfaces = {
531            let mut last_interfaces = BTreeMap::<String, NetworkInterface>::new();
532            let mut platform_support = PlatformSupport::new();
533            platform_support
534                .get_interfaces(&mut last_interfaces)
535                .await?;
536            last_interfaces
537        };
538
539        let mut inner = self.inner.lock();
540        core::mem::swap(&mut inner.interfaces, &mut last_interfaces);
541        inner.valid = true;
542
543        if last_interfaces != inner.interfaces {
544            // get last address cache
545            let old_interface_address_state = inner.interface_address_state_cache.clone();
546
547            // redo the address cache
548            Self::cache_interface_address_state(&mut inner);
549
550            // See if our best addresses have changed
551            if old_interface_address_state != inner.interface_address_state_cache {
552                return Ok(true);
553            }
554        }
555        Ok(false)
556    }
557    pub fn with_interfaces<F, R>(&self, f: F) -> R
558    where
559        F: FnOnce(&BTreeMap<String, NetworkInterface>) -> R,
560    {
561        let inner = self.inner.lock();
562        f(&inner.interfaces)
563    }
564
565    #[must_use]
566    pub fn interface_address_state(&self) -> Arc<NetworkInterfaceAddressState> {
567        let inner = self.inner.lock();
568        inner.interface_address_state_cache.clone()
569    }
570
571    /////////////////////////////////////////////
572
573    fn cache_interface_address_state(inner: &mut NetworkInterfacesInner) {
574        // Reduce interfaces to their best routable ip addresses
575        let mut intf_addrs = Vec::new();
576        let mut gateway_addresses = Vec::new();
577        for intf in inner.interfaces.values() {
578            if !intf.is_running() || intf.is_loopback() {
579                continue;
580            }
581
582            for addr in intf.addresses() {
583                if addr.is_temporary() {
584                    continue;
585                }
586                intf_addrs.push(addr.clone());
587            }
588
589            for gateway in intf.gateways() {
590                gateway_addresses.push(*gateway);
591            }
592        }
593
594        // Sort one more time to get the best interface addresses overall
595        let mut interface_addresses = intf_addrs
596            .iter()
597            .map(|x| x.if_addr().clone())
598            .collect::<Vec<_>>();
599
600        interface_addresses.sort();
601        interface_addresses.dedup();
602
603        gateway_addresses.sort();
604        gateway_addresses.dedup();
605
606        // Now export just the addresses
607        inner.interface_address_state_cache = Arc::new(NetworkInterfaceAddressState {
608            gateway_addresses,
609            interface_addresses,
610        });
611    }
612}