From 5322403165916edc8fcd1173a2366e6227727a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=BCke?= Date: Fri, 10 Nov 2023 12:19:40 +0100 Subject: [PATCH] refactor: clean up a bit add more docs --- Cargo.lock | 10 +- wgbind/Cargo.toml | 2 +- wgbind/src/lib.rs | 177 ++++++----------------------- wgbind/src/wireguard_device.rs | 197 +++++++++++++++++++++++++++++++++ wgbindraw-sys/build.rs | 1 + 5 files changed, 235 insertions(+), 152 deletions(-) create mode 100644 wgbind/src/wireguard_device.rs diff --git a/Cargo.lock b/Cargo.lock index 68e3f2a..82a0429 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -281,17 +281,15 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "wgbind" -version = "0.2.0" +version = "0.2.2" dependencies = [ "libc", - "wgbindraw-sys 0.2.0", + "wgbindraw-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wgbindraw-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12d59781529f0b645d771237df46cee95200761a3edf30111b18f5f1f7f9dd1d" +version = "0.2.1" dependencies = [ "bindgen", "cc", @@ -301,6 +299,8 @@ dependencies = [ [[package]] name = "wgbindraw-sys" version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab86e65125a5db6a6cc5ad0688461236882822fecb195a73c9b858c1b38ce4f4" dependencies = [ "bindgen", "cc", diff --git a/wgbind/Cargo.toml b/wgbind/Cargo.toml index 01ceaa6..c34629d 100644 --- a/wgbind/Cargo.toml +++ b/wgbind/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wgbind" -version = "0.2.1" +version = "0.2.2" edition = "2021" license = "MIT" authors = ["Johannes Lüke"] diff --git a/wgbind/src/lib.rs b/wgbind/src/lib.rs index 9dbafb1..b21fdea 100644 --- a/wgbind/src/lib.rs +++ b/wgbind/src/lib.rs @@ -1,3 +1,11 @@ +//! Wrapper around the wireguard c library originating from Jason A. Donenfeld +//! +//! Provides an abstraction around the c ffi bindings. This should allow to invoke +//! Wireguard function within safe rust code. +//! Be aware to run these methods the programm requires the priviliges to change your +//! network settings. Most likely root rights! otherwise calling the methods will fail. +//! +//! The same is true if you attempt to run any tests. #![crate_name = "wgbind"] use std::{alloc::Layout, ffi::CString}; @@ -7,6 +15,8 @@ extern crate wgbindraw_sys; use wgbindraw_sys::*; +pub mod wireguard_device; +use wireguard_device::{WireguardDevice,WireguardControl}; unsafe fn determine_length( mut ptr : *mut i8) -> usize { @@ -125,7 +135,7 @@ pub fn add_device(device_name: &str) -> Result<(),std::io::Error>{ } -/// . +/// Removes a wireguard network interface device pub fn delete_device(device_name: &str) -> Result<(),std::io::Error>{ let name = CString::new(device_name).unwrap().into_raw().cast() as *const ::std::os::raw::c_char ; let result = unsafe{ wg_del_device(name)}; @@ -138,7 +148,16 @@ pub fn delete_device(device_name: &str) -> Result<(),std::io::Error>{ } -/// . +/// Gets a new wg_device +/// +/// allocates a new object and fills it with the necessary data from the wg interface +/// the device_name must match an network interface of type wireguard! +/// +/// # Arguments +/// +/// * `name` - Name of the Network Interface e.g. wg0 +/// +/// pub fn get_device(device_name: &str) -> Result{ let name = CString::new(device_name).unwrap().into_raw().cast() as *const ::std::os::raw::c_char ; //let structsize = std::mem::size_of::()+ std::mem::size_of::()*2; @@ -161,141 +180,6 @@ pub fn get_device(device_name: &str) -> Result{ } -/// # WireguardDevice -/// -/// holds configuration data for a Wireguard Device. -/// if this object drops, the associated strings get -/// lost, if the wireguard implementation depends on these -/// string values, that might cause significant problems !!! -/// -/// -#[derive(Debug)] -pub struct WireguardDevice { - raw_device : Box<::core::ffi::c_void>, - name : &'static str, - flags: wg_device_flags, - fwmark: u32, - private_key: Option<&'static str>, - public_key: Option<&'static str>, -} - - - -impl WireguardDevice { - pub fn new(device : Box<::core::ffi::c_void>,name: &'static str, flags: wg_device_flags, fwmark: u32, private_key: Option<&'static str>, public_key: Option<&'static str>) -> Self { - Self { raw_device: device, name, flags, fwmark, private_key, public_key, } - } - - pub fn private_key(&self) -> Option<&str> { - self.private_key - } - - pub fn public_key(&self) -> Option<&str> { - self.public_key - } - - pub fn name(&self) -> &str { - self.name - } - - pub fn set_name(&mut self, name: &'static str) { - self.name = name; - } - - pub fn flags(&self) -> wg_device_flags { - self.flags - } - - pub fn set_flags(&mut self, flags: wg_device_flags) { - self.flags = flags; - } - - pub fn fwmark(&self) -> u32 { - self.fwmark - } - - pub fn set_fwmark(&mut self, fwmark: u32) { - self.fwmark = fwmark; - } -} - -impl Into for WireguardDevice{ - fn into(self) -> wg_device { - todo!() - } -} - -impl Into for wg_device{ - fn into(self) -> WireguardDevice { - todo!() - } -} - - -impl Into<*mut wg_device> for WireguardDevice{ - fn into(self) -> *mut wg_device { - todo!() - } -} - -impl Into<&mut WireguardDevice> for wg_device { - fn into(self) -> &'static mut WireguardDevice { - todo!() - } -} - - -impl Drop for WireguardDevice { - fn drop(&mut self) { - free_device(self); - } -} - - - -impl WireguardControl for WireguardDevice{ - fn create_interface(&self)-> Result<(),std::io::Error> { - return add_device(self.name) - } - - fn remove_interface(&self) -> Result<(),std::io::Error> { - todo!() - } - - fn update_device(&mut self) -> Result<(),std::io::Error> { - let result = get_device(self.name); - *self = result.unwrap().into(); - - Ok(()) - } - - fn refresh_device(&mut self) -> Result<(), std::io::Error> { - - set_device(self) - } - - fn raw_device_handler(&self) -> &Box { - &self.raw_device - } -} - -trait WireguardControl { - fn create_interface(&self) -> Result<(),std::io::Error>; - fn remove_interface(&self) -> Result<(),std::io::Error>; - - /// writes to the kernal - fn update_device(&mut self) -> Result<(),std::io::Error>; - - /// Read from the kernel - fn refresh_device(&mut self) -> Result<(), std::io::Error>; - - fn raw_device_handler(&self) -> &Box<::core::ffi::c_void>; - - fn raw_device_ptr(&self) -> *mut wg_device { - let ptr = &* *self.raw_device_handler() as *const ::core::ffi::c_void; - ptr.cast_mut() as *mut wg_device - } -} /// Set a new wireguard device - not a network interface /// @@ -314,7 +198,7 @@ pub fn set_device(device : &mut WireguardDevice) -> Result<(), std::io::Error> { // If the wireguard device has already a raw device then simply us that pointer // only if the pointer is NULL skip this and create new raw device if raw_ptr.is_null() == false{ - let error = unsafe { wg_set_device(raw_ptr)}; + let error = unsafe { wg_set_device(raw_ptr.cast_mut())}; if error != 0 { return Err(std::io::Error::last_os_error()); @@ -326,7 +210,7 @@ pub fn set_device(device : &mut WireguardDevice) -> Result<(), std::io::Error> { // transform the name from &'static str into [i8;16]. The way to get there seems fucked up // not sure if this the best way let devicename = unsafe { - let devicename = CString::new(device.name).expect("CString::new failed"); + let devicename = CString::new(device.name().unwrap()).expect("CString::new failed"); let devicename = std::ffi::CStr::from_bytes_with_nul(devicename.to_bytes_with_nul()).expect("CStr::from_bytes_with_null failed"); let devicename = std::slice::from_raw_parts( devicename.as_ptr(), 16).as_ptr(); let devicename = *std::mem::transmute::<*const i8,&[i8;16]>(devicename); @@ -347,9 +231,9 @@ pub fn set_device(device : &mut WireguardDevice) -> Result<(), std::io::Error> { let wgdevice = Box::new(wg_device { name: devicename, ifindex: 0, - flags: device.flags, + flags: device.flags(), - fwmark: device.fwmark, + fwmark: device.fwmark(), listen_port: 51820, first_peer: firstpeer, @@ -364,10 +248,10 @@ pub fn set_device(device : &mut WireguardDevice) -> Result<(), std::io::Error> { // Because the pointer is of type c_void, the destructor of Box has no effect on the value // behind the pointer let raw_ptr = &* wgdevice as *const wg_device; - let handle = raw_ptr as *mut ::core::ffi::c_void; - device.raw_device = unsafe { Box::from_raw(handle) }; + let handle = raw_ptr as *const ::core::ffi::c_void; + device.raw_device = unsafe { Box::from(handle) }; - let error = unsafe { wg_set_device(device.raw_device_ptr())}; + let error = unsafe { wg_set_device(device.raw_device_ptr().cast_mut())}; if error != 0 { return Err(std::io::Error::last_os_error()); @@ -376,9 +260,10 @@ pub fn set_device(device : &mut WireguardDevice) -> Result<(), std::io::Error> { Ok(()) } - + +/// delete the wg_device allocated by get_device pub fn free_device(device: &mut WireguardDevice) { - unsafe {wg_free_device(device.raw_device_ptr())} + unsafe {wg_free_device(device.raw_device_ptr().cast_mut())} } #[cfg(test)] diff --git a/wgbind/src/wireguard_device.rs b/wgbind/src/wireguard_device.rs new file mode 100644 index 0000000..dc6408f --- /dev/null +++ b/wgbind/src/wireguard_device.rs @@ -0,0 +1,197 @@ + +use std::ffi::CStr; + +use super::*; + +extern crate wgbindraw_sys; +use wgbindraw_sys::*; + +/// # WireguardDevice +/// +/// holds configuration data for a Wireguard Device. +/// if this object drops, the associated strings get +/// lost, if the wireguard implementation depends on these +/// string values, that might cause significant problems !!! +/// +/// +#[derive(Debug)] +pub struct WireguardDevice { + pub raw_device : Box<*const::core::ffi::c_void>, + +} + + +/// trait to bind functionailty directly to an instance +/// of WireguardDevice +/// +/// +pub trait WireguardControl { + + /// Creates new network interface and hence a new wg_device indirectly + fn create_interface(&self, name: &str) -> Result<(),std::io::Error>; + + /// deletes a network interface basically dropping everything + fn remove_interface(&mut self) -> Result<(),std::io::Error>; + + /// writes to the kernal + fn update_device(&mut self) -> Result<(),std::io::Error>; + + /// Read from the kernel + fn refresh_device(&mut self) -> Result<(), std::io::Error>; + + fn raw_device_handler(&self) -> &Box<*const ::core::ffi::c_void>; + + fn raw_device_ptr(&self) -> *const wg_device { + let ptr = **self.raw_device_handler(); + ptr.cast() + } +} + +/// converts any raw wg_device into a managed WireguardDevice +impl From<*mut wg_device> for WireguardDevice{ + fn from(value: *mut wg_device) -> Self { + let handler = unsafe{ &*value as *const wg_device }; + let handler = handler as * const ::core::ffi::c_void; + let handler = unsafe{ Box::new( + handler + )}; + + WireguardDevice::new( + handler + ) + } +} + + +impl WireguardDevice { + pub fn new(device : Box<*const ::core::ffi::c_void>) -> Self { + Self { + raw_device: device + } + } + + pub fn private_key(&self) -> Option<&str> { + let pk = unsafe { self.raw_device_ptr().as_ref().unwrap().private_key }.as_ptr(); + let pk = unsafe{std::slice::from_raw_parts(pk, 32)}; + let pk = CStr::from_bytes_until_nul(pk); + + if pk.is_ok() { + let pk = pk.unwrap(); + let pk = pk.to_str().unwrap(); + return Some(pk); + } + + None + } + + pub fn public_key(&self) -> Option<&str> { + let pubk = unsafe { self.raw_device_ptr().as_ref().unwrap().public_key }.as_ptr(); + + let pubk = unsafe{std::slice::from_raw_parts(pubk, 32)}; + + let pubk = CStr::from_bytes_until_nul(pubk); + + if pubk.is_ok() { + let pubk = pubk.unwrap(); + let pubk = pubk.to_str().unwrap(); + return Some(pubk); + } + + None + } + + pub fn name(&self) -> Option<&str> { + let pk = unsafe { self.raw_device_ptr().as_ref().unwrap().name }.as_ptr() as *const u8; + let pk = unsafe{std::slice::from_raw_parts(pk, 16)}; + let pk = CStr::from_bytes_until_nul(pk); + + if pk.is_ok() { + let pk = pk.unwrap(); + let pk = pk.to_str().unwrap(); + return Some(pk); + } + + None + } + + + pub fn flags(&self) -> wg_device_flags { + unsafe { self.raw_device_ptr().as_ref().unwrap().flags }.clone() + } + + pub fn fwmark(&self) -> u32 { + unsafe { self.raw_device_ptr().as_ref().unwrap().fwmark }.clone() + } + +} + +impl Into for WireguardDevice{ + fn into(self) -> wg_device { + todo!() + } +} + +impl Into for wg_device{ + fn into(self) -> WireguardDevice { + todo!() + } +} + + +impl Into<*mut wg_device> for WireguardDevice{ + fn into(self) -> *mut wg_device { + todo!() + } +} + +impl Into<&mut WireguardDevice> for wg_device { + fn into(self) -> &'static mut WireguardDevice { + todo!() + } +} + + +impl Drop for WireguardDevice { + fn drop(&mut self) { + free_device(self); + } +} + + + +impl WireguardControl for WireguardDevice where Self:Drop{ + fn create_interface(&self, name : &str)-> Result<(),std::io::Error> { + return add_device(name); + } + + fn remove_interface(&mut self) -> Result<(),std::io::Error> { + + let res = delete_device(self.name().unwrap()); + if res.is_ok() { + free_device(self); + return Ok(()); + } + + res.into() + } + + fn update_device(&mut self) -> Result<(),std::io::Error> { + let result = get_device(self.name().unwrap()); + if result.is_ok() { + *self = result.unwrap().into(); + + return Ok(()); + } + + Err(result.unwrap_err()) + } + + fn refresh_device(&mut self) -> Result<(), std::io::Error> { + + set_device(self) + } + + fn raw_device_handler(&self) -> &Box<*const ::core::ffi::c_void> { + &self.raw_device + } +} diff --git a/wgbindraw-sys/build.rs b/wgbindraw-sys/build.rs index 6d0c369..3384ad3 100644 --- a/wgbindraw-sys/build.rs +++ b/wgbindraw-sys/build.rs @@ -42,6 +42,7 @@ fn main() { // .must_use_type("bool") // .must_use_type("char") // .must_use_type(r"char \*") + .allowlist_function("wg_.*") .bitfield_enum("wg_peer_flags") .bitfield_enum("wg_device_flags")