From 05710c455f1c759cf9bc1a1eaa6307fe564f15cc Mon Sep 17 00:00:00 2001 From: Mathias Hall-Andersen Date: Fri, 15 Nov 2019 15:32:36 +0100 Subject: Update UAPI semantics for remove --- src/configuration/uapi/get.rs | 10 +-- src/configuration/uapi/mod.rs | 29 ++++---- src/configuration/uapi/set.rs | 156 ++++++++++++++++++++++++------------------ 3 files changed, 112 insertions(+), 83 deletions(-) (limited to 'src/configuration/uapi') diff --git a/src/configuration/uapi/get.rs b/src/configuration/uapi/get.rs index 9b05421..0874cfc 100644 --- a/src/configuration/uapi/get.rs +++ b/src/configuration/uapi/get.rs @@ -1,6 +1,8 @@ use hex::FromHex; use subtle::ConstantTimeEq; +use log; + use super::Configuration; use std::io; @@ -8,9 +10,11 @@ pub fn serialize(writer: &mut W, config: &C) -> let mut write = |key: &'static str, value: String| { debug_assert!(value.is_ascii()); debug_assert!(key.is_ascii()); + log::trace!("UAPI: return : {} = {}", key, value); writer.write(key.as_ref())?; writer.write(b"=")?; - writer.write(value.as_ref()) + writer.write(value.as_ref())?; + writer.write(b"\n") }; // serialize interface @@ -40,9 +44,7 @@ pub fn serialize(writer: &mut W, config: &C) -> p.last_handshake_time_nsec.to_string(), )?; write("public_key", hex::encode(p.public_key.as_bytes()))?; - if let Some(psk) = p.preshared_key { - write("preshared_key", hex::encode(psk))?; - } + write("preshared_key", hex::encode(p.preshared_key))?; for (ip, cidr) in p.allowed_ips { write("allowed_ip", ip.to_string() + "/" + &cidr.to_string())?; } diff --git a/src/configuration/uapi/mod.rs b/src/configuration/uapi/mod.rs index 117d970..4261e7d 100644 --- a/src/configuration/uapi/mod.rs +++ b/src/configuration/uapi/mod.rs @@ -1,6 +1,7 @@ mod get; mod set; +use log; use std::io::{Read, Write}; use super::{ConfigError, Configuration}; @@ -10,10 +11,9 @@ use set::LineParser; const MAX_LINE_LENGTH: usize = 256; -pub fn process(reader: &mut R, writer: &mut W, config: &C) { - fn operation( - reader: &mut R, - writer: &mut W, +pub fn handle(stream: &mut S, config: &C) { + fn operation( + stream: &mut S, config: &C, ) -> Result<(), ConfigError> { // read string up to maximum length (why is this not in std?) @@ -23,6 +23,7 @@ pub fn process(reader: &mut R, writer: &mut while let Ok(_) = reader.read_exact(&mut m) { let c = m[0] as char; if c == '\n' { + log::trace!("UAPI, line: {}", l); return Ok(l); }; l.push(c); @@ -43,12 +44,16 @@ pub fn process(reader: &mut R, writer: &mut }; // read operation line - match readline(reader)?.as_str() { - "get=1" => serialize(writer, config).map_err(|_| ConfigError::IOError), + match readline(stream)?.as_str() { + "get=1" => { + log::debug!("UAPI, Get operation"); + serialize(stream, config).map_err(|_| ConfigError::IOError) + } "set=1" => { + log::debug!("UAPI, Set operation"); let mut parser = LineParser::new(config); loop { - let ln = readline(reader)?; + let ln = readline(stream)?; if ln == "" { break Ok(()); }; @@ -61,17 +66,17 @@ pub fn process(reader: &mut R, writer: &mut } // process operation - let res = operation(reader, writer, config); - log::debug!("{:?}", res); + let res = operation(stream, config); + log::debug!("UAPI, Result of operation: {:?}", res); // return errno - let _ = writer.write("errno=".as_ref()); - let _ = writer.write( + let _ = stream.write("errno=".as_ref()); + let _ = stream.write( match res { Err(e) => e.errno().to_string(), Ok(()) => "0".to_owned(), } .as_ref(), ); - let _ = writer.write("\n\n".as_ref()); + let _ = stream.write("\n\n".as_ref()); } diff --git a/src/configuration/uapi/set.rs b/src/configuration/uapi/set.rs index 4c2c554..e449edd 100644 --- a/src/configuration/uapi/set.rs +++ b/src/configuration/uapi/set.rs @@ -1,18 +1,27 @@ use hex::FromHex; +use std::net::{IpAddr, SocketAddr}; use subtle::ConstantTimeEq; use x25519_dalek::{PublicKey, StaticSecret}; use super::{ConfigError, Configuration}; -#[derive(Copy, Clone)] enum ParserState { - Peer { - public_key: PublicKey, - update_only: bool, - }, + Peer(ParsedPeer), Interface, } +struct ParsedPeer { + public_key: PublicKey, + update_only: bool, + allowed_ips: Vec<(IpAddr, u32)>, + remove: bool, + preshared_key: Option<[u8; 32]>, + replace_allowed_ips: bool, + persistent_keepalive_interval: Option, + protocol_version: Option, + endpoint: Option, +} + pub struct LineParser<'a, C: Configuration> { config: &'a C, state: ParserState, @@ -28,45 +37,71 @@ impl<'a, C: Configuration> LineParser<'a, C> { fn new_peer(value: &str) -> Result { match <[u8; 32]>::from_hex(value) { - Ok(pk) => Ok(ParserState::Peer { + Ok(pk) => Ok(ParserState::Peer(ParsedPeer { public_key: PublicKey::from(pk), + remove: false, update_only: false, - }), + allowed_ips: vec![], + preshared_key: None, + replace_allowed_ips: false, + persistent_keepalive_interval: None, + protocol_version: None, + endpoint: None, + })), Err(_) => Err(ConfigError::InvalidHexValue), } } pub fn parse_line(&mut self, key: &str, value: &str) -> Result<(), ConfigError> { - // add the peer if not update_only - let flush_peer = |st: ParserState| -> ParserState { - match st { - ParserState::Peer { - public_key, - update_only: false, - } => { - self.config.add_peer(&public_key); - ParserState::Peer { - public_key, - update_only: true, - } + // flush peer updates to configuration + fn flush_peer(config: &C, peer: &ParsedPeer) -> Option { + if peer.remove { + config.remove_peer(&peer.public_key); + return None; + } + + if !peer.update_only { + config.add_peer(&peer.public_key); + } + + for (ip, masklen) in &peer.allowed_ips { + config.add_allowed_ip(&peer.public_key, *ip, *masklen); + } + + if let Some(psk) = peer.preshared_key { + config.set_preshared_key(&peer.public_key, psk); + } + + if let Some(secs) = peer.persistent_keepalive_interval { + config.set_persistent_keepalive_interval(&peer.public_key, secs); + } + + if let Some(version) = peer.protocol_version { + if version == 0 || version > config.get_protocol_version() { + return Some(ConfigError::UnsupportedProtocolVersion); } - _ => st, } + + if let Some(endpoint) = peer.endpoint { + config.set_endpoint(&peer.public_key, endpoint); + }; + + None }; // parse line and update parser state - self.state = match self.state { + match self.state { // configure the interface ParserState::Interface => match key { // opt: set private key "private_key" => match <[u8; 32]>::from_hex(value) { Ok(sk) => { - self.config.set_private_key(if sk == [0u8; 32] { + self.config.set_private_key(if sk.ct_eq(&[0u8; 32]).into() { None } else { Some(StaticSecret::from(sk)) }); - Ok(self.state) + Ok(()) } Err(_) => Err(ConfigError::InvalidHexValue), }, @@ -75,7 +110,7 @@ impl<'a, C: Configuration> LineParser<'a, C> { "listen_port" => match value.parse() { Ok(port) => { self.config.set_listen_port(Some(port)); - Ok(self.state) + Ok(()) } Err(_) => Err(ConfigError::InvalidPortNumber), }, @@ -85,7 +120,7 @@ impl<'a, C: Configuration> LineParser<'a, C> { Ok(fwmark) => { self.config .set_fwmark(if fwmark == 0 { None } else { Some(fwmark) }); - Ok(self.state) + Ok(()) } Err(_) => Err(ConfigError::InvalidFwmark), }, @@ -96,51 +131,47 @@ impl<'a, C: Configuration> LineParser<'a, C> { for p in self.config.get_peers() { self.config.remove_peer(&p.public_key) } - Ok(self.state) + Ok(()) } _ => Err(ConfigError::UnsupportedValue), }, // opt: transition to peer configuration - "public_key" => Self::new_peer(value), + "public_key" => { + self.state = Self::new_peer(value)?; + Ok(()) + } // unknown key _ => Err(ConfigError::InvalidKey), }, // configure peers - ParserState::Peer { public_key, .. } => match key { + ParserState::Peer(ref mut peer) => match key { // opt: new peer "public_key" => { - flush_peer(self.state); - Self::new_peer(value) + flush_peer(self.config, &peer); + self.state = Self::new_peer(value)?; + Ok(()) } // opt: remove peer "remove" => { - self.config.remove_peer(&public_key); - Ok(self.state) + peer.remove = true; + Ok(()) } // opt: update only - "update_only" => Ok(ParserState::Peer { - public_key, - update_only: true, - }), + "update_only" => { + peer.update_only = true; + Ok(()) + } // opt: set preshared key "preshared_key" => match <[u8; 32]>::from_hex(value) { Ok(psk) => { - let st = flush_peer(self.state); - self.config.set_preshared_key( - &public_key, - if psk.ct_eq(&[0u8; 32]).into() { - None - } else { - Some(psk) - }, - ); - Ok(st) + peer.preshared_key = Some(psk); + Ok(()) } Err(_) => Err(ConfigError::InvalidHexValue), }, @@ -148,9 +179,8 @@ impl<'a, C: Configuration> LineParser<'a, C> { // opt: set endpoint "endpoint" => match value.parse() { Ok(endpoint) => { - let st = flush_peer(self.state); - self.config.set_endpoint(&public_key, endpoint); - Ok(st) + peer.endpoint = Some(endpoint); + Ok(()) } Err(_) => Err(ConfigError::InvalidSocketAddr), }, @@ -158,19 +188,17 @@ impl<'a, C: Configuration> LineParser<'a, C> { // opt: set persistent keepalive interval "persistent_keepalive_interval" => match value.parse() { Ok(secs) => { - let st = flush_peer(self.state); - self.config - .set_persistent_keepalive_interval(&public_key, secs); - Ok(st) + peer.persistent_keepalive_interval = Some(secs); + Ok(()) } Err(_) => Err(ConfigError::InvalidKeepaliveInterval), }, // opt replace allowed ips "replace_allowed_ips" => { - let st = flush_peer(self.state); - self.config.replace_allowed_ips(&public_key); - Ok(st) + peer.replace_allowed_ips = true; + peer.allowed_ips.clear(); + Ok(()) } // opt add allowed ips @@ -180,9 +208,8 @@ impl<'a, C: Configuration> LineParser<'a, C> { let cidr = split.next().and_then(|x| x.parse().ok()); match (addr, cidr) { (Some(addr), Some(cidr)) => { - let st = flush_peer(self.state); - self.config.add_allowed_ip(&public_key, addr, cidr); - Ok(st) + peer.allowed_ips.push((addr, cidr)); + Ok(()) } _ => Err(ConfigError::InvalidAllowedIp), } @@ -193,11 +220,8 @@ impl<'a, C: Configuration> LineParser<'a, C> { let parse_res: Result = value.parse(); match parse_res { Ok(version) => { - if version == 0 || version > self.config.get_protocol_version() { - Err(ConfigError::UnsupportedProtocolVersion) - } else { - Ok(self.state) - } + peer.protocol_version = Some(version); + Ok(()) } Err(_) => Err(ConfigError::UnsupportedProtocolVersion), } @@ -206,8 +230,6 @@ impl<'a, C: Configuration> LineParser<'a, C> { // unknown key _ => Err(ConfigError::InvalidKey), }, - }?; - - Ok(()) + } } } -- cgit v1.2.3-59-g8ed1b