Compare commits
11 Commits
rewrite
...
threadppol
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cb138358ce | ||
![]() |
3cdee28f92 | ||
![]() |
2acbb6d574 | ||
![]() |
8e68c5c90c | ||
![]() |
e56376778d | ||
![]() |
e7999b0951 | ||
![]() |
a64fa75170 | ||
![]() |
d1daf3be00 | ||
![]() |
6a13b27c19 | ||
![]() |
88b68a1de9 | ||
![]() |
e3815e3198 |
6
Makefile
6
Makefile
@@ -2,6 +2,12 @@ REPO := repo.shimun.net/shimun/wireguard-user
|
|||||||
|
|
||||||
build:
|
build:
|
||||||
docker build . -t ${REPO}
|
docker build . -t ${REPO}
|
||||||
|
|
||||||
|
.ONESHELL:
|
||||||
|
update:
|
||||||
|
cd boringtun
|
||||||
|
git checkout master
|
||||||
|
git pull
|
||||||
|
|
||||||
push: build
|
push: build
|
||||||
docker push ${REPO}
|
docker push ${REPO}
|
||||||
|
Submodule boringtun updated: cabd969874...1f842a618a
21
wg-event-gen/Cargo.lock
generated
21
wg-event-gen/Cargo.lock
generated
@@ -1,3 +1,5 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ansi_term"
|
name = "ansi_term"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
@@ -130,6 +132,14 @@ name = "libc"
|
|||||||
version = "0.2.47"
|
version = "0.2.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_cpus"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "0.4.27"
|
version = "0.4.27"
|
||||||
@@ -212,6 +222,14 @@ dependencies = [
|
|||||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "threadpool"
|
||||||
|
version = "1.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.1.42"
|
version = "0.1.42"
|
||||||
@@ -251,6 +269,7 @@ dependencies = [
|
|||||||
"hex 0.3.2 (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 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)",
|
"structopt-derive 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -290,6 +309,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
|
"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 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 libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "48450664a984b25d5b479554c29cc04e3150c97aa4c01da5604a2d4ed9151476"
|
||||||
|
"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
|
||||||
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
|
"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 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_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)" = "52ee9a534dc1301776eff45b4fa92d2c39b1d8c3d3357e6eb593e0d795506fc2"
|
||||||
@@ -300,6 +320,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
|
"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
|
||||||
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
||||||
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
||||||
|
"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
|
||||||
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||||
"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1"
|
"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1"
|
||||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||||
|
@@ -11,6 +11,7 @@ time = "0.1.42"
|
|||||||
structopt = "0.2.14"
|
structopt = "0.2.14"
|
||||||
structopt-derive = "0.2.14"
|
structopt-derive = "0.2.14"
|
||||||
derive_builder = "0.7.1"
|
derive_builder = "0.7.1"
|
||||||
|
threadpool = "1.7.1"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
use crate::model::{
|
use crate::model::{
|
||||||
Base64Backed, ECCKey, Interface, Peer, PeerBuilder, SharedKey, WireguardController,
|
ECCKey, HexBackend, Interface, Peer, PeerBuilder, SharedKey, WireguardController,
|
||||||
};
|
};
|
||||||
use std::io::{BufRead, BufReader, Error, ErrorKind, Result, Write};
|
use std::io::{BufRead, BufReader, Error, ErrorKind, Result, Write};
|
||||||
use std::net::{IpAddr, SocketAddr};
|
use std::net::{IpAddr, SocketAddr};
|
||||||
@@ -33,9 +33,12 @@ impl WireguardController for Userspace {
|
|||||||
let value_as_num = || parse_err(value.parse::<u64>());
|
let value_as_num = || parse_err(value.parse::<u64>());
|
||||||
let mut peer: Option<Peer> = None;
|
let mut peer: Option<Peer> = None;
|
||||||
let build_peer = |peer: &mut Option<Peer>, builder: &mut PeerBuilder| -> Result<()> {
|
let build_peer = |peer: &mut Option<Peer>, builder: &mut PeerBuilder| -> Result<()> {
|
||||||
let built: Result<Peer> = parse_err(builder.build());
|
if builder.has_key() {
|
||||||
*peer = Some(built?);
|
//Threat as uninitialized otherwise
|
||||||
*builder = PeerBuilder::default();
|
let built: Result<Peer> = parse_err(builder.build());
|
||||||
|
*peer = Some(built?);
|
||||||
|
*builder = PeerBuilder::default();
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
};
|
};
|
||||||
let mut add_key = |peer: &mut Option<Peer>, key: ECCKey| -> Result<()> {
|
let mut add_key = |peer: &mut Option<Peer>, key: ECCKey| -> Result<()> {
|
||||||
@@ -50,16 +53,24 @@ impl WireguardController for Userspace {
|
|||||||
match key.as_ref() {
|
match key.as_ref() {
|
||||||
"" => {
|
"" => {
|
||||||
//Empty line means end of data
|
//Empty line means end of data
|
||||||
build_peer(&mut peer, builder); //TODO: handle possible actual error case
|
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" => {
|
"public_key" => {
|
||||||
add_key(&mut peer, parse_err(ECCKey::from_base64(value))?)?;
|
add_key(&mut peer, parse_err(ECCKey::from_hex(value))?)?;
|
||||||
}
|
}
|
||||||
"private_key" => {
|
"private_key" => {
|
||||||
add_key(&mut peer, ECCKey::from_base64(value)?)?;
|
add_key(&mut peer, ECCKey::from_hex(value)?)?;
|
||||||
}
|
}
|
||||||
"preshared_key" => {
|
"preshared_key" => {
|
||||||
builder.shared_key(Some(SharedKey::from_base64(value)?));
|
builder.shared_key(Some(SharedKey::from_hex(value)?));
|
||||||
}
|
}
|
||||||
"endpoint" => {
|
"endpoint" => {
|
||||||
builder.endpoint(Some(parse_err(value.parse::<SocketAddr>())?));
|
builder.endpoint(Some(parse_err(value.parse::<SocketAddr>())?));
|
||||||
|
@@ -19,31 +19,39 @@ pub(crate) fn gen_events(
|
|||||||
.map(|p| (*p, (prev.get(*p), state.get(*p))))
|
.map(|p| (*p, (prev.get(*p), state.get(*p))))
|
||||||
.collect::<HashMap<&ECCKey, (Option<&Peer>, Option<&Peer>)>>()
|
.collect::<HashMap<&ECCKey, (Option<&Peer>, Option<&Peer>)>>()
|
||||||
};
|
};
|
||||||
|
let d_zero = Duration::from_secs(0);
|
||||||
|
let h_ms = Duration::from_millis(100);
|
||||||
for (_id, (prev, cur)) in side_by_side {
|
for (_id, (prev, cur)) in side_by_side {
|
||||||
match (prev, cur) {
|
match (prev, cur) {
|
||||||
(Some(prev), Some(cur)) => {
|
(Some(prev), Some(cur)) => {
|
||||||
let timedout = |peer: &Peer| {
|
|
||||||
peer.last_handshake
|
|
||||||
.map(|shake| {
|
|
||||||
shake.elapsed().unwrap() > timeout
|
|
||||||
|| shake.elapsed().unwrap() + poll_interval < timeout
|
|
||||||
})
|
|
||||||
.unwrap_or(true)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let (Some(prev_addr), Some(cur_addr)) = (prev.endpoint, cur.endpoint) {
|
if let (Some(prev_addr), Some(cur_addr)) = (prev.endpoint, cur.endpoint) {
|
||||||
if prev_addr != cur_addr {
|
if prev_addr != cur_addr {
|
||||||
listeners.roaming(&cur, prev_addr);
|
listeners.roaming(&cur, prev_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !timedout(&prev) && timedout(&cur) {
|
let timedout_now = || {
|
||||||
listeners.disconnected(&cur);
|
if let Some(shake) = cur.last_handshake {
|
||||||
continue;
|
if let Ok(el) = shake.elapsed() {
|
||||||
}
|
return el > timeout && el + poll_interval < timeout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
if timedout(&prev) && !timedout(&cur) {
|
let timedout_prev = || {
|
||||||
listeners.connected(&cur);
|
if let Some(shake) = prev.last_handshake {
|
||||||
|
if let Ok(el) = shake.elapsed().map(|el| el - poll_interval) {
|
||||||
|
return el > timeout && el < timeout + poll_interval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
match (timedout_prev(), timedout_now()) {
|
||||||
|
(false, true) => listeners.disconnected(&cur),
|
||||||
|
(true, false) => listeners.connected(&cur),
|
||||||
|
other => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(None, Some(cur)) => listeners.added(&cur),
|
(None, Some(cur)) => listeners.added(&cur),
|
||||||
@@ -56,6 +64,7 @@ pub(crate) fn gen_events(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -88,31 +97,31 @@ mod test {
|
|||||||
fn added<'a>(&self, peer: &'a Peer) {
|
fn added<'a>(&self, peer: &'a Peer) {
|
||||||
self.calls
|
self.calls
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.push(format!("add {}", peer.public_key));
|
.push(format!("add {}", peer.key));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connected<'a>(&self, peer: &'a Peer) {
|
fn connected<'a>(&self, peer: &'a Peer) {
|
||||||
self.calls
|
self.calls
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.push(format!("con {}", peer.public_key));
|
.push(format!("con {}", peer.key));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disconnected<'a>(&self, peer: &'a Peer) {
|
fn disconnected<'a>(&self, peer: &'a Peer) {
|
||||||
self.calls
|
self.calls
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.push(format!("dis {}", peer.public_key));
|
.push(format!("dis {}", peer.key));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn removed<'a>(&self, peer: &'a Peer) {
|
fn removed<'a>(&self, peer: &'a Peer) {
|
||||||
self.calls
|
self.calls
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.push(format!("rem {}", peer.public_key));
|
.push(format!("rem {}", peer.key));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn roaming<'a>(&self, peer: &'a Peer, _previous_addr: SocketAddr) {
|
fn roaming<'a>(&self, peer: &'a Peer, _previous_addr: SocketAddr) {
|
||||||
self.calls
|
self.calls
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.push(format!("rom {}", peer.public_key));
|
.push(format!("rom {}", peer.key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +137,7 @@ mod test {
|
|||||||
let peer = peer();
|
let peer = peer();
|
||||||
listeners.connected(&peer);
|
listeners.connected(&peer);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vec![["con", &peer.public_key].join(" ")],
|
vec![["con", &peer.key].join(" ")],
|
||||||
calls.borrow().clone()
|
calls.borrow().clone()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -141,121 +150,121 @@ mod test {
|
|||||||
let bkey = "HhRgEL2xsnEIqThSTUKLGaTXusorM1MFdjSSYvzBynY=";
|
let bkey = "HhRgEL2xsnEIqThSTUKLGaTXusorM1MFdjSSYvzBynY=";
|
||||||
let key = b2h(bkey);
|
let key = b2h(bkey);
|
||||||
Peer::from_kv(&vec![
|
Peer::from_kv(&vec![
|
||||||
("public_key".to_string(), key.clone()),
|
("key".to_string(), key.clone()),
|
||||||
/*(
|
/*(
|
||||||
"last_handshake_time_nsec".to_string(),
|
"last_handshake_time_nsec".to_string(),
|
||||||
(1000 * 1000 * 1).to_string(),
|
(1000 * 1000 * 1).to_string(),
|
||||||
),*/
|
),*/
|
||||||
("endpoint".to_string(), "1.1.1.1:22222".to_string()),
|
("endpoint".to_string(), "1.1.1.1:22222".to_string()),
|
||||||
])
|
])
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn connected() {
|
|
||||||
let peer = peer();
|
|
||||||
let mut peer_cur = peer.clone();
|
|
||||||
let mut prev: HashMap<String, Peer> = HashMap::new();
|
|
||||||
let mut cur: HashMap<String, Peer> = HashMap::new();
|
|
||||||
cur.insert(peer_cur.public_key.clone(), peer_cur.clone());
|
|
||||||
let (listener, calls) = listeners();
|
|
||||||
let interval = time::Duration::from_secs(3);
|
|
||||||
gen_events(
|
|
||||||
&cur,
|
|
||||||
&prev,
|
|
||||||
&listener,
|
|
||||||
time::Duration::from_secs(3),
|
|
||||||
interval,
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
vec![["add", &peer_cur.public_key].join(" ")],
|
|
||||||
calls.borrow().clone()
|
|
||||||
);
|
|
||||||
|
|
||||||
gen_events(
|
|
||||||
&cur,
|
|
||||||
&cur,
|
|
||||||
&listener,
|
|
||||||
time::Duration::from_secs(3),
|
|
||||||
interval,
|
|
||||||
);
|
|
||||||
|
|
||||||
//Shouldn't gen any new events
|
|
||||||
assert!(calls.borrow().len() == 1);
|
|
||||||
|
|
||||||
let (listener, calls) = listeners();
|
|
||||||
gen_events(
|
|
||||||
&prev,
|
|
||||||
&cur,
|
|
||||||
&listener,
|
|
||||||
time::Duration::from_secs(10),
|
|
||||||
interval,
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
vec![["rem", &peer.public_key].join(" ")],
|
|
||||||
calls.borrow().clone()
|
|
||||||
);
|
|
||||||
|
|
||||||
calls.borrow_mut().clear();
|
|
||||||
|
|
||||||
let mut peer_prev = peer.clone();
|
|
||||||
|
|
||||||
peer_prev.endpoint = Some("2.2.2.2:33333".parse::<SocketAddr>().unwrap());
|
|
||||||
|
|
||||||
peer_prev.last_handshake = Some(time::Duration::from_secs(1000));
|
|
||||||
|
|
||||||
prev.insert(peer_prev.public_key.clone(), peer_prev.clone());
|
|
||||||
|
|
||||||
gen_events(
|
|
||||||
&prev,
|
|
||||||
&cur,
|
|
||||||
&listener,
|
|
||||||
time::Duration::from_secs(10),
|
|
||||||
interval,
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(calls
|
|
||||||
.borrow()
|
|
||||||
.clone()
|
|
||||||
.contains(&["rom", &peer.public_key].join(" ")));
|
|
||||||
|
|
||||||
calls.borrow_mut().clear();
|
|
||||||
|
|
||||||
let peer_prev = peer.clone();
|
|
||||||
|
|
||||||
peer_cur.last_handshake = Some(time::Duration::from_secs(5));
|
|
||||||
|
|
||||||
cur.insert(peer_cur.public_key.clone(), peer_cur.clone());
|
|
||||||
prev.insert(peer_prev.public_key.clone(), peer_prev.clone());
|
|
||||||
|
|
||||||
gen_events(
|
|
||||||
&cur,
|
|
||||||
&prev,
|
|
||||||
&listener,
|
|
||||||
time::Duration::from_secs(10),
|
|
||||||
interval,
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
vec![["con", &peer.public_key].join(" ")],
|
|
||||||
calls.borrow().clone()
|
|
||||||
);
|
|
||||||
|
|
||||||
calls.borrow_mut().clear();
|
|
||||||
|
|
||||||
//Other way around should be a disconnect
|
|
||||||
gen_events(
|
|
||||||
&prev,
|
|
||||||
&cur,
|
|
||||||
&listener,
|
|
||||||
time::Duration::from_secs(3),
|
|
||||||
interval,
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
vec![["dis", &peer.public_key].join(" ")],
|
|
||||||
calls.borrow().clone()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn connected() {
|
||||||
|
let peer = peer();
|
||||||
|
let mut peer_cur = peer.clone();
|
||||||
|
let mut prev: HashMap<String, Peer> = HashMap::new();
|
||||||
|
let mut cur: HashMap<String, Peer> = HashMap::new();
|
||||||
|
cur.insert(peer_cur.key.clone(), peer_cur.clone());
|
||||||
|
let (listener, calls) = listeners();
|
||||||
|
let interval = time::Duration::from_secs(3);
|
||||||
|
gen_events(
|
||||||
|
&cur,
|
||||||
|
&prev,
|
||||||
|
&listener,
|
||||||
|
time::Duration::from_secs(3),
|
||||||
|
interval,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec![["add", &peer_cur.key].join(" ")],
|
||||||
|
calls.borrow().clone()
|
||||||
|
);
|
||||||
|
|
||||||
|
gen_events(
|
||||||
|
&cur,
|
||||||
|
&cur,
|
||||||
|
&listener,
|
||||||
|
time::Duration::from_secs(3),
|
||||||
|
interval,
|
||||||
|
);
|
||||||
|
|
||||||
|
//Shouldn't gen any new events
|
||||||
|
assert!(calls.borrow().len() == 1);
|
||||||
|
|
||||||
|
let (listener, calls) = listeners();
|
||||||
|
gen_events(
|
||||||
|
&prev,
|
||||||
|
&cur,
|
||||||
|
&listener,
|
||||||
|
time::Duration::from_secs(10),
|
||||||
|
interval,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec![["rem", &peer.key].join(" ")],
|
||||||
|
calls.borrow().clone()
|
||||||
|
);
|
||||||
|
|
||||||
|
calls.borrow_mut().clear();
|
||||||
|
|
||||||
|
let mut peer_prev = peer.clone();
|
||||||
|
|
||||||
|
peer_prev.endpoint = Some("2.2.2.2:33333".parse::<SocketAddr>().unwrap());
|
||||||
|
|
||||||
|
peer_prev.last_handshake = Some(time::Duration::from_secs(1000));
|
||||||
|
|
||||||
|
prev.insert(peer_prev.key.clone(), peer_prev.clone());
|
||||||
|
|
||||||
|
gen_events(
|
||||||
|
&prev,
|
||||||
|
&cur,
|
||||||
|
&listener,
|
||||||
|
time::Duration::from_secs(10),
|
||||||
|
interval,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(calls
|
||||||
|
.borrow()
|
||||||
|
.clone()
|
||||||
|
.contains(&["rom", &peer.key].join(" ")));
|
||||||
|
|
||||||
|
calls.borrow_mut().clear();
|
||||||
|
|
||||||
|
let peer_prev = peer.clone();
|
||||||
|
|
||||||
|
peer_cur.last_handshake = Some(time::Duration::from_secs(5));
|
||||||
|
|
||||||
|
cur.insert(peer_cur.key.clone(), peer_cur.clone());
|
||||||
|
prev.insert(peer_prev.key.clone(), peer_prev.clone());
|
||||||
|
|
||||||
|
gen_events(
|
||||||
|
&cur,
|
||||||
|
&prev,
|
||||||
|
&listener,
|
||||||
|
time::Duration::from_secs(10),
|
||||||
|
interval,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
vec![["con", &peer.key].join(" ")],
|
||||||
|
calls.borrow().clone()
|
||||||
|
);
|
||||||
|
|
||||||
|
calls.borrow_mut().clear();
|
||||||
|
|
||||||
|
//Other way around should be a disconnect
|
||||||
|
gen_events(
|
||||||
|
&prev,
|
||||||
|
&cur,
|
||||||
|
&listener,
|
||||||
|
time::Duration::from_secs(3),
|
||||||
|
interval,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
vec![["dis", &peer.key].join(" ")],
|
||||||
|
calls.borrow().clone()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}*/
|
||||||
|
@@ -4,8 +4,11 @@ use std::path::PathBuf;
|
|||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
use threadpool::ThreadPool;
|
||||||
|
|
||||||
pub trait EventListener {
|
pub trait EventListener {
|
||||||
|
fn name(&self) -> &'static str;
|
||||||
|
|
||||||
fn added<'a>(&self, peer: &'a Peer) {
|
fn added<'a>(&self, peer: &'a Peer) {
|
||||||
self.connected(peer);
|
self.connected(peer);
|
||||||
}
|
}
|
||||||
@@ -22,6 +25,10 @@ pub trait EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EventListener for Vec<Box<EventListener>> {
|
impl EventListener for Vec<Box<EventListener>> {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"List of Listeners"
|
||||||
|
}
|
||||||
|
|
||||||
fn added<'a>(&self, peer: &'a Peer) {
|
fn added<'a>(&self, peer: &'a Peer) {
|
||||||
if cfg!(feature = "addrem") || cfg!(test) {
|
if cfg!(feature = "addrem") || cfg!(test) {
|
||||||
self.iter().for_each(|l| l.added(&peer));
|
self.iter().for_each(|l| l.added(&peer));
|
||||||
@@ -50,6 +57,9 @@ impl EventListener for Vec<Box<EventListener>> {
|
|||||||
pub struct LogListener;
|
pub struct LogListener;
|
||||||
|
|
||||||
impl EventListener for LogListener {
|
impl EventListener for LogListener {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"Log"
|
||||||
|
}
|
||||||
fn connected<'a>(&self, peer: &'a Peer) {
|
fn connected<'a>(&self, peer: &'a Peer) {
|
||||||
println!("{} connected!", peer.key);
|
println!("{} connected!", peer.key);
|
||||||
}
|
}
|
||||||
@@ -78,11 +88,13 @@ impl EventListener for LogListener {
|
|||||||
|
|
||||||
pub struct ScriptListener {
|
pub struct ScriptListener {
|
||||||
pub script: PathBuf,
|
pub script: PathBuf,
|
||||||
|
pub pool: ThreadPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptListener {
|
impl ScriptListener {
|
||||||
pub fn new(script: PathBuf) -> ScriptListener {
|
pub fn new(script: PathBuf) -> ScriptListener {
|
||||||
ScriptListener { script }
|
let pool = ThreadPool::new(4);
|
||||||
|
ScriptListener { script, pool }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peer_props<'a>(&self, peer: &'a Peer) -> String {
|
fn peer_props<'a>(&self, peer: &'a Peer) -> String {
|
||||||
@@ -127,13 +139,16 @@ impl ScriptListener {
|
|||||||
|
|
||||||
fn call_sub<'a>(&self, args: Vec<&'a str>) {
|
fn call_sub<'a>(&self, args: Vec<&'a str>) {
|
||||||
let mut cmd = self.mkcmd(args);
|
let mut cmd = self.mkcmd(args);
|
||||||
thread::spawn(move || {
|
self.pool.execute(move || {
|
||||||
cmd.spawn().expect("Failed to call Script hooḱ!");
|
cmd.spawn().expect("Failed to call Script hooḱ!");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventListener for ScriptListener {
|
impl EventListener for ScriptListener {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"Script"
|
||||||
|
}
|
||||||
fn connected<'a>(&self, peer: &'a Peer) {
|
fn connected<'a>(&self, peer: &'a Peer) {
|
||||||
self.call_sub(vec!["connected", &self.peer_props(peer)]);
|
self.call_sub(vec!["connected", &self.peer_props(peer)]);
|
||||||
}
|
}
|
||||||
|
@@ -17,9 +17,10 @@ use controller::Userspace;
|
|||||||
use model::WireguardController;
|
use model::WireguardController;
|
||||||
use opts::Opts;
|
use opts::Opts;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::error::Error;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
fn listeners(opts: &Opts) -> Vec<Box<EventListener>> {
|
fn listeners(opts: &Opts) -> Vec<Box<EventListener>> {
|
||||||
@@ -30,6 +31,7 @@ fn listeners(opts: &Opts) -> Vec<Box<EventListener>> {
|
|||||||
if opts.log {
|
if opts.log {
|
||||||
listeners.push(Box::new(LogListener));
|
listeners.push(Box::new(LogListener));
|
||||||
}
|
}
|
||||||
|
println!("Enabled handlers: {}", (&listeners.iter().map(|l| l.name()).collect::<Vec<_>>()).join(", "));
|
||||||
listeners
|
listeners
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,31 +50,30 @@ fn main() -> io::Result<()> {
|
|||||||
let mut peers_last: Option<HashMap<ECCKey, Peer>> = None;
|
let mut peers_last: Option<HashMap<ECCKey, Peer>> = None;
|
||||||
loop {
|
loop {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let peers = controller.peers()?;
|
let peers = match controller.peers() {
|
||||||
/*println!("Connected peers:");
|
Err(ref err) if opts.ignore_socket_errors => {
|
||||||
for peer in peers {
|
eprintln!(
|
||||||
let peer = peer?;
|
"Encountered error while querying Wireguard: {}",
|
||||||
if peer
|
err.description()
|
||||||
.last_handshake
|
);
|
||||||
.map(|h| h.elapsed().unwrap() < timeout)
|
sleep(interval);
|
||||||
.unwrap_or(false)
|
continue;
|
||||||
{
|
|
||||||
println!("/\\{:?} {}",(timeout - peer.last_handshake.unwrap().elapsed().unwrap()), peer);
|
|
||||||
}
|
}
|
||||||
}*/
|
res => res?,
|
||||||
|
};
|
||||||
let peers = peers
|
let peers = peers
|
||||||
.map(|peer| peer.map(|peer_ok| (peer_ok.key.clone(), peer_ok)))
|
.map(|peer| peer.map(|peer_ok| (peer_ok.key.clone(), peer_ok)))
|
||||||
.collect::<io::Result<HashMap<_, _>>>()?;
|
.collect::<io::Result<HashMap<_, _>>>()?;
|
||||||
|
|
||||||
if let Some(ref mut peers_last) = peers_last {
|
if let Some(ref mut peers_last) = peers_last {
|
||||||
|
gen_events(&peers, &peers_last, &listeners, timeout, interval);
|
||||||
gen_events(&peers, &peers_last, &listeners, timeout, interval);
|
|
||||||
|
|
||||||
*peers_last = peers;
|
*peers_last = peers;
|
||||||
} else {
|
} else {
|
||||||
peers_last = Some(peers);
|
peers_last = Some(peers);
|
||||||
}
|
}
|
||||||
let pause = interval - now.elapsed();
|
let pause = interval - now.elapsed();
|
||||||
dbg!(interval - pause);
|
|
||||||
sleep(if pause > interval / 2 {
|
sleep(if pause > interval / 2 {
|
||||||
pause
|
pause
|
||||||
} else {
|
} else {
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
use base64::{decode, encode};
|
use base64::{decode, encode};
|
||||||
|
use hex;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
@@ -21,6 +22,31 @@ impl fmt::Display for ECCKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait HexBackend {
|
||||||
|
fn from_bytes(bytes: Vec<u8>) -> Self;
|
||||||
|
fn bytes(&self) -> &Vec<u8>;
|
||||||
|
fn from_hex<I: AsRef<str>>(key: I) -> io::Result<Self>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Ok(Self::from_bytes(hex::decode(key.as_ref()).map_err(
|
||||||
|
|_| io::Error::new(io::ErrorKind::InvalidData, "Failed to decode hexstring"),
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
fn as_hex(&self) -> io::Result<String> {
|
||||||
|
Ok(hex::encode(&self.bytes()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Base64Backed> HexBackend for T {
|
||||||
|
fn from_bytes(bytes: Vec<u8>) -> Self {
|
||||||
|
<Self as Base64Backed>::from_bytes(bytes)
|
||||||
|
}
|
||||||
|
fn bytes(&self) -> &Vec<u8> {
|
||||||
|
<Self as Base64Backed>::bytes(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Base64Backed {
|
pub trait Base64Backed {
|
||||||
fn from_bytes(bytes: Vec<u8>) -> Self;
|
fn from_bytes(bytes: Vec<u8>) -> Self;
|
||||||
fn bytes(&self) -> &Vec<u8>;
|
fn bytes(&self) -> &Vec<u8>;
|
||||||
@@ -34,7 +60,7 @@ pub trait Base64Backed {
|
|||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
io::ErrorKind::InvalidData,
|
io::ErrorKind::InvalidData,
|
||||||
"Failed to decode base64",
|
"Failed to decode base64",
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
}; /*.map_err(|err| {
|
}; /*.map_err(|err| {
|
||||||
|
|
||||||
@@ -168,6 +194,10 @@ impl PeerBuilder {
|
|||||||
self.validate().is_ok()
|
self.validate().is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn has_key(&self) -> bool {
|
||||||
|
self.key.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_allowed_ip(&mut self, ip: (IpAddr, u8)) {
|
pub fn add_allowed_ip(&mut self, ip: (IpAddr, u8)) {
|
||||||
if let Some(ref mut ips) = &mut self.allowed_ips {
|
if let Some(ref mut ips) = &mut self.allowed_ips {
|
||||||
ips.push(ip);
|
ips.push(ip);
|
||||||
@@ -203,3 +233,15 @@ pub trait WireguardController {
|
|||||||
|
|
||||||
fn update_peer(&mut self, peer: &Peer) -> io::Result<()>;
|
fn update_peer(&mut self, peer: &Peer) -> io::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn key_encoding() {
|
||||||
|
let key_encoded = "08df3bebd54217eb769d607f8673e1c3c53bb55d6ac689348a9227c8c4dd8857";
|
||||||
|
let key = ECCKey::from_hex(key_encoded).unwrap();
|
||||||
|
assert_eq!(&key.as_hex().unwrap(), key_encoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -4,14 +4,16 @@ use structopt::StructOpt;
|
|||||||
#[derive(StructOpt, Debug)]
|
#[derive(StructOpt, Debug)]
|
||||||
#[structopt(name = "event-gen")]
|
#[structopt(name = "event-gen")]
|
||||||
pub struct Opts {
|
pub struct Opts {
|
||||||
|
///Time after which a client is considered as offline
|
||||||
#[structopt(
|
#[structopt(
|
||||||
short = "t",
|
short = "t",
|
||||||
long = "timeout",
|
long = "timeout",
|
||||||
default_value = "120",
|
default_value = "115",
|
||||||
env = "WG_EVENT_TIMEOUT"
|
env = "WG_EVENT_TIMEOUT"
|
||||||
)]
|
)]
|
||||||
pub timeout: u64,
|
pub timeout: u64,
|
||||||
|
|
||||||
|
///Interval after which Wireguard will be polled for updates
|
||||||
#[structopt(
|
#[structopt(
|
||||||
short = "p",
|
short = "p",
|
||||||
long = "poll-interval",
|
long = "poll-interval",
|
||||||
@@ -20,6 +22,7 @@ pub struct Opts {
|
|||||||
)]
|
)]
|
||||||
pub poll: u64,
|
pub poll: u64,
|
||||||
|
|
||||||
|
///Programm to run when an event has fired
|
||||||
#[structopt(
|
#[structopt(
|
||||||
short = "e",
|
short = "e",
|
||||||
long = "event-handler",
|
long = "event-handler",
|
||||||
@@ -28,12 +31,15 @@ pub struct Opts {
|
|||||||
)]
|
)]
|
||||||
pub events: Option<PathBuf>,
|
pub events: Option<PathBuf>,
|
||||||
|
|
||||||
|
///Don't exit on API errors
|
||||||
#[structopt(short = "I", long = "ignore-socket-err", env = "WG_IGNORE_SOCKET_ERR")]
|
#[structopt(short = "I", long = "ignore-socket-err", env = "WG_IGNORE_SOCKET_ERR")]
|
||||||
pub ignore_socket_errors: bool,
|
pub ignore_socket_errors: bool,
|
||||||
|
|
||||||
|
///Log all events to Stdout
|
||||||
#[structopt(short = "l", long = "log", env = "WG_LOG_EVENTS")]
|
#[structopt(short = "l", long = "log", env = "WG_LOG_EVENTS")]
|
||||||
pub log: bool,
|
pub log: bool,
|
||||||
|
|
||||||
|
///Socket for the userspace implementation to poll
|
||||||
#[structopt(name = "SOCKET", parse(from_os_str), env = "WG_EVENT_SOCKET")]
|
#[structopt(name = "SOCKET", parse(from_os_str), env = "WG_EVENT_SOCKET")]
|
||||||
pub socket: PathBuf,
|
pub socket: PathBuf,
|
||||||
}
|
}
|
||||||
|
@@ -1 +1 @@
|
|||||||
cargo build --release && cat target/release/wg-event-gen | ssh core@ks1 "sudo bash -c 'cat > /srv/vpn/wireguard/event-gen'"
|
cargo +nightly build && cat target/release/wg-event-gen | ssh core@ks1 "sudo bash -c 'rm -f /srv/vpn/wireguard/event-gen; cat > /srv/vpn/wireguard/event-gen; chmod +x /srv/vpn/wireguard/event-gen'"
|
||||||
|
Reference in New Issue
Block a user