diff options
author | Sascha Grunert <mail@saschagrunert.de> | 2017-02-23 16:48:01 +0100 |
---|---|---|
committer | Sascha Grunert <mail@saschagrunert.de> | 2017-02-23 16:48:01 +0100 |
commit | f0f7cc8c9084237056f63918a6b5428e9ac5d944 (patch) | |
tree | 0ae9b1e2bbd7a826ffa4beb6d917ebb6ea1de26d | |
parent | Using the libc ioctl (diff) | |
download | wireguard-rs-f0f7cc8c9084237056f63918a6b5428e9ac5d944.tar.xz wireguard-rs-f0f7cc8c9084237056f63918a6b5428e9ac5d944.zip |
Removed bindgen, added uapi bindings by hand
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | .travis.yml | 5 | ||||
-rw-r--r-- | Cargo.toml | 4 | ||||
-rw-r--r-- | build.rs | 40 | ||||
-rwxr-xr-x | ci/before_install.sh | 40 | ||||
-rw-r--r-- | src/bindgen.rs | 34 | ||||
-rw-r--r-- | src/device.rs | 146 | ||||
-rw-r--r-- | src/lib.rs | 17 | ||||
-rw-r--r-- | src/uapi.rs | 163 | ||||
m--------- | src/wireguard | 0 | ||||
-rw-r--r-- | tests/device.rs | 47 |
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= @@ -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 - } -} @@ -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()); -} |