initial
This commit is contained in:
79
rust/src/tunnel.rs
Normal file
79
rust/src/tunnel.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use anyhow::Result;
|
||||
use std::net::Ipv4Addr;
|
||||
use tracing::info;
|
||||
|
||||
/// Configuration for creating a TUN device.
|
||||
pub struct TunConfig {
|
||||
pub name: String,
|
||||
pub address: Ipv4Addr,
|
||||
pub netmask: Ipv4Addr,
|
||||
pub mtu: u16,
|
||||
}
|
||||
|
||||
impl Default for TunConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: "smartvpn0".to_string(),
|
||||
address: Ipv4Addr::new(10, 8, 0, 1),
|
||||
netmask: Ipv4Addr::new(255, 255, 255, 0),
|
||||
mtu: 1420,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create and configure a TUN device.
|
||||
/// Returns an async TUN device handle.
|
||||
pub fn create_tun(config: &TunConfig) -> Result<tun::AsyncDevice> {
|
||||
let mut tun_config = tun::Configuration::default();
|
||||
tun_config
|
||||
.tun_name(&config.name)
|
||||
.address(config.address)
|
||||
.netmask(config.netmask)
|
||||
.mtu(config.mtu as u16)
|
||||
.up();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
tun_config.platform_config(|p| {
|
||||
p.ensure_root_privileges(true);
|
||||
});
|
||||
|
||||
let device = tun::create_as_async(&tun_config)?;
|
||||
info!(
|
||||
"TUN device {} created: addr={}, mtu={}",
|
||||
config.name, config.address, config.mtu
|
||||
);
|
||||
Ok(device)
|
||||
}
|
||||
|
||||
/// Set up routing: add a route for the VPN subnet through the TUN device.
|
||||
pub async fn add_route(subnet: &str, device_name: &str) -> Result<()> {
|
||||
let output = tokio::process::Command::new("ip")
|
||||
.args(["route", "add", subnet, "dev", device_name])
|
||||
.output()
|
||||
.await?;
|
||||
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
// Ignore "File exists" errors (route already set)
|
||||
if !stderr.contains("File exists") {
|
||||
anyhow::bail!("Failed to add route: {}", stderr);
|
||||
}
|
||||
}
|
||||
|
||||
info!("Added route {} via {}", subnet, device_name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove a route.
|
||||
pub async fn remove_route(subnet: &str, device_name: &str) -> Result<()> {
|
||||
let output = tokio::process::Command::new("ip")
|
||||
.args(["route", "del", subnet, "dev", device_name])
|
||||
.output()
|
||||
.await?;
|
||||
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
tracing::warn!("Failed to remove route (may not exist): {}", stderr);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user