fix: preserve macos shared tun ipv4 aliases

This commit is contained in:
sijie.sun
2026-06-14 11:24:57 +08:00
parent 7ef023fcdd
commit 3d0d2bed9e
5 changed files with 80 additions and 14 deletions
+75 -12
View File
@@ -1,10 +1,42 @@
use std::net::Ipv4Addr;
use std::{
collections::{BTreeMap, BTreeSet},
net::Ipv4Addr,
sync::Arc,
};
use super::{Error, IfConfiguerTrait, cidr_to_subnet_mask, run_shell_cmd};
use async_trait::async_trait;
use cidr::{Ipv4Inet, Ipv6Inet};
use tokio::sync::Mutex;
#[derive(Default)]
pub struct MacIfConfiger {
configured_ipv4: Arc<Mutex<BTreeMap<String, BTreeSet<Ipv4Inet>>>>,
}
impl MacIfConfiger {
fn build_add_ipv4_cmd(name: &str, addr: Ipv4Inet, has_configured_ipv4: bool) -> String {
let address = addr.address();
if has_configured_ipv4 {
format!(
"ifconfig {} alias {:?} {:?} netmask {}",
name,
address,
address,
cidr_to_subnet_mask(addr.network_length())
)
} else {
format!(
"ifconfig {} {:?}/{:?} {:?} up",
name,
address,
addr.network_length(),
address,
)
}
}
}
pub struct MacIfConfiger {}
#[async_trait]
impl IfConfiguerTrait for MacIfConfiger {
async fn add_ipv4_route(
@@ -51,14 +83,23 @@ impl IfConfiguerTrait for MacIfConfiger {
address: Ipv4Addr,
cidr_prefix: u8,
) -> Result<(), Error> {
run_shell_cmd(
format!(
"ifconfig {} {:?}/{:?} {:?} up",
name, address, cidr_prefix, address,
)
.as_str(),
)
.await
let addr = Ipv4Inet::new(address, cidr_prefix).map_err(|err| {
Error::RouteError(Some(format!(
"invalid IPv4 address {address}/{cidr_prefix}: {err:?}"
)))
})?;
let mut configured_ipv4 = self.configured_ipv4.lock().await;
let has_configured_ipv4 = configured_ipv4
.get(name)
.is_some_and(|addresses| !addresses.is_empty());
let cmd = Self::build_add_ipv4_cmd(name, addr, has_configured_ipv4);
run_shell_cmd(cmd.as_str()).await?;
configured_ipv4
.entry(name.to_owned())
.or_default()
.insert(addr);
Ok(())
}
async fn set_link_status(&self, name: &str, up: bool) -> Result<(), Error> {
@@ -67,11 +108,33 @@ impl IfConfiguerTrait for MacIfConfiger {
}
async fn remove_ip(&self, name: &str, ip: Option<Ipv4Inet>) -> Result<(), Error> {
let mut configured_ipv4 = self.configured_ipv4.lock().await;
if let Some(ip) = ip {
run_shell_cmd(format!("ifconfig {} inet {} delete", name, ip.address()).as_str()).await
run_shell_cmd(format!("ifconfig {} inet {} delete", name, ip.address()).as_str())
.await?;
if let Some(addresses) = configured_ipv4.get_mut(name) {
addresses.remove(&ip);
if addresses.is_empty() {
configured_ipv4.remove(name);
}
}
} else {
run_shell_cmd(format!("ifconfig {} inet delete", name).as_str()).await
if let Some(addresses) = configured_ipv4.get(name).cloned() {
for ip in addresses {
run_shell_cmd(
format!("ifconfig {} inet {} delete", name, ip.address()).as_str(),
)
.await?;
if let Some(addresses) = configured_ipv4.get_mut(name) {
addresses.remove(&ip);
}
}
configured_ipv4.remove(name);
} else {
run_shell_cmd(format!("ifconfig {} inet delete", name).as_str()).await?;
}
}
Ok(())
}
async fn set_mtu(&self, name: &str, mtu: u32) -> Result<(), Error> {
+1
View File
@@ -140,6 +140,7 @@ async fn run_shell_cmd(cmd: &str) -> Result<(), Error> {
Ok(())
}
#[derive(Default)]
pub struct DummyIfConfiger {}
#[async_trait]
impl IfConfiguerTrait for DummyIfConfiger {}
+1
View File
@@ -157,6 +157,7 @@ impl From<RouteMessage> for Route {
}
}
#[derive(Default)]
pub struct NetlinkIfConfiger {}
impl NetlinkIfConfiger {
+1
View File
@@ -22,6 +22,7 @@ use winreg::{
};
use super::{Error, IfConfiguerTrait};
#[derive(Default)]
pub struct WindowsIfConfiger {}
fn format_win_error(error: u32) -> String {
+2 -2
View File
@@ -292,7 +292,7 @@ impl VirtualNic {
Self {
config,
ifname: None,
ifcfg: Box::new(IfConfiger {}),
ifcfg: Box::new(IfConfiger::default()),
}
}
@@ -832,7 +832,7 @@ impl VirtualNic {
}
pub fn get_ifcfg(&self) -> IfConfiger {
IfConfiger {}
IfConfiger::default()
}
}