diff --git a/Cargo.lock b/Cargo.lock index 774cd4c..7f35e26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,9 +27,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220" [[package]] name = "anstyle-parse" @@ -151,7 +151,7 @@ dependencies = [ [[package]] name = "defguard_wireguard_rs" -version = "0.4.0" +version = "0.4.1" dependencies = [ "base64", "env_logger", @@ -181,9 +181,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eeb342678d785662fd2514be38c459bb925f02b68dd2a3e0f21d7ef82d979dd" +checksum = "05e7cf40684ae96ade6232ed84582f40ce0a66efcd43a5117aef610534f8e0b8" dependencies = [ "anstream", "anstyle", @@ -194,9 +194,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" +checksum = "1676f435fc1dadde4d03e43f5d62b259e1ce5f40bd4ffb21db2b42ebe59c1382" [[package]] name = "getrandom" @@ -217,9 +217,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "libc" -version = "0.2.152" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "log" @@ -381,9 +381,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", @@ -413,18 +413,18 @@ checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.195" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 0d1cfbe..bc74aba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "defguard_wireguard_rs" -version = "0.4.0" +version = "0.4.1" edition = "2021" description = "A unified multi-platform high-level API for managing WireGuard interfaces" license = "Apache-2.0" diff --git a/examples/userspace.rs b/examples/userspace.rs index 650fbdd..74a2b82 100644 --- a/examples/userspace.rs +++ b/examples/userspace.rs @@ -1,6 +1,6 @@ -#[cfg(target_os = "mac_os")] -use defguard_wireguard_rs::WireguardApiUserspace; use defguard_wireguard_rs::{host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration}; +#[cfg(target_os = "macos")] +use defguard_wireguard_rs::{WireguardApiUserspace, WireguardInterfaceApi}; use std::{ io::{stdin, stdout, Read, Write}, net::SocketAddr, @@ -15,7 +15,7 @@ fn pause() { stdin().read_exact(&mut [0]).unwrap(); } -#[cfg(target_os = "mac_os")] +#[cfg(target_os = "macos")] fn main() -> Result<(), Box> { // Setup API struct for interface management let ifname: String = if cfg!(target_os = "linux") || cfg!(target_os = "freebsd") { @@ -35,7 +35,7 @@ fn main() -> Result<(), Box> { let peer_key: Key = key.as_ref().try_into().unwrap(); let mut peer = Peer::new(peer_key.clone()); - log::info!("endpoint"); + println!("endpoint"); // Your WireGuard server endpoint which peer connects too let endpoint: SocketAddr = "10.20.30.40:55001".parse().unwrap(); // Peer endpoint and interval @@ -73,5 +73,5 @@ fn main() -> Result<(), Box> { Ok(()) } -#[cfg(not(mac_os))] +#[cfg(not(target_os = "macos"))] fn main() {} diff --git a/src/bsd/ifconfig.rs b/src/bsd/ifconfig.rs index 3ea3544..b1485b7 100644 --- a/src/bsd/ifconfig.rs +++ b/src/bsd/ifconfig.rs @@ -50,7 +50,11 @@ impl IfReq { .for_each(|(i, b)| ifr_name[i] = b); // First, try to load a kernel module for this type of network interface. - let mod_name = format!("if_{if_name}"); + // Omit digits at the end of interface name, e.g. "wg0" -> "if_wg". + let index = if_name + .find(|c: char| c.is_ascii_digit()) + .unwrap_or(if_name.len()); + let mod_name = format!("if_{}", &if_name[0..index]); unsafe { // Ignore the return value for the time being. // Do the cast because `c_char` differs across platforms. diff --git a/src/bsd/wgio.rs b/src/bsd/wgio.rs index 2dd9c08..88e4621 100644 --- a/src/bsd/wgio.rs +++ b/src/bsd/wgio.rs @@ -62,11 +62,17 @@ impl WgDataIo { let socket = create_socket(AddressFamily::Unix).map_err(IoError::ReadIo)?; unsafe { // First do ioctl with empty `wg_data` to obtain buffer size. - read_wireguard_data(socket.as_raw_fd(), self).map_err(IoError::ReadIo)?; + if let Err(err) = read_wireguard_data(socket.as_raw_fd(), self) { + error!("WgDataIo first read error {err}"); + return Err(IoError::ReadIo(err)); + } // Allocate buffer. self.alloc_data()?; // Second call to ioctl with allocated buffer. - read_wireguard_data(socket.as_raw_fd(), self).map_err(IoError::ReadIo)?; + if let Err(err) = read_wireguard_data(socket.as_raw_fd(), self) { + error!("WgDataIo second read error {err}"); + return Err(IoError::ReadIo(err)); + } } Ok(()) @@ -75,7 +81,10 @@ impl WgDataIo { pub(super) fn write_data(&mut self) -> Result<(), IoError> { let socket = create_socket(AddressFamily::Unix).map_err(IoError::WriteIo)?; unsafe { - write_wireguard_data(socket.as_raw_fd(), self).map_err(IoError::WriteIo)?; + if let Err(err) = write_wireguard_data(socket.as_raw_fd(), self) { + error!("WgDataIo write error {err}"); + return Err(IoError::WriteIo(err)); + } } Ok(()) diff --git a/src/key.rs b/src/key.rs index 1979bc3..1b5d2ab 100644 --- a/src/key.rs +++ b/src/key.rs @@ -1,7 +1,7 @@ //! Public key utilities use std::{ - error, fmt, + fmt, hash::{Hash, Hasher}, str::FromStr, }; @@ -11,29 +11,21 @@ use serde::{Deserialize, Serialize}; const KEY_LENGTH: usize = 32; +/// Returns value of hex digit, if possible. +fn hex_value(char: u8) -> Option { + match char { + b'A'..=b'F' => Some(char - b'A' + 10), + b'a'..=b'f' => Some(char - b'a' + 10), + b'0'..=b'9' => Some(char - b'0'), + _ => None, + } +} + /// WireGuard key representation in binary form. #[derive(Clone, Default, Serialize, Deserialize)] +#[serde(try_from = "&str")] pub struct Key([u8; KEY_LENGTH]); -#[derive(Debug)] -pub enum KeyError { - InvalidCharacter(u8), - InvalidStringLength(usize), -} - -impl error::Error for KeyError {} - -impl fmt::Display for KeyError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::InvalidCharacter(char) => { - write!(f, "Invalid character {char}") - } - Self::InvalidStringLength(length) => write!(f, "Invalid string length {length}"), - } - } -} - impl Key { /// Create a new key from buffer. #[must_use] @@ -71,28 +63,22 @@ impl Key { /// Converts a text string of hexadecimal digits to `Key`. /// /// # Errors - /// Will return `KeyError` if text string has wrong length, + /// Will return `DecodeError` if text string has wrong length, /// or contains an invalid character. - pub fn decode>(hex: T) -> Result { + pub fn decode>(hex: T) -> Result { let hex = hex.as_ref(); - let length = hex.len(); - if length != 64 { - return Err(KeyError::InvalidStringLength(length)); + if hex.len() != KEY_LENGTH * 2 { + return Err(DecodeError::InvalidLength); } - let hex_value = |char: u8| -> Result { - match char { - b'A'..=b'F' => Ok(char - b'A' + 10), - b'a'..=b'f' => Ok(char - b'a' + 10), - b'0'..=b'9' => Ok(char - b'0'), - _ => Err(KeyError::InvalidCharacter(char)), - } - }; - let mut key = [0; KEY_LENGTH]; for (index, chunk) in hex.chunks(2).enumerate() { - let msd = hex_value(chunk[0])?; - let lsd = hex_value(chunk[1])?; + let Some(msd) = hex_value(chunk[0]) else { + return Err(DecodeError::InvalidByte(index, chunk[0])); + }; + let Some(lsd) = hex_value(chunk[1]) else { + return Err(DecodeError::InvalidByte(index, chunk[1])); + }; key[index] = msd << 4 | lsd; } Ok(Self(key)) @@ -102,13 +88,20 @@ impl Key { impl TryFrom<&str> for Key { type Error = DecodeError; + /// Try to decode `Key` from base16 or base64 encoded string. fn try_from(value: &str) -> Result { - let v = BASE64_STANDARD.decode(value)?; - if v.len() == KEY_LENGTH { - let buf = v.try_into().map_err(|_| Self::Error::InvalidLength)?; - Ok(Self::new(buf)) + if value.len() == KEY_LENGTH * 2 { + // Try base16 + Key::decode(value) } else { - Err(Self::Error::InvalidLength) + // Try base64 + let v = BASE64_STANDARD.decode(value)?; + if v.len() == KEY_LENGTH { + let buf = v.try_into().map_err(|_| Self::Error::InvalidLength)?; + Ok(Self::new(buf)) + } else { + Err(Self::Error::InvalidLength) + } } } } diff --git a/src/wgapi.rs b/src/wgapi.rs index 63bfb01..91e3e1d 100644 --- a/src/wgapi.rs +++ b/src/wgapi.rs @@ -45,7 +45,12 @@ impl WGApi { #[cfg(target_os = "freebsd")] return Ok(Self(Box::new(WireguardApiFreebsd::new(ifname)))); - #[cfg(not(any(target_os = "linux", target_os = "freebsd")))] + #[cfg(not(any( + target_os = "linux", + target_os = "freebsd", + target_os = "macos", + target_os = "windows" + )))] Err(WireguardInterfaceError::KernelNotSupported) } } diff --git a/src/wgapi_freebsd.rs b/src/wgapi_freebsd.rs index 0e86b88..6576550 100644 --- a/src/wgapi_freebsd.rs +++ b/src/wgapi_freebsd.rs @@ -9,7 +9,7 @@ use crate::{ /// Manages interfaces created with FreeBSD kernel WireGuard module. /// -/// Requires FreeBSD version 14+. +/// Requires FreeBSD version 13+. #[derive(Clone)] pub struct WireguardApiFreebsd { ifname: String,