Implement TunInterfaceOptions

This commit is contained in:
dav 2023-06-24 09:24:19 -07:00 committed by David Zhong
parent da065b503f
commit 84f1d91d5c
6 changed files with 83 additions and 9 deletions

View file

@ -6,4 +6,7 @@ mod imp;
#[path = "unix/mod.rs"] #[path = "unix/mod.rs"]
pub(crate) mod imp; pub(crate) mod imp;
mod options;
pub use imp::{TunInterface, TunQueue}; pub use imp::{TunInterface, TunQueue};
pub use options::TunInterfaceOptions;

38
tun/src/options.rs Normal file
View file

@ -0,0 +1,38 @@
use fehler::throws;
use std::io::Error;
use super::TunInterface;
#[derive(Default)]
pub struct TunInterfaceOptions {
/// (Windows + Linux) Name the tun interface.
pub(crate) name: Option<String>,
/// (Linux) Don't include packet information.
pub(crate) no_pi: Option<()>,
/// (Linux) Avoid opening an existing persistant device.
pub(crate) tun_excl: Option<()>,
}
impl TunInterfaceOptions {
pub fn new() -> Self {
Self::default()
}
pub fn name(mut self, name: &str) -> Self {
self.name = Some(name.to_owned());
self
}
pub fn no_pi(mut self, enable: bool) {
self.no_pi = enable.then_some(());
}
pub fn tun_excl(mut self, enable: bool) {
self.tun_excl = enable.then_some(());
}
#[throws]
pub fn open(self) -> TunInterface {
TunInterface::new_with_options(self)?
}
}

View file

@ -15,7 +15,7 @@ mod sys;
pub use super::queue::TunQueue; pub use super::queue::TunQueue;
use super::{ifname_to_string, string_to_ifname}; use super::{ifname_to_string, string_to_ifname, TunInterfaceOptions};
use kern_control::SysControlSocket; use kern_control::SysControlSocket;
#[derive(Debug)] #[derive(Debug)]
@ -26,6 +26,11 @@ pub struct TunInterface {
impl TunInterface { impl TunInterface {
#[throws] #[throws]
pub fn new() -> TunInterface { pub fn new() -> TunInterface {
Self::new_with_options(TunInterfaceOptions::new())?
}
#[throws]
pub fn new_with_options(_: TunInterfaceOptions) -> TunInterface {
TunInterface::connect(0)? TunInterface::connect(0)?
} }

View file

@ -12,7 +12,7 @@ use log::info;
use libc::in6_ifreq; use libc::in6_ifreq;
use super::{ifname_to_string, string_to_ifname}; use super::{ifname_to_string, string_to_ifname, TunInterfaceOptions};
mod sys; mod sys;
@ -24,16 +24,33 @@ pub struct TunInterface {
impl TunInterface { impl TunInterface {
#[throws] #[throws]
pub fn new() -> TunInterface { pub fn new() -> TunInterface {
Self::new_with_options(TunInterfaceOptions::new())?
}
#[throws]
pub(crate) fn new_with_options(options: TunInterfaceOptions) -> TunInterface {
let file = OpenOptions::new() let file = OpenOptions::new()
.read(true) .read(true)
.write(true) .write(true)
.open("/dev/net/tun")?; .open("/dev/net/tun")?;
let mut flags = libc::IFF_TUN as i16;
if options.no_pi.is_some() {
flags |= libc::IFF_NO_PI as i16;
}
if options.tun_excl.is_some() {
flags |= libc::IFF_TUN_EXCL as i16;
}
let name = options
.name
.map(|name| string_to_ifname(&name))
.unwrap_or([0; libc::IFNAMSIZ]);
let iff = libc::ifreq { let iff = libc::ifreq {
ifr_name: [0; libc::IFNAMSIZ], ifr_name: name,
ifr_ifru: libc::__c_anonymous_ifr_ifru { ifr_ifru: libc::__c_anonymous_ifr_ifru { ifru_flags: flags },
ifru_flags: (libc::IFF_TUN | libc::IFF_TUN_EXCL | libc::IFF_NO_PI) as i16,
},
}; };
unsafe { sys::tun_set_iff(file.as_raw_fd(), &iff)? }; unsafe { sys::tun_set_iff(file.as_raw_fd(), &iff)? };

View file

@ -3,6 +3,8 @@ use std::{
os::fd::{AsRawFd, FromRawFd, IntoRawFd, RawFd}, os::fd::{AsRawFd, FromRawFd, IntoRawFd, RawFd},
}; };
use super::TunInterfaceOptions;
mod queue; mod queue;
#[cfg(target_vendor = "apple")] #[cfg(target_vendor = "apple")]
@ -71,7 +73,7 @@ mod test {
use super::*; use super::*;
use std::io::Write; use std::io::Write;
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
#[throws] #[throws]

View file

@ -5,6 +5,8 @@ use widestring::{u16cstr, U16CString};
use windows::Win32::Foundation::GetLastError; use windows::Win32::Foundation::GetLastError;
mod queue; mod queue;
use super::TunInterfaceOptions;
pub use queue::TunQueue; pub use queue::TunQueue;
pub struct TunInterface { pub struct TunInterface {
@ -15,7 +17,14 @@ pub struct TunInterface {
impl TunInterface { impl TunInterface {
#[throws] #[throws]
pub fn new() -> TunInterface { pub fn new() -> TunInterface {
let name = U16CString::from(u16cstr!("Burrow")); Self::new_with_options(TunInterfaceOptions::new())?
}
#[throws]
pub(crate) fn new_with_options(options: TunInterfaceOptions) -> TunInterface {
let name_owned = options.name.unwrap_or("Burrow".to_owned());
let name = U16CString::from_str(&name_owned).unwrap();
let handle = let handle =
unsafe { sys::WINTUN.WintunCreateAdapter(name.as_ptr(), name.as_ptr(), ptr::null()) }; unsafe { sys::WINTUN.WintunCreateAdapter(name.as_ptr(), name.as_ptr(), ptr::null()) };
if handle.is_null() { if handle.is_null() {
@ -23,7 +32,7 @@ impl TunInterface {
} }
TunInterface { TunInterface {
handle, handle,
name: String::from("Burrow"), name: name_owned,
} }
} }