diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index aeaa896..31018ae 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -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 diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 0a6dd85..d01adc6 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -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: diff --git a/.rpm/vpncloud.spec b/.rpm/vpncloud.spec index 2dbdc77..b09c36f 100644 --- a/.rpm/vpncloud.spec +++ b/.rpm/vpncloud.spec @@ -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 diff --git a/.whitesource b/.whitesource deleted file mode 100644 index 55b922e..0000000 --- a/.whitesource +++ /dev/null @@ -1,12 +0,0 @@ -{ - "scanSettings": { - "baseBranches": [] - }, - "checkRunSettings": { - "vulnerableCheckRunConclusionLevel": "failure", - "displayMode": "diff" - }, - "issueSettings": { - "minSeverityLevel": "LOW" - } -} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e63562..bfb16a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/Cargo.lock b/Cargo.lock index b407c24..9a4e930 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 7682df2..3160165 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "vpncloud" -version = "2.1.0" +version = "2.2.0" authors = ["Dennis Schwerdel "] 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"] ] diff --git a/README.md b/README.md index 64c7417..9666a72 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/assets/changelog.txt b/assets/changelog.txt index 1ebb0ac..e008230 100644 --- a/assets/changelog.txt +++ b/assets/changelog.txt @@ -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 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 Sat, 06 Feb 2020 13:13:00 +0100 + -- Dennis Schwerdel Sat, 06 Feb 2021 13:13:00 +0100 vpncloud (2.0.1) stable; urgency=medium diff --git a/assets/vpncloud.target b/assets/vpncloud.target new file mode 100644 index 0000000..1313447 --- /dev/null +++ b/assets/vpncloud.target @@ -0,0 +1,2 @@ +[Unit] +Description=VpnCloud target allowing to start/stop all vpncloud@.service instances at once diff --git a/assets/vpncloud@.service b/assets/vpncloud@.service index 7067953..5797232 100644 --- a/assets/vpncloud@.service +++ b/assets/vpncloud@.service @@ -2,6 +2,7 @@ Description=VpnCloud network '%I' After=network-online.target Wants=network-online.target +PartOf=vpncloud.target Documentation=man:vpncloud(1) [Service] diff --git a/contrib/asciinema-recorder/Dockerfile b/contrib/asciinema-recorder/Dockerfile index 53c152d..d342c20 100644 --- a/contrib/asciinema-recorder/Dockerfile +++ b/contrib/asciinema-recorder/Dockerfile @@ -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 \ No newline at end of file +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 diff --git a/contrib/asciinema-recorder/config b/contrib/asciinema-recorder/config index 5746cd5..6bfaf0c 100644 --- a/contrib/asciinema-recorder/config +++ b/contrib/asciinema-recorder/config @@ -1,3 +1,3 @@ [record] -command = /usr/bin/bash -l -idle_time_limit = 2.5 \ No newline at end of file +command = bash -l +idle_time_limit = 2.5 diff --git a/contrib/asciinema-recorder/record.sh b/contrib/asciinema-recorder/record.sh deleted file mode 100755 index c9d9da4..0000000 --- a/contrib/asciinema-recorder/record.sh +++ /dev/null @@ -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 "$@" \ No newline at end of file diff --git a/contrib/asciinema-recorder/recorder.sh b/contrib/asciinema-recorder/recorder.sh new file mode 100755 index 0000000..9b289b7 --- /dev/null +++ b/contrib/asciinema-recorder/recorder.sh @@ -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 diff --git a/contrib/aws/measurements/2021-04-06_2.2.0_perf.json b/contrib/aws/measurements/2021-04-06_2.2.0_perf.json new file mode 100644 index 0000000..7cb4ad5 --- /dev/null +++ b/contrib/aws/measurements/2021-04-06_2.2.0_perf.json @@ -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 + } + } + } +} \ No newline at end of file diff --git a/contrib/aws/performance.py b/contrib/aws/performance.py index 5ba95a5..15d7f8e 100755 --- a/contrib/aws/performance.py +++ b/contrib/aws/performance.py @@ -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.") \ No newline at end of file +eprint("done.") diff --git a/src/beacon.rs b/src/beacon.rs index ccf58d9..3f58044 100644 --- a/src/beacon.rs +++ b/src/beacon.rs @@ -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 { has_result: AtomicBool, - result: Mutex + result: Mutex, } #[derive(Clone)] pub struct BeaconSerializer { shared_key: Vec, future_peers: Arc>>, - _dummy_ts: PhantomData + _dummy_ts: PhantomData, } impl BeaconSerializer { @@ -55,7 +54,7 @@ impl BeaconSerializer { 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 BeaconSerializer { fn decrypt_data(&self, data: &mut Vec) -> 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 BeaconSerializer { 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 BeaconSerializer { 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 BeaconSerializer { 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 BeaconSerializer { 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>( - &self, path: P, ttl_hours: Option + &self, path: P, ttl_hours: Option, ) -> Result, io::Error> { let mut f = File::open(&path)?; let mut contents = String::new(); @@ -316,26 +315,22 @@ impl BeaconSerializer { } } - -#[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::::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::::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::::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::::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::::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::::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::::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::::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)); diff --git a/src/config.rs b/src/config.rs index 8173b7e..2c2e18b 100644 --- a/src/config.rs +++ b/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, + pub advertise_addresses: Vec, pub ifup: Option, pub ifdown: Option, @@ -53,7 +47,7 @@ pub struct Config { pub user: Option, pub group: Option, pub hook: Option, - pub hooks: HashMap + pub hooks: HashMap, } 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)>, detach: bool + &self, event: &'static str, envs: impl IntoIterator)>, 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, + /// A list of IP Addresses to advertise as our external address(s) + #[structopt(long = "advertise_addresses", use_delimiter = true)] + pub advertise_addresses: Vec, + /// A command to setup the network interface #[structopt(long)] pub ifup: Option, @@ -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 + name: Option, }, /// 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, pub ip: Option, + pub advertise_addresses: Option>, pub ifup: Option, pub ifdown: Option, @@ -679,7 +681,7 @@ pub struct ConfigFile { pub user: Option, pub group: Option, pub hook: Option, - pub hooks: HashMap + pub hooks: HashMap, } #[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()), diff --git a/src/crypto/core.rs b/src/crypto/core.rs index 8d16464..0a21dfa 100644 --- a/src/crypto/core.rs +++ b/src/crypto/core.rs @@ -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 { 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::()); diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs index c329001..4910294 100644 --- a/src/crypto/mod.rs +++ b/src/crypto/mod.rs @@ -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}; diff --git a/src/crypto/rotate.rs b/src/crypto/rotate.rs index 7355153..7f2b5a3 100644 --- a/src/crypto/rotate.rs +++ b/src/crypto/rotate.rs @@ -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>; type EcdhPrivateKey = EphemeralPrivateKey; - pub struct RotationMessage { message_id: u64, propose: EcdhPublicKey, - confirm: Option + confirm: Option, } impl RotationMessage { @@ -91,13 +89,13 @@ pub struct RotationState { pending: Option<(Key, EcdhPublicKey)>, // sent by remote, to be confirmed proposed: Option, // 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 { 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 { if self.is_empty() { - return None + return None; } let msg = RotationMessage::read_from(Cursor::new(self.message())).unwrap(); self.set_length(0); diff --git a/src/error.rs b/src/error.rs index c217b99..dc7177d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -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), } diff --git a/src/installer.rs b/src/installer.rs index 184d025..342e7e0 100644 --- a/src/installer.rs +++ b/src/installer.rs @@ -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))?; diff --git a/src/main.rs b/src/main.rs index 1f81d3a..ade0893 100644 --- a/src/main.rs +++ b/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> + file: Option>, } 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::(config, socket).await, Type::Tun => run::(config, socket).await } - return + return; } let socket = try_fail!(NetSocket::listen(&config.listen).await, "Failed to open socket {}: {}", config.listen); match config.device_type { diff --git a/src/messages.rs b/src/messages.rs index 928dd49..4c5f261 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -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, - 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, - 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: &mut Take, flags: u8) -> Result { 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: &mut Take) -> Result { 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::().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) -> 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::(0)?; @@ -257,7 +254,6 @@ impl NodeInfo { } } - impl Payload for NodeInfo { fn write_to(&self, buffer: &mut MsgBuffer) { self.encode(buffer) diff --git a/src/net.rs b/src/net.rs index 13a774b..c8922dd 100644 --- a/src/net.rs +++ b/src/net.rs @@ -40,15 +40,17 @@ pub trait Socket: Sized + Clone + Send + Sync + 'static { async fn create_port_forwarding(&self) -> Option; } -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::(), "Invalid port: {}"); SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), port) } else if addr.contains(':') { try_fail!(addr.parse::(), "Invalid address: {}: {}", addr) - } else { - let port = try_fail!(addr.parse::(), "Invalid port: {}"); + } else if let Ok(port) = addr.parse::() { SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), port) + } else { + let ip = try_fail!(addr.parse::(), "Invalid addr: {}"); + SocketAddr::new(ip, default_port) } } diff --git a/src/oldconfig.rs b/src/oldconfig.rs index 70fe744..0411e87 100644 --- a/src/oldconfig.rs +++ b/src/oldconfig.rs @@ -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, pub user: Option, - pub group: Option + pub group: Option, } 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(), } } } diff --git a/src/payload.rs b/src/payload.rs index 90163fb..6d42821 100644 --- a/src/payload.rs +++ b/src/payload.rs @@ -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()); -} \ No newline at end of file +} diff --git a/src/poll/epoll.rs b/src/poll/epoll.rs index 8224c65..b5f7b92 100644 --- a/src/poll/epoll.rs +++ b/src/poll/epoll.rs @@ -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!(), }) } } diff --git a/src/poll/mod.rs b/src/poll/mod.rs index 0bcf414..1a195c5 100644 --- a/src/poll/mod.rs +++ b/src/poll/mod.rs @@ -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), } diff --git a/src/port_forwarding.rs b/src/port_forwarding.rs index 733f680..6580494 100644 --- a/src/port_forwarding.rs +++ b/src/port_forwarding.rs @@ -19,7 +19,7 @@ mod internal { pub internal_addr: SocketAddrV4, pub external_addr: SocketAddrV4, gateway: Gateway, - pub next_extension: Option