WIP [CI SKIP]

This commit is contained in:
shimunn 2019-03-19 08:10:45 +01:00 committed by Drone CI
parent 22dd07cc14
commit fc494fe4c0
5 changed files with 196 additions and 259 deletions

View File

@ -48,6 +48,65 @@ dependencies = [
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "darling"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"darling_core 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)",
"darling_macro 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "darling_core"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "darling_macro"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"darling_core 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "derive_builder"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"darling 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)",
"derive_builder_core 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "derive_builder_core"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"darling 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fnv"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "heck"
version = "0.3.1"
@ -61,6 +120,11 @@ name = "hex"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.47"
@ -68,7 +132,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "0.4.25"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -79,7 +143,7 @@ name = "quote"
version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -115,7 +179,7 @@ version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -125,7 +189,7 @@ name = "syn"
version = "0.15.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -183,6 +247,7 @@ name = "wg-event-gen"
version = "0.1.0"
dependencies = [
"base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"derive_builder 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt-derive 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
@ -215,10 +280,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
"checksum darling 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9158d690bc62a3a57c3e45b85e4d50de2008b39345592c64efd79345c7e24be0"
"checksum darling_core 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d2a368589465391e127e10c9e3a08efc8df66fd49b87dc8524c764bbe7f2ef82"
"checksum darling_macro 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "244e8987bd4e174385240cde20a3657f607fb0797563c28255c353b5819a07b1"
"checksum derive_builder 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a0ca533e6abb78f9108585535ce2ae0b14c8b4504e138a9a28eaf8ba2b270c1d"
"checksum derive_builder_core 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fb484fe06ba1dc5b82f88aff700191dfc127e02b06b35e302c169706168e2528"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
"checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
"checksum libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "48450664a984b25d5b479554c29cc04e3150c97aa4c01da5604a2d4ed9151476"
"checksum proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)" = "d3797b7142c9aa74954e351fc089bbee7958cebbff6bf2815e7ffff0b19f547d"
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
"checksum redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)" = "52ee9a534dc1301776eff45b4fa92d2c39b1d8c3d3357e6eb593e0d795506fc2"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"

View File

@ -10,6 +10,7 @@ base64 = "0.10.0"
time = "0.1.42"
structopt = "0.2.14"
structopt-derive = "0.2.14"
derive_builder = "0.7.1"
[profile.release]
lto = true

View File

@ -0,0 +1,68 @@
use crate::model::WireguardController;
use std::os::unix::net::UnixStream;
use std::path::PathBuf;
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) -> 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: String) -> Result<()> {
let line = line?;
let mut iter = line.chars();
let key = iter.by_ref().take_while(|c| c != &'=').collect::<String>();
let value = iter.collect::<String>();
let mut allowed_ips: Vec<(IpAddr, u8)> = Vec::new();
let mut last_handshake: Option<Duration> = None;
let update_handshake = |d: Duration| {
last_handshake = last_handshake.map(|c| c + d);
};
match key.as_ref() {
"public_key" => builder.key(ECCKey::from_base64(value)?),
"private_key" => builder.key(ECCKey::from_base64(value)?),
"endpoint" => builder.endpoint(value::parse::<SocketAddr>()?),
"last_handshake_time_sec" => {
update_handshake(Duration::from_secs(value::parse::<usize>().into()))
}
"last_handshake_time_nsec" => {
update_handshake(Duration::from_nsecs(value::parse::<usize>().into()))
}
"persistent_keepalive" => {
builder.keepalive(Duration::from_secs(value::parse::<usize>().into()))
}
"allowed_ip" => {
let mut parts = value.split("/").into_iter();
let ip = 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,
};
ips.push(ip);
}
}
builder.allowed_ips(ips);
builder.last_handshake(last_handshake);
}
let peers = BufReader::new(stream)
.lines()
.scan(PeerBuilder::default(), build_peer);
loop {}
}
fn update_peer(&mut self, peer: &Peer) -> Result<()> {
loop {}
}
}

View File

@ -1,258 +1,7 @@
#[macro_use]
extern crate structopt;
mod controller;
mod gen;
mod listener;
mod opts;
use listener::*;
use base64;
use hex;
use opts::Opts;
use std::collections::HashMap;
use std::env;
use std::fmt;
use std::io::prelude::*;
use std::io::{BufRead, BufReader, Error, ErrorKind, Result};
use std::net::{IpAddr, SocketAddr};
use std::os::unix::net::UnixStream;
use std::path::PathBuf;
use std::process::exit;
use std::thread;
use std::time::Duration;
use structopt::StructOpt;
use time;
pub type KV = (String, String);
#[derive(Debug, PartialEq, Eq, Hash)]
enum State {
Interface(Vec<KV>),
Peer(Vec<KV>),
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct Peer {
public_key: String,
endpoint: Option<SocketAddr>,
allowed_ips: Vec<(IpAddr, u8)>,
last_handshake: Option<Duration>,
persistent_keepalive: Option<Duration>,
traffic: (u64, u64),
parsed: time::Timespec,
}
impl Peer {
fn from_kv(entries: &Vec<KV>) -> Result<Peer> {
let key = match entries
.iter()
.filter(|(key, _)| key == &"public_key")
.map(|(_, value)| value)
.next()
{
Some(key) => key,
None => return Err(Error::new(ErrorKind::Other, "Peer is missing key")),
};
Ok(Peer {
public_key: base64::encode(&hex::decode(key).unwrap()),
endpoint: entries
.iter()
.filter(|(key, _)| key == &"endpoint")
.map(|(_, value)| value.parse::<SocketAddr>().unwrap())
.next(),
allowed_ips: entries
.iter()
.filter(|(key, _)| key == &"allowed_ip")
.map(|(_, value)| {
let mut parts = value.split("/").into_iter();
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,
}
})
.filter_map(|net| net)
.collect::<Vec<(IpAddr, u8)>>(),
last_handshake: entries
.iter()
.filter_map(|(key, value)| {
let value = || value.parse::<u64>().unwrap();
match key.as_ref() {
"last_handshake_time_sec" if value() != 0 => {
Some(Duration::new(value(), 0))
}
"last_handshake_time_nsec" if value() != 0 => {
Some(Duration::from_nanos(value()))
}
_ => None,
}
})
.fold(None, |acc, add| {
if let Some(dur) = acc {
Some(dur + add)
} else {
Some(add)
}
}),
persistent_keepalive: entries
.iter()
.filter(|(key, _)| key == &"persistent_keepalive")
.map(|(_, value)| Duration::from_secs(value.parse::<u64>().unwrap()))
.next(),
traffic: (0, 0),
parsed: time::get_time(),
})
}
pub fn last_handshake_rel(&self) -> Option<Duration> {
let time = self.parsed;
Some(Duration::new(time.sec as u64, time.nsec as u32) - self.last_handshake?)
}
}
impl State {
pub fn kv(&self) -> &Vec<KV> {
match self {
State::Interface(kv) => kv,
State::Peer(kv) => kv,
}
}
fn kv_mut(&mut self) -> &mut Vec<KV> {
match self {
State::Interface(kv) => kv,
State::Peer(kv) => kv,
}
}
pub fn id<'a>(&'a self) -> Option<String> {
self.kv()
.iter()
.filter(|(key, _)| key == &"private_key" || key == &"public_key")
.map(|(_, value)| base64::encode(&hex::decode(&value).unwrap()))
.next()
}
pub fn push(&mut self, key: String, value: String) {
self.kv_mut().push((key, value));
}
}
impl fmt::Display for State {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (k, v) in self.kv() {
write!(f, "({:10}= {})", k, v)?;
}
Ok(())
}
}
impl fmt::Display for Peer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
// write!(f, "peer {}\nshake {} ago\naddr {}\nkeepalive {}\n", self.public_key, self.last_handshake.map(|d|d.to_string()).unwrap_or("-"), self.endpoint.map(|d|d.to_string()).unwrap_or("-"), self.persistent_keepalive.map(|d|d.to_string()).unwrap_or("-"))
}
}
struct Socket {
pub path: PathBuf,
}
impl Socket {
pub fn get(&self) -> Result<Vec<State>> {
let mut stream = UnixStream::connect(&self.path)?;
stream.write_all(b"get=1\n")?;
let mut state: Vec<State> = vec![];
let mut cur = State::Interface(Vec::with_capacity(0));
for line in BufReader::new(stream).lines() {
let line = line?;
let mut iter = line.chars();
let key = iter.by_ref().take_while(|c| c != &'=').collect::<String>();
let value = iter.collect::<String>();
match key.as_ref() {
"errno" if value != "0" => {
Err(Error::new(
ErrorKind::Other,
format!("Socket said error: {}", value),
))?;
break;
}
"public_key" | "private_key" => {
state.push(cur);
cur = if key == "private_key" {
State::Interface(Vec::with_capacity(3))
} else {
State::Peer(Vec::with_capacity(5))
};
cur.push(key, value);
}
_ => cur.push(key, value),
}
}
Ok(state)
}
pub fn get_by_id(&self) -> Result<HashMap<String, State>> {
let state = self.get()?;
let mut ided = HashMap::new();
for s in state {
if let Some(id) = s.id() {
ided.insert(id.clone(), s);
}
}
Ok(ided)
}
pub fn get_peers(&self) -> Result<HashMap<String, Peer>> {
let by_id = self.get_by_id()?;
Ok(by_id
.iter()
.filter_map(|(id, state)| {
Peer::from_kv(state.kv())
.ok()
.map(|peer| (id.to_owned(), peer))
})
.collect())
}
}
use controller::Userspace;
fn main() {
let opts = Opts::from_args();
let timeout = Duration::from_secs(opts.timeout);
let interval = Duration::from_secs(opts.poll);
let events = opts.events;
let path = opts.socket;
let mut listeners: Vec<Box<EventListener>> = vec![Box::new(LogListener)];
if let Some(events) = events {
listeners.push(Box::new(ScriptListener::new(events)))
}
let sock = Socket { path };
let mut prev_state: Option<HashMap<String, Peer>> = None;
loop {
let state = match sock.get_peers() {
Ok(state) => state,
Err(err) => {
eprintln!("Failed to read from socket: {}", err);
if !opts.ignore_socket_errors {
exit(1);
}
continue;
}
};
if let Some(prev_state) = prev_state {
gen::gen_events(&state, &prev_state, &listeners, timeout, interval);
}
prev_state = Some(state);
thread::sleep(interval);
}
let controller = Userspace::new("");
}

47
wg-event-gen/src/model.rs Normal file
View File

@ -0,0 +1,47 @@
#[macro_use]
extern crate structopt;
#[macro_use]
extern crate derive_builder;
use std::io::Result;
use base64::{decode};
pub enum ECCKey{
PublicKey([u8; 32]),
PrivateKey([u8; 32])
}
impl ECCKey {
fn from_base64<I: AsRef<str>>(key: I) -> Result<ECCKey> {
let key = decode(key.as_ref::<str>())?;
let bytes = [0; 32];
bytes.copy_from_slice(key);
ECCKey::PublicKey(bytes)
}
}
struct SharedKey([u8; 32]);
#[derive(Debug,Builder, PartialEq, Eq, Hash, Clone)]
pub struct Peer {
key: ECCKey,
shared_key: Option<SharedKey>,
endpoint: Option<SocketAddr>,
allowed_ips: Vec<(IpAddr, u8)>,
last_handshake: Option<Duration>,
persistent_keepalive: Option<Duration>,
traffic: (u64, u64),
parsed: time::Timespec,
}
trait WireguardController {
fn peers<'a>(&'a mut self) -> Box<Iterator<Item=Result<Peer>> + 'a>;
fn update_peer(&mut self, peer: &Peer) -> Result<()>;
}