diff options
author | Mathias Hall-Andersen <mathias@hall-andersen.dk> | 2019-11-11 23:13:46 +0100 |
---|---|---|
committer | Mathias Hall-Andersen <mathias@hall-andersen.dk> | 2019-11-11 23:13:46 +0100 |
commit | 5b555a2e176bd5310d2efa614f67c96cb314eda4 (patch) | |
tree | b79cb04b38e052fb8ed63d7212020a1c8a31b6f2 /src | |
parent | Implemented UAPI "get" line-parser (diff) | |
download | wireguard-rs-5b555a2e176bd5310d2efa614f67c96cb314eda4.tar.xz wireguard-rs-5b555a2e176bd5310d2efa614f67c96cb314eda4.zip |
Work on UAPI serialize device
Diffstat (limited to 'src')
-rw-r--r-- | src/configuration/config.rs | 18 | ||||
-rw-r--r-- | src/configuration/uapi/get.rs | 41 | ||||
-rw-r--r-- | src/configuration/uapi/mod.rs | 45 | ||||
-rw-r--r-- | src/configuration/uapi/set.rs | 21 | ||||
-rw-r--r-- | src/wireguard/handshake/device.rs | 2 | ||||
-rw-r--r-- | src/wireguard/wireguard.rs | 3 |
6 files changed, 113 insertions, 17 deletions
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<T: tun::Tun, B: bind::Platform> { @@ -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<ConfigError>; + fn get_listen_port(&self) -> Option<u16>; + /// Returns the state of all peers /// /// # Returns /// /// A list of structures describing the state of each peer fn get_peers(&self) -> Vec<PeerState>; + + fn get_fwmark(&self) -> Option<u32>; } impl<T: tun::Tun, B: bind::Platform> Configuration for WireguardConfig<T, B> { + fn get_fwmark(&self) -> Option<u32> { + self.network + .lock() + .as_ref() + .and_then(|bind| bind.get_fwmark()) + } + fn set_private_key(&self, sk: Option<StaticSecret>) { self.wireguard.set_key(sk) } @@ -178,6 +190,10 @@ impl<T: tun::Tun, B: bind::Platform> Configuration for WireguardConfig<T, B> { 1 } + fn get_listen_port(&self) -> Option<u16> { + self.network.lock().as_ref().map(|bind| bind.get_port()) + } + fn set_listen_port(&self, port: Option<u16>) -> Option<ConfigError> { let mut bind = self.network.lock(); @@ -285,6 +301,7 @@ impl<T: tun::Tun, B: bind::Platform> Configuration for WireguardConfig<T, B> { fn get_peers(&self) -> Vec<PeerState> { 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<T: tun::Tun, B: bind::Platform> Configuration for WireguardConfig<T, B> { // 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<C: Configuration> { impl<C: Configuration> Serializer<C> { fn get(&self) -> Vec<String> { - 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<C: Configuration, R: Read, W: Write> { + config: C, + reader: R, + writer: W, +} + +impl<C: Configuration, R: Read, W: Write> Parser<C, R, W> { + fn new(&self, reader: R, writer: W, config: C) -> Parser<C, R, W> { + 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<C: Configuration> { state: ParserState, } -struct Serializer<C: Configuration> { - config: C, -} - impl<C: Configuration> LineParser<C> { fn new_peer(value: &str) -> Result<ParserState, ConfigError> { match <[u8; 32]>::from_hex(value) { @@ -34,6 +30,7 @@ impl<C: Configuration> LineParser<C> { } fn parse_line(&mut self, key: &str, value: &str) -> Option<ConfigError> { + // add the peer if not update_only let flush_peer = |st: ParserState| -> ParserState { match st { ParserState::Peer { @@ -51,7 +48,7 @@ impl<C: Configuration> LineParser<C> { }; // 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<C: Configuration> LineParser<C> { // 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<Psk, ConfigError> { + pub fn get_psk(&self, pk: &PublicKey) -> Result<Psk, ConfigError> { 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<T: Tun, B: Bind> Wireguard<T, B> { 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()) { |