mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-06 17:59:11 +00:00
fix(windows): avoid pnet interface enumeration panic (#2031)
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
use std::{net::IpAddr, ops::Deref, sync::Arc};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
use network_interface::{
|
||||
Addr as SystemAddr, NetworkInterface as SystemNetworkInterface, NetworkInterfaceConfig,
|
||||
};
|
||||
use pnet::datalink::NetworkInterface;
|
||||
#[cfg(target_os = "windows")]
|
||||
use pnet::{ipnetwork::IpNetwork, util::MacAddr};
|
||||
use tokio::{
|
||||
sync::{Mutex, RwLock},
|
||||
task::JoinSet,
|
||||
@@ -264,6 +270,9 @@ impl IPCollector {
|
||||
|
||||
pub async fn collect_interfaces(net_ns: NetNS, filter: bool) -> Vec<NetworkInterface> {
|
||||
let _g = net_ns.guard();
|
||||
#[cfg(target_os = "windows")]
|
||||
let ifaces = Self::collect_interfaces_windows();
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let ifaces = pnet::datalink::interfaces();
|
||||
let mut ret = vec![];
|
||||
for iface in ifaces {
|
||||
@@ -281,6 +290,86 @@ impl IPCollector {
|
||||
ret
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn collect_interfaces_windows() -> Vec<NetworkInterface> {
|
||||
match SystemNetworkInterface::show() {
|
||||
Ok(ifaces) => ifaces
|
||||
.into_iter()
|
||||
.map(Self::convert_windows_interface)
|
||||
.collect(),
|
||||
Err(e) => {
|
||||
tracing::warn!(
|
||||
?e,
|
||||
"failed to enumerate interfaces via network-interface, falling back to pnet"
|
||||
);
|
||||
match std::panic::catch_unwind(pnet::datalink::interfaces) {
|
||||
Ok(ifaces) => ifaces,
|
||||
Err(_) => {
|
||||
tracing::error!(
|
||||
"failed to enumerate interfaces via both network-interface and pnet"
|
||||
);
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn convert_windows_interface(iface: SystemNetworkInterface) -> NetworkInterface {
|
||||
let mac = iface.mac_addr.as_deref().and_then(|mac| {
|
||||
mac.parse::<MacAddr>()
|
||||
.map_err(|e| {
|
||||
tracing::debug!(iface = %iface.name, mac, ?e, "failed to parse interface mac")
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
|
||||
let ips = iface
|
||||
.addr
|
||||
.into_iter()
|
||||
.filter_map(Self::convert_windows_interface_addr)
|
||||
.collect();
|
||||
|
||||
NetworkInterface {
|
||||
name: iface.name,
|
||||
description: String::new(),
|
||||
index: iface.index,
|
||||
mac,
|
||||
ips,
|
||||
// pnet does not populate Windows flags either, so keep the existing semantics.
|
||||
flags: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn convert_windows_interface_addr(addr: SystemAddr) -> Option<IpNetwork> {
|
||||
match addr {
|
||||
SystemAddr::V4(addr) => {
|
||||
let netmask = addr
|
||||
.netmask
|
||||
.map(IpAddr::V4)
|
||||
.unwrap_or(IpAddr::V4(std::net::Ipv4Addr::new(255, 255, 255, 255)));
|
||||
IpNetwork::with_netmask(IpAddr::V4(addr.ip), netmask)
|
||||
.map_err(|e| {
|
||||
tracing::debug!(ip = %addr.ip, ?addr.netmask, ?e, "failed to convert ipv4")
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
SystemAddr::V6(addr) => {
|
||||
let netmask = addr
|
||||
.netmask
|
||||
.map(IpAddr::V6)
|
||||
.unwrap_or(IpAddr::V6(std::net::Ipv6Addr::from(u128::MAX)));
|
||||
IpNetwork::with_netmask(IpAddr::V6(addr.ip), netmask)
|
||||
.map_err(|e| {
|
||||
tracing::debug!(ip = %addr.ip, ?addr.netmask, ?e, "failed to convert ipv6")
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(net_ns))]
|
||||
async fn do_collect_local_ip_addrs(net_ns: NetNS) -> GetIpListResponse {
|
||||
let mut ret = GetIpListResponse::default();
|
||||
|
||||
@@ -221,7 +221,8 @@ fn get_or_create_worker(interface_name: &str) -> io::Result<Arc<InterfaceWorker>
|
||||
|
||||
// But creation is rare.
|
||||
// Let's find interface first.
|
||||
let interfaces = datalink::interfaces();
|
||||
let interfaces = std::panic::catch_unwind(datalink::interfaces)
|
||||
.map_err(|_| io::Error::other("failed to enumerate network interfaces: pnet panicked"))?;
|
||||
let interface = interfaces
|
||||
.into_iter()
|
||||
.find(|iface| iface.name == interface_name)
|
||||
|
||||
Reference in New Issue
Block a user