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>(path: P) -> Userspace { Userspace(path.into()) } } impl WireguardController for Userspace { fn peers<'a>(&'a mut self) -> Result> + 'a>> { let mut stream = UnixStream::connect(&self.0)?; stream.write_all(b"get=1\n")?; fn build_peer(builder: &mut PeerBuilder, line: Result) -> Result> { let line = line?; fn parse_err>>( res: std::result::Result, ) -> Result { res.map_err(|err| Error::new(ErrorKind::InvalidData, err)) } let mut iter = line.chars(); let key = iter.by_ref().take_while(|c| c != &'=').collect::(); let value = iter.collect::(); let value_as_num = || parse_err(value.parse::()); let mut peer: Option = None; let build_peer = |peer: &mut Option, builder: &mut PeerBuilder| -> Result<()> { if builder.has_key() { //Threat as uninitialized otherwise let built: Result = parse_err(builder.build()); *peer = Some(built?); *builder = PeerBuilder::default(); } Ok(()) }; let mut add_key = |peer: &mut Option, 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::())?)); } "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::())?, 0)); } "tx_bytes" => { builder.add_traffic((0, (parse_err(value.parse::())?))); } "allowed_ip" => { let mut parts = value.split("/").into_iter(); let net = match ( parts.next().and_then(|addr| addr.parse::().ok()), parts.next().and_then(|mask| mask.parse::().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 { 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 {} } }