summaryrefslogtreecommitdiffstats
path: root/src/configuration/uapi.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/configuration/uapi.rs')
-rw-r--r--src/configuration/uapi.rs161
1 files changed, 161 insertions, 0 deletions
diff --git a/src/configuration/uapi.rs b/src/configuration/uapi.rs
new file mode 100644
index 0000000..d5b3262
--- /dev/null
+++ b/src/configuration/uapi.rs
@@ -0,0 +1,161 @@
+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),
+ }
+ }
+}