aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Grunert <mail@saschagrunert.de>2017-02-23 16:48:01 +0100
committerSascha Grunert <mail@saschagrunert.de>2017-02-23 16:48:01 +0100
commitf0f7cc8c9084237056f63918a6b5428e9ac5d944 (patch)
tree0ae9b1e2bbd7a826ffa4beb6d917ebb6ea1de26d
parentUsing the libc ioctl (diff)
downloadwireguard-rs-f0f7cc8c9084237056f63918a6b5428e9ac5d944.tar.xz
wireguard-rs-f0f7cc8c9084237056f63918a6b5428e9ac5d944.zip
Removed bindgen, added uapi bindings by hand
-rw-r--r--.gitmodules3
-rw-r--r--.travis.yml5
-rw-r--r--Cargo.toml4
-rw-r--r--build.rs40
-rwxr-xr-xci/before_install.sh40
-rw-r--r--src/bindgen.rs34
-rw-r--r--src/device.rs146
-rw-r--r--src/lib.rs17
-rw-r--r--src/uapi.rs163
m---------src/wireguard0
-rw-r--r--tests/device.rs47
11 files changed, 171 insertions, 328 deletions
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 9afcb38..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "src/wireguard"]
- path = src/wireguard
- url = https://github.com/WireGuard/WireGuard.git
diff --git a/.travis.yml b/.travis.yml
index 7e950f0..1634ab4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,8 +11,6 @@ before_script:
- export PATH=$HOME/.local/bin:$PATH
- export PATH=$HOME/Library/Python/2.7/bin:$PATH
- cargo install cargo-kcov
- - clang --version
-before_install: . ./ci/before_install.sh
script:
- export CARGO_TARGET_DIR=`pwd`/target
- travis-cargo build
@@ -38,9 +36,6 @@ addons:
- libelf-dev
- libdw-dev
- binutils-dev
- - gcc-5
env:
global:
- - CARGO_TARGET_DIR=/tmp/wireguard LLVM_VERSION=3.9 BINDGEN_FEATURES=
- - TRAVIS_CARGO_NIGHTLY_FEATURE=""
- secure: WC9zSfV0u90iqsZD5477le2r7f0PwPEXQffN2fVbiV1kOWYZa7czyMeLQdCadfROf9K5SMgDBvRdB+FEyVWDMsatp5hIfeLyxug/xrktP7onzcWIImX+zFXV/Z+RDWOH+ojDsgmtR9PmP+k1+8DAq+w7d2e9uWkrVXhuY2xwvoUi0Ry3Ilw3Kji4EkzAV+sTCHV0wYM95Q1OOeYgIxf69Az73DqC6H254lud+EHculiBKaT+rnLvTdWJKP97xLuZ9p7wB368D3I4LGSQvtuGFynO+FRhjPbWKljeu6D1Q/Zj/CzX8Us0OXY0z4oGPsJTfLeSEJsIwTPFnqCyzmMBkpV4GC63Prso8pYmSe9a+226OAtLTyhWTWuHpw78BO23lsSLHpRIpHleNeMJhdAirEld7OWV3R3gYSNfuYKEQ6moQfpLdpWQbAddmE5qDsp9T5WIeFRu+aUPR45h6H4ma3w0txGiNSJKKzopIolnI3TZoI05B+dOGYoxPAhx5r1adDsqhZiXMgAni/NmUAN+nY19qBOLGQKhrqdqzRyz9QeNUiirPiL1ezyKQazTqjuubsgrbGk3hz9nyFrVgfEGbacYL6wCRzZuoOhBjcSePhymUXjSI+7PB5Ew4GfFNi5Jqxx47/Ba+uM5Gk8CTft/CjQ6jBOH2YxZeVHmwXKbaNI=
diff --git a/Cargo.toml b/Cargo.toml
index 59c8ea2..4a057ba 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,14 +2,10 @@
name = "wireguard"
version = "0.1.0"
authors = ["The WireGuard developers", "Sascha Grunert <mail@saschagrunert.de>"]
-build = "build.rs"
[[bin]]
name = "userspace-wg"
-[build-dependencies]
-bindgen = "0"
-
[dependencies]
clap = { version = "2", features = ["yaml"] }
libc = "0"
diff --git a/build.rs b/build.rs
deleted file mode 100644
index 55ea620..0000000
--- a/build.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-extern crate bindgen;
-
-use bindgen::Builder;
-
-use std::env;
-use std::fs::File;
-use std::io::Write;
-use std::error::Error;
-use std::path::PathBuf;
-
-static HEADERS: &'static [&'static str] = &["linux/if_tun.h", "uapi.h"];
-
-fn main() {
- run().expect("Could not execute build script.");
-}
-
-fn run() -> Result<(), Box<Error>> {
- // Create a wrapper header file
- let out_path = PathBuf::from(env::var("OUT_DIR")?);
- let wrapper_path = out_path.join("wrapper.h");
- let mut wrapper = File::create(&wrapper_path)?;
- for header in HEADERS {
- writeln!(wrapper, "#include <{}>", header)?;
- }
-
- // Generate the bindungs
- let wrapper_path_str = wrapper_path.to_str().expect("Wrapper include path corrupt.");
- let bindings = Builder::default()
- .no_unstable_rust()
- .generate_comments(true)
- .hide_type("pthread_mutex_t")
- .header(wrapper_path_str)
- .clang_arg("-I./src/wireguard/src")
- .generate()
- .expect("Unable to generate bindings");
-
- // Write the bindungs to the output directory
- bindings.write_to_file(out_path.join("bindings.rs"))?;
- Ok(())
-}
diff --git a/ci/before_install.sh b/ci/before_install.sh
deleted file mode 100755
index 28d209c..0000000
--- a/ci/before_install.sh
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/env bash
-set -e
-pushd ~
-
-# Workaround for Travis CI macOS bug (https://github.com/travis-ci/travis-ci/issues/6307)
-if [ "${TRAVIS_OS_NAME}" == "osx" ]; then
- rvm get head || true
-fi
-
-function llvm_version_triple() {
- if [ "$1" == "3.8" ]; then
- echo "3.8.0"
- elif [ "$1" == "3.9" ]; then
- echo "3.9.0"
- fi
-}
-
-function llvm_download() {
- export LLVM_VERSION_TRIPLE=`llvm_version_triple ${LLVM_VERSION}`
- export LLVM=clang+llvm-${LLVM_VERSION_TRIPLE}-x86_64-$1
-
- wget http://llvm.org/releases/${LLVM_VERSION_TRIPLE}/${LLVM}.tar.xz
- mkdir llvm
- tar -xf ${LLVM}.tar.xz -C llvm --strip-components=1
-
- export LLVM_CONFIG_PATH=`pwd`/llvm/bin/llvm-config
- if [ "${TRAVIS_OS_NAME}" == "osx" ]; then
- cp llvm/lib/libclang.dylib /usr/local/lib/libclang.dylib
- fi
-}
-
-
-if [ "${TRAVIS_OS_NAME}" == "linux" ]; then
- llvm_download linux-gnu-ubuntu-14.04
-else
- llvm_download apple-darwin
-fi
-
-popd
-set +e
diff --git a/src/bindgen.rs b/src/bindgen.rs
deleted file mode 100644
index 80bedd8..0000000
--- a/src/bindgen.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-//! Bindgen source code
-#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case, dead_code, improper_ctypes)]
-#![cfg_attr(feature = "cargo-clippy", allow(expl_impl_clone_on_copy, useless_transmute))]
-
-pub const TUNSETIFF: u64 = (1 << (8 + 8 + 14)) | (84 << 8) | 202 | (4 << (8 + 8));
-
-include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
-
-impl ifreq {
- /// Create a new `ifreq`
- pub fn new() -> Self {
- ifreq {
- ifr_ifrn: ifreq__bindgen_ty_1 {
- ifrn_name: __BindgenUnionField::new(),
- bindgen_union_field: [0; IFNAMSIZ as usize],
- },
- ifr_ifru: ifreq__bindgen_ty_2 {
- ifru_addr: __BindgenUnionField::new(),
- ifru_dstaddr: __BindgenUnionField::new(),
- ifru_broadaddr: __BindgenUnionField::new(),
- ifru_netmask: __BindgenUnionField::new(),
- ifru_hwaddr: __BindgenUnionField::new(),
- ifru_flags: __BindgenUnionField::new(),
- ifru_ivalue: __BindgenUnionField::new(),
- ifru_mtu: __BindgenUnionField::new(),
- ifru_map: __BindgenUnionField::new(),
- ifru_slave: __BindgenUnionField::new(),
- ifru_newname: __BindgenUnionField::new(),
- ifru_data: __BindgenUnionField::new(),
- bindgen_union_field: [0u64; 3usize],
- },
- }
- }
-}
diff --git a/src/device.rs b/src/device.rs
deleted file mode 100644
index 7d5ddad..0000000
--- a/src/device.rs
+++ /dev/null
@@ -1,146 +0,0 @@
-//! Tunnel device handling
-use std::env::temp_dir;
-use std::fs::{File, OpenOptions};
-use std::io::{Read, Write};
-use std::os::unix::io::AsRawFd;
-use std::path::{Path, PathBuf};
-
-use bindgen;
-use libc::ioctl;
-use error::WgResult;
-
-#[derive(Debug)]
-/// A certain device
-pub struct Device {
- /// The interface name
- name: String,
-
- /// The tunnel device file descriptor
- fd: File,
-
- /// The full path to the file
- path: PathBuf,
-
- /// Dummy indicator
- is_dummy: bool,
-
- /// A read/write counter
- rw_count: u64,
-}
-
-impl Device {
- /// Create a new tunneling `Device`
- pub fn new(name: &str) -> WgResult<Self> {
- // Get a file descriptor to the operating system
- let path = "/dev/net/tun";
- let fd = OpenOptions::new().read(true).write(true).open(path)?;
-
- // Get the default interface options
- 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 >= bindgen::IFNAMSIZ as usize - 1 {
- bail!("Interface name too long.");
- }
- ifr_name[index] = *character as i8;
- }
-
- // Set the interface flags
- let ifr_flags = unsafe { ifr.ifr_ifru.ifru_flags.as_mut() };
- *ifr_flags = (bindgen::IFF_TUN | bindgen::IFF_NO_PI) as i16;
- }
-
- // Create the tunnel device
- if unsafe { ioctl(fd.as_raw_fd(), bindgen::TUNSETIFF, &ifr) < 0 } {
- bail!("Device creation failed.");
- }
-
- Ok(Device {
- name: name.to_owned(),
- fd: fd,
- path: PathBuf::from(path),
- is_dummy: false,
- rw_count: 0,
- })
- }
-
- /// Create a dummy device for testing
- pub fn dummy(name: &str) -> WgResult<Self> {
- // Place the dummy in the sytems default temp dir
- let path = temp_dir().join(name);
-
- // Create a file descriptor
- let fd = OpenOptions::new().create(true)
- .read(true)
- .write(true)
- .open(&path)?;
- Ok(Device {
- name: name.to_owned(),
- fd: fd,
- path: path,
- is_dummy: true,
- rw_count: 0,
- })
- }
-
- /// Reads a frame from the device, returns the number of bytes read
- pub fn read(&mut self, mut buffer: &mut [u8]) -> WgResult<usize> {
- // Increment the read/write count
- self.increment_rw_count();
-
- // Read from the file descriptor
- Ok(self.fd.read(&mut buffer)?)
- }
-
- /// Write a frame to the device
- pub fn write(&mut self, data: &[u8]) -> WgResult<usize> {
- // Increment the read/write count
- self.increment_rw_count();
-
- // Write the data
- let size = self.fd.write(data)?;
-
- // Flush the device file descriptor
- self.fd.flush()?;
-
- Ok(size)
- }
-
- /// Increment the read/write count
- fn increment_rw_count(&mut self) {
- self.rw_count = self.rw_count.saturating_add(1);
- }
-
- /// Flush the device
- pub fn flush(&mut self) -> WgResult<()> {
- Ok(self.fd.flush()?)
- }
-
- /// Returns `true` if the device is a dummy
- pub fn is_dummy(&self) -> bool {
- self.is_dummy
- }
-
- /// Returns the device name
- pub fn get_name(&self) -> &str {
- self.name.as_str()
- }
-
- /// Returns the read/write counter of the device
- pub fn get_rw_count(&self) -> u64 {
- self.rw_count
- }
-
- /// Returns a reference to the internal file descriptor
- pub fn get_fd(&self) -> &File {
- &self.fd
- }
-
- /// Returns a reference to the path of the file
- pub fn get_path(&self) -> &Path {
- &self.path
- }
-}
diff --git a/src/lib.rs b/src/lib.rs
index c314041..7a6a6de 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -10,11 +10,10 @@ extern crate libc;
#[macro_use]
mod error;
-mod device;
-mod bindgen;
+mod uapi;
-pub use device::Device;
pub use error::{WgResult, WgError};
+use uapi::{WgDevice, WgIpMask, WgPeer};
use std::ffi::CString;
use std::fs::{create_dir, remove_file};
@@ -153,9 +152,9 @@ impl WireGuard {
// 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;
+ let wgdev_size = size_of::<WgDevice>() as isize;
+ let wgpeer_size = size_of::<WgPeer>() as isize;
+ let wgipmask_size = size_of::<WgIpMask>() as isize;
// Otherwise, we "set" the received wgdevice and send back the return status.
// Check the message size
@@ -164,12 +163,12 @@ impl WireGuard {
bail!("Message size too small.")
}
- device = buffer as *mut bindgen::wgdevice;
+ device = buffer as *mut 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 {
+ let mut peer = device.offset(wgdev_size) as *mut WgPeer;
+ for _ in 0..*(*device).peers.num_peers.as_ref() {
// Calculate the current peer
let peer_offset = wgpeer_size + wgipmask_size * (*peer).num_ipmasks as isize;
peer = peer.offset(peer_offset);
diff --git a/src/uapi.rs b/src/uapi.rs
new file mode 100644
index 0000000..85afb91
--- /dev/null
+++ b/src/uapi.rs
@@ -0,0 +1,163 @@
+//! Mapping to the `WireGuard` user API
+
+#![allow(dead_code)]
+
+use std::convert::{AsMut, AsRef};
+use std::fmt::{Debug, Result, Formatter};
+use std::marker::PhantomData;
+use std::mem::transmute;
+
+use libc::{in_addr, in6_addr, sockaddr, sockaddr_in, sockaddr_in6, timeval};
+
+const IFNAMSIZ: usize = 16;
+const WG_KEY_LEN: usize = 32;
+
+#[repr(C)]
+#[derive(Clone)]
+/// Represents a union field
+pub struct UnionField<T>(PhantomData<T>);
+
+impl<T> UnionField<T> {
+ /// Creates a new `UnionField`
+ pub fn new() -> Self {
+ UnionField(PhantomData)
+ }
+}
+
+impl<T: Clone> Copy for UnionField<T> {}
+
+impl<T> AsRef<T> for UnionField<T> {
+ fn as_ref(&self) -> &T {
+ unsafe { transmute(self) }
+ }
+}
+
+impl<T> AsMut<T> for UnionField<T> {
+ fn as_mut(&mut self) -> &mut T {
+ unsafe { transmute(self) }
+ }
+}
+
+
+impl<T> Debug for UnionField<T> {
+ fn fmt(&self, fmt: &mut Formatter) -> Result {
+ fmt.write_str("Union")
+ }
+}
+
+#[repr(C)]
+#[derive(Debug, Clone, Copy)]
+/// A `WireGuard` device
+pub struct WgDevice {
+ /// The name of the interface
+ pub interface: [u8; IFNAMSIZ],
+
+ /// Interface flags
+ pub flags: u32,
+
+ /// The `WireGuard` public key
+ pub public_key: [u8; WG_KEY_LEN],
+
+ /// The `WireGuard` private key
+ pub private_key: [u8; WG_KEY_LEN],
+
+ /// The `WireGuard` pre-shared key
+ pub preshared_key: [u8; WG_KEY_LEN],
+
+ /// The wirewall mark
+ pub fwmark: u32,
+
+ /// The port of the device
+ pub port: u16,
+
+ /// The peers
+ pub peers: Peers,
+}
+
+#[repr(C)]
+#[derive(Debug, Clone, Copy)]
+/// `WireGuard` peer union
+pub struct Peers {
+ /// The number of peers
+ pub num_peers: UnionField<u16>,
+
+ /// The overall peer size
+ pub peers_size: UnionField<u32>,
+
+ /// The union field size as placeholder
+ pub union_size: u32,
+}
+
+#[repr(C)]
+#[derive(Debug, Clone, Copy)]
+/// A `WireGuard` IP mask
+pub struct WgIpMask {
+ /// The network family
+ pub family: i32,
+
+ /// The network address
+ pub addr: Addr,
+
+ /// Classless Inter-Domain Routing
+ pub cidr: u8,
+}
+
+#[repr(C)]
+#[derive(Debug, Clone, Copy)]
+/// A `WireGuard` network address
+pub struct Addr {
+ /// IP version 4
+ pub ip4: UnionField<in_addr>,
+
+ /// IP version 6
+ pub ip6: UnionField<in6_addr>,
+
+ /// The union field size as placeholder
+ pub union_size: [u32; 4usize],
+}
+
+#[repr(C)]
+#[derive(Clone, Copy)]
+/// A `WireGuard` peer
+pub struct WgPeer {
+ /// The public key
+ pub public_key: [u8; 32usize],
+
+ /// Set flags for the peer
+ pub flags: u32,
+
+ /// The endpoint of the peer
+ pub endpoint: WgEndpoint,
+
+ /// Time of the last handshake
+ pub last_handshake_time: timeval,
+
+ /// Received bytes
+ pub rx_bytes: u64,
+
+ /// Sent bytes
+ pub tx_bytes: u64,
+
+ /// The persistent keep alive interval
+ pub persistent_keepalive_interval: u16,
+
+ /// The amount of IP masks
+ pub num_ipmasks: u16,
+}
+
+#[repr(C)]
+#[derive(Debug, Clone, Copy)]
+/// A `WireGuard` endpoint type
+pub struct WgEndpoint {
+ /// The socket address
+ pub addr: UnionField<sockaddr>,
+
+ /// The IPv4 socket address
+ pub addr4: UnionField<sockaddr_in>,
+
+ /// The IPv6 socket address
+ pub addr6: UnionField<sockaddr_in6>,
+
+ /// The union field size as placeholder
+ pub union_size: [u32; 7usize],
+}
diff --git a/src/wireguard b/src/wireguard
deleted file mode 160000
-Subproject 0ca9047b783d661c455c43e97fbac0d18d5811f
diff --git a/tests/device.rs b/tests/device.rs
deleted file mode 100644
index c5f2c96..0000000
--- a/tests/device.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-extern crate wireguard;
-
-use wireguard::Device;
-
-use std::io::Write;
-use std::fs::OpenOptions;
-
-#[test]
-fn success_dummy() {
- // Create a dummy device
- let name = "test_1";
- let dummy = Device::dummy(name).expect("Could not create dummy device");
-
- // Check the defaults
- assert!(dummy.is_dummy());
- assert_eq!(dummy.get_name(), name);
- assert_eq!(dummy.get_rw_count(), 0);
- println!("Dummy: {:?}", dummy);
-}
-
-#[test]
-fn success_read_write() {
- // Create a dummy device and reset it
- let mut dummy = Device::dummy("test_2").expect("Could not create dummy device");
- dummy.get_fd().set_len(0).expect("Could not reset dummy file");
-
- // Check the defaults
- assert_eq!(dummy.get_rw_count(), 0);
- assert!(dummy.flush().is_ok());
-
- // Write to the dummy
- let test_data = b"test string";
- assert!(dummy.write(test_data).is_ok());
- assert_eq!(dummy.get_rw_count(), 1);
- assert!(dummy.flush().is_ok());
-
- // Write from outside to the dummy
- let mut file = OpenOptions::new().append(true).open(dummy.get_path()).expect("Could not open dummy device file");
- file.write_all(test_data).expect("Could not write to file via file descriptor");
-
- // Read from the dummy
- let mut buffer = vec![0; 100];
- assert_eq!(dummy.read(&mut buffer).expect("Could not read from dummy device"), test_data.len());
- assert_eq!(&buffer[..test_data.len()], test_data);
- assert_eq!(dummy.get_rw_count(), 2);
- assert!(dummy.flush().is_ok());
-}