Initial version of full UAPI parser
This commit is contained in:
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +1,52 @@
|
||||
use hex::FromHex;
|
||||
use subtle::ConstantTimeEq;
|
||||
use x25519_dalek::{PublicKey, StaticSecret};
|
||||
|
||||
use super::{ConfigError, Configuration};
|
||||
use super::Configuration;
|
||||
use std::io;
|
||||
|
||||
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);
|
||||
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
|
||||
self.config
|
||||
config
|
||||
.get_private_key()
|
||||
.map(|sk| write("private_key", hex::encode(sk.to_bytes())));
|
||||
|
||||
self.config
|
||||
config
|
||||
.get_listen_port()
|
||||
.map(|port| write("listen_port", port.to_string()));
|
||||
|
||||
self.config
|
||||
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("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)));
|
||||
)?;
|
||||
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())
|
||||
write("allowed_ip", ip.to_string() + "/" + &cidr.to_string())?;
|
||||
}
|
||||
}
|
||||
|
||||
lines
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
const MAX_LINE_LENGTH: usize = 256;
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user