From 3fa928b3158ce33a57e9ba2c1913485eb409ff4b Mon Sep 17 00:00:00 2001 From: Mathias Hall-Andersen Date: Wed, 23 Oct 2019 10:32:18 +0200 Subject: Work on platform specific code (Linux) --- src/configuration/config.rs | 260 ++++++++++++++++++++++++++++++++++++++++++++ src/configuration/mod.rs | 5 + 2 files changed, 265 insertions(+) create mode 100644 src/configuration/config.rs create mode 100644 src/configuration/mod.rs (limited to 'src/configuration') diff --git a/src/configuration/config.rs b/src/configuration/config.rs new file mode 100644 index 0000000..24b1349 --- /dev/null +++ b/src/configuration/config.rs @@ -0,0 +1,260 @@ +use spin::Mutex; +use std::net::{IpAddr, SocketAddr}; +use x25519_dalek::{PublicKey, StaticSecret}; + +use super::BindOwner; +use super::PlatformBind; +use super::Tun; +use super::Wireguard; + +/// The goal of the configuration interface is, among others, +/// to hide the IO implementations (over which the WG device is generic), +/// from the configuration and UAPI code. + +/// Describes a snapshot of the state of a peer +pub struct PeerState { + rx_bytes: u64, + tx_bytes: u64, + last_handshake_time_sec: u64, + last_handshake_time_nsec: u64, + public_key: PublicKey, + allowed_ips: Vec<(IpAddr, u32)>, +} + +struct UDPState { + fwmark: Option, + owner: O, + port: u16, +} + +pub struct WireguardConfig { + wireguard: Wireguard, + network: Mutex>>, +} + +pub enum ConfigError { + NoSuchPeer, + NotListening, +} + +impl ConfigError { + fn errno(&self) -> i32 { + // TODO: obtain the correct error values + match self { + NoSuchPeer => 1, + NotListening => 2, + } + } +} + +/// Exposed configuration interface +pub trait Configuration { + /// Updates the private key of the device + /// + /// # Arguments + /// + /// - `sk`: The new private key (or None, if the private key should be cleared) + fn set_private_key(&self, sk: Option); + + /// Returns the private key of the device + /// + /// # Returns + /// + /// The private if set, otherwise None. + fn get_private_key(&self) -> Option; + + /// Returns the protocol version of the device + /// + /// # Returns + /// + /// An integer indicating the protocol version + fn get_protocol_version(&self) -> usize; + + fn set_listen_port(&self, port: u16) -> Option; + + /// Set the firewall mark (or similar, depending on platform) + /// + /// # Arguments + /// + /// - `mark`: The fwmark value + /// + /// # Returns + /// + /// An error if this operation is not supported by the underlying + /// "bind" implementation. + fn set_fwmark(&self, mark: Option) -> Option; + + /// Removes all peers from the device + fn replace_peers(&self); + + /// Remove the peer from the + /// + /// # Arguments + /// + /// - `peer`: The public key of the peer to remove + /// + /// # Returns + /// + /// If the peer does not exists this operation is a noop + fn remove_peer(&self, peer: PublicKey); + + /// Adds a new peer to the device + /// + /// # Arguments + /// + /// - `peer`: The public key of the peer to add + /// + /// # Returns + /// + /// A bool indicating if the peer was added. + /// + /// If the peer already exists this operation is a noop + fn add_peer(&self, peer: PublicKey) -> bool; + + /// Update the psk of a peer + /// + /// # Arguments + /// + /// - `peer`: The public key of the peer + /// - `psk`: The new psk or None if the psk should be unset + /// + /// # Returns + /// + /// An error if no such peer exists + fn set_preshared_key(&self, peer: PublicKey, psk: Option<[u8; 32]>) -> Option; + + /// Update the endpoint of the + /// + /// # Arguments + /// + /// - `peer': The public key of the peer + /// - `psk` + fn set_endpoint(&self, peer: PublicKey, addr: SocketAddr) -> Option; + + /// Update the endpoint of the + /// + /// # Arguments + /// + /// - `peer': The public key of the peer + /// - `psk` + fn set_persistent_keepalive_interval( + &self, + peer: PublicKey, + interval: usize, + ) -> Option; + + /// Remove all allowed IPs from the peer + /// + /// # Arguments + /// + /// - `peer': The public key of the peer + /// + /// # Returns + /// + /// An error if no such peer exists + fn replace_allowed_ips(&self, peer: PublicKey) -> Option; + + /// Add a new allowed subnet to the peer + /// + /// # Arguments + /// + /// - `peer`: The public key of the peer + /// - `ip`: Subnet mask + /// - `masklen`: + /// + /// # Returns + /// + /// An error if the peer does not exist + /// + /// # Note: + /// + /// The API must itself sanitize the (ip, masklen) set: + /// The ip should be masked to remove any set bits right of the first "masklen" bits. + fn add_allowed_ip(&self, peer: PublicKey, ip: IpAddr, masklen: u32) -> Option; + + /// Returns the state of all peers + /// + /// # Returns + /// + /// A list of structures describing the state of each peer + fn get_peers(&self) -> Vec; +} + +impl Configuration for WireguardConfig { + fn set_private_key(&self, sk: Option) { + self.wireguard.set_key(sk) + } + + fn get_private_key(&self) -> Option { + self.wireguard.get_sk() + } + + fn get_protocol_version(&self) -> usize { + 1 + } + + fn set_listen_port(&self, port: u16) -> Option { + let mut udp = self.network.lock(); + + // close the current listener + *udp = None; + + None + } + + fn set_fwmark(&self, mark: Option) -> Option { + match self.network.lock().as_mut() { + Some(mut bind) => { + // there is a active bind + // set the fwmark (the IO operation) + bind.owner.set_fwmark(mark).unwrap(); // TODO: handle + + // update stored value + bind.fwmark = mark; + None + } + None => Some(ConfigError::NotListening), + } + } + + fn replace_peers(&self) { + self.wireguard.clear_peers(); + } + + fn remove_peer(&self, peer: PublicKey) { + self.wireguard.remove_peer(peer); + } + + fn add_peer(&self, peer: PublicKey) -> bool { + self.wireguard.new_peer(peer); + false + } + + fn set_preshared_key(&self, peer: PublicKey, psk: Option<[u8; 32]>) -> Option { + None + } + + fn set_endpoint(&self, peer: PublicKey, addr: SocketAddr) -> Option { + None + } + + fn set_persistent_keepalive_interval( + &self, + peer: PublicKey, + interval: usize, + ) -> Option { + None + } + + fn replace_allowed_ips(&self, peer: PublicKey) -> Option { + None + } + + fn add_allowed_ip(&self, peer: PublicKey, ip: IpAddr, masklen: u32) -> Option { + None + } + + fn get_peers(&self) -> Vec { + vec![] + } +} diff --git a/src/configuration/mod.rs b/src/configuration/mod.rs new file mode 100644 index 0000000..56a83e2 --- /dev/null +++ b/src/configuration/mod.rs @@ -0,0 +1,5 @@ +mod config; + +use super::platform::{BindOwner, PlatformBind}; +use super::wireguard::tun::Tun; +use super::wireguard::Wireguard; -- cgit v1.2.3-59-g8ed1b