aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSascha Grunert <mail@saschagrunert.de>2017-02-23 13:17:16 +0100
committerSascha Grunert <mail@saschagrunert.de>2017-02-23 13:17:16 +0100
commit7ffe77495b412e280071d0559fe72126af4915c1 (patch)
treeb9daf54307ac8da9b89ab338e866f93d4102fc6c /src
parentAdded read write test to dummy device (diff)
downloadwireguard-rs-7ffe77495b412e280071d0559fe72126af4915c1.tar.xz
wireguard-rs-7ffe77495b412e280071d0559fe72126af4915c1.zip
Changed integration regarding xplatforms example
Diffstat (limited to 'src')
-rw-r--r--src/cli.yaml22
-rw-r--r--src/device.rs10
-rw-r--r--src/error.rs2
-rw-r--r--src/lib.rs317
-rw-r--r--src/main.rs57
m---------src/wireguard0
6 files changed, 266 insertions, 142 deletions
diff --git a/src/cli.yaml b/src/cli.yaml
new file mode 100644
index 0000000..9a36f0d
--- /dev/null
+++ b/src/cli.yaml
@@ -0,0 +1,22 @@
+name: git-journal
+bin_name: git journal
+author: The WireGuard developers
+about: Fast, modern and secure VPN tunnel
+after_help: 'More info at: https://www.wireguard.io'
+global_settings:
+ - VersionlessSubcommands
+ - ColoredHelp
+
+args:
+ - foreground:
+ short: f
+ long: foreground
+ help: Do not daemonize and run in foreground
+ - interface_name:
+ value_name: INTERFACE-NAME
+ default_value: wg0
+ help: Specifies the WireGuard interface name
+ - verbose:
+ help: Set the verbosity level (maximum 4x `v`)
+ short: v
+ multiple: true
diff --git a/src/device.rs b/src/device.rs
index 75fc1ef..6df9483 100644
--- a/src/device.rs
+++ b/src/device.rs
@@ -5,7 +5,7 @@ use std::io::{Read, Write};
use std::os::unix::io::AsRawFd;
use std::path::{Path, PathBuf};
-use bindgen::*;
+use bindgen;
use error::WgResult;
#[derive(Debug)]
@@ -35,13 +35,13 @@ impl Device {
let fd = OpenOptions::new().read(true).write(true).open(path)?;
// Get the default interface options
- let mut ifr = ifreq::new();
+ let mut ifr = bindgen::ifreq::new();
{
// Set the interface name
let ifr_name = unsafe { ifr.ifr_ifrn.ifrn_name.as_mut() };
for (index, character) in name.as_bytes().iter().enumerate() {
- if index >= IFNAMSIZ as usize - 1 {
+ if index >= bindgen::IFNAMSIZ as usize - 1 {
bail!("Interface name too long.");
}
ifr_name[index] = *character as i8;
@@ -49,11 +49,11 @@ impl Device {
// Set the interface flags
let ifr_flags = unsafe { ifr.ifr_ifru.ifru_flags.as_mut() };
- *ifr_flags = (IFF_TUN | IFF_NO_PI) as i16;
+ *ifr_flags = (bindgen::IFF_TUN | bindgen::IFF_NO_PI) as i16;
}
// Create the tunnel device
- if unsafe { ioctl(fd.as_raw_fd(), TUNSETIFF, &ifr) < 0 } {
+ if unsafe { bindgen::ioctl(fd.as_raw_fd(), bindgen::TUNSETIFF, &ifr) < 0 } {
bail!("Device creation failed.");
}
diff --git a/src/error.rs b/src/error.rs
index 220ed27..3a3ba97 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -3,6 +3,7 @@ use std::error::Error;
use std::{fmt, io, net, convert};
use log;
+use std::ffi;
/// Common Tunnel Result type
pub type WgResult<T> = Result<T, WgError>;
@@ -73,6 +74,7 @@ macro_rules! from_error {
from_error! {
io::Error,
log::SetLoggerError,
+ ffi::NulError,
net::AddrParseError,
}
diff --git a/src/lib.rs b/src/lib.rs
index f094c74..c314041 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,11 +6,7 @@
#[macro_use]
extern crate log;
-
-#[macro_use]
-extern crate tokio_core;
-extern crate futures;
-extern crate mowl;
+extern crate libc;
#[macro_use]
mod error;
@@ -20,163 +16,210 @@ mod bindgen;
pub use device::Device;
pub use error::{WgResult, WgError};
-use std::io;
-use std::net::SocketAddr;
-use std::str::FromStr;
+use std::ffi::CString;
+use std::fs::{create_dir, remove_file};
+use std::mem::{size_of, size_of_val};
+use std::ptr::null_mut;
+use std::path::{Path, PathBuf};
-use log::LogLevel;
-use futures::{Async, Future, Poll};
-use tokio_core::net::UdpSocket;
-use tokio_core::reactor::{Core, Handle};
+use libc::{accept, bind, c_void, close, FIONREAD, free, ioctl, listen, malloc};
+use libc::{read, socket, sockaddr, sockaddr_un, strncpy};
+use libc::{poll, pollfd, POLLIN, POLLERR, POLLHUP, POLLNVAL};
/// The main `WireGuard` structure
pub struct WireGuard {
- /// The tokio core which runs the server
- core: Core,
-
- /// The `WireGuard` future for tokio
- tunnel: WireGuardFuture,
+ /// The file descriptor of the socket
+ fd: i32,
}
impl WireGuard {
/// Creates a new `WireGuard` instance
- pub fn new(addr: &str) -> WgResult<Self> {
- WireGuard::create(addr, false)
- }
-
- /// Create a new dummy `WireGuard` instance
- pub fn dummy(addr: &str) -> WgResult<Self> {
- WireGuard::create(addr, true)
- }
-
- /// Internal `WireGuard` creation method
- fn create(addr: &str, dummy: bool) -> WgResult<Self> {
- // Create a new tokio core
- let core = Core::new()?;
+ pub fn new(name: &str) -> WgResult<Self> {
+ // Create the unix socket
+ let fd = unsafe { socket(libc::AF_UNIX, libc::SOCK_STREAM, 0) };
+ if fd < 0 {
+ bail!("Could not create local socket.");
+ }
+ debug!("Created socket.");
- /// Create a tunnel instance
- let tunnel = WireGuardFuture::new(&core.handle(), addr, dummy)?;
+ // Create the socket directory if not existing
+ let mut socket_path = PathBuf::from("/var").join("run").join("wireguard");
+ if !socket_path.exists() {
+ create_dir(&socket_path)?;
+ debug!("Created socket path: {}", socket_path.display());
+ }
+ Self::chmod(&socket_path, 0o700)?;
+
+ // Finish the socket path
+ socket_path.push(name);
+ socket_path.set_extension("sock");
+ if socket_path.exists() {
+ remove_file(&socket_path)?;
+ debug!("Removed existing socket: {}", socket_path.display());
+ }
- /// Return the `WireGuard` instance
- Ok(WireGuard {
- core: core,
- tunnel: tunnel,
- })
- }
+ // Create the `sockaddr_un` structure
+ let mut sun_path = [0; 108];
+ let src = CString::new(format!("{}", socket_path.display()))?;
+ unsafe { strncpy(sun_path.as_mut_ptr(), src.as_ptr(), src.to_bytes().len()) };
- /// Run the server, consumes the `WireGuard` instance
- pub fn run(mut self) -> WgResult<()> {
- Ok(self.core.run(self.tunnel)?)
- }
+ let sock_addr = sockaddr_un {
+ sun_family: libc::AF_UNIX as u16,
+ sun_path: sun_path,
+ };
- /// Initializes global logging
- pub fn init_logging(self, level: LogLevel) -> WgResult<Self> {
- mowl::init_with_level(level)?;
- Ok(self)
- }
+ // Bind the socket
+ if unsafe {
+ bind(fd,
+ &sock_addr as *const _ as *const sockaddr,
+ size_of_val(&sock_addr) as u32)
+ } < 0 {
+ bail!("Could not bind socket.");
+ }
+ debug!("Bound socket: {}", socket_path.display());
- /// Returns the socket address of the server
- pub fn get_addr(&self) -> WgResult<SocketAddr> {
- Ok(self.tunnel.server.local_addr()?)
- }
+ // Listen on the socket
+ if unsafe { listen(fd, 100) } < 0 {
+ bail!("Could not listen on socket.");
+ }
+ debug!("Listening on socket.");
- /// Returns a reference to the tunneling device
- pub fn get_device(&self) -> &Device {
- &self.tunnel.device
+ // Return the `WireGuard` instance
+ Ok(WireGuard { fd: fd })
}
-}
-
-#[derive(Debug)]
-/// The main `WireGuard` future
-pub struct WireGuardFuture {
- /// A tunneling device
- device: Device,
-
- /// The VPN server socket
- server: UdpSocket,
- /// An internal packet buffer
- buffer: Vec<u8>,
+ /// Run the `WireGuard` instance
+ pub fn run(&self) -> WgResult<()> {
+ // A temporarily buffer to write in
+ let mut buffer = null_mut::<c_void>();
- /// Packets to send to the tunneling device
- send_to_device: Option<(usize, SocketAddr)>,
-
- /// Packets to send to the client
- send_to_client: Option<(usize, SocketAddr)>,
-}
+ debug!("Waiting for connections.");
-impl WireGuardFuture {
- /// Creates a new `WireGuardFuture`
- pub fn new(handle: &Handle, addr: &str, dummy: bool) -> WgResult<Self> {
- // Create a tunneling device
- let name = "wg";
- let device = if dummy {
- Device::dummy(name)?
- } else {
- Device::new(name)?
- };
-
- // Create a server for the tunnel
- let sock_addr = SocketAddr::from_str(addr)?;
- let server = UdpSocket::bind(&sock_addr, handle)?;
-
- /// Return the `WireGuardFuture` instance
- Ok(WireGuardFuture {
- device: device,
- server: server,
- buffer: vec![0; 1500],
- send_to_device: None,
- send_to_client: None,
- })
- }
-}
-
-impl Future for WireGuardFuture {
- type Item = ();
- type Error = io::Error;
-
- fn poll(&mut self) -> Poll<(), io::Error> {
loop {
- // Process message from the clients
- if let Some((length, peer)) = self.send_to_device {
- // Write the message to the tunnel device
- let bytes_written = try_nb!(self.device.write(&self.buffer[..length]));
-
- // Set to `None` if transmission is done
- self.send_to_device = None;
-
- info!("Wrote {}/{} bytes from {} to tunnel device",
- bytes_written,
- length,
- peer);
+ // Accept new connections
+ let client = unsafe { accept(self.fd, null_mut(), null_mut()) };
+ if client < 0 {
+ Self::cleanup(buffer, client);
+ error!("Can not 'accept' new connections.");
+ break;
}
-
- // Process message from the tunneling device
- if let Some((length, peer)) = self.send_to_client {
- // Read from the tunnel device and write to the client
- let bytes_written = try_nb!(self.server.send_to(&self.buffer[..length], &peer));
-
- // Set to `None` if transmission is done
- self.send_to_client = None;
-
- info!("Wrote {}/{} bytes from the server to {}",
- bytes_written,
- length,
- peer);
+ trace!("Accepted new connection.");
+
+ // Poll for new events
+ let pfd = pollfd {
+ fd: client,
+ events: POLLIN,
+ revents: 0,
+ };
+ if unsafe { poll(&pfd as *const _ as *mut pollfd, 1, -1) < 0 } ||
+ (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) != 0 || (pfd.revents & POLLIN) == 0 {
+ Self::cleanup(buffer, client);
+ bail!("Polling failed.");
+ }
+ trace!("Event polled.");
+
+ // Get the size of the message
+ let len = 0;
+ let ret = unsafe { ioctl(client, FIONREAD, &len) };
+ if ret < 0 || len == 0 {
+ Self::cleanup(buffer, client);
+ bail!("Call to 'ioctl' failed.");
+ }
+ trace!("Got message size.");
+
+ // Allocate a buffer for the received data
+ // TODO: memory leaks?
+ buffer = unsafe { malloc(len) };
+ if buffer.is_null() {
+ Self::cleanup(buffer, client);
+ bail!("Buffer memory allocation failed.");
}
+ trace!("Buffer memory allocated.");
+ // Finally we receive the data
+ let data_len = unsafe { read(client, buffer, len) };
+ if data_len <= 0 {
+ Self::cleanup(buffer, client);
+ bail!("Could not receive data");
+ }
+ trace!("Received message.");
+
+ // If `data_len` is 1 and it is a NULL byte, it's a "get" request, so we send our
+ // device back.
+ let device;
+ if data_len == 1 && unsafe { buffer.offset(0) as u8 } == 0 {
+ // TODO:
+ // device = get_current_wireguard_device(&data_len);
+ // unsafe { write(client, device, data_len as usize) };
+
+ } else {
+ let wgdev_size = size_of::<bindgen::wgdevice>() as isize;
+ let wgpeer_size = size_of::<bindgen::wgpeer>() as isize;
+ let wgipmask_size = size_of::<bindgen::wgipmask>() as isize;
+
+ // Otherwise, we "set" the received wgdevice and send back the return status.
+ // Check the message size
+ if data_len < wgdev_size {
+ Self::cleanup(buffer, client);
+ bail!("Message size too small.")
+ }
+
+ device = buffer as *mut bindgen::wgdevice;
+
+ // Check that we're not out of bounds.
+ unsafe {
+ let mut peer = device.offset(wgdev_size) as *mut bindgen::wgpeer;
+ for _ in 0..(*device).__bindgen_anon_1.bindgen_union_field {
+ // Calculate the current peer
+ let peer_offset = wgpeer_size + wgipmask_size * (*peer).num_ipmasks as isize;
+ peer = peer.offset(peer_offset);
+
+ if peer.offset(wgpeer_size) as *mut u8 > device.offset(data_len) as *mut u8 {
+ Self::cleanup(buffer, client);
+ bail!("Message out of bounds.");
+ }
+
+ if peer.offset(peer_offset) as *mut u8 > device.offset(data_len) as *mut u8 {
+ Self::cleanup(buffer, client);
+ bail!("Message out of bounds.");
+ }
+ }
+ }
+
+ // TODO:
+ // let ret = set_current_wireguard_device(device);
+ // unsafe { write(client, &ret, size_of_val(ret)) };
+ }
+ }
- // If `send_to_device` is `None` we can receive the next message from the client
- self.send_to_device = Some(try_nb!(self.server.recv_from(&mut self.buffer)));
+ Ok(())
+ }
- // If `send_to_client` is `None` we can receive the next message from the tunnel device
- // self.send_to_client = Some(try_nb!(self.device.read(&mut self.buffer)));
- // info!("Read {} bytes from tunnel device", self.send_to_client.0);
+ /// Cleanup the buffer and client
+ fn cleanup(buffer: *mut c_void, client: i32) {
+ // Free the buffer
+ if !buffer.is_null() {
+ unsafe { free(buffer) };
+ }
- // Stop the future when running in test mode
- if self.device.is_dummy() && self.device.get_rw_count() > 2 {
- return Ok(Async::Ready(()));
- }
+ // Close the client
+ if client >= 0 {
+ unsafe { close(client) };
}
}
+
+ #[cfg(unix)]
+ /// Sets the permissions to a given `Path`
+ fn chmod(path: &Path, perms: u32) -> WgResult<()> {
+ use std::os::unix::prelude::PermissionsExt;
+ use std::fs::{set_permissions, Permissions};
+ set_permissions(path, Permissions::from_mode(perms))?;
+ Ok(())
+ }
+
+ #[cfg(windows)]
+ /// Sets the permissions to a given `Path`
+ fn chmod(_path: &Path, _perms: u32) -> WgResult<()> {
+ Ok(())
+ }
}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..833c821
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,57 @@
+//! The main executable for `WireGuard`
+
+#[macro_use]
+extern crate clap;
+extern crate libc;
+
+#[macro_use]
+extern crate log;
+extern crate mowl;
+extern crate wireguard;
+
+use clap::App;
+use log::LogLevel;
+use wireguard::{WireGuard, WgResult, WgError};
+
+use std::process::exit;
+
+fn main() {
+ if let Err(error) = run() {
+ println!("Main error: {}", error);
+ exit(1);
+ }
+}
+
+fn run() -> WgResult<()> {
+ // Load the CLI parameters from the yaml file
+ let yaml = load_yaml!("cli.yaml");
+ let app = App::from_yaml(yaml).version(crate_version!());
+ let matches = app.get_matches();
+
+ // Set the verbosity level
+ let log_level = match matches.occurrences_of("verbose") {
+ 0 => LogLevel::Error,
+ 1 => LogLevel::Warn,
+ 2 => LogLevel::Info,
+ 3 => LogLevel::Debug,
+ _ => LogLevel::Trace,
+ };
+
+ match mowl::init_with_level(log_level) {
+ Err(_) => warn!("Log level already set"),
+ Ok(_) => warn!("Log level set to: {}", log_level),
+ }
+
+ // Get the CLI matches
+ let interface_name = matches.value_of("interface_name")
+ .ok_or_else(|| WgError::new("No 'interface_name' provided"))?;
+ let _ = matches.is_present("foreground");
+
+ // Create a `WireGuard` instance
+ let wireguard = WireGuard::new(interface_name)?;
+
+ // Run the instance
+ wireguard.run()?;
+
+ Ok(())
+}
diff --git a/src/wireguard b/src/wireguard
new file mode 160000
+Subproject 0ca9047b783d661c455c43e97fbac0d18d5811f