Skip to main content

fast_down/utils/
network.rs

1use getifaddrs::{InterfaceFlags, getifaddrs};
2use std::net::IpAddr;
3
4pub fn get_available_local_ips() -> std::io::Result<Vec<InterfaceInfo>> {
5    const VIRTUAL_KEYWORDS: &[&str] = &[
6        // Docker 及其网桥
7        "docker",
8        "veth",
9        "br-",
10        // VPN, 隧道, 虚拟机
11        "utun",
12        "tun",
13        "tap",
14        // VirtualBox, VMware
15        "vboxnet",
16        "vmnet",
17        // 虽然已经过滤了 LOOPBACK 标志,但双重保险
18        "lo",
19        // 常见的组网软件
20        "tailscale",
21        "zerotier",
22        "bridge",
23        // 虚拟桥接和空设备
24        "dummy",
25        "virtual",
26        "pseudo",
27    ];
28
29    let mut ips = Vec::new();
30    let interfaces = getifaddrs()?;
31    for interface in interfaces {
32        if interface.flags.contains(InterfaceFlags::UP)
33            && !interface.flags.contains(InterfaceFlags::LOOPBACK)
34            && let Some(ip_addr) = interface.address.ip_addr()
35            && !ip_addr.is_unspecified()
36            && !is_link_local(&ip_addr)
37            && {
38                let name = interface.name.to_lowercase();
39                !VIRTUAL_KEYWORDS.iter().any(|k| name.contains(k))
40            }
41        {
42            ips.push(InterfaceInfo {
43                name: interface.name,
44                ip: ip_addr,
45            });
46        }
47    }
48    Ok(ips)
49}
50
51fn is_link_local(ip: &IpAddr) -> bool {
52    match ip {
53        IpAddr::V4(v4) => v4.is_link_local(),
54        IpAddr::V6(v6) => (v6.segments()[0] & 0xffc0) == 0xfe80,
55    }
56}
57
58pub struct InterfaceInfo {
59    pub name: String,
60    pub ip: IpAddr,
61}