From 5b555a2e176bd5310d2efa614f67c96cb314eda4 Mon Sep 17 00:00:00 2001 From: Mathias Hall-Andersen Date: Mon, 11 Nov 2019 23:13:46 +0100 Subject: Work on UAPI serialize device --- src/configuration/config.rs | 18 ++++++++++++++++ src/configuration/uapi/get.rs | 41 ++++++++++++++++++++++++++++++++++- src/configuration/uapi/mod.rs | 45 +++++++++++++++++++++++++++++++++++++++ src/configuration/uapi/set.rs | 21 ++++++------------ src/wireguard/handshake/device.rs | 2 +- src/wireguard/wireguard.rs | 3 +++ 6 files changed, 113 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/configuration/config.rs b/src/configuration/config.rs index ed78e43..b1c0121 100644 --- a/src/configuration/config.rs +++ b/src/configuration/config.rs @@ -19,6 +19,7 @@ pub struct PeerState { pub last_handshake_time_nsec: u64, pub public_key: PublicKey, pub allowed_ips: Vec<(IpAddr, u32)>, + pub preshared_key: Option<[u8; 32]>, } pub struct WireguardConfig { @@ -157,15 +158,26 @@ pub trait Configuration { /// 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; + fn get_listen_port(&self) -> Option; + /// Returns the state of all peers /// /// # Returns /// /// A list of structures describing the state of each peer fn get_peers(&self) -> Vec; + + fn get_fwmark(&self) -> Option; } impl Configuration for WireguardConfig { + fn get_fwmark(&self) -> Option { + self.network + .lock() + .as_ref() + .and_then(|bind| bind.get_fwmark()) + } + fn set_private_key(&self, sk: Option) { self.wireguard.set_key(sk) } @@ -178,6 +190,10 @@ impl Configuration for WireguardConfig { 1 } + fn get_listen_port(&self) -> Option { + self.network.lock().as_ref().map(|bind| bind.get_port()) + } + fn set_listen_port(&self, port: Option) -> Option { let mut bind = self.network.lock(); @@ -285,6 +301,7 @@ impl Configuration for WireguardConfig { fn get_peers(&self) -> 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()) @@ -293,6 +310,7 @@ impl Configuration for WireguardConfig { // extract state into PeerState state.push(PeerState { + preshared_key: self.wireguard.get_psk(&p.pk), rx_bytes: p.rx_bytes.load(Ordering::Relaxed), tx_bytes: p.tx_bytes.load(Ordering::Relaxed), allowed_ips: p.router.list_allowed_ips(), diff --git a/src/configuration/uapi/get.rs b/src/configuration/uapi/get.rs index c6f3c42..99ebbde 100644 --- a/src/configuration/uapi/get.rs +++ b/src/configuration/uapi/get.rs @@ -10,6 +10,45 @@ struct Serializer { impl Serializer { fn get(&self) -> Vec { - vec![] + let mut peers = self.config.get_peers(); + let mut lines = Vec::with_capacity(peers.len() * 6 + 5); + let mut write = |key, value: String| { + lines.push(String::new() + key + "=" + &value); + }; + + // serialize interface + self.config + .get_private_key() + .map(|sk| write("private_key", hex::encode(sk.to_bytes()))); + + self.config + .get_listen_port() + .map(|port| write("listen_port", port.to_string())); + + self.config + .get_fwmark() + .map(|fwmark| write("fwmark", fwmark.to_string())); + + // serialize all peers + while let Some(p) = peers.pop() { + write("rx_bytes", p.rx_bytes.to_string()); + write("tx_bytes", p.tx_bytes.to_string()); + write( + "last_handshake_time_sec", + p.last_handshake_time_nsec.to_string(), + ); + write( + "last_handshake_time_nsec", + p.last_handshake_time_nsec.to_string(), + ); + write("public_key", hex::encode(p.public_key.as_bytes())); + p.preshared_key + .map(|psk| write("preshared_key", hex::encode(psk))); + for (ip, cidr) in p.allowed_ips { + write("allowed_ip", ip.to_string() + "/" + &cidr.to_string()) + } + } + + lines } } diff --git a/src/configuration/uapi/mod.rs b/src/configuration/uapi/mod.rs index 5d89b94..cba156d 100644 --- a/src/configuration/uapi/mod.rs +++ b/src/configuration/uapi/mod.rs @@ -1,4 +1,49 @@ mod get; mod set; +use std::io::{Read, Write}; + use super::{ConfigError, Configuration}; + +const MAX_LINE_LENGTH: usize = 128; + +struct Parser { + config: C, + reader: R, + writer: W, +} + +impl Parser { + fn new(&self, reader: R, writer: W, config: C) -> Parser { + Parser { + config, + reader, + writer, + } + } + + fn parse(&mut self) -> Option<()> { + // read string up to maximum length (why is this not in std?) + let mut line = || { + let mut m: [u8; 1] = [0u8]; + let mut l: String = String::with_capacity(MAX_LINE_LENGTH); + while let Ok(_) = self.reader.read_exact(&mut m) { + let c = m[0] as char; + if c == '\n' { + return Some(l); + }; + l.push(c); + if l.len() > MAX_LINE_LENGTH { + break; + } + } + None + }; + + match line()?.as_str() { + "get=1" => Some(()), + "set=1" => Some(()), + _ => None, + } + } +} diff --git a/src/configuration/uapi/set.rs b/src/configuration/uapi/set.rs index 575c7ad..c609d83 100644 --- a/src/configuration/uapi/set.rs +++ b/src/configuration/uapi/set.rs @@ -7,8 +7,8 @@ use super::{ConfigError, Configuration}; #[derive(Copy, Clone)] enum ParserState { Peer { - public_key: PublicKey, // peer identity - update_only: bool, // is the update_only flag set + public_key: PublicKey, + update_only: bool, }, Interface, } @@ -18,10 +18,6 @@ struct LineParser { state: ParserState, } -struct Serializer { - config: C, -} - impl LineParser { fn new_peer(value: &str) -> Result { match <[u8; 32]>::from_hex(value) { @@ -34,6 +30,7 @@ impl LineParser { } fn parse_line(&mut self, key: &str, value: &str) -> Option { + // add the peer if not update_only let flush_peer = |st: ParserState| -> ParserState { match st { ParserState::Peer { @@ -51,7 +48,7 @@ impl LineParser { }; // parse line and update parser state - let new_state = match self.state { + match self.state { // configure the interface ParserState::Interface => match key { // opt: set private key @@ -202,14 +199,8 @@ impl LineParser { // unknown key _ => Err(ConfigError::InvalidKey), }, - }; - - match new_state { - Err(e) => Some(e), - Ok(st) => { - self.state = st; - None - } } + .map(|st| self.state = st) + .err() } } diff --git a/src/wireguard/handshake/device.rs b/src/wireguard/handshake/device.rs index 85c2e45..f65692c 100644 --- a/src/wireguard/handshake/device.rs +++ b/src/wireguard/handshake/device.rs @@ -202,7 +202,7 @@ impl Device { /// A 32 byte array holding the PSK /// /// The call might fail if the public key is not found - pub fn get_psk(&self, pk: PublicKey) -> Result { + pub fn get_psk(&self, pk: &PublicKey) -> Result { match self.pk_map.get(pk.as_bytes()) { Some(peer) => Ok(peer.psk), _ => Err(ConfigError::new("No such public key")), diff --git a/src/wireguard/wireguard.rs b/src/wireguard/wireguard.rs index a890d5e..77be9f8 100644 --- a/src/wireguard/wireguard.rs +++ b/src/wireguard/wireguard.rs @@ -204,6 +204,9 @@ impl Wireguard { pub fn set_psk(&self, pk: PublicKey, psk: Option<[u8; 32]>) -> bool { self.state.handshake.write().set_psk(pk, psk).is_ok() } + pub fn get_psk(&self, pk: &PublicKey) -> Option<[u8; 32]> { + self.state.handshake.read().get_psk(pk).ok() + } pub fn add_peer(&self, pk: PublicKey) { if self.state.peers.read().contains_key(pk.as_bytes()) { -- cgit v1.2.3-59-g8ed1b