Skip to main content

seyd_nat/
ifaces.rs

1// Copyright 2026 Anton Gravestam
2// SPDX-License-Identifier: Apache-2.0
3//! Local addresses worth advertising.
4
5use crate::addr::is_global;
6use std::net::IpAddr;
7
8/// Non-loopback local addresses: IPv4 (private *and* public — the private
9/// one is the same-LAN candidate, the fastest path there is when the pilot
10/// shares the network) and globally routable IPv6 only. Link-local and
11/// unique-local IPv6 are filtered: a pilot elsewhere on the internet cannot
12/// reach them, so advertising them only wastes a connection attempt.
13pub fn interfaces() -> Vec<IpAddr> {
14    let mut out: Vec<IpAddr> = Vec::new();
15    let Ok(addrs) = if_addrs::get_if_addrs() else {
16        return out;
17    };
18    for a in addrs {
19        let ip = a.ip();
20        if a.is_loopback() || ip.is_multicast() {
21            continue;
22        }
23        let keep = match ip {
24            IpAddr::V4(v4) => !v4.is_link_local() && !v4.is_unspecified(),
25            IpAddr::V6(v6) => is_global(IpAddr::V6(v6)),
26        };
27        if keep && !out.contains(&ip) {
28            out.push(ip);
29        }
30    }
31    out
32}
33
34#[cfg(test)]
35mod tests {
36    #[test]
37    fn no_loopback_or_link_local() {
38        for ip in super::interfaces() {
39            assert!(!ip.is_loopback());
40            if let std::net::IpAddr::V6(v6) = ip {
41                assert_ne!(v6.segments()[0] & 0xffc0, 0xfe80);
42            }
43        }
44    }
45}