diff options
author | Galen Guyer <galen@galenguyer.com> | 2023-06-05 14:42:38 -0400 |
---|---|---|
committer | Galen Guyer <galen@galenguyer.com> | 2023-06-05 14:42:38 -0400 |
commit | eea5763756343c64617f1c12cd13690604b34078 (patch) | |
tree | e36e16040935d1d8ad3c29ed869e47e812ed8609 | |
parent | 3f290369b88cefbdc25222d62add4509a87f02b9 (diff) |
-rw-r--r-- | wg-rs/src/allowed_ip.rs | 32 | ||||
-rw-r--r-- | wg-rs/src/device.rs | 67 | ||||
-rw-r--r-- | wg-rs/src/lib.rs | 183 | ||||
-rw-r--r-- | wg-rs/src/peer.rs | 78 | ||||
-rw-r--r-- | wg-sys/src/lib.rs | 2 |
5 files changed, 189 insertions, 173 deletions
diff --git a/wg-rs/src/allowed_ip.rs b/wg-rs/src/allowed_ip.rs new file mode 100644 index 0000000..b91c45a --- /dev/null +++ b/wg-rs/src/allowed_ip.rs @@ -0,0 +1,32 @@ +use std::net::IpAddr; + +#[derive(Debug)] +pub struct WgAllowedIp { + pub ip: IpAddr, + pub cidr: u8, +} +impl From<&wg_sys::wg_allowedip> for WgAllowedIp { + fn from(allowed_ip: &wg_sys::wg_allowedip) -> Self { + unsafe { + match allowed_ip.family as i32 { + wg_sys::AF_INET => Self { + ip: IpAddr::V4( + allowed_ip + .__bindgen_anon_1 + .ip4 + .as_ref() + .s_addr + .to_be() + .into(), + ), + cidr: allowed_ip.cidr, + }, + wg_sys::AF_INET6 => Self { + ip: IpAddr::V6(allowed_ip.__bindgen_anon_1.ip6.as_ref().s6_addr.into()), + cidr: allowed_ip.cidr, + }, + _ => unimplemented!("Unsupported family"), + } + } + } +} diff --git a/wg-rs/src/device.rs b/wg-rs/src/device.rs new file mode 100644 index 0000000..c865c5b --- /dev/null +++ b/wg-rs/src/device.rs @@ -0,0 +1,67 @@ +use std::ffi::CStr; + +use crate::{raw, WgPeer}; + +#[derive(Debug)] +pub struct WgDevice { + pub name: String, + pub ifindex: u32, + pub private_key: String, + pub public_key: String, + pub fwmark: u32, + pub listen_port: u16, + pub peers: Vec<WgPeer>, + pub flags: WgDeviceFlags, +} + +#[allow(non_snake_case)] +#[derive(Debug)] +pub struct WgDeviceFlags { + pub ReplacePeers: bool, + pub HasPrivateKey: bool, + pub HasPublicKey: bool, + pub HasListenPort: bool, + pub HasFwmark: bool, +} + +impl From<wg_sys::wg_device> for WgDevice { + fn from(device: wg_sys::wg_device) -> Self { + let mut dev = Self { + name: CStr::from_bytes_until_nul( + &device.name.iter().map(|&c| c as u8).collect::<Vec<u8>>(), + ) + .unwrap() + .to_str() + .unwrap() + .to_string(), + ifindex: device.ifindex, + private_key: raw::wg_key_to_base64(device.private_key), + public_key: raw::wg_key_to_base64(device.public_key), + fwmark: device.fwmark, + listen_port: device.listen_port, + peers: vec![], + flags: WgDeviceFlags { + ReplacePeers: (device.flags.0 & wg_sys::wg_device_flags::WGDEVICE_REPLACE_PEERS.0) + != 0, + HasPrivateKey: (device.flags.0 + & wg_sys::wg_device_flags::WGDEVICE_HAS_PRIVATE_KEY.0) + != 0, + HasPublicKey: (device.flags.0 & wg_sys::wg_device_flags::WGDEVICE_HAS_PUBLIC_KEY.0) + != 0, + HasListenPort: (device.flags.0 + & wg_sys::wg_device_flags::WGDEVICE_HAS_LISTEN_PORT.0) + != 0, + HasFwmark: (device.flags.0 & wg_sys::wg_device_flags::WGDEVICE_HAS_FWMARK.0) != 0, + }, + }; + + let mut peer_opt = unsafe { device.first_peer.as_ref() }; + + while let Some(peer) = peer_opt { + dev.peers.push(WgPeer::from(peer)); + peer_opt = unsafe { peer.next_peer.as_ref() }; + } + + dev + } +} diff --git a/wg-rs/src/lib.rs b/wg-rs/src/lib.rs index b0313b1..8c6fc8d 100644 --- a/wg-rs/src/lib.rs +++ b/wg-rs/src/lib.rs @@ -1,178 +1,13 @@ +mod allowed_ip; +mod device; +mod peer; mod raw; -use std::ffi::CStr; -use std::net::{IpAddr, SocketAddr}; -use raw::wg_get_device; +pub use allowed_ip::*; +pub use device::*; +pub use peer::*; -#[derive(Debug)] -pub struct WgDevice { - pub name: String, - pub ifindex: u32, - pub private_key: String, - pub public_key: String, - pub fwmark: u32, - pub listen_port: u16, - pub peers: Vec<WgPeer>, - pub flags: WgDeviceFlags, -} - -#[allow(non_snake_case)] -#[derive(Debug)] -pub struct WgDeviceFlags { - pub ReplacePeers: bool, - pub HasPrivateKey: bool, - pub HasPublicKey: bool, - pub HasListenPort: bool, - pub HasFwmark: bool, -} - -impl From<wg_sys::wg_device> for WgDevice { - fn from(device: wg_sys::wg_device) -> Self { - let mut dev = Self { - name: CStr::from_bytes_until_nul( - &device.name.iter().map(|&c| c as u8).collect::<Vec<u8>>(), - ) - .unwrap() - .to_str() - .unwrap() - .to_string(), - ifindex: device.ifindex, - private_key: raw::wg_key_to_base64(device.private_key), - public_key: raw::wg_key_to_base64(device.public_key), - fwmark: device.fwmark, - listen_port: device.listen_port, - peers: vec![], - flags: WgDeviceFlags { - ReplacePeers: (device.flags.0 & wg_sys::wg_device_flags::WGDEVICE_REPLACE_PEERS.0) - != 0, - HasPrivateKey: (device.flags.0 - & wg_sys::wg_device_flags::WGDEVICE_HAS_PRIVATE_KEY.0) - != 0, - HasPublicKey: (device.flags.0 & wg_sys::wg_device_flags::WGDEVICE_HAS_PUBLIC_KEY.0) - != 0, - HasListenPort: (device.flags.0 - & wg_sys::wg_device_flags::WGDEVICE_HAS_LISTEN_PORT.0) - != 0, - HasFwmark: (device.flags.0 & wg_sys::wg_device_flags::WGDEVICE_HAS_FWMARK.0) != 0, - }, - }; - - let mut peer_opt = unsafe { device.first_peer.as_ref() }; - - while let Some(peer) = peer_opt { - dev.peers.push(WgPeer::from(peer)); - peer_opt = unsafe { peer.next_peer.as_ref() }; - } - - dev - } -} - -#[derive(Debug)] -pub struct WgPeer { - pub public_key: String, - pub preshared_key: String, - pub endpoint: SocketAddr, - pub allowed_ips: Vec<WgAllowedIp>, - pub rx_bytes: u64, - pub tx_bytes: u64, - pub persistent_keepalive: u16, - pub last_handshake_time: (u64, u64), - pub flags: WgPeerFlags, -} -#[allow(non_snake_case)] -#[derive(Debug)] -pub struct WgPeerFlags { - pub RemoveMe: bool, - pub ReplaceAllowedIps: bool, - pub HasPublicKey: bool, - pub HasPresharedKey: bool, - pub HasPersistentKeepalive: bool, -} - -impl From<&wg_sys::wg_peer> for WgPeer { - fn from(peer: &wg_sys::wg_peer) -> Self { - let endpoint = unsafe { - match peer.endpoint.addr.as_ref().sa_family as i32 { - wg_sys::AF_INET => SocketAddr::new( - IpAddr::V4(peer.endpoint.addr4.as_ref().sin_addr.s_addr.to_be().into()), - peer.endpoint.addr4.as_ref().sin_port.to_be(), - ), - wg_sys::AF_INET6 => SocketAddr::new( - IpAddr::V6(peer.endpoint.addr6.as_ref().sin6_addr.s6_addr.into()), - peer.endpoint.addr6.as_ref().sin6_port.to_be(), - ), - _ => unimplemented!("Unsupported family"), - } - }; - - let mut wgpeer = Self { - public_key: raw::wg_key_to_base64(peer.public_key), - preshared_key: raw::wg_key_to_base64(peer.preshared_key), - rx_bytes: peer.rx_bytes, - tx_bytes: peer.tx_bytes, - persistent_keepalive: peer.persistent_keepalive_interval, - endpoint, - last_handshake_time: ( - peer.last_handshake_time.tv_sec as u64, - peer.last_handshake_time.tv_nsec as u64, - ), - allowed_ips: vec![], - flags: WgPeerFlags { - RemoveMe: (peer.flags.0 & wg_sys::wg_peer_flags::WGPEER_REMOVE_ME.0) != 0, - ReplaceAllowedIps: (peer.flags.0 - & wg_sys::wg_peer_flags::WGPEER_REPLACE_ALLOWEDIPS.0) - != 0, - HasPublicKey: (peer.flags.0 & wg_sys::wg_peer_flags::WGPEER_HAS_PUBLIC_KEY.0) != 0, - HasPresharedKey: (peer.flags.0 & wg_sys::wg_peer_flags::WGPEER_HAS_PRESHARED_KEY.0) - != 0, - HasPersistentKeepalive: (peer.flags.0 - & wg_sys::wg_peer_flags::WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL.0) - != 0, - }, - }; - - let mut aip_opt = unsafe { peer.first_allowedip.as_ref() }; - - while let Some(aip) = aip_opt { - wgpeer.allowed_ips.push(WgAllowedIp::from(aip)); - aip_opt = unsafe { aip.next_allowedip.as_ref() }; - } - - wgpeer - } -} - -#[derive(Debug)] -pub struct WgAllowedIp { - pub ip: IpAddr, - pub cidr: u8, -} -impl From<&wg_sys::wg_allowedip> for WgAllowedIp { - fn from(allowed_ip: &wg_sys::wg_allowedip) -> Self { - unsafe { - match allowed_ip.family as i32 { - wg_sys::AF_INET => Self { - ip: IpAddr::V4( - allowed_ip - .__bindgen_anon_1 - .ip4 - .as_ref() - .s_addr - .to_be() - .into(), - ), - cidr: allowed_ip.cidr, - }, - wg_sys::AF_INET6 => Self { - ip: IpAddr::V6(allowed_ip.__bindgen_anon_1.ip6.as_ref().s6_addr.into()), - cidr: allowed_ip.cidr, - }, - _ => unimplemented!("Unsupported family"), - } - } - } -} +use raw::{wg_get_device, wg_set_device}; pub fn list_device_names() -> Vec<String> { raw::wg_list_device_names() @@ -196,6 +31,10 @@ pub fn get_device(name: &str) -> Result<WgDevice, String> { Ok(WgDevice::from(dev)) } +pub fn set_device(device: &WgDevice) { + // wg_set_device(device.into()).unwrap(); +} + #[cfg(test)] mod test { use super::*; diff --git a/wg-rs/src/peer.rs b/wg-rs/src/peer.rs new file mode 100644 index 0000000..dc1852e --- /dev/null +++ b/wg-rs/src/peer.rs @@ -0,0 +1,78 @@ +use std::net::{SocketAddr, IpAddr}; + +use crate::{WgAllowedIp, raw}; + +#[derive(Debug)] +pub struct WgPeer { + pub public_key: String, + pub preshared_key: String, + pub endpoint: SocketAddr, + pub allowed_ips: Vec<WgAllowedIp>, + pub rx_bytes: u64, + pub tx_bytes: u64, + pub persistent_keepalive: u16, + pub last_handshake_time: (u64, u64), + pub flags: WgPeerFlags, +} +#[allow(non_snake_case)] +#[derive(Debug)] +pub struct WgPeerFlags { + pub RemoveMe: bool, + pub ReplaceAllowedIps: bool, + pub HasPublicKey: bool, + pub HasPresharedKey: bool, + pub HasPersistentKeepalive: bool, +} + +impl From<&wg_sys::wg_peer> for WgPeer { + fn from(peer: &wg_sys::wg_peer) -> Self { + let endpoint = unsafe { + match peer.endpoint.addr.as_ref().sa_family as i32 { + wg_sys::AF_INET => SocketAddr::new( + IpAddr::V4(peer.endpoint.addr4.as_ref().sin_addr.s_addr.to_be().into()), + peer.endpoint.addr4.as_ref().sin_port.to_be(), + ), + wg_sys::AF_INET6 => SocketAddr::new( + IpAddr::V6(peer.endpoint.addr6.as_ref().sin6_addr.s6_addr.into()), + peer.endpoint.addr6.as_ref().sin6_port.to_be(), + ), + _ => unimplemented!("Unsupported family"), + } + }; + + let mut wgpeer = Self { + public_key: raw::wg_key_to_base64(peer.public_key), + preshared_key: raw::wg_key_to_base64(peer.preshared_key), + rx_bytes: peer.rx_bytes, + tx_bytes: peer.tx_bytes, + persistent_keepalive: peer.persistent_keepalive_interval, + endpoint, + last_handshake_time: ( + peer.last_handshake_time.tv_sec as u64, + peer.last_handshake_time.tv_nsec as u64, + ), + allowed_ips: vec![], + flags: WgPeerFlags { + RemoveMe: (peer.flags.0 & wg_sys::wg_peer_flags::WGPEER_REMOVE_ME.0) != 0, + ReplaceAllowedIps: (peer.flags.0 + & wg_sys::wg_peer_flags::WGPEER_REPLACE_ALLOWEDIPS.0) + != 0, + HasPublicKey: (peer.flags.0 & wg_sys::wg_peer_flags::WGPEER_HAS_PUBLIC_KEY.0) != 0, + HasPresharedKey: (peer.flags.0 & wg_sys::wg_peer_flags::WGPEER_HAS_PRESHARED_KEY.0) + != 0, + HasPersistentKeepalive: (peer.flags.0 + & wg_sys::wg_peer_flags::WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL.0) + != 0, + }, + }; + + let mut aip_opt = unsafe { peer.first_allowedip.as_ref() }; + + while let Some(aip) = aip_opt { + wgpeer.allowed_ips.push(WgAllowedIp::from(aip)); + aip_opt = unsafe { aip.next_allowedip.as_ref() }; + } + + wgpeer + } +} diff --git a/wg-sys/src/lib.rs b/wg-sys/src/lib.rs index 2cf9dd9..6d7ac2d 100644 --- a/wg-sys/src/lib.rs +++ b/wg-sys/src/lib.rs @@ -6,4 +6,4 @@ include!(concat!(env!("OUT_DIR"), "/bindings.rs")); -pub use libc::{AF_INET, AF_INET6};
\ No newline at end of file +pub use libc::{AF_INET, AF_INET6}; |