Skip to content
47 changes: 47 additions & 0 deletions examples/routes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <meh@schizofreni.co> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.

use std::io::Read;
use tun::route::RouteEntry;

fn main() {
let mut config = tun::Configuration::default();
config
.address((10, 0, 0, 9))
.netmask((255, 255, 255, 252))
.destination((10, 0, 0, 1))
.up();

#[cfg(target_os = "linux")]
config.platform_config(|config| {
#[allow(deprecated)]
config.packet_information(true);
});

// This sets the default gateway to the other side of the tunnel.
config.add_route(
RouteEntry::new()
.set_rt_dst((0, 0, 0, 0))
.set_rt_genmask((0, 0, 0, 0))
.set_rt_gateway((10, 0, 0, 1)),
);

let mut dev = tun::create(&config).unwrap();
let mut buf = [0; 4096];

loop {
let amount = dev.read(&mut buf).unwrap();
println!("{:?}", &buf[0..amount]);
}
}
13 changes: 13 additions & 0 deletions src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub struct Configuration {
pub(crate) metric: Option<u16>,
#[cfg(unix)]
pub(crate) close_fd_on_drop: Option<bool>,
pub(crate) routes: Option<Vec<crate::route::RouteEntry>>,
}

impl Configuration {
Expand Down Expand Up @@ -154,6 +155,18 @@ impl Configuration {
self.raw_fd = Some(fd);
self
}

/// Add a route to the configuration
pub fn add_route(&mut self, route: crate::route::RouteEntry) -> &mut Self {
match self.routes {
Some(ref mut routes) => routes.push(route),
None => {
self.routes = Some(vec![route]);
}
}
self
}

#[cfg(not(unix))]
pub fn raw_fd(&mut self, fd: i32) -> &mut Self {
self.raw_fd = Some(fd);
Expand Down
7 changes: 7 additions & 0 deletions src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ pub trait AbstractDevice: Read + Write {
self.enabled(enabled)?;
}

if let Some(routes) = config.routes.as_ref() {
self.set_routes(routes)?;
}

Ok(())
}

Expand Down Expand Up @@ -92,6 +96,9 @@ pub trait AbstractDevice: Read + Write {
/// [Note: This setting has no effect on the Windows platform due to the mtu of wintun is always 65535. --end note]
fn set_mtu(&mut self, value: u16) -> Result<()>;

/// Set routes
fn set_routes(&mut self, routes: &[crate::route::RouteEntry]) -> Result<()>;

/// Return whether the underlying tun device on the platform has packet information
///
/// [Note: This value is not used to specify whether the packets delivered from/to tun have packet information. -- end note]
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub use crate::device::AbstractDevice;
mod configuration;
pub use crate::configuration::{Configuration, Layer};

pub mod route;

mod platform;
pub use crate::platform::*;

Expand Down
4 changes: 4 additions & 0 deletions src/platform/android/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ impl AbstractDevice for Device {
Ok(())
}

fn set_routes(&mut self, _routes: &[crate::route::RouteEntry]) -> Result<()> {
unimplemented!("android routes coming soon...");
}

fn packet_information(&self) -> bool {
self.tun.packet_information()
}
Expand Down
4 changes: 4 additions & 0 deletions src/platform/freebsd/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,10 @@ impl AbstractDevice for Device {
}
}

fn set_routes(&mut self, _routes: &[crate::route::RouteEntry]) -> Result<()> {
unimplemented!("freebsd routes coming soon...");
}

fn packet_information(&self) -> bool {
self.tun.packet_information()
}
Expand Down
4 changes: 4 additions & 0 deletions src/platform/ios/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ impl AbstractDevice for Device {
Ok(())
}

fn set_routes(&mut self, _routes: &[crate::route::RouteEntry]) -> Result<()> {
unimplemented!("ios routes coming soon...");
}

fn packet_information(&self) -> bool {
self.tun.packet_information()
}
Expand Down
9 changes: 9 additions & 0 deletions src/platform/linux/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,15 @@ impl AbstractDevice for Device {
}
}

fn set_routes(&mut self, routes: &[crate::route::RouteEntry]) -> Result<()> {
for r in routes.iter() {
if let Err(err) = unsafe { siocaddrt(self.ctl.as_raw_fd(), &libc::rtentry::from(r)) } {
return Err(std::io::Error::from(err).into());
}
}
Ok(())
}

fn packet_information(&self) -> bool {
self.tun.packet_information()
}
Expand Down
3 changes: 2 additions & 1 deletion src/platform/linux/sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

//! Bindings to internal Linux stuff.

use libc::{c_int, ifreq};
use libc::{c_int, ifreq, rtentry};
use nix::{ioctl_read_bad, ioctl_write_ptr, ioctl_write_ptr_bad};

ioctl_read_bad!(siocgifflags, 0x8913, ifreq);
Expand All @@ -30,6 +30,7 @@ ioctl_write_ptr_bad!(siocsifnetmask, 0x891c, ifreq);
ioctl_read_bad!(siocgifmtu, 0x8921, ifreq);
ioctl_write_ptr_bad!(siocsifmtu, 0x8922, ifreq);
ioctl_write_ptr_bad!(siocsifname, 0x8923, ifreq);
ioctl_write_ptr_bad!(siocaddrt, 0x890B, rtentry);

ioctl_write_ptr!(tunsetiff, b'T', 202, c_int);
ioctl_write_ptr!(tunsetpersist, b'T', 203, c_int);
Expand Down
4 changes: 4 additions & 0 deletions src/platform/macos/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,10 @@ impl AbstractDevice for Device {
}
}

fn set_routes(&mut self, _routes: &[crate::route::RouteEntry]) -> Result<()> {
unimplemented!("macos routes coming soon...");
}

fn packet_information(&self) -> bool {
self.tun.packet_information()
}
Expand Down
4 changes: 4 additions & 0 deletions src/platform/ohos/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ impl AbstractDevice for Device {
fn packet_information(&self) -> bool {
self.tun.packet_information()
}

fn set_routes(&mut self, _routes: &[crate::route::RouteEntry]) -> Result<()> {
unimplemented!("freebsd routes coming soon...");
}
}

impl AsRawFd for Device {
Expand Down
3 changes: 3 additions & 0 deletions src/platform/posix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ mod split;
pub(crate) use self::split::Tun;
pub use self::split::{Reader, Writer};

#[cfg(target_os = "linux")]
mod rtentry;

#[allow(dead_code)]
pub fn tun_name_to_index(name: impl AsRef<str>) -> std::io::Result<u32> {
let name_cstr = std::ffi::CString::new(name.as_ref()).map_err(|_| {
Expand Down
62 changes: 62 additions & 0 deletions src/platform/posix/rtentry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyleft (ↄ) meh. <meh@schizofreni.co> | http://meh.schizofreni.co
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.

use crate::posix::sockaddr::sockaddr_union;
use crate::route::{RTF_GATEWAY, RTF_UP, RouteEntry};

impl From<&RouteEntry> for libc::rtentry {
fn from(value: &RouteEntry) -> libc::rtentry {
let rt_dst = value
.rt_dst()
.expect("Route destination address is required.");

let rt_gateway = value
.rt_gateway()
.expect("Route gateway address is required.");

let rt_genmask = value.rt_genmask().expect("Route subnet mask is required.");

let rt_dev: *mut libc::c_char = std::ptr::null_mut();

let rt_pad4 = {
cfg_if::cfg_if! {
if #[cfg(all(target_arch = "arm", target_env = "ohos"))] {
[value.rt_pad4().unwrap_or(0)]
} else if #[cfg(target_pointer_width = "64")] {
value.rt_pad4().unwrap_or([0, 0, 0])
} else {
value.rt_pad4().unwrap_or(0 as libc::c_short)
}
}
};

libc::rtentry {
rt_pad1: value.rt_pad1().unwrap_or(0),
rt_dst: unsafe { sockaddr_union::from((rt_dst, 0)).addr },
rt_gateway: unsafe { sockaddr_union::from((rt_gateway, 0)).addr },
rt_genmask: unsafe { sockaddr_union::from((rt_genmask, 0)).addr },
rt_flags: value.rt_flags().unwrap_or(RTF_GATEWAY | RTF_UP),
rt_pad2: value.rt_pad2().unwrap_or(0),
rt_pad3: value.rt_pad3().unwrap_or(0),
rt_tos: value.rt_tos().unwrap_or(0),
rt_class: value.rt_class().unwrap_or(0),
rt_pad4,
rt_metric: value.rt_metric().unwrap_or(0),
rt_dev: value.rt_dev().unwrap_or(rt_dev),
rt_mtu: value.rt_mtu().unwrap_or(1500),
rt_window: value.rt_window().unwrap_or(0),
rt_irtt: value.rt_irtt().unwrap_or(0),
}
}
}
4 changes: 4 additions & 0 deletions src/platform/windows/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ impl AbstractDevice for Device {
Ok(())
}

fn set_routes(&mut self, _routes: &[crate::route::RouteEntry]) -> Result<()> {
unimplemented!("windows routes coming soon...");
}

fn packet_information(&self) -> bool {
// Note: wintun does not support packet information
false
Expand Down
Loading
Loading