diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0f10b67..d89da1a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,12 +5,12 @@ on: branches: - main paths-ignore: - - 'LICENSE' + - "LICENSE" pull_request: branches: - main paths-ignore: - - 'LICENSE' + - "LICENSE" env: CARGO_TERM_COLOR: always @@ -18,7 +18,7 @@ env: jobs: test: runs-on: [self-hosted, Linux] - container: rust:1.75 + container: rust:1.80 steps: - name: Debug diff --git a/Cargo.lock b/Cargo.lock index 3d8502f..e881823 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -28,33 +28,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", "windows-sys", @@ -62,9 +62,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "autocfg" @@ -92,9 +92,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cfg-if" @@ -110,15 +110,15 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -151,7 +151,7 @@ dependencies = [ [[package]] name = "defguard_wireguard_rs" -version = "0.5.5" +version = "0.6.0" dependencies = [ "base64", "env_logger", @@ -165,7 +165,8 @@ dependencies = [ "netlink-sys", "nix", "serde", - "thiserror", + "serde_test", + "thiserror 2.0.6", "x25519-dalek", ] @@ -223,9 +224,9 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "log" @@ -295,7 +296,7 @@ dependencies = [ "anyhow", "byteorder", "paste", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -314,9 +315,9 @@ dependencies = [ [[package]] name = "netlink-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" +checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23" dependencies = [ "bytes", "libc", @@ -344,9 +345,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -371,9 +372,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -383,9 +384,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -415,24 +416,33 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "serde_test" +version = "1.0.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed" +dependencies = [ + "serde", +] + [[package]] name = "subtle" version = "2.6.1" @@ -441,9 +451,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.79" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -452,18 +462,38 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" +dependencies = [ + "thiserror-impl 2.0.6", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" dependencies = [ "proc-macro2", "quote", @@ -472,9 +502,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "utf8parse" @@ -490,9 +520,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] diff --git a/Cargo.toml b/Cargo.toml index 77866dd..a2c3724 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,8 @@ [package] name = "defguard_wireguard_rs" -version = "0.5.5" +version = "0.6.0" edition = "2021" +rust-version = "1.80" description = "A unified multi-platform high-level API for managing WireGuard interfaces" license = "Apache-2.0" readme = "README.md" @@ -13,12 +14,13 @@ categories = ["network-programming"] [dependencies] base64 = "0.22" log = "0.4" -serde = { version = "1.0", features = ["derive"] } -thiserror = "1.0" +serde = { version = "1.0", features = ["derive"], optional = true } +thiserror = "2.0" +x25519-dalek = { version = "2.0", features = ["getrandom", "static_secrets"] } [dev-dependencies] env_logger = "0.11" -x25519-dalek = { version = "2.0", features = ["getrandom", "static_secrets"] } +serde_test = "1.0" [target.'cfg(target_os = "freebsd")'.dependencies] libc = { version = "0.2", default-features = false } @@ -40,6 +42,11 @@ netlink-packet-utils = "0.5" netlink-packet-wireguard = "0.2" netlink-sys = "0.8" +[features] +default = ["serde"] +check_dependencies = [] +serde = ["dep:serde"] + [profile.release] lto = "thin" strip = "symbols" diff --git a/src/bsd/nvlist.rs b/src/bsd/nvlist.rs index a064903..ef2deb0 100644 --- a/src/bsd/nvlist.rs +++ b/src/bsd/nvlist.rs @@ -78,7 +78,7 @@ pub enum NvValue<'a> { // NvListAUp, } -impl<'a> NvValue<'a> { +impl NvValue<'_> { /// Return number of bytes this value occupies when packed. #[must_use] pub fn byte_size(&self) -> usize { @@ -162,7 +162,7 @@ pub struct NvList<'a> { is_big_endian: bool, } -impl<'a> Default for NvList<'a> { +impl Default for NvList<'_> { fn default() -> Self { Self::new() } diff --git a/src/dependencies.rs b/src/dependencies.rs index 40308f3..832e008 100644 --- a/src/dependencies.rs +++ b/src/dependencies.rs @@ -20,34 +20,31 @@ pub(crate) fn check_external_dependencies() -> Result<(), WireguardInterfaceErro "Environment variable `PATH` not found".into(), ))?; - // Find the missing command to provide a more informative error message later + // Find the missing command to provide a more informative error message later. let missing = COMMANDS.iter().find(|cmd| { - env::split_paths(&paths) - .find(|dir| { - trace!("Trying to find {cmd} in {dir:?}"); - match dir.join(cmd).try_exists() { - Ok(true) => { - debug!("{cmd} found in {dir:?}"); - true - } - Ok(false) => { - trace!("{cmd} not found in {dir:?}"); - false - } - Err(err) => { - warn!("Error while checking for {cmd} in {dir:?}: {err}"); - false - } + !env::split_paths(&paths).any(|dir| { + trace!("Trying to find {cmd} in {dir:?}"); + match dir.join(cmd).try_exists() { + Ok(true) => { + debug!("{cmd} found in {dir:?}"); + true } - }) - .is_none() + Ok(false) => { + trace!("{cmd} not found in {dir:?}"); + false + } + Err(err) => { + warn!("Error while checking for {cmd} in {dir:?}: {err}"); + false + } + } + }) }); if let Some(cmd) = missing { - return Err(WireguardInterfaceError::MissingDependency(format!( - "Command `{}` required by wireguard-rs couldn't be found. The following directories were checked: {paths:?}", - cmd - ))); + Err(WireguardInterfaceError::MissingDependency(format!( + "Command `{cmd}` required by wireguard-rs couldn't be found. The following directories were checked: {paths:?}" + ))) } else { debug!("All commands required by wireguard-rs are available"); Ok(()) diff --git a/src/host.rs b/src/host.rs index 5ef9b39..b20e749 100644 --- a/src/host.rs +++ b/src/host.rs @@ -14,12 +14,14 @@ use netlink_packet_wireguard::{ constants::{WGDEVICE_F_REPLACE_PEERS, WGPEER_F_REPLACE_ALLOWEDIPS}, nlas::{WgAllowedIpAttrs, WgDeviceAttrs, WgPeer, WgPeerAttrs}, }; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use crate::{error::WireguardInterfaceError, key::Key, net::IpAddrMask, utils::resolve}; /// WireGuard peer representation. -#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Peer { pub public_key: Key, pub preshared_key: Option, @@ -171,7 +173,8 @@ impl Peer { } /// WireGuard host representation. -#[derive(Default, Clone, Serialize, Deserialize)] +#[derive(Clone, Default)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Host { pub listen_port: u16, pub private_key: Option, diff --git a/src/key.rs b/src/key.rs index ef5b8ca..e317e76 100644 --- a/src/key.rs +++ b/src/key.rs @@ -7,7 +7,12 @@ use std::{ }; use base64::{prelude::BASE64_STANDARD, DecodeError, Engine}; -use serde::{Deserialize, Serialize}; +#[cfg(feature = "serde")] +use serde::{ + de::{Unexpected, Visitor}, + Deserialize, Deserializer, Serialize, Serializer, +}; +use x25519_dalek::{PublicKey, StaticSecret}; const KEY_LENGTH: usize = 32; @@ -22,8 +27,7 @@ fn hex_value(char: u8) -> Option { } /// WireGuard key representation in binary form. -#[derive(Clone, Default, Serialize, Deserialize)] -#[serde(try_from = "&str")] +#[derive(Clone, Default)] pub struct Key([u8; KEY_LENGTH]); impl Key { @@ -84,6 +88,18 @@ impl Key { } Ok(Self(key)) } + + /// Generate WireGuard private key. + #[must_use] + pub fn generate() -> Self { + Self(StaticSecret::random().to_bytes()) + } + + /// Make WireGuard public key from a private key. + #[must_use] + pub fn public_key(&self) -> Self { + Self(PublicKey::from(self.0).to_bytes()) + } } impl TryFrom<&str> for Key { @@ -128,15 +144,9 @@ impl TryFrom<&[u8]> for Key { impl FromStr for Key { type Err = DecodeError; + /// Try to decode `Key` from base16 or base64 encoded string. fn from_str(value: &str) -> Result { - let v = BASE64_STANDARD.decode(value)?; - let length = v.len(); - if length == KEY_LENGTH { - let buf = v.try_into().map_err(|_| Self::Err::InvalidLength(length))?; - Ok(Self::new(buf)) - } else { - Err(Self::Err::InvalidLength(length)) - } + value.try_into() } } @@ -166,45 +176,81 @@ impl fmt::Display for Key { } } +#[cfg(feature = "serde")] +impl Serialize for Key { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&BASE64_STANDARD.encode(self.0)) + } +} + +#[cfg(feature = "serde")] +struct KeyVisitor; + +#[cfg(feature = "serde")] +impl Visitor<'_> for KeyVisitor { + type Value = Key; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("32-bytes encoded as either base16 or base64") + } + + fn visit_str(self, s: &str) -> Result + where + E: serde::de::Error, + { + Key::try_from(s).map_err(|_| serde::de::Error::invalid_value(Unexpected::Str(s), &self)) + } +} + +#[cfg(feature = "serde")] +impl<'de> Deserialize<'de> for Key { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(KeyVisitor) + } +} + #[cfg(test)] mod tests { use super::*; + #[cfg(feature = "serde")] + use serde_test::{assert_tokens, Token}; + + // Same `Key` in different representations. + static KEY_B64: &str = "AAECAwQFBgcICQoLDA0OD/Dh0sO0pZaHeGlaSzwtHg8="; + static KEY_HEX: &str = "000102030405060708090a0b0c0d0e0ff0e1d2c3b4a5968778695a4b3c2d1e0f"; + static KEY_BUF: [u8; KEY_LENGTH] = [ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, + 0x1e, 0x0f, + ]; + #[test] fn decode_key() { - let key_str = "000102030405060708090a0b0c0d0e0ff0e1d2c3b4a5968778695a4b3c2d1e0f"; - let key = Key::decode(key_str).unwrap(); - assert_eq!( - key.0, - [ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, - 0x0e, 0x0f, 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b, - 0x3c, 0x2d, 0x1e, 0x0f - ] - ); - assert_eq!(key.to_lower_hex(), key_str); - assert_eq!( - format!("{key}"), - "AAECAwQFBgcICQoLDA0OD/Dh0sO0pZaHeGlaSzwtHg8=" - ); + let key = Key::decode(KEY_HEX).unwrap(); + assert_eq!(key.0, KEY_BUF); + assert_eq!(key.to_lower_hex(), KEY_HEX); + assert_eq!(key.to_string(), KEY_B64); } #[test] fn parse_key() { - let key_str = "AAECAwQFBgcICQoLDA0OD/Dh0sO0pZaHeGlaSzwtHg8="; - let key: Key = key_str.try_into().unwrap(); - assert_eq!( - key.0, - [ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, - 0x0e, 0x0f, 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b, - 0x3c, 0x2d, 0x1e, 0x0f - ] - ); - assert_eq!( - key.to_lower_hex(), - "000102030405060708090a0b0c0d0e0ff0e1d2c3b4a5968778695a4b3c2d1e0f" - ); - assert_eq!(format!("{key}"), key_str); + let key: Key = KEY_B64.try_into().unwrap(); + assert_eq!(key.0, KEY_BUF); + assert_eq!(key.to_lower_hex(), KEY_HEX); + assert_eq!(key.to_string(), KEY_B64); + } + + #[cfg(feature = "serde")] + #[test] + fn serialize_key() { + let key = Key(KEY_BUF); + assert_tokens(&key, &[Token::Str(KEY_B64)]); } } diff --git a/src/lib.rs b/src/lib.rs index fea086d..fc98ca1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,6 +61,7 @@ pub(crate) mod netlink; mod utils; mod wgapi; +#[cfg(feature = "check_dependencies")] mod dependencies; #[cfg(target_os = "freebsd")] mod wgapi_freebsd; @@ -77,6 +78,7 @@ extern crate log; use std::{fmt, process::Output}; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; // public re-exports pub use wgapi::{Kernel, Userspace, WGApi}; @@ -97,7 +99,8 @@ pub enum IpVersion { } /// Host WireGuard interface configuration -#[derive(Clone, Serialize, Deserialize)] +#[derive(Clone)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct InterfaceConfiguration { pub name: String, pub prvkey: String, diff --git a/src/net.rs b/src/net.rs index 9a20ad6..e4ac646 100644 --- a/src/net.rs +++ b/src/net.rs @@ -11,10 +11,12 @@ use netlink_packet_wireguard::{ constants::{AF_INET, AF_INET6}, nlas::{WgAllowedIp, WgAllowedIpAttrs}, }; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; /// IP address with CIDR. -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Eq, Hash)] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct IpAddrMask { // IP v4 or v6 pub ip: IpAddr, diff --git a/src/utils.rs b/src/utils.rs index f588c42..474c4bb 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,16 +1,15 @@ -#[cfg(target_os = "linux")] -use std::collections::HashSet; #[cfg(target_os = "macos")] use std::io::{BufRead, BufReader, Cursor, Error as IoError}; #[cfg(any(target_os = "freebsd", target_os = "macos", target_os = "netbsd"))] use std::net::{Ipv4Addr, Ipv6Addr}; +#[cfg(target_os = "linux")] +use std::{collections::HashSet, fs::OpenOptions}; +#[cfg(any(target_os = "freebsd", target_os = "linux", target_os = "netbsd"))] +use std::{io::Write, process::Stdio}; use std::{ - fs::OpenOptions, net::{IpAddr, SocketAddr, ToSocketAddrs}, process::Command, }; -#[cfg(any(target_os = "freebsd", target_os = "linux", target_os = "netbsd"))] -use std::{io::Write, process::Stdio}; #[cfg(target_os = "freebsd")] use crate::check_command_output_status; @@ -296,7 +295,7 @@ pub(crate) fn add_peer_routing( Ok(()) => debug!("Route to {default1} has been added for interface {ifname}"), Err(err) => { match err { - IoError::WriteIo(errno) if errno == Errno::ENETUNREACH => { + IoError::WriteIo(Errno::ENETUNREACH) => { warn!("Failed to add default route {default1} for interface {ifname}: Network is unreachable. \ This may happen if your interface's IP address is not the same IP version as the default gateway ({default1}) that was tried to be set, in this case this warning can be ignored. \ Otherwise, there may be some other issues with your network configuration."); @@ -311,7 +310,7 @@ pub(crate) fn add_peer_routing( Ok(()) => debug!("Route to {default2} has been added for interface {ifname}"), Err(err) => { match err { - IoError::WriteIo(errno) if errno == Errno::ENETUNREACH => { + IoError::WriteIo(Errno::ENETUNREACH) => { warn!("Failed to add default route {default2} for interface {ifname}: Network is unreachable. \ This may happen if your interface's IP address is not the same IP version as the default gateway ({default2}) that was tried to be set, in this case this warning can be ignored. \ Otherwise, there may be some other issues with your network configuration."); diff --git a/src/wgapi.rs b/src/wgapi.rs index d02e196..d0b6fa2 100644 --- a/src/wgapi.rs +++ b/src/wgapi.rs @@ -1,7 +1,9 @@ //! Shared multi-platform management API abstraction use std::marker::PhantomData; -use crate::{dependencies::check_external_dependencies, error::WireguardInterfaceError}; +#[cfg(feature = "check_dependencies")] +use crate::dependencies::check_external_dependencies; +use crate::error::WireguardInterfaceError; pub struct Kernel; pub struct Userspace; @@ -18,6 +20,7 @@ pub struct WGApi { impl WGApi { /// Create new instance of `WGApi`. pub fn new(ifname: String) -> Result { + #[cfg(feature = "check_dependencies")] check_external_dependencies()?; Ok(WGApi { ifname, diff --git a/src/wgapi_freebsd.rs b/src/wgapi_freebsd.rs index c5aeb70..fde760e 100644 --- a/src/wgapi_freebsd.rs +++ b/src/wgapi_freebsd.rs @@ -91,7 +91,10 @@ impl WireguardInterfaceApi for WGApi { if let Some(mtu) = config.mtu { debug!("Setting MTU of {mtu} for interface {}", self.ifname); bsd::set_mtu(&self.ifname, mtu)?; - debug!("MTU of {mtu} set for interface {}, value: {mtu}"); + debug!( + "MTU of {mtu} set for interface {}, value: {mtu}", + self.ifname + ); } info!( diff --git a/src/wgapi_linux.rs b/src/wgapi_linux.rs index 2d4b8f6..b2025b7 100644 --- a/src/wgapi_linux.rs +++ b/src/wgapi_linux.rs @@ -1,4 +1,4 @@ -use std::{marker::PhantomData, net::IpAddr, process::Command, str::FromStr}; +use std::{net::IpAddr, str::FromStr}; use crate::{ netlink, diff --git a/src/wgapi_userspace.rs b/src/wgapi_userspace.rs index 37b13fd..fd6d86b 100644 --- a/src/wgapi_userspace.rs +++ b/src/wgapi_userspace.rs @@ -9,6 +9,8 @@ use std::{ time::Duration, }; +#[cfg(feature = "check_dependencies")] +use crate::dependencies::check_external_dependencies; #[cfg(target_os = "linux")] use crate::netlink; #[cfg(any(target_os = "freebsd", target_os = "linux", target_os = "netbsd"))] @@ -17,7 +19,6 @@ use crate::utils::clear_dns; use crate::{bsd, utils::resolve}; use crate::{ check_command_output_status, - dependencies::check_external_dependencies, error::WireguardInterfaceError, utils::{add_peer_routing, configure_dns}, wgapi::{Userspace, WGApi}, @@ -37,6 +38,7 @@ impl WGApi { /// # Errors /// Will return `WireguardInterfaceError` if `wireguard-go` can't be found. pub fn new(ifname: String) -> Result { + #[cfg(feature = "check_dependencies")] check_external_dependencies()?; Ok(WGApi { ifname, @@ -303,7 +305,7 @@ impl WireguardInterfaceApi for WGApi { return Err(WireguardInterfaceError::UnixSockerError(format!( "Failed to remove socket for interface {}: {err}", self.ifname - ))) + ))); } } @@ -383,7 +385,7 @@ impl WireguardInterfaceApi for WGApi { } Err(err) => match err { err if err.kind() == ErrorKind::NotFound => { - return Err(WireguardInterfaceError::SocketClosed(format!( + Err(WireguardInterfaceError::SocketClosed(format!( "Failed to read network information for interface {} data, the socket may have been closed before we've attempted to read. If the socket has been closed intentionally, this message can be ignored. Error details: {err}", self.ifname )))