track events
This commit is contained in:
parent
f6c1c2771e
commit
c58c970cad
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
*/target
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*/target
|
@ -1,3 +1,11 @@
|
|||||||
|
FROM rust:1.31.1 AS eventbuild
|
||||||
|
|
||||||
|
COPY wg-event-gen/ /build
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
RUN cargo build --release
|
||||||
|
|
||||||
FROM golang AS build
|
FROM golang AS build
|
||||||
|
|
||||||
COPY wireguard-go /go/src/wireguard
|
COPY wireguard-go /go/src/wireguard
|
||||||
|
14
wg-event-gen/Cargo.lock
generated
Normal file
14
wg-event-gen/Cargo.lock
generated
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[[package]]
|
||||||
|
name = "strum"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wg-event-gen"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"strum 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
"checksum strum 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f6b3fc98c482ff9bb37a6db6a6491218c4c82bec368bd5682033e5b96b969143"
|
8
wg-event-gen/Cargo.toml
Normal file
8
wg-event-gen/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "wg-event-gen"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["shimun <wg.shimun@shimun.net>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
strum = "0.13.0"
|
214
wg-event-gen/src/main.rs
Normal file
214
wg-event-gen/src/main.rs
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::env;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::io::{BufRead, BufReader, Error, ErrorKind, Result};
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use std::os::unix::net::UnixStream;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::{thread, time};
|
||||||
|
|
||||||
|
pub type KV = (String, String);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
|
enum State {
|
||||||
|
Interface(Vec<KV>),
|
||||||
|
Peer(Vec<KV>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
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<&'a String> {
|
||||||
|
self.kv()
|
||||||
|
.iter()
|
||||||
|
.filter(|(key, _)| key == &"private_key" || key == &"public_key")
|
||||||
|
.map(|(_, value)| value)
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addr(&self) -> Option<SocketAddr> {
|
||||||
|
self.kv()
|
||||||
|
.iter()
|
||||||
|
.filter(|(key, _)| key == &"endpoint")
|
||||||
|
.map(|(_, value)| value.parse::<SocketAddr>().unwrap())
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn last_handshake(&self) -> Option<u64> {
|
||||||
|
self.kv()
|
||||||
|
.iter()
|
||||||
|
.filter(|(key, _)| key == &"last_handshake_time_nsec")
|
||||||
|
.map(|(_, value)| value.parse::<u64>().unwrap())
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, key: String, value: String) {
|
||||||
|
self.kv_mut().push((key, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delta(&self, other: Self) -> Vec<KV> {
|
||||||
|
let kv = self.kv();
|
||||||
|
other
|
||||||
|
.kv()
|
||||||
|
.iter()
|
||||||
|
.filter(|pair| !kv.contains(pair))
|
||||||
|
.map(|p| p.clone())
|
||||||
|
.collect::<Vec<KV>>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
))?,
|
||||||
|
"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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait EventListener {
|
||||||
|
fn added<'a>(&self, peer: &'a State) {
|
||||||
|
self.connected(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connected<'a>(&self, peer: &'a State);
|
||||||
|
|
||||||
|
fn disconnected<'a>(&self, peer: &'a State);
|
||||||
|
|
||||||
|
fn removed<'a>(&self, peer: &'a State) {
|
||||||
|
self.disconnected(peer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn roaming<'a>(&self, peer: &'a State, previous_addr: SocketAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LogListener;
|
||||||
|
|
||||||
|
impl EventListener for LogListener {
|
||||||
|
fn connected<'a>(&self, peer: &'a State) {
|
||||||
|
println!("{} connected!", peer.id().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disconnected<'a>(&self, peer: &'a State) {
|
||||||
|
println!("{} disconnected!", peer.id().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn roaming<'a>(&self, peer: &'a State, previous_addr: SocketAddr) {
|
||||||
|
println!(
|
||||||
|
"{} roamed {} -> {}!",
|
||||||
|
peer.id().unwrap(),
|
||||||
|
previous_addr,
|
||||||
|
peer.addr().unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut args = env::args();
|
||||||
|
args.next(); //Ignore program name
|
||||||
|
let path = args
|
||||||
|
.next()
|
||||||
|
.map(PathBuf::from)
|
||||||
|
.filter(|p| p.as_path().exists());
|
||||||
|
let interval = args
|
||||||
|
.next()
|
||||||
|
.map(|i| {
|
||||||
|
i.parse::<u64>()
|
||||||
|
.expect("[interval] has to be a positive int")
|
||||||
|
})
|
||||||
|
.unwrap_or(1000);
|
||||||
|
let listeners = vec![LogListener];
|
||||||
|
|
||||||
|
let timeout: u64 = 3 * 1000;
|
||||||
|
|
||||||
|
if let Some(path) = path {
|
||||||
|
let sock = Socket { path };
|
||||||
|
let mut prev_state: Option<HashMap<String, State>> = None;
|
||||||
|
loop {
|
||||||
|
let state = match sock.get_by_id() {
|
||||||
|
Ok(state) => state,
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Failed to read from socket: {}", err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(prev_state) = prev_state {
|
||||||
|
for (peer, state) in state.iter() {
|
||||||
|
if let Some(p_state) = prev_state.get(peer) {
|
||||||
|
if let (Some(addr), Some(p_addr)) = (state.addr(), p_state.addr()) {
|
||||||
|
if addr != p_addr {
|
||||||
|
listeners.iter().for_each(|l| l.roaming(state, p_addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
listeners.iter().for_each(|l| l.connected(state));
|
||||||
|
}
|
||||||
|
if let Some(shake) = state.last_handshake() {
|
||||||
|
if (shake / 1000) > timeout && shake / 1000 < timeout + interval {
|
||||||
|
listeners.iter().for_each(|l| l.disconnected(state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev_state
|
||||||
|
.iter()
|
||||||
|
.filter(|(k, _)| !state.contains_key(k.clone()))
|
||||||
|
.for_each(|(_, state)| listeners.iter().for_each(|l| l.disconnected(state)));
|
||||||
|
}
|
||||||
|
state.keys().for_each(|k| print!("{}, ", k)); println!("");
|
||||||
|
prev_state = Some(state);
|
||||||
|
thread::sleep(time::Duration::from_millis(interval));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("<path> does not exist");
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user