mirror of
https://mirror.suhoan.cn/https://github.com/EasyTier/EasyTier.git
synced 2025-12-14 21:57:24 +08:00
fix ip & route cfg on windows (#28)
This commit is contained in:
@@ -90,6 +90,8 @@ clap = { version = "4.4", features = ["derive"] }
|
||||
|
||||
async-recursion = "1.0.5"
|
||||
|
||||
network-interface = "1.1.1"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows-sys = { version = "0.52", features = [
|
||||
"Win32_Networking_WinSock",
|
||||
|
||||
@@ -7,6 +7,7 @@ use std::{
|
||||
ptr,
|
||||
};
|
||||
|
||||
use network_interface::NetworkInterfaceConfig;
|
||||
use windows_sys::{
|
||||
core::PCSTR,
|
||||
Win32::{
|
||||
@@ -61,18 +62,21 @@ pub fn disable_connection_reset<S: AsRawSocket>(socket: &S) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn find_interface_index_cached(iface_name: &str) -> io::Result<u32> {
|
||||
let ifaces = pnet::datalink::interfaces();
|
||||
for iface in ifaces {
|
||||
if iface.name == iface_name {
|
||||
pub fn find_interface_index(iface_name: &str) -> io::Result<u32> {
|
||||
let ifaces = network_interface::NetworkInterface::show().map_err(|e| {
|
||||
io::Error::new(
|
||||
ErrorKind::NotFound,
|
||||
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,
|
||||
format!("Failed to find interface index for {}", iface_name),
|
||||
);
|
||||
Err(err)
|
||||
format!("{}", iface_name),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn set_ip_unicast_if<S: AsRawSocket>(
|
||||
@@ -82,7 +86,7 @@ pub fn set_ip_unicast_if<S: AsRawSocket>(
|
||||
) -> io::Result<()> {
|
||||
let handle = socket.as_raw_socket() as SOCKET;
|
||||
|
||||
let if_index = find_interface_index_cached(iface)?;
|
||||
let if_index = find_interface_index(iface)?;
|
||||
|
||||
unsafe {
|
||||
// https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options
|
||||
|
||||
@@ -202,7 +202,46 @@ pub struct WindowsIfConfiger {}
|
||||
#[cfg(target_os = "windows")]
|
||||
impl WindowsIfConfiger {
|
||||
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> {
|
||||
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 {
|
||||
run_shell_cmd(
|
||||
format!(
|
||||
"netsh interface ipv4 delete address {} address={}",
|
||||
name,
|
||||
ip.unwrap().to_string()
|
||||
)
|
||||
.as_str(),
|
||||
)
|
||||
.await
|
||||
Self::remove_one_ipv4(name, ip.unwrap()).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,18 +335,15 @@ impl IfConfiguerTrait for WindowsIfConfiger {
|
||||
Ok(
|
||||
tokio::time::timeout(std::time::Duration::from_secs(10), async move {
|
||||
loop {
|
||||
let Ok(_) = run_shell_cmd(
|
||||
format!("netsh interface ipv4 show interfaces {}", name).as_str(),
|
||||
)
|
||||
.await
|
||||
else {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
continue;
|
||||
};
|
||||
if let Some(idx) = Self::get_interface_index(name) {
|
||||
tracing::info!(?name, ?idx, "Interface found");
|
||||
break;
|
||||
}
|
||||
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
||||
}
|
||||
Ok::<(), Error>(())
|
||||
})
|
||||
.await?,
|
||||
.await??,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ impl VirtualNic {
|
||||
let mut config = tun::Configuration::default();
|
||||
let has_packet_info = cfg!(target_os = "macos");
|
||||
config.layer(tun::Layer::L3);
|
||||
config.name(format!("et_{}", self.global_ctx.inst_name));
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
|
||||
@@ -83,7 +83,7 @@ impl PeerCenterBase {
|
||||
});
|
||||
loop {
|
||||
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;
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -416,7 +416,7 @@ impl PeerManager {
|
||||
|
||||
let mut dst_peers = vec![];
|
||||
// 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(
|
||||
self.peers
|
||||
.list_routes()
|
||||
@@ -429,7 +429,7 @@ impl PeerManager {
|
||||
}
|
||||
|
||||
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(());
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use std::{
|
||||
|
||||
use async_stream::stream;
|
||||
use futures::{Future, FutureExt, Sink, SinkExt, Stream, StreamExt};
|
||||
use network_interface::NetworkInterfaceConfig;
|
||||
use tokio::{sync::Mutex, time::error::Elapsed};
|
||||
|
||||
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> {
|
||||
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 ip in iface.ips {
|
||||
if ip.ip() == *local_ip {
|
||||
for addr in iface.addr {
|
||||
if addr.ip() == *local_ip {
|
||||
return Some(iface.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tracing::error!(?local_ip, "can not find interface name by ip");
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user