Implemented UAPI "get" line-parser

This commit is contained in:
Mathias Hall-Andersen
2019-11-10 17:57:39 +01:00
parent dd85201c15
commit 2ff044dda9
5 changed files with 240 additions and 161 deletions

View File

@@ -6,6 +6,9 @@ pub enum ConfigError {
InvalidPortNumber, InvalidPortNumber,
InvalidFwmark, InvalidFwmark,
InvalidKey, InvalidKey,
InvalidSocketAddr,
InvalidKeepaliveInterval,
InvalidAllowedIp,
UnsupportedValue, UnsupportedValue,
UnsupportedProtocolVersion, UnsupportedProtocolVersion,
} }
@@ -20,6 +23,9 @@ impl ConfigError {
ConfigError::InvalidHexValue => 4, ConfigError::InvalidHexValue => 4,
ConfigError::InvalidPortNumber => 5, ConfigError::InvalidPortNumber => 5,
ConfigError::InvalidFwmark => 6, ConfigError::InvalidFwmark => 6,
ConfigError::InvalidSocketAddr => 10,
ConfigError::InvalidKeepaliveInterval => 11,
ConfigError::InvalidAllowedIp => 12,
ConfigError::UnsupportedValue => 7, ConfigError::UnsupportedValue => 7,
ConfigError::InvalidKey => 8, ConfigError::InvalidKey => 8,
ConfigError::UnsupportedProtocolVersion => 9, ConfigError::UnsupportedProtocolVersion => 9,

View File

@@ -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),
}
}
}

View File

@@ -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![]
}
}

View File

@@ -0,0 +1,4 @@
mod get;
mod set;
use super::{ConfigError, Configuration};

View File

@@ -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
}
}
}
}