Compare commits

...

60 Commits

Author SHA1 Message Date
shimunn
60dac9ea17 added option to supress Transfer logging
Some checks are pending
continuous-integration/drone/push Build is running
2019-05-23 20:26:27 +02:00
shimunn
b8d14bee77 useless feature while using docker
Some checks are pending
continuous-integration/drone/push Build was killed
2019-05-23 19:46:18 +02:00
shimunn
5a40f34ca7 Merge branch 'new_events'
Some checks are pending
continuous-integration/drone/push Build was killed
2019-05-23 19:42:34 +02:00
shimunn
574d389b48 actually execute on threadpool
Some checks are pending
continuous-integration/drone/push Build was killed
2019-05-23 19:29:28 +02:00
shimunn
299ba5a5dd release_mode
Some checks are pending
continuous-integration/drone/push Build is running
2019-05-17 16:05:00 +02:00
shimunn
c119cebcf9 correct paths
Some checks are pending
continuous-integration/drone/push Build encountered an error
2019-05-16 22:16:36 +02:00
shimunn
94dd1738bb Merge branch 'threadppol' 2019-05-16 21:54:22 +02:00
shimunn
88454794d4 caching 2019-05-16 21:51:31 +02:00
shimunn
cb138358ce use thread pool to avoid zombie processes
Some checks reported errors
continuous-integration/drone/push Build was killed
2019-05-16 20:48:50 +02:00
shimunn
3cdee28f92 update command
Some checks are pending
continuous-integration/drone/push Build is failing
2019-04-24 22:37:28 +02:00
shimunn
0301a53ac9 implemented listeners for transfered event [CI SKIP] 2019-04-04 21:18:21 +02:00
shimunn
ceb3d7b77d Merge branch 'timeout' into new_events 2019-04-04 20:39:00 +02:00
shimunn
f3eeac404c added transfered event [CI SKIP] 2019-04-04 20:34:54 +02:00
shimunn
a2cda16977 handle timeouts based on the existence of last_handshake 2019-04-04 18:59:17 +02:00
shimunn
2acbb6d574 updated boring tun
Some checks are pending
continuous-integration/drone/push Build is failing
2019-04-03 21:29:00 +02:00
shimunn
8e68c5c90c more logging output [CI SKIP] 2019-04-03 20:20:08 +02:00
shimunn
e56376778d reimplemented -I option [CI SKIP] 2019-04-03 20:07:23 +02:00
shimunn
ba247655bd new event system [CI SKIP] 2019-04-03 17:54:53 +02:00
shimunn
e7999b0951 improved timeout detection [CI SKIP] 2019-04-03 16:57:49 +02:00
shimunn
a64fa75170 improved timeout detection 2019-04-03 16:57:39 +02:00
shimunn
d1daf3be00 Added descriptions [CI SKIP] 2019-04-03 16:57:00 +02:00
shimunn
6a13b27c19 handle last peer error case [CI SKIP] 2019-04-03 14:07:28 +02:00
shimunn
88b68a1de9 parse keys as hex
Some checks are pending
continuous-integration/drone/push Build is failing
2019-04-03 13:54:53 +02:00
shimunn
e3815e3198 added convesion from and to hex [CI SKIP] 2019-04-03 13:51:49 +02:00
5976ddecdf source --log option via env
Some checks are pending
continuous-integration/drone/push Build is failing
2019-04-02 18:38:45 +02:00
8ea6d6e78d complete oxidation
Some checks are pending
continuous-integration/drone/push Build was killed
2019-03-31 18:07:32 +02:00
819eb7d362 integrate old code
Some checks are pending
continuous-integration/drone/push Build is running
2019-03-31 18:04:01 +02:00
fb7d706dae implemented Display [CI SKIP] 2019-03-30 23:45:22 +01:00
b72ca91423 replaced Duration with SystemTime where applicable, implemented Display 2019-03-30 23:44:09 +01:00
a6af494cb9 progress [CI SKIP] 2019-03-30 17:53:27 +01:00
a8be702e88 added interface function [CI SKIP] 2019-03-30 14:30:55 +01:00
0f50dc3e00 figure out why no peers are being produced [CI SKIP] 2019-03-30 14:29:05 +01:00
90f9d4cd36 basic main loop [CI SKIP] 2019-03-30 14:28:30 +01:00
9c5e14cd4e upload script [CI SKIP] 2019-03-30 14:23:39 +01:00
1255a0ed7b parse psk [CI SKIP] 2019-03-30 13:41:22 +01:00
d363fb2401 abstract over base64 [CI SKIP] 2019-03-30 13:41:03 +01:00
shimunn
90d35895e2 switch to boringtun
Some checks are pending
continuous-integration/drone/push Build encountered an error
2019-03-27 21:32:57 +01:00
Drone CI
9993a8f7a4 Compiles [WIP][CI SKIP] 2019-03-20 16:28:16 +01:00
Drone CI
fac5c7c442 closer [CI SKIP] 2019-03-19 15:23:06 +01:00
Drone CI
7491902b34 basic strcuture [CI SKIP] 2019-03-19 12:05:31 +01:00
shimunn
fc494fe4c0 WIP [CI SKIP] 2019-03-19 11:09:10 +01:00
shimunn
22dd07cc14 fail on socket error per default
Some checks are pending
continuous-integration/drone/push Build is passing
2019-03-16 20:34:16 +01:00
shimunn
3b4f13aa44 Merge branch 'structop' 2019-01-25 23:12:21 +01:00
shimunn
0e7ff7293b addrem feature 2019-01-25 23:11:58 +01:00
shimunn
7cf669e619 cargo-fmt 2019-01-25 23:11:30 +01:00
shimunn
34a081c6d6 basic handler [CI SKIP] 2019-01-19 23:04:06 +01:00
shimunn
678987fbbd updated .service [CI SKIP] 2019-01-19 23:03:21 +01:00
shimunn
fa84103e8a added feature to Cargo.toml
Some checks are pending
continuous-integration/drone/push Build is failing
2019-01-19 22:47:23 +01:00
shimunn
804a7fec47 removed unused
Some checks are pending
continuous-integration/drone/push Build encountered an error
2019-01-19 21:00:18 +01:00
shimunn
67cda61245 removed legacy code 2019-01-19 20:56:22 +01:00
shimunn
11411b9d13 lil alias 2019-01-19 20:30:43 +01:00
shimunn
8300e94414 added structopt
Some checks are pending
continuous-integration/drone/push Build encountered an error
2019-01-19 19:36:56 +01:00
shimunn
5835ca7ad6 fix drone
Some checks are pending
continuous-integration/drone/push Build is passing
2019-01-19 17:27:27 +01:00
shimunn
46c10a69da cleanup
Some checks are pending
continuous-integration/drone/push Build was killed
2019-01-19 16:53:34 +01:00
shimunn
5f997ca191 supply more info
Some checks are pending
continuous-integration/drone/push Build was killed
2019-01-19 16:44:05 +01:00
shimunn
32a86b45ab more reliable events 2019-01-19 15:43:55 +01:00
Drone CI
215cb7ec8f proper hash
Some checks are pending
continuous-integration/drone/push Build is failing
2019-01-18 19:03:27 +01:00
Drone CI
5526084882 use debug build
Some checks are pending
continuous-integration/drone/push Build is failing
2019-01-18 18:54:00 +01:00
Drone CI
a96c557b45 target alpine
Some checks are pending
continuous-integration/drone/push Build is failing
2019-01-18 10:37:16 +01:00
Drone CI
fa757372cb verify working binary
Some checks are pending
continuous-integration/drone/push Build is failing
2019-01-18 10:27:42 +01:00
18 changed files with 1221 additions and 512 deletions

View File

@ -4,9 +4,12 @@ name: default
steps: steps:
- name: event-gen - name: event-gen
image: plugins/docker image: plugins/docker
repo: repo.shimun.net/shimun/wireguard-user::build-event-gen settings:
repo: repo.shimun.net/shimun/wireguard-user
tag: build-event-gen
registry: repo.shimun.net registry: repo.shimun.net
cache_from: ["repo.shimun.net/shimun/wireguard-user:build-event-gen"] cache_from: ["repo.shimun.net/shimun/wireguard-user:build-event-gen"]
storage_path: "/drone/docker"
target: eventbuild target: eventbuild
username: username:
from_secret: docker_username from_secret: docker_username
@ -16,21 +19,26 @@ steps:
image: alpine/git image: alpine/git
commands: commands:
- git submodule update --recursive --remote --init - git submodule update --recursive --remote --init
- name: wireguard-go - name: boringtun
image: plugins/docker image: plugins/docker
repo: repo.shimun.net/shimun/wireguard-user:build-wireguard-go settings:
repo: repo.shimun.net/shimun/wireguard-user
tag: build-boringtun
registry: repo.shimun.net registry: repo.shimun.net
cache-from: ["repo.shimun.net/shimun/wireguard-user:build-wireguard-go", "repo.shimun.net/shimun/wireguard-user:build-event-gen"] cache_from: ["repo.shimun.net/shimun/wireguard-user:build-boringtun", "repo.shimun.net/shimun/wireguard-user:build-event-gen"]
target: build storage_path: "/drone/docker"
target: boringbuild
username: username:
from_secret: docker_username from_secret: docker_username
password: password:
from_secret: docker_password from_secret: docker_password
- name: package - name: package
image: plugins/docker image: plugins/docker
settings:
repo: repo.shimun.net/shimun/wireguard-user repo: repo.shimun.net/shimun/wireguard-user
registry: repo.shimun.net registry: repo.shimun.net
cache-from: ["repo.shimun.net/shimun/wireguard-user:build-wireguard-go", "repo.shimun.net/shimun/wireguard-user:build-event-gen", "repo.shimun.net/shimun/wireguard-user"] cache_from: ["repo.shimun.net/shimun/wireguard-user:build-boringtun", "repo.shimun.net/shimun/wireguard-user:build-event-gen", "repo.shimun.net/shimun/wireguard-user"]
storage_path: "/drone/docker"
username: username:
from_secret: docker_username from_secret: docker_username
password: password:

6
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "wireguard-go"] [submodule "boringtun"]
path = wireguard-go path = boringtun
url = https://git.zx2c4.com/wireguard-go url = https://github.com/cloudflare/boringtun.git

View File

@ -1,24 +1,48 @@
FROM rust:1.32-slim AS eventbuild FROM rust:1.33-slim AS rustbuild
WORKDIR /build WORKDIR /build
COPY wg-event-gen/Cargo.* /build/ RUN rustup target add x86_64-unknown-linux-musl
RUN mkdir -p src && echo "fn main() {}" > src/main.rs && cargo build --release ENV USER root
COPY wg-event-gen/ /build ENV CARGO_INSTALL_ROOT /build/
RUN cargo build --release RUN mkdir -p /build/bin
FROM golang AS build RUN bash -c "cd /tmp/; cargo new --bin index; cd index; echo 'test_crate_hello_world = \"0.1.2\"' >> Cargo.toml; cargo build; cd /tmp; rm -rf index"
COPY wireguard-go /go/src/wireguard FROM rustbuild AS eventbuild
WORKDIR /go/src/wireguard WORKDIR /build
RUN echo "package main" > ./donotuseon_linux.go && go get RUN cargo new --lib wg-event-gen
COPY wg-event-gen/Cargo.* /build/wg-event-gen/
WORKDIR /build/wg-event-gen
RUN cargo build --target x86_64-unknown-linux-musl
COPY wg-event-gen/src/ /build/wg-event-gen/src/
RUN cargo install --debug --path . --target x86_64-unknown-linux-musl
FROM rustbuild AS boringbuild
RUN cargo new --bin boringtun && touch boringtun/src/lib.rs
COPY boringtun/Cargo.* /build/boringtun/
WORKDIR /build/boringtun
RUN cargo build --release && rm -rf src Cargo.*
COPY boringtun/ /build/boringtun/
RUN cargo install --path .
RUN go build
FROM frolvlad/alpine-glibc FROM frolvlad/alpine-glibc
@ -26,13 +50,13 @@ RUN echo http://nl.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories
ENV WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD=1 ENV WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD=1
COPY --from=build /go/bin/wireguard /usr/bin/wireguard-go COPY --from=eventbuild /build/bin/wg-event-gen /usr/bin/
COPY --from=eventbuild /build/target/release/wg-event-gen /usr/bin/ COPY --from=boringbuild /build/bin/boringtun /usr/bin/
COPY init.sh /init.sh COPY init.sh /init.sh
RUN chmod +x /init.sh RUN chmod +x /init.sh && echo 'alias nload="nload ${WG_INTERFACE:-wg0}"' >> /root/.bashrc
VOLUME /etc/wireguard/ VOLUME /etc/wireguard/

View File

@ -3,5 +3,11 @@ 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}

1
boringtun Submodule

@ -0,0 +1 @@
Subproject commit 1f842a618a4efb460841a3e0104f4979b21a2485

37
handler.sh Normal file
View File

@ -0,0 +1,37 @@
#!/bin/bash
#{event} {id} {allowed_ips} {endpoint} {last_handshake} {persistent_keepalive} {traffic}
EVENT=$1
PUB_KEY=$2
IFS=',' read -ra ALLOWED_IPS <<< "$3"
ENDPOINT=$4
LAST_HSHAKE=$5
KEEPALIVE=$6
IFS=',' read -ra TRAFFIC <<< "$7"
TX_BYTES=${TRAFFIC[0]}
RX_BYTES=${TRAFFIC[1]}
echo "Caught event $EVENT for $PUB_KEY with IP $ALLOWED_IPS last shaked: $LAST_HSHAKE" > /tmp/log
case "$EVENT" in
"connected")
;;
"disconnected")
;;
"roaming")
PREV_ENDPOINT=$8
;;
"added")
;;
"removed")
;;
"transfered")
*)
exit 1
;;
esac

View File

@ -27,7 +27,7 @@ function setup_iptables() {
iptables -t nat -$1 POSTROUTING -s $ADDRESS -o $PHY_IF -j MASQUERADE; iptables -t nat -$1 POSTROUTING -s $ADDRESS -o $PHY_IF -j MASQUERADE;
} }
/usr/bin/wireguard-go $WG_IF /usr/bin/boringtun --disable-drop-privileges $WG_IF
if [ ! -f "/etc/wireguard/$WG_IF.conf" ]; then if [ ! -f "/etc/wireguard/$WG_IF.conf" ]; then
mkdir -p /etc/wireguard/keys mkdir -p /etc/wireguard/keys
@ -47,7 +47,8 @@ setup_iptables "A"
sleep 3 sleep 3
if [ -e "/usr/bin/wg-event-gen" ]; then if [ -e "/usr/bin/wg-event-gen" ]; then
sleep 3 && /usr/bin/wg-event-gen /var/run/wireguard/$WG_IF.sock 3000 export WG_EVENT_SOCKET=/var/run/wireguard/$WG_IF.sock
/usr/bin/wg-event-gen
else else
while [ -e "/sys/class/net/$WG_IF/operstate" ]; do while [ -e "/sys/class/net/$WG_IF/operstate" ]; do
sleep 10 sleep 10

307
wg-event-gen/Cargo.lock generated
View File

@ -1,15 +1,121 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]] [[package]]
name = "base64" name = "ansi_term"
version = "0.10.0" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "byteorder" name = "atty"
version = "1.2.7" version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "base64"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"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.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.34 (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.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.34 (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.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.34 (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.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.34 (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"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "hex" name = "hex"
@ -17,37 +123,171 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "libc" name = "ident_case"
version = "0.2.47" version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "redox_syscall" name = "libc"
version = "0.1.50" version = "0.2.55"
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.55 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "number_prefix"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "numtoa"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "0.4.30"
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)",
]
[[package]]
name = "quote"
version = "0.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "structopt"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "structopt-derive"
version = "0.2.15"
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.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.15.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termion"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
"numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"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"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "unicode-segmentation"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "wg-event-gen" name = "wg-event-gen"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.10.1 (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)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"number_prefix 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt-derive 0.2.15 (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)",
] ]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.6" version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -65,12 +305,41 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata] [metadata]
"checksum base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "621fc7ecb8008f86d7fb9b95356cd692ce9514b80a86d85b397f32a22da7b9e2" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"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 hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
"checksum libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "48450664a984b25d5b479554c29cc04e3150c97aa4c01da5604a2d4ed9151476" "checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
"checksum redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)" = "52ee9a534dc1301776eff45b4fa92d2c39b1d8c3d3357e6eb593e0d795506fc2" "checksum libc 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "42914d39aad277d9e176efbdad68acb1d5443ab65afe0e0e4f0d49352a950880"
"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
"checksum number_prefix 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b02fc0ff9a9e4b35b3342880f48e896ebf69f2967921fe8646bf5b7125956a"
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3d0760c312538987d363c36c42339b55f5ee176ea8808bbe4543d484a291c8d1"
"checksum structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "528aeb7351d042e6ffbc2a6fb76a86f9b622fdf7c25932798e7a82cb03bc94c6"
"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe"
"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"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 winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -8,6 +8,11 @@ edition = "2018"
hex = "0.3.2" hex = "0.3.2"
base64 = "0.10.0" base64 = "0.10.0"
time = "0.1.42" time = "0.1.42"
structopt = "0.2.14"
structopt-derive = "0.2.14"
derive_builder = "0.7.1"
threadpool = "1.7.1"
number_prefix = "0.3.0"
[profile.release] [profile.release]
lto = false lto = true

View File

@ -0,0 +1,149 @@
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 {}
}
}

View File

@ -1,59 +1,65 @@
use crate::listener::*; use crate::listener::*;
use crate::*; use crate::*;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::env; use std::time;
use std::fmt;
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::rc::Rc;
use std::{thread, time};
pub(crate) fn gen_events( pub(crate) fn gen_events(
state: &HashMap<String, Peer>, state: &HashMap<ECCKey, Peer>,
prev: &HashMap<String, Peer>, prev: &HashMap<ECCKey, Peer>,
listeners: &Vec<Box<EventListener>>, listeners: &Vec<Box<EventListener>>,
timeout: time::Duration, timeout: time::Duration,
poll_interval: time::Duration,
) { ) {
let side_by_side = { let side_by_side = {
state state
.keys() .keys()
.map(String::as_ref) .chain(prev.keys())
.chain(prev.keys().map(String::as_ref)) .collect::<HashSet<&ECCKey>>()
.collect::<HashSet<&str>>()
.iter() .iter()
.map(|p| (p.to_owned(), (prev.get(*p), state.get(*p)))) .map(|p| (*p, (prev.get(*p), state.get(*p))))
.collect::<HashMap<&str, (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)) if prev.endpoint != cur.endpoint => {
if let (Some(prev_addr), Some(_)) = (prev.endpoint, cur.endpoint) {
listeners.roaming(&cur, prev_addr);
}
}
(Some(prev), Some(cur)) => { (Some(prev), Some(cur)) => {
let timedout = |peer: &Peer| match peer.last_handshake_rel() { if let (Some(prev_addr), Some(cur_addr)) = (prev.endpoint, cur.endpoint) {
Some(shake) if shake < timeout => false, if prev_addr != cur_addr {
_ => true, listeners.fire(Event::Roamed(&cur, prev_addr));
};
//if _id == "HhRgEL2xsnEIqThSTUKLGaTXusorM1MFdjSSYvzBynY=" { dbg!((cur.last_handshake_rel(),timedout(&prev) , timedout(&cur))); }
if !timedout(&prev) && timedout(&cur) {
listeners.disconnected(&cur);
}
if timedout(&prev) && !timedout(&cur) {
listeners.connected(&cur);
} }
} }
(None, Some(cur)) => (), //listeners.added(&cur),
(Some(prev), None) => (), //listeners.removed(&prev), let timedout_now = || !cur.last_handshake.is_some();
(None, Some(_cur)) => (),
(Some(_prev), None) => (), let timedout_prev = || !prev.last_handshake.is_some();
match (
timedout_prev(),
timedout_now(),
prev.last_handshake.and_then(|p_shake| {
cur.last_handshake
.and_then(|c_shake| c_shake.duration_since(p_shake).ok())
}),
) {
(false, true, _) => listeners.fire(Event::Disconnected(&cur)),
(true, false, _) => listeners.fire(Event::Connected(&cur)),
other => {
//dbg!(other);
}
}
if prev.traffic != cur.traffic {
if let ((p_tx, p_rx), (c_tx, c_rx)) = (prev.traffic, cur.traffic) {
listeners.fire(Event::Transfered {
peer: &cur,
tx: c_tx - p_tx,
rx: c_rx - p_rx,
});
}
}
}
(None, Some(cur)) => listeners.fire(Event::Added(&cur)),
(Some(prev), None) => listeners.fire(Event::Removed(&prev)),
fail => { fail => {
println!("{:?}", fail); println!("{:?}", fail);
unreachable!() unreachable!()
@ -62,6 +68,7 @@ pub(crate) fn gen_events(
} }
} }
/*
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
@ -94,31 +101,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));
} }
} }
@ -134,7 +141,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()
); );
} }
@ -147,7 +154,7 @@ 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(),
@ -163,23 +170,42 @@ mod test {
let mut peer_cur = peer.clone(); let mut peer_cur = peer.clone();
let mut prev: HashMap<String, Peer> = HashMap::new(); let mut prev: HashMap<String, Peer> = HashMap::new();
let mut cur: HashMap<String, Peer> = HashMap::new(); let mut cur: HashMap<String, Peer> = HashMap::new();
cur.insert(peer_cur.public_key.clone(), peer_cur.clone()); cur.insert(peer_cur.key.clone(), peer_cur.clone());
let (listener, calls) = listeners(); let (listener, calls) = listeners();
gen_events(&cur, &prev, &listener, time::Duration::from_secs(3)); let interval = time::Duration::from_secs(3);
gen_events(
&cur,
&prev,
&listener,
time::Duration::from_secs(3),
interval,
);
assert_eq!( assert_eq!(
vec![["add", &peer_cur.public_key].join(" ")], vec![["add", &peer_cur.key].join(" ")],
calls.borrow().clone() calls.borrow().clone()
); );
gen_events(&cur, &cur, &listener, time::Duration::from_secs(3)); gen_events(
&cur,
&cur,
&listener,
time::Duration::from_secs(3),
interval,
);
//Shouldn't gen any new events //Shouldn't gen any new events
assert!(calls.borrow().len() == 1); assert!(calls.borrow().len() == 1);
let (listener, calls) = listeners(); let (listener, calls) = listeners();
gen_events(&prev, &cur, &listener, time::Duration::from_secs(10)); gen_events(
&prev,
&cur,
&listener,
time::Duration::from_secs(10),
interval,
);
assert_eq!( assert_eq!(
vec![["rem", &peer.public_key].join(" ")], vec![["rem", &peer.key].join(" ")],
calls.borrow().clone() calls.borrow().clone()
); );
@ -191,40 +217,58 @@ mod test {
peer_prev.last_handshake = Some(time::Duration::from_secs(1000)); peer_prev.last_handshake = Some(time::Duration::from_secs(1000));
prev.insert(peer_prev.public_key.clone(), peer_prev.clone()); prev.insert(peer_prev.key.clone(), peer_prev.clone());
gen_events(&prev, &cur, &listener, time::Duration::from_secs(10)); gen_events(
&prev,
assert_eq!( &cur,
vec![["rom", &peer.public_key].join(" ")], &listener,
calls.borrow().clone() time::Duration::from_secs(10),
interval,
); );
assert!(calls
.borrow()
.clone()
.contains(&["rom", &peer.key].join(" ")));
calls.borrow_mut().clear(); calls.borrow_mut().clear();
let mut peer_prev = peer.clone(); let peer_prev = peer.clone();
peer_cur.last_handshake = Some(time::Duration::from_secs(5)); peer_cur.last_handshake = Some(time::Duration::from_secs(5));
cur.insert(peer_cur.public_key.clone(), peer_cur.clone()); cur.insert(peer_cur.key.clone(), peer_cur.clone());
prev.insert(peer_prev.public_key.clone(), peer_prev.clone()); prev.insert(peer_prev.key.clone(), peer_prev.clone());
gen_events(&cur, &prev, &listener, time::Duration::from_secs(10)); gen_events(
&cur,
&prev,
&listener,
time::Duration::from_secs(10),
interval,
);
assert_eq!( assert_eq!(
vec![["con", &peer.public_key].join(" ")], vec![["con", &peer.key].join(" ")],
calls.borrow().clone() calls.borrow().clone()
); );
calls.borrow_mut().clear(); calls.borrow_mut().clear();
//Other way around should be a disconnect //Other way around should be a disconnect
gen_events(&prev, &cur, &listener, time::Duration::from_secs(3)); gen_events(
&prev,
&cur,
&listener,
time::Duration::from_secs(3),
interval,
);
assert_eq!( assert_eq!(
vec![["dis", &peer.public_key].join(" ")], vec![["dis", &peer.key].join(" ")],
calls.borrow().clone() calls.borrow().clone()
); );
} }
} }*/

View File

@ -1,123 +1,170 @@
use crate::Peer; use crate::Peer;
use number_prefix::{NumberPrefix, Prefixed, Standalone};
use std::env;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command; use std::process::Command;
use std::thread; use std::thread;
use std::time::SystemTime;
use threadpool::ThreadPool;
//#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum Event<'a> {
Added(&'a Peer),
Removed(&'a Peer),
Connected(&'a Peer),
Disconnected(&'a Peer),
Roamed(&'a Peer, SocketAddr),
Transfered { peer: &'a Peer, tx: u64, rx: u64 },
}
pub trait EventListener { pub trait EventListener {
fn added<'a>(&self, peer: &'a Peer) { fn name(&self) -> &'static str;
self.connected(peer);
}
fn connected<'a>(&self, peer: &'a Peer); fn fire<'a>(&self, event: Event<'a>);
fn disconnected<'a>(&self, peer: &'a Peer);
fn removed<'a>(&self, peer: &'a Peer) {
self.disconnected(peer)
}
fn roaming<'a>(&self, peer: &'a Peer, previous_addr: SocketAddr);
} }
impl EventListener for Vec<Box<EventListener>> { impl EventListener for Vec<Box<EventListener>> {
fn added<'a>(&self, peer: &'a Peer) { fn name(&self) -> &'static str {
self.iter().for_each(|l| l.added(&peer)); "List of Listeners"
} }
fn fire<'a>(&self, event: Event<'a>) {
fn connected<'a>(&self, peer: &'a Peer) { self.iter().for_each(|l| l.fire(event.clone()));
self.iter().for_each(|l| l.connected(&peer));
}
fn disconnected<'a>(&self, peer: &'a Peer) {
self.iter().for_each(|l| l.disconnected(&peer));
}
fn removed<'a>(&self, peer: &'a Peer) {
self.iter().for_each(|l| l.removed(&peer));
}
fn roaming<'a>(&self, peer: &'a Peer, previous_addr: SocketAddr) {
self.iter().for_each(|l| l.roaming(&peer, previous_addr));
} }
} }
pub struct LogListener; pub struct LogListener {
log_transfer: bool,
}
impl Default for LogListener {
fn default() -> LogListener {
let log = env::var("WG_LOG_TRANSFER")
.map(|t| t.parse::<bool>().unwrap_or(true))
.unwrap_or(false);
LogListener { log_transfer: log }
}
}
impl EventListener for LogListener { impl EventListener for LogListener {
fn connected<'a>(&self, peer: &'a Peer) { fn name(&self) -> &'static str {
println!("{} connected!", peer.public_key); "Log"
} }
fn disconnected<'a>(&self, peer: &'a Peer) { fn fire<'a>(&self, event: Event<'a>) {
println!("{} disconnected!", peer.public_key); match event {
} Event::Connected(peer) => println!("{} connected!", peer.key),
Event::Disconnected(peer) => println!("{} disconnected!", peer.key),
fn added<'a>(&self, peer: &'a Peer) { Event::Added(peer) => println!("{} added!", peer.key),
println!("{} added!", peer.public_key); Event::Removed(peer) => println!("{} removed!", peer.key),
} Event::Roamed(peer, previous_addr) => println!(
fn removed<'a>(&self, peer: &'a Peer) {
println!("{} removed!", peer.public_key);
}
fn roaming<'a>(&self, peer: &'a Peer, previous_addr: SocketAddr) {
println!(
"{} roamed {} -> {}!", "{} roamed {} -> {}!",
peer.public_key, peer.key,
previous_addr, previous_addr,
peer.endpoint.unwrap() peer.endpoint.unwrap()
),
Event::Transfered { peer, tx, rx } if self.log_transfer => {
let prefix = |cnt: u64| match NumberPrefix::binary(cnt as f64) {
Standalone(bytes) => format!("{}B", bytes),
Prefixed(prefix, n) => format!("{:.0} {}B", n, prefix),
};
println!(
"{} transfered {} up, {} down",
peer.key,
prefix(tx),
prefix(rx)
); );
} }
Event::Transfered { peer, tx, rx } => (),
_ => unimplemented!(),
}
}
} }
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(8);
ScriptListener { script, pool }
}
fn peer_props<'a>(&self, peer: &'a Peer) -> String {
format!(
"{id} {allowed_ips} {endpoint} {last_handshake} {persistent_keepalive} {traffic}",
id = peer.key,
allowed_ips = peer
.allowed_ips
.iter()
.map(|(addr, mask)| [addr.to_string(), mask.to_string()].join("/"))
.collect::<Vec<String>>()
.join(","),
endpoint = peer
.endpoint
.map(|e| e.to_string())
.unwrap_or("0".to_owned()),
last_handshake = peer
.last_handshake
.map(|s| s.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs() as i64)
.unwrap_or(-1),
persistent_keepalive = peer
.persistent_keepalive
.map(|k| k.as_secs() as i64)
.unwrap_or(-1),
traffic = {
let (rx, tx) = peer.traffic;
[rx.to_string(), tx.to_string()].join(",")
}
)
} }
fn mkcmd<'a>(&self, args: Vec<&'a str>) -> Command { fn mkcmd<'a>(&self, args: Vec<&'a str>) -> Command {
let mut cmd = Command::new("/bin/sh"); let mut cmd = Command::new("/bin/sh");
cmd.arg("-c"); cmd.arg("-c");
cmd.arg(format!("{} {}",(&self.script).to_str().unwrap(), args.join(" "))); cmd.arg(format!(
"{} {}",
(&self.script).to_str().unwrap(),
args.join(" ")
));
cmd cmd
} }
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.output().expect("Failed to call Script hooḱ!");
}); });
} }
} }
impl EventListener for ScriptListener { impl EventListener for ScriptListener {
fn connected<'a>(&self, peer: &'a Peer) { fn name(&self) -> &'static str {
self.call_sub(vec!["connected", &peer.public_key]); "Script"
} }
fn fire<'a>(&self, event: Event<'a>) {
fn disconnected<'a>(&self, peer: &'a Peer) { match event {
self.call_sub(vec!["disconnected", &peer.public_key]); Event::Connected(peer) => self.call_sub(vec!["connected", &self.peer_props(peer)]),
Event::Disconnected(peer) => {
self.call_sub(vec!["disconnected", &self.peer_props(peer)])
} }
Event::Added(peer) => self.call_sub(vec!["added", &self.peer_props(peer)]),
fn added<'a>(&self, peer: &'a Peer) { Event::Removed(peer) => self.call_sub(vec!["removed", &self.peer_props(peer)]),
self.call_sub(vec!["added", &peer.public_key]); Event::Roamed(peer, previous_addr) => self.call_sub(vec![
}
fn removed<'a>(&self, peer: &'a Peer) {
self.call_sub(vec!["removed", &peer.public_key]);
}
fn roaming<'a>(&self, peer: &'a Peer, previous_addr: SocketAddr) {
self.call_sub(vec![
"roaming", "roaming",
&peer.public_key, &self.peer_props(peer),
&previous_addr.to_string(), &previous_addr.to_string(),
&peer.endpoint.unwrap().to_string(), ]),
]); Event::Transfered { peer, tx, rx } => self.call_sub(vec![
"transfered",
&self.peer_props(peer),
&tx.to_string(),
&rx.to_string(),
]),
_ => unimplemented!(),
}
} }
} }

View File

@ -1,263 +1,84 @@
#[macro_use]
extern crate structopt;
#[macro_use]
extern crate derive_builder;
mod controller;
mod gen; mod gen;
mod listener; mod listener;
mod model;
mod opts;
use crate::gen::*; use crate::gen::gen_events;
use crate::listener::*; use crate::listener::*;
use crate::model::{ECCKey, Peer};
use base64; use controller::Userspace;
use hex; use model::WireguardController;
use opts::Opts;
use std::collections::HashMap; use std::collections::HashMap;
use std::env; use std::error::Error;
use std::fmt; use std::io;
use std::io::prelude::*; use std::thread::sleep;
use std::io::{BufRead, BufReader, Error, ErrorKind, Result}; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use std::net::SocketAddr; use structopt::StructOpt;
use std::os::unix::net::UnixStream;
use std::path::PathBuf;
use time;
use std::thread;
use std::time::Duration;
pub type KV = (String, String); fn listeners(opts: &Opts) -> Vec<Box<EventListener>> {
let mut listeners: Vec<Box<EventListener>> = Vec::with_capacity(2);
#[derive(Debug, PartialEq, Eq, Hash)] if let Some(events) = opts.events.clone() {
enum State { listeners.push(Box::new(ScriptListener::new(events)))
Interface(Vec<KV>), }
Peer(Vec<KV>), if opts.log {
listeners.push(Box::new(LogListener::default()));
}
println!("Enabled handlers: {}", (&listeners.iter().map(|l| l.name()).collect::<Vec<_>>()).join(", "));
listeners
} }
#[derive(Debug, PartialEq, Eq, Hash, Clone)] fn main() -> io::Result<()> {
pub struct Peer { let opts = Opts::from_args();
public_key: String, let mut controller: Box<WireguardController> = Box::new(Userspace::new(opts.socket.clone()));
endpoint: Option<SocketAddr>, let interval = Duration::from_millis(opts.poll);
last_handshake: Option<Duration>, let timeout = Duration::from_secs(opts.timeout);
persistent_keepalive: Option<Duration>, let listeners = listeners(&opts);
parsed: time::Timespec,
}
impl Peer { println!(
fn from_kv(entries: &Vec<KV>) -> Result<Peer> { "Polling {} every {:?}",
let key = match entries opts.socket.to_str().unwrap(),
.iter() interval
.filter(|(key, _)| key == &"public_key") );
.map(|(_, value)| value) let mut peers_last: Option<HashMap<ECCKey, Peer>> = None;
.next() loop {
{ let now = Instant::now();
Some(key) => key, let peers = match controller.peers() {
None => return Err(Error::new(ErrorKind::Other, "Peer is missing key")), Err(ref err) if opts.ignore_socket_errors => {
eprintln!(
"Encountered error while querying Wireguard: {}",
err.description()
);
sleep(interval);
continue;
}
res => res?,
}; };
Ok(Peer { let peers = peers
public_key: base64::encode(&hex::decode(key).unwrap()), .map(|peer| peer.map(|peer_ok| (peer_ok.key.clone(), peer_ok)))
endpoint: entries .collect::<io::Result<HashMap<_, _>>>()?;
.iter()
.filter(|(key, _)| key == &"endpoint") if let Some(ref mut peers_last) = peers_last {
.map(|(_, value)| value.parse::<SocketAddr>().unwrap()) gen_events(&peers, &peers_last, &listeners, timeout, interval);
.next(),
last_handshake: entries *peers_last = peers;
.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 { } else {
Some(add) peers_last = Some(peers);
}
}),
persistent_keepalive: entries
.iter()
.filter(|(key, _)| key == &"persistent_keepalive")
.map(|(_, value)| Duration::from_secs(value.parse::<u64>().unwrap()))
.next(),
parsed: time::get_time(),
})
} }
let pause = interval - now.elapsed();
pub fn last_handshake_rel(&self) -> Option<Duration> { sleep(if pause > interval / 2 {
let time = self.parsed; pause
Some(Duration::new(time.sec as u64, time.nsec as u32) - self.last_handshake?) } else {
} interval
});
}
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 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>>()
}
}
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(()) 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),
))?,
"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())
}
}
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 mut listeners: Vec<Box<EventListener>> = vec![Box::new(LogListener)];
let events: PathBuf = "/etc/wireguard/events.sh".into();
if events.exists() {
listeners.push(Box::new(ScriptListener::new(events)))
}
let timeout = env::vars().collect::<HashMap<String,String>>().get("WG_EVENT_GEN_TIMEOUT").map(|timeout| Duration::from_secs(timeout.parse::<u64>().expect(&format!("Can't parse {} as timeout", timeout)))).unwrap_or(Duration::from_secs(30));
if let Some(path) = path {
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);
continue;
}
};
if let Some(prev_state) = prev_state {
gen::gen_events(&state, &prev_state, &listeners, timeout);
}
prev_state = Some(state);
thread::sleep(Duration::from_millis(interval));
}
} else {
println!("<path> does not exist");
}
}

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

@ -0,0 +1,247 @@
use base64::{decode, encode};
use hex;
use std::error::Error;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::io;
use std::net::{IpAddr, SocketAddr};
use std::time::Instant;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
const KEY_SIZE: usize = 48; //TODO: use VEC instead of array
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum ECCKey {
PublicKey(Vec<u8>),
PrivateKey(Vec<u8>),
}
impl fmt::Display for ECCKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_base64().unwrap())
}
}
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 {
fn from_bytes(bytes: Vec<u8>) -> Self;
fn bytes(&self) -> &Vec<u8>;
fn from_base64<I: AsRef<str>>(key: I) -> io::Result<Self>
where
Self: Sized,
{
let key = match decode(key.as_ref()) {
Ok(key) => key,
_ => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Failed to decode base64",
));
}
}; /*.map_err(|err| {
})?;*/
if key.len() != KEY_SIZE {
return Err(io::Error::new(
io::ErrorKind::Other,
format!(
"Mismatched key size. Expected: {}, Got {}",
KEY_SIZE,
key.len()
),
));
}
Ok(Self::from_bytes(key))
}
fn as_base64(&self) -> io::Result<String> {
Ok(encode(self.bytes()))
}
}
impl Base64Backed for ECCKey {
fn bytes(&self) -> &Vec<u8> {
match self {
ECCKey::PublicKey(bytes) => &bytes,
ECCKey::PrivateKey(bytes) => &bytes,
}
}
fn from_bytes(bytes: Vec<u8>) -> ECCKey {
ECCKey::PublicKey(bytes)
}
}
impl ECCKey {
pub fn public_key(&self) -> Option<ECCKey> {
//TODO: Determine whether Self is a private key and only the return public part
Some(self.clone())
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct SharedKey(Vec<u8>);
impl fmt::Display for SharedKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_base64().unwrap())
}
}
impl Base64Backed for SharedKey {
fn bytes(&self) -> &Vec<u8> {
&self.0
}
fn from_bytes(bytes: Vec<u8>) -> SharedKey {
SharedKey(bytes)
}
}
#[derive(Debug, Builder, PartialEq, Eq, Clone)]
pub struct Interface {
pub key: ECCKey,
pub port: usize,
pub fwmark: Option<String>,
}
impl Hash for Interface {
fn hash<H: Hasher>(&self, state: &mut H) {
self.key.public_key().hash(state);
}
}
#[derive(Debug, Builder, PartialEq, Eq, Clone)]
pub struct Peer {
pub key: ECCKey,
#[builder(default = "None")]
pub shared_key: Option<SharedKey>,
#[builder(default = "None")]
pub endpoint: Option<SocketAddr>,
#[builder(default = "Vec::new()")]
pub allowed_ips: Vec<(IpAddr, u8)>,
#[builder(default = "None")]
pub last_handshake: Option<SystemTime>,
#[builder(default = "None")]
pub persistent_keepalive: Option<Duration>,
#[builder(default = "(0u64,0u64)")]
pub traffic: (u64, u64),
#[builder(default = "Instant::now()")]
pub parsed: Instant,
}
impl Hash for Peer {
fn hash<H: Hasher>(&self, state: &mut H) {
self.key.hash(state);
}
}
impl fmt::Display for Peer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn dis_opt<'a, T: fmt::Display + 'a>(opt: &Option<T>) -> String {
opt.as_ref()
.map(|s| s.to_string())
.unwrap_or(" ".to_string())
}
write!(
f,
"peer {} {}{}{}",
self.key,
dis_opt(&self.shared_key),
dis_opt(&self.endpoint),
self.allowed_ips
.iter()
.map(|(ip, sub)| format!(" {}/{}", ip, sub))
.collect::<Vec<_>>()
.join(",")
)
}
}
impl PeerBuilder {
fn validate(&self) -> Result<(), String> {
if let Some(ref key) = self.key {
Ok(())
} else {
Err("No key supplied".into())
}
}
pub fn is_whole(&self) -> bool {
self.validate().is_ok()
}
pub fn has_key(&self) -> bool {
self.key.is_some()
}
pub fn add_allowed_ip(&mut self, ip: (IpAddr, u8)) {
if let Some(ref mut ips) = &mut self.allowed_ips {
ips.push(ip);
} else {
self.allowed_ips = Some(vec![ip]);
}
}
pub fn add_last_handshake(&mut self, d: Duration) {
if !self.last_handshake.is_some() {
self.last_handshake = Some(Some(UNIX_EPOCH + d));
} else {
self.last_handshake = self
.last_handshake
.map(|shake| shake.map(|shake| shake + d));
}
}
pub fn add_traffic(&mut self, txrx: (u64, u64)) {
if let Some(ref mut traffic) = &mut self.traffic {
traffic.0 += txrx.0;
traffic.1 += txrx.1;
} else {
self.traffic = Some(txrx);
}
}
}
pub trait WireguardController {
fn peers<'a>(&'a mut self) -> io::Result<Box<Iterator<Item = io::Result<Peer>> + 'a>>;
fn interface(&mut self) -> io::Result<Interface>;
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);
}
}

45
wg-event-gen/src/opts.rs Normal file
View File

@ -0,0 +1,45 @@
use std::path::PathBuf;
use structopt::StructOpt;
#[derive(StructOpt, Debug)]
#[structopt(name = "event-gen")]
pub struct Opts {
///Time after which a client is considered as offline
#[structopt(
short = "t",
long = "timeout",
default_value = "115",
env = "WG_EVENT_TIMEOUT"
)]
pub timeout: u64,
///Interval after which Wireguard will be polled for updates
#[structopt(
short = "p",
long = "poll-interval",
default_value = "3000",
env = "WG_EVENT_INTERVAL"
)]
pub poll: u64,
///Programm to run when an event has fired
#[structopt(
short = "e",
long = "event-handler",
parse(from_os_str),
env = "WG_EVENT_HANDLER"
)]
pub events: Option<PathBuf>,
///Don't exit on API errors
#[structopt(short = "I", long = "ignore-socket-err", env = "WG_IGNORE_SOCKET_ERR")]
pub ignore_socket_errors: bool,
///Log all events to Stdout
#[structopt(short = "l", long = "log", env = "WG_LOG_EVENTS")]
pub log: bool,
///Socket for the userspace implementation to poll
#[structopt(name = "SOCKET", parse(from_os_str), env = "WG_EVENT_SOCKET")]
pub socket: PathBuf,
}

1
wg-event-gen/upload.sh Executable file
View File

@ -0,0 +1 @@
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'"

@ -1 +0,0 @@
Subproject commit f49da8b7ad99b479b9221426eec865cd5ee09a30

View File

@ -21,6 +21,8 @@ ExecStartPre=-/bin/mknod /dev/net/tun c 10 200
#Environment=WG_HOST_INTERFACE=eth0 #Environment=WG_HOST_INTERFACE=eth0
#Environment=WG_ADDRESS=10.200.200.1/24 #Environment=WG_ADDRESS=10.200.200.1/24
#Environment=WG_LOG_EVENTS=1
Environment=ROOT_DIR=/srv/wireguard Environment=ROOT_DIR=/srv/wireguard
Environment=WG_CAPS="CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FSETID,CAP_FOWNER,CAP_MKNOD,CAP_NET_RAW,CAP_SETGID,CAP_SETUID,CAP_SETFCAP,CAP_SETPCAP,CAP_NET_BIND_SERVICE,CAP_SYS_CHROOT,CAP_KILL,CAP_AUDIT_WRITE,CAP_NET_ADMIN,CAP_SYS_ADMIN" Environment=WG_CAPS="CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FSETID,CAP_FOWNER,CAP_MKNOD,CAP_NET_RAW,CAP_SETGID,CAP_SETUID,CAP_SETFCAP,CAP_SETPCAP,CAP_NET_BIND_SERVICE,CAP_SYS_CHROOT,CAP_KILL,CAP_AUDIT_WRITE,CAP_NET_ADMIN,CAP_SYS_ADMIN"
@ -31,6 +33,9 @@ ExecStart=/usr/bin/rkt --insecure-options=image run --uuid-file-save=${ROOT_DIR}
--volume dev-net,kind=host,source=/dev/net/tun --volume volume-etc-wireguard,kind=host,source=${ROOT_DIR},readOnly=false \ --volume dev-net,kind=host,source=/dev/net/tun --volume volume-etc-wireguard,kind=host,source=${ROOT_DIR},readOnly=false \
--port 51820-udp:51820 repo.shimun.net/shimun/wireguard-user --mount volume=dev-net,target=/dev/net/tun --caps-retain=${WG_CAPS} --port 51820-udp:51820 repo.shimun.net/shimun/wireguard-user --mount volume=dev-net,target=/dev/net/tun --caps-retain=${WG_CAPS}
ExecStop=-/usr/bin/rkt enter --app=wireguard-user $(cat ${ROOT_DIR}/container.uuid) /bin/wg-save
TimeoutStopSec=5
ExecStopPost=-/usr/bin/rkt rm --uuid-file=${ROOT_DIR}/container.uuid ExecStopPost=-/usr/bin/rkt rm --uuid-file=${ROOT_DIR}/container.uuid
KillMode=mixed KillMode=mixed
Restart=always Restart=always