fix ip & route cfg on windows (#28)

This commit is contained in:
Sijie.Sun
2024-03-09 00:24:16 +08:00
committed by GitHub
parent 5f30747f62
commit cb0df51319
7 changed files with 82 additions and 38 deletions

View File

@@ -90,6 +90,8 @@ clap = { version = "4.4", features = ["derive"] }
async-recursion = "1.0.5" async-recursion = "1.0.5"
network-interface = "1.1.1"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.52", features = [ windows-sys = { version = "0.52", features = [
"Win32_Networking_WinSock", "Win32_Networking_WinSock",

View File

@@ -7,6 +7,7 @@ use std::{
ptr, ptr,
}; };
use network_interface::NetworkInterfaceConfig;
use windows_sys::{ use windows_sys::{
core::PCSTR, core::PCSTR,
Win32::{ Win32::{
@@ -61,18 +62,21 @@ pub fn disable_connection_reset<S: AsRawSocket>(socket: &S) -> io::Result<()> {
Ok(()) Ok(())
} }
pub fn find_interface_index_cached(iface_name: &str) -> io::Result<u32> { pub fn find_interface_index(iface_name: &str) -> io::Result<u32> {
let ifaces = pnet::datalink::interfaces(); let ifaces = network_interface::NetworkInterface::show().map_err(|e| {
for iface in ifaces { io::Error::new(
if iface.name == iface_name { ErrorKind::NotFound,
return Ok(iface.index); format!("Failed to get interfaces. {}, error: {}", iface_name, e),
} )
})?;
if let Some(iface) = ifaces.iter().find(|iface| iface.name == iface_name) {
return Ok(iface.index);
} }
let err = io::Error::new( tracing::error!("Failed to find interface index for {}", iface_name);
Err(io::Error::new(
ErrorKind::NotFound, ErrorKind::NotFound,
format!("Failed to find interface index for {}", iface_name), format!("{}", iface_name),
); ))
Err(err)
} }
pub fn set_ip_unicast_if<S: AsRawSocket>( pub fn set_ip_unicast_if<S: AsRawSocket>(
@@ -82,7 +86,7 @@ pub fn set_ip_unicast_if<S: AsRawSocket>(
) -> io::Result<()> { ) -> io::Result<()> {
let handle = socket.as_raw_socket() as SOCKET; let handle = socket.as_raw_socket() as SOCKET;
let if_index = find_interface_index_cached(iface)?; let if_index = find_interface_index(iface)?;
unsafe { unsafe {
// https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options // https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options

View File

@@ -202,7 +202,46 @@ pub struct WindowsIfConfiger {}
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
impl WindowsIfConfiger { impl WindowsIfConfiger {
pub fn get_interface_index(name: &str) -> Option<u32> { pub fn get_interface_index(name: &str) -> Option<u32> {
crate::arch::windows::find_interface_index_cached(name).ok() crate::arch::windows::find_interface_index(name).ok()
}
async fn list_ipv4(name: &str) -> Result<Vec<Ipv4Addr>, Error> {
use anyhow::Context;
use network_interface::NetworkInterfaceConfig;
use std::net::IpAddr;
let ret = network_interface::NetworkInterface::show().with_context(|| "show interface")?;
let addrs = ret
.iter()
.filter_map(|x| {
if x.name != name {
return None;
}
Some(x.addr.clone())
})
.flat_map(|x| x)
.map(|x| x.ip())
.filter_map(|x| {
if let IpAddr::V4(ipv4) = x {
Some(ipv4)
} else {
None
}
})
.collect::<Vec<_>>();
Ok(addrs)
}
async fn remove_one_ipv4(name: &str, ip: Ipv4Addr) -> Result<(), Error> {
run_shell_cmd(
format!(
"netsh interface ipv4 delete address {} address={}",
name,
ip.to_string()
)
.as_str(),
)
.await
} }
} }
@@ -283,17 +322,12 @@ impl IfConfiguerTrait for WindowsIfConfiger {
async fn remove_ip(&self, name: &str, ip: Option<Ipv4Addr>) -> Result<(), Error> { async fn remove_ip(&self, name: &str, ip: Option<Ipv4Addr>) -> Result<(), Error> {
if ip.is_none() { if ip.is_none() {
run_shell_cmd(format!("netsh interface ipv4 delete address {}", name).as_str()).await for ip in Self::list_ipv4(name).await?.iter() {
Self::remove_one_ipv4(name, *ip).await?;
}
Ok(())
} else { } else {
run_shell_cmd( Self::remove_one_ipv4(name, ip.unwrap()).await
format!(
"netsh interface ipv4 delete address {} address={}",
name,
ip.unwrap().to_string()
)
.as_str(),
)
.await
} }
} }
@@ -301,18 +335,15 @@ impl IfConfiguerTrait for WindowsIfConfiger {
Ok( Ok(
tokio::time::timeout(std::time::Duration::from_secs(10), async move { tokio::time::timeout(std::time::Duration::from_secs(10), async move {
loop { loop {
let Ok(_) = run_shell_cmd( if let Some(idx) = Self::get_interface_index(name) {
format!("netsh interface ipv4 show interfaces {}", name).as_str(), tracing::info!(?name, ?idx, "Interface found");
) break;
.await }
else { tokio::time::sleep(std::time::Duration::from_millis(100)).await;
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
continue;
};
break;
} }
Ok::<(), Error>(())
}) })
.await?, .await??,
) )
} }
} }

View File

@@ -54,6 +54,7 @@ impl VirtualNic {
let mut config = tun::Configuration::default(); let mut config = tun::Configuration::default();
let has_packet_info = cfg!(target_os = "macos"); let has_packet_info = cfg!(target_os = "macos");
config.layer(tun::Layer::L3); config.layer(tun::Layer::L3);
config.name(format!("et_{}", self.global_ctx.inst_name));
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {

View File

@@ -83,7 +83,7 @@ impl PeerCenterBase {
}); });
loop { loop {
let Some(center_peer) = Self::select_center_peer(&peer_mgr).await else { let Some(center_peer) = Self::select_center_peer(&peer_mgr).await else {
tracing::warn!("no center peer found, sleep 1 second"); tracing::trace!("no center peer found, sleep 1 second");
tokio::time::sleep(Duration::from_secs(1)).await; tokio::time::sleep(Duration::from_secs(1)).await;
continue; continue;
}; };

View File

@@ -416,7 +416,7 @@ impl PeerManager {
let mut dst_peers = vec![]; let mut dst_peers = vec![];
// NOTE: currently we only support ipv4 and cidr is 24 // NOTE: currently we only support ipv4 and cidr is 24
if ipv4_addr.octets()[3] == 255 { if ipv4_addr.is_broadcast() || ipv4_addr.is_multicast() || ipv4_addr.octets()[3] == 255 {
dst_peers.extend( dst_peers.extend(
self.peers self.peers
.list_routes() .list_routes()
@@ -429,7 +429,7 @@ impl PeerManager {
} }
if dst_peers.is_empty() { if dst_peers.is_empty() {
log::error!("no peer id for ipv4: {}", ipv4_addr); tracing::info!("no peer id for ipv4: {}", ipv4_addr);
return Ok(()); return Ok(());
} }

View File

@@ -7,6 +7,7 @@ use std::{
use async_stream::stream; use async_stream::stream;
use futures::{Future, FutureExt, Sink, SinkExt, Stream, StreamExt}; use futures::{Future, FutureExt, Sink, SinkExt, Stream, StreamExt};
use network_interface::NetworkInterfaceConfig;
use tokio::{sync::Mutex, time::error::Elapsed}; use tokio::{sync::Mutex, time::error::Elapsed};
use std::pin::Pin; use std::pin::Pin;
@@ -258,14 +259,19 @@ impl Tunnel for TunnelWithCustomInfo {
} }
pub(crate) fn get_interface_name_by_ip(local_ip: &IpAddr) -> Option<String> { pub(crate) fn get_interface_name_by_ip(local_ip: &IpAddr) -> Option<String> {
let ifaces = pnet::datalink::interfaces(); if local_ip.is_unspecified() || local_ip.is_multicast() {
return None;
}
let ifaces = network_interface::NetworkInterface::show().ok()?;
for iface in ifaces { for iface in ifaces {
for ip in iface.ips { for addr in iface.addr {
if ip.ip() == *local_ip { if addr.ip() == *local_ip {
return Some(iface.name); return Some(iface.name);
} }
} }
} }
tracing::error!(?local_ip, "can not find interface name by ip");
None None
} }