mirror of https://github.com/dswd/vpncloud.git
Merge branch 'master' into threading
This commit is contained in:
commit
a7a7ab3a1f
|
@ -1,6 +1,18 @@
|
|||
# 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:0-1
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/rust:1
|
||||
|
||||
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
&& 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,6 +18,9 @@ jobs:
|
|||
name: Test Suite
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: szenius/set-timezone@v1.0
|
||||
with:
|
||||
timezoneLinux: Europe/Berlin
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
|
|
@ -28,6 +28,7 @@ mkdir -p %{buildroot}/lib/systemd/system
|
|||
mkdir -p %{buildroot}/usr/share/man/man1
|
||||
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.target %{buildroot}/lib/systemd/system/vpncloud.target
|
||||
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 -a * %{buildroot}
|
||||
|
@ -40,6 +41,7 @@ rm -rf %{buildroot}
|
|||
/etc/vpncloud/example.net.disabled
|
||||
/usr/bin/vpncloud
|
||||
/lib/systemd/system/vpncloud@.service
|
||||
/lib/systemd/system/vpncloud.target
|
||||
/lib/systemd/system/vpncloud-wsproxy.service
|
||||
/usr/share/man/man1/vpncloud.1.gz
|
||||
|
||||
|
|
12
.whitesource
12
.whitesource
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"scanSettings": {
|
||||
"baseBranches": []
|
||||
},
|
||||
"checkRunSettings": {
|
||||
"vulnerableCheckRunConclusionLevel": "failure",
|
||||
"displayMode": "diff"
|
||||
},
|
||||
"issueSettings": {
|
||||
"minSeverityLevel": "LOW"
|
||||
}
|
||||
}
|
|
@ -2,14 +2,15 @@
|
|||
|
||||
This project follows [semantic versioning](http://semver.org).
|
||||
|
||||
### UNRELEASED
|
||||
### v2.2.0 (2021-04-06)
|
||||
|
||||
- [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.50.0
|
||||
- [changed] Changed Rust version to 1.51.0
|
||||
- [changed] Updated dependencies
|
||||
- [changed] Change permissions of /etc/vpncloud
|
||||
|
||||
|
|
|
@ -102,9 +102,9 @@ checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
|
|||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.2"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
|
@ -171,9 +171,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "const_fn"
|
||||
version = "0.4.5"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6"
|
||||
checksum = "076a6803b0dacd6a88cfe64deba628b01533ff5ef265687e6938280c1afd0a28"
|
||||
|
||||
[[package]]
|
||||
name = "cpuid-bool"
|
||||
|
@ -240,35 +240,33 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.2"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d60ab4a8dba064f2fbb5aa270c28da5cf4bbd0e72dae1140a6b0353a779dbe00"
|
||||
checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"loom",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bae8f328835f8f5a6ceb6a7842a7f2d0c03692adb5c889347235d59194731fe3"
|
||||
checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if 1.0.0",
|
||||
"lazy_static",
|
||||
"loom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "1.1.5"
|
||||
version = "1.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9d58633299b24b515ac72a3f869f8b91306a3cec616a602843a383acd6f9e97"
|
||||
checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"csv-core",
|
||||
|
@ -325,9 +323,9 @@ checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
|||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.7"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e"
|
||||
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
|
@ -357,19 +355,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "generic-array"
|
||||
version = "0.14.4"
|
||||
|
@ -506,9 +491,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.47"
|
||||
version = "0.3.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65"
|
||||
checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
@ -521,9 +506,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.86"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
|
||||
checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
|
@ -549,17 +534,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "matches"
|
||||
version = "0.1.8"
|
||||
|
@ -574,9 +548,9 @@ checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
|
|||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.1"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
|
||||
checksum = "f83fb6581e8ed1f85fd45c116db8405483899489e38406156c25eb743554361d"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
@ -659,9 +633,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.6.0"
|
||||
version = "1.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ad167a2f54e832b82dbe003a046280dceffe5227b5f79e08e363a29638cfddd"
|
||||
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
|
@ -788,9 +762,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
@ -880,9 +854,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.4.3"
|
||||
version = "1.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
|
||||
checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19"
|
||||
dependencies = [
|
||||
"regex-syntax",
|
||||
]
|
||||
|
@ -898,9 +872,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.22"
|
||||
version = "0.6.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
|
||||
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
|
@ -935,12 +909,6 @@ dependencies = [
|
|||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
|
@ -956,12 +924,6 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
|
@ -985,9 +947,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.123"
|
||||
version = "1.0.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
|
||||
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
@ -1004,9 +966,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.123"
|
||||
version = "1.0.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
|
||||
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1015,9 +977,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.62"
|
||||
version = "1.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486"
|
||||
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -1099,9 +1061,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
|||
|
||||
[[package]]
|
||||
name = "standback"
|
||||
version = "0.2.15"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2beb4d1860a61f571530b3f855a1b538d0200f7871c63331ecd6f17b1f014f8"
|
||||
checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
@ -1187,9 +1149,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.60"
|
||||
version = "1.0.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
|
||||
checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1289,9 +1251,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tinytemplate"
|
||||
version = "1.2.0"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2ada8616fad06a2d0c455adc530de4ef57605a8120cc65da9653e0e9623ca74"
|
||||
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -1299,9 +1261,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.1.1"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023"
|
||||
checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
@ -1365,9 +1327,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.12.0"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
|
||||
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
|
@ -1437,9 +1399,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
|||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.2"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
|
@ -1449,7 +1411,7 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
|||
|
||||
[[package]]
|
||||
name = "vpncloud"
|
||||
version = "2.1.0"
|
||||
version = "2.2.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"byteorder",
|
||||
|
@ -1481,9 +1443,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.1"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
||||
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi",
|
||||
|
@ -1498,9 +1460,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.70"
|
||||
version = "0.2.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be"
|
||||
checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen-macro",
|
||||
|
@ -1508,9 +1470,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.70"
|
||||
version = "0.2.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7"
|
||||
checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
|
@ -1523,9 +1485,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.70"
|
||||
version = "0.2.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c"
|
||||
checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
@ -1533,9 +1495,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.70"
|
||||
version = "0.2.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385"
|
||||
checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1546,15 +1508,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.70"
|
||||
version = "0.2.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64"
|
||||
checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.47"
|
||||
version = "0.3.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3"
|
||||
checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
@ -1562,9 +1524,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wildmatch"
|
||||
version = "1.0.13"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2399814fda0d6999a6bfe9b5c7660d836334deb162a09db8b73d5b38fd8c40a"
|
||||
checksum = "7f44b95f62d34113cf558c93511ac93027e03e9c29a60dd0fd70e6e025c7270a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "vpncloud"
|
||||
version = "2.1.0"
|
||||
version = "2.2.0"
|
||||
authors = ["Dennis Schwerdel <schwerdel@googlemail.com>"]
|
||||
build = "build.rs"
|
||||
license = "GPL-3.0"
|
||||
|
@ -12,7 +12,7 @@ readme = "README.md"
|
|||
edition = "2018"
|
||||
|
||||
[package.metadata]
|
||||
toolchain = "1.50.0"
|
||||
toolchain = "1.51.0"
|
||||
upx_version = "3.96"
|
||||
|
||||
[dependencies]
|
||||
|
@ -86,6 +86,7 @@ assets = [
|
|||
["target/release/vpncloud", "/usr/bin/vpncloud", "755"],
|
||||
["assets/example.net.disabled", "/etc/vpncloud/example.net.disabled", "600"],
|
||||
["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"],
|
||||
["target/vpncloud.1.gz", "/usr/share/man/man1/vpncloud.1.gz", "644"]
|
||||
]
|
||||
|
|
|
@ -19,7 +19,7 @@ peers:
|
|||
- REMOTE_HOST:PORT
|
||||
```
|
||||
|
||||
For more information, please see the [Website](https://vpncloud.ddswd.de) or the [Forum](https://groups.google.com/forum/#!forum/vpncloud).
|
||||
For more information, please see the [Website](https://vpncloud.ddswd.de) or the [Discussions group](https://github.com/dswd/vpncloud/discussions).
|
||||
|
||||
|
||||
### Project Status
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
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
|
||||
|
||||
* [added] Support for websocket proxy mode
|
||||
|
@ -9,7 +23,7 @@ vpncloud (2.1.0) stable; urgency=medium
|
|||
* [fixed] Added missing peer address propagation
|
||||
* [fixed] Fixed problem with peer addresses without port
|
||||
|
||||
-- Dennis Schwerdel <schwerdel@googlemail.com> Sat, 06 Feb 2020 13:13:00 +0100
|
||||
-- Dennis Schwerdel <schwerdel@googlemail.com> Sat, 06 Feb 2021 13:13:00 +0100
|
||||
|
||||
vpncloud (2.0.1) stable; urgency=medium
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
[Unit]
|
||||
Description=VpnCloud target allowing to start/stop all vpncloud@.service instances at once
|
|
@ -2,6 +2,7 @@
|
|||
Description=VpnCloud network '%I'
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
PartOf=vpncloud.target
|
||||
Documentation=man:vpncloud(1)
|
||||
|
||||
[Service]
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
FROM ubuntu
|
||||
|
||||
RUN apt-get update && apt-get install -y asciinema
|
||||
RUN apt-get update && apt-get install -y asciinema locales bash iputils-ping
|
||||
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 /etc/vpncloud
|
||||
|
||||
WORKDIR /data
|
||||
ADD config /root/.asciinema/config
|
||||
RUN echo 'PS1="\[\e[00;34m\]\[\e[01;31m\]\u\[\e[00;01;34m\]@\[\e[00;34m\]node\[\e[01;31m\]:\[\e[00;34m\]\w\[\e[01;31m\]> \[\e[00m\]"' >> /root/.bashrc
|
||||
RUN echo 'PS1="\[\e[00;34m\]\[\e[01;31m\]\u\[\e[00;01;34m\]@\[\e[00;34m\]node\[\e[01;31m\]:\[\e[00;34m\]\w\[\e[01;31m\]> \[\e[00m\]"' >> /root/.bashrc
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[record]
|
||||
command = /usr/bin/bash -l
|
||||
idle_time_limit = 2.5
|
||||
command = bash -l
|
||||
idle_time_limit = 2.5
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
#!/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 "$@"
|
|
@ -0,0 +1,11 @@
|
|||
#!/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
|
|
@ -0,0 +1,165 @@
|
|||
{
|
||||
"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
|
||||
|
||||
FILE = "../target/release/vpncloud"
|
||||
VERSION = "2.1.0"
|
||||
FILE = "../../target/release/vpncloud"
|
||||
VERSION = "2.2.0"
|
||||
REGION = "eu-central-1"
|
||||
|
||||
env = EC2Environment(
|
||||
|
@ -113,4 +113,4 @@ name = "measurements/{date}_{version}_perf.json".format(date=date.today().strfti
|
|||
eprint('Storing results in {}'.format(name))
|
||||
with open(name, 'w') as fp:
|
||||
json.dump(results, fp, indent=2)
|
||||
eprint("done.")
|
||||
eprint("done.")
|
||||
|
|
|
@ -15,16 +15,15 @@ use std::{
|
|||
process::{Command, Stdio},
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc, Mutex
|
||||
Arc, Mutex,
|
||||
},
|
||||
thread
|
||||
thread,
|
||||
};
|
||||
|
||||
use super::util::{from_base62, to_base62, Encoder, TimeSource};
|
||||
use smallvec::SmallVec;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
|
||||
|
||||
const TYPE_BEGIN: u8 = 0;
|
||||
const TYPE_END: u8 = 1;
|
||||
const TYPE_DATA: u8 = 2;
|
||||
|
@ -40,14 +39,14 @@ fn sha512(data: &[u8]) -> SmallVec<[u8; 64]> {
|
|||
|
||||
struct FutureResult<T> {
|
||||
has_result: AtomicBool,
|
||||
result: Mutex<T>
|
||||
result: Mutex<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BeaconSerializer<TS> {
|
||||
shared_key: Vec<u8>,
|
||||
future_peers: Arc<FutureResult<Vec<SocketAddr>>>,
|
||||
_dummy_ts: PhantomData<TS>
|
||||
_dummy_ts: PhantomData<TS>,
|
||||
}
|
||||
|
||||
impl<TS: TimeSource> BeaconSerializer<TS> {
|
||||
|
@ -55,7 +54,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
|||
Self {
|
||||
shared_key: shared_key.to_owned(),
|
||||
future_peers: Arc::new(FutureResult { has_result: AtomicBool::new(false), result: Mutex::new(Vec::new()) }),
|
||||
_dummy_ts: PhantomData
|
||||
_dummy_ts: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,7 +104,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
|||
|
||||
fn decrypt_data(&self, data: &mut Vec<u8>) -> bool {
|
||||
if data.is_empty() {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
let seed = data.pop().unwrap() ^ self.get_keystream(TYPE_SEED, 0, 0)[0];
|
||||
self.mask_with_keystream(data as &mut [u8], TYPE_DATA, seed);
|
||||
|
@ -122,7 +121,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
|||
for p in peers {
|
||||
match *p {
|
||||
SocketAddr::V4(addr) => v4addrs.push(addr),
|
||||
SocketAddr::V6(addr) => v6addrs.push(addr)
|
||||
SocketAddr::V6(addr) => v6addrs.push(addr),
|
||||
}
|
||||
}
|
||||
// Add count of v4 addresses
|
||||
|
@ -158,23 +157,23 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
|||
let mut peers = Vec::new();
|
||||
let mut pos = 0;
|
||||
if data.len() < 4 {
|
||||
return peers
|
||||
return peers;
|
||||
}
|
||||
if !self.decrypt_data(&mut data) {
|
||||
return peers
|
||||
return peers;
|
||||
}
|
||||
let then = Wrapping(Encoder::read_u16(&data[pos..=pos + 1]));
|
||||
if let Some(ttl) = ttl_hours {
|
||||
let now = Wrapping(Self::now_hour_16());
|
||||
if now - then > Wrapping(ttl) && then - now > Wrapping(ttl) {
|
||||
return peers
|
||||
return peers;
|
||||
}
|
||||
}
|
||||
pos += 2;
|
||||
let v4count = data[pos] as usize;
|
||||
pos += 1;
|
||||
if v4count * 6 > data.len() - pos || (data.len() - pos - v4count * 6) % 18 > 0 {
|
||||
return peers
|
||||
return peers;
|
||||
}
|
||||
for _ in 0..v4count {
|
||||
assert!(data.len() >= pos + 6);
|
||||
|
@ -198,7 +197,7 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
|||
Ipv6Addr::new(ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]),
|
||||
port,
|
||||
0,
|
||||
0
|
||||
0,
|
||||
));
|
||||
peers.push(addr);
|
||||
}
|
||||
|
@ -262,14 +261,14 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
|||
peers.append(&mut self.peerlist_decode(&data[start_pos..end_pos], ttl_hours));
|
||||
pos = start_pos
|
||||
} else {
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
peers
|
||||
}
|
||||
|
||||
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> {
|
||||
let mut f = File::open(&path)?;
|
||||
let mut contents = String::new();
|
||||
|
@ -316,26 +315,22 @@ impl<TS: TimeSource> BeaconSerializer<TS> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)] use crate::util::MockTimeSource;
|
||||
#[cfg(test)] use std::str::FromStr;
|
||||
#[cfg(test)] use std::time::Duration;
|
||||
#[cfg(test)]
|
||||
use crate::util::MockTimeSource;
|
||||
#[cfg(test)]
|
||||
use std::str::FromStr;
|
||||
#[cfg(test)]
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
async fn encode() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
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));
|
||||
peers.push(SocketAddr::from_str("[::1]:5678").unwrap());
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -343,10 +338,7 @@ async fn encode() {
|
|||
async fn decode() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
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)));
|
||||
peers.push(SocketAddr::from_str("[::1]:5678").unwrap());
|
||||
assert_eq!(
|
||||
|
@ -359,10 +351,7 @@ async fn decode() {
|
|||
async fn decode_split() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
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!(
|
||||
format!("{:?}", peers),
|
||||
format!("{:?}", ser.decode("WsHI3-1E.WD:MB Yx\tvI\nTi(IL)Ir[m2]k9ügEäik22E", None))
|
||||
|
@ -377,10 +366,7 @@ async fn decode_split() {
|
|||
async fn decode_offset() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
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!(
|
||||
format!("{:?}", peers),
|
||||
format!("{:?}", ser.decode("Hello World: WsHI31EWDMBYxvITiILIrm2k9gEik22E! End of the World", None))
|
||||
|
@ -391,10 +377,7 @@ async fn decode_offset() {
|
|||
async fn decode_multiple() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
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!(
|
||||
format!("{:?}", peers),
|
||||
format!("{:?}", ser.decode("WsHI31HVpqxFNMNSPrvik22E WsHI34yOBcZIulKdtn2ik22E", None))
|
||||
|
@ -438,15 +421,11 @@ async fn decode_invalid() {
|
|||
assert_eq!(2, ser.decode("WsHI3WsHI31EWDMBYxvITiILIrm2k9gEik22Eik22E", None).len());
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
async fn encode_decode() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
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 peers2 = ser.decode(&data, None);
|
||||
assert_eq!(format!("{:?}", peers), format!("{:?}", peers2));
|
||||
|
@ -456,10 +435,7 @@ async fn encode_decode() {
|
|||
async fn encode_decode_file() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
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");
|
||||
assert!(ser.write_to_file(&peers, file.path()).is_ok());
|
||||
let peers2 = ser.read_from_file(file.path(), None);
|
||||
|
@ -471,10 +447,7 @@ async fn encode_decode_file() {
|
|||
async fn encode_decode_cmd() {
|
||||
MockTimeSource::set_time(2000 * 3600);
|
||||
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");
|
||||
assert!(ser.write_to_cmd(&peers, &format!("echo $beacon > {}", file.path().display())).is_ok());
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
|
|
126
src/config.rs
126
src/config.rs
|
@ -2,22 +2,15 @@
|
|||
// Copyright (C) 2015-2021 Dennis Schwerdel
|
||||
// This software is licensed under GPL-3 or newer (see LICENSE.md)
|
||||
|
||||
use super::{device::Type, types::Mode, util::Duration, util::run_cmd};
|
||||
use super::{device::Type, types::Mode, util::run_cmd, util::Duration};
|
||||
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};
|
||||
|
||||
pub const DEFAULT_PEER_TIMEOUT: u16 = 300;
|
||||
pub const DEFAULT_PORT: u16 = 3210;
|
||||
|
||||
|
||||
#[derive(Deserialize, Debug, PartialEq, Clone)]
|
||||
pub struct Config {
|
||||
pub device_type: Type,
|
||||
|
@ -27,6 +20,7 @@ pub struct Config {
|
|||
pub fix_rp_filter: bool,
|
||||
|
||||
pub ip: Option<String>,
|
||||
pub advertise_addresses: Vec<String>,
|
||||
pub ifup: Option<String>,
|
||||
pub ifdown: Option<String>,
|
||||
|
||||
|
@ -53,7 +47,7 @@ pub struct Config {
|
|||
pub user: Option<String>,
|
||||
pub group: Option<String>,
|
||||
pub hook: Option<String>,
|
||||
pub hooks: HashMap<String, String>
|
||||
pub hooks: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
|
@ -65,6 +59,7 @@ impl Default for Config {
|
|||
device_mtu: None,
|
||||
fix_rp_filter: false,
|
||||
ip: None,
|
||||
advertise_addresses: vec![],
|
||||
ifup: None,
|
||||
ifdown: None,
|
||||
crypto: CryptoConfig::default(),
|
||||
|
@ -89,7 +84,7 @@ impl Default for Config {
|
|||
user: None,
|
||||
group: None,
|
||||
hook: None,
|
||||
hooks: HashMap::new()
|
||||
hooks: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,6 +112,9 @@ impl Config {
|
|||
if let Some(val) = file.ip {
|
||||
self.ip = Some(val);
|
||||
}
|
||||
if let Some(mut val) = file.advertise_addresses {
|
||||
self.advertise_addresses.append(&mut val);
|
||||
}
|
||||
if let Some(val) = file.ifup {
|
||||
self.ifup = Some(val);
|
||||
}
|
||||
|
@ -227,6 +225,7 @@ impl Config {
|
|||
if let Some(val) = args.ifup {
|
||||
self.ifup = Some(val);
|
||||
}
|
||||
self.advertise_addresses.append(&mut args.advertise_addresses);
|
||||
if let Some(val) = args.ifdown {
|
||||
self.ifdown = Some(val);
|
||||
}
|
||||
|
@ -303,7 +302,7 @@ impl Config {
|
|||
if s.contains(':') {
|
||||
let pos = s.find(':').unwrap();
|
||||
let name = &s[..pos];
|
||||
let hook = &s[pos+1..];
|
||||
let hook = &s[pos + 1..];
|
||||
self.hooks.insert(name.to_string(), hook.to_string());
|
||||
} else {
|
||||
self.hook = Some(s);
|
||||
|
@ -319,14 +318,14 @@ impl Config {
|
|||
store: self.beacon_store,
|
||||
load: self.beacon_load,
|
||||
interval: Some(self.beacon_interval),
|
||||
password: self.beacon_password
|
||||
password: self.beacon_password,
|
||||
}),
|
||||
device: Some(ConfigFileDevice {
|
||||
name: Some(self.device_name),
|
||||
path: self.device_path,
|
||||
mtu: self.device_mtu,
|
||||
type_: Some(self.device_type),
|
||||
fix_rp_filter: Some(self.fix_rp_filter)
|
||||
fix_rp_filter: Some(self.fix_rp_filter),
|
||||
}),
|
||||
crypto: self.crypto,
|
||||
group: self.group,
|
||||
|
@ -334,6 +333,7 @@ impl Config {
|
|||
ifup: self.ifup,
|
||||
ifdown: self.ifdown,
|
||||
ip: self.ip,
|
||||
advertise_addresses: Some(self.advertise_addresses),
|
||||
keepalive: self.keepalive,
|
||||
listen: Some(self.listen),
|
||||
mode: Some(self.mode),
|
||||
|
@ -342,13 +342,10 @@ impl Config {
|
|||
pid_file: self.pid_file,
|
||||
port_forwarding: Some(self.port_forwarding),
|
||||
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),
|
||||
hook: self.hook,
|
||||
hooks: self.hooks
|
||||
hooks: self.hooks,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,7 +385,7 @@ impl Config {
|
|||
}
|
||||
|
||||
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;
|
||||
if let Some(ref s) = self.hook {
|
||||
|
@ -398,7 +395,7 @@ impl Config {
|
|||
script = Some(s);
|
||||
}
|
||||
if script.is_none() {
|
||||
return
|
||||
return;
|
||||
}
|
||||
let script = script.unwrap();
|
||||
let mut cmd = process::Command::new("sh");
|
||||
|
@ -518,6 +515,10 @@ pub struct Args {
|
|||
#[structopt(long)]
|
||||
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
|
||||
#[structopt(long)]
|
||||
pub ifup: Option<String>,
|
||||
|
@ -589,8 +590,8 @@ pub enum Command {
|
|||
#[structopt(alias = "wsproxy")]
|
||||
WsProxy {
|
||||
/// Websocket listen address IP:PORT
|
||||
#[structopt(long, short, default_value="3210")]
|
||||
listen: String
|
||||
#[structopt(long, short, default_value = "3210")]
|
||||
listen: String,
|
||||
},
|
||||
|
||||
/// Migrate an old config file
|
||||
|
@ -604,8 +605,8 @@ pub enum Command {
|
|||
/// Generate shell completions
|
||||
Completion {
|
||||
/// Shell to create completions for
|
||||
#[structopt(long, default_value="bash")]
|
||||
shell: Shell
|
||||
#[structopt(long, default_value = "bash")]
|
||||
shell: Shell,
|
||||
},
|
||||
|
||||
/// Edit the config of a network
|
||||
|
@ -613,7 +614,7 @@ pub enum Command {
|
|||
Config {
|
||||
/// Name of the network
|
||||
#[structopt(short, long)]
|
||||
name: Option<String>
|
||||
name: Option<String>,
|
||||
},
|
||||
|
||||
/// Install required utility files
|
||||
|
@ -621,8 +622,8 @@ pub enum Command {
|
|||
Install {
|
||||
/// Remove installed files again
|
||||
#[structopt(long)]
|
||||
uninstall: bool
|
||||
}
|
||||
uninstall: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
|
||||
|
@ -658,6 +659,7 @@ pub struct ConfigFile {
|
|||
pub device: Option<ConfigFileDevice>,
|
||||
|
||||
pub ip: Option<String>,
|
||||
pub advertise_addresses: Option<Vec<String>>,
|
||||
pub ifup: Option<String>,
|
||||
pub ifdown: Option<String>,
|
||||
|
||||
|
@ -679,7 +681,7 @@ pub struct ConfigFile {
|
|||
pub user: Option<String>,
|
||||
pub group: Option<String>,
|
||||
pub hook: Option<String>,
|
||||
pub hooks: HashMap<String, String>
|
||||
pub hooks: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -691,6 +693,9 @@ device:
|
|||
path: /dev/net/tun
|
||||
mtu: 1400
|
||||
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
|
||||
ifdown: 'true'
|
||||
peers:
|
||||
|
@ -727,6 +732,7 @@ statsd:
|
|||
fix_rp_filter: None
|
||||
}),
|
||||
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()),
|
||||
ifdown: Some("true".to_string()),
|
||||
crypto: CryptoConfig::default(),
|
||||
|
@ -776,6 +782,7 @@ async fn config_merge() {
|
|||
fix_rp_filter: None,
|
||||
}),
|
||||
ip: None,
|
||||
advertise_addresses: Some(vec![]),
|
||||
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
|
||||
ifdown: Some("true".to_string()),
|
||||
crypto: CryptoConfig::default(),
|
||||
|
@ -803,35 +810,39 @@ async fn config_merge() {
|
|||
prefix: Some("prefix".to_string()),
|
||||
}),
|
||||
hook: None,
|
||||
hooks: HashMap::new()
|
||||
});
|
||||
assert_eq!(config, Config {
|
||||
device_type: Type::Tun,
|
||||
device_name: "vpncloud%d".to_string(),
|
||||
device_path: None,
|
||||
ip: None,
|
||||
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
|
||||
ifdown: Some("true".to_string()),
|
||||
listen: "3210".to_string(),
|
||||
peers: vec!["remote.machine.foo:3210".to_string(), "remote.machine.bar:3210".to_string()],
|
||||
peer_timeout: 600,
|
||||
keepalive: Some(840),
|
||||
switch_timeout: 300,
|
||||
beacon_store: Some("/run/vpncloud.beacon.out".to_string()),
|
||||
beacon_load: Some("/run/vpncloud.beacon.in".to_string()),
|
||||
beacon_interval: 7200,
|
||||
beacon_password: Some("test123".to_string()),
|
||||
mode: Mode::Normal,
|
||||
port_forwarding: true,
|
||||
claims: vec!["10.0.1.0/24".to_string()],
|
||||
user: Some("nobody".to_string()),
|
||||
group: Some("nogroup".to_string()),
|
||||
pid_file: Some("/run/vpncloud.run".to_string()),
|
||||
stats_file: Some("/var/log/vpncloud.stats".to_string()),
|
||||
statsd_server: Some("example.com:1234".to_string()),
|
||||
statsd_prefix: Some("prefix".to_string()),
|
||||
..Default::default()
|
||||
hooks: HashMap::new(),
|
||||
});
|
||||
assert_eq!(
|
||||
config,
|
||||
Config {
|
||||
device_type: Type::Tun,
|
||||
device_name: "vpncloud%d".to_string(),
|
||||
device_path: None,
|
||||
ip: None,
|
||||
advertise_addresses: vec![],
|
||||
ifup: Some("ifconfig $IFNAME 10.0.1.1/16 mtu 1400 up".to_string()),
|
||||
ifdown: Some("true".to_string()),
|
||||
listen: "3210".to_string(),
|
||||
peers: vec!["remote.machine.foo:3210".to_string(), "remote.machine.bar:3210".to_string()],
|
||||
peer_timeout: 600,
|
||||
keepalive: Some(840),
|
||||
switch_timeout: 300,
|
||||
beacon_store: Some("/run/vpncloud.beacon.out".to_string()),
|
||||
beacon_load: Some("/run/vpncloud.beacon.in".to_string()),
|
||||
beacon_interval: 7200,
|
||||
beacon_password: Some("test123".to_string()),
|
||||
mode: Mode::Normal,
|
||||
port_forwarding: true,
|
||||
claims: vec!["10.0.1.0/24".to_string()],
|
||||
user: Some("nobody".to_string()),
|
||||
group: Some("nogroup".to_string()),
|
||||
pid_file: Some("/run/vpncloud.run".to_string()),
|
||||
stats_file: Some("/var/log/vpncloud.stats".to_string()),
|
||||
statsd_server: Some("example.com:1234".to_string()),
|
||||
statsd_prefix: Some("prefix".to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
config.merge_args(Args {
|
||||
type_: Some(Type::Tap),
|
||||
device: Some("vpncloud0".to_string()),
|
||||
|
@ -866,6 +877,7 @@ async fn config_merge() {
|
|||
device_path: Some("/dev/null".to_string()),
|
||||
device_mtu: None,
|
||||
fix_rp_filter: false,
|
||||
advertise_addresses: vec![],
|
||||
ip: None,
|
||||
ifup: Some("ifconfig $IFNAME 10.0.1.2/16 mtu 1400 up".to_string()),
|
||||
ifdown: Some("ifconfig $IFNAME down".to_string()),
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||
use ring::{
|
||||
aead::{self, LessSafeKey, UnboundKey},
|
||||
rand::{SecureRandom, SystemRandom}
|
||||
rand::{SecureRandom, SystemRandom},
|
||||
};
|
||||
use std::cell::UnsafeCell;
|
||||
|
||||
|
@ -57,12 +57,10 @@ use std::{
|
|||
|
||||
use crate::{error::Error, util::MsgBuffer};
|
||||
|
||||
|
||||
const NONCE_LEN: usize = 12;
|
||||
pub const TAG_LEN: usize = 16;
|
||||
pub const EXTRA_LEN: usize = 8;
|
||||
|
||||
|
||||
fn random_data(size: usize) -> Vec<u8> {
|
||||
let rand = SystemRandom::new();
|
||||
let mut data = vec![0; size];
|
||||
|
@ -98,7 +96,7 @@ impl Nonce {
|
|||
num = num.wrapping_add(1);
|
||||
self.0[i] = num;
|
||||
if num > 0 {
|
||||
return
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +107,7 @@ struct CryptoKey {
|
|||
send_nonce: Nonce,
|
||||
min_nonce: Nonce,
|
||||
next_min_nonce: Nonce,
|
||||
seen_nonce: Nonce
|
||||
seen_nonce: Nonce,
|
||||
}
|
||||
|
||||
impl CryptoKey {
|
||||
|
@ -121,7 +119,7 @@ impl CryptoKey {
|
|||
send_nonce,
|
||||
min_nonce: Nonce::zero(),
|
||||
next_min_nonce: Nonce::zero(),
|
||||
seen_nonce: Nonce::zero()
|
||||
seen_nonce: Nonce::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,7 +188,7 @@ impl CryptoCore {
|
|||
|
||||
fn decrypt_with_key(key: &mut CryptoKey, nonce: Nonce, data_and_tag: &mut [u8]) -> Result<(), Error> {
|
||||
if nonce < key.min_nonce {
|
||||
return Err(Error::Crypto("Old nonce rejected"))
|
||||
return Err(Error::Crypto("Old nonce rejected"));
|
||||
}
|
||||
// decrypt
|
||||
let crypto_nonce = aead::Nonce::assume_unique_for_key(*nonce.as_bytes());
|
||||
|
@ -273,7 +271,6 @@ pub fn test_speed(algo: &'static aead::Algorithm, max_time: &Duration) -> f64 {
|
|||
data as f64 / duration / 1_000_000.0
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -316,7 +313,6 @@ mod tests {
|
|||
test_encrypt_decrypt(&aead::CHACHA20_POLY1305)
|
||||
}
|
||||
|
||||
|
||||
fn test_tampering(algo: &'static aead::Algorithm) {
|
||||
let (sender, receiver) = create_dummy_pair(algo);
|
||||
let plain = random_data(1000);
|
||||
|
@ -447,7 +443,6 @@ mod tests {
|
|||
test_key_rotation(&aead::CHACHA20_POLY1305);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
async fn test_core_size() {
|
||||
assert_eq!(2400, mem::size_of::<CryptoCore>());
|
||||
|
|
|
@ -7,5 +7,6 @@ mod core;
|
|||
mod init;
|
||||
mod rotate;
|
||||
|
||||
pub use self::core::{EXTRA_LEN, TAG_LEN};
|
||||
pub use common::*;
|
||||
pub use self::core::{EXTRA_LEN, TAG_LEN};
|
||||
|
|
|
@ -34,20 +34,18 @@ use crate::{error::Error, util::MsgBuffer};
|
|||
use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
|
||||
use ring::{
|
||||
agreement::{agree_ephemeral, EphemeralPrivateKey, UnparsedPublicKey, X25519},
|
||||
rand::SystemRandom
|
||||
rand::SystemRandom,
|
||||
};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::io::{self, Cursor, Read, Write};
|
||||
|
||||
|
||||
type EcdhPublicKey = UnparsedPublicKey<SmallVec<[u8; 96]>>;
|
||||
type EcdhPrivateKey = EphemeralPrivateKey;
|
||||
|
||||
|
||||
pub struct RotationMessage {
|
||||
message_id: u64,
|
||||
propose: EcdhPublicKey,
|
||||
confirm: Option<EcdhPublicKey>
|
||||
confirm: Option<EcdhPublicKey>,
|
||||
}
|
||||
|
||||
impl RotationMessage {
|
||||
|
@ -91,13 +89,13 @@ pub struct RotationState {
|
|||
pending: Option<(Key, EcdhPublicKey)>, // sent by remote, to be confirmed
|
||||
proposed: Option<EcdhPrivateKey>, // my own, proposed but not confirmed
|
||||
message_id: u64,
|
||||
timeout: bool
|
||||
timeout: bool,
|
||||
}
|
||||
|
||||
pub struct RotatedKey {
|
||||
pub key: Key,
|
||||
pub id: u64,
|
||||
pub use_for_sending: bool
|
||||
pub use_for_sending: bool,
|
||||
}
|
||||
|
||||
impl RotationState {
|
||||
|
@ -155,7 +153,7 @@ impl RotationState {
|
|||
|
||||
pub fn process_message(&mut self, msg: RotationMessage) -> Option<RotatedKey> {
|
||||
if msg.message_id <= self.message_id {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
debug!("Received rotation message with id {}", msg.message_id);
|
||||
self.timeout = false;
|
||||
|
@ -167,7 +165,7 @@ impl RotationState {
|
|||
if let Some(peer_key) = msg.confirm {
|
||||
if let Some(private_key) = self.proposed.take() {
|
||||
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
|
||||
|
@ -183,7 +181,7 @@ impl RotationState {
|
|||
// Reconfirm last confirmed key
|
||||
Self::send(
|
||||
&RotationMessage { confirm: Some(confirmed_key.clone()), propose: proposed_key, message_id },
|
||||
out
|
||||
out,
|
||||
);
|
||||
} else {
|
||||
// First message has been lost
|
||||
|
@ -202,7 +200,7 @@ impl RotationState {
|
|||
self.proposed = Some(private_key);
|
||||
self.confirmed = Some((confirm_key.clone(), message_id));
|
||||
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 {
|
||||
// Nothing pending nor proposed, still waiting to receive message 1
|
||||
// Do nothing, peer will retry
|
||||
|
@ -221,7 +219,7 @@ mod tests {
|
|||
impl MsgBuffer {
|
||||
fn msg(&mut self) -> Option<RotationMessage> {
|
||||
if self.is_empty() {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
let msg = RotationMessage::read_from(Cursor::new(self.message())).unwrap();
|
||||
self.set_length(0);
|
||||
|
|
|
@ -6,7 +6,6 @@ use thiserror::Error;
|
|||
|
||||
use std::io;
|
||||
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
/// Crypto init error, this is recoverable
|
||||
|
@ -52,5 +51,5 @@ pub enum Error {
|
|||
Parse(&'static str),
|
||||
|
||||
#[error("Name can not be resolved: {0}")]
|
||||
NameUnresolvable(String)
|
||||
NameUnresolvable(String),
|
||||
}
|
||||
|
|
|
@ -4,11 +4,12 @@ use std::{
|
|||
fs::{self, File},
|
||||
io::Write,
|
||||
os::unix::fs::PermissionsExt,
|
||||
process::Command
|
||||
process::Command,
|
||||
};
|
||||
|
||||
const MANPAGE: &[u8] = include_bytes!("../target/vpncloud.1.gz");
|
||||
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 EXAMPLE_CONFIG: &[u8] = include_bytes!("../assets/example.net.disabled");
|
||||
|
||||
|
@ -22,10 +23,10 @@ pub fn install() -> Result<(), Error> {
|
|||
env::current_exe()
|
||||
.and_then(|p| fs::copy(p, "/usr/bin/vpncloud"))
|
||||
.map_err(|e| Error::FileIo("Failed to copy binary", e))?;
|
||||
fs::set_permissions("/usr/bin/vpncloud", fs::Permissions::from_mode(755))
|
||||
fs::set_permissions("/usr/bin/vpncloud", fs::Permissions::from_mode(0o755))
|
||||
.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::set_permissions("/etc/vpncloud", fs::Permissions::from_mode(700))
|
||||
fs::set_permissions("/etc/vpncloud", fs::Permissions::from_mode(0o700))
|
||||
.map_err(|e| Error::FileIo("Failed to set permissions for config folder", e))?;
|
||||
File::create("/etc/vpncloud/example.net.disabled")
|
||||
.and_then(|mut f| f.write_all(EXAMPLE_CONFIG))
|
||||
|
@ -36,6 +37,9 @@ pub fn install() -> Result<(), Error> {
|
|||
File::create("/lib/systemd/system/vpncloud@.service")
|
||||
.and_then(|mut f| f.write_all(SERVICE_FILE))
|
||||
.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")
|
||||
.and_then(|mut f| f.write_all(WS_PROXY_SERVICE_FILE))
|
||||
.map_err(|e| Error::FileIo("Failed to create wsporxy service file", e))?;
|
||||
|
@ -49,6 +53,8 @@ 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("/lib/systemd/system/vpncloud@.service")
|
||||
.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")
|
||||
.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))?;
|
||||
|
|
30
src/main.rs
30
src/main.rs
|
@ -6,7 +6,8 @@
|
|||
#[macro_use] extern crate serde;
|
||||
#[macro_use] extern crate tokio;
|
||||
|
||||
#[cfg(test)] extern crate tempfile;
|
||||
#[cfg(test)]
|
||||
extern crate tempfile;
|
||||
|
||||
#[macro_use]
|
||||
pub mod util;
|
||||
|
@ -19,6 +20,8 @@ pub mod config;
|
|||
pub mod crypto;
|
||||
pub mod device;
|
||||
pub mod error;
|
||||
#[cfg(feature = "installer")]
|
||||
pub mod installer;
|
||||
pub mod messages;
|
||||
pub mod net;
|
||||
pub mod oldconfig;
|
||||
|
@ -28,9 +31,10 @@ pub mod port_forwarding;
|
|||
pub mod table;
|
||||
pub mod traffic;
|
||||
pub mod types;
|
||||
#[cfg(feature = "wizard")] pub mod wizard;
|
||||
#[cfg(feature = "websocket")] pub mod wsproxy;
|
||||
#[cfg(feature = "installer")] pub mod installer;
|
||||
#[cfg(feature = "wizard")]
|
||||
pub mod wizard;
|
||||
#[cfg(feature = "websocket")]
|
||||
pub mod wsproxy;
|
||||
|
||||
use structopt::StructOpt;
|
||||
|
||||
|
@ -43,7 +47,7 @@ use std::{
|
|||
process,
|
||||
str::FromStr,
|
||||
sync::Mutex,
|
||||
thread
|
||||
thread,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -61,7 +65,7 @@ use crate::{
|
|||
use crate::wsproxy::ProxyConnection;
|
||||
|
||||
struct DualLogger {
|
||||
file: Option<Mutex<File>>
|
||||
file: Option<Mutex<File>>,
|
||||
}
|
||||
|
||||
impl DualLogger {
|
||||
|
@ -117,18 +121,18 @@ fn run_script(script: &str, ifname: &str) {
|
|||
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> {
|
||||
let (ip_str, len_str) = match addr.find('/') {
|
||||
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))?;
|
||||
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 netmask = Ipv4Addr::from(u32::max_value().checked_shl(32 - prefix_len as u32).unwrap());
|
||||
|
@ -233,7 +237,7 @@ async fn main() {
|
|||
let args: Args = Args::from_args();
|
||||
if args.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: {}");
|
||||
log::set_boxed_logger(Box::new(logger)).unwrap();
|
||||
|
@ -294,7 +298,7 @@ async fn main() {
|
|||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
return;
|
||||
}
|
||||
let mut config = Config::default();
|
||||
if let Some(ref file) = args.config {
|
||||
|
@ -319,7 +323,7 @@ async fn main() {
|
|||
debug!("Config: {:?}", config);
|
||||
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");
|
||||
return
|
||||
return;
|
||||
}
|
||||
#[cfg(feature = "websocket")]
|
||||
if config.listen.starts_with("ws://") {
|
||||
|
@ -328,7 +332,7 @@ async fn main() {
|
|||
Type::Tap => run::<payload::Frame, _>(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);
|
||||
match config.device_type {
|
||||
|
|
|
@ -6,30 +6,27 @@ use crate::{
|
|||
crypto::Payload,
|
||||
error::Error,
|
||||
types::{NodeId, Range, RangeList, NODE_ID_BYTES},
|
||||
util::MsgBuffer
|
||||
util::MsgBuffer,
|
||||
};
|
||||
use byteorder::{NetworkEndian, ReadBytesExt, WriteBytesExt};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::{
|
||||
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_NODE_INFO: u8 = 1;
|
||||
pub const MESSAGE_TYPE_KEEPALIVE: u8 = 2;
|
||||
pub const MESSAGE_TYPE_CLOSE: u8 = 0xff;
|
||||
|
||||
|
||||
pub type AddrList = SmallVec<[SocketAddr; 4]>;
|
||||
pub type PeerList = SmallVec<[PeerInfo; 16]>;
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct PeerInfo {
|
||||
pub node_id: Option<NodeId>,
|
||||
pub addrs: AddrList
|
||||
pub addrs: AddrList,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
@ -38,7 +35,7 @@ pub struct NodeInfo {
|
|||
pub peers: PeerList,
|
||||
pub claims: RangeList,
|
||||
pub peer_timeout: Option<u16>,
|
||||
pub addrs: AddrList
|
||||
pub addrs: AddrList,
|
||||
}
|
||||
|
||||
impl NodeInfo {
|
||||
|
@ -53,7 +50,7 @@ impl NodeInfo {
|
|||
let flags = r.read_u8()?;
|
||||
Self::read_addr_list_inner(r, flags)
|
||||
}
|
||||
|
||||
|
||||
fn read_addr_list_inner<R: Read>(r: &mut Take<R>, flags: u8) -> Result<AddrList, io::Error> {
|
||||
let num_ipv4_addrs = (flags & 0x07) as usize;
|
||||
let num_ipv6_addrs = (flags & 0x38) as usize / 8;
|
||||
|
@ -74,7 +71,7 @@ impl NodeInfo {
|
|||
}
|
||||
Ok(addrs)
|
||||
}
|
||||
|
||||
|
||||
fn decode_peer_list_part<R: Read>(r: &mut Take<R>) -> Result<PeerList, io::Error> {
|
||||
let mut peers = smallvec![];
|
||||
while r.limit() > 0 {
|
||||
|
@ -109,7 +106,7 @@ impl NodeInfo {
|
|||
loop {
|
||||
let part = r.read_u8().map_err(|_| Error::Message("Truncated message"))?;
|
||||
if part == Self::PART_END {
|
||||
break
|
||||
break;
|
||||
}
|
||||
let part_len = r.read_u16::<NetworkEndian>().map_err(|_| Error::Message("Truncated message"))? as usize;
|
||||
let mut rp = r.take(part_len as u64);
|
||||
|
@ -139,7 +136,7 @@ impl NodeInfo {
|
|||
}
|
||||
let node_id = match 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 })
|
||||
}
|
||||
|
@ -155,7 +152,7 @@ impl NodeInfo {
|
|||
for a in &p.addrs {
|
||||
match a {
|
||||
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 {
|
||||
|
@ -190,7 +187,7 @@ impl NodeInfo {
|
|||
for a in &self.addrs {
|
||||
match a {
|
||||
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 {
|
||||
|
@ -213,7 +210,7 @@ impl NodeInfo {
|
|||
}
|
||||
|
||||
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> {
|
||||
cursor.write_u8(part)?;
|
||||
cursor.write_u16::<NetworkEndian>(0)?;
|
||||
|
@ -257,7 +254,6 @@ impl NodeInfo {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl Payload for NodeInfo {
|
||||
fn write_to(&self, buffer: &mut MsgBuffer) {
|
||||
self.encode(buffer)
|
||||
|
|
|
@ -40,15 +40,17 @@ pub trait Socket: Sized + Clone + Send + Sync + 'static {
|
|||
async fn create_port_forwarding(&self) -> Option<PortForwarding>;
|
||||
}
|
||||
|
||||
pub fn parse_listen(addr: &str) -> SocketAddr {
|
||||
pub fn parse_listen(addr: &str, default_port: u16) -> SocketAddr {
|
||||
if let Some(addr) = addr.strip_prefix("*:") {
|
||||
let port = try_fail!(addr.parse::<u16>(), "Invalid port: {}");
|
||||
SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), port)
|
||||
} else if addr.contains(':') {
|
||||
try_fail!(addr.parse::<SocketAddr>(), "Invalid address: {}: {}", addr)
|
||||
} else {
|
||||
let port = try_fail!(addr.parse::<u16>(), "Invalid port: {}");
|
||||
} else if let Ok(port) = addr.parse::<u16>() {
|
||||
SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), port)
|
||||
} else {
|
||||
let ip = try_fail!(addr.parse::<IpAddr>(), "Invalid addr: {}");
|
||||
SocketAddr::new(ip, default_port)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ pub enum OldCryptoMethod {
|
|||
#[serde(rename = "aes256")]
|
||||
AES256,
|
||||
#[serde(rename = "aes128")]
|
||||
AES128
|
||||
AES128,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
|
||||
|
@ -57,7 +57,7 @@ pub struct OldConfigFile {
|
|||
#[serde(alias = "statsd-prefix")]
|
||||
pub statsd_prefix: Option<String>,
|
||||
pub user: Option<String>,
|
||||
pub group: Option<String>
|
||||
pub group: Option<String>,
|
||||
}
|
||||
|
||||
impl OldConfigFile {
|
||||
|
@ -89,7 +89,7 @@ impl OldConfigFile {
|
|||
interval: self.beacon_interval,
|
||||
load: self.beacon_load,
|
||||
store: self.beacon_store,
|
||||
password: self.shared_key.clone()
|
||||
password: self.shared_key.clone(),
|
||||
}),
|
||||
claims: self.subnets,
|
||||
crypto: CryptoConfig {
|
||||
|
@ -97,7 +97,7 @@ impl OldConfigFile {
|
|||
password: Some(self.shared_key.unwrap_or_else(|| "none".to_string())),
|
||||
private_key: None,
|
||||
public_key: None,
|
||||
trusted_keys: vec![]
|
||||
trusted_keys: vec![],
|
||||
},
|
||||
device: Some(ConfigFileDevice {
|
||||
fix_rp_filter: None,
|
||||
|
@ -110,6 +110,7 @@ impl OldConfigFile {
|
|||
ifdown: self.ifdown,
|
||||
ifup: self.ifup,
|
||||
ip: None,
|
||||
advertise_addresses: None,
|
||||
keepalive: self.keepalive,
|
||||
listen: self.listen.or(self.port.map(|p| format!("{}", p))),
|
||||
mode: self.mode,
|
||||
|
@ -122,7 +123,7 @@ impl OldConfigFile {
|
|||
switch_timeout: self.dst_timeout,
|
||||
user: self.user,
|
||||
hook: None,
|
||||
hooks: HashMap::new()
|
||||
hooks: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ impl Protocol for Frame {
|
|||
// treat vlan id 0x000 as untagged
|
||||
src.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 }))
|
||||
} else {
|
||||
|
@ -52,7 +52,6 @@ impl Protocol for Frame {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
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];
|
||||
|
@ -93,13 +92,13 @@ impl Protocol for Packet {
|
|||
fn parse(data: &[u8]) -> Result<(Address, Address), Error> {
|
||||
// HOT PATH
|
||||
if data.is_empty() {
|
||||
return Err(Error::Parse("Empty header"))
|
||||
return Err(Error::Parse("Empty header"));
|
||||
}
|
||||
let version = data[0] >> 4;
|
||||
match version {
|
||||
4 => {
|
||||
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 dst = Address::read_from_fixed(&data[16..], 4)?;
|
||||
|
@ -107,18 +106,17 @@ impl Protocol for Packet {
|
|||
}
|
||||
6 => {
|
||||
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 dst = Address::read_from_fixed(&data[24..], 16)?;
|
||||
Ok((src, dst))
|
||||
}
|
||||
_ => Err(Error::Parse("Invalid IP protocol version"))
|
||||
_ => Err(Error::Parse("Invalid IP protocol version")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
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];
|
||||
|
@ -131,7 +129,7 @@ async fn decode_ipv4_packet() {
|
|||
async fn decode_ipv6_packet() {
|
||||
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,
|
||||
4, 3, 2, 1
|
||||
4, 3, 2, 1,
|
||||
];
|
||||
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 });
|
||||
|
@ -158,4 +156,4 @@ async fn decode_invalid_packet() {
|
|||
4, 3, 2
|
||||
])
|
||||
.is_err());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ pub struct EpollWait {
|
|||
event: libc::epoll_event,
|
||||
socket: RawFd,
|
||||
device: RawFd,
|
||||
timeout: u32
|
||||
timeout: u32,
|
||||
}
|
||||
|
||||
impl EpollWait {
|
||||
|
@ -27,14 +27,14 @@ impl EpollWait {
|
|||
let mut event = libc::epoll_event { u64: 0, events: 0 };
|
||||
let poll_fd = unsafe { libc::epoll_create(3) };
|
||||
if poll_fd == -1 {
|
||||
return Err(io::Error::last_os_error())
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
for fd in &[socket, device] {
|
||||
event.u64 = *fd as u64;
|
||||
event.events = flags;
|
||||
let res = unsafe { libc::epoll_ctl(poll_fd, libc::EPOLL_CTL_ADD, *fd, &mut event) };
|
||||
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 })
|
||||
|
@ -63,7 +63,7 @@ impl Iterator for EpollWait {
|
|||
unreachable!()
|
||||
}
|
||||
}
|
||||
_ => unreachable!()
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,11 @@ mod epoll;
|
|||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub use self::epoll::EpollWait as WaitImpl;
|
||||
|
||||
|
||||
use std::io;
|
||||
|
||||
pub enum WaitResult {
|
||||
Timeout,
|
||||
Socket,
|
||||
Device,
|
||||
Error(io::Error)
|
||||
Error(io::Error),
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ mod internal {
|
|||
pub internal_addr: SocketAddrV4,
|
||||
pub external_addr: SocketAddrV4,
|
||||
gateway: Gateway,
|
||||
pub next_extension: Option<Time>
|
||||
pub next_extension: Option<Time>,
|
||||
}
|
||||
|
||||
impl PortForwarding {
|
||||
|
@ -32,11 +32,11 @@ mod internal {
|
|||
if err.kind() == io::ErrorKind::WouldBlock {
|
||||
// Why this code?
|
||||
info!("Port-forwarding: no router found");
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
}
|
||||
error!("Port-forwarding: failed to find router: {}", err);
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
};
|
||||
debug!("Port-forwarding: found router at {}", gateway.addr);
|
||||
|
@ -46,7 +46,7 @@ mod internal {
|
|||
Ok(ip) => ip,
|
||||
Err(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) {
|
||||
|
@ -64,19 +64,19 @@ mod internal {
|
|||
|
||||
fn get_any_forwarding(gateway: &Gateway, addr: SocketAddrV4, port: u16) -> Result<(u16, u32), ()> {
|
||||
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) {
|
||||
return Ok(a)
|
||||
return Ok(a);
|
||||
}
|
||||
for i in 1..5 {
|
||||
if let Ok(a) = Self::get_forwarding(gateway, addr, port + i) {
|
||||
return Ok(a)
|
||||
return Ok(a);
|
||||
}
|
||||
}
|
||||
for _ in 0..5 {
|
||||
if let Ok(a) = Self::get_forwarding(gateway, addr, rand::random()) {
|
||||
return Ok(a)
|
||||
return Ok(a);
|
||||
}
|
||||
}
|
||||
warn!("Failed to activate port forwarding");
|
||||
|
@ -125,20 +125,20 @@ mod internal {
|
|||
pub fn check_extend(&mut self) {
|
||||
if let Some(deadline) = self.next_extension {
|
||||
if deadline > SystemTimeSource::now() {
|
||||
return
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return
|
||||
return;
|
||||
}
|
||||
match self.gateway.add_port(
|
||||
PortMappingProtocol::UDP,
|
||||
self.external_addr.port(),
|
||||
self.internal_addr,
|
||||
LEASE_TIME,
|
||||
DESCRIPTION
|
||||
DESCRIPTION,
|
||||
) {
|
||||
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);
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ mod internal {
|
|||
fn deactivate(&self) {
|
||||
match self.gateway.remove_port(PortMappingProtocol::UDP, self.external_addr.port()) {
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
28
src/table.rs
28
src/table.rs
|
@ -4,27 +4,25 @@
|
|||
|
||||
use fnv::FnvHasher;
|
||||
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::{
|
||||
types::{Address, Range, RangeList},
|
||||
util::{addr_nice, Duration, Time, TimeSource}
|
||||
util::{addr_nice, Duration, Time, TimeSource},
|
||||
};
|
||||
|
||||
|
||||
type Hash = BuildHasherDefault<FnvHasher>;
|
||||
|
||||
|
||||
struct CacheValue {
|
||||
peer: SocketAddr,
|
||||
timeout: Time
|
||||
timeout: Time,
|
||||
}
|
||||
|
||||
struct ClaimEntry {
|
||||
peer: SocketAddr,
|
||||
claim: Range,
|
||||
timeout: Time
|
||||
timeout: Time,
|
||||
}
|
||||
|
||||
pub struct ClaimTable<TS: TimeSource> {
|
||||
|
@ -32,7 +30,7 @@ pub struct ClaimTable<TS: TimeSource> {
|
|||
cache_timeout: Duration,
|
||||
claims: Vec<ClaimEntry>,
|
||||
claim_timeout: Duration,
|
||||
_dummy: PhantomData<TS>
|
||||
_dummy: PhantomData<TS>,
|
||||
}
|
||||
|
||||
impl<TS: TimeSource> ClaimTable<TS> {
|
||||
|
@ -57,7 +55,7 @@ impl<TS: TimeSource> ClaimTable<TS> {
|
|||
entry.timeout = TS::now() + self.claim_timeout as Time;
|
||||
claims.swap_remove(pos);
|
||||
if claims.is_empty() {
|
||||
break
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
entry.timeout = 0
|
||||
|
@ -92,7 +90,7 @@ impl<TS: TimeSource> ClaimTable<TS> {
|
|||
pub fn lookup(&mut self, addr: Address) -> Option<SocketAddr> {
|
||||
// HOT PATH
|
||||
if let Some(entry) = self.cache.get(&addr) {
|
||||
return Some(entry.peer)
|
||||
return Some(entry.peer);
|
||||
}
|
||||
// COLD PATH
|
||||
let mut found = None;
|
||||
|
@ -104,11 +102,11 @@ impl<TS: TimeSource> ClaimTable<TS> {
|
|||
}
|
||||
}
|
||||
if let Some(entry) = found {
|
||||
self.cache.insert(addr, CacheValue {
|
||||
peer: entry.peer,
|
||||
timeout: min(TS::now() + self.cache_timeout as Time, entry.timeout)
|
||||
});
|
||||
return Some(entry.peer)
|
||||
self.cache.insert(
|
||||
addr,
|
||||
CacheValue { peer: entry.peer, timeout: min(TS::now() + self.cache_timeout as Time, entry.timeout) },
|
||||
);
|
||||
return Some(entry.peer);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -155,4 +153,4 @@ impl<TS: TimeSource> ClaimTable<TS> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: test
|
||||
// TODO: test
|
||||
|
|
|
@ -8,8 +8,8 @@ use std::{
|
|||
net::SocketAddr,
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
Once
|
||||
}
|
||||
Once,
|
||||
},
|
||||
};
|
||||
|
||||
pub use crate::{
|
||||
|
@ -19,10 +19,9 @@ pub use crate::{
|
|||
net::MockSocket,
|
||||
payload::{Frame, Packet, Protocol},
|
||||
types::Range,
|
||||
util::{MockTimeSource, Time, TimeSource}
|
||||
util::{MockTimeSource, Time, TimeSource},
|
||||
};
|
||||
|
||||
|
||||
static INIT_LOGGER: Once = Once::new();
|
||||
|
||||
pub fn init_debug_logger() {
|
||||
|
@ -61,20 +60,18 @@ impl log::Log for DebugLogger {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
type TestNode<P> = GenericCloud<MockDevice, P, MockSocket, MockTimeSource>;
|
||||
|
||||
pub struct Simulator<P: Protocol> {
|
||||
next_port: u16,
|
||||
nodes: HashMap<SocketAddr, TestNode<P>>,
|
||||
messages: VecDeque<(SocketAddr, SocketAddr, Vec<u8>)>
|
||||
messages: VecDeque<(SocketAddr, SocketAddr, Vec<u8>)>,
|
||||
}
|
||||
|
||||
pub type TapSimulator = Simulator<Frame>;
|
||||
#[allow(dead_code)]
|
||||
pub type TunSimulator = Simulator<Packet>;
|
||||
|
||||
|
||||
impl<P: Protocol> Simulator<P> {
|
||||
pub fn new() -> Self {
|
||||
init_debug_logger();
|
||||
|
|
|
@ -5,4 +5,9 @@
|
|||
mod common;
|
||||
mod nat;
|
||||
mod payload;
|
||||
mod peers;
|
||||
mod peers;
|
||||
|
||||
#[test]
|
||||
fn test_time_format() {
|
||||
assert!(time::OffsetDateTime::try_now_local().is_ok());
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@ use std::{
|
|||
collections::HashMap,
|
||||
io::{self, Write},
|
||||
net::SocketAddr,
|
||||
ops::AddAssign
|
||||
ops::AddAssign,
|
||||
};
|
||||
|
||||
use super::{
|
||||
engine::common::{Hash, STATS_INTERVAL},
|
||||
types::Address,
|
||||
util::{addr_nice, Bytes}
|
||||
util::{addr_nice, Bytes},
|
||||
};
|
||||
|
||||
|
||||
|
@ -26,7 +26,7 @@ pub struct TrafficEntry {
|
|||
pub in_packets_total: usize,
|
||||
pub in_bytes: u64,
|
||||
pub in_packets: usize,
|
||||
pub idle_periods: usize
|
||||
pub idle_periods: usize,
|
||||
}
|
||||
|
||||
impl AddAssign<&TrafficEntry> for TrafficEntry {
|
||||
|
@ -72,12 +72,11 @@ impl TrafficEntry {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TrafficStats {
|
||||
peers: HashMap<SocketAddr, TrafficEntry, Hash>,
|
||||
payload: HashMap<(Address, Address), TrafficEntry, Hash>,
|
||||
pub dropped: TrafficEntry
|
||||
pub dropped: TrafficEntry,
|
||||
}
|
||||
|
||||
impl TrafficStats {
|
||||
|
|
35
src/types.rs
35
src/types.rs
|
@ -4,7 +4,7 @@
|
|||
|
||||
use crate::{
|
||||
error::Error,
|
||||
util::{bytes_to_hex, Encoder}
|
||||
util::{bytes_to_hex, Encoder},
|
||||
};
|
||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||
use smallvec::SmallVec;
|
||||
|
@ -13,18 +13,17 @@ use std::{
|
|||
hash::{Hash, Hasher},
|
||||
io::{Read, Write},
|
||||
net::{Ipv4Addr, Ipv6Addr},
|
||||
str::FromStr
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
pub const NODE_ID_BYTES: usize = 16;
|
||||
|
||||
pub type NodeId = [u8; NODE_ID_BYTES];
|
||||
|
||||
|
||||
#[derive(Eq, Clone, Copy)]
|
||||
pub struct Address {
|
||||
pub data: [u8; 16],
|
||||
pub len: u8
|
||||
pub len: u8,
|
||||
}
|
||||
|
||||
impl Address {
|
||||
|
@ -37,7 +36,7 @@ impl Address {
|
|||
#[inline]
|
||||
pub fn read_from_fixed<R: Read>(mut r: R, len: u8) -> Result<Address, Error> {
|
||||
if len > 16 {
|
||||
return Err(Error::Parse("Invalid address, too long"))
|
||||
return Err(Error::Parse("Invalid address, too long"));
|
||||
}
|
||||
let mut data = [0; 16];
|
||||
r.read_exact(&mut data[..len as usize]).map_err(|_| Error::Parse("Address too short"))?;
|
||||
|
@ -57,7 +56,6 @@ impl Address {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl PartialEq for Address {
|
||||
#[inline]
|
||||
fn eq(&self, rhs: &Self) -> bool {
|
||||
|
@ -65,7 +63,6 @@ impl PartialEq for Address {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl Hash for Address {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||
|
@ -73,7 +70,6 @@ impl Hash for Address {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl fmt::Display for Address {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
let d = &self.data;
|
||||
|
@ -108,7 +104,7 @@ impl FromStr for Address {
|
|||
let ip = addr.octets();
|
||||
let mut res = [0; 16];
|
||||
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) {
|
||||
let segments = addr.segments();
|
||||
|
@ -116,7 +112,7 @@ impl FromStr for Address {
|
|||
for i in 0..8 {
|
||||
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();
|
||||
if parts.len() == 6 {
|
||||
|
@ -124,17 +120,16 @@ impl FromStr for Address {
|
|||
for i in 0..6 {
|
||||
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"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub struct Range {
|
||||
pub base: Address,
|
||||
pub prefix_len: u8
|
||||
pub prefix_len: u8,
|
||||
}
|
||||
|
||||
pub type RangeList = SmallVec<[Range; 4]>;
|
||||
|
@ -142,14 +137,14 @@ pub type RangeList = SmallVec<[Range; 4]>;
|
|||
impl Range {
|
||||
pub fn matches(&self, addr: Address) -> bool {
|
||||
if self.base.len != addr.len {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
let mut match_len = 0;
|
||||
for i in 0..addr.len as usize {
|
||||
let m = addr.data[i] ^ self.base.data[i];
|
||||
match_len += m.leading_zeros() as u8;
|
||||
if m != 0 {
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
match_len >= self.prefix_len
|
||||
|
@ -175,7 +170,7 @@ impl FromStr for Range {
|
|||
fn from_str(text: &str) -> Result<Self, Self::Err> {
|
||||
let pos = match text.find('/') {
|
||||
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 base = Address::from_str(&text[..pos])?;
|
||||
|
@ -195,7 +190,6 @@ impl fmt::Debug for Range {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Mode {
|
||||
#[serde(rename = "normal")]
|
||||
|
@ -205,7 +199,7 @@ pub enum Mode {
|
|||
#[serde(rename = "switch")]
|
||||
Switch,
|
||||
#[serde(rename = "router")]
|
||||
Router
|
||||
Router,
|
||||
}
|
||||
impl fmt::Display for Mode {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
|
@ -213,7 +207,7 @@ impl fmt::Display for Mode {
|
|||
Mode::Normal => write!(formatter, "normal"),
|
||||
Mode::Hub => write!(formatter, "hub"),
|
||||
Mode::Switch => write!(formatter, "switch"),
|
||||
Mode::Router => write!(formatter, "router")
|
||||
Mode::Router => write!(formatter, "router"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -226,12 +220,11 @@ impl FromStr for Mode {
|
|||
"hub" => Self::Hub,
|
||||
"switch" => Self::Switch,
|
||||
"router" => Self::Router,
|
||||
_ => return Err("Unknown mode")
|
||||
_ => return Err("Unknown mode"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
|
|
125
src/wizard.rs
125
src/wizard.rs
|
@ -32,7 +32,7 @@ fn configure_connectivity(config: &mut Config, mode: usize, theme: &ColorfulThem
|
|||
Input::with_theme(theme)
|
||||
.with_prompt("Peer addresses (comma separated)")
|
||||
.default(config.peers.join(","))
|
||||
.interact_text()?
|
||||
.interact_text()?,
|
||||
);
|
||||
if mode >= MODE_ADVANCED {
|
||||
config.port_forwarding = Confirm::with_theme(theme)
|
||||
|
@ -41,6 +41,12 @@ fn configure_connectivity(config: &mut Config, mode: usize, theme: &ColorfulThem
|
|||
.interact()?;
|
||||
}
|
||||
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)
|
||||
.with_prompt("Peer timeout (in seconds)")
|
||||
.default(config.peer_timeout)
|
||||
|
@ -54,12 +60,11 @@ fn configure_connectivity(config: &mut Config, mode: usize, theme: &ColorfulThem
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
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())
|
||||
&& !Confirm::with_theme(theme).with_prompt("Create new crypto config?").default(false).interact()?
|
||||
{
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
}
|
||||
let mut use_password = true;
|
||||
if mode >= MODE_ADVANCED {
|
||||
|
@ -75,7 +80,7 @@ fn configure_crypto(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
|||
Password::with_theme(theme)
|
||||
.with_prompt("Password")
|
||||
.with_confirmation("Confirm password", "Passwords do not match")
|
||||
.interact()?
|
||||
.interact()?,
|
||||
);
|
||||
config.crypto.private_key = None;
|
||||
config.crypto.public_key = None;
|
||||
|
@ -113,13 +118,13 @@ fn configure_crypto(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
|||
info!("Public key: {}", pub_key);
|
||||
(priv_key, pub_key)
|
||||
}
|
||||
_ => unreachable!()
|
||||
_ => unreachable!(),
|
||||
};
|
||||
config.crypto.trusted_keys = str_list(
|
||||
Input::with_theme(theme)
|
||||
.with_prompt("Trusted keys (public keys, comma separated)")
|
||||
.default(pub_key.clone())
|
||||
.interact_text()?
|
||||
.interact_text()?,
|
||||
);
|
||||
config.crypto.private_key = Some(priv_key);
|
||||
config.crypto.public_key = Some(pub_key);
|
||||
|
@ -133,7 +138,7 @@ fn configure_crypto(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
|||
("Unencrypted (dangerous)", unencrypted),
|
||||
("AES-128 in GCM mode", allowed_algos.contains(&&aead::AES_128_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()?;
|
||||
config.crypto.algorithms = vec![];
|
||||
|
@ -156,7 +161,7 @@ fn configure_device(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
|||
{
|
||||
0 => device::Type::Tun,
|
||||
1 => device::Type::Tap,
|
||||
_ => unreachable!()
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
if mode == MODE_EXPERT {
|
||||
|
@ -166,7 +171,7 @@ fn configure_device(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
|||
Input::with_theme(theme)
|
||||
.with_prompt("Device path (empty for default)")
|
||||
.default(config.device_path.as_ref().cloned().unwrap_or_default())
|
||||
.interact_text()?
|
||||
.interact_text()?,
|
||||
);
|
||||
config.fix_rp_filter = Confirm::with_theme(theme)
|
||||
.with_prompt("Automatically fix insecure rp_filter settings")
|
||||
|
@ -179,7 +184,7 @@ fn configure_device(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
|||
Mode::Normal => 0,
|
||||
Mode::Router => 1,
|
||||
Mode::Switch => 2,
|
||||
Mode::Hub => 3
|
||||
Mode::Hub => 3,
|
||||
})
|
||||
.interact()?
|
||||
{
|
||||
|
@ -187,7 +192,7 @@ fn configure_device(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
|||
1 => Mode::Router,
|
||||
2 => Mode::Switch,
|
||||
3 => Mode::Hub,
|
||||
_ => unreachable!()
|
||||
_ => unreachable!(),
|
||||
};
|
||||
if config.mode == Mode::Switch {
|
||||
config.switch_timeout = Input::with_theme(theme)
|
||||
|
@ -205,7 +210,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)")
|
||||
.allow_empty(true)
|
||||
.default(config.ip.as_ref().cloned().unwrap_or_default())
|
||||
.interact_text()?
|
||||
.interact_text()?,
|
||||
);
|
||||
if config.device_type == device::Type::Tun {
|
||||
if mode >= MODE_ADVANCED {
|
||||
|
@ -220,7 +225,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)")
|
||||
.allow_empty(true)
|
||||
.default(config.claims.join(","))
|
||||
.interact_text()?
|
||||
.interact_text()?,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
@ -232,14 +237,14 @@ fn configure_addresses(config: &mut Config, mode: usize, theme: &ColorfulTheme)
|
|||
.with_prompt("Interface setup command (leave empty for none)")
|
||||
.allow_empty(true)
|
||||
.default(config.ifup.as_ref().cloned().unwrap_or_default())
|
||||
.interact_text()?
|
||||
.interact_text()?,
|
||||
);
|
||||
config.ifdown = str_opt(
|
||||
Input::with_theme(theme)
|
||||
.with_prompt("Interface tear down command (leave empty for none)")
|
||||
.allow_empty(true)
|
||||
.default(config.ifdown.as_ref().cloned().unwrap_or_default())
|
||||
.interact_text()?
|
||||
.interact_text()?,
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
|
@ -267,24 +272,20 @@ fn configure_beacon(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
|||
.interact()?
|
||||
{
|
||||
0 => None,
|
||||
1 => {
|
||||
Some(
|
||||
Input::with_theme(theme)
|
||||
.with_prompt("File path")
|
||||
.default(config.beacon_store.clone().unwrap_or_default())
|
||||
.interact_text()?
|
||||
)
|
||||
}
|
||||
2 => {
|
||||
Some(format!(
|
||||
"|{}",
|
||||
Input::<String>::with_theme(theme)
|
||||
.with_prompt("Command")
|
||||
.default(config.beacon_store.clone().unwrap_or_default().trim_start_matches('|').to_string())
|
||||
.interact_text()?
|
||||
))
|
||||
}
|
||||
_ => unreachable!()
|
||||
1 => Some(
|
||||
Input::with_theme(theme)
|
||||
.with_prompt("File path")
|
||||
.default(config.beacon_store.clone().unwrap_or_default())
|
||||
.interact_text()?,
|
||||
),
|
||||
2 => Some(format!(
|
||||
"|{}",
|
||||
Input::<String>::with_theme(theme)
|
||||
.with_prompt("Command")
|
||||
.default(config.beacon_store.clone().unwrap_or_default().trim_start_matches('|').to_string())
|
||||
.interact_text()?
|
||||
)),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
config.beacon_load = match Select::with_theme(theme)
|
||||
.with_prompt("How to load beacons")
|
||||
|
@ -301,24 +302,20 @@ fn configure_beacon(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
|||
.interact()?
|
||||
{
|
||||
0 => None,
|
||||
1 => {
|
||||
Some(
|
||||
Input::with_theme(theme)
|
||||
.with_prompt("File path")
|
||||
.default(config.beacon_load.clone().unwrap_or_default())
|
||||
.interact_text()?
|
||||
)
|
||||
}
|
||||
2 => {
|
||||
Some(format!(
|
||||
"|{}",
|
||||
Input::<String>::with_theme(theme)
|
||||
.with_prompt("Command")
|
||||
.default(config.beacon_load.clone().unwrap_or_default().trim_start_matches('|').to_string())
|
||||
.interact_text()?
|
||||
))
|
||||
}
|
||||
_ => unreachable!()
|
||||
1 => Some(
|
||||
Input::with_theme(theme)
|
||||
.with_prompt("File path")
|
||||
.default(config.beacon_load.clone().unwrap_or_default())
|
||||
.interact_text()?,
|
||||
),
|
||||
2 => Some(format!(
|
||||
"|{}",
|
||||
Input::<String>::with_theme(theme)
|
||||
.with_prompt("Command")
|
||||
.default(config.beacon_load.clone().unwrap_or_default().trim_start_matches('|').to_string())
|
||||
.interact_text()?
|
||||
)),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
config.beacon_interval = Input::with_theme(theme)
|
||||
.with_prompt("Beacon interval (in seconds)")
|
||||
|
@ -329,7 +326,7 @@ fn configure_beacon(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
|||
.with_prompt("Beacon password (leave empty for none)")
|
||||
.with_confirmation("Confirm password", "Passwords do not match")
|
||||
.allow_empty_password(true)
|
||||
.interact()?
|
||||
.interact()?,
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
|
@ -342,7 +339,7 @@ fn configure_stats(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> R
|
|||
.with_prompt("Write stats to file (empty to disable)")
|
||||
.default(config.stats_file.clone().unwrap_or_default())
|
||||
.allow_empty(true)
|
||||
.interact_text()?
|
||||
.interact_text()?,
|
||||
);
|
||||
}
|
||||
if mode == MODE_EXPERT {
|
||||
|
@ -356,14 +353,14 @@ fn configure_stats(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> R
|
|||
.with_prompt("Statsd server URL")
|
||||
.default(config.statsd_server.clone().unwrap_or_default())
|
||||
.allow_empty(true)
|
||||
.interact_text()?
|
||||
.interact_text()?,
|
||||
);
|
||||
config.statsd_prefix = str_opt(
|
||||
Input::with_theme(theme)
|
||||
.with_prompt("Statsd prefix")
|
||||
.default(config.statsd_prefix.clone().unwrap_or_default())
|
||||
.allow_empty(true)
|
||||
.interact_text()?
|
||||
.interact_text()?,
|
||||
);
|
||||
} else {
|
||||
config.statsd_server = None;
|
||||
|
@ -379,21 +376,21 @@ fn configure_process(config: &mut Config, mode: usize, theme: &ColorfulTheme) ->
|
|||
.with_prompt("Run as different user (empty to disable)")
|
||||
.default(config.user.clone().unwrap_or_default())
|
||||
.allow_empty(true)
|
||||
.interact_text()?
|
||||
.interact_text()?,
|
||||
);
|
||||
config.group = str_opt(
|
||||
Input::with_theme(theme)
|
||||
.with_prompt("Run as different group (empty to disable)")
|
||||
.default(config.group.clone().unwrap_or_default())
|
||||
.allow_empty(true)
|
||||
.interact_text()?
|
||||
.interact_text()?,
|
||||
);
|
||||
config.pid_file = str_opt(
|
||||
Input::with_theme(theme)
|
||||
.with_prompt("Write process id to file (empty to disable)")
|
||||
.default(config.pid_file.clone().unwrap_or_default())
|
||||
.allow_empty(true)
|
||||
.interact_text()?
|
||||
.interact_text()?,
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
|
@ -411,7 +408,7 @@ fn configure_hooks(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> R
|
|||
.with_prompt("Command to execute for all events (empty to disable)")
|
||||
.default(config.hook.clone().unwrap_or_default())
|
||||
.allow_empty(true)
|
||||
.interact_text()?
|
||||
.interact_text()?,
|
||||
);
|
||||
let mut hooks: HashMap<String, String> = Default::default();
|
||||
for event in &[
|
||||
|
@ -421,14 +418,14 @@ fn configure_hooks(config: &mut Config, mode: usize, theme: &ColorfulTheme) -> R
|
|||
"device_setup",
|
||||
"device_configured",
|
||||
"vpn_started",
|
||||
"vpn_shutdown"
|
||||
"vpn_shutdown",
|
||||
] {
|
||||
if let Some(cmd) = str_opt(
|
||||
Input::with_theme(theme)
|
||||
.with_prompt(format!("Command to execute for event '{}' (empty to disable)", event))
|
||||
.default(config.hooks.get(*event).cloned().unwrap_or_default())
|
||||
.allow_empty(true)
|
||||
.interact_text()?
|
||||
.interact_text()?,
|
||||
) {
|
||||
hooks.insert(event.to_string(), cmd);
|
||||
}
|
||||
|
@ -470,7 +467,7 @@ pub fn configure(name: Option<String>) -> Result<(), io::Error> {
|
|||
config.merge_file(config_file);
|
||||
}
|
||||
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 {
|
||||
|
@ -489,7 +486,7 @@ pub fn configure(name: Option<String>) -> Result<(), io::Error> {
|
|||
configure_process(&mut config, mode, &theme)?;
|
||||
configure_hooks(&mut config, mode, &theme)?;
|
||||
if Confirm::with_theme(&theme).with_prompt("Finish configuration?").default(true).interact()? {
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -498,7 +495,7 @@ pub fn configure(name: Option<String>) -> Result<(), io::Error> {
|
|||
let f = fs::File::create(&file)?;
|
||||
serde_yaml::to_writer(f, &config_file)
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Failed to parse config file"))?;
|
||||
fs::set_permissions(file, fs::Permissions::from_mode(600))?;
|
||||
fs::set_permissions(file, fs::Permissions::from_mode(0o600))?;
|
||||
println!();
|
||||
println!("Use the following commands to control your VPN:");
|
||||
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> {
|
||||
let addr = parse_listen(listen);
|
||||
let addr = parse_listen(listen, 8080);
|
||||
let server = TcpListener::bind(addr)?;
|
||||
info!("Listening on ws://{}", server.local_addr()?);
|
||||
for stream in server.incoming() {
|
||||
|
@ -121,7 +121,7 @@ impl ProxyConnection {
|
|||
unimplemented!();
|
||||
/*
|
||||
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