aboutsummaryrefslogtreecommitdiffstats
path: root/src/configuration/uapi/set.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/configuration/uapi/set.rs156
1 files changed, 89 insertions, 67 deletions
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<u64>,
+ protocol_version: Option<usize>,
+ endpoint: Option<SocketAddr>,
+}
+
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<ParserState, ConfigError> {
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<C: Configuration>(config: &C, peer: &ParsedPeer) -> Option<ConfigError> {
+ 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<usize, _> = 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(())
+ }
}
}