mirror of https://github.com/dswd/vpncloud.git
Compare commits
No commits in common. "66bef5cd21e2fb7f0d6f33ee0eb2299829a2eeb4" and "a3d0daa0f6666413efb0b9cc64a852adc931c08f" have entirely different histories.
66bef5cd21
...
a3d0daa0f6
|
@ -1,18 +1,6 @@
|
||||||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.148.1/containers/rust/.devcontainer/base.Dockerfile
|
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.148.1/containers/rust/.devcontainer/base.Dockerfile
|
||||||
|
|
||||||
FROM mcr.microsoft.com/vscode/devcontainers/rust:1
|
FROM mcr.microsoft.com/vscode/devcontainers/rust:0-1
|
||||||
|
|
||||||
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||||
&& apt-get -y install --no-install-recommends asciidoctor valgrind
|
&& apt-get -y install --no-install-recommends asciidoctor valgrind
|
||||||
|
|
||||||
RUN rm /etc/localtime && ln -s /usr/share/zoneinfo/Europe/Berlin /etc/localtime
|
|
||||||
|
|
||||||
RUN chown vscode: -R /usr/local/rustup /usr/local/cargo
|
|
||||||
|
|
||||||
USER vscode
|
|
||||||
|
|
||||||
RUN rustup default 1.51.0 \
|
|
||||||
&& rustup component add clippy rust-src rustfmt
|
|
||||||
|
|
||||||
RUN cargo install cargo-outdated cargo-cache \
|
|
||||||
&& cargo cache -a
|
|
||||||
|
|
|
@ -18,9 +18,6 @@ jobs:
|
||||||
name: Test Suite
|
name: Test Suite
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: szenius/set-timezone@v1.0
|
|
||||||
with:
|
|
||||||
timezoneLinux: Europe/Berlin
|
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -28,7 +28,6 @@ mkdir -p %{buildroot}/lib/systemd/system
|
||||||
mkdir -p %{buildroot}/usr/share/man/man1
|
mkdir -p %{buildroot}/usr/share/man/man1
|
||||||
cp %{buildroot}/../../../../../assets/example.net.disabled %{buildroot}/etc/vpncloud/example.net.disabled
|
cp %{buildroot}/../../../../../assets/example.net.disabled %{buildroot}/etc/vpncloud/example.net.disabled
|
||||||
cp %{buildroot}/../../../../../assets/vpncloud@.service %{buildroot}/lib/systemd/system/vpncloud@.service
|
cp %{buildroot}/../../../../../assets/vpncloud@.service %{buildroot}/lib/systemd/system/vpncloud@.service
|
||||||
cp %{buildroot}/../../../../../assets/vpncloud.target %{buildroot}/lib/systemd/system/vpncloud.target
|
|
||||||
cp %{buildroot}/../../../../../assets/vpncloud-wsproxy.service %{buildroot}/lib/systemd/system/vpncloud-wsproxy.service
|
cp %{buildroot}/../../../../../assets/vpncloud-wsproxy.service %{buildroot}/lib/systemd/system/vpncloud-wsproxy.service
|
||||||
cp %{buildroot}/../../../../../target/vpncloud.1.gz %{buildroot}/usr/share/man/man1/vpncloud.1.gz
|
cp %{buildroot}/../../../../../target/vpncloud.1.gz %{buildroot}/usr/share/man/man1/vpncloud.1.gz
|
||||||
cp -a * %{buildroot}
|
cp -a * %{buildroot}
|
||||||
|
@ -41,7 +40,6 @@ rm -rf %{buildroot}
|
||||||
/etc/vpncloud/example.net.disabled
|
/etc/vpncloud/example.net.disabled
|
||||||
/usr/bin/vpncloud
|
/usr/bin/vpncloud
|
||||||
/lib/systemd/system/vpncloud@.service
|
/lib/systemd/system/vpncloud@.service
|
||||||
/lib/systemd/system/vpncloud.target
|
|
||||||
/lib/systemd/system/vpncloud-wsproxy.service
|
/lib/systemd/system/vpncloud-wsproxy.service
|
||||||
/usr/share/man/man1/vpncloud.1.gz
|
/usr/share/man/man1/vpncloud.1.gz
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"scanSettings": {
|
||||||
|
"baseBranches": []
|
||||||
|
},
|
||||||
|
"checkRunSettings": {
|
||||||
|
"vulnerableCheckRunConclusionLevel": "failure",
|
||||||
|
"displayMode": "diff"
|
||||||
|
},
|
||||||
|
"issueSettings": {
|
||||||
|
"minSeverityLevel": "LOW"
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,15 +2,14 @@
|
||||||
|
|
||||||
This project follows [semantic versioning](http://semver.org).
|
This project follows [semantic versioning](http://semver.org).
|
||||||
|
|
||||||
### v2.2.0 (2021-04-06)
|
### UNRELEASED
|
||||||
|
|
||||||
- [added] Service target file (thanks to mnhauke)
|
|
||||||
- [added] Added interactive configuration wizard
|
- [added] Added interactive configuration wizard
|
||||||
- [added] Support for (un-)installation
|
- [added] Support for (un-)installation
|
||||||
- [added] Building static binaries
|
- [added] Building static binaries
|
||||||
- [added] Building i686 rpm
|
- [added] Building i686 rpm
|
||||||
- [changed] Restructured example config
|
- [changed] Restructured example config
|
||||||
- [changed] Changed Rust version to 1.51.0
|
- [changed] Changed Rust version to 1.50.0
|
||||||
- [changed] Updated dependencies
|
- [changed] Updated dependencies
|
||||||
- [changed] Change permissions of /etc/vpncloud
|
- [changed] Change permissions of /etc/vpncloud
|
||||||
|
|
||||||
|
|
|
@ -102,9 +102,9 @@ checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.4.3"
|
version = "1.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
|
@ -171,9 +171,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const_fn"
|
name = "const_fn"
|
||||||
version = "0.4.6"
|
version = "0.4.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "076a6803b0dacd6a88cfe64deba628b01533ff5ef265687e6938280c1afd0a28"
|
checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpuid-bool"
|
name = "cpuid-bool"
|
||||||
|
@ -240,33 +240,35 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-epoch"
|
name = "crossbeam-epoch"
|
||||||
version = "0.9.3"
|
version = "0.9.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12"
|
checksum = "d60ab4a8dba064f2fbb5aa270c28da5cf4bbd0e72dae1140a6b0353a779dbe00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"loom",
|
||||||
"memoffset",
|
"memoffset",
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.3"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49"
|
checksum = "bae8f328835f8f5a6ceb6a7842a7f2d0c03692adb5c889347235d59194731fe3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"loom",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "csv"
|
name = "csv"
|
||||||
version = "1.1.6"
|
version = "1.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
|
checksum = "f9d58633299b24b515ac72a3f869f8b91306a3cec616a602843a383acd6f9e97"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bstr",
|
"bstr",
|
||||||
"csv-core",
|
"csv-core",
|
||||||
|
@ -323,9 +325,9 @@ checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dtoa"
|
name = "dtoa"
|
||||||
version = "0.4.8"
|
version = "0.4.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
|
checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
|
@ -355,6 +357,19 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generator"
|
||||||
|
version = "0.6.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a9fed24fd1e18827652b4d55652899a1e9da8e54d91624dc3437a5bc3a9f9a9c"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"rustversion",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.4"
|
version = "0.14.4"
|
||||||
|
@ -491,9 +506,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.50"
|
version = "0.3.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c"
|
checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
@ -506,9 +521,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.93"
|
version = "0.2.86"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
|
checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linked-hash-map"
|
name = "linked-hash-map"
|
||||||
|
@ -534,6 +549,17 @@ dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "loom"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d44c73b4636e497b4917eb21c33539efa3816741a2d3ff26c6316f1b529481a4"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"generator",
|
||||||
|
"scoped-tls",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matches"
|
name = "matches"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
|
@ -548,9 +574,9 @@ checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memoffset"
|
name = "memoffset"
|
||||||
version = "0.6.3"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d"
|
checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
@ -633,9 +659,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.7.2"
|
version = "1.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
|
checksum = "4ad167a2f54e832b82dbe003a046280dceffe5227b5f79e08e363a29638cfddd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oorandom"
|
name = "oorandom"
|
||||||
|
@ -762,9 +788,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.26"
|
version = "1.0.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
@ -854,9 +880,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.4.5"
|
version = "1.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19"
|
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
@ -872,9 +898,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.6.23"
|
version = "0.6.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
|
checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "remove_dir_all"
|
name = "remove_dir_all"
|
||||||
|
@ -909,6 +935,12 @@ dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
|
@ -924,6 +956,12 @@ dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scoped-tls"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -947,9 +985,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.125"
|
version = "1.0.123"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
|
checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
@ -966,9 +1004,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.125"
|
version = "1.0.123"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
|
checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -977,9 +1015,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.64"
|
version = "1.0.62"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
|
checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
|
@ -1061,9 +1099,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "standback"
|
name = "standback"
|
||||||
version = "0.2.17"
|
version = "0.2.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff"
|
checksum = "a2beb4d1860a61f571530b3f855a1b538d0200f7871c63331ecd6f17b1f014f8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
@ -1149,9 +1187,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.68"
|
version = "1.0.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87"
|
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1251,9 +1289,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinytemplate"
|
name = "tinytemplate"
|
||||||
version = "1.2.1"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
|
checksum = "a2ada8616fad06a2d0c455adc530de4ef57605a8120cc65da9653e0e9623ca74"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -1261,9 +1299,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
version = "1.2.0"
|
version = "1.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342"
|
checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tinyvec_macros",
|
"tinyvec_macros",
|
||||||
]
|
]
|
||||||
|
@ -1327,9 +1365,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.13.0"
|
version = "1.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
|
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
|
@ -1399,9 +1437,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.3"
|
version = "0.9.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "void"
|
name = "void"
|
||||||
|
@ -1411,7 +1449,7 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vpncloud"
|
name = "vpncloud"
|
||||||
version = "2.2.0"
|
version = "2.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
@ -1443,9 +1481,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.3.2"
|
version = "2.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
|
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"same-file",
|
"same-file",
|
||||||
"winapi",
|
"winapi",
|
||||||
|
@ -1460,9 +1498,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.73"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9"
|
checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
|
@ -1470,9 +1508,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.73"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae"
|
checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
@ -1485,9 +1523,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.73"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f"
|
checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
|
@ -1495,9 +1533,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.73"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c"
|
checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1508,15 +1546,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.73"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489"
|
checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.50"
|
version = "0.3.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be"
|
checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
@ -1524,9 +1562,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wildmatch"
|
name = "wildmatch"
|
||||||
version = "1.1.0"
|
version = "1.0.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f44b95f62d34113cf558c93511ac93027e03e9c29a60dd0fd70e6e025c7270a"
|
checksum = "d2399814fda0d6999a6bfe9b5c7660d836334deb162a09db8b73d5b38fd8c40a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "vpncloud"
|
name = "vpncloud"
|
||||||
version = "2.2.0"
|
version = "2.1.0"
|
||||||
authors = ["Dennis Schwerdel <schwerdel@googlemail.com>"]
|
authors = ["Dennis Schwerdel <schwerdel@googlemail.com>"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
|
@ -12,7 +12,7 @@ readme = "README.md"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
toolchain = "1.51.0"
|
toolchain = "1.50.0"
|
||||||
upx_version = "3.96"
|
upx_version = "3.96"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -86,7 +86,6 @@ assets = [
|
||||||
["target/release/vpncloud", "/usr/bin/vpncloud", "755"],
|
["target/release/vpncloud", "/usr/bin/vpncloud", "755"],
|
||||||
["assets/example.net.disabled", "/etc/vpncloud/example.net.disabled", "600"],
|
["assets/example.net.disabled", "/etc/vpncloud/example.net.disabled", "600"],
|
||||||
["assets/vpncloud@.service", "/lib/systemd/system/vpncloud@.service", "644"],
|
["assets/vpncloud@.service", "/lib/systemd/system/vpncloud@.service", "644"],
|
||||||
["assets/vpncloud.target", "/lib/systemd/system/vpncloud.target", "644"],
|
|
||||||
["assets/vpncloud-wsproxy.service", "/lib/systemd/system/vpncloud-wsproxy.service", "644"],
|
["assets/vpncloud-wsproxy.service", "/lib/systemd/system/vpncloud-wsproxy.service", "644"],
|
||||||
["target/vpncloud.1.gz", "/usr/share/man/man1/vpncloud.1.gz", "644"]
|
["target/vpncloud.1.gz", "/usr/share/man/man1/vpncloud.1.gz", "644"]
|
||||||
]
|
]
|
||||||
|
|
|
@ -19,7 +19,7 @@ peers:
|
||||||
- REMOTE_HOST:PORT
|
- REMOTE_HOST:PORT
|
||||||
```
|
```
|
||||||
|
|
||||||
For more information, please see the [Website](https://vpncloud.ddswd.de) or the [Discussions group](https://github.com/dswd/vpncloud/discussions).
|
For more information, please see the [Website](https://vpncloud.ddswd.de) or the [Forum](https://groups.google.com/forum/#!forum/vpncloud).
|
||||||
|
|
||||||
|
|
||||||
### Project Status
|
### Project Status
|
||||||
|
|
|
@ -1,17 +1,3 @@
|
||||||
vpncloud (2.2.0) stable; urgency=medium
|
|
||||||
|
|
||||||
* [added] Service target file (thanks to mnhauke)
|
|
||||||
* [added] Added interactive configuration wizard
|
|
||||||
* [added] Support for (un-)installation
|
|
||||||
* [added] Building static binaries
|
|
||||||
* [added] Building i686 rpm
|
|
||||||
* [changed] Restructured example config
|
|
||||||
* [changed] Changed Rust version to 1.51.0
|
|
||||||
* [changed] Updated dependencies
|
|
||||||
* [changed] Change permissions of /etc/vpncloud
|
|
||||||
|
|
||||||
-- Dennis Schwerdel <schwerdel+vpncloud@googlemail.com> Tue, 06 Apr 2021 12:27:00 +0200
|
|
||||||
|
|
||||||
vpncloud (2.1.0) stable; urgency=medium
|
vpncloud (2.1.0) stable; urgency=medium
|
||||||
|
|
||||||
* [added] Support for websocket proxy mode
|
* [added] Support for websocket proxy mode
|
||||||
|
@ -23,7 +9,7 @@ vpncloud (2.1.0) stable; urgency=medium
|
||||||
* [fixed] Added missing peer address propagation
|
* [fixed] Added missing peer address propagation
|
||||||
* [fixed] Fixed problem with peer addresses without port
|
* [fixed] Fixed problem with peer addresses without port
|
||||||
|
|
||||||
-- Dennis Schwerdel <schwerdel@googlemail.com> Sat, 06 Feb 2021 13:13:00 +0100
|
-- Dennis Schwerdel <schwerdel@googlemail.com> Sat, 06 Feb 2020 13:13:00 +0100
|
||||||
|
|
||||||
vpncloud (2.0.1) stable; urgency=medium
|
vpncloud (2.0.1) stable; urgency=medium
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[Unit]
|
|
||||||
Description=VpnCloud target allowing to start/stop all vpncloud@.service instances at once
|
|
|
@ -2,7 +2,6 @@
|
||||||
Description=VpnCloud network '%I'
|
Description=VpnCloud network '%I'
|
||||||
After=network-online.target
|
After=network-online.target
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
PartOf=vpncloud.target
|
|
||||||
Documentation=man:vpncloud(1)
|
Documentation=man:vpncloud(1)
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
FROM ubuntu
|
FROM ubuntu
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y asciinema locales bash iputils-ping
|
RUN apt-get update && apt-get install -y asciinema
|
||||||
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
|
|
||||||
ENV LANG en_US.UTF-8
|
|
||||||
ENV LANGUAGE en_US:en
|
|
||||||
ENV LC_ALL en_US.UTF-8
|
|
||||||
RUN mkdir /root/.asciinema
|
RUN mkdir /root/.asciinema
|
||||||
RUN mkdir /etc/vpncloud
|
RUN mkdir /etc/vpncloud
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[record]
|
[record]
|
||||||
command = bash -l
|
command = /usr/bin/bash -l
|
||||||
idle_time_limit = 2.5
|
idle_time_limit = 2.5
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
docker build -t asciinema-recorder .
|
||||||
|
docker run -it --rm --network host -v $(pwd)/../../target/release/:/usr/local/bin/ -v $(pwd):/data asciinema-recorder asciinema "$@"
|
|
@ -1,11 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
cd $(dirname $0)
|
|
||||||
|
|
||||||
docker build -t asciinema-recorder .
|
|
||||||
docker run -it --rm --network host \
|
|
||||||
-v $(pwd):/data \
|
|
||||||
-v /etc/hosts:/etc/hosts \
|
|
||||||
asciinema-recorder
|
|
|
@ -1,165 +0,0 @@
|
||||||
{
|
|
||||||
"meta": {
|
|
||||||
"region": "eu-central-1",
|
|
||||||
"instance_type": "m5.large",
|
|
||||||
"ami": "ami-0db9040eb3ab74509",
|
|
||||||
"version": "2.2.0",
|
|
||||||
"duration": 623.0307722091675
|
|
||||||
},
|
|
||||||
"native": {
|
|
||||||
"iperf": {
|
|
||||||
"throughput": 9680235000.0,
|
|
||||||
"cpu_sender": 12.015535,
|
|
||||||
"cpu_receiver": 71.982452
|
|
||||||
},
|
|
||||||
"ping_100": {
|
|
||||||
"rtt_min": 0.049,
|
|
||||||
"rtt_max": 0.219,
|
|
||||||
"rtt_avg": 0.058,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_500": {
|
|
||||||
"rtt_min": 0.053,
|
|
||||||
"rtt_max": 0.247,
|
|
||||||
"rtt_avg": 0.059,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_1000": {
|
|
||||||
"rtt_min": 0.053,
|
|
||||||
"rtt_max": 0.189,
|
|
||||||
"rtt_avg": 0.06,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"plain": {
|
|
||||||
"iperf": {
|
|
||||||
"throughput": 5790600000.0,
|
|
||||||
"cpu_sender": 14.109763,
|
|
||||||
"cpu_receiver": 69.727033
|
|
||||||
},
|
|
||||||
"ping_100": {
|
|
||||||
"rtt_min": 0.079,
|
|
||||||
"rtt_max": 0.291,
|
|
||||||
"rtt_avg": 0.094,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_500": {
|
|
||||||
"rtt_min": 0.079,
|
|
||||||
"rtt_max": 0.304,
|
|
||||||
"rtt_avg": 0.096,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_1000": {
|
|
||||||
"rtt_min": 0.082,
|
|
||||||
"rtt_max": 0.367,
|
|
||||||
"rtt_avg": 0.097,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"aes256": {
|
|
||||||
"iperf": {
|
|
||||||
"throughput": 3917767000.0,
|
|
||||||
"cpu_sender": 6.439156,
|
|
||||||
"cpu_receiver": 64.267206
|
|
||||||
},
|
|
||||||
"ping_100": {
|
|
||||||
"rtt_min": 0.081,
|
|
||||||
"rtt_max": 0.206,
|
|
||||||
"rtt_avg": 0.097,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_500": {
|
|
||||||
"rtt_min": 0.088,
|
|
||||||
"rtt_max": 0.206,
|
|
||||||
"rtt_avg": 0.1,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_1000": {
|
|
||||||
"rtt_min": 0.089,
|
|
||||||
"rtt_max": 0.319,
|
|
||||||
"rtt_avg": 0.103,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"aes128": {
|
|
||||||
"iperf": {
|
|
||||||
"throughput": 3697142000.0,
|
|
||||||
"cpu_sender": 7.417808,
|
|
||||||
"cpu_receiver": 59.433831
|
|
||||||
},
|
|
||||||
"ping_100": {
|
|
||||||
"rtt_min": 0.083,
|
|
||||||
"rtt_max": 0.265,
|
|
||||||
"rtt_avg": 0.097,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_500": {
|
|
||||||
"rtt_min": 0.081,
|
|
||||||
"rtt_max": 0.369,
|
|
||||||
"rtt_avg": 0.102,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_1000": {
|
|
||||||
"rtt_min": 0.086,
|
|
||||||
"rtt_max": 0.448,
|
|
||||||
"rtt_avg": 0.102,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"chacha20": {
|
|
||||||
"iperf": {
|
|
||||||
"throughput": 3194412000.0,
|
|
||||||
"cpu_sender": 6.12856,
|
|
||||||
"cpu_receiver": 61.223349
|
|
||||||
},
|
|
||||||
"ping_100": {
|
|
||||||
"rtt_min": 0.081,
|
|
||||||
"rtt_max": 0.28,
|
|
||||||
"rtt_avg": 0.098,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_500": {
|
|
||||||
"rtt_min": 0.088,
|
|
||||||
"rtt_max": 0.264,
|
|
||||||
"rtt_avg": 0.103,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
},
|
|
||||||
"ping_1000": {
|
|
||||||
"rtt_min": 0.092,
|
|
||||||
"rtt_max": 0.204,
|
|
||||||
"rtt_avg": 0.106,
|
|
||||||
"pkt_loss": 0.0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"results": {
|
|
||||||
"throughput_mbits": {
|
|
||||||
"native": 9680.235,
|
|
||||||
"plain": 5790.6,
|
|
||||||
"aes256": 3917.767,
|
|
||||||
"aes128": 3697.142,
|
|
||||||
"chacha20": 3194.412
|
|
||||||
},
|
|
||||||
"latency_us": {
|
|
||||||
"plain": {
|
|
||||||
"100": 18.0,
|
|
||||||
"500": 18.500000000000004,
|
|
||||||
"1000": 18.500000000000004
|
|
||||||
},
|
|
||||||
"aes256": {
|
|
||||||
"100": 19.5,
|
|
||||||
"500": 20.500000000000004,
|
|
||||||
"1000": 21.5
|
|
||||||
},
|
|
||||||
"aes128": {
|
|
||||||
"100": 19.5,
|
|
||||||
"500": 21.5,
|
|
||||||
"1000": 20.999999999999996
|
|
||||||
},
|
|
||||||
"chacha20": {
|
|
||||||
"100": 20.0,
|
|
||||||
"500": 22.0,
|
|
||||||
"1000": 23.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,8 +7,8 @@ from datetime import date
|
||||||
|
|
||||||
# Note: this script will run for ~8 minutes and incur costs of about $ 0.02
|
# Note: this script will run for ~8 minutes and incur costs of about $ 0.02
|
||||||
|
|
||||||
FILE = "../../target/release/vpncloud"
|
FILE = "../target/release/vpncloud"
|
||||||
VERSION = "2.2.0"
|
VERSION = "2.1.0"
|
||||||
REGION = "eu-central-1"
|
REGION = "eu-central-1"
|
||||||
|
|
||||||
env = EC2Environment(
|
env = EC2Environment(
|
||||||
|
|
|
@ -15,15 +15,16 @@ use std::{
|
||||||
process::{Command, Stdio},
|
process::{Command, Stdio},
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
Arc, Mutex,
|
Arc, Mutex
|
||||||
},
|
},
|
||||||
thread,
|
thread
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::util::{from_base62, to_base62, Encoder, TimeSource};
|
use super::util::{from_base62, to_base62, Encoder, TimeSource};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||||
|
|
||||||
|
|
||||||
const TYPE_BEGIN: u8 = 0;
|
const TYPE_BEGIN: u8 = 0;
|
||||||
const TYPE_END: u8 = 1;
|
const TYPE_END: u8 = 1;
|
||||||
const TYPE_DATA: u8 = 2;
|
const TYPE_DATA: u8 = 2;
|
||||||
|
@ -39,14 +40,14 @@ fn sha512(data: &[u8]) -> SmallVec<[u8; 64]> {
|
||||||
|
|
||||||
struct FutureResult<T> {
|
struct FutureResult<T> {
|
||||||
has_result: AtomicBool,
|
has_result: AtomicBool,
|
||||||
result: Mutex<T>,
|
result: Mutex<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BeaconSerializer<TS> {
|
pub struct BeaconSerializer<TS> {
|
||||||
shared_key: Vec<u8>,
|
shared_key: Vec<u8>,
|
||||||
future_peers: Arc<FutureResult<Vec<SocketAddr>>>,
|
future_peers: Arc<FutureResult<Vec<SocketAddr>>>,
|
||||||
_dummy_ts: PhantomData<TS>,
|
_dummy_ts: PhantomData<TS>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TS: TimeSource> BeaconSerializer<TS> {
|
impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
|
@ -54,7 +55,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
Self {
|
Self {
|
||||||
shared_key: shared_key.to_owned(),
|
shared_key: shared_key.to_owned(),
|
||||||
future_peers: Arc::new(FutureResult { has_result: AtomicBool::new(false), result: Mutex::new(Vec::new()) }),
|
future_peers: Arc::new(FutureResult { has_result: AtomicBool::new(false), result: Mutex::new(Vec::new()) }),
|
||||||
_dummy_ts: PhantomData,
|
_dummy_ts: PhantomData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +105,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
|
|
||||||
fn decrypt_data(&self, data: &mut Vec<u8>) -> bool {
|
fn decrypt_data(&self, data: &mut Vec<u8>) -> bool {
|
||||||
if data.is_empty() {
|
if data.is_empty() {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
let seed = data.pop().unwrap() ^ self.get_keystream(TYPE_SEED, 0, 0)[0];
|
let seed = data.pop().unwrap() ^ self.get_keystream(TYPE_SEED, 0, 0)[0];
|
||||||
self.mask_with_keystream(data as &mut [u8], TYPE_DATA, seed);
|
self.mask_with_keystream(data as &mut [u8], TYPE_DATA, seed);
|
||||||
|
@ -121,7 +122,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
for p in peers {
|
for p in peers {
|
||||||
match *p {
|
match *p {
|
||||||
SocketAddr::V4(addr) => v4addrs.push(addr),
|
SocketAddr::V4(addr) => v4addrs.push(addr),
|
||||||
SocketAddr::V6(addr) => v6addrs.push(addr),
|
SocketAddr::V6(addr) => v6addrs.push(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add count of v4 addresses
|
// Add count of v4 addresses
|
||||||
|
@ -157,23 +158,23 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
let mut peers = Vec::new();
|
let mut peers = Vec::new();
|
||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
if data.len() < 4 {
|
if data.len() < 4 {
|
||||||
return peers;
|
return peers
|
||||||
}
|
}
|
||||||
if !self.decrypt_data(&mut data) {
|
if !self.decrypt_data(&mut data) {
|
||||||
return peers;
|
return peers
|
||||||
}
|
}
|
||||||
let then = Wrapping(Encoder::read_u16(&data[pos..=pos + 1]));
|
let then = Wrapping(Encoder::read_u16(&data[pos..=pos + 1]));
|
||||||
if let Some(ttl) = ttl_hours {
|
if let Some(ttl) = ttl_hours {
|
||||||
let now = Wrapping(Self::now_hour_16());
|
let now = Wrapping(Self::now_hour_16());
|
||||||
if now - then > Wrapping(ttl) && then - now > Wrapping(ttl) {
|
if now - then > Wrapping(ttl) && then - now > Wrapping(ttl) {
|
||||||
return peers;
|
return peers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pos += 2;
|
pos += 2;
|
||||||
let v4count = data[pos] as usize;
|
let v4count = data[pos] as usize;
|
||||||
pos += 1;
|
pos += 1;
|
||||||
if v4count * 6 > data.len() - pos || (data.len() - pos - v4count * 6) % 18 > 0 {
|
if v4count * 6 > data.len() - pos || (data.len() - pos - v4count * 6) % 18 > 0 {
|
||||||
return peers;
|
return peers
|
||||||
}
|
}
|
||||||
for _ in 0..v4count {
|
for _ in 0..v4count {
|
||||||
assert!(data.len() >= pos + 6);
|
assert!(data.len() >= pos + 6);
|
||||||
|
@ -197,7 +198,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
Ipv6Addr::new(ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]),
|
Ipv6Addr::new(ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]),
|
||||||
port,
|
port,
|
||||||
0,
|
0,
|
||||||
0,
|
0
|
||||||
));
|
));
|
||||||
peers.push(addr);
|
peers.push(addr);
|
||||||
}
|
}
|
||||||
|
@ -261,14 +262,14 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
peers.append(&mut self.peerlist_decode(&data[start_pos..end_pos], ttl_hours));
|
peers.append(&mut self.peerlist_decode(&data[start_pos..end_pos], ttl_hours));
|
||||||
pos = start_pos
|
pos = start_pos
|
||||||
} else {
|
} else {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
peers
|
peers
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_from_file<P: AsRef<Path>>(
|
pub fn read_from_file<P: AsRef<Path>>(
|
||||||
&self, path: P, ttl_hours: Option<u16>,
|
&self, path: P, ttl_hours: Option<u16>
|
||||||
) -> Result<Vec<SocketAddr>, io::Error> {
|
) -> Result<Vec<SocketAddr>, io::Error> {
|
||||||
let mut f = File::open(&path)?;
|
let mut f = File::open(&path)?;
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
|
@ -315,22 +316,26 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
use crate::util::MockTimeSource;
|
#[cfg(test)] use crate::util::MockTimeSource;
|
||||||
#[cfg(test)]
|
#[cfg(test)] use std::str::FromStr;
|
||||||
use std::str::FromStr;
|
#[cfg(test)] use std::time::Duration;
|
||||||
#[cfg(test)]
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
async fn encode() {
|
async fn encode() {
|
||||||
MockTimeSource::set_time(2000 * 3600);
|
MockTimeSource::set_time(2000 * 3600);
|
||||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||||
let mut peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
let mut peers = vec![
|
||||||
|
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||||
|
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||||
|
];
|
||||||
assert_eq!("WsHI31EWDMBYxvITiILIrm2k9gEik22E", ser.encode(&peers));
|
assert_eq!("WsHI31EWDMBYxvITiILIrm2k9gEik22E", ser.encode(&peers));
|
||||||
peers.push(SocketAddr::from_str("[::1]:5678").unwrap());
|
peers.push(SocketAddr::from_str("[::1]:5678").unwrap());
|
||||||
assert_eq!("WsHI3GXKaXCveo6uejmZizZ72kR6Y0L9T7h49TXONp1ugfKvvvEik22E", ser.encode(&peers));
|
assert_eq!("WsHI3GXKaXCveo6uejmZizZ72kR6Y0L9T7h49TXONp1ugfKvvvEik22E", ser.encode(&peers));
|
||||||
let peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:54").unwrap()];
|
let peers = vec![
|
||||||
|
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||||
|
SocketAddr::from_str("6.6.6.6:54").unwrap()
|
||||||
|
];
|
||||||
assert_eq!("WsHI32gm9eMSHP3Lm1GXcdP7rD3ik22E", ser.encode(&peers));
|
assert_eq!("WsHI32gm9eMSHP3Lm1GXcdP7rD3ik22E", ser.encode(&peers));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +343,10 @@ async fn encode() {
|
||||||
async fn decode() {
|
async fn decode() {
|
||||||
MockTimeSource::set_time(2000 * 3600);
|
MockTimeSource::set_time(2000 * 3600);
|
||||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||||
let mut peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
let mut peers = vec![
|
||||||
|
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||||
|
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||||
|
];
|
||||||
assert_eq!(format!("{:?}", peers), format!("{:?}", ser.decode("WsHI31EWDMBYxvITiILIrm2k9gEik22E", None)));
|
assert_eq!(format!("{:?}", peers), format!("{:?}", ser.decode("WsHI31EWDMBYxvITiILIrm2k9gEik22E", None)));
|
||||||
peers.push(SocketAddr::from_str("[::1]:5678").unwrap());
|
peers.push(SocketAddr::from_str("[::1]:5678").unwrap());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -351,7 +359,10 @@ async fn decode() {
|
||||||
async fn decode_split() {
|
async fn decode_split() {
|
||||||
MockTimeSource::set_time(2000 * 3600);
|
MockTimeSource::set_time(2000 * 3600);
|
||||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||||
let peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
let peers = vec![
|
||||||
|
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||||
|
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||||
|
];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:?}", peers),
|
format!("{:?}", peers),
|
||||||
format!("{:?}", ser.decode("WsHI3-1E.WD:MB Yx\tvI\nTi(IL)Ir[m2]k9ügEäik22E", None))
|
format!("{:?}", ser.decode("WsHI3-1E.WD:MB Yx\tvI\nTi(IL)Ir[m2]k9ügEäik22E", None))
|
||||||
|
@ -366,7 +377,10 @@ async fn decode_split() {
|
||||||
async fn decode_offset() {
|
async fn decode_offset() {
|
||||||
MockTimeSource::set_time(2000 * 3600);
|
MockTimeSource::set_time(2000 * 3600);
|
||||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||||
let peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
let peers = vec![
|
||||||
|
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||||
|
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||||
|
];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:?}", peers),
|
format!("{:?}", peers),
|
||||||
format!("{:?}", ser.decode("Hello World: WsHI31EWDMBYxvITiILIrm2k9gEik22E! End of the World", None))
|
format!("{:?}", ser.decode("Hello World: WsHI31EWDMBYxvITiILIrm2k9gEik22E! End of the World", None))
|
||||||
|
@ -377,7 +391,10 @@ async fn decode_offset() {
|
||||||
async fn decode_multiple() {
|
async fn decode_multiple() {
|
||||||
MockTimeSource::set_time(2000 * 3600);
|
MockTimeSource::set_time(2000 * 3600);
|
||||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||||
let peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
let peers = vec![
|
||||||
|
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||||
|
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||||
|
];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{:?}", peers),
|
format!("{:?}", peers),
|
||||||
format!("{:?}", ser.decode("WsHI31HVpqxFNMNSPrvik22E WsHI34yOBcZIulKdtn2ik22E", None))
|
format!("{:?}", ser.decode("WsHI31HVpqxFNMNSPrvik22E WsHI34yOBcZIulKdtn2ik22E", None))
|
||||||
|
@ -421,11 +438,15 @@ async fn decode_invalid() {
|
||||||
assert_eq!(2, ser.decode("WsHI3WsHI31EWDMBYxvITiILIrm2k9gEik22Eik22E", None).len());
|
assert_eq!(2, ser.decode("WsHI3WsHI31EWDMBYxvITiILIrm2k9gEik22Eik22E", None).len());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
async fn encode_decode() {
|
async fn encode_decode() {
|
||||||
MockTimeSource::set_time(2000 * 3600);
|
MockTimeSource::set_time(2000 * 3600);
|
||||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||||
let peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
let peers = vec![
|
||||||
|
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||||
|
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||||
|
];
|
||||||
let data = ser.encode(&peers);
|
let data = ser.encode(&peers);
|
||||||
let peers2 = ser.decode(&data, None);
|
let peers2 = ser.decode(&data, None);
|
||||||
assert_eq!(format!("{:?}", peers), format!("{:?}", peers2));
|
assert_eq!(format!("{:?}", peers), format!("{:?}", peers2));
|
||||||
|
@ -435,7 +456,10 @@ async fn encode_decode() {
|
||||||
async fn encode_decode_file() {
|
async fn encode_decode_file() {
|
||||||
MockTimeSource::set_time(2000 * 3600);
|
MockTimeSource::set_time(2000 * 3600);
|
||||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||||
let peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
let peers = vec![
|
||||||
|
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||||
|
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||||
|
];
|
||||||
let file = tempfile::NamedTempFile::new().expect("Failed to create temp file");
|
let file = tempfile::NamedTempFile::new().expect("Failed to create temp file");
|
||||||
assert!(ser.write_to_file(&peers, file.path()).is_ok());
|
assert!(ser.write_to_file(&peers, file.path()).is_ok());
|
||||||
let peers2 = ser.read_from_file(file.path(), None);
|
let peers2 = ser.read_from_file(file.path(), None);
|
||||||
|
@ -447,7 +471,10 @@ async fn encode_decode_file() {
|
||||||
async fn encode_decode_cmd() {
|
async fn encode_decode_cmd() {
|
||||||
MockTimeSource::set_time(2000 * 3600);
|
MockTimeSource::set_time(2000 * 3600);
|
||||||
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
let ser = BeaconSerializer::<MockTimeSource>::new(b"mysecretkey");
|
||||||
let peers = vec![SocketAddr::from_str("1.2.3.4:5678").unwrap(), SocketAddr::from_str("6.6.6.6:53").unwrap()];
|
let peers = vec![
|
||||||
|
SocketAddr::from_str("1.2.3.4:5678").unwrap(),
|
||||||
|
SocketAddr::from_str("6.6.6.6:53").unwrap()
|
||||||
|
];
|
||||||
let file = tempfile::NamedTempFile::new().expect("Failed to create temp file");
|
let file = tempfile::NamedTempFile::new().expect("Failed to create temp file");
|
||||||
assert!(ser.write_to_cmd(&peers, &format!("echo $beacon > {}", file.path().display())).is_ok());
|
assert!(ser.write_to_cmd(&peers, &format!("echo $beacon > {}", file.path().display())).is_ok());
|
||||||
thread::sleep(Duration::from_millis(100));
|
thread::sleep(Duration::from_millis(100));
|
||||||
|
|
|
@ -2,15 +2,22 @@
|
||||||
// Copyright (C) 2015-2021 Dennis Schwerdel
|
// Copyright (C) 2015-2021 Dennis Schwerdel
|
||||||
// This software is licensed under GPL-3 or newer (see LICENSE.md)
|
// This software is licensed under GPL-3 or newer (see LICENSE.md)
|
||||||
|
|
||||||
use super::{device::Type, types::Mode, util::run_cmd, util::Duration};
|
use super::{device::Type, types::Mode, util::Duration, util::run_cmd};
|
||||||
pub use crate::crypto::Config as CryptoConfig;
|
pub use crate::crypto::Config as CryptoConfig;
|
||||||
|
|
||||||
use std::{cmp::max, collections::HashMap, ffi::OsStr, process, thread};
|
use std::{
|
||||||
|
cmp::max,
|
||||||
|
collections::HashMap,
|
||||||
|
ffi::OsStr,
|
||||||
|
process,
|
||||||
|
thread
|
||||||
|
};
|
||||||
use structopt::{clap::Shell, StructOpt};
|
use structopt::{clap::Shell, StructOpt};
|
||||||
|
|
||||||
pub const DEFAULT_PEER_TIMEOUT: u16 = 300;
|
pub const DEFAULT_PEER_TIMEOUT: u16 = 300;
|
||||||
pub const DEFAULT_PORT: u16 = 3210;
|
pub const DEFAULT_PORT: u16 = 3210;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, PartialEq, Clone)]
|
#[derive(Deserialize, Debug, PartialEq, Clone)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub device_type: Type,
|
pub device_type: Type,
|
||||||
|
@ -20,7 +27,6 @@ pub struct Config {
|
||||||
pub fix_rp_filter: bool,
|
pub fix_rp_filter: bool,
|
||||||
|
|
||||||
pub ip: Option<String>,
|
pub ip: Option<String>,
|
||||||
pub advertise_addresses: Vec<String>,
|
|
||||||
pub ifup: Option<String>,
|
pub ifup: Option<String>,
|
||||||
pub ifdown: Option<String>,
|
pub ifdown: Option<String>,
|
||||||
|
|
||||||
|
@ -47,7 +53,7 @@ pub struct Config {
|
||||||
pub user: Option<String>,
|
pub user: Option<String>,
|
||||||
pub group: Option<String>,
|
pub group: Option<String>,
|
||||||
pub hook: Option<String>,
|
pub hook: Option<String>,
|
||||||
pub hooks: HashMap<String, String>,
|
pub hooks: HashMap<String, String>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
|
@ -59,7 +65,6 @@ impl Default for Config {
|
||||||
device_mtu: None,
|
device_mtu: None,
|
||||||
fix_rp_filter: false,
|
fix_rp_filter: false,
|
||||||
ip: None,
|
ip: None,
|
||||||
advertise_addresses: vec![],
|
|
||||||
ifup: None,
|
ifup: None,
|
||||||
ifdown: None,
|
ifdown: None,
|
||||||
crypto: CryptoConfig::default(),
|
crypto: CryptoConfig::default(),
|
||||||
|
@ -84,7 +89,7 @@ impl Default for Config {
|
||||||
user: None,
|
user: None,
|
||||||
group: None,
|
group: None,
|
||||||
hook: None,
|
hook: None,
|
||||||
hooks: HashMap::new(),
|
hooks: HashMap::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,9 +117,6 @@ impl Config {
|
||||||
if let Some(val) = file.ip {
|
if let Some(val) = file.ip {
|
||||||
self.ip = Some(val);
|
self.ip = Some(val);
|
||||||
}
|
}
|
||||||
if let Some(mut val) = file.advertise_addresses {
|
|
||||||
self.advertise_addresses.append(&mut val);
|
|
||||||
}
|
|
||||||
if let Some(val) = file.ifup {
|
if let Some(val) = file.ifup {
|
||||||
self.ifup = Some(val);
|
self.ifup = Some(val);
|
||||||
}
|
}
|
||||||
|
@ -225,7 +227,6 @@ impl Config {
|
||||||
if let Some(val) = args.ifup {
|
if let Some(val) = args.ifup {
|
||||||
self.ifup = Some(val);
|
self.ifup = Some(val);
|
||||||
}
|
}
|
||||||
self.advertise_addresses.append(&mut args.advertise_addresses);
|
|
||||||
if let Some(val) = args.ifdown {
|
if let Some(val) = args.ifdown {
|
||||||
self.ifdown = Some(val);
|
self.ifdown = Some(val);
|
||||||
}
|
}
|
||||||
|
@ -302,7 +303,7 @@ impl Config {
|
||||||
if s.contains(':') {
|
if s.contains(':') {
|
||||||
let pos = s.find(':').unwrap();
|
let pos = s.find(':').unwrap();
|
||||||
let name = &s[..pos];
|
let name = &s[..pos];
|
||||||
let hook = &s[pos + 1..];
|
let hook = &s[pos+1..];
|
||||||
self.hooks.insert(name.to_string(), hook.to_string());
|
self.hooks.insert(name.to_string(), hook.to_string());
|
||||||
} else {
|
} else {
|
||||||
self.hook = Some(s);
|
self.hook = Some(s);
|
||||||
|
@ -318,14 +319,14 @@ impl Config {
|
||||||
store: self.beacon_store,
|
store: self.beacon_store,
|
||||||
load: self.beacon_load,
|
load: self.beacon_load,
|
||||||
interval: Some(self.beacon_interval),
|
interval: Some(self.beacon_interval),
|
||||||
password: self.beacon_password,
|
password: self.beacon_password
|
||||||
}),
|
}),
|
||||||
device: Some(ConfigFileDevice {
|
device: Some(ConfigFileDevice {
|
||||||
name: Some(self.device_name),
|
name: Some(self.device_name),
|
||||||
path: self.device_path,
|
path: self.device_path,
|
||||||
mtu: self.device_mtu,
|
mtu: self.device_mtu,
|
||||||
type_: Some(self.device_type),
|
type_: Some(self.device_type),
|
||||||
fix_rp_filter: Some(self.fix_rp_filter),
|
fix_rp_filter: Some(self.fix_rp_filter)
|
||||||
}),
|
}),
|
||||||
crypto: self.crypto,
|
crypto: self.crypto,
|
||||||
group: self.group,
|
group: self.group,
|
||||||
|
@ -333,7 +334,6 @@ impl Config {
|
||||||
ifup: self.ifup,
|
ifup: self.ifup,
|
||||||
ifdown: self.ifdown,
|
ifdown: self.ifdown,
|
||||||
ip: self.ip,
|
ip: self.ip,
|
||||||
advertise_addresses: Some(self.advertise_addresses),
|
|
||||||
keepalive: self.keepalive,
|
keepalive: self.keepalive,
|
||||||
listen: Some(self.listen),
|
listen: Some(self.listen),
|
||||||
mode: Some(self.mode),
|
mode: Some(self.mode),
|
||||||
|
@ -342,10 +342,13 @@ impl Config {
|
||||||
pid_file: self.pid_file,
|
pid_file: self.pid_file,
|
||||||
port_forwarding: Some(self.port_forwarding),
|
port_forwarding: Some(self.port_forwarding),
|
||||||
stats_file: self.stats_file,
|
stats_file: self.stats_file,
|
||||||
statsd: Some(ConfigFileStatsd { server: self.statsd_server, prefix: self.statsd_prefix }),
|
statsd: Some(ConfigFileStatsd {
|
||||||
|
server: self.statsd_server,
|
||||||
|
prefix: self.statsd_prefix
|
||||||
|
}),
|
||||||
switch_timeout: Some(self.switch_timeout),
|
switch_timeout: Some(self.switch_timeout),
|
||||||
hook: self.hook,
|
hook: self.hook,
|
||||||
hooks: self.hooks,
|
hooks: self.hooks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,7 +388,7 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call_hook(
|
pub fn call_hook(
|
||||||
&self, event: &'static str, envs: impl IntoIterator<Item = (&'static str, impl AsRef<OsStr>)>, detach: bool,
|
&self, event: &'static str, envs: impl IntoIterator<Item = (&'static str, impl AsRef<OsStr>)>, detach: bool
|
||||||
) {
|
) {
|
||||||
let mut script = None;
|
let mut script = None;
|
||||||
if let Some(ref s) = self.hook {
|
if let Some(ref s) = self.hook {
|
||||||
|
@ -395,7 +398,7 @@ impl Config {
|
||||||
script = Some(s);
|
script = Some(s);
|
||||||
}
|
}
|
||||||
if script.is_none() {
|
if script.is_none() {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
let script = script.unwrap();
|
let script = script.unwrap();
|
||||||
let mut cmd = process::Command::new("sh");
|
let mut cmd = process::Command::new("sh");
|
||||||
|
@ -515,10 +518,6 @@ pub struct Args {
|
||||||
#[structopt(long)]
|
#[structopt(long)]
|
||||||
pub ip: Option<String>,
|
pub ip: Option<String>,
|
||||||
|
|
||||||
/// A list of IP Addresses to advertise as our external address(s)
|
|
||||||
#[structopt(long = "advertise_addresses", use_delimiter = true)]
|
|
||||||
pub advertise_addresses: Vec<String>,
|
|
||||||
|
|
||||||
/// A command to setup the network interface
|
/// A command to setup the network interface
|
||||||
#[structopt(long)]
|
#[structopt(long)]
|
||||||
pub ifup: Option<String>,
|
pub ifup: Option<String>,
|
||||||
|
@ -590,8 +589,8 @@ pub enum Command {
|
||||||
#[structopt(alias = "wsproxy")]
|
#[structopt(alias = "wsproxy")]
|
||||||
WsProxy {
|
WsProxy {
|
||||||
/// Websocket listen address IP:PORT
|
/// Websocket listen address IP:PORT
|
||||||
#[structopt(long, short, default_value = "3210")]
|
#[structopt(long, short, default_value="3210")]
|
||||||
listen: String,
|
listen: String
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Migrate an old config file
|
/// Migrate an old config file
|
||||||
|
@ -605,8 +604,8 @@ pub enum Command {
|
||||||
/// Generate shell completions
|
/// Generate shell completions
|
||||||
Completion {
|
Completion {
|
||||||
/// Shell to create completions for
|
/// Shell to create completions for
|
||||||
#[structopt(long, default_value = "bash")]
|
#[structopt(long, default_value="bash")]
|
||||||
shell: Shell,
|
shell: Shell
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Edit the config of a network
|
/// Edit the config of a network
|
||||||
|
@ -614,7 +613,7 @@ pub enum Command {
|
||||||
Config {
|
Config {
|
||||||
/// Name of the network
|
/// Name of the network
|
||||||
#[structopt(short, long)]
|
#[structopt(short, long)]
|
||||||
name: Option<String>,
|
name: Option<String>
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Install required utility files
|
/// Install required utility files
|
||||||
|
@ -622,8 +621,8 @@ pub enum Command {
|
||||||
Install {
|
Install {
|
||||||
/// Remove installed files again
|
/// Remove installed files again
|
||||||
#[structopt(long)]
|
#[structopt(long)]
|
||||||
uninstall: bool,
|
uninstall: bool
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
|
||||||
|
@ -659,7 +658,6 @@ pub struct ConfigFile {
|
||||||
pub device: Option<ConfigFileDevice>,
|
pub device: Option<ConfigFileDevice>,
|
||||||
|
|
||||||
pub ip: Option<String>,
|
pub ip: Option<String>,
|
||||||
pub advertise_addresses: Option<Vec<String>>,
|
|
||||||
pub ifup: Option<String>,
|
pub ifup: Option<String>,
|
||||||
pub ifdown: Option<String>,
|
pub ifdown: Option<String>,
|
||||||
|
|
||||||
|
@ -681,7 +679,7 @@ pub struct ConfigFile {
|
||||||
pub user: Option<String>,
|
pub user: Option<String>,
|
||||||
pub group: Option<String>,
|
pub group: Option<String>,
|
||||||
pub hook: Option<String>,
|
pub hook: Option<String>,
|
||||||
pub hooks: HashMap<String, String>,
|
pub hooks: HashMap<String, String>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -693,9 +691,6 @@ device:
|
||||||
path: /dev/net/tun
|
path: /dev/net/tun
|
||||||
mtu: 1400
|
mtu: 1400
|
||||||
ip: 10.0.1.1/16
|
ip: 10.0.1.1/16
|
||||||
advertise-addresses:
|
|
||||||
- 192.168.0.1
|
|
||||||
- 192.168.1.1
|
|
||||||
ifup: ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up
|
ifup: ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up
|
||||||
ifdown: 'true'
|
ifdown: 'true'
|
||||||
peers:
|
peers:
|
||||||
|
@ -732,7 +727,6 @@ statsd:
|
||||||
fix_rp_filter: None
|
fix_rp_filter: None
|
||||||
}),
|
}),
|
||||||
ip: Some("10.0.1.1/16".to_string()),
|
ip: Some("10.0.1.1/16".to_string()),
|
||||||
advertise_addresses: Some(vec!["192.168.0.1".to_string(), "192.168.1.1".to_string()]),
|
|
||||||
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
|
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
|
||||||
ifdown: Some("true".to_string()),
|
ifdown: Some("true".to_string()),
|
||||||
crypto: CryptoConfig::default(),
|
crypto: CryptoConfig::default(),
|
||||||
|
@ -782,7 +776,6 @@ async fn config_merge() {
|
||||||
fix_rp_filter: None,
|
fix_rp_filter: None,
|
||||||
}),
|
}),
|
||||||
ip: None,
|
ip: None,
|
||||||
advertise_addresses: Some(vec![]),
|
|
||||||
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
|
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
|
||||||
ifdown: Some("true".to_string()),
|
ifdown: Some("true".to_string()),
|
||||||
crypto: CryptoConfig::default(),
|
crypto: CryptoConfig::default(),
|
||||||
|
@ -810,16 +803,13 @@ async fn config_merge() {
|
||||||
prefix: Some("prefix".to_string()),
|
prefix: Some("prefix".to_string()),
|
||||||
}),
|
}),
|
||||||
hook: None,
|
hook: None,
|
||||||
hooks: HashMap::new(),
|
hooks: HashMap::new()
|
||||||
});
|
});
|
||||||
assert_eq!(
|
assert_eq!(config, Config {
|
||||||
config,
|
|
||||||
Config {
|
|
||||||
device_type: Type::Tun,
|
device_type: Type::Tun,
|
||||||
device_name: "vpncloud%d".to_string(),
|
device_name: "vpncloud%d".to_string(),
|
||||||
device_path: None,
|
device_path: None,
|
||||||
ip: None,
|
ip: None,
|
||||||
advertise_addresses: vec![],
|
|
||||||
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
|
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
|
||||||
ifdown: Some("true".to_string()),
|
ifdown: Some("true".to_string()),
|
||||||
listen: "3210".to_string(),
|
listen: "3210".to_string(),
|
||||||
|
@ -841,8 +831,7 @@ async fn config_merge() {
|
||||||
statsd_server: Some("example.com:1234".to_string()),
|
statsd_server: Some("example.com:1234".to_string()),
|
||||||
statsd_prefix: Some("prefix".to_string()),
|
statsd_prefix: Some("prefix".to_string()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
});
|
||||||
);
|
|
||||||
config.merge_args(Args {
|
config.merge_args(Args {
|
||||||
type_: Some(Type::Tap),
|
type_: Some(Type::Tap),
|
||||||
device: Some("vpncloud0".to_string()),
|
device: Some("vpncloud0".to_string()),
|
||||||
|
@ -877,7 +866,6 @@ async fn config_merge() {
|
||||||
device_path: Some("/dev/null".to_string()),
|
device_path: Some("/dev/null".to_string()),
|
||||||
device_mtu: None,
|
device_mtu: None,
|
||||||
fix_rp_filter: false,
|
fix_rp_filter: false,
|
||||||
advertise_addresses: vec![],
|
|
||||||
ip: None,
|
ip: None,
|
||||||
ifup: Some("ifconfig $IFNAME 10.0.1.2/16 mtu 1400 up".to_string()),
|
ifup: Some("ifconfig $IFNAME 10.0.1.2/16 mtu 1400 up".to_string()),
|
||||||
ifdown: Some("ifconfig $IFNAME down".to_string()),
|
ifdown: Some("ifconfig $IFNAME down".to_string()),
|
||||||
|
|
|
@ -8,6 +8,7 @@ use crate::{
|
||||||
types::NodeId,
|
types::NodeId,
|
||||||
util::{from_base62, to_base62, MsgBuffer},
|
util::{from_base62, to_base62, MsgBuffer},
|
||||||
};
|
};
|
||||||
|
use libc::BPF_FS_MAGIC;
|
||||||
use ring::{
|
use ring::{
|
||||||
aead::{self, Algorithm, LessSafeKey, UnboundKey},
|
aead::{self, Algorithm, LessSafeKey, UnboundKey},
|
||||||
agreement::{EphemeralPrivateKey, UnparsedPublicKey},
|
agreement::{EphemeralPrivateKey, UnparsedPublicKey},
|
||||||
|
@ -252,8 +253,8 @@ impl PeerCrypto {
|
||||||
if msg.stage() == STAGE_PONG {
|
if msg.stage() == STAGE_PONG {
|
||||||
buffer.set_length(last_init_message.len());
|
buffer.set_length(last_init_message.len());
|
||||||
buffer.message_mut().copy_from_slice(last_init_message);
|
buffer.message_mut().copy_from_slice(last_init_message);
|
||||||
return Ok(MessageResult::Reply)
|
|
||||||
}
|
}
|
||||||
|
return Ok(MessageResult::Reply)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(MessageResult::None)
|
Ok(MessageResult::None)
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||||
use ring::{
|
use ring::{
|
||||||
aead::{self, LessSafeKey, UnboundKey},
|
aead::{self, LessSafeKey, UnboundKey},
|
||||||
rand::{SecureRandom, SystemRandom},
|
rand::{SecureRandom, SystemRandom}
|
||||||
};
|
};
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
|
|
||||||
|
@ -57,10 +57,12 @@ use std::{
|
||||||
|
|
||||||
use crate::{error::Error, util::MsgBuffer};
|
use crate::{error::Error, util::MsgBuffer};
|
||||||
|
|
||||||
|
|
||||||
const NONCE_LEN: usize = 12;
|
const NONCE_LEN: usize = 12;
|
||||||
pub const TAG_LEN: usize = 16;
|
pub const TAG_LEN: usize = 16;
|
||||||
pub const EXTRA_LEN: usize = 8;
|
pub const EXTRA_LEN: usize = 8;
|
||||||
|
|
||||||
|
|
||||||
fn random_data(size: usize) -> Vec<u8> {
|
fn random_data(size: usize) -> Vec<u8> {
|
||||||
let rand = SystemRandom::new();
|
let rand = SystemRandom::new();
|
||||||
let mut data = vec![0; size];
|
let mut data = vec![0; size];
|
||||||
|
@ -96,7 +98,7 @@ impl Nonce {
|
||||||
num = num.wrapping_add(1);
|
num = num.wrapping_add(1);
|
||||||
self.0[i] = num;
|
self.0[i] = num;
|
||||||
if num > 0 {
|
if num > 0 {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,7 +109,7 @@ struct CryptoKey {
|
||||||
send_nonce: Nonce,
|
send_nonce: Nonce,
|
||||||
min_nonce: Nonce,
|
min_nonce: Nonce,
|
||||||
next_min_nonce: Nonce,
|
next_min_nonce: Nonce,
|
||||||
seen_nonce: Nonce,
|
seen_nonce: Nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CryptoKey {
|
impl CryptoKey {
|
||||||
|
@ -119,7 +121,7 @@ impl CryptoKey {
|
||||||
send_nonce,
|
send_nonce,
|
||||||
min_nonce: Nonce::zero(),
|
min_nonce: Nonce::zero(),
|
||||||
next_min_nonce: Nonce::zero(),
|
next_min_nonce: Nonce::zero(),
|
||||||
seen_nonce: Nonce::zero(),
|
seen_nonce: Nonce::zero()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +190,7 @@ impl CryptoCore {
|
||||||
|
|
||||||
fn decrypt_with_key(key: &mut CryptoKey, nonce: Nonce, data_and_tag: &mut [u8]) -> Result<(), Error> {
|
fn decrypt_with_key(key: &mut CryptoKey, nonce: Nonce, data_and_tag: &mut [u8]) -> Result<(), Error> {
|
||||||
if nonce < key.min_nonce {
|
if nonce < key.min_nonce {
|
||||||
return Err(Error::Crypto("Old nonce rejected"));
|
return Err(Error::Crypto("Old nonce rejected"))
|
||||||
}
|
}
|
||||||
// decrypt
|
// decrypt
|
||||||
let crypto_nonce = aead::Nonce::assume_unique_for_key(*nonce.as_bytes());
|
let crypto_nonce = aead::Nonce::assume_unique_for_key(*nonce.as_bytes());
|
||||||
|
@ -271,6 +273,7 @@ pub fn test_speed(algo: &'static aead::Algorithm, max_time: &Duration) -> f64 {
|
||||||
data as f64 / duration / 1_000_000.0
|
data as f64 / duration / 1_000_000.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -313,6 +316,7 @@ mod tests {
|
||||||
test_encrypt_decrypt(&aead::CHACHA20_POLY1305)
|
test_encrypt_decrypt(&aead::CHACHA20_POLY1305)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn test_tampering(algo: &'static aead::Algorithm) {
|
fn test_tampering(algo: &'static aead::Algorithm) {
|
||||||
let (sender, receiver) = create_dummy_pair(algo);
|
let (sender, receiver) = create_dummy_pair(algo);
|
||||||
let plain = random_data(1000);
|
let plain = random_data(1000);
|
||||||
|
@ -443,6 +447,7 @@ mod tests {
|
||||||
test_key_rotation(&aead::CHACHA20_POLY1305);
|
test_key_rotation(&aead::CHACHA20_POLY1305);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
async fn test_core_size() {
|
async fn test_core_size() {
|
||||||
assert_eq!(2400, mem::size_of::<CryptoCore>());
|
assert_eq!(2400, mem::size_of::<CryptoCore>());
|
||||||
|
|
|
@ -7,5 +7,5 @@ mod core;
|
||||||
mod init;
|
mod init;
|
||||||
mod rotate;
|
mod rotate;
|
||||||
|
|
||||||
pub use self::core::{EXTRA_LEN, TAG_LEN};
|
|
||||||
pub use common::*;
|
pub use common::*;
|
||||||
|
pub use self::core::{EXTRA_LEN, TAG_LEN};
|
||||||
|
|
|
@ -34,18 +34,20 @@ use crate::{error::Error, util::MsgBuffer};
|
||||||
use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use ring::{
|
use ring::{
|
||||||
agreement::{agree_ephemeral, EphemeralPrivateKey, UnparsedPublicKey, X25519},
|
agreement::{agree_ephemeral, EphemeralPrivateKey, UnparsedPublicKey, X25519},
|
||||||
rand::SystemRandom,
|
rand::SystemRandom
|
||||||
};
|
};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use std::io::{self, Cursor, Read, Write};
|
use std::io::{self, Cursor, Read, Write};
|
||||||
|
|
||||||
|
|
||||||
type EcdhPublicKey = UnparsedPublicKey<SmallVec<[u8; 96]>>;
|
type EcdhPublicKey = UnparsedPublicKey<SmallVec<[u8; 96]>>;
|
||||||
type EcdhPrivateKey = EphemeralPrivateKey;
|
type EcdhPrivateKey = EphemeralPrivateKey;
|
||||||
|
|
||||||
|
|
||||||
pub struct RotationMessage {
|
pub struct RotationMessage {
|
||||||
message_id: u64,
|
message_id: u64,
|
||||||
propose: EcdhPublicKey,
|
propose: EcdhPublicKey,
|
||||||
confirm: Option<EcdhPublicKey>,
|
confirm: Option<EcdhPublicKey>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RotationMessage {
|
impl RotationMessage {
|
||||||
|
@ -89,13 +91,13 @@ pub struct RotationState {
|
||||||
pending: Option<(Key, EcdhPublicKey)>, // sent by remote, to be confirmed
|
pending: Option<(Key, EcdhPublicKey)>, // sent by remote, to be confirmed
|
||||||
proposed: Option<EcdhPrivateKey>, // my own, proposed but not confirmed
|
proposed: Option<EcdhPrivateKey>, // my own, proposed but not confirmed
|
||||||
message_id: u64,
|
message_id: u64,
|
||||||
timeout: bool,
|
timeout: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RotatedKey {
|
pub struct RotatedKey {
|
||||||
pub key: Key,
|
pub key: Key,
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
pub use_for_sending: bool,
|
pub use_for_sending: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RotationState {
|
impl RotationState {
|
||||||
|
@ -153,7 +155,7 @@ impl RotationState {
|
||||||
|
|
||||||
pub fn process_message(&mut self, msg: RotationMessage) -> Option<RotatedKey> {
|
pub fn process_message(&mut self, msg: RotationMessage) -> Option<RotatedKey> {
|
||||||
if msg.message_id <= self.message_id {
|
if msg.message_id <= self.message_id {
|
||||||
return None;
|
return None
|
||||||
}
|
}
|
||||||
debug!("Received rotation message with id {}", msg.message_id);
|
debug!("Received rotation message with id {}", msg.message_id);
|
||||||
self.timeout = false;
|
self.timeout = false;
|
||||||
|
@ -165,7 +167,7 @@ impl RotationState {
|
||||||
if let Some(peer_key) = msg.confirm {
|
if let Some(peer_key) = msg.confirm {
|
||||||
if let Some(private_key) = self.proposed.take() {
|
if let Some(private_key) = self.proposed.take() {
|
||||||
let key = Self::derive_key(private_key, peer_key);
|
let key = Self::derive_key(private_key, peer_key);
|
||||||
return Some(RotatedKey { key, id: msg.message_id, use_for_sending: true });
|
return Some(RotatedKey { key, id: msg.message_id, use_for_sending: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
@ -181,7 +183,7 @@ impl RotationState {
|
||||||
// Reconfirm last confirmed key
|
// Reconfirm last confirmed key
|
||||||
Self::send(
|
Self::send(
|
||||||
&RotationMessage { confirm: Some(confirmed_key.clone()), propose: proposed_key, message_id },
|
&RotationMessage { confirm: Some(confirmed_key.clone()), propose: proposed_key, message_id },
|
||||||
out,
|
out
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// First message has been lost
|
// First message has been lost
|
||||||
|
@ -200,7 +202,7 @@ impl RotationState {
|
||||||
self.proposed = Some(private_key);
|
self.proposed = Some(private_key);
|
||||||
self.confirmed = Some((confirm_key.clone(), message_id));
|
self.confirmed = Some((confirm_key.clone(), message_id));
|
||||||
Self::send(&RotationMessage { confirm: Some(confirm_key), propose: propose_key, message_id }, out);
|
Self::send(&RotationMessage { confirm: Some(confirm_key), propose: propose_key, message_id }, out);
|
||||||
return Some(RotatedKey { key, id: message_id, use_for_sending: false });
|
return Some(RotatedKey { key, id: message_id, use_for_sending: false })
|
||||||
} else {
|
} else {
|
||||||
// Nothing pending nor proposed, still waiting to receive message 1
|
// Nothing pending nor proposed, still waiting to receive message 1
|
||||||
// Do nothing, peer will retry
|
// Do nothing, peer will retry
|
||||||
|
@ -219,7 +221,7 @@ mod tests {
|
||||||
impl MsgBuffer {
|
impl MsgBuffer {
|
||||||
fn msg(&mut self) -> Option<RotationMessage> {
|
fn msg(&mut self) -> Option<RotationMessage> {
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
return None;
|
return None
|
||||||
}
|
}
|
||||||
let msg = RotationMessage::read_from(Cursor::new(self.message())).unwrap();
|
let msg = RotationMessage::read_from(Cursor::new(self.message())).unwrap();
|
||||||
self.set_length(0);
|
self.set_length(0);
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
use super::{
|
use super::{
|
||||||
common::SPACE_BEFORE,
|
|
||||||
shared::{SharedPeerCrypto, SharedTable, SharedTraffic},
|
shared::{SharedPeerCrypto, SharedTable, SharedTraffic},
|
||||||
|
common::SPACE_BEFORE,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
beacon::BeaconSerializer,
|
beacon::BeaconSerializer,
|
||||||
config::{DEFAULT_PEER_TIMEOUT, DEFAULT_PORT},
|
config::{DEFAULT_PEER_TIMEOUT, DEFAULT_PORT},
|
||||||
crypto::{is_init_message, Crypto, InitResult, InitState, MessageResult},
|
crypto::{is_init_message, InitResult, InitState, MessageResult, Crypto},
|
||||||
device::{Device, Type},
|
device::{Type, Device},
|
||||||
engine::common::{Hash, PeerData},
|
engine::common::{Hash, PeerData},
|
||||||
error::Error,
|
error::Error,
|
||||||
messages::{
|
messages::{
|
||||||
AddrList, NodeInfo, PeerInfo, MESSAGE_TYPE_CLOSE, MESSAGE_TYPE_DATA, MESSAGE_TYPE_KEEPALIVE,
|
AddrList, NodeInfo, PeerInfo, MESSAGE_TYPE_CLOSE, MESSAGE_TYPE_DATA, MESSAGE_TYPE_KEEPALIVE,
|
||||||
MESSAGE_TYPE_NODE_INFO,
|
MESSAGE_TYPE_NODE_INFO,
|
||||||
},
|
},
|
||||||
net::{mapped_addr, parse_listen, Socket},
|
net::{mapped_addr, Socket},
|
||||||
port_forwarding::PortForwarding,
|
port_forwarding::PortForwarding,
|
||||||
types::{Address, NodeId, Range, RangeList},
|
types::{Address, NodeId, Range, RangeList},
|
||||||
util::{addr_nice, resolve, MsgBuffer, StatsdMsg, Time, TimeSource},
|
util::{addr_nice, resolve, MsgBuffer, StatsdMsg, Time, TimeSource},
|
||||||
|
@ -236,17 +236,7 @@ impl<S: Socket, D: Device, P: Protocol, TS: TimeSource> SocketThread<S, D, P, TS
|
||||||
async fn update_peer_info(&mut self, addr: SocketAddr, info: Option<NodeInfo>) -> Result<(), Error> {
|
async fn update_peer_info(&mut self, addr: SocketAddr, info: Option<NodeInfo>) -> Result<(), Error> {
|
||||||
if let Some(peer) = self.peers.get_mut(&addr) {
|
if let Some(peer) = self.peers.get_mut(&addr) {
|
||||||
peer.last_seen = TS::now();
|
peer.last_seen = TS::now();
|
||||||
peer.timeout = TS::now() + self.config.peer_timeout as Time;
|
peer.timeout = TS::now() + self.config.peer_timeout as Time
|
||||||
if let Some(info) = &info {
|
|
||||||
// Update peer addresses, always add seen address
|
|
||||||
peer.addrs.clear();
|
|
||||||
peer.addrs.push(addr);
|
|
||||||
for addr in &info.addrs {
|
|
||||||
if !peer.addrs.contains(addr) {
|
|
||||||
peer.addrs.push(*addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
error!("Received peer update from non peer {}", addr_nice(addr));
|
error!("Received peer update from non peer {}", addr_nice(addr));
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -291,12 +281,6 @@ impl<S: Socket, D: Device, P: Protocol, TS: TimeSource> SocketThread<S, D, P, TS
|
||||||
'outer: for peer in peers {
|
'outer: for peer in peers {
|
||||||
for addr in &peer.addrs {
|
for addr in &peer.addrs {
|
||||||
if self.peers.contains_key(addr) {
|
if self.peers.contains_key(addr) {
|
||||||
// Check addresses and add addresses that we don't know to own addresses
|
|
||||||
for addr in &peer.addrs {
|
|
||||||
if !self.own_addresses.contains(addr) {
|
|
||||||
self.own_addresses.push(*addr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue 'outer;
|
continue 'outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,6 +427,11 @@ impl<S: Socket, D: Device, P: Protocol, TS: TimeSource> SocketThread<S, D, P, TS
|
||||||
pfw.check_extend();
|
pfw.check_extend();
|
||||||
}
|
}
|
||||||
let now = TS::now();
|
let now = TS::now();
|
||||||
|
// Periodically reset own peers
|
||||||
|
if self.next_own_address_reset <= now {
|
||||||
|
self.reset_own_addresses().await.map_err(|err| Error::SocketIo("Failed to get own addresses", err))?;
|
||||||
|
self.next_own_address_reset = now + OWN_ADDRESS_RESET_INTERVAL;
|
||||||
|
}
|
||||||
// Periodically send peer list to peers
|
// Periodically send peer list to peers
|
||||||
if self.next_peers <= now {
|
if self.next_peers <= now {
|
||||||
debug!("Send peer list to all peers");
|
debug!("Send peer list to all peers");
|
||||||
|
@ -476,11 +465,6 @@ impl<S: Socket, D: Device, P: Protocol, TS: TimeSource> SocketThread<S, D, P, TS
|
||||||
self.table.sync();
|
self.table.sync();
|
||||||
self.traffic.sync();
|
self.traffic.sync();
|
||||||
self.peer_crypto.store(&self.peers);
|
self.peer_crypto.store(&self.peers);
|
||||||
// Periodically reset own peers
|
|
||||||
if self.next_own_address_reset <= now {
|
|
||||||
self.reset_own_addresses().await.map_err(|err| Error::SocketIo("Failed to get own addresses", err))?;
|
|
||||||
self.next_own_address_reset = now + OWN_ADDRESS_RESET_INTERVAL;
|
|
||||||
}
|
|
||||||
assert!(self.buffer.is_empty());
|
assert!(self.buffer.is_empty());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -513,14 +497,7 @@ impl<S: Socket, D: Device, P: Protocol, TS: TimeSource> SocketThread<S, D, P, TS
|
||||||
|
|
||||||
async fn reset_own_addresses(&mut self) -> io::Result<()> {
|
async fn reset_own_addresses(&mut self) -> io::Result<()> {
|
||||||
self.own_addresses.clear();
|
self.own_addresses.clear();
|
||||||
let socket_addr = self.socket.address().await.map(mapped_addr)?;
|
self.own_addresses.push(self.socket.address().await.map(mapped_addr)?);
|
||||||
// 1) Specified advertise addresses
|
|
||||||
for addr in &self.config.advertise_addresses {
|
|
||||||
self.own_addresses.push(parse_listen(addr, socket_addr.port()));
|
|
||||||
}
|
|
||||||
// 2) Address of UDP socket
|
|
||||||
self.own_addresses.push(socket_addr);
|
|
||||||
// 3) Addresses from port forwarding
|
|
||||||
if let Some(ref pfw) = self.port_forwarding {
|
if let Some(ref pfw) = self.port_forwarding {
|
||||||
self.own_addresses.push(pfw.get_internal_ip().into());
|
self.own_addresses.push(pfw.get_internal_ip().into());
|
||||||
self.own_addresses.push(pfw.get_external_ip().into());
|
self.own_addresses.push(pfw.get_external_ip().into());
|
||||||
|
|
|
@ -6,6 +6,7 @@ use thiserror::Error;
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Crypto init error, this is recoverable
|
/// Crypto init error, this is recoverable
|
||||||
|
@ -51,5 +52,5 @@ pub enum Error {
|
||||||
Parse(&'static str),
|
Parse(&'static str),
|
||||||
|
|
||||||
#[error("Name can not be resolved: {0}")]
|
#[error("Name can not be resolved: {0}")]
|
||||||
NameUnresolvable(String),
|
NameUnresolvable(String)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,11 @@ use std::{
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io::Write,
|
io::Write,
|
||||||
os::unix::fs::PermissionsExt,
|
os::unix::fs::PermissionsExt,
|
||||||
process::Command,
|
process::Command
|
||||||
};
|
};
|
||||||
|
|
||||||
const MANPAGE: &[u8] = include_bytes!("../target/vpncloud.1.gz");
|
const MANPAGE: &[u8] = include_bytes!("../target/vpncloud.1.gz");
|
||||||
const SERVICE_FILE: &[u8] = include_bytes!("../assets/vpncloud@.service");
|
const SERVICE_FILE: &[u8] = include_bytes!("../assets/vpncloud@.service");
|
||||||
const TARGET_FILE: &[u8] = include_bytes!("../assets/vpncloud.target");
|
|
||||||
const WS_PROXY_SERVICE_FILE: &[u8] = include_bytes!("../assets/vpncloud-wsproxy.service");
|
const WS_PROXY_SERVICE_FILE: &[u8] = include_bytes!("../assets/vpncloud-wsproxy.service");
|
||||||
const EXAMPLE_CONFIG: &[u8] = include_bytes!("../assets/example.net.disabled");
|
const EXAMPLE_CONFIG: &[u8] = include_bytes!("../assets/example.net.disabled");
|
||||||
|
|
||||||
|
@ -23,10 +22,10 @@ pub fn install() -> Result<(), Error> {
|
||||||
env::current_exe()
|
env::current_exe()
|
||||||
.and_then(|p| fs::copy(p, "/usr/bin/vpncloud"))
|
.and_then(|p| fs::copy(p, "/usr/bin/vpncloud"))
|
||||||
.map_err(|e| Error::FileIo("Failed to copy binary", e))?;
|
.map_err(|e| Error::FileIo("Failed to copy binary", e))?;
|
||||||
fs::set_permissions("/usr/bin/vpncloud", fs::Permissions::from_mode(0o755))
|
fs::set_permissions("/usr/bin/vpncloud", fs::Permissions::from_mode(755))
|
||||||
.map_err(|e| Error::FileIo("Failed to set permissions for binary", e))?;
|
.map_err(|e| Error::FileIo("Failed to set permissions for binary", e))?;
|
||||||
fs::create_dir_all("/etc/vpncloud").map_err(|e| Error::FileIo("Failed to create config folder", e))?;
|
fs::create_dir_all("/etc/vpncloud").map_err(|e| Error::FileIo("Failed to create config folder", e))?;
|
||||||
fs::set_permissions("/etc/vpncloud", fs::Permissions::from_mode(0o700))
|
fs::set_permissions("/etc/vpncloud", fs::Permissions::from_mode(700))
|
||||||
.map_err(|e| Error::FileIo("Failed to set permissions for config folder", e))?;
|
.map_err(|e| Error::FileIo("Failed to set permissions for config folder", e))?;
|
||||||
File::create("/etc/vpncloud/example.net.disabled")
|
File::create("/etc/vpncloud/example.net.disabled")
|
||||||
.and_then(|mut f| f.write_all(EXAMPLE_CONFIG))
|
.and_then(|mut f| f.write_all(EXAMPLE_CONFIG))
|
||||||
|
@ -37,9 +36,6 @@ pub fn install() -> Result<(), Error> {
|
||||||
File::create("/lib/systemd/system/vpncloud@.service")
|
File::create("/lib/systemd/system/vpncloud@.service")
|
||||||
.and_then(|mut f| f.write_all(SERVICE_FILE))
|
.and_then(|mut f| f.write_all(SERVICE_FILE))
|
||||||
.map_err(|e| Error::FileIo("Failed to create service file", e))?;
|
.map_err(|e| Error::FileIo("Failed to create service file", e))?;
|
||||||
File::create("/lib/systemd/system/vpncloud.target")
|
|
||||||
.and_then(|mut f| f.write_all(TARGET_FILE))
|
|
||||||
.map_err(|e| Error::FileIo("Failed to create service target file", e))?;
|
|
||||||
File::create("/lib/systemd/system/vpncloud-wsproxy.service")
|
File::create("/lib/systemd/system/vpncloud-wsproxy.service")
|
||||||
.and_then(|mut f| f.write_all(WS_PROXY_SERVICE_FILE))
|
.and_then(|mut f| f.write_all(WS_PROXY_SERVICE_FILE))
|
||||||
.map_err(|e| Error::FileIo("Failed to create wsporxy service file", e))?;
|
.map_err(|e| Error::FileIo("Failed to create wsporxy service file", e))?;
|
||||||
|
@ -53,8 +49,6 @@ pub fn uninstall() -> Result<(), Error> {
|
||||||
fs::remove_file("/usr/share/man/man1/vpncloud.1.gz").map_err(|e| Error::FileIo("Failed to remove manpage", e))?;
|
fs::remove_file("/usr/share/man/man1/vpncloud.1.gz").map_err(|e| Error::FileIo("Failed to remove manpage", e))?;
|
||||||
fs::remove_file("/lib/systemd/system/vpncloud@.service")
|
fs::remove_file("/lib/systemd/system/vpncloud@.service")
|
||||||
.map_err(|e| Error::FileIo("Failed to remove service file", e))?;
|
.map_err(|e| Error::FileIo("Failed to remove service file", e))?;
|
||||||
fs::remove_file("/lib/systemd/system/vpncloud.target")
|
|
||||||
.map_err(|e| Error::FileIo("Failed to remove service target file", e))?;
|
|
||||||
fs::remove_file("/lib/systemd/system/vpncloud-wsproxy.service")
|
fs::remove_file("/lib/systemd/system/vpncloud-wsproxy.service")
|
||||||
.map_err(|e| Error::FileIo("Failed to remove wsproxy service file", e))?;
|
.map_err(|e| Error::FileIo("Failed to remove wsproxy service file", e))?;
|
||||||
fs::remove_file("/usr/bin/vpncloud").map_err(|e| Error::FileIo("Failed to remove binary", e))?;
|
fs::remove_file("/usr/bin/vpncloud").map_err(|e| Error::FileIo("Failed to remove binary", e))?;
|
||||||
|
|
30
src/main.rs
30
src/main.rs
|
@ -6,8 +6,7 @@
|
||||||
#[macro_use] extern crate serde;
|
#[macro_use] extern crate serde;
|
||||||
#[macro_use] extern crate tokio;
|
#[macro_use] extern crate tokio;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)] extern crate tempfile;
|
||||||
extern crate tempfile;
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
@ -20,8 +19,6 @@ pub mod config;
|
||||||
pub mod crypto;
|
pub mod crypto;
|
||||||
pub mod device;
|
pub mod device;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
#[cfg(feature = "installer")]
|
|
||||||
pub mod installer;
|
|
||||||
pub mod messages;
|
pub mod messages;
|
||||||
pub mod net;
|
pub mod net;
|
||||||
pub mod oldconfig;
|
pub mod oldconfig;
|
||||||
|
@ -31,10 +28,9 @@ pub mod port_forwarding;
|
||||||
pub mod table;
|
pub mod table;
|
||||||
pub mod traffic;
|
pub mod traffic;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
#[cfg(feature = "wizard")]
|
#[cfg(feature = "wizard")] pub mod wizard;
|
||||||
pub mod wizard;
|
#[cfg(feature = "websocket")] pub mod wsproxy;
|
||||||
#[cfg(feature = "websocket")]
|
#[cfg(feature = "installer")] pub mod installer;
|
||||||
pub mod wsproxy;
|
|
||||||
|
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
@ -47,7 +43,7 @@ use std::{
|
||||||
process,
|
process,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
sync::Mutex,
|
sync::Mutex,
|
||||||
thread,
|
thread
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -65,7 +61,7 @@ use crate::{
|
||||||
use crate::wsproxy::ProxyConnection;
|
use crate::wsproxy::ProxyConnection;
|
||||||
|
|
||||||
struct DualLogger {
|
struct DualLogger {
|
||||||
file: Option<Mutex<File>>,
|
file: Option<Mutex<File>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DualLogger {
|
impl DualLogger {
|
||||||
|
@ -121,18 +117,18 @@ fn run_script(script: &str, ifname: &str) {
|
||||||
error!("Script returned with error: {:?}", status.code())
|
error!("Script returned with error: {:?}", status.code())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => error!("Failed to execute script {:?}: {}", script, e),
|
Err(e) => error!("Failed to execute script {:?}: {}", script, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ip_netmask(addr: &str) -> Result<(Ipv4Addr, Ipv4Addr), String> {
|
fn parse_ip_netmask(addr: &str) -> Result<(Ipv4Addr, Ipv4Addr), String> {
|
||||||
let (ip_str, len_str) = match addr.find('/') {
|
let (ip_str, len_str) = match addr.find('/') {
|
||||||
Some(pos) => (&addr[..pos], &addr[pos + 1..]),
|
Some(pos) => (&addr[..pos], &addr[pos + 1..]),
|
||||||
None => (addr, "24"),
|
None => (addr, "24")
|
||||||
};
|
};
|
||||||
let prefix_len = u8::from_str(len_str).map_err(|_| format!("Invalid prefix length: {}", len_str))?;
|
let prefix_len = u8::from_str(len_str).map_err(|_| format!("Invalid prefix length: {}", len_str))?;
|
||||||
if prefix_len > 32 {
|
if prefix_len > 32 {
|
||||||
return Err(format!("Invalid prefix length: {}", prefix_len));
|
return Err(format!("Invalid prefix length: {}", prefix_len))
|
||||||
}
|
}
|
||||||
let ip = Ipv4Addr::from_str(ip_str).map_err(|_| format!("Invalid ip address: {}", ip_str))?;
|
let ip = Ipv4Addr::from_str(ip_str).map_err(|_| format!("Invalid ip address: {}", ip_str))?;
|
||||||
let netmask = Ipv4Addr::from(u32::max_value().checked_shl(32 - prefix_len as u32).unwrap());
|
let netmask = Ipv4Addr::from(u32::max_value().checked_shl(32 - prefix_len as u32).unwrap());
|
||||||
|
@ -237,7 +233,7 @@ async fn main() {
|
||||||
let args: Args = Args::from_args();
|
let args: Args = Args::from_args();
|
||||||
if args.version {
|
if args.version {
|
||||||
println!("VpnCloud v{}", env!("CARGO_PKG_VERSION"));
|
println!("VpnCloud v{}", env!("CARGO_PKG_VERSION"));
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
let logger = try_fail!(DualLogger::new(args.log_file.as_ref()), "Failed to open logfile: {}");
|
let logger = try_fail!(DualLogger::new(args.log_file.as_ref()), "Failed to open logfile: {}");
|
||||||
log::set_boxed_logger(Box::new(logger)).unwrap();
|
log::set_boxed_logger(Box::new(logger)).unwrap();
|
||||||
|
@ -298,7 +294,7 @@ async fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
if let Some(ref file) = args.config {
|
if let Some(ref file) = args.config {
|
||||||
|
@ -323,7 +319,7 @@ async fn main() {
|
||||||
debug!("Config: {:?}", config);
|
debug!("Config: {:?}", config);
|
||||||
if config.crypto.password.is_none() && config.crypto.private_key.is_none() {
|
if config.crypto.password.is_none() && config.crypto.private_key.is_none() {
|
||||||
error!("Either password or private key must be set in config or given as parameter");
|
error!("Either password or private key must be set in config or given as parameter");
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
#[cfg(feature = "websocket")]
|
#[cfg(feature = "websocket")]
|
||||||
if config.listen.starts_with("ws://") {
|
if config.listen.starts_with("ws://") {
|
||||||
|
@ -332,7 +328,7 @@ async fn main() {
|
||||||
Type::Tap => run::<payload::Frame, _>(config, socket).await,
|
Type::Tap => run::<payload::Frame, _>(config, socket).await,
|
||||||
Type::Tun => run::<payload::Packet, _>(config, socket).await
|
Type::Tun => run::<payload::Packet, _>(config, socket).await
|
||||||
}
|
}
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
let socket = try_fail!(NetSocket::listen(&config.listen).await, "Failed to open socket {}: {}", config.listen);
|
let socket = try_fail!(NetSocket::listen(&config.listen).await, "Failed to open socket {}: {}", config.listen);
|
||||||
match config.device_type {
|
match config.device_type {
|
||||||
|
|
|
@ -6,27 +6,30 @@ use crate::{
|
||||||
crypto::Payload,
|
crypto::Payload,
|
||||||
error::Error,
|
error::Error,
|
||||||
types::{NodeId, Range, RangeList, NODE_ID_BYTES},
|
types::{NodeId, Range, RangeList, NODE_ID_BYTES},
|
||||||
util::MsgBuffer,
|
util::MsgBuffer
|
||||||
};
|
};
|
||||||
use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use std::{
|
use std::{
|
||||||
io::{self, Cursor, Read, Seek, SeekFrom, Take, Write},
|
io::{self, Cursor, Read, Seek, SeekFrom, Take, Write},
|
||||||
net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
|
net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
pub const MESSAGE_TYPE_DATA: u8 = 0;
|
pub const MESSAGE_TYPE_DATA: u8 = 0;
|
||||||
pub const MESSAGE_TYPE_NODE_INFO: u8 = 1;
|
pub const MESSAGE_TYPE_NODE_INFO: u8 = 1;
|
||||||
pub const MESSAGE_TYPE_KEEPALIVE: u8 = 2;
|
pub const MESSAGE_TYPE_KEEPALIVE: u8 = 2;
|
||||||
pub const MESSAGE_TYPE_CLOSE: u8 = 0xff;
|
pub const MESSAGE_TYPE_CLOSE: u8 = 0xff;
|
||||||
|
|
||||||
|
|
||||||
pub type AddrList = SmallVec<[SocketAddr; 4]>;
|
pub type AddrList = SmallVec<[SocketAddr; 4]>;
|
||||||
pub type PeerList = SmallVec<[PeerInfo; 16]>;
|
pub type PeerList = SmallVec<[PeerInfo; 16]>;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct PeerInfo {
|
pub struct PeerInfo {
|
||||||
pub node_id: Option<NodeId>,
|
pub node_id: Option<NodeId>,
|
||||||
pub addrs: AddrList,
|
pub addrs: AddrList
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
@ -35,7 +38,7 @@ pub struct NodeInfo {
|
||||||
pub peers: PeerList,
|
pub peers: PeerList,
|
||||||
pub claims: RangeList,
|
pub claims: RangeList,
|
||||||
pub peer_timeout: Option<u16>,
|
pub peer_timeout: Option<u16>,
|
||||||
pub addrs: AddrList,
|
pub addrs: AddrList
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeInfo {
|
impl NodeInfo {
|
||||||
|
@ -106,7 +109,7 @@ impl NodeInfo {
|
||||||
loop {
|
loop {
|
||||||
let part = r.read_u8().map_err(|_| Error::Message("Truncated message"))?;
|
let part = r.read_u8().map_err(|_| Error::Message("Truncated message"))?;
|
||||||
if part == Self::PART_END {
|
if part == Self::PART_END {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
let part_len = r.read_u16::<NetworkEndian>().map_err(|_| Error::Message("Truncated message"))? as usize;
|
let part_len = r.read_u16::<NetworkEndian>().map_err(|_| Error::Message("Truncated message"))? as usize;
|
||||||
let mut rp = r.take(part_len as u64);
|
let mut rp = r.take(part_len as u64);
|
||||||
|
@ -136,7 +139,7 @@ impl NodeInfo {
|
||||||
}
|
}
|
||||||
let node_id = match node_id {
|
let node_id = match node_id {
|
||||||
Some(node_id) => node_id,
|
Some(node_id) => node_id,
|
||||||
None => return Err(Error::Message("Payload without node_id")),
|
None => return Err(Error::Message("Payload without node_id"))
|
||||||
};
|
};
|
||||||
Ok(Self { node_id, peers, claims, peer_timeout, addrs })
|
Ok(Self { node_id, peers, claims, peer_timeout, addrs })
|
||||||
}
|
}
|
||||||
|
@ -152,7 +155,7 @@ impl NodeInfo {
|
||||||
for a in &p.addrs {
|
for a in &p.addrs {
|
||||||
match a {
|
match a {
|
||||||
SocketAddr::V4(addr) => addr_ipv4.push(*addr),
|
SocketAddr::V4(addr) => addr_ipv4.push(*addr),
|
||||||
SocketAddr::V6(addr) => addr_ipv6.push(*addr),
|
SocketAddr::V6(addr) => addr_ipv6.push(*addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while addr_ipv4.len() >= 8 {
|
while addr_ipv4.len() >= 8 {
|
||||||
|
@ -187,7 +190,7 @@ impl NodeInfo {
|
||||||
for a in &self.addrs {
|
for a in &self.addrs {
|
||||||
match a {
|
match a {
|
||||||
SocketAddr::V4(addr) => addr_ipv4.push(*addr),
|
SocketAddr::V4(addr) => addr_ipv4.push(*addr),
|
||||||
SocketAddr::V6(addr) => addr_ipv6.push(*addr),
|
SocketAddr::V6(addr) => addr_ipv6.push(*addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while addr_ipv4.len() >= 8 {
|
while addr_ipv4.len() >= 8 {
|
||||||
|
@ -210,7 +213,7 @@ impl NodeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_part<F: FnOnce(&mut Cursor<&mut [u8]>) -> Result<(), io::Error>>(
|
fn encode_part<F: FnOnce(&mut Cursor<&mut [u8]>) -> Result<(), io::Error>>(
|
||||||
cursor: &mut Cursor<&mut [u8]>, part: u8, f: F,
|
cursor: &mut Cursor<&mut [u8]>, part: u8, f: F
|
||||||
) -> Result<(), io::Error> {
|
) -> Result<(), io::Error> {
|
||||||
cursor.write_u8(part)?;
|
cursor.write_u8(part)?;
|
||||||
cursor.write_u16::<NetworkEndian>(0)?;
|
cursor.write_u16::<NetworkEndian>(0)?;
|
||||||
|
@ -254,6 +257,7 @@ impl NodeInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Payload for NodeInfo {
|
impl Payload for NodeInfo {
|
||||||
fn write_to(&self, buffer: &mut MsgBuffer) {
|
fn write_to(&self, buffer: &mut MsgBuffer) {
|
||||||
self.encode(buffer)
|
self.encode(buffer)
|
||||||
|
|
18
src/net.rs
18
src/net.rs
|
@ -2,15 +2,15 @@
|
||||||
// Copyright (C) 2015-2021 Dennis Schwerdel
|
// Copyright (C) 2015-2021 Dennis Schwerdel
|
||||||
// This software is licensed under GPL-3 or newer (see LICENSE.md)
|
// This software is licensed under GPL-3 or newer (see LICENSE.md)
|
||||||
|
|
||||||
use crate::config::DEFAULT_PORT;
|
use super::util::{MockTimeSource, MsgBuffer, Time, TimeSource};
|
||||||
use crate::port_forwarding::PortForwarding;
|
use crate::port_forwarding::PortForwarding;
|
||||||
use crate::util::{MockTimeSource, MsgBuffer, Time, TimeSource};
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, VecDeque},
|
collections::{HashMap, VecDeque},
|
||||||
io::{self, ErrorKind},
|
io::{self, ErrorKind},
|
||||||
net::{IpAddr, Ipv6Addr, SocketAddr, UdpSocket},
|
net::{IpAddr, Ipv6Addr, SocketAddr, UdpSocket},
|
||||||
|
os::unix::io::AsRawFd,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
|
@ -40,17 +40,15 @@ pub trait Socket: Sized + Clone + Send + Sync + 'static {
|
||||||
async fn create_port_forwarding(&self) -> Option<PortForwarding>;
|
async fn create_port_forwarding(&self) -> Option<PortForwarding>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_listen(addr: &str, default_port: u16) -> SocketAddr {
|
pub fn parse_listen(addr: &str) -> SocketAddr {
|
||||||
if let Some(addr) = addr.strip_prefix("*:") {
|
if let Some(addr) = addr.strip_prefix("*:") {
|
||||||
let port = try_fail!(addr.parse::<u16>(), "Invalid port: {}");
|
let port = try_fail!(addr.parse::<u16>(), "Invalid port: {}");
|
||||||
SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), port)
|
SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), port)
|
||||||
} else if addr.contains(':') {
|
} else if addr.contains(':') {
|
||||||
try_fail!(addr.parse::<SocketAddr>(), "Invalid address: {}: {}", addr)
|
try_fail!(addr.parse::<SocketAddr>(), "Invalid address: {}: {}", addr)
|
||||||
} else if let Ok(port) = addr.parse::<u16>() {
|
|
||||||
SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), port)
|
|
||||||
} else {
|
} else {
|
||||||
let ip = try_fail!(addr.parse::<IpAddr>(), "Invalid addr: {}");
|
let port = try_fail!(addr.parse::<u16>(), "Invalid port: {}");
|
||||||
SocketAddr::new(ip, default_port)
|
SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,10 +60,11 @@ impl Clone for NetSocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Socket for NetSocket {
|
impl Socket for NetSocket {
|
||||||
async fn listen(addr: &str) -> Result<Self, io::Error> {
|
async fn listen(addr: &str) -> Result<Self, io::Error> {
|
||||||
let addr = parse_listen(addr, DEFAULT_PORT);
|
let addr = parse_listen(addr);
|
||||||
Ok(NetSocket(UdpSocket::bind(addr)?))
|
Ok(NetSocket(UdpSocket::bind(addr)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,10 +142,11 @@ impl MockSocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Socket for MockSocket {
|
impl Socket for MockSocket {
|
||||||
async fn listen(addr: &str) -> Result<Self, io::Error> {
|
async fn listen(addr: &str) -> Result<Self, io::Error> {
|
||||||
Ok(Self::new(parse_listen(addr, DEFAULT_PORT)))
|
Ok(Self::new(parse_listen(addr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn receive(&mut self, buffer: &mut MsgBuffer) -> Result<SocketAddr, io::Error> {
|
async fn receive(&mut self, buffer: &mut MsgBuffer) -> Result<SocketAddr, io::Error> {
|
||||||
|
|
|
@ -13,7 +13,7 @@ pub enum OldCryptoMethod {
|
||||||
#[serde(rename = "aes256")]
|
#[serde(rename = "aes256")]
|
||||||
AES256,
|
AES256,
|
||||||
#[serde(rename = "aes128")]
|
#[serde(rename = "aes128")]
|
||||||
AES128,
|
AES128
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
|
||||||
|
@ -57,7 +57,7 @@ pub struct OldConfigFile {
|
||||||
#[serde(alias = "statsd-prefix")]
|
#[serde(alias = "statsd-prefix")]
|
||||||
pub statsd_prefix: Option<String>,
|
pub statsd_prefix: Option<String>,
|
||||||
pub user: Option<String>,
|
pub user: Option<String>,
|
||||||
pub group: Option<String>,
|
pub group: Option<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OldConfigFile {
|
impl OldConfigFile {
|
||||||
|
@ -89,7 +89,7 @@ impl OldConfigFile {
|
||||||
interval: self.beacon_interval,
|
interval: self.beacon_interval,
|
||||||
load: self.beacon_load,
|
load: self.beacon_load,
|
||||||
store: self.beacon_store,
|
store: self.beacon_store,
|
||||||
password: self.shared_key.clone(),
|
password: self.shared_key.clone()
|
||||||
}),
|
}),
|
||||||
claims: self.subnets,
|
claims: self.subnets,
|
||||||
crypto: CryptoConfig {
|
crypto: CryptoConfig {
|
||||||
|
@ -97,7 +97,7 @@ impl OldConfigFile {
|
||||||
password: Some(self.shared_key.unwrap_or_else(|| "none".to_string())),
|
password: Some(self.shared_key.unwrap_or_else(|| "none".to_string())),
|
||||||
private_key: None,
|
private_key: None,
|
||||||
public_key: None,
|
public_key: None,
|
||||||
trusted_keys: vec![],
|
trusted_keys: vec![]
|
||||||
},
|
},
|
||||||
device: Some(ConfigFileDevice {
|
device: Some(ConfigFileDevice {
|
||||||
fix_rp_filter: None,
|
fix_rp_filter: None,
|
||||||
|
@ -110,7 +110,6 @@ impl OldConfigFile {
|
||||||
ifdown: self.ifdown,
|
ifdown: self.ifdown,
|
||||||
ifup: self.ifup,
|
ifup: self.ifup,
|
||||||
ip: None,
|
ip: None,
|
||||||
advertise_addresses: None,
|
|
||||||
keepalive: self.keepalive,
|
keepalive: self.keepalive,
|
||||||
listen: self.listen.or(self.port.map(|p| format!("{}", p))),
|
listen: self.listen.or(self.port.map(|p| format!("{}", p))),
|
||||||
mode: self.mode,
|
mode: self.mode,
|
||||||
|
@ -123,7 +122,7 @@ impl OldConfigFile {
|
||||||
switch_timeout: self.dst_timeout,
|
switch_timeout: self.dst_timeout,
|
||||||
user: self.user,
|
user: self.user,
|
||||||
hook: None,
|
hook: None,
|
||||||
hooks: HashMap::new(),
|
hooks: HashMap::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ impl Protocol for Frame {
|
||||||
// treat vlan id 0x000 as untagged
|
// treat vlan id 0x000 as untagged
|
||||||
src.copy_within(2..8, 0);
|
src.copy_within(2..8, 0);
|
||||||
dst.copy_within(2..8, 0);
|
dst.copy_within(2..8, 0);
|
||||||
return Ok((Address { data: src, len: 6 }, Address { data: dst, len: 6 }));
|
return Ok((Address { data: src, len: 6 }, Address { data: dst, len: 6 }))
|
||||||
}
|
}
|
||||||
Ok((Address { data: src, len: 8 }, Address { data: dst, len: 8 }))
|
Ok((Address { data: src, len: 8 }, Address { data: dst, len: 8 }))
|
||||||
} else {
|
} else {
|
||||||
|
@ -52,6 +52,7 @@ impl Protocol for Frame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
async fn decode_frame_without_vlan() {
|
async fn decode_frame_without_vlan() {
|
||||||
let data = [6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8];
|
let data = [6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8];
|
||||||
|
@ -92,13 +93,13 @@ impl Protocol for Packet {
|
||||||
fn parse(data: &[u8]) -> Result<(Address, Address), Error> {
|
fn parse(data: &[u8]) -> Result<(Address, Address), Error> {
|
||||||
// HOT PATH
|
// HOT PATH
|
||||||
if data.is_empty() {
|
if data.is_empty() {
|
||||||
return Err(Error::Parse("Empty header"));
|
return Err(Error::Parse("Empty header"))
|
||||||
}
|
}
|
||||||
let version = data[0] >> 4;
|
let version = data[0] >> 4;
|
||||||
match version {
|
match version {
|
||||||
4 => {
|
4 => {
|
||||||
if data.len() < 20 {
|
if data.len() < 20 {
|
||||||
return Err(Error::Parse("Truncated IPv4 header"));
|
return Err(Error::Parse("Truncated IPv4 header"))
|
||||||
}
|
}
|
||||||
let src = Address::read_from_fixed(&data[12..], 4)?;
|
let src = Address::read_from_fixed(&data[12..], 4)?;
|
||||||
let dst = Address::read_from_fixed(&data[16..], 4)?;
|
let dst = Address::read_from_fixed(&data[16..], 4)?;
|
||||||
|
@ -106,17 +107,18 @@ impl Protocol for Packet {
|
||||||
}
|
}
|
||||||
6 => {
|
6 => {
|
||||||
if data.len() < 40 {
|
if data.len() < 40 {
|
||||||
return Err(Error::Parse("Truncated IPv6 header"));
|
return Err(Error::Parse("Truncated IPv6 header"))
|
||||||
}
|
}
|
||||||
let src = Address::read_from_fixed(&data[8..], 16)?;
|
let src = Address::read_from_fixed(&data[8..], 16)?;
|
||||||
let dst = Address::read_from_fixed(&data[24..], 16)?;
|
let dst = Address::read_from_fixed(&data[24..], 16)?;
|
||||||
Ok((src, dst))
|
Ok((src, dst))
|
||||||
}
|
}
|
||||||
_ => Err(Error::Parse("Invalid IP protocol version")),
|
_ => Err(Error::Parse("Invalid IP protocol version"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
async fn decode_ipv4_packet() {
|
async fn decode_ipv4_packet() {
|
||||||
let data = [0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 1, 1, 192, 168, 1, 2];
|
let data = [0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 1, 1, 192, 168, 1, 2];
|
||||||
|
@ -129,7 +131,7 @@ async fn decode_ipv4_packet() {
|
||||||
async fn decode_ipv6_packet() {
|
async fn decode_ipv6_packet() {
|
||||||
let data = [
|
let data = [
|
||||||
0x60, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 6, 5,
|
0x60, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 6, 5,
|
||||||
4, 3, 2, 1,
|
4, 3, 2, 1
|
||||||
];
|
];
|
||||||
let (src, dst) = Packet::parse(&data).unwrap();
|
let (src, dst) = Packet::parse(&data).unwrap();
|
||||||
assert_eq!(src, Address { data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6], len: 16 });
|
assert_eq!(src, Address { data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6], len: 16 });
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub struct EpollWait {
|
||||||
event: libc::epoll_event,
|
event: libc::epoll_event,
|
||||||
socket: RawFd,
|
socket: RawFd,
|
||||||
device: RawFd,
|
device: RawFd,
|
||||||
timeout: u32,
|
timeout: u32
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EpollWait {
|
impl EpollWait {
|
||||||
|
@ -27,14 +27,14 @@ impl EpollWait {
|
||||||
let mut event = libc::epoll_event { u64: 0, events: 0 };
|
let mut event = libc::epoll_event { u64: 0, events: 0 };
|
||||||
let poll_fd = unsafe { libc::epoll_create(3) };
|
let poll_fd = unsafe { libc::epoll_create(3) };
|
||||||
if poll_fd == -1 {
|
if poll_fd == -1 {
|
||||||
return Err(io::Error::last_os_error());
|
return Err(io::Error::last_os_error())
|
||||||
}
|
}
|
||||||
for fd in &[socket, device] {
|
for fd in &[socket, device] {
|
||||||
event.u64 = *fd as u64;
|
event.u64 = *fd as u64;
|
||||||
event.events = flags;
|
event.events = flags;
|
||||||
let res = unsafe { libc::epoll_ctl(poll_fd, libc::EPOLL_CTL_ADD, *fd, &mut event) };
|
let res = unsafe { libc::epoll_ctl(poll_fd, libc::EPOLL_CTL_ADD, *fd, &mut event) };
|
||||||
if res == -1 {
|
if res == -1 {
|
||||||
return Err(io::Error::last_os_error());
|
return Err(io::Error::last_os_error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Self { poll_fd, event, socket, device, timeout })
|
Ok(Self { poll_fd, event, socket, device, timeout })
|
||||||
|
@ -63,7 +63,7 @@ impl Iterator for EpollWait {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,12 @@ mod epoll;
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
pub use self::epoll::EpollWait as WaitImpl;
|
pub use self::epoll::EpollWait as WaitImpl;
|
||||||
|
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
pub enum WaitResult {
|
pub enum WaitResult {
|
||||||
Timeout,
|
Timeout,
|
||||||
Socket,
|
Socket,
|
||||||
Device,
|
Device,
|
||||||
Error(io::Error),
|
Error(io::Error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ mod internal {
|
||||||
pub internal_addr: SocketAddrV4,
|
pub internal_addr: SocketAddrV4,
|
||||||
pub external_addr: SocketAddrV4,
|
pub external_addr: SocketAddrV4,
|
||||||
gateway: Gateway,
|
gateway: Gateway,
|
||||||
pub next_extension: Option<Time>,
|
pub next_extension: Option<Time>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PortForwarding {
|
impl PortForwarding {
|
||||||
|
@ -32,11 +32,11 @@ mod internal {
|
||||||
if err.kind() == io::ErrorKind::WouldBlock {
|
if err.kind() == io::ErrorKind::WouldBlock {
|
||||||
// Why this code?
|
// Why this code?
|
||||||
info!("Port-forwarding: no router found");
|
info!("Port-forwarding: no router found");
|
||||||
return None;
|
return None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
error!("Port-forwarding: failed to find router: {}", err);
|
error!("Port-forwarding: failed to find router: {}", err);
|
||||||
return None;
|
return None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
debug!("Port-forwarding: found router at {}", gateway.addr);
|
debug!("Port-forwarding: found router at {}", gateway.addr);
|
||||||
|
@ -46,7 +46,7 @@ mod internal {
|
||||||
Ok(ip) => ip,
|
Ok(ip) => ip,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("Port-forwarding: failed to obtain external IP: {}", err);
|
error!("Port-forwarding: failed to obtain external IP: {}", err);
|
||||||
return None;
|
return None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Ok((port, timeout)) = Self::get_any_forwarding(&gateway, internal_addr, port) {
|
if let Ok((port, timeout)) = Self::get_any_forwarding(&gateway, internal_addr, port) {
|
||||||
|
@ -64,19 +64,19 @@ mod internal {
|
||||||
|
|
||||||
fn get_any_forwarding(gateway: &Gateway, addr: SocketAddrV4, port: u16) -> Result<(u16, u32), ()> {
|
fn get_any_forwarding(gateway: &Gateway, addr: SocketAddrV4, port: u16) -> Result<(u16, u32), ()> {
|
||||||
if let Ok(a) = Self::get_forwarding(gateway, addr, port) {
|
if let Ok(a) = Self::get_forwarding(gateway, addr, port) {
|
||||||
return Ok(a);
|
return Ok(a)
|
||||||
}
|
}
|
||||||
if let Ok(a) = Self::get_forwarding(gateway, addr, 0) {
|
if let Ok(a) = Self::get_forwarding(gateway, addr, 0) {
|
||||||
return Ok(a);
|
return Ok(a)
|
||||||
}
|
}
|
||||||
for i in 1..5 {
|
for i in 1..5 {
|
||||||
if let Ok(a) = Self::get_forwarding(gateway, addr, port + i) {
|
if let Ok(a) = Self::get_forwarding(gateway, addr, port + i) {
|
||||||
return Ok(a);
|
return Ok(a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
if let Ok(a) = Self::get_forwarding(gateway, addr, rand::random()) {
|
if let Ok(a) = Self::get_forwarding(gateway, addr, rand::random()) {
|
||||||
return Ok(a);
|
return Ok(a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
warn!("Failed to activate port forwarding");
|
warn!("Failed to activate port forwarding");
|
||||||
|
@ -125,20 +125,20 @@ mod internal {
|
||||||
pub fn check_extend(&mut self) {
|
pub fn check_extend(&mut self) {
|
||||||
if let Some(deadline) = self.next_extension {
|
if let Some(deadline) = self.next_extension {
|
||||||
if deadline > SystemTimeSource::now() {
|
if deadline > SystemTimeSource::now() {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
match self.gateway.add_port(
|
match self.gateway.add_port(
|
||||||
PortMappingProtocol::UDP,
|
PortMappingProtocol::UDP,
|
||||||
self.external_addr.port(),
|
self.external_addr.port(),
|
||||||
self.internal_addr,
|
self.internal_addr,
|
||||||
LEASE_TIME,
|
LEASE_TIME,
|
||||||
DESCRIPTION,
|
DESCRIPTION
|
||||||
) {
|
) {
|
||||||
Ok(()) => debug!("Port-forwarding: extended port forwarding"),
|
Ok(()) => debug!("Port-forwarding: extended port forwarding"),
|
||||||
Err(err) => debug!("Port-forwarding: failed to extend port forwarding: {}", err),
|
Err(err) => debug!("Port-forwarding: failed to extend port forwarding: {}", err)
|
||||||
};
|
};
|
||||||
self.next_extension = Some(SystemTimeSource::now() + Time::from(LEASE_TIME) - 60);
|
self.next_extension = Some(SystemTimeSource::now() + Time::from(LEASE_TIME) - 60);
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ mod internal {
|
||||||
fn deactivate(&self) {
|
fn deactivate(&self) {
|
||||||
match self.gateway.remove_port(PortMappingProtocol::UDP, self.external_addr.port()) {
|
match self.gateway.remove_port(PortMappingProtocol::UDP, self.external_addr.port()) {
|
||||||
Ok(()) => info!("Port-forwarding: successfully deactivated port forwarding"),
|
Ok(()) => info!("Port-forwarding: successfully deactivated port forwarding"),
|
||||||
Err(err) => debug!("Port-forwarding: failed to deactivate port forwarding: {}", err),
|
Err(err) => debug!("Port-forwarding: failed to deactivate port forwarding: {}", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
26
src/table.rs
26
src/table.rs
|
@ -4,25 +4,27 @@
|
||||||
|
|
||||||
use fnv::FnvHasher;
|
use fnv::FnvHasher;
|
||||||
use std::{
|
use std::{
|
||||||
cmp::min, collections::HashMap, hash::BuildHasherDefault, io, io::Write, marker::PhantomData, net::SocketAddr,
|
cmp::min, collections::HashMap, hash::BuildHasherDefault, io, io::Write, marker::PhantomData, net::SocketAddr
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
types::{Address, Range, RangeList},
|
types::{Address, Range, RangeList},
|
||||||
util::{addr_nice, Duration, Time, TimeSource},
|
util::{addr_nice, Duration, Time, TimeSource}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
type Hash = BuildHasherDefault<FnvHasher>;
|
type Hash = BuildHasherDefault<FnvHasher>;
|
||||||
|
|
||||||
|
|
||||||
struct CacheValue {
|
struct CacheValue {
|
||||||
peer: SocketAddr,
|
peer: SocketAddr,
|
||||||
timeout: Time,
|
timeout: Time
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ClaimEntry {
|
struct ClaimEntry {
|
||||||
peer: SocketAddr,
|
peer: SocketAddr,
|
||||||
claim: Range,
|
claim: Range,
|
||||||
timeout: Time,
|
timeout: Time
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ClaimTable<TS: TimeSource> {
|
pub struct ClaimTable<TS: TimeSource> {
|
||||||
|
@ -30,7 +32,7 @@ pub struct ClaimTable<TS: TimeSource> {
|
||||||
cache_timeout: Duration,
|
cache_timeout: Duration,
|
||||||
claims: Vec<ClaimEntry>,
|
claims: Vec<ClaimEntry>,
|
||||||
claim_timeout: Duration,
|
claim_timeout: Duration,
|
||||||
_dummy: PhantomData<TS>,
|
_dummy: PhantomData<TS>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TS: TimeSource> ClaimTable<TS> {
|
impl<TS: TimeSource> ClaimTable<TS> {
|
||||||
|
@ -55,7 +57,7 @@ impl<TS: TimeSource> ClaimTable<TS> {
|
||||||
entry.timeout = TS::now() + self.claim_timeout as Time;
|
entry.timeout = TS::now() + self.claim_timeout as Time;
|
||||||
claims.swap_remove(pos);
|
claims.swap_remove(pos);
|
||||||
if claims.is_empty() {
|
if claims.is_empty() {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
entry.timeout = 0
|
entry.timeout = 0
|
||||||
|
@ -90,7 +92,7 @@ impl<TS: TimeSource> ClaimTable<TS> {
|
||||||
pub fn lookup(&mut self, addr: Address) -> Option<SocketAddr> {
|
pub fn lookup(&mut self, addr: Address) -> Option<SocketAddr> {
|
||||||
// HOT PATH
|
// HOT PATH
|
||||||
if let Some(entry) = self.cache.get(&addr) {
|
if let Some(entry) = self.cache.get(&addr) {
|
||||||
return Some(entry.peer);
|
return Some(entry.peer)
|
||||||
}
|
}
|
||||||
// COLD PATH
|
// COLD PATH
|
||||||
let mut found = None;
|
let mut found = None;
|
||||||
|
@ -102,11 +104,11 @@ impl<TS: TimeSource> ClaimTable<TS> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(entry) = found {
|
if let Some(entry) = found {
|
||||||
self.cache.insert(
|
self.cache.insert(addr, CacheValue {
|
||||||
addr,
|
peer: entry.peer,
|
||||||
CacheValue { peer: entry.peer, timeout: min(TS::now() + self.cache_timeout as Time, entry.timeout) },
|
timeout: min(TS::now() + self.cache_timeout as Time, entry.timeout)
|
||||||
);
|
});
|
||||||
return Some(entry.peer);
|
return Some(entry.peer)
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,8 @@ use std::{
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicUsize, Ordering},
|
atomic::{AtomicUsize, Ordering},
|
||||||
Once,
|
Once
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
|
@ -19,9 +19,10 @@ pub use crate::{
|
||||||
net::MockSocket,
|
net::MockSocket,
|
||||||
payload::{Frame, Packet, Protocol},
|
payload::{Frame, Packet, Protocol},
|
||||||
types::Range,
|
types::Range,
|
||||||
util::{MockTimeSource, Time, TimeSource},
|
util::{MockTimeSource, Time, TimeSource}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static INIT_LOGGER: Once = Once::new();
|
static INIT_LOGGER: Once = Once::new();
|
||||||
|
|
||||||
pub fn init_debug_logger() {
|
pub fn init_debug_logger() {
|
||||||
|
@ -60,18 +61,20 @@ impl log::Log for DebugLogger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type TestNode<P> = GenericCloud<MockDevice, P, MockSocket, MockTimeSource>;
|
type TestNode<P> = GenericCloud<MockDevice, P, MockSocket, MockTimeSource>;
|
||||||
|
|
||||||
pub struct Simulator<P: Protocol> {
|
pub struct Simulator<P: Protocol> {
|
||||||
next_port: u16,
|
next_port: u16,
|
||||||
nodes: HashMap<SocketAddr, TestNode<P>>,
|
nodes: HashMap<SocketAddr, TestNode<P>>,
|
||||||
messages: VecDeque<(SocketAddr, SocketAddr, Vec<u8>)>,
|
messages: VecDeque<(SocketAddr, SocketAddr, Vec<u8>)>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type TapSimulator = Simulator<Frame>;
|
pub type TapSimulator = Simulator<Frame>;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub type TunSimulator = Simulator<Packet>;
|
pub type TunSimulator = Simulator<Packet>;
|
||||||
|
|
||||||
|
|
||||||
impl<P: Protocol> Simulator<P> {
|
impl<P: Protocol> Simulator<P> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
init_debug_logger();
|
init_debug_logger();
|
||||||
|
|
|
@ -6,8 +6,3 @@ mod common;
|
||||||
mod nat;
|
mod nat;
|
||||||
mod payload;
|
mod payload;
|
||||||
mod peers;
|
mod peers;
|
||||||
|
|
||||||
#[test]
|
|
||||||
async fn test_time_format() {
|
|
||||||
assert!(time::OffsetDateTime::try_now_local().is_ok());
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,13 +6,13 @@ use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
ops::AddAssign,
|
ops::AddAssign
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
engine::common::{Hash, STATS_INTERVAL},
|
engine::common::{Hash, STATS_INTERVAL},
|
||||||
types::Address,
|
types::Address,
|
||||||
util::{addr_nice, Bytes},
|
util::{addr_nice, Bytes}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ pub struct TrafficEntry {
|
||||||
pub in_packets_total: usize,
|
pub in_packets_total: usize,
|
||||||
pub in_bytes: u64,
|
pub in_bytes: u64,
|
||||||
pub in_packets: usize,
|
pub in_packets: usize,
|
||||||
pub idle_periods: usize,
|
pub idle_periods: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddAssign<&TrafficEntry> for TrafficEntry {
|
impl AddAssign<&TrafficEntry> for TrafficEntry {
|
||||||
|
@ -72,11 +72,12 @@ impl TrafficEntry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct TrafficStats {
|
pub struct TrafficStats {
|
||||||
peers: HashMap<SocketAddr, TrafficEntry, Hash>,
|
peers: HashMap<SocketAddr, TrafficEntry, Hash>,
|
||||||
payload: HashMap<(Address, Address), TrafficEntry, Hash>,
|
payload: HashMap<(Address, Address), TrafficEntry, Hash>,
|
||||||
pub dropped: TrafficEntry,
|
pub dropped: TrafficEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TrafficStats {
|
impl TrafficStats {
|
||||||
|
|
35
src/types.rs
35
src/types.rs
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::Error,
|
error::Error,
|
||||||
util::{bytes_to_hex, Encoder},
|
util::{bytes_to_hex, Encoder}
|
||||||
};
|
};
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
@ -13,17 +13,18 @@ use std::{
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
net::{Ipv4Addr, Ipv6Addr},
|
net::{Ipv4Addr, Ipv6Addr},
|
||||||
str::FromStr,
|
str::FromStr
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const NODE_ID_BYTES: usize = 16;
|
pub const NODE_ID_BYTES: usize = 16;
|
||||||
|
|
||||||
pub type NodeId = [u8; NODE_ID_BYTES];
|
pub type NodeId = [u8; NODE_ID_BYTES];
|
||||||
|
|
||||||
|
|
||||||
#[derive(Eq, Clone, Copy)]
|
#[derive(Eq, Clone, Copy)]
|
||||||
pub struct Address {
|
pub struct Address {
|
||||||
pub data: [u8; 16],
|
pub data: [u8; 16],
|
||||||
pub len: u8,
|
pub len: u8
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Address {
|
impl Address {
|
||||||
|
@ -36,7 +37,7 @@ impl Address {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn read_from_fixed<R: Read>(mut r: R, len: u8) -> Result<Address, Error> {
|
pub fn read_from_fixed<R: Read>(mut r: R, len: u8) -> Result<Address, Error> {
|
||||||
if len > 16 {
|
if len > 16 {
|
||||||
return Err(Error::Parse("Invalid address, too long"));
|
return Err(Error::Parse("Invalid address, too long"))
|
||||||
}
|
}
|
||||||
let mut data = [0; 16];
|
let mut data = [0; 16];
|
||||||
r.read_exact(&mut data[..len as usize]).map_err(|_| Error::Parse("Address too short"))?;
|
r.read_exact(&mut data[..len as usize]).map_err(|_| Error::Parse("Address too short"))?;
|
||||||
|
@ -56,6 +57,7 @@ impl Address {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl PartialEq for Address {
|
impl PartialEq for Address {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, rhs: &Self) -> bool {
|
fn eq(&self, rhs: &Self) -> bool {
|
||||||
|
@ -63,6 +65,7 @@ impl PartialEq for Address {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Hash for Address {
|
impl Hash for Address {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||||
|
@ -70,6 +73,7 @@ impl Hash for Address {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl fmt::Display for Address {
|
impl fmt::Display for Address {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
let d = &self.data;
|
let d = &self.data;
|
||||||
|
@ -104,7 +108,7 @@ impl FromStr for Address {
|
||||||
let ip = addr.octets();
|
let ip = addr.octets();
|
||||||
let mut res = [0; 16];
|
let mut res = [0; 16];
|
||||||
res[0..4].copy_from_slice(&ip);
|
res[0..4].copy_from_slice(&ip);
|
||||||
return Ok(Address { data: res, len: 4 });
|
return Ok(Address { data: res, len: 4 })
|
||||||
}
|
}
|
||||||
if let Ok(addr) = Ipv6Addr::from_str(text) {
|
if let Ok(addr) = Ipv6Addr::from_str(text) {
|
||||||
let segments = addr.segments();
|
let segments = addr.segments();
|
||||||
|
@ -112,7 +116,7 @@ impl FromStr for Address {
|
||||||
for i in 0..8 {
|
for i in 0..8 {
|
||||||
Encoder::write_u16(segments[i], &mut res[2 * i..]);
|
Encoder::write_u16(segments[i], &mut res[2 * i..]);
|
||||||
}
|
}
|
||||||
return Ok(Address { data: res, len: 16 });
|
return Ok(Address { data: res, len: 16 })
|
||||||
}
|
}
|
||||||
let parts: SmallVec<[&str; 10]> = text.split(':').collect();
|
let parts: SmallVec<[&str; 10]> = text.split(':').collect();
|
||||||
if parts.len() == 6 {
|
if parts.len() == 6 {
|
||||||
|
@ -120,16 +124,17 @@ impl FromStr for Address {
|
||||||
for i in 0..6 {
|
for i in 0..6 {
|
||||||
bytes[i] = u8::from_str_radix(parts[i], 16).map_err(|_| Error::Parse("Failed to parse mac"))?;
|
bytes[i] = u8::from_str_radix(parts[i], 16).map_err(|_| Error::Parse("Failed to parse mac"))?;
|
||||||
}
|
}
|
||||||
return Ok(Address { data: bytes, len: 6 });
|
return Ok(Address { data: bytes, len: 6 })
|
||||||
}
|
}
|
||||||
Err(Error::Parse("Failed to parse address"))
|
Err(Error::Parse("Failed to parse address"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
pub struct Range {
|
pub struct Range {
|
||||||
pub base: Address,
|
pub base: Address,
|
||||||
pub prefix_len: u8,
|
pub prefix_len: u8
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type RangeList = SmallVec<[Range; 4]>;
|
pub type RangeList = SmallVec<[Range; 4]>;
|
||||||
|
@ -137,14 +142,14 @@ pub type RangeList = SmallVec<[Range; 4]>;
|
||||||
impl Range {
|
impl Range {
|
||||||
pub fn matches(&self, addr: Address) -> bool {
|
pub fn matches(&self, addr: Address) -> bool {
|
||||||
if self.base.len != addr.len {
|
if self.base.len != addr.len {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
let mut match_len = 0;
|
let mut match_len = 0;
|
||||||
for i in 0..addr.len as usize {
|
for i in 0..addr.len as usize {
|
||||||
let m = addr.data[i] ^ self.base.data[i];
|
let m = addr.data[i] ^ self.base.data[i];
|
||||||
match_len += m.leading_zeros() as u8;
|
match_len += m.leading_zeros() as u8;
|
||||||
if m != 0 {
|
if m != 0 {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match_len >= self.prefix_len
|
match_len >= self.prefix_len
|
||||||
|
@ -170,7 +175,7 @@ impl FromStr for Range {
|
||||||
fn from_str(text: &str) -> Result<Self, Self::Err> {
|
fn from_str(text: &str) -> Result<Self, Self::Err> {
|
||||||
let pos = match text.find('/') {
|
let pos = match text.find('/') {
|
||||||
Some(pos) => pos,
|
Some(pos) => pos,
|
||||||
None => return Err(Error::Parse("Invalid range format")),
|
None => return Err(Error::Parse("Invalid range format"))
|
||||||
};
|
};
|
||||||
let prefix_len = u8::from_str(&text[pos + 1..]).map_err(|_| Error::Parse("Failed to parse prefix length"))?;
|
let prefix_len = u8::from_str(&text[pos + 1..]).map_err(|_| Error::Parse("Failed to parse prefix length"))?;
|
||||||
let base = Address::from_str(&text[..pos])?;
|
let base = Address::from_str(&text[..pos])?;
|
||||||
|
@ -190,6 +195,7 @@ impl fmt::Debug for Range {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
#[serde(rename = "normal")]
|
#[serde(rename = "normal")]
|
||||||
|
@ -199,7 +205,7 @@ pub enum Mode {
|
||||||
#[serde(rename = "switch")]
|
#[serde(rename = "switch")]
|
||||||
Switch,
|
Switch,
|
||||||
#[serde(rename = "router")]
|
#[serde(rename = "router")]
|
||||||
Router,
|
Router
|
||||||
}
|
}
|
||||||
impl fmt::Display for Mode {
|
impl fmt::Display for Mode {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
@ -207,7 +213,7 @@ impl fmt::Display for Mode {
|
||||||
Mode::Normal => write!(formatter, "normal"),
|
Mode::Normal => write!(formatter, "normal"),
|
||||||
Mode::Hub => write!(formatter, "hub"),
|
Mode::Hub => write!(formatter, "hub"),
|
||||||
Mode::Switch => write!(formatter, "switch"),
|
Mode::Switch => write!(formatter, "switch"),
|
||||||
Mode::Router => write!(formatter, "router"),
|
Mode::Router => write!(formatter, "router")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,11 +226,12 @@ impl FromStr for Mode {
|
||||||
"hub" => Self::Hub,
|
"hub" => Self::Hub,
|
||||||
"switch" => Self::Switch,
|
"switch" => Self::Switch,
|
||||||
"router" => Self::Router,
|
"router" => Self::Router,
|
||||||
_ => return Err("Unknown mode"),
|
_ => return Err("Unknown mode")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ fn configure_connectivity(config: &mut Config, mode: usize, theme: &ColorfulThem
|
||||||
Input::with_theme(theme)
|
Input::with_theme(theme)
|
||||||
.with_prompt("Peer addresses (comma separated)")
|
.with_prompt("Peer addresses (comma separated)")
|
||||||
.default(config.peers.join(","))
|
.default(config.peers.join(","))
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
);
|
);
|
||||||
if mode >= MODE_ADVANCED {
|
if mode >= MODE_ADVANCED {
|
||||||
config.port_forwarding = Confirm::with_theme(theme)
|
config.port_forwarding = Confirm::with_theme(theme)
|
||||||
|
@ -41,12 +41,6 @@ fn configure_connectivity(config: &mut Config, mode: usize, theme: &ColorfulThem
|
||||||
.interact()?;
|
.interact()?;
|
||||||
}
|
}
|
||||||
if mode == MODE_EXPERT {
|
if mode == MODE_EXPERT {
|
||||||
config.advertise_addresses = str_list(
|
|
||||||
Input::with_theme(theme)
|
|
||||||
.with_prompt("Advertise addresses (comma separated)")
|
|
||||||
.default(config.advertise_addresses.join(","))
|
|
||||||
.interact_text()?,
|
|
||||||
);
|
|
||||||
config.peer_timeout = Input::with_theme(theme)
|
config.peer_timeout = Input::with_theme(theme)
|
||||||
.with_prompt("Peer timeout (in seconds)")
|
.with_prompt("Peer timeout (in seconds)")
|
||||||
.default(config.peer_timeout)
|
.default(config.peer_timeout)
|
||||||
|
@ -60,11 +54,12 @@ fn configure_connectivity(config: &mut Config, mode: usize, theme: &ColorfulThem
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn configure_crypto(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), io::Error> {
|
fn configure_crypto(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> Result<(), io::Error> {
|
||||||
if (config.crypto.password.is_some() || config.crypto.private_key.is_some())
|
if (config.crypto.password.is_some() || config.crypto.private_key.is_some())
|
||||||
&& !Confirm::with_theme(theme).with_prompt("Create new crypto config?").default(false).interact()?
|
&& !Confirm::with_theme(theme).with_prompt("Create new crypto config?").default(false).interact()?
|
||||||
{
|
{
|
||||||
return Ok(());
|
return Ok(())
|
||||||
}
|
}
|
||||||
let mut use_password = true;
|
let mut use_password = true;
|
||||||
if mode >= MODE_ADVANCED {
|
if mode >= MODE_ADVANCED {
|
||||||
|
@ -80,7 +75,7 @@ fn configure_crypto(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
||||||
Password::with_theme(theme)
|
Password::with_theme(theme)
|
||||||
.with_prompt("Password")
|
.with_prompt("Password")
|
||||||
.with_confirmation("Confirm password", "Passwords do not match")
|
.with_confirmation("Confirm password", "Passwords do not match")
|
||||||
.interact()?,
|
.interact()?
|
||||||
);
|
);
|
||||||
config.crypto.private_key = None;
|
config.crypto.private_key = None;
|
||||||
config.crypto.public_key = None;
|
config.crypto.public_key = None;
|
||||||
|
@ -118,13 +113,13 @@ fn configure_crypto(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
||||||
info!("Public key: {}", pub_key);
|
info!("Public key: {}", pub_key);
|
||||||
(priv_key, pub_key)
|
(priv_key, pub_key)
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
config.crypto.trusted_keys = str_list(
|
config.crypto.trusted_keys = str_list(
|
||||||
Input::with_theme(theme)
|
Input::with_theme(theme)
|
||||||
.with_prompt("Trusted keys (public keys, comma separated)")
|
.with_prompt("Trusted keys (public keys, comma separated)")
|
||||||
.default(pub_key.clone())
|
.default(pub_key.clone())
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
);
|
);
|
||||||
config.crypto.private_key = Some(priv_key);
|
config.crypto.private_key = Some(priv_key);
|
||||||
config.crypto.public_key = Some(pub_key);
|
config.crypto.public_key = Some(pub_key);
|
||||||
|
@ -138,7 +133,7 @@ fn configure_crypto(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
||||||
("Unencrypted (dangerous)", unencrypted),
|
("Unencrypted (dangerous)", unencrypted),
|
||||||
("AES-128 in GCM mode", allowed_algos.contains(&&aead::AES_128_GCM)),
|
("AES-128 in GCM mode", allowed_algos.contains(&&aead::AES_128_GCM)),
|
||||||
("AES-256 in GCM mode", allowed_algos.contains(&&aead::AES_256_GCM)),
|
("AES-256 in GCM mode", allowed_algos.contains(&&aead::AES_256_GCM)),
|
||||||
("ChaCha20-Poly1305 (RFC 7539)", allowed_algos.contains(&&aead::CHACHA20_POLY1305)),
|
("ChaCha20-Poly1305 (RFC 7539)", allowed_algos.contains(&&aead::CHACHA20_POLY1305))
|
||||||
])
|
])
|
||||||
.interact()?;
|
.interact()?;
|
||||||
config.crypto.algorithms = vec![];
|
config.crypto.algorithms = vec![];
|
||||||
|
@ -161,7 +156,7 @@ fn configure_device(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
||||||
{
|
{
|
||||||
0 => device::Type::Tun,
|
0 => device::Type::Tun,
|
||||||
1 => device::Type::Tap,
|
1 => device::Type::Tap,
|
||||||
_ => unreachable!(),
|
_ => unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if mode == MODE_EXPERT {
|
if mode == MODE_EXPERT {
|
||||||
|
@ -171,7 +166,7 @@ fn configure_device(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
||||||
Input::with_theme(theme)
|
Input::with_theme(theme)
|
||||||
.with_prompt("Device path (empty for default)")
|
.with_prompt("Device path (empty for default)")
|
||||||
.default(config.device_path.as_ref().cloned().unwrap_or_default())
|
.default(config.device_path.as_ref().cloned().unwrap_or_default())
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
);
|
);
|
||||||
config.fix_rp_filter = Confirm::with_theme(theme)
|
config.fix_rp_filter = Confirm::with_theme(theme)
|
||||||
.with_prompt("Automatically fix insecure rp_filter settings")
|
.with_prompt("Automatically fix insecure rp_filter settings")
|
||||||
|
@ -184,7 +179,7 @@ fn configure_device(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
||||||
Mode::Normal => 0,
|
Mode::Normal => 0,
|
||||||
Mode::Router => 1,
|
Mode::Router => 1,
|
||||||
Mode::Switch => 2,
|
Mode::Switch => 2,
|
||||||
Mode::Hub => 3,
|
Mode::Hub => 3
|
||||||
})
|
})
|
||||||
.interact()?
|
.interact()?
|
||||||
{
|
{
|
||||||
|
@ -192,7 +187,7 @@ fn configure_device(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
||||||
1 => Mode::Router,
|
1 => Mode::Router,
|
||||||
2 => Mode::Switch,
|
2 => Mode::Switch,
|
||||||
3 => Mode::Hub,
|
3 => Mode::Hub,
|
||||||
_ => unreachable!(),
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
if config.mode == Mode::Switch {
|
if config.mode == Mode::Switch {
|
||||||
config.switch_timeout = Input::with_theme(theme)
|
config.switch_timeout = Input::with_theme(theme)
|
||||||
|
@ -210,7 +205,7 @@ fn configure_addresses(config: &mut Config, mode: usize, theme: &ColorfulTheme)
|
||||||
.with_prompt("Virtual IP address (e.g. 10.0.0.1, leave empty for none)")
|
.with_prompt("Virtual IP address (e.g. 10.0.0.1, leave empty for none)")
|
||||||
.allow_empty(true)
|
.allow_empty(true)
|
||||||
.default(config.ip.as_ref().cloned().unwrap_or_default())
|
.default(config.ip.as_ref().cloned().unwrap_or_default())
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
);
|
);
|
||||||
if config.device_type == device::Type::Tun {
|
if config.device_type == device::Type::Tun {
|
||||||
if mode >= MODE_ADVANCED {
|
if mode >= MODE_ADVANCED {
|
||||||
|
@ -225,7 +220,7 @@ fn configure_addresses(config: &mut Config, mode: usize, theme: &ColorfulTheme)
|
||||||
.with_prompt("Claim additional addresses (e.g. 10.0.0.0/24, comma separated, leave empty for none)")
|
.with_prompt("Claim additional addresses (e.g. 10.0.0.0/24, comma separated, leave empty for none)")
|
||||||
.allow_empty(true)
|
.allow_empty(true)
|
||||||
.default(config.claims.join(","))
|
.default(config.claims.join(","))
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -237,14 +232,14 @@ fn configure_addresses(config: &mut Config, mode: usize, theme: &ColorfulTheme)
|
||||||
.with_prompt("Interface setup command (leave empty for none)")
|
.with_prompt("Interface setup command (leave empty for none)")
|
||||||
.allow_empty(true)
|
.allow_empty(true)
|
||||||
.default(config.ifup.as_ref().cloned().unwrap_or_default())
|
.default(config.ifup.as_ref().cloned().unwrap_or_default())
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
);
|
);
|
||||||
config.ifdown = str_opt(
|
config.ifdown = str_opt(
|
||||||
Input::with_theme(theme)
|
Input::with_theme(theme)
|
||||||
.with_prompt("Interface tear down command (leave empty for none)")
|
.with_prompt("Interface tear down command (leave empty for none)")
|
||||||
.allow_empty(true)
|
.allow_empty(true)
|
||||||
.default(config.ifdown.as_ref().cloned().unwrap_or_default())
|
.default(config.ifdown.as_ref().cloned().unwrap_or_default())
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -272,20 +267,24 @@ fn configure_beacon(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
||||||
.interact()?
|
.interact()?
|
||||||
{
|
{
|
||||||
0 => None,
|
0 => None,
|
||||||
1 => Some(
|
1 => {
|
||||||
|
Some(
|
||||||
Input::with_theme(theme)
|
Input::with_theme(theme)
|
||||||
.with_prompt("File path")
|
.with_prompt("File path")
|
||||||
.default(config.beacon_store.clone().unwrap_or_default())
|
.default(config.beacon_store.clone().unwrap_or_default())
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
),
|
)
|
||||||
2 => Some(format!(
|
}
|
||||||
|
2 => {
|
||||||
|
Some(format!(
|
||||||
"|{}",
|
"|{}",
|
||||||
Input::<String>::with_theme(theme)
|
Input::<String>::with_theme(theme)
|
||||||
.with_prompt("Command")
|
.with_prompt("Command")
|
||||||
.default(config.beacon_store.clone().unwrap_or_default().trim_start_matches('|').to_string())
|
.default(config.beacon_store.clone().unwrap_or_default().trim_start_matches('|').to_string())
|
||||||
.interact_text()?
|
.interact_text()?
|
||||||
)),
|
))
|
||||||
_ => unreachable!(),
|
}
|
||||||
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
config.beacon_load = match Select::with_theme(theme)
|
config.beacon_load = match Select::with_theme(theme)
|
||||||
.with_prompt("How to load beacons")
|
.with_prompt("How to load beacons")
|
||||||
|
@ -302,20 +301,24 @@ fn configure_beacon(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
||||||
.interact()?
|
.interact()?
|
||||||
{
|
{
|
||||||
0 => None,
|
0 => None,
|
||||||
1 => Some(
|
1 => {
|
||||||
|
Some(
|
||||||
Input::with_theme(theme)
|
Input::with_theme(theme)
|
||||||
.with_prompt("File path")
|
.with_prompt("File path")
|
||||||
.default(config.beacon_load.clone().unwrap_or_default())
|
.default(config.beacon_load.clone().unwrap_or_default())
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
),
|
)
|
||||||
2 => Some(format!(
|
}
|
||||||
|
2 => {
|
||||||
|
Some(format!(
|
||||||
"|{}",
|
"|{}",
|
||||||
Input::<String>::with_theme(theme)
|
Input::<String>::with_theme(theme)
|
||||||
.with_prompt("Command")
|
.with_prompt("Command")
|
||||||
.default(config.beacon_load.clone().unwrap_or_default().trim_start_matches('|').to_string())
|
.default(config.beacon_load.clone().unwrap_or_default().trim_start_matches('|').to_string())
|
||||||
.interact_text()?
|
.interact_text()?
|
||||||
)),
|
))
|
||||||
_ => unreachable!(),
|
}
|
||||||
|
_ => unreachable!()
|
||||||
};
|
};
|
||||||
config.beacon_interval = Input::with_theme(theme)
|
config.beacon_interval = Input::with_theme(theme)
|
||||||
.with_prompt("Beacon interval (in seconds)")
|
.with_prompt("Beacon interval (in seconds)")
|
||||||
|
@ -326,7 +329,7 @@ fn configure_beacon(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
||||||
.with_prompt("Beacon password (leave empty for none)")
|
.with_prompt("Beacon password (leave empty for none)")
|
||||||
.with_confirmation("Confirm password", "Passwords do not match")
|
.with_confirmation("Confirm password", "Passwords do not match")
|
||||||
.allow_empty_password(true)
|
.allow_empty_password(true)
|
||||||
.interact()?,
|
.interact()?
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -339,7 +342,7 @@ fn configure_stats(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> R
|
||||||
.with_prompt("Write stats to file (empty to disable)")
|
.with_prompt("Write stats to file (empty to disable)")
|
||||||
.default(config.stats_file.clone().unwrap_or_default())
|
.default(config.stats_file.clone().unwrap_or_default())
|
||||||
.allow_empty(true)
|
.allow_empty(true)
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if mode == MODE_EXPERT {
|
if mode == MODE_EXPERT {
|
||||||
|
@ -353,14 +356,14 @@ fn configure_stats(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> R
|
||||||
.with_prompt("Statsd server URL")
|
.with_prompt("Statsd server URL")
|
||||||
.default(config.statsd_server.clone().unwrap_or_default())
|
.default(config.statsd_server.clone().unwrap_or_default())
|
||||||
.allow_empty(true)
|
.allow_empty(true)
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
);
|
);
|
||||||
config.statsd_prefix = str_opt(
|
config.statsd_prefix = str_opt(
|
||||||
Input::with_theme(theme)
|
Input::with_theme(theme)
|
||||||
.with_prompt("Statsd prefix")
|
.with_prompt("Statsd prefix")
|
||||||
.default(config.statsd_prefix.clone().unwrap_or_default())
|
.default(config.statsd_prefix.clone().unwrap_or_default())
|
||||||
.allow_empty(true)
|
.allow_empty(true)
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
config.statsd_server = None;
|
config.statsd_server = None;
|
||||||
|
@ -376,21 +379,21 @@ fn configure_process(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
||||||
.with_prompt("Run as different user (empty to disable)")
|
.with_prompt("Run as different user (empty to disable)")
|
||||||
.default(config.user.clone().unwrap_or_default())
|
.default(config.user.clone().unwrap_or_default())
|
||||||
.allow_empty(true)
|
.allow_empty(true)
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
);
|
);
|
||||||
config.group = str_opt(
|
config.group = str_opt(
|
||||||
Input::with_theme(theme)
|
Input::with_theme(theme)
|
||||||
.with_prompt("Run as different group (empty to disable)")
|
.with_prompt("Run as different group (empty to disable)")
|
||||||
.default(config.group.clone().unwrap_or_default())
|
.default(config.group.clone().unwrap_or_default())
|
||||||
.allow_empty(true)
|
.allow_empty(true)
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
);
|
);
|
||||||
config.pid_file = str_opt(
|
config.pid_file = str_opt(
|
||||||
Input::with_theme(theme)
|
Input::with_theme(theme)
|
||||||
.with_prompt("Write process id to file (empty to disable)")
|
.with_prompt("Write process id to file (empty to disable)")
|
||||||
.default(config.pid_file.clone().unwrap_or_default())
|
.default(config.pid_file.clone().unwrap_or_default())
|
||||||
.allow_empty(true)
|
.allow_empty(true)
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -408,7 +411,7 @@ fn configure_hooks(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> R
|
||||||
.with_prompt("Command to execute for all events (empty to disable)")
|
.with_prompt("Command to execute for all events (empty to disable)")
|
||||||
.default(config.hook.clone().unwrap_or_default())
|
.default(config.hook.clone().unwrap_or_default())
|
||||||
.allow_empty(true)
|
.allow_empty(true)
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
);
|
);
|
||||||
let mut hooks: HashMap<String, String> = Default::default();
|
let mut hooks: HashMap<String, String> = Default::default();
|
||||||
for event in &[
|
for event in &[
|
||||||
|
@ -418,14 +421,14 @@ fn configure_hooks(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> R
|
||||||
"device_setup",
|
"device_setup",
|
||||||
"device_configured",
|
"device_configured",
|
||||||
"vpn_started",
|
"vpn_started",
|
||||||
"vpn_shutdown",
|
"vpn_shutdown"
|
||||||
] {
|
] {
|
||||||
if let Some(cmd) = str_opt(
|
if let Some(cmd) = str_opt(
|
||||||
Input::with_theme(theme)
|
Input::with_theme(theme)
|
||||||
.with_prompt(format!("Command to execute for event '{}' (empty to disable)", event))
|
.with_prompt(format!("Command to execute for event '{}' (empty to disable)", event))
|
||||||
.default(config.hooks.get(*event).cloned().unwrap_or_default())
|
.default(config.hooks.get(*event).cloned().unwrap_or_default())
|
||||||
.allow_empty(true)
|
.allow_empty(true)
|
||||||
.interact_text()?,
|
.interact_text()?
|
||||||
) {
|
) {
|
||||||
hooks.insert(event.to_string(), cmd);
|
hooks.insert(event.to_string(), cmd);
|
||||||
}
|
}
|
||||||
|
@ -467,7 +470,7 @@ pub fn configure(name: Option<String>) -> Result<(), io::Error> {
|
||||||
config.merge_file(config_file);
|
config.merge_file(config_file);
|
||||||
}
|
}
|
||||||
if file.parent().unwrap().metadata()?.permissions().readonly() {
|
if file.parent().unwrap().metadata()?.permissions().readonly() {
|
||||||
return Err(io::Error::new(io::ErrorKind::PermissionDenied, "Config file not writable"));
|
return Err(io::Error::new(io::ErrorKind::PermissionDenied, "Config file not writable"))
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -486,7 +489,7 @@ pub fn configure(name: Option<String>) -> Result<(), io::Error> {
|
||||||
configure_process(&mut config, mode, &theme)?;
|
configure_process(&mut config, mode, &theme)?;
|
||||||
configure_hooks(&mut config, mode, &theme)?;
|
configure_hooks(&mut config, mode, &theme)?;
|
||||||
if Confirm::with_theme(&theme).with_prompt("Finish configuration?").default(true).interact()? {
|
if Confirm::with_theme(&theme).with_prompt("Finish configuration?").default(true).interact()? {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,7 +498,7 @@ pub fn configure(name: Option<String>) -> Result<(), io::Error> {
|
||||||
let f = fs::File::create(&file)?;
|
let f = fs::File::create(&file)?;
|
||||||
serde_yaml::to_writer(f, &config_file)
|
serde_yaml::to_writer(f, &config_file)
|
||||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Failed to parse config file"))?;
|
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Failed to parse config file"))?;
|
||||||
fs::set_permissions(file, fs::Permissions::from_mode(0o600))?;
|
fs::set_permissions(file, fs::Permissions::from_mode(600))?;
|
||||||
println!();
|
println!();
|
||||||
println!("Use the following commands to control your VPN:");
|
println!("Use the following commands to control your VPN:");
|
||||||
println!(" start the VPN: sudo service vpncloud@{0} start", name);
|
println!(" start the VPN: sudo service vpncloud@{0} start", name);
|
||||||
|
|
|
@ -94,7 +94,7 @@ fn serve_proxy_connection(stream: TcpStream) -> Result<(), io::Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_proxy(listen: &str) -> Result<(), io::Error> {
|
pub fn run_proxy(listen: &str) -> Result<(), io::Error> {
|
||||||
let addr = parse_listen(listen, 8080);
|
let addr = parse_listen(listen);
|
||||||
let server = TcpListener::bind(addr)?;
|
let server = TcpListener::bind(addr)?;
|
||||||
info!("Listening on ws://{}", server.local_addr()?);
|
info!("Listening on ws://{}", server.local_addr()?);
|
||||||
for stream in server.incoming() {
|
for stream in server.incoming() {
|
||||||
|
@ -121,7 +121,7 @@ impl ProxyConnection {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
/*
|
/*
|
||||||
if let Message::Binary(data) = io_error!(self.socket.read_message(), "Failed to read from ws proxy: {}")? {
|
if let Message::Binary(data) = io_error!(self.socket.read_message(), "Failed to read from ws proxy: {}")? {
|
||||||
return Ok(data);
|
return Ok(data)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue