aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathias Hall-Andersen <mathias@hall-andersen.dk>2019-11-13 15:30:16 +0100
committerMathias Hall-Andersen <mathias@hall-andersen.dk>2019-11-13 15:30:16 +0100
commita85725eede89f8d7fecd10dc0628a01e48cccd7d (patch)
tree2ac1b7473b95b0791552988b6f9b6294675348f2
parentWork on UAPI serialize device (diff)
downloadwireguard-rs-a85725eede89f8d7fecd10dc0628a01e48cccd7d.tar.xz
wireguard-rs-a85725eede89f8d7fecd10dc0628a01e48cccd7d.zip
Initial version of full UAPI parser
-rw-r--r--src/configuration/error.rs30
-rw-r--r--src/configuration/uapi/get.rs94
-rw-r--r--src/configuration/uapi/mod.rs78
-rw-r--r--src/configuration/uapi/set.rs23
4 files changed, 142 insertions, 83 deletions
diff --git a/src/configuration/error.rs b/src/configuration/error.rs
index be08c9e..b7d7bb0 100644
--- a/src/configuration/error.rs
+++ b/src/configuration/error.rs
@@ -1,3 +1,7 @@
+use std::error::Error;
+use std::fmt;
+
+#[derive(Debug)]
pub enum ConfigError {
NoSuchPeer,
NotListening,
@@ -9,13 +13,32 @@ pub enum ConfigError {
InvalidSocketAddr,
InvalidKeepaliveInterval,
InvalidAllowedIp,
+ InvalidOperation,
+ LineTooLong,
+ IOError,
UnsupportedValue,
UnsupportedProtocolVersion,
}
+impl fmt::Display for ConfigError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ConfigError(errno = {})", self.errno())
+ }
+}
+
+impl Error for ConfigError {
+ fn description(&self) -> &str {
+ ""
+ }
+
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ None
+ }
+}
+
impl ConfigError {
- fn errno(&self) -> i32 {
- // TODO: obtain the correct error values
+ pub fn errno(&self) -> i32 {
+ // TODO: obtain the correct errorno values
match self {
ConfigError::NoSuchPeer => 1,
ConfigError::NotListening => 2,
@@ -26,9 +49,12 @@ impl ConfigError {
ConfigError::InvalidSocketAddr => 10,
ConfigError::InvalidKeepaliveInterval => 11,
ConfigError::InvalidAllowedIp => 12,
+ ConfigError::InvalidOperation => 15,
ConfigError::UnsupportedValue => 7,
+ ConfigError::LineTooLong => 13,
ConfigError::InvalidKey => 8,
ConfigError::UnsupportedProtocolVersion => 9,
+ ConfigError::IOError => 14,
}
}
}
diff --git a/src/configuration/uapi/get.rs b/src/configuration/uapi/get.rs
index 99ebbde..9b05421 100644
--- a/src/configuration/uapi/get.rs
+++ b/src/configuration/uapi/get.rs
@@ -1,54 +1,52 @@
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> {
- let mut peers = self.config.get_peers();
- let mut lines = Vec::with_capacity(peers.len() * 6 + 5);
- let mut write = |key, value: String| {
- lines.push(String::new() + key + "=" + &value);
- };
-
- // serialize interface
- self.config
- .get_private_key()
- .map(|sk| write("private_key", hex::encode(sk.to_bytes())));
-
- self.config
- .get_listen_port()
- .map(|port| write("listen_port", port.to_string()));
-
- self.config
- .get_fwmark()
- .map(|fwmark| write("fwmark", fwmark.to_string()));
-
- // serialize all peers
- while let Some(p) = peers.pop() {
- write("rx_bytes", p.rx_bytes.to_string());
- write("tx_bytes", p.tx_bytes.to_string());
- write(
- "last_handshake_time_sec",
- p.last_handshake_time_nsec.to_string(),
- );
- write(
- "last_handshake_time_nsec",
- p.last_handshake_time_nsec.to_string(),
- );
- write("public_key", hex::encode(p.public_key.as_bytes()));
- p.preshared_key
- .map(|psk| write("preshared_key", hex::encode(psk)));
- for (ip, cidr) in p.allowed_ips {
- write("allowed_ip", ip.to_string() + "/" + &cidr.to_string())
- }
+use super::Configuration;
+use std::io;
+
+pub fn serialize<C: Configuration, W: io::Write>(writer: &mut W, config: &C) -> io::Result<()> {
+ let mut write = |key: &'static str, value: String| {
+ debug_assert!(value.is_ascii());
+ debug_assert!(key.is_ascii());
+ writer.write(key.as_ref())?;
+ writer.write(b"=")?;
+ writer.write(value.as_ref())
+ };
+
+ // serialize interface
+ config
+ .get_private_key()
+ .map(|sk| write("private_key", hex::encode(sk.to_bytes())));
+
+ config
+ .get_listen_port()
+ .map(|port| write("listen_port", port.to_string()));
+
+ config
+ .get_fwmark()
+ .map(|fwmark| write("fwmark", fwmark.to_string()));
+
+ // serialize all peers
+ let mut peers = config.get_peers();
+ while let Some(p) = peers.pop() {
+ write("rx_bytes", p.rx_bytes.to_string())?;
+ write("tx_bytes", p.tx_bytes.to_string())?;
+ write(
+ "last_handshake_time_sec",
+ p.last_handshake_time_nsec.to_string(),
+ )?;
+ write(
+ "last_handshake_time_nsec",
+ 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))?;
+ }
+ for (ip, cidr) in p.allowed_ips {
+ write("allowed_ip", ip.to_string() + "/" + &cidr.to_string())?;
}
-
- lines
}
+
+ Ok(())
}
diff --git a/src/configuration/uapi/mod.rs b/src/configuration/uapi/mod.rs
index cba156d..117d970 100644
--- a/src/configuration/uapi/mod.rs
+++ b/src/configuration/uapi/mod.rs
@@ -5,45 +5,73 @@ use std::io::{Read, Write};
use super::{ConfigError, Configuration};
-const MAX_LINE_LENGTH: usize = 128;
+use get::serialize;
+use set::LineParser;
-struct Parser<C: Configuration, R: Read, W: Write> {
- config: C,
- reader: R,
- writer: W,
-}
-
-impl<C: Configuration, R: Read, W: Write> Parser<C, R, W> {
- fn new(&self, reader: R, writer: W, config: C) -> Parser<C, R, W> {
- Parser {
- config,
- reader,
- writer,
- }
- }
+const MAX_LINE_LENGTH: usize = 256;
- fn parse(&mut self) -> Option<()> {
+pub fn process<R: Read, W: Write, C: Configuration>(reader: &mut R, writer: &mut W, config: &C) {
+ fn operation<R: Read, W: Write, C: Configuration>(
+ reader: &mut R,
+ writer: &mut W,
+ config: &C,
+ ) -> Result<(), ConfigError> {
// read string up to maximum length (why is this not in std?)
- let mut line = || {
+ fn readline<R: Read>(reader: &mut R) -> Result<String, ConfigError> {
let mut m: [u8; 1] = [0u8];
let mut l: String = String::with_capacity(MAX_LINE_LENGTH);
- while let Ok(_) = self.reader.read_exact(&mut m) {
+ while let Ok(_) = reader.read_exact(&mut m) {
let c = m[0] as char;
if c == '\n' {
- return Some(l);
+ return Ok(l);
};
l.push(c);
if l.len() > MAX_LINE_LENGTH {
- break;
+ return Err(ConfigError::LineTooLong);
}
}
- None
+ return Err(ConfigError::IOError);
+ }
+
+ // split into (key, value) pair
+ fn keypair<'a>(ln: &'a str) -> Result<(&'a str, &'a str), ConfigError> {
+ let mut split = ln.splitn(2, "=");
+ match (split.next(), split.next()) {
+ (Some(key), Some(value)) => Ok((key, value)),
+ _ => Err(ConfigError::LineTooLong),
+ }
};
- match line()?.as_str() {
- "get=1" => Some(()),
- "set=1" => Some(()),
- _ => None,
+ // read operation line
+ match readline(reader)?.as_str() {
+ "get=1" => serialize(writer, config).map_err(|_| ConfigError::IOError),
+ "set=1" => {
+ let mut parser = LineParser::new(config);
+ loop {
+ let ln = readline(reader)?;
+ if ln == "" {
+ break Ok(());
+ };
+ let (k, v) = keypair(ln.as_str())?;
+ parser.parse_line(k, v)?;
+ }
+ }
+ _ => Err(ConfigError::InvalidOperation),
}
}
+
+ // process operation
+ let res = operation(reader, writer, config);
+ log::debug!("{:?}", res);
+
+ // return errno
+ let _ = writer.write("errno=".as_ref());
+ let _ = writer.write(
+ match res {
+ Err(e) => e.errno().to_string(),
+ Ok(()) => "0".to_owned(),
+ }
+ .as_ref(),
+ );
+ let _ = writer.write("\n\n".as_ref());
}
diff --git a/src/configuration/uapi/set.rs b/src/configuration/uapi/set.rs
index c609d83..4c2c554 100644
--- a/src/configuration/uapi/set.rs
+++ b/src/configuration/uapi/set.rs
@@ -13,12 +13,19 @@ enum ParserState {
Interface,
}
-struct LineParser<C: Configuration> {
- config: C,
+pub struct LineParser<'a, C: Configuration> {
+ config: &'a C,
state: ParserState,
}
-impl<C: Configuration> LineParser<C> {
+impl<'a, C: Configuration> LineParser<'a, C> {
+ pub fn new(config: &'a C) -> LineParser<'a, C> {
+ LineParser {
+ config,
+ state: ParserState::Interface,
+ }
+ }
+
fn new_peer(value: &str) -> Result<ParserState, ConfigError> {
match <[u8; 32]>::from_hex(value) {
Ok(pk) => Ok(ParserState::Peer {
@@ -29,7 +36,7 @@ impl<C: Configuration> LineParser<C> {
}
}
- fn parse_line(&mut self, key: &str, value: &str) -> Option<ConfigError> {
+ 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 {
@@ -48,7 +55,7 @@ impl<C: Configuration> LineParser<C> {
};
// parse line and update parser state
- match self.state {
+ self.state = match self.state {
// configure the interface
ParserState::Interface => match key {
// opt: set private key
@@ -199,8 +206,8 @@ impl<C: Configuration> LineParser<C> {
// unknown key
_ => Err(ConfigError::InvalidKey),
},
- }
- .map(|st| self.state = st)
- .err()
+ }?;
+
+ Ok(())
}
}