Work on UAPI parser

This commit is contained in:
Mathias Hall-Andersen
2019-11-03 18:33:49 +01:00
parent 027d3d24d9
commit a0fa261a8a
6 changed files with 231 additions and 41 deletions

View File

@@ -1,5 +1,7 @@
use spin::Mutex;
use std::net::{IpAddr, SocketAddr};
use std::sync::atomic::Ordering;
use std::time::SystemTime;
use x25519_dalek::{PublicKey, StaticSecret};
use super::*;
@@ -11,12 +13,12 @@ use bind::Owner;
/// Describes a snapshot of the state of a peer
pub struct PeerState {
rx_bytes: u64,
tx_bytes: u64,
last_handshake_time_sec: u64,
last_handshake_time_nsec: u64,
public_key: PublicKey,
allowed_ips: Vec<(IpAddr, u32)>,
pub rx_bytes: u64,
pub tx_bytes: u64,
pub last_handshake_time_sec: u64,
pub last_handshake_time_nsec: u64,
pub public_key: PublicKey,
pub allowed_ips: Vec<(IpAddr, u32)>,
}
pub struct WireguardConfig<T: tun::Tun, B: bind::Platform> {
@@ -33,23 +35,6 @@ impl<T: tun::Tun, B: bind::Platform> WireguardConfig<T, B> {
}
}
pub enum ConfigError {
NoSuchPeer,
NotListening,
FailedToBind,
}
impl ConfigError {
fn errno(&self) -> i32 {
// TODO: obtain the correct error values
match self {
ConfigError::NoSuchPeer => 1,
ConfigError::NotListening => 2,
ConfigError::FailedToBind => 3,
}
}
}
/// Exposed configuration interface
pub trait Configuration {
/// Updates the private key of the device
@@ -244,7 +229,7 @@ impl<T: tun::Tun, B: bind::Platform> Configuration for WireguardConfig<T, B> {
}
fn add_peer(&self, peer: &PublicKey) -> bool {
self.wireguard.new_peer(*peer);
self.wireguard.add_peer(*peer);
false
}
@@ -301,6 +286,24 @@ impl<T: tun::Tun, B: bind::Platform> Configuration for WireguardConfig<T, B> {
}
fn get_peers(&self) -> Vec<PeerState> {
vec![]
let peers = self.wireguard.list_peers();
let mut state = Vec::with_capacity(peers.len());
for p in peers {
// convert the system time to (secs, nano) since epoch
let last_handshake = (*p.walltime_last_handshake.lock())
.duration_since(SystemTime::UNIX_EPOCH)
.expect("There should be no earlier time");
// extract state into PeerState
state.push(PeerState {
rx_bytes: p.rx_bytes.load(Ordering::Relaxed),
tx_bytes: p.tx_bytes.load(Ordering::Relaxed),
allowed_ips: p.router.list_allowed_ips(),
last_handshake_time_nsec: last_handshake.subsec_nanos() as u64,
last_handshake_time_sec: last_handshake.as_secs(),
public_key: p.pk,
})
}
state
}
}

View File

@@ -0,0 +1,28 @@
pub enum ConfigError {
NoSuchPeer,
NotListening,
FailedToBind,
InvalidHexValue,
InvalidPortNumber,
InvalidFwmark,
InvalidKey,
UnsupportedValue,
UnsupportedProtocolVersion,
}
impl ConfigError {
fn errno(&self) -> i32 {
// TODO: obtain the correct error values
match self {
ConfigError::NoSuchPeer => 1,
ConfigError::NotListening => 2,
ConfigError::FailedToBind => 3,
ConfigError::InvalidHexValue => 4,
ConfigError::InvalidPortNumber => 5,
ConfigError::InvalidFwmark => 6,
ConfigError::UnsupportedValue => 7,
ConfigError::InvalidKey => 8,
ConfigError::UnsupportedProtocolVersion => 9,
}
}
}

View File

@@ -1,8 +1,12 @@
mod config;
mod error;
mod uapi;
use super::platform::Endpoint;
use super::platform::{bind, tun};
use super::wireguard::Wireguard;
pub use error::ConfigError;
pub use config::Configuration;
pub use config::WireguardConfig;

161
src/configuration/uapi.rs Normal file
View File

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

View File

@@ -120,8 +120,8 @@ fn test_pure_wireguard() {
let pk2 = PublicKey::from(&sk2);
wg1.new_peer(pk2);
wg2.new_peer(pk1);
wg1.add_peer(pk2);
wg2.add_peer(pk1);
wg1.set_key(Some(sk1));
wg2.set_key(Some(sk2));

View File

@@ -148,16 +148,6 @@ impl<B: Bind> PeerInner<B> {
self.queue.lock().send(HandshakeJob::New(self.pk)).unwrap();
}
}
pub fn set_persistent_keepalive_interval(&self, interval: usize) {
self.timers().send_persistent_keepalive.stop();
self.keepalive.store(interval, Ordering::SeqCst);
if interval > 0 {
self.timers()
.send_persistent_keepalive
.start(Duration::from_secs(internal as u64));
}
}
}
struct Handshake {
@@ -260,7 +250,11 @@ impl<T: Tun, B: Bind> Wireguard<T, B> {
self.state.handshake.write().device.set_psk(pk, psk).is_ok()
}
pub fn new_peer(&self, pk: PublicKey) {
pub fn add_peer(&self, pk: PublicKey) {
if self.state.peers.read().contains_key(pk.as_bytes()) {
return;
}
let mut rng = OsRng::new().unwrap();
let state = Arc::new(PeerInner {
id: rng.gen(),
@@ -278,9 +272,6 @@ impl<T: Tun, B: Bind> Wireguard<T, B> {
// create a router peer
let router = Arc::new(self.state.router.new_peer(state.clone()));
// add to the handshake device
self.state.handshake.write().device.add(pk).unwrap(); // TODO: handle adding of public key for interface
// form WireGuard peer
let peer = Peer { router, state };
@@ -295,6 +286,9 @@ impl<T: Tun, B: Bind> Wireguard<T, B> {
// finally, add the peer to the wireguard device
let mut peers = self.state.peers.write();
peers.entry(*pk.as_bytes()).or_insert(peer);
// add to the handshake device
self.state.handshake.write().device.add(pk).unwrap(); // TODO: handle adding of public key for interface
}
/* Begin consuming messages from the reader.