extern crate libc;
extern crate wgctrl_sys;
use self::wgctrl_sys::wg_device_flags as wgdf;
use self::wgctrl_sys::wg_peer_flags as wgpf;
use device::{AllowedIp, PeerConfig};
use key::{Key, KeyPair};
use std::ffi::CString;
use std::io;
use std::mem;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::ptr;
fn encode_allowedips(
allowed_ips: &[AllowedIp],
) -> (*mut wgctrl_sys::wg_allowedip, *mut wgctrl_sys::wg_allowedip) {
if allowed_ips.is_empty() {
return (ptr::null_mut(), ptr::null_mut());
}
let mut first_ip = ptr::null_mut();
let mut last_ip: *mut wgctrl_sys::wg_allowedip = ptr::null_mut();
for ip in allowed_ips {
let mut wg_allowedip = Box::new(wgctrl_sys::wg_allowedip {
family: 0,
__bindgen_anon_1: unsafe { mem::uninitialized() },
cidr: ip.cidr,
next_allowedip: first_ip,
});
match ip.address {
IpAddr::V4(a) => {
wg_allowedip.family = libc::AF_INET as u16;
unsafe { wg_allowedip.__bindgen_anon_1.ip4.s_addr = u32::to_be(a.into()) };
}
IpAddr::V6(a) => {
wg_allowedip.family = libc::AF_INET6 as u16;
unsafe { wg_allowedip.__bindgen_anon_1.ip6.s6_addr = a.octets() };
}
}
first_ip = Box::into_raw(wg_allowedip);
if last_ip.is_null() {
last_ip = first_ip;
}
}
(first_ip, last_ip)
}
fn encode_endpoint(endpoint: Option<SocketAddr>) -> wgctrl_sys::wg_peer__bindgen_ty_1 {
match endpoint {
Some(SocketAddr::V4(s)) => wgctrl_sys::wg_peer__bindgen_ty_1 {
addr4: libc::sockaddr_in {
sin_family: libc::AF_INET as u16,
sin_addr: libc::in_addr {
s_addr: u32::from_be(s.ip().clone().into()),
},
sin_port: u16::to_be(s.port()),
sin_zero: [0; 8],
},
},
Some(SocketAddr::V6(s)) => {
let mut result = wgctrl_sys::wg_peer__bindgen_ty_1 {
addr6: libc::sockaddr_in6 {
sin6_family: libc::AF_INET6 as u16,
sin6_addr: unsafe { mem::uninitialized() },
sin6_port: u16::to_be(s.port()),
sin6_flowinfo: 0,
sin6_scope_id: 0,
},
};
unsafe { result.addr6.sin6_addr.s6_addr = s.ip().octets() };
result
}
None => wgctrl_sys::wg_peer__bindgen_ty_1 {
addr6: unsafe { mem::zeroed() },
},
}
}
fn encode_peers(peers: Vec<PeerConfigBuilder>) -> (*mut wgctrl_sys::wg_peer, *mut wgctrl_sys::wg_peer) {
let mut first_peer = ptr::null_mut();
let mut last_peer: *mut wgctrl_sys::wg_peer = ptr::null_mut();
for peer in peers {
let (first_allowedip, last_allowedip) = encode_allowedips(&peer.allowed_ips);
let mut wg_peer = Box::new(wgctrl_sys::wg_peer {
public_key: peer.public_key.0,
preshared_key: wgctrl_sys::wg_key::default(),
endpoint: encode_endpoint(peer.endpoint),
last_handshake_time: libc::timespec {
tv_sec: 0,
tv_nsec: 0,
},
tx_bytes: 0,
rx_bytes: 0,
persistent_keepalive_interval: 0,
first_allowedip,
last_allowedip,
next_peer: first_peer,
flags: peer.flags,
});
if let Some(Key(k)) = peer.preshared_key {
wg_peer.preshared_key = k;
}
if let Some(n) = peer.persistent_keepalive_interval {
wg_peer.persistent_keepalive_interval = n;
}
first_peer = Box::into_raw(wg_peer);
if last_peer.is_null() {
last_peer = first_peer;
}
}
(first_peer, last_peer)
}
fn encode_name(name: &str) -> [i8; 16] {
let mut bytes: Vec<_> = name.bytes().collect();
bytes.resize(16, 0);
let mut result = [0u8; 16];
result.copy_from_slice(&bytes[..]);
unsafe { mem::transmute(result) }
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct DeviceConfigBuilder {
public_key: Option<Key>,
private_key: Option<Key>,
fwmark: Option<u32>,
listen_port: Option<u16>,
peers: Vec<PeerConfigBuilder>,
flags: wgdf,
}
impl DeviceConfigBuilder {
pub fn new() -> Self {
DeviceConfigBuilder {
public_key: None,
private_key: None,
fwmark: None,
listen_port: None,
peers: vec![],
flags: wgdf(0),
}
}
pub fn set_keypair(self, keypair: KeyPair) -> Self {
self.set_public_key(keypair.public)
.set_private_key(keypair.private)
}
pub fn set_public_key(mut self, key: Key) -> Self {
self.public_key = Some(key);
self.flags |= wgdf::WGDEVICE_HAS_PUBLIC_KEY;
self
}
pub fn unset_public_key(self) -> Self {
self.set_public_key(Key::zero())
}
pub fn set_private_key(mut self, key: Key) -> Self {
self.private_key = Some(key);
self.flags |= wgdf::WGDEVICE_HAS_PRIVATE_KEY;
self
}
pub fn unset_private_key(self) -> Self {
self.set_private_key(Key::zero())
}
pub fn set_fwmark(mut self, fwmark: u32) -> Self {
self.fwmark = Some(fwmark);
self.flags |= wgdf::WGDEVICE_HAS_FWMARK;
self
}
pub fn unset_fwmark(self) -> Self {
self.set_fwmark(0)
}
pub fn set_listen_port(mut self, port: u16) -> Self {
self.listen_port = Some(port);
self.flags |= wgdf::WGDEVICE_HAS_LISTEN_PORT;
self
}
pub fn randomize_listen_port(self) -> Self {
self.set_listen_port(0)
}
pub fn add_peer(mut self, peer: PeerConfigBuilder) -> Self {
self.peers.push(peer);
self
}
pub fn add_peer_with(
self,
pubkey: &Key,
builder: impl Fn(PeerConfigBuilder) -> PeerConfigBuilder,
) -> Self {
self.add_peer(builder(PeerConfigBuilder::new(pubkey)))
}
pub fn add_peers(mut self, peers: &[PeerConfigBuilder]) -> Self {
self.peers.extend_from_slice(peers);
self
}
pub fn replace_peers(mut self) -> Self {
self.flags |= wgdf::WGDEVICE_REPLACE_PEERS;
self
}
pub fn remove_peer_by_key(self, public_key: &Key) -> Self {
let mut peer = PeerConfigBuilder::new(public_key);
peer.flags |= wgpf::WGPEER_REMOVE_ME;
self.add_peer(peer)
}
pub fn apply(self, iface: &str) -> io::Result<()> {
let (first_peer, last_peer) = encode_peers(self.peers);
let iface_str = CString::new(iface)?;
let result = unsafe { wgctrl_sys::wg_add_device(iface_str.as_ptr()) };
match result {
0 | -17 => {}
_ => return Err(io::Error::last_os_error()),
};
let mut wg_device = Box::new(wgctrl_sys::wg_device {
name: encode_name(iface),
ifindex: 0,
public_key: wgctrl_sys::wg_key::default(),
private_key: wgctrl_sys::wg_key::default(),
fwmark: 0,
listen_port: 0,
first_peer,
last_peer,
flags: self.flags,
});
if let Some(Key(k)) = self.public_key {
wg_device.public_key = k;
}
if let Some(Key(k)) = self.private_key {
wg_device.private_key = k;
}
if let Some(f) = self.fwmark {
wg_device.fwmark = f;
}
if let Some(f) = self.listen_port {
wg_device.listen_port = f;
}
let ptr = Box::into_raw(wg_device);
let result = unsafe { wgctrl_sys::wg_set_device(ptr) };
unsafe { wgctrl_sys::wg_free_device(ptr) };
if result == 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
}
impl Default for DeviceConfigBuilder {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct PeerConfigBuilder {
public_key: Key,
preshared_key: Option<Key>,
endpoint: Option<SocketAddr>,
persistent_keepalive_interval: Option<u16>,
allowed_ips: Vec<AllowedIp>,
flags: wgpf,
}
impl PeerConfigBuilder {
pub fn new(public_key: &Key) -> Self {
PeerConfigBuilder {
public_key: public_key.clone(),
preshared_key: None,
endpoint: None,
persistent_keepalive_interval: None,
allowed_ips: vec![],
flags: wgpf::WGPEER_HAS_PUBLIC_KEY,
}
}
pub fn from_peer_config(config: PeerConfig) -> Self {
let mut builder = Self::new(&config.public_key);
if let Some(k) = config.preshared_key {
builder = builder.set_preshared_key(k);
}
if let Some(e) = config.endpoint {
builder = builder.set_endpoint(e.ip(), e.port());
}
if let Some(k) = config.persistent_keepalive_interval {
builder = builder.set_persistent_keepalive_interval(k);
}
builder
.replace_allowed_ips()
.add_allowed_ips(&config.allowed_ips)
}
pub fn set_preshared_key(mut self, key: Key) -> Self {
self.preshared_key = Some(key);
self.flags |= wgpf::WGPEER_HAS_PRESHARED_KEY;
self
}
pub fn unset_preshared_key(self) -> Self {
self.set_preshared_key(Key::zero())
}
pub fn set_endpoint(mut self, address: IpAddr, port: u16) -> Self {
self.endpoint = Some(SocketAddr::new(address, port));
self
}
pub fn set_persistent_keepalive_interval(mut self, interval: u16) -> Self {
self.persistent_keepalive_interval = Some(interval);
self.flags |= wgpf::WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
self
}
pub fn disable_persistent_keepalive(self) -> Self {
self.set_persistent_keepalive_interval(0)
}
pub fn add_allowed_ip(mut self, address: IpAddr, cidr: u8) -> Self {
self.allowed_ips.push(AllowedIp { address, cidr });
self
}
pub fn add_allowed_ips(mut self, ips: &[AllowedIp]) -> Self {
self.allowed_ips.extend_from_slice(ips);
self
}
pub fn allow_all_ips(self) -> Self {
self.add_allowed_ip(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0)
.add_allowed_ip(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), 0)
}
pub fn replace_allowed_ips(mut self) -> Self {
self.flags |= wgpf::WGPEER_REPLACE_ALLOWEDIPS;
self
}
}
pub fn delete_interface(iface: &str) -> io::Result<()> {
let iface_str = CString::new(iface)?;
let result = unsafe { wgctrl_sys::wg_del_device(iface_str.as_ptr()) };
if result == 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}