diff options
| author | Emīls Piņķis <emils@mullvad.net> | 2018-12-03 18:02:04 +0000 |
|---|---|---|
| committer | Emīls Piņķis <emils@mullvad.net> | 2018-12-03 18:02:04 +0000 |
| commit | 16d4ef5fe4fa8450210eecf20099a1c2b8becb39 (patch) | |
| tree | de1ebb84e3efe56f97a5f0e8697e89257edc6909 /talpid-core | |
| parent | 399ab4cfdd538e6e2c8b8312185c62bfcef8ca11 (diff) | |
| download | mullvadvpn-16d4ef5fe4fa8450210eecf20099a1c2b8becb39.tar.xz mullvadvpn-16d4ef5fe4fa8450210eecf20099a1c2b8becb39.zip | |
Add network interface management to talpid-core
Diffstat (limited to 'talpid-core')
| -rw-r--r-- | talpid-core/Cargo.toml | 2 | ||||
| -rw-r--r-- | talpid-core/src/lib.rs | 7 | ||||
| -rw-r--r-- | talpid-core/src/network_interface.rs | 133 |
3 files changed, 142 insertions, 0 deletions
diff --git a/talpid-core/Cargo.toml b/talpid-core/Cargo.toml index 323c3026ab..3be2dfe4cc 100644 --- a/talpid-core/Cargo.toml +++ b/talpid-core/Cargo.toml @@ -27,6 +27,8 @@ talpid-types = { path = "../talpid-types" } [target.'cfg(unix)'.dependencies] ipnetwork = "0.13" lazy_static = "1.0" +tun = { git = "https://github.com/pinkisemils/rust-tun", branch = "add-raw-fd-traits" } +nix = "0.12" [target.'cfg(target_os = "linux")'.dependencies] dbus = "0.6" diff --git a/talpid-core/src/lib.rs b/talpid-core/src/lib.rs index c570d94f85..7e8ca9e26f 100644 --- a/talpid-core/src/lib.rs +++ b/talpid-core/src/lib.rs @@ -26,8 +26,12 @@ extern crate jsonrpc_macros; #[cfg(unix)] extern crate lazy_static; extern crate libc; +#[cfg(unix)] +extern crate nix; extern crate shell_escape; extern crate tokio_core; +#[cfg(unix)] +extern crate tun; extern crate uuid; #[cfg(target_os = "linux")] extern crate which; @@ -44,6 +48,9 @@ extern crate talpid_types; mod winnet; #[cfg(unix)] +/// Working with IP interface devices +pub mod network_interface; +#[cfg(unix)] /// Abstraction over operating system routing table. pub mod routing; diff --git a/talpid-core/src/network_interface.rs b/talpid-core/src/network_interface.rs new file mode 100644 index 0000000000..4a2cd21f93 --- /dev/null +++ b/talpid-core/src/network_interface.rs @@ -0,0 +1,133 @@ +use nix::fcntl; +use std::net::IpAddr; +use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; +use tun::{platform, Configuration, Device}; + +error_chain! { + errors { + /// Unable to open a tunnel device + SetupDeviceError { description("Failed to setup a device") } + /// Unable to get the name of a tunnel device + GetNameError { description("Failed to get a name for the device") } + /// Failed to set IP address + SetIpError{ description( "Failed to set IP address" ) } + /// Failed to toggle device state + ToggleDeviceError{ description( "Failed to enable/disable link device" ) } + } +} + + +/// A trait for managing link devices +pub trait NetworkInterface: Sized { + /// Bring a given interface up or down + fn set_up(&mut self, up: bool) -> Result<()>; + + /// Set host IPs for interface + fn set_ip(&mut self, ip: IpAddr) -> Result<()>; + + /// Set MTU for interface + fn set_mtu(&mut self, mtu: u16) -> Result<()>; + + /// Get name of interface + fn get_name(&self) -> &str; +} + + +trait WireguardLink: AsRawFd + IntoRawFd {} + +fn apply_async_flags(fd: RawFd) -> Result<()> { + fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFL).chain_err(|| ErrorKind::SetupDeviceError)?; + let arg = fcntl::FcntlArg::F_SETFL(fcntl::OFlag::O_RDWR | fcntl::OFlag::O_NONBLOCK); + fcntl::fcntl(fd, arg).chain_err(|| ErrorKind::SetupDeviceError)?; + Ok(()) +} + +/// A tunnel devie +pub struct TunnelDevice { + dev: platform::Device, +} + +impl TunnelDevice { + /// Creates a new Tunnel device + #[allow(unused_mut)] + pub fn new() -> Result<Self> { + let mut config = Configuration::default(); + + #[cfg(target_os = "linux")] + config.platform(|config| { + config.packet_information(true); + }); + let mut dev = platform::create(&config).chain_err(|| ErrorKind::SetupDeviceError)?; + apply_async_flags(dev.as_raw_fd())?; + Ok(Self { dev }) + } +} + +impl AsRawFd for TunnelDevice { + fn as_raw_fd(&self) -> RawFd { + self.dev.as_raw_fd() + } +} + +impl IntoRawFd for TunnelDevice { + fn into_raw_fd(self) -> RawFd { + self.dev.into_raw_fd() + } +} + +impl NetworkInterface for TunnelDevice { + fn set_ip(&mut self, ip: IpAddr) -> Result<()> { + match ip { + IpAddr::V4(ipv4) => self + .dev + .set_address(ipv4) + .chain_err(|| ErrorKind::SetIpError), + IpAddr::V6(ipv6) => { + #[cfg(target_os = "linux")] + { + duct::cmd!( + "ip", + "addr", + "add", + ipv6.to_string(), + "dev", + self.dev.name() + ) + .run() + .map(|_| ()) + .chain_err(|| ErrorKind::SetIpError) + } + #[cfg(target_os = "macos")] + { + duct::cmd!( + "ifconfig", + self.dev.name(), + "inet6", + ipv6.to_string(), + "alias" + ) + .run() + .map(|_| ()) + .chain_err(|| ErrorKind::SetIpError) + } + } + } + } + + fn set_up(&mut self, up: bool) -> Result<()> { + self.dev + .enabled(up) + .chain_err(|| ErrorKind::ToggleDeviceError) + } + + + fn set_mtu(&mut self, mtu: u16) -> Result<()> { + self.dev + .set_mtu(mtu as i32) + .chain_err(|| ErrorKind::ToggleDeviceError) + } + + fn get_name(&self) -> &str { + self.dev.name() + } +} |
