summaryrefslogtreecommitdiffstats
path: root/src/configuration
diff options
context:
space:
mode:
Diffstat (limited to 'src/configuration')
-rw-r--r--src/configuration/config.rs53
-rw-r--r--src/configuration/error.rs28
-rw-r--r--src/configuration/mod.rs4
-rw-r--r--src/configuration/uapi.rs161
4 files changed, 221 insertions, 25 deletions
diff --git a/src/configuration/config.rs b/src/configuration/config.rs
index d68084c..e3eb0af 100644
--- a/src/configuration/config.rs
+++ b/src/configuration/config.rs
@@ -1,5 +1,7 @@
use spin::Mutex;
use std::net::{IpAddr, SocketAddr};
+use std::sync::atomic::Ordering;
+use std::time::SystemTime;
use x25519_dalek::{PublicKey, StaticSecret};
use super::*;
@@ -11,12 +13,12 @@ use bind::Owner;
/// 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)>,
+ pub rx_bytes: u64,
+ pub tx_bytes: u64,
+ pub last_handshake_time_sec: u64,
+ pub last_handshake_time_nsec: u64,
+ pub public_key: PublicKey,
+ pub allowed_ips: Vec<(IpAddr, u32)>,
}
pub struct WireguardConfig<T: tun::Tun, B: bind::Platform> {
@@ -33,23 +35,6 @@ impl<T: tun::Tun, B: bind::Platform> WireguardConfig<T, B> {
}
}
-pub enum ConfigError {
- NoSuchPeer,
- NotListening,
- FailedToBind,
-}
-
-impl ConfigError {
- fn errno(&self) -> i32 {
- // TODO: obtain the correct error values
- match self {
- ConfigError::NoSuchPeer => 1,
- ConfigError::NotListening => 2,
- ConfigError::FailedToBind => 3,
- }
- }
-}
-
/// Exposed configuration interface
pub trait Configuration {
/// Updates the private key of the device
@@ -244,7 +229,7 @@ impl<T: tun::Tun, B: bind::Platform> Configuration for WireguardConfig<T, B> {
}
fn add_peer(&self, peer: &PublicKey) -> bool {
- self.wireguard.new_peer(*peer);
+ self.wireguard.add_peer(*peer);
false
}
@@ -301,6 +286,24 @@ impl<T: tun::Tun, B: bind::Platform> Configuration for WireguardConfig<T, B> {
}
fn get_peers(&self) -> Vec<PeerState> {
- vec![]
+ let peers = self.wireguard.list_peers();
+ let mut state = Vec::with_capacity(peers.len());
+ for p in peers {
+ // convert the system time to (secs, nano) since epoch
+ let last_handshake = (*p.walltime_last_handshake.lock())
+ .duration_since(SystemTime::UNIX_EPOCH)
+ .expect("There should be no earlier time");
+
+ // extract state into PeerState
+ state.push(PeerState {
+ rx_bytes: p.rx_bytes.load(Ordering::Relaxed),
+ tx_bytes: p.tx_bytes.load(Ordering::Relaxed),
+ allowed_ips: p.router.list_allowed_ips(),
+ last_handshake_time_nsec: last_handshake.subsec_nanos() as u64,
+ last_handshake_time_sec: last_handshake.as_secs(),
+ public_key: p.pk,
+ })
+ }
+ state
}
}
diff --git a/src/configuration/error.rs b/src/configuration/error.rs
new file mode 100644
index 0000000..74e2144
--- /dev/null
+++ b/src/configuration/error.rs
@@ -0,0 +1,28 @@
+pub enum ConfigError {
+ NoSuchPeer,
+ NotListening,
+ FailedToBind,
+ InvalidHexValue,
+ InvalidPortNumber,
+ InvalidFwmark,
+ InvalidKey,
+ UnsupportedValue,
+ UnsupportedProtocolVersion,
+}
+
+impl ConfigError {
+ fn errno(&self) -> i32 {
+ // TODO: obtain the correct error values
+ match self {
+ ConfigError::NoSuchPeer => 1,
+ ConfigError::NotListening => 2,
+ ConfigError::FailedToBind => 3,
+ ConfigError::InvalidHexValue => 4,
+ ConfigError::InvalidPortNumber => 5,
+ ConfigError::InvalidFwmark => 6,
+ ConfigError::UnsupportedValue => 7,
+ ConfigError::InvalidKey => 8,
+ ConfigError::UnsupportedProtocolVersion => 9,
+ }
+ }
+}
diff --git a/src/configuration/mod.rs b/src/configuration/mod.rs
index 83419bc..26f0c6e 100644
--- a/src/configuration/mod.rs
+++ b/src/configuration/mod.rs
@@ -1,8 +1,12 @@
mod config;
+mod error;
+mod uapi;
use super::platform::Endpoint;
use super::platform::{bind, tun};
use super::wireguard::Wireguard;
+pub use error::ConfigError;
+
pub use config::Configuration;
pub use config::WireguardConfig;
diff --git a/src/configuration/uapi.rs b/src/configuration/uapi.rs
new file mode 100644
index 0000000..d5b3262
--- /dev/null
+++ b/src/configuration/uapi.rs
@@ -0,0 +1,161 @@
+use hex::FromHex;
+use x25519_dalek::{PublicKey, StaticSecret};
+
+use super::{ConfigError, Configuration};
+
+struct StreamPeer {
+ public_key: PublicKey,
+ update_only: bool,
+ added: bool,
+}
+
+struct StreamParser<C: Configuration> {
+ config: C,
+ update_only: bool,
+ peer: Option<StreamPeer>,
+}
+
+impl<C: Configuration> StreamParser<C> {
+ fn parse_interface_line(&mut self, key: &str, value: &str) -> (bool, Option<ConfigError>) {
+ let err = match key {
+ "private_key" => match <[u8; 32]>::from_hex(value) {
+ Ok(sk) => {
+ self.config.set_private_key(if sk == [0u8; 32] {
+ None
+ } else {
+ Some(StaticSecret::from(sk))
+ });
+ None
+ }
+ Err(_) => Some(ConfigError::InvalidHexValue),
+ },
+ "listen_port" => match value.parse() {
+ Ok(port) => {
+ self.config.set_listen_port(Some(port));
+ None
+ }
+ Err(_) => Some(ConfigError::InvalidPortNumber),
+ },
+ "fwmark" => match value.parse() {
+ Ok(fwmark) => {
+ self.config
+ .set_fwmark(if fwmark == 0 { None } else { Some(fwmark) });
+ None
+ }
+ Err(_) => Some(ConfigError::InvalidFwmark),
+ },
+ "replace_peers" => match value {
+ "true" => {
+ for p in self.config.get_peers() {
+ self.config.remove_peer(&p.public_key)
+ }
+ None
+ }
+ _ => Some(ConfigError::UnsupportedValue),
+ },
+
+ // transition to peer configuration
+ "public_key" => {
+ return (true, None);
+ }
+
+ // unknown key
+ _ => Some(ConfigError::InvalidKey),
+ };
+ (false, err)
+ }
+
+ fn parse_peer_line(&mut self, key: &str, value: &str) -> Option<ConfigError> {
+ // add a p
+ let mut flush_peer = || match self.peer.as_mut() {
+ None => (),
+ Some(peer) => {
+ if !peer.added {
+ peer.added = true;
+ if !peer.update_only {
+ self.config.add_peer(&peer.public_key);
+ }
+ }
+ }
+ };
+
+ match key {
+ // new peer
+ "public_key" => {
+ // add previous peer
+ flush_peer();
+
+ // create state for new peer
+ match <[u8; 32]>::from_hex(value) {
+ Ok(pk) => {
+ self.peer = Some(StreamPeer {
+ public_key: PublicKey::from(pk),
+ update_only: false,
+ added: false,
+ });
+ None
+ }
+ Err(_) => Some(ConfigError::InvalidHexValue),
+ }
+ }
+
+ "remove" => {
+ let peer = self.peer.as_ref().unwrap();
+ self.config.remove_peer(&peer.public_key);
+ None
+ }
+
+ "update_only" => {
+ let peer = self.peer.as_mut().unwrap();
+ peer.update_only = true;
+ None
+ }
+
+ "preshared_key" => {
+ // add peer (if not exists)
+ let peer = self.peer.as_mut().unwrap();
+ if !peer.added && !peer.update_only {
+ self.config.add_peer(&peer.public_key);
+ peer.added = true;
+ }
+
+ // set preshared key
+ match <[u8; 32]>::from_hex(value) {
+ Ok(psk) => {
+ self.config.set_preshared_key(
+ &peer.public_key,
+ if psk == [0u8; 32] { None } else { Some(psk) },
+ );
+ None
+ }
+ Err(_) => Some(ConfigError::InvalidHexValue),
+ }
+ }
+
+ "endpoint" => None,
+
+ "persistent_keepalive_interval" => None,
+
+ "replace_allowed_ips" => None,
+
+ "allowed_ip" => None,
+
+ // set protocol version of peer
+ "protocol_version" => {
+ let parse_res: Result<usize, _> = value.parse();
+ match parse_res {
+ Ok(version) => {
+ if version == 0 || version > self.config.get_protocol_version() {
+ Some(ConfigError::UnsupportedProtocolVersion)
+ } else {
+ None
+ }
+ }
+ Err(_) => Some(ConfigError::UnsupportedProtocolVersion),
+ }
+ }
+ // unknown key
+ _ => Some(ConfigError::InvalidKey),
+ }
+ }
+}