summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMathias Hall-Andersen <mathias@hall-andersen.dk>2019-11-10 17:57:39 +0100
committerMathias Hall-Andersen <mathias@hall-andersen.dk>2019-11-10 17:57:39 +0100
commit2ff044dda954ad2402309bd9022b33dd385bb3d7 (patch)
tree3030233c8958c96e292a4f3dd80a7622eb042c26 /src
parentRemoval of secret key in the handshake module (diff)
downloadwireguard-rs-2ff044dda954ad2402309bd9022b33dd385bb3d7.tar.xz
wireguard-rs-2ff044dda954ad2402309bd9022b33dd385bb3d7.zip
Implemented UAPI "get" line-parser
Diffstat (limited to 'src')
-rw-r--r--src/configuration/error.rs6
-rw-r--r--src/configuration/uapi.rs161
-rw-r--r--src/configuration/uapi/get.rs15
-rw-r--r--src/configuration/uapi/mod.rs4
-rw-r--r--src/configuration/uapi/set.rs215
5 files changed, 240 insertions, 161 deletions
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<C: Configuration> {
- config: C,
- update_only: bool,
- peer: Option<StreamPeer>,
-}
-
-impl<C: Configuration> StreamParser<C> {
- fn parse_interface_line(&mut self, key: &str, value: &str) -> (bool, Option<ConfigError>) {
- 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<ConfigError> {
- // 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<usize, _> = 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<C: Configuration> {
+ config: C,
+}
+
+impl<C: Configuration> Serializer<C> {
+ fn get(&self) -> Vec<String> {
+ 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<C: Configuration> {
+ config: C,
+ 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) {
+ 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<ConfigError> {
+ 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<usize, _> = 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
+ }
+ }
+ }
+}