use std::net::IpAddr;
use log::info;
use tun::{Configuration as TunConfiguration, Device};
#[derive(Clone, Debug)]
pub struct TunServerConfig {
pub resource_limits: crate::config::tun::TunResourceLimits,
pub mtu: u16,
pub tcp_enabled: bool,
pub udp_enabled: bool,
pub icmp_enabled: bool,
pub tun_name: Option<String>,
pub address: Option<IpAddr>,
pub netmask: Option<IpAddr>,
pub destination: Option<IpAddr>,
pub raw_fd: Option<i32>,
#[allow(dead_code)] pub close_fd_on_drop: bool,
#[allow(dead_code)] pub packet_information: bool,
}
impl Default for TunServerConfig {
fn default() -> Self {
#[cfg(target_os = "ios")]
let default_mtu = 4064;
#[cfg(target_os = "android")]
let default_mtu = 9000;
#[cfg(not(any(target_os = "ios", target_os = "android")))]
let default_mtu = 1500;
Self {
resource_limits: Default::default(),
mtu: default_mtu,
tcp_enabled: true,
udp_enabled: true,
icmp_enabled: true,
tun_name: None,
address: None,
netmask: None,
destination: None,
raw_fd: None,
close_fd_on_drop: true,
packet_information: false,
}
}
}
impl TunServerConfig {
pub fn new() -> Self {
Self::default()
}
pub fn mtu(mut self, mtu: u16) -> Self {
self.mtu = mtu;
self
}
pub fn tun_name(mut self, name: impl Into<String>) -> Self {
self.tun_name = Some(name.into());
self
}
pub fn address(mut self, addr: IpAddr) -> Self {
self.address = Some(addr);
self
}
pub fn netmask(mut self, mask: IpAddr) -> Self {
self.netmask = Some(mask);
self
}
pub fn destination(mut self, dest: IpAddr) -> Self {
self.destination = Some(dest);
self
}
pub fn raw_fd(mut self, fd: i32) -> Self {
self.raw_fd = Some(fd);
self
}
#[allow(dead_code)] pub fn close_fd_on_drop(mut self, close: bool) -> Self {
self.close_fd_on_drop = close;
self
}
#[allow(dead_code)] pub fn packet_information(mut self, pi: bool) -> Self {
self.packet_information = pi;
self
}
pub fn tcp_enabled(mut self, enabled: bool) -> Self {
self.tcp_enabled = enabled;
self
}
pub fn udp_enabled(mut self, enabled: bool) -> Self {
self.udp_enabled = enabled;
self
}
pub fn icmp_enabled(mut self, enabled: bool) -> Self {
self.icmp_enabled = enabled;
self
}
pub fn create_sync_device(&self) -> std::io::Result<Device> {
let mut config = TunConfiguration::default();
config.mtu(self.mtu);
#[cfg(target_os = "linux")]
{
if let Some(ref name) = self.tun_name {
config.tun_name(name);
}
if let Some(addr) = self.address {
config.address(addr);
}
if let Some(mask) = self.netmask {
config.netmask(mask);
}
if let Some(dest) = self.destination {
config.destination(dest);
}
config.platform_config(|p| {
p.ensure_root_privileges(true);
});
config.up();
}
#[cfg(target_os = "ios")]
{
config.platform_config(|p| {
p.packet_information(self.packet_information);
});
}
#[cfg(target_os = "android")]
{
if self.raw_fd.is_none() {
return Err(std::io::Error::other(
"Android requires raw_fd from VpnService.Builder.establish()",
));
}
if let Some(addr) = self.address {
config.address(addr);
}
if let Some(mask) = self.netmask {
config.netmask(mask);
}
}
if let Some(fd) = self.raw_fd {
info!("Creating TUN device from raw FD: {}", fd);
#[cfg(unix)]
{
config.raw_fd(fd);
config.close_fd_on_drop(self.close_fd_on_drop);
}
#[cfg(not(unix))]
{
return Err(std::io::Error::other(
"raw_fd is only supported on Unix platforms",
));
}
}
tun::create(&config)
.map_err(|e| std::io::Error::other(format!("Failed to create TUN device: {}", e)))
}
}