try create tun device if not exist (#1131)

This commit is contained in:
Sijie.Sun
2025-07-19 22:56:19 +08:00
committed by GitHub
parent 50c6f5ae6c
commit 2660ed5fda
2 changed files with 133 additions and 12 deletions
+1 -1
View File
@@ -89,7 +89,7 @@ tun = { package = "tun-easytier", git="https://github.com/EasyTier/rust-tun", fe
"async", "async",
], optional = true } ], optional = true }
# for net ns # for net ns
nix = { version = "0.29.0", features = ["sched", "socket", "ioctl", "net"] } nix = { version = "0.29.0", features = ["sched", "socket", "ioctl", "net", "fs"] }
uuid = { version = "1.5.0", features = [ uuid = { version = "1.5.0", features = [
"v4", "v4",
+129 -8
View File
@@ -255,7 +255,10 @@ impl Drop for VirtualNic {
if let Some(ref ifname) = self.ifname { if let Some(ref ifname) = self.ifname {
// Try to clean up firewall rules, but don't panic in destructor // Try to clean up firewall rules, but don't panic in destructor
if let Err(e) = crate::arch::windows::remove_interface_firewall_rules(ifname) { if let Err(e) = crate::arch::windows::remove_interface_firewall_rules(ifname) {
eprintln!("Warning: Failed to remove firewall rules for interface {}: {}", ifname, e); eprintln!(
"Warning: Failed to remove firewall rules for interface {}: {}",
ifname, e
);
} }
} }
} }
@@ -271,12 +274,113 @@ impl VirtualNic {
} }
} }
/// Check and create TUN device node if necessary on Linux systems
#[cfg(target_os = "linux")]
async fn ensure_tun_device_node() {
const TUN_DEV_PATH: &str = "/dev/net/tun";
const TUN_DIR_PATH: &str = "/dev/net";
// Check if /dev/net/tun already exists
if tokio::fs::metadata(TUN_DEV_PATH).await.is_ok() {
tracing::debug!("TUN device node {} already exists", TUN_DEV_PATH);
return;
}
tracing::info!(
"TUN device node {} not found, attempting to create",
TUN_DEV_PATH
);
// Check if TUN kernel module is available
let tun_module_available = tokio::fs::metadata("/proc/net/dev").await.is_ok()
&& (tokio::fs::read_to_string("/proc/modules").await)
.map(|content| content.contains("tun"))
.unwrap_or(false);
if !tun_module_available {
tracing::warn!("TUN kernel module may not be loaded");
println!("⚠ Warning: TUN kernel module may not be available.");
println!(" You may need to load it with: sudo modprobe tun");
}
// Try to create /dev/net directory if it doesn't exist
if tokio::fs::metadata(TUN_DIR_PATH).await.is_err() {
if let Err(e) = tokio::fs::create_dir_all(TUN_DIR_PATH).await {
tracing::warn!(
"Failed to create directory {}: {}. Continuing anyway.",
TUN_DIR_PATH,
e
);
println!(
"⚠ Warning: Failed to create directory {}. TUN device creation may fail.",
TUN_DIR_PATH
);
println!(
" You may need to run with root privileges or manually create the TUN device."
);
Self::print_troubleshooting_info();
return;
}
tracing::info!("Created directory {}", TUN_DIR_PATH);
}
// Try to create the TUN device node
// Major number 10, minor number 200 for /dev/net/tun
let dev_node = nix::sys::stat::makedev(10, 200);
match nix::sys::stat::mknod(
TUN_DEV_PATH,
nix::sys::stat::SFlag::S_IFCHR,
nix::sys::stat::Mode::from_bits(0o600).unwrap(),
dev_node,
) {
Ok(_) => {
tracing::info!("Successfully created TUN device node {}", TUN_DEV_PATH);
println!("✓ Created TUN device node {}", TUN_DEV_PATH);
}
Err(e) => {
tracing::warn!(
"Failed to create TUN device node {}: {}. Continuing anyway.",
TUN_DEV_PATH,
e
);
println!(
"⚠ Warning: Failed to create TUN device node {}.",
TUN_DEV_PATH
);
println!(" Error: {}", e);
Self::print_troubleshooting_info();
}
}
}
/// Print troubleshooting information for TUN device issues
#[cfg(target_os = "linux")]
fn print_troubleshooting_info() {
println!(" Possible solutions:");
println!(" 1. Run with root privileges: sudo ./easytier-core [options]");
println!(" 2. Manually create TUN device: sudo mkdir -p /dev/net && sudo mknod /dev/net/tun c 10 200");
println!(" 3. Load TUN kernel module: sudo modprobe tun");
println!(" 4. Use --no-tun flag if TUN functionality is not needed");
println!(" 5. Check if your system/container supports TUN devices");
println!(" Note: TUN functionality may still work if the kernel supports dynamic device creation.");
}
/// For non-Linux systems, this is a no-op
#[cfg(not(target_os = "linux"))]
async fn ensure_tun_device_node() -> Result<(), Error> {
Ok(())
}
async fn create_tun(&mut self) -> Result<tun::platform::Device, Error> { async fn create_tun(&mut self) -> Result<tun::platform::Device, Error> {
let mut config = Configuration::default(); let mut config = Configuration::default();
config.layer(Layer::L3); config.layer(Layer::L3);
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
// Check and create TUN device node if necessary (Linux only)
Self::ensure_tun_device_node().await;
let dev_name = self.global_ctx.get_flags().dev_name; let dev_name = self.global_ctx.get_flags().dev_name;
if !dev_name.is_empty() { if !dev_name.is_empty() {
config.tun_name(format!("{}", dev_name)); config.tun_name(format!("{}", dev_name));
@@ -434,15 +538,28 @@ impl VirtualNic {
// Add firewall rules for virtual NIC interface to allow all traffic // Add firewall rules for virtual NIC interface to allow all traffic
match crate::arch::windows::add_interface_to_firewall_allowlist(&ifname) { match crate::arch::windows::add_interface_to_firewall_allowlist(&ifname) {
Ok(_) => { Ok(_) => {
tracing::info!("Successfully configured Windows Firewall for interface: {}", ifname); tracing::info!(
tracing::info!("All protocols (TCP/UDP/ICMP) are now allowed on interface: {}", ifname); "Successfully configured Windows Firewall for interface: {}",
}, ifname
);
tracing::info!(
"All protocols (TCP/UDP/ICMP) are now allowed on interface: {}",
ifname
);
}
Err(e) => { Err(e) => {
tracing::warn!("Failed to configure Windows Firewall for {}: {}", ifname, e); tracing::warn!("Failed to configure Windows Firewall for {}: {}", ifname, e);
println!("⚠ Warning: Failed to configure Windows Firewall for interface {}.", ifname); println!(
"⚠ Warning: Failed to configure Windows Firewall for interface {}.",
ifname
);
println!(" This may cause connectivity issues with ping and other network functions."); println!(" This may cause connectivity issues with ping and other network functions.");
println!(" Please run as Administrator or manually configure Windows Firewall."); println!(
println!(" Alternatively, you can disable Windows Firewall for testing purposes."); " Please run as Administrator or manually configure Windows Firewall."
);
println!(
" Alternatively, you can disable Windows Firewall for testing purposes."
);
} }
} }
} }
@@ -754,7 +871,11 @@ impl NicCtx {
Ok(()) Ok(())
} }
pub async fn run(&mut self, ipv4_addr: Option<cidr::Ipv4Inet>, ipv6_addr: Option<cidr::Ipv6Inet>) -> Result<(), Error> { pub async fn run(
&mut self,
ipv4_addr: Option<cidr::Ipv4Inet>,
ipv6_addr: Option<cidr::Ipv6Inet>,
) -> Result<(), Error> {
let tunnel = { let tunnel = {
let mut nic = self.nic.lock().await; let mut nic = self.nic.lock().await;
match nic.create_dev().await { match nic.create_dev().await {