Work on UAPI serialize device

This commit is contained in:
Mathias Hall-Andersen
2019-11-11 23:13:46 +01:00
parent 2ff044dda9
commit 5b555a2e17
6 changed files with 113 additions and 17 deletions

View File

@@ -19,6 +19,7 @@ pub struct PeerState {
pub last_handshake_time_nsec: u64,
pub public_key: PublicKey,
pub allowed_ips: Vec<(IpAddr, u32)>,
pub preshared_key: Option<[u8; 32]>,
}
pub struct WireguardConfig<T: tun::Tun, B: bind::Platform> {
@@ -157,15 +158,26 @@ pub trait Configuration {
/// The ip should be masked to remove any set bits right of the first "masklen" bits.
fn add_allowed_ip(&self, peer: &PublicKey, ip: IpAddr, masklen: u32) -> Option<ConfigError>;
fn get_listen_port(&self) -> Option<u16>;
/// Returns the state of all peers
///
/// # Returns
///
/// A list of structures describing the state of each peer
fn get_peers(&self) -> Vec<PeerState>;
fn get_fwmark(&self) -> Option<u32>;
}
impl<T: tun::Tun, B: bind::Platform> Configuration for WireguardConfig<T, B> {
fn get_fwmark(&self) -> Option<u32> {
self.network
.lock()
.as_ref()
.and_then(|bind| bind.get_fwmark())
}
fn set_private_key(&self, sk: Option<StaticSecret>) {
self.wireguard.set_key(sk)
}
@@ -178,6 +190,10 @@ impl<T: tun::Tun, B: bind::Platform> Configuration for WireguardConfig<T, B> {
1
}
fn get_listen_port(&self) -> Option<u16> {
self.network.lock().as_ref().map(|bind| bind.get_port())
}
fn set_listen_port(&self, port: Option<u16>) -> Option<ConfigError> {
let mut bind = self.network.lock();
@@ -285,6 +301,7 @@ impl<T: tun::Tun, B: bind::Platform> Configuration for WireguardConfig<T, B> {
fn get_peers(&self) -> Vec<PeerState> {
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())
@@ -293,6 +310,7 @@ impl<T: tun::Tun, B: bind::Platform> Configuration for WireguardConfig<T, B> {
// extract state into PeerState
state.push(PeerState {
preshared_key: self.wireguard.get_psk(&p.pk),
rx_bytes: p.rx_bytes.load(Ordering::Relaxed),
tx_bytes: p.tx_bytes.load(Ordering::Relaxed),
allowed_ips: p.router.list_allowed_ips(),

View File

@@ -10,6 +10,45 @@ struct Serializer<C: Configuration> {
impl<C: Configuration> Serializer<C> {
fn get(&self) -> Vec<String> {
vec![]
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())
}
}
lines
}
}

View File

@@ -1,4 +1,49 @@
mod get;
mod set;
use std::io::{Read, Write};
use super::{ConfigError, Configuration};
const MAX_LINE_LENGTH: usize = 128;
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,
}
}
fn parse(&mut self) -> Option<()> {
// read string up to maximum length (why is this not in std?)
let mut line = || {
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) {
let c = m[0] as char;
if c == '\n' {
return Some(l);
};
l.push(c);
if l.len() > MAX_LINE_LENGTH {
break;
}
}
None
};
match line()?.as_str() {
"get=1" => Some(()),
"set=1" => Some(()),
_ => None,
}
}
}

View File

@@ -7,8 +7,8 @@ use super::{ConfigError, Configuration};
#[derive(Copy, Clone)]
enum ParserState {
Peer {
public_key: PublicKey, // peer identity
update_only: bool, // is the update_only flag set
public_key: PublicKey,
update_only: bool,
},
Interface,
}
@@ -18,10 +18,6 @@ struct LineParser<C: Configuration> {
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) {
@@ -34,6 +30,7 @@ impl<C: Configuration> LineParser<C> {
}
fn parse_line(&mut self, key: &str, value: &str) -> Option<ConfigError> {
// add the peer if not update_only
let flush_peer = |st: ParserState| -> ParserState {
match st {
ParserState::Peer {
@@ -51,7 +48,7 @@ impl<C: Configuration> LineParser<C> {
};
// parse line and update parser state
let new_state = match self.state {
match self.state {
// configure the interface
ParserState::Interface => match key {
// opt: set private key
@@ -202,14 +199,8 @@ impl<C: Configuration> LineParser<C> {
// unknown key
_ => Err(ConfigError::InvalidKey),
},
};
match new_state {
Err(e) => Some(e),
Ok(st) => {
self.state = st;
None
}
}
}
.map(|st| self.state = st)
.err()
}
}

View File

@@ -202,7 +202,7 @@ impl Device {
/// A 32 byte array holding the PSK
///
/// The call might fail if the public key is not found
pub fn get_psk(&self, pk: PublicKey) -> Result<Psk, ConfigError> {
pub fn get_psk(&self, pk: &PublicKey) -> Result<Psk, ConfigError> {
match self.pk_map.get(pk.as_bytes()) {
Some(peer) => Ok(peer.psk),
_ => Err(ConfigError::new("No such public key")),

View File

@@ -204,6 +204,9 @@ impl<T: Tun, B: Bind> Wireguard<T, B> {
pub fn set_psk(&self, pk: PublicKey, psk: Option<[u8; 32]>) -> bool {
self.state.handshake.write().set_psk(pk, psk).is_ok()
}
pub fn get_psk(&self, pk: &PublicKey) -> Option<[u8; 32]> {
self.state.handshake.read().get_psk(pk).ok()
}
pub fn add_peer(&self, pk: PublicKey) {
if self.state.peers.read().contains_key(pk.as_bytes()) {