Compare commits
73 Commits
test
...
new_events
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0301a53ac9 | ||
![]() |
ceb3d7b77d | ||
![]() |
f3eeac404c | ||
![]() |
a2cda16977 | ||
![]() |
2acbb6d574 | ||
![]() |
8e68c5c90c | ||
![]() |
e56376778d | ||
![]() |
ba247655bd | ||
![]() |
e7999b0951 | ||
![]() |
a64fa75170 | ||
![]() |
d1daf3be00 | ||
![]() |
6a13b27c19 | ||
![]() |
88b68a1de9 | ||
![]() |
e3815e3198 | ||
5976ddecdf | |||
8ea6d6e78d | |||
819eb7d362 | |||
fb7d706dae | |||
b72ca91423 | |||
a6af494cb9 | |||
a8be702e88 | |||
0f50dc3e00 | |||
90f9d4cd36 | |||
9c5e14cd4e | |||
1255a0ed7b | |||
d363fb2401 | |||
![]() |
90d35895e2 | ||
![]() |
9993a8f7a4 | ||
![]() |
fac5c7c442 | ||
![]() |
7491902b34 | ||
![]() |
fc494fe4c0 | ||
![]() |
22dd07cc14 | ||
![]() |
3b4f13aa44 | ||
![]() |
0e7ff7293b | ||
![]() |
7cf669e619 | ||
![]() |
34a081c6d6 | ||
![]() |
678987fbbd | ||
![]() |
fa84103e8a | ||
![]() |
804a7fec47 | ||
![]() |
67cda61245 | ||
![]() |
11411b9d13 | ||
![]() |
8300e94414 | ||
![]() |
5835ca7ad6 | ||
![]() |
46c10a69da | ||
![]() |
5f997ca191 | ||
![]() |
32a86b45ab | ||
![]() |
215cb7ec8f | ||
![]() |
5526084882 | ||
![]() |
a96c557b45 | ||
![]() |
fa757372cb | ||
![]() |
fa79ceae9e | ||
![]() |
22f51f85f1 | ||
![]() |
7acd090b21 | ||
![]() |
1dbc9596c2 | ||
![]() |
edf635ca9b | ||
![]() |
34e04ae726 | ||
![]() |
e2dbf0112e | ||
![]() |
198703c01b | ||
![]() |
5879bcc4e6 | ||
![]() |
a06edf48dd | ||
![]() |
1ba7eb556e | ||
![]() |
7a17b0d22c | ||
![]() |
c1e6d09246 | ||
![]() |
f036aeca41 | ||
![]() |
b7641871fb | ||
![]() |
e432793aeb | ||
![]() |
da029637a1 | ||
![]() |
03fb5cef29 | ||
![]() |
c58c970cad | ||
![]() |
f6c1c2771e | ||
![]() |
43a0f495f6 | ||
![]() |
459888cafa | ||
![]() |
7c93c5739a |
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*/target
|
45
.drone.yml
Normal file
45
.drone.yml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
kind: pipeline
|
||||||
|
name: default
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: event-gen
|
||||||
|
image: plugins/docker
|
||||||
|
settings:
|
||||||
|
repo: repo.shimun.net/shimun/wireguard-user
|
||||||
|
tag: build-event-gen
|
||||||
|
registry: repo.shimun.net
|
||||||
|
cache_from: ["repo.shimun.net/shimun/wireguard-user:build-event-gen"]
|
||||||
|
storage_path: "/drone/docker"
|
||||||
|
target: eventbuild
|
||||||
|
username:
|
||||||
|
from_secret: docker_username
|
||||||
|
password:
|
||||||
|
from_secret: docker_password
|
||||||
|
- name: git-modules
|
||||||
|
image: alpine/git
|
||||||
|
commands:
|
||||||
|
- git submodule update --recursive --remote --init
|
||||||
|
- name: boringtun
|
||||||
|
image: plugins/docker
|
||||||
|
settings:
|
||||||
|
repo: repo.shimun.net/shimun/wireguard-user
|
||||||
|
tag: build-boringtun
|
||||||
|
registry: repo.shimun.net
|
||||||
|
cache_from: ["repo.shimun.net/shimun/wireguard-user:build-boringtun", "repo.shimun.net/shimun/wireguard-user:build-event-gen"]
|
||||||
|
storage_path: "/drone/docker"
|
||||||
|
target: boringbuild
|
||||||
|
username:
|
||||||
|
from_secret: docker_username
|
||||||
|
password:
|
||||||
|
from_secret: docker_password
|
||||||
|
- name: package
|
||||||
|
image: plugins/docker
|
||||||
|
settings:
|
||||||
|
repo: repo.shimun.net/shimun/wireguard-user
|
||||||
|
registry: repo.shimun.net
|
||||||
|
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:
|
||||||
|
from_secret: docker_username
|
||||||
|
password:
|
||||||
|
from_secret: docker_password
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*/target
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -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
|
||||||
|
45
Dockerfile
45
Dockerfile
@@ -1,24 +1,53 @@
|
|||||||
FROM golang AS build
|
FROM rust:1.33-slim AS rustbuild
|
||||||
|
|
||||||
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 rustup target add x86_64-unknown-linux-musl
|
||||||
|
|
||||||
|
COPY wg-event-gen/Cargo.* /build/
|
||||||
|
|
||||||
|
RUN mkdir -p src && echo "fn main() {}" > src/main.rs && cargo build --release --target x86_64-unknown-linux-musl
|
||||||
|
|
||||||
|
COPY wg-event-gen/ /build
|
||||||
|
|
||||||
|
RUN cargo build --target x86_64-unknown-linux-musl
|
||||||
|
|
||||||
|
FROM frolvlad/alpine-glibc AS test
|
||||||
|
|
||||||
|
COPY --from=eventbuild /build/target/x86_64-unknown-linux-musl/debug/wg-event-gen /usr/bin/
|
||||||
|
|
||||||
|
RUN echo "d41d8cd98f00b204e9800998ecf8427e -" > test.md5 && wg-event-gen | md5sum -c test.md5
|
||||||
|
|
||||||
|
FROM rustbuild AS boringbuild
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
RUN rustup target add x86_64-unknown-linux-musl
|
||||||
|
|
||||||
|
COPY boringtun/Cargo.* /build/
|
||||||
|
|
||||||
|
RUN mkdir -p src && echo "fn main() {}" > src/main.rs && touch src/lib.rs && cargo build --release #--target x86_64-unknown-linux-musl #Ring won't compile https://github.com/briansmith/ring/issues/713
|
||||||
|
|
||||||
|
COPY boringtun/ /build
|
||||||
|
|
||||||
|
RUN cargo build --release #--target x86_64-unknown-linux-musl
|
||||||
|
|
||||||
RUN go build
|
|
||||||
|
|
||||||
FROM frolvlad/alpine-glibc
|
FROM frolvlad/alpine-glibc
|
||||||
|
|
||||||
RUN echo http://nl.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories && apk --no-cache add wireguard-tools bash
|
RUN echo http://nl.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories && apk --no-cache add wireguard-tools bash nload
|
||||||
|
|
||||||
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/target/x86_64-unknown-linux-musl/debug/wg-event-gen /usr/bin/
|
||||||
|
|
||||||
|
COPY --from=boringbuild /build/target/release/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/
|
||||||
|
|
||||||
|
7
Makefile
Normal file
7
Makefile
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
REPO := repo.shimun.net/shimun/wireguard-user
|
||||||
|
|
||||||
|
build:
|
||||||
|
docker build . -t ${REPO}
|
||||||
|
|
||||||
|
push: build
|
||||||
|
docker push ${REPO}
|
1
README.md
Normal file
1
README.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
[](https://ci.shimun.net/shimun/wireguard-user)
|
1
boringtun
Submodule
1
boringtun
Submodule
Submodule boringtun added at 1f842a618a
37
handler.sh
Normal file
37
handler.sh
Normal 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
|
40
init.sh
40
init.sh
@@ -8,14 +8,26 @@ PHY_IF=${WG_HOST_INTERFACE:-$(ip route | awk '/default/ { print $5 }')}
|
|||||||
ADDRESS=${WG_ADDRESS:-10.200.200.1/24}
|
ADDRESS=${WG_ADDRESS:-10.200.200.1/24}
|
||||||
|
|
||||||
function shutdown() {
|
function shutdown() {
|
||||||
|
CONF=$(wg showconf $WG_IF)
|
||||||
|
if [ ! -z "$CONF" ]; then
|
||||||
|
echo "$CONF" > /etc/wireguard/$WG_IF.conf
|
||||||
|
fi
|
||||||
ip link del dev $WG_IF
|
ip link del dev $WG_IF
|
||||||
iptables -D FORWARD -i $WG_IF -j ACCEPT; iptables -D FORWARD -i $WG_IF -o $PHY_IF -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -D FORWARD -i $PHY_IF -o $WG_IF -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -D POSTROUTING -s $ADDRESS -o $PHY_IF -j MASQUERADE;
|
setup_iptables "D"
|
||||||
#iptables -D FORWARD -i $WG_IF -j ACCEPT; iptables -t nat -D POSTROUTING -o $PHY_IF -j MASQUERADE
|
|
||||||
wg showconf $WG_IF > /etc/wireguard/$WG_IF.conf
|
|
||||||
killall sleep
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/usr/bin/wireguard-go $WG_IF
|
function setup_iptables() {
|
||||||
|
if [ ! -z "$WG_REDIRECT_DNS" ]; then
|
||||||
|
iptables -t nat -$1 OUTPUT -p udp --dport 53 -j DNAT --to $WG_REDIRECT_DNS
|
||||||
|
iptables -t nat -$1 OUTPUT -p tcp --dport 53 -j DNAT --to $WG_REDIRECT_DNS
|
||||||
|
fi
|
||||||
|
iptables -$1 FORWARD -i $WG_IF -j ACCEPT
|
||||||
|
iptables -$1 FORWARD -i $WG_IF -o $PHY_IF -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||||
|
iptables -$1 FORWARD -i $PHY_IF -o $WG_IF -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||||
|
iptables -t nat -$1 POSTROUTING -s $ADDRESS -o $PHY_IF -j MASQUERADE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/usr/bin/boringtun $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
|
||||||
@@ -26,11 +38,21 @@ else
|
|||||||
wg setconf $WG_IF /etc/wireguard/$WG_IF.conf
|
wg setconf $WG_IF /etc/wireguard/$WG_IF.conf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
trap shutdown EXIT
|
trap shutdown EXIT SIGTERM SIGTERM
|
||||||
|
|
||||||
ip link set up dev $WG_IF
|
ip link set up dev $WG_IF
|
||||||
ip address add $ADDRESS dev $WG_IF
|
ip address add $ADDRESS dev $WG_IF
|
||||||
iptables -A FORWARD -i $WG_IF -j ACCEPT; iptables -A FORWARD -i $WG_IF -o $PHY_IF -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -A FORWARD -i $PHY_IF -o $WG_IF -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -A POSTROUTING -s $ADDRESS -o $PHY_IF -j MASQUERADE;
|
setup_iptables "A"
|
||||||
#iptables -A FORWARD -i $WG_IF -j ACCEPT; iptables -t nat -A POSTROUTING -o $PHY_IF -j MASQUERADE
|
|
||||||
|
|
||||||
sleep 100000000
|
sleep 3
|
||||||
|
|
||||||
|
if [ -e "/usr/bin/wg-event-gen" ]; then
|
||||||
|
export WG_EVENT_SOCKET=/var/run/wireguard/$WG_IF.sock
|
||||||
|
/usr/bin/wg-event-gen
|
||||||
|
else
|
||||||
|
while [ -e "/sys/class/net/$WG_IF/operstate" ]; do
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
shutdown
|
||||||
|
319
wg-event-gen/Cargo.lock
generated
Normal file
319
wg-event-gen/Cargo.lock
generated
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atty"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 1.2.7 (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.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "2.32.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.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"textwrap 0.10.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.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.8.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_builder"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"darling 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"derive_builder_core 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_builder_core"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"darling 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fnv"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.47"
|
||||||
|
source = "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 = "proc-macro2"
|
||||||
|
version = "0.4.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "0.6.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.1.50"
|
||||||
|
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.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "structopt"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"structopt-derive 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "structopt-derive"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "0.15.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termion"
|
||||||
|
version = "1.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"redox_syscall 0.1.50 (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.10.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 = "time"
|
||||||
|
version = "0.1.42"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.2.1"
|
||||||
|
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]]
|
||||||
|
name = "wg-event-gen"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"derive_builder 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"number_prefix 0.3.0 (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)",
|
||||||
|
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||||
|
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||||
|
"checksum base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "621fc7ecb8008f86d7fb9b95356cd692ce9514b80a86d85b397f32a22da7b9e2"
|
||||||
|
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||||
|
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
|
||||||
|
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||||
|
"checksum darling 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9158d690bc62a3a57c3e45b85e4d50de2008b39345592c64efd79345c7e24be0"
|
||||||
|
"checksum darling_core 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d2a368589465391e127e10c9e3a08efc8df66fd49b87dc8524c764bbe7f2ef82"
|
||||||
|
"checksum darling_macro 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "244e8987bd4e174385240cde20a3657f607fb0797563c28255c353b5819a07b1"
|
||||||
|
"checksum derive_builder 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a0ca533e6abb78f9108585535ce2ae0b14c8b4504e138a9a28eaf8ba2b270c1d"
|
||||||
|
"checksum derive_builder_core 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fb484fe06ba1dc5b82f88aff700191dfc127e02b06b35e302c169706168e2528"
|
||||||
|
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||||
|
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||||
|
"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
|
||||||
|
"checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
"checksum libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "48450664a984b25d5b479554c29cc04e3150c97aa4c01da5604a2d4ed9151476"
|
||||||
|
"checksum number_prefix 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b02fc0ff9a9e4b35b3342880f48e896ebf69f2967921fe8646bf5b7125956a"
|
||||||
|
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
|
||||||
|
"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
|
||||||
|
"checksum redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)" = "52ee9a534dc1301776eff45b4fa92d2c39b1d8c3d3357e6eb593e0d795506fc2"
|
||||||
|
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||||
|
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||||
|
"checksum structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "670ad348dc73012fcf78c71f06f9d942232cdd4c859d4b6975e27836c3efc0c3"
|
||||||
|
"checksum structopt-derive 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ef98172b1a00b0bec738508d3726540edcbd186d50dfd326f2b1febbb3559f04"
|
||||||
|
"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 textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
||||||
|
"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-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.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||||
|
"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"
|
23
wg-event-gen/Cargo.toml
Normal file
23
wg-event-gen/Cargo.toml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
[package]
|
||||||
|
name = "wg-event-gen"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["shimun <wg.shimun@shimun.net>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
hex = "0.3.2"
|
||||||
|
base64 = "0.10.0"
|
||||||
|
time = "0.1.42"
|
||||||
|
structopt = "0.2.14"
|
||||||
|
structopt-derive = "0.2.14"
|
||||||
|
derive_builder = "0.7.1"
|
||||||
|
number_prefix = "0.3.0"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
|
||||||
|
default = ["addrem"]
|
||||||
|
|
||||||
|
addrem = []
|
149
wg-event-gen/src/controller.rs
Normal file
149
wg-event-gen/src/controller.rs
Normal 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 {}
|
||||||
|
}
|
||||||
|
}
|
274
wg-event-gen/src/gen.rs
Normal file
274
wg-event-gen/src/gen.rs
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
use crate::listener::*;
|
||||||
|
use crate::*;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::time;
|
||||||
|
|
||||||
|
pub(crate) fn gen_events(
|
||||||
|
state: &HashMap<ECCKey, Peer>,
|
||||||
|
prev: &HashMap<ECCKey, Peer>,
|
||||||
|
listeners: &Vec<Box<EventListener>>,
|
||||||
|
timeout: time::Duration,
|
||||||
|
poll_interval: time::Duration,
|
||||||
|
) {
|
||||||
|
let side_by_side = {
|
||||||
|
state
|
||||||
|
.keys()
|
||||||
|
.chain(prev.keys())
|
||||||
|
.collect::<HashSet<&ECCKey>>()
|
||||||
|
.iter()
|
||||||
|
.map(|p| (*p, (prev.get(*p), state.get(*p))))
|
||||||
|
.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 {
|
||||||
|
match (prev, cur) {
|
||||||
|
(Some(prev), Some(cur)) => {
|
||||||
|
if let (Some(prev_addr), Some(cur_addr)) = (prev.endpoint, cur.endpoint) {
|
||||||
|
if prev_addr != cur_addr {
|
||||||
|
listeners.fire(Event::Roamed(&cur, prev_addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let timedout_now = || !cur.last_handshake.is_some();
|
||||||
|
|
||||||
|
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 => {
|
||||||
|
println!("{:?}", fail);
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use crate::listener::*;
|
||||||
|
use crate::*;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::env;
|
||||||
|
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::{thread, time};
|
||||||
|
|
||||||
|
struct TestListener {
|
||||||
|
calls: Rc<RefCell<Vec<String>>>,
|
||||||
|
}
|
||||||
|
impl TestListener {
|
||||||
|
fn new() -> TestListener {
|
||||||
|
Self::from(Rc::new(RefCell::new(vec![])))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from(calls: Rc<RefCell<Vec<String>>>) -> TestListener {
|
||||||
|
TestListener { calls: calls }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl EventListener for TestListener {
|
||||||
|
fn added<'a>(&self, peer: &'a Peer) {
|
||||||
|
self.calls
|
||||||
|
.borrow_mut()
|
||||||
|
.push(format!("add {}", peer.key));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connected<'a>(&self, peer: &'a Peer) {
|
||||||
|
self.calls
|
||||||
|
.borrow_mut()
|
||||||
|
.push(format!("con {}", peer.key));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disconnected<'a>(&self, peer: &'a Peer) {
|
||||||
|
self.calls
|
||||||
|
.borrow_mut()
|
||||||
|
.push(format!("dis {}", peer.key));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn removed<'a>(&self, peer: &'a Peer) {
|
||||||
|
self.calls
|
||||||
|
.borrow_mut()
|
||||||
|
.push(format!("rem {}", peer.key));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn roaming<'a>(&self, peer: &'a Peer, _previous_addr: SocketAddr) {
|
||||||
|
self.calls
|
||||||
|
.borrow_mut()
|
||||||
|
.push(format!("rom {}", peer.key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn listeners() -> (Vec<Box<EventListener>>, Rc<RefCell<Vec<String>>>) {
|
||||||
|
let l = TestListener::new();
|
||||||
|
let calls = l.calls.clone();
|
||||||
|
(vec![Box::new(l)], calls)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_setup() {
|
||||||
|
let (listeners, calls) = listeners();
|
||||||
|
let peer = peer();
|
||||||
|
listeners.connected(&peer);
|
||||||
|
assert_eq!(
|
||||||
|
vec![["con", &peer.key].join(" ")],
|
||||||
|
calls.borrow().clone()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b2h(b: &str) -> String {
|
||||||
|
hex::encode(base64::decode(b).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn peer() -> Peer {
|
||||||
|
let bkey = "HhRgEL2xsnEIqThSTUKLGaTXusorM1MFdjSSYvzBynY=";
|
||||||
|
let key = b2h(bkey);
|
||||||
|
Peer::from_kv(&vec![
|
||||||
|
("key".to_string(), key.clone()),
|
||||||
|
/*(
|
||||||
|
"last_handshake_time_nsec".to_string(),
|
||||||
|
(1000 * 1000 * 1).to_string(),
|
||||||
|
),*/
|
||||||
|
("endpoint".to_string(), "1.1.1.1:22222".to_string()),
|
||||||
|
])
|
||||||
|
.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.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()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}*/
|
155
wg-event-gen/src/listener.rs
Normal file
155
wg-event-gen/src/listener.rs
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
use crate::Peer;
|
||||||
|
use number_prefix::{NumberPrefix, Prefixed, Standalone};
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
|
//#[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 {
|
||||||
|
fn name(&self) -> &'static str;
|
||||||
|
|
||||||
|
fn fire<'a>(&self, event: Event<'a>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventListener for Vec<Box<EventListener>> {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"List of Listeners"
|
||||||
|
}
|
||||||
|
fn fire<'a>(&self, event: Event<'a>) {
|
||||||
|
self.iter().for_each(|l| l.fire(event.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LogListener;
|
||||||
|
|
||||||
|
impl EventListener for LogListener {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"Log"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fire<'a>(&self, event: Event<'a>) {
|
||||||
|
match event {
|
||||||
|
Event::Connected(peer) => println!("{} connected!", peer.key),
|
||||||
|
Event::Disconnected(peer) => println!("{} disconnected!", peer.key),
|
||||||
|
Event::Added(peer) => println!("{} added!", peer.key),
|
||||||
|
Event::Removed(peer) => println!("{} removed!", peer.key),
|
||||||
|
Event::Roamed(peer, previous_addr) => println!(
|
||||||
|
"{} roamed {} -> {}!",
|
||||||
|
peer.key,
|
||||||
|
previous_addr,
|
||||||
|
peer.endpoint.unwrap()
|
||||||
|
),
|
||||||
|
Event::Transfered { peer, tx, rx } => {
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ScriptListener {
|
||||||
|
pub script: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScriptListener {
|
||||||
|
pub fn new(script: PathBuf) -> ScriptListener {
|
||||||
|
ScriptListener { script }
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
let mut cmd = Command::new("/bin/sh");
|
||||||
|
cmd.arg("-c");
|
||||||
|
cmd.arg(format!(
|
||||||
|
"{} {}",
|
||||||
|
(&self.script).to_str().unwrap(),
|
||||||
|
args.join(" ")
|
||||||
|
));
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_sub<'a>(&self, args: Vec<&'a str>) {
|
||||||
|
let mut cmd = self.mkcmd(args);
|
||||||
|
thread::spawn(move || {
|
||||||
|
cmd.spawn().expect("Failed to call Script hooḱ!");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventListener for ScriptListener {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"Script"
|
||||||
|
}
|
||||||
|
fn fire<'a>(&self, event: Event<'a>) {
|
||||||
|
match event {
|
||||||
|
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)]),
|
||||||
|
Event::Removed(peer) => self.call_sub(vec!["removed", &self.peer_props(peer)]),
|
||||||
|
Event::Roamed(peer, previous_addr) => self.call_sub(vec![
|
||||||
|
"roaming",
|
||||||
|
&self.peer_props(peer),
|
||||||
|
&previous_addr.to_string(),
|
||||||
|
]),
|
||||||
|
Event::Transfered { peer, tx, rx } => self.call_sub(vec![
|
||||||
|
"transfered",
|
||||||
|
&self.peer_props(peer),
|
||||||
|
&tx.to_string(),
|
||||||
|
&rx.to_string(),
|
||||||
|
]),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
84
wg-event-gen/src/main.rs
Normal file
84
wg-event-gen/src/main.rs
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate structopt;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate derive_builder;
|
||||||
|
|
||||||
|
mod controller;
|
||||||
|
mod gen;
|
||||||
|
mod listener;
|
||||||
|
mod model;
|
||||||
|
mod opts;
|
||||||
|
|
||||||
|
use crate::gen::gen_events;
|
||||||
|
use crate::listener::*;
|
||||||
|
use crate::model::{ECCKey, Peer};
|
||||||
|
use controller::Userspace;
|
||||||
|
use model::WireguardController;
|
||||||
|
use opts::Opts;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::error::Error;
|
||||||
|
use std::io;
|
||||||
|
use std::thread::sleep;
|
||||||
|
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
fn listeners(opts: &Opts) -> Vec<Box<EventListener>> {
|
||||||
|
let mut listeners: Vec<Box<EventListener>> = Vec::with_capacity(2);
|
||||||
|
if let Some(events) = opts.events.clone() {
|
||||||
|
listeners.push(Box::new(ScriptListener::new(events)))
|
||||||
|
}
|
||||||
|
if opts.log {
|
||||||
|
listeners.push(Box::new(LogListener));
|
||||||
|
}
|
||||||
|
println!("Enabled handlers: {}", (&listeners.iter().map(|l| l.name()).collect::<Vec<_>>()).join(", "));
|
||||||
|
listeners
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let opts = Opts::from_args();
|
||||||
|
let mut controller: Box<WireguardController> = Box::new(Userspace::new(opts.socket.clone()));
|
||||||
|
let interval = Duration::from_millis(opts.poll);
|
||||||
|
let timeout = Duration::from_secs(opts.timeout);
|
||||||
|
let listeners = listeners(&opts);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Polling {} every {:?}",
|
||||||
|
opts.socket.to_str().unwrap(),
|
||||||
|
interval
|
||||||
|
);
|
||||||
|
let mut peers_last: Option<HashMap<ECCKey, Peer>> = None;
|
||||||
|
loop {
|
||||||
|
let now = Instant::now();
|
||||||
|
let peers = match controller.peers() {
|
||||||
|
Err(ref err) if opts.ignore_socket_errors => {
|
||||||
|
eprintln!(
|
||||||
|
"Encountered error while querying Wireguard: {}",
|
||||||
|
err.description()
|
||||||
|
);
|
||||||
|
sleep(interval);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
res => res?,
|
||||||
|
};
|
||||||
|
let peers = peers
|
||||||
|
.map(|peer| peer.map(|peer_ok| (peer_ok.key.clone(), peer_ok)))
|
||||||
|
.collect::<io::Result<HashMap<_, _>>>()?;
|
||||||
|
|
||||||
|
if let Some(ref mut peers_last) = peers_last {
|
||||||
|
gen_events(&peers, &peers_last, &listeners, timeout, interval);
|
||||||
|
|
||||||
|
*peers_last = peers;
|
||||||
|
} else {
|
||||||
|
peers_last = Some(peers);
|
||||||
|
}
|
||||||
|
let pause = interval - now.elapsed();
|
||||||
|
|
||||||
|
sleep(if pause > interval / 2 {
|
||||||
|
pause
|
||||||
|
} else {
|
||||||
|
interval
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
247
wg-event-gen/src/model.rs
Normal file
247
wg-event-gen/src/model.rs
Normal 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
45
wg-event-gen/src/opts.rs
Normal 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
1
wg-event-gen/upload.sh
Executable 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'"
|
Submodule wireguard-go deleted from f49da8b7ad
@@ -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"
|
||||||
@@ -30,6 +32,9 @@ ExecStartPre=/bin/mkdir -p $ROOT_DIR
|
|||||||
ExecStart=/usr/bin/rkt --insecure-options=image run --uuid-file-save=${ROOT_DIR}/container.uuid --inherit-env --dns 8.8.8.8 --dns 9.9.9.9 --dns 1.1.1.1 \
|
ExecStart=/usr/bin/rkt --insecure-options=image run --uuid-file-save=${ROOT_DIR}/container.uuid --inherit-env --dns 8.8.8.8 --dns 9.9.9.9 --dns 1.1.1.1 \
|
||||||
--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
|
||||||
|
Reference in New Issue
Block a user