From 2ff044dda954ad2402309bd9022b33dd385bb3d7 Mon Sep 17 00:00:00 2001 From: Mathias Hall-Andersen Date: Sun, 10 Nov 2019 17:57:39 +0100 Subject: Implemented UAPI "get" line-parser --- src/configuration/error.rs | 6 ++ src/configuration/uapi.rs | 161 ------------------------------- src/configuration/uapi/get.rs | 15 +++ src/configuration/uapi/mod.rs | 4 + src/configuration/uapi/set.rs | 215 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 240 insertions(+), 161 deletions(-) delete mode 100644 src/configuration/uapi.rs create mode 100644 src/configuration/uapi/get.rs create mode 100644 src/configuration/uapi/mod.rs create mode 100644 src/configuration/uapi/set.rs (limited to 'src') diff --git a/src/configuration/error.rs b/src/configuration/error.rs index 74e2144..be08c9e 100644 --- a/src/configuration/error.rs +++ b/src/configuration/error.rs @@ -6,6 +6,9 @@ pub enum ConfigError { InvalidPortNumber, InvalidFwmark, InvalidKey, + InvalidSocketAddr, + InvalidKeepaliveInterval, + InvalidAllowedIp, UnsupportedValue, UnsupportedProtocolVersion, } @@ -20,6 +23,9 @@ impl ConfigError { ConfigError::InvalidHexValue => 4, ConfigError::InvalidPortNumber => 5, ConfigError::InvalidFwmark => 6, + ConfigError::InvalidSocketAddr => 10, + ConfigError::InvalidKeepaliveInterval => 11, + ConfigError::InvalidAllowedIp => 12, ConfigError::UnsupportedValue => 7, ConfigError::InvalidKey => 8, ConfigError::UnsupportedProtocolVersion => 9, diff --git a/src/configuration/uapi.rs b/src/configuration/uapi.rs deleted file mode 100644 index d5b3262..0000000 --- a/src/configuration/uapi.rs +++ /dev/null @@ -1,161 +0,0 @@ -use hex::FromHex; -use x25519_dalek::{PublicKey, StaticSecret}; - -use super::{ConfigError, Configuration}; - -struct StreamPeer { - public_key: PublicKey, - update_only: bool, - added: bool, -} - -struct StreamParser { - config: C, - update_only: bool, - peer: Option, -} - -impl StreamParser { - fn parse_interface_line(&mut self, key: &str, value: &str) -> (bool, Option) { - 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 { - // 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 = 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/configuration/uapi/get.rs b/src/configuration/uapi/get.rs new file mode 100644 index 0000000..c6f3c42 --- /dev/null +++ b/src/configuration/uapi/get.rs @@ -0,0 +1,15 @@ +use hex::FromHex; +use subtle::ConstantTimeEq; +use x25519_dalek::{PublicKey, StaticSecret}; + +use super::{ConfigError, Configuration}; + +struct Serializer { + config: C, +} + +impl Serializer { + fn get(&self) -> Vec { + vec![] + } +} diff --git a/src/configuration/uapi/mod.rs b/src/configuration/uapi/mod.rs new file mode 100644 index 0000000..5d89b94 --- /dev/null +++ b/src/configuration/uapi/mod.rs @@ -0,0 +1,4 @@ +mod get; +mod set; + +use super::{ConfigError, Configuration}; diff --git a/src/configuration/uapi/set.rs b/src/configuration/uapi/set.rs new file mode 100644 index 0000000..575c7ad --- /dev/null +++ b/src/configuration/uapi/set.rs @@ -0,0 +1,215 @@ +use hex::FromHex; +use subtle::ConstantTimeEq; +use x25519_dalek::{PublicKey, StaticSecret}; + +use super::{ConfigError, Configuration}; + +#[derive(Copy, Clone)] +enum ParserState { + Peer { + public_key: PublicKey, // peer identity + update_only: bool, // is the update_only flag set + }, + Interface, +} + +struct LineParser { + config: C, + state: ParserState, +} + +struct Serializer { + config: C, +} + +impl LineParser { + fn new_peer(value: &str) -> Result { + match <[u8; 32]>::from_hex(value) { + Ok(pk) => Ok(ParserState::Peer { + public_key: PublicKey::from(pk), + update_only: false, + }), + Err(_) => Err(ConfigError::InvalidHexValue), + } + } + + fn parse_line(&mut self, key: &str, value: &str) -> Option { + 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, + } + } + _ => st, + } + }; + + // parse line and update parser state + let new_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] { + None + } else { + Some(StaticSecret::from(sk)) + }); + Ok(self.state) + } + Err(_) => Err(ConfigError::InvalidHexValue), + }, + + // opt: set listen port + "listen_port" => match value.parse() { + Ok(port) => { + self.config.set_listen_port(Some(port)); + Ok(self.state) + } + Err(_) => Err(ConfigError::InvalidPortNumber), + }, + + // opt: set fwmark + "fwmark" => match value.parse() { + Ok(fwmark) => { + self.config + .set_fwmark(if fwmark == 0 { None } else { Some(fwmark) }); + Ok(self.state) + } + Err(_) => Err(ConfigError::InvalidFwmark), + }, + + // opt: remove all peers + "replace_peers" => match value { + "true" => { + for p in self.config.get_peers() { + self.config.remove_peer(&p.public_key) + } + Ok(self.state) + } + _ => Err(ConfigError::UnsupportedValue), + }, + + // opt: transition to peer configuration + "public_key" => Self::new_peer(value), + + // unknown key + _ => Err(ConfigError::InvalidKey), + }, + + // configure peers + ParserState::Peer { public_key, .. } => match key { + // opt: new peer + "public_key" => { + flush_peer(self.state); + Self::new_peer(value) + } + + // opt: remove peer + "remove" => { + self.config.remove_peer(&public_key); + Ok(self.state) + } + + // opt: update only + "update_only" => Ok(ParserState::Peer { + public_key, + update_only: true, + }), + + // 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) + } + Err(_) => Err(ConfigError::InvalidHexValue), + }, + + // opt: set endpoint + "endpoint" => match value.parse() { + Ok(endpoint) => { + let st = flush_peer(self.state); + self.config.set_endpoint(&public_key, endpoint); + Ok(st) + } + Err(_) => Err(ConfigError::InvalidSocketAddr), + }, + + // 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) + } + 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) + } + + // opt add allowed ips + "allowed_ip" => { + let mut split = value.splitn(2, "/"); + let addr = split.next().and_then(|x| x.parse().ok()); + 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) + } + _ => Err(ConfigError::InvalidAllowedIp), + } + } + + // set protocol version of peer + "protocol_version" => { + 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) + } + } + Err(_) => Err(ConfigError::UnsupportedProtocolVersion), + } + } + + // unknown key + _ => Err(ConfigError::InvalidKey), + }, + }; + + match new_state { + Err(e) => Some(e), + Ok(st) => { + self.state = st; + None + } + } + } +} -- cgit v1.2.3-59-g8ed1b