Files
wireguard-user/wg-event-gen/src/controller.rs
2019-04-03 16:57:49 +02:00

150 lines
5.9 KiB
Rust

use crate::model::{
ECCKey, HexBackend, Interface, Peer, PeerBuilder, SharedKey, WireguardController,
};
use std::io::{BufRead, BufReader, Error, ErrorKind, Result, Write};
use std::net::{IpAddr, SocketAddr};
use std::os::unix::net::UnixStream;
use std::path::PathBuf;
use std::time::{Duration, Instant};
pub struct Userspace(PathBuf);
impl Userspace {
pub fn new<P: Into<PathBuf>>(path: P) -> Userspace {
Userspace(path.into())
}
}
impl WireguardController for Userspace {
fn peers<'a>(&'a mut self) -> Result<Box<Iterator<Item = Result<Peer>> + 'a>> {
let mut stream = UnixStream::connect(&self.0)?;
stream.write_all(b"get=1\n")?;
fn build_peer(builder: &mut PeerBuilder, line: Result<String>) -> Result<Option<Peer>> {
let line = line?;
fn parse_err<O, E: Into<Box<dyn std::error::Error + Sync + Send>>>(
res: std::result::Result<O, E>,
) -> Result<O> {
res.map_err(|err| Error::new(ErrorKind::InvalidData, err))
}
let mut iter = line.chars();
let key = iter.by_ref().take_while(|c| c != &'=').collect::<String>();
let value = iter.collect::<String>();
let value_as_num = || parse_err(value.parse::<u64>());
let mut peer: Option<Peer> = None;
let build_peer = |peer: &mut Option<Peer>, builder: &mut PeerBuilder| -> Result<()> {
if builder.has_key() {
//Threat as uninitialized otherwise
let built: Result<Peer> = parse_err(builder.build());
*peer = Some(built?);
*builder = PeerBuilder::default();
}
Ok(())
};
let mut add_key = |peer: &mut Option<Peer>, key: ECCKey| -> Result<()> {
if builder.is_whole() {
build_peer(peer, builder)?;
} else {
*peer = None
}
builder.key(key);
Ok(())
};
match key.as_ref() {
"" => {
//Empty line means end of data
build_peer(&mut peer, builder).map_err(|err| {
Error::new(
ErrorKind::InvalidData,
format!(
"Protocol error, wireguard supplied insufficent data: {}",
err
),
)
})?; //TODO: handle possible actual error case
}
"public_key" => {
add_key(&mut peer, parse_err(ECCKey::from_hex(value))?)?;
}
"private_key" => {
add_key(&mut peer, ECCKey::from_hex(value)?)?;
}
"preshared_key" => {
builder.shared_key(Some(SharedKey::from_hex(value)?));
}
"endpoint" => {
builder.endpoint(Some(parse_err(value.parse::<SocketAddr>())?));
}
"last_handshake_time_sec" => {
builder.add_last_handshake(Duration::from_secs(value_as_num()?));
}
"last_handshake_time_nsec" => {
builder.add_last_handshake(Duration::from_nanos(value_as_num()?.into()));
}
"persistent_keepalive_interval" => {
builder.persistent_keepalive(Some(Duration::from_secs(value_as_num()?.into())));
}
"rx_bytes" => {
builder.add_traffic((parse_err(value.parse::<u64>())?, 0));
}
"tx_bytes" => {
builder.add_traffic((0, (parse_err(value.parse::<u64>())?)));
}
"allowed_ip" => {
let mut parts = value.split("/").into_iter();
let net = match (
parts.next().and_then(|addr| addr.parse::<IpAddr>().ok()),
parts.next().and_then(|mask| mask.parse::<u8>().ok()),
) {
(Some(addr), Some(mask)) => Some((addr, mask)),
(Some(addr), None) if addr.is_ipv6() => Some((addr, 128)),
(Some(addr), None) => Some((addr, 32)),
_ => None,
};
if let Some(net) = net {
builder.add_allowed_ip(net);
}
}
"errno" => match value_as_num()? {
0 => build_peer(&mut peer, builder)?,
code => Err(Error::new(
ErrorKind::Other,
format!("Returned error code: {}", code),
))?,
},
"listen_port" | "fwmark" | "private_key" => (), //Ignore for now
_ => Err(Error::new(
ErrorKind::InvalidData,
["Unknown key: \"", &key, "\""].join(""),
))?,
}
Ok(peer)
}
let peers = BufReader::new(stream)
.lines()
.scan(PeerBuilder::default(), |builder, line| {
match build_peer(builder, line) {
Ok(Some(value)) => Some(Some(Ok(value))),
Err(err) => {
eprintln!("{:?}", err);
None
} //TODO: propagate
_ => Some(None),
}
})
.flatten();
Ok(Box::new(peers))
}
fn interface(&mut self) -> Result<Interface> {
let mut stream = UnixStream::connect(&self.0)?;
stream.write_all(b"get=1\n")?;
unimplemented!("TODO: return iface")
}
fn update_peer(&mut self, peer: &Peer) -> Result<()> {
loop {}
}
}