aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathias Hall-Andersen <mathias@hall-andersen.dk>2019-11-03 18:33:49 +0100
committerMathias Hall-Andersen <mathias@hall-andersen.dk>2019-11-03 18:33:49 +0100
commita0fa261a8a9542418072c42cfe73807d8d30cf88 (patch)
tree550af2cf98219323cda009fe76b81655d65719a8
parentWork on configuration interface (diff)
downloadwireguard-rs-a0fa261a8a9542418072c42cfe73807d8d30cf88.tar.xz
wireguard-rs-a0fa261a8a9542418072c42cfe73807d8d30cf88.zip
Work on UAPI parser
-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
-rw-r--r--src/wireguard/tests.rs4
-rw-r--r--src/wireguard/wireguard.rs22
6 files changed, 231 insertions, 41 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),
+ }
+ }
+}
diff --git a/src/wireguard/tests.rs b/src/wireguard/tests.rs
index 6a02e1f..83ef594 100644
--- a/src/wireguard/tests.rs
+++ b/src/wireguard/tests.rs
@@ -120,8 +120,8 @@ fn test_pure_wireguard() {
let pk2 = PublicKey::from(&sk2);
- wg1.new_peer(pk2);
- wg2.new_peer(pk1);
+ wg1.add_peer(pk2);
+ wg2.add_peer(pk1);
wg1.set_key(Some(sk1));
wg2.set_key(Some(sk2));
diff --git a/src/wireguard/wireguard.rs b/src/wireguard/wireguard.rs
index 78f24da..6cdae6c 100644
--- a/src/wireguard/wireguard.rs
+++ b/src/wireguard/wireguard.rs
@@ -148,16 +148,6 @@ impl<B: Bind> PeerInner<B> {
self.queue.lock().send(HandshakeJob::New(self.pk)).unwrap();
}
}
-
- pub fn set_persistent_keepalive_interval(&self, interval: usize) {
- self.timers().send_persistent_keepalive.stop();
- self.keepalive.store(interval, Ordering::SeqCst);
- if interval > 0 {
- self.timers()
- .send_persistent_keepalive
- .start(Duration::from_secs(internal as u64));
- }
- }
}
struct Handshake {
@@ -260,7 +250,11 @@ impl<T: Tun, B: Bind> Wireguard<T, B> {
self.state.handshake.write().device.set_psk(pk, psk).is_ok()
}
- pub fn new_peer(&self, pk: PublicKey) {
+ pub fn add_peer(&self, pk: PublicKey) {
+ if self.state.peers.read().contains_key(pk.as_bytes()) {
+ return;
+ }
+
let mut rng = OsRng::new().unwrap();
let state = Arc::new(PeerInner {
id: rng.gen(),
@@ -278,9 +272,6 @@ impl<T: Tun, B: Bind> Wireguard<T, B> {
// create a router peer
let router = Arc::new(self.state.router.new_peer(state.clone()));
- // add to the handshake device
- self.state.handshake.write().device.add(pk).unwrap(); // TODO: handle adding of public key for interface
-
// form WireGuard peer
let peer = Peer { router, state };
@@ -295,6 +286,9 @@ impl<T: Tun, B: Bind> Wireguard<T, B> {
// finally, add the peer to the wireguard device
let mut peers = self.state.peers.write();
peers.entry(*pk.as_bytes()).or_insert(peer);
+
+ // add to the handshake device
+ self.state.handshake.write().device.add(pk).unwrap(); // TODO: handle adding of public key for interface
}
/* Begin consuming messages from the reader.