150 lines
5.9 KiB
Rust
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 {}
|
|
}
|
|
}
|