#[cfg(any(target_os = "macos", target_os = "freebsd"))] mod darwin; #[cfg(any(target_os = "linux"))] mod netlink; #[cfg(target_os = "windows")] mod windows; mod route; use std::net::Ipv4Addr; use async_trait::async_trait; use tokio::process::Command; use super::error::Error; #[async_trait] pub trait IfConfiguerTrait: Send + Sync { async fn add_ipv4_route( &self, _name: &str, _address: Ipv4Addr, _cidr_prefix: u8, _cost: Option, ) -> Result<(), Error> { Ok(()) } async fn remove_ipv4_route( &self, _name: &str, _address: Ipv4Addr, _cidr_prefix: u8, ) -> Result<(), Error> { Ok(()) } async fn add_ipv4_ip( &self, _name: &str, _address: Ipv4Addr, _cidr_prefix: u8, ) -> Result<(), Error> { Ok(()) } async fn set_link_status(&self, _name: &str, _up: bool) -> Result<(), Error> { Ok(()) } async fn remove_ip(&self, _name: &str, _ip: Option) -> Result<(), Error> { Ok(()) } async fn wait_interface_show(&self, _name: &str) -> Result<(), Error> { return Ok(()); } async fn set_mtu(&self, _name: &str, _mtu: u32) -> Result<(), Error> { Ok(()) } } fn cidr_to_subnet_mask(prefix_length: u8) -> Ipv4Addr { if prefix_length > 32 { panic!("Invalid CIDR prefix length"); } let subnet_mask: u32 = (!0u32) .checked_shl(32 - u32::from(prefix_length)) .unwrap_or(0); Ipv4Addr::new( ((subnet_mask >> 24) & 0xFF) as u8, ((subnet_mask >> 16) & 0xFF) as u8, ((subnet_mask >> 8) & 0xFF) as u8, (subnet_mask & 0xFF) as u8, ) } async fn run_shell_cmd(cmd: &str) -> Result<(), Error> { let cmd_out: std::process::Output; let stdout: String; let stderr: String; #[cfg(target_os = "windows")] { const CREATE_NO_WINDOW: u32 = 0x08000000; cmd_out = Command::new("cmd") .stdin(std::process::Stdio::null()) .arg("/C") .arg(cmd) .creation_flags(CREATE_NO_WINDOW) .output() .await?; stdout = crate::utils::utf8_or_gbk_to_string(cmd_out.stdout.as_slice()); stderr = crate::utils::utf8_or_gbk_to_string(cmd_out.stderr.as_slice()); }; #[cfg(not(target_os = "windows"))] { cmd_out = Command::new("sh").arg("-c").arg(cmd).output().await?; stdout = String::from_utf8_lossy(cmd_out.stdout.as_slice()).to_string(); stderr = String::from_utf8_lossy(cmd_out.stderr.as_slice()).to_string(); }; let ec = cmd_out.status.code(); let succ = cmd_out.status.success(); tracing::info!(?cmd, ?ec, ?succ, ?stdout, ?stderr, "run shell cmd"); if !cmd_out.status.success() { return Err(Error::ShellCommandError(stdout + &stderr)); } Ok(()) } pub struct DummyIfConfiger {} #[async_trait] impl IfConfiguerTrait for DummyIfConfiger {} #[cfg(any(target_os = "linux"))] pub type IfConfiger = netlink::NetlinkIfConfiger; #[cfg(any(target_os = "macos", target_os = "freebsd"))] pub type IfConfiger = darwin::MacIfConfiger; #[cfg(target_os = "windows")] pub type IfConfiger = windows::WindowsIfConfiger; #[cfg(not(any( target_os = "macos", target_os = "linux", target_os = "windows", target_os = "freebsd", )))] pub type IfConfiger = DummyIfConfiger; #[cfg(target_os = "windows")] pub use windows::RegistryManager;