summaryrefslogtreecommitdiffhomepage
path: root/talpid-core
diff options
context:
space:
mode:
authorEmīls Piņķis <emils@mullvad.net>2018-12-03 18:02:04 +0000
committerEmīls Piņķis <emils@mullvad.net>2018-12-03 18:02:04 +0000
commit16d4ef5fe4fa8450210eecf20099a1c2b8becb39 (patch)
treede1ebb84e3efe56f97a5f0e8697e89257edc6909 /talpid-core
parent399ab4cfdd538e6e2c8b8312185c62bfcef8ca11 (diff)
downloadmullvadvpn-16d4ef5fe4fa8450210eecf20099a1c2b8becb39.tar.xz
mullvadvpn-16d4ef5fe4fa8450210eecf20099a1c2b8becb39.zip
Add network interface management to talpid-core
Diffstat (limited to 'talpid-core')
-rw-r--r--talpid-core/Cargo.toml2
-rw-r--r--talpid-core/src/lib.rs7
-rw-r--r--talpid-core/src/network_interface.rs133
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()
+ }
+}