Compare commits

..

3 Commits

Author SHA1 Message Date
Dennis Schwerdel 1f94d0deff Statsd support 2020-05-29 11:51:04 +02:00
Dennis Schwerdel ed0fdbc366 Change stats output format ot yaml 2020-05-29 10:04:14 +02:00
Dennis Schwerdel 02ccea326e Structopt instead of docopt 2020-05-29 08:37:29 +02:00
14 changed files with 589 additions and 239 deletions

View File

@ -9,6 +9,7 @@ This project follows [semantic versioning](http://semver.org).
- [changed] Warning for missing router is now info - [changed] Warning for missing router is now info
- [changed] New warning on claimed addresses in learning mode - [changed] New warning on claimed addresses in learning mode
- [changed] Updated dependencies - [changed] Updated dependencies
- [changed] Rewrote argument parsing
- [fixed] Fixed problem that could lead to 100% cpu consumption - [fixed] Fixed problem that could lead to 100% cpu consumption

232
Cargo.lock generated
View File

@ -1,11 +1,11 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]] [[package]]
name = "aho-corasick" name = "ansi_term"
version = "0.7.10" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -18,6 +18,16 @@ dependencies = [
"url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "base-x" name = "base-x"
version = "0.2.6" version = "0.2.6"
@ -53,6 +63,20 @@ name = "cfg-if"
version = "0.1.10" version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.33.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "daemonize" name = "daemonize"
version = "0.4.1" version = "0.4.1"
@ -67,17 +91,6 @@ name = "discard"
version = "1.0.4" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "docopt"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "dtoa" name = "dtoa"
version = "0.4.5" version = "0.4.5"
@ -98,6 +111,22 @@ dependencies = [
"wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "heck"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hermit-abi"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "http" name = "http"
version = "0.2.1" version = "0.2.1"
@ -137,10 +166,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.39" version = "0.3.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"wasm-bindgen 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -171,11 +200,6 @@ name = "matches"
version = "0.1.8" version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.14.1" version = "0.14.1"
@ -229,6 +253,30 @@ dependencies = [
"nix 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "proc-macro-error"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro-error-attr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "proc-macro-hack" name = "proc-macro-hack"
version = "0.5.16" version = "0.5.16"
@ -292,22 +340,6 @@ name = "redox_syscall"
version = "0.1.56" version = "0.1.56"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "regex"
version = "1.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.6.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "remove_dir_all" name = "remove_dir_all"
version = "0.5.2" version = "0.5.2"
@ -326,7 +358,7 @@ dependencies = [
"once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"web-sys 0.3.39 (registry+https://github.com/rust-lang/crates.io-index)", "web-sys 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -360,9 +392,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "serde" name = "serde"
version = "1.0.110" version = "1.0.110"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
@ -439,7 +468,7 @@ dependencies = [
"stdweb-derive 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "stdweb-derive 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"stdweb-internal-macros 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "stdweb-internal-macros 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"stdweb-internal-runtime 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "stdweb-internal-runtime 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -476,9 +505,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.9.3" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "structopt"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt-derive 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "structopt-derive"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-error 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.27" version = "1.0.27"
@ -489,6 +540,16 @@ dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "syn-mid"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.1.0" version = "3.1.0"
@ -503,11 +564,11 @@ dependencies = [
] ]
[[package]] [[package]]
name = "thread_local" name = "textwrap"
version = "1.0.1" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -561,6 +622,16 @@ dependencies = [
"smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "unicode-segmentation"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.0" version = "0.2.0"
@ -581,6 +652,11 @@ dependencies = [
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.2" version = "0.9.2"
@ -597,7 +673,6 @@ version = "1.3.0"
dependencies = [ dependencies = [
"cc 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)",
"daemonize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "daemonize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"igd 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
@ -611,6 +686,7 @@ dependencies = [
"serde_yaml 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)",
"signal 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "signal 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"siphasher 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "siphasher 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
"yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -623,16 +699,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.62" version = "0.2.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-macro 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-macro 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.62" version = "0.2.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bumpalo 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "bumpalo 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -641,42 +717,42 @@ dependencies = [
"proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-shared 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-shared 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.62" version = "0.2.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-macro-support 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-macro-support 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.62" version = "0.2.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-backend 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-backend 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-shared 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-shared 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.62" version = "0.2.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.39" version = "0.3.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"js-sys 0.3.39 (registry+https://github.com/rust-lang/crates.io-index)", "js-sys 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -720,8 +796,9 @@ dependencies = [
] ]
[metadata] [metadata]
"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum attohttpc 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "baf13118df3e3dce4b5ac930641343b91b656e4e72c8f8325838b01a4b1c9d45" "checksum attohttpc 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "baf13118df3e3dce4b5ac930641343b91b656e4e72c8f8325838b01a4b1c9d45"
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
"checksum base-x 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b20b618342cf9891c292c4f5ac2cde7287cc5c87e87e9c769d617793607dec1" "checksum base-x 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b20b618342cf9891c292c4f5ac2cde7287cc5c87e87e9c769d617793607dec1"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum boxfnonce 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5988cb1d626264ac94100be357308f29ff7cbdd3b36bda27f450a4ee3f713426" "checksum boxfnonce 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5988cb1d626264ac94100be357308f29ff7cbdd3b36bda27f450a4ee3f713426"
@ -729,23 +806,24 @@ dependencies = [
"checksum bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" "checksum bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1"
"checksum cc 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)" = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311" "checksum cc 1.0.54 (registry+https://github.com/rust-lang/crates.io-index)" = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
"checksum daemonize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70c24513e34f53b640819f0ac9f705b673fcf4006d7aab8778bee72ebfc89815" "checksum daemonize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70c24513e34f53b640819f0ac9f705b673fcf4006d7aab8778bee72ebfc89815"
"checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" "checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
"checksum docopt 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f525a586d310c87df72ebcd98009e57f1cc030c8c268305287a476beb653969"
"checksum dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" "checksum dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3"
"checksum fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" "checksum fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
"checksum hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71"
"checksum http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9" "checksum http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9"
"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" "checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
"checksum igd 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e8cad093dcfafa3770b737b9d570cf4d44177e90785385716d90322ef60ddc4" "checksum igd 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e8cad093dcfafa3770b737b9d570cf4d44177e90785385716d90322ef60ddc4"
"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" "checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
"checksum js-sys 0.3.39 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5a448de267e7358beaf4a5d849518fe9a0c13fce7afd44b06e68550e5562a7" "checksum js-sys 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "ce10c23ad2ea25ceca0093bd3192229da4c5b3c0f2de499c1ecac0d98d452177"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" "checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
"checksum linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" "checksum linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
"checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" "checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce"
"checksum nix 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dd0eaf8df8bab402257e0a5c17a254e4cc1f72a93588a1ddfb5d356c801aa7cb" "checksum nix 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dd0eaf8df8bab402257e0a5c17a254e4cc1f72a93588a1ddfb5d356c801aa7cb"
"checksum once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" "checksum once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d"
@ -753,6 +831,8 @@ dependencies = [
"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" "checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
"checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" "checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
"checksum privdrop 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "939fa7cbfef9c15c65cf2fb3ed57f3f2a14dca1757a556aa1ba4a7f998b2b479" "checksum privdrop 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "939fa7cbfef9c15c65cf2fb3ed57f3f2a14dca1757a556aa1ba4a7f998b2b479"
"checksum proc-macro-error 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98e9e4b82e0ef281812565ea4751049f1bdcdfccda7d3f459f2e138a40c08678"
"checksum proc-macro-error-attr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4f5444ead4e9935abd7f27dc51f7e852a0569ac888096d5ec2499470794e2e53"
"checksum proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" "checksum proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4"
"checksum proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "1502d12e458c49a4c9cbff560d0fe0060c252bc29799ed94ca2ed4bb665a0101" "checksum proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "1502d12e458c49a4c9cbff560d0fe0060c252bc29799ed94ca2ed4bb665a0101"
"checksum quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" "checksum quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea"
@ -761,8 +841,6 @@ dependencies = [
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
"checksum regex 1.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692"
"checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
"checksum ring 0.16.13 (registry+https://github.com/rust-lang/crates.io-index)" = "703516ae74571f24b465b4a1431e81e2ad51336cb0ded733a55a1aa3eccac196" "checksum ring 0.16.13 (registry+https://github.com/rust-lang/crates.io-index)" = "703516ae74571f24b465b4a1431e81e2ad51336cb0ded733a55a1aa3eccac196"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
@ -783,27 +861,33 @@ dependencies = [
"checksum stdweb-derive 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" "checksum stdweb-derive 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
"checksum stdweb-internal-macros 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" "checksum stdweb-internal-macros 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
"checksum stdweb-internal-runtime 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" "checksum stdweb-internal-runtime 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
"checksum strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum structopt 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "863246aaf5ddd0d6928dfeb1a9ca65f505599e4e1b399935ef7e75107516b4ef"
"checksum structopt-derive 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d239ca4b13aee7a2142e6795cbd69e457665ff8037aed33b3effdc430d2f927a"
"checksum syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "ef781e621ee763a2a40721a8861ec519cb76966aee03bb5d00adb6a31dc1c1de" "checksum syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "ef781e621ee763a2a40721a8861ec519cb76966aee03bb5d00adb6a31dc1c1de"
"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum time 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "3a51cadc5b1eec673a685ff7c33192ff7b7603d0b75446fb354939ee615acb15" "checksum time 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "3a51cadc5b1eec673a685ff7c33192ff7b7603d0b75446fb354939ee615acb15"
"checksum time-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9ae9b6e9f095bc105e183e3cd493d72579be3181ad4004fceb01adbe9eecab2d" "checksum time-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9ae9b6e9f095bc105e183e3cd493d72579be3181ad4004fceb01adbe9eecab2d"
"checksum time-macros-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa" "checksum time-macros-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" "checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4"
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" "checksum untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
"checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" "checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" "checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
"checksum wasm-bindgen 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "e3c7d40d09cdbf0f4895ae58cf57d92e1e57a9dd8ed2e8390514b54a47cc5551" "checksum wasm-bindgen 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)" = "4c2dc4aa152834bc334f506c1a06b866416a8b6697d5c9f75b9a689c8486def0"
"checksum wasm-bindgen-backend 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "c3972e137ebf830900db522d6c8fd74d1900dcfc733462e9a12e942b00b4ac94" "checksum wasm-bindgen-backend 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)" = "ded84f06e0ed21499f6184df0e0cb3494727b0c5da89534e0fcc55c51d812101"
"checksum wasm-bindgen-macro 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "2cd85aa2c579e8892442954685f0d801f9129de24fa2136b2c6a539c76b65776" "checksum wasm-bindgen-macro 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)" = "838e423688dac18d73e31edce74ddfac468e37b1506ad163ffaf0a46f703ffe3"
"checksum wasm-bindgen-macro-support 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "8eb197bd3a47553334907ffd2f16507b4f4f01bbec3ac921a7719e0decdfe72a" "checksum wasm-bindgen-macro-support 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)" = "3156052d8ec77142051a533cdd686cba889537b213f948cd1d20869926e68e92"
"checksum wasm-bindgen-shared 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "a91c2916119c17a8e316507afaaa2dd94b47646048014bbdf6bef098c1bb58ad" "checksum wasm-bindgen-shared 0.2.63 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ba19973a58daf4db6f352eda73dc0e289493cd29fb2632eb172085b6521acd"
"checksum web-sys 0.3.39 (registry+https://github.com/rust-lang/crates.io-index)" = "8bc359e5dd3b46cb9687a051d50a2fdd228e4ba7cf6fcf861a5365c3d671a642" "checksum web-sys 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "7b72fe77fd39e4bd3eaa4412fd299a0be6b3dfe9d2597e2f1c20beb968f41d17"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -13,7 +13,7 @@ edition = "2018"
[dependencies] [dependencies]
time = "0.2" time = "0.2"
docopt = "^1" structopt = "0.3"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
serde_yaml = "0.8" serde_yaml = "0.8"

View File

@ -28,7 +28,7 @@ use super::{
traffic::TrafficStats, traffic::TrafficStats,
types::{Error, HeaderMagic, NodeId, Protocol, Range, Table}, types::{Error, HeaderMagic, NodeId, Protocol, Range, Table},
udpmessage::{decode, encode, Message}, udpmessage::{decode, encode, Message},
util::{resolve, CtrlC, Duration, Time, TimeSource} util::{addr_nice, resolve, CtrlC, Duration, Time, TimeSource}
}; };
pub type Hash = BuildHasherDefault<FnvHasher>; pub type Hash = BuildHasherDefault<FnvHasher>;
@ -73,7 +73,7 @@ impl<TS: TimeSource> PeerList<TS> {
} }
} }
for addr in &del { for addr in &del {
info!("Forgot peer: {}", addr); info!("Forgot peer: {}", addr_nice(*addr));
if let Some(data) = self.peers.remove(addr) { if let Some(data) = self.peers.remove(addr) {
self.nodes.remove(&data.node_id); self.nodes.remove(&data.node_id);
self.addresses.remove(addr); self.addresses.remove(addr);
@ -113,7 +113,7 @@ impl<TS: TimeSource> PeerList<TS> {
#[inline] #[inline]
fn add(&mut self, node_id: NodeId, addr: SocketAddr, peer_timeout: u16) { fn add(&mut self, node_id: NodeId, addr: SocketAddr, peer_timeout: u16) {
if self.nodes.insert(node_id, addr).is_none() { if self.nodes.insert(node_id, addr).is_none() {
info!("New peer: {}", addr); info!("New peer: {}", addr_nice(addr));
let mut alt_addrs = vec![]; let mut alt_addrs = vec![];
if let SocketAddr::V6(v6_addr) = addr { if let SocketAddr::V6(v6_addr) = addr {
if let Some(ipv4) = v6_addr.ip().to_ipv4() { if let Some(ipv4) = v6_addr.ip().to_ipv4() {
@ -188,7 +188,7 @@ impl<TS: TimeSource> PeerList<TS> {
#[inline] #[inline]
fn remove(&mut self, addr: &SocketAddr) { fn remove(&mut self, addr: &SocketAddr) {
if let Some(data) = self.peers.remove(addr) { if let Some(data) = self.peers.remove(addr) {
info!("Removed peer: {}", addr); info!("Removed peer: {}", addr_nice(*addr));
self.nodes.remove(&data.node_id); self.nodes.remove(&data.node_id);
self.addresses.remove(addr); self.addresses.remove(addr);
for addr in data.alt_addrs { for addr in data.alt_addrs {
@ -199,10 +199,10 @@ impl<TS: TimeSource> PeerList<TS> {
#[inline] #[inline]
fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error> { fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error> {
writeln!(out, "Peers:")?; writeln!(out, "peers:")?;
let now = TS::now(); let now = TS::now();
for (addr, data) in &self.peers { for (addr, data) in &self.peers {
writeln!(out, " - {} (ttl: {} s)", addr, data.timeout - now)?; writeln!(out, " - \"{}\": {{ ttl_secs: {} }}", addr_nice(*addr), data.timeout - now)?;
} }
Ok(()) Ok(())
} }
@ -238,6 +238,7 @@ pub struct GenericCloud<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSou
update_freq: u16, update_freq: u16,
buffer_out: [u8; 64 * 1024], buffer_out: [u8; 64 * 1024],
stats_file: Option<File>, stats_file: Option<File>,
statsd_server: Option<String>,
next_housekeep: Time, next_housekeep: Time,
next_stats_out: Time, next_stats_out: Time,
next_beacon: Time, next_beacon: Time,
@ -277,6 +278,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
next_peerlist: now, next_peerlist: now,
update_freq, update_freq,
stats_file, stats_file,
statsd_server: config.statsd_server.clone(),
buffer_out: [0; 64 * 1024], buffer_out: [0; 64 * 1024],
next_housekeep: now, next_housekeep: now,
next_stats_out: now + STATS_INTERVAL, next_stats_out: now + STATS_INTERVAL,
@ -516,6 +518,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
if self.next_stats_out < now { if self.next_stats_out < now {
// Write out the statistics // Write out the statistics
self.write_out_stats().map_err(|err| Error::File("Failed to write stats file", err))?; self.write_out_stats().map_err(|err| Error::File("Failed to write stats file", err))?;
self.send_stats_to_statsd()?;
self.next_stats_out = now + STATS_INTERVAL; self.next_stats_out = now + STATS_INTERVAL;
self.traffic.period(Some(5)); self.traffic.period(Some(5));
} }
@ -575,7 +578,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
Ok(()) Ok(())
} }
/// Calculates, resets and writes out the statistics to a file /// Writes out the statistics to a file
fn write_out_stats(&mut self) -> Result<(), io::Error> { fn write_out_stats(&mut self) -> Result<(), io::Error> {
if let Some(ref mut f) = self.stats_file { if let Some(ref mut f) = self.stats_file {
debug!("Writing out stats"); debug!("Writing out stats");
@ -591,6 +594,61 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
Ok(()) Ok(())
} }
/// Sends the statistics to a statsd endpoint
fn send_stats_to_statsd(&mut self) -> Result<(), Error> {
if let Some(ref endpoint) = self.statsd_server {
let peer_traffic = self.traffic.total_peer_traffic();
let payload_traffic = self.traffic.total_payload_traffic();
let dropped = &self.traffic.dropped;
let msg = format!(
"peer_count:{}|g\ntable_entries:{}|g\n\
traffic.protocol.inbound.bytes:{}\n\
traffic.protocol.inbound.packets:{}\n\
traffic.protocol.outbound.bytes:{}\n\
traffic.protocol.outbound.packets:{}\n\
traffic.payload.inbound.bytes:{}\n\
traffic.payload.inbound.packets:{}\n\
traffic.payload.outbound.bytes:{}\n\
traffic.payload.outbound.packets:{}\n\
invalid_protocol_traffic.bytes:{}\n\
invalid_protocol_traffic.packets:{}\n\
dropped_payload.bytes:{}\n\
dropped_payload.packets:{}",
self.peers.len(),
self.table.len(),
peer_traffic.in_bytes,
peer_traffic.in_packets,
peer_traffic.out_bytes,
peer_traffic.out_packets,
payload_traffic.in_bytes,
payload_traffic.in_packets,
payload_traffic.out_bytes,
payload_traffic.out_packets,
dropped.in_bytes,
dropped.in_packets,
dropped.out_bytes,
dropped.out_packets
);
let msg_data = msg.as_bytes();
let addrs = resolve(endpoint)?;
if let Some(addr) = addrs.first() {
match self.socket.send(msg_data, *addr) {
Ok(written) if written == msg_data.len() => Ok(()),
Ok(_) => {
Err(Error::Socket(
"Sent out truncated packet",
io::Error::new(io::ErrorKind::Other, "truncated")
))
}
Err(e) => Err(Error::Socket("IOError when sending", e))
}?
} else {
error!("Failed to resolve statsd server {}", endpoint);
}
}
Ok(())
}
/// Handles payload data coming in from the local network device /// Handles payload data coming in from the local network device
/// ///
/// This method takes payload data received from the local device and parses it to obtain the /// This method takes payload data received from the local device and parses it to obtain the
@ -619,7 +677,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
if !self.peers.contains_addr(&addr) { if !self.peers.contains_addr(&addr) {
// If the peer is not actually connected, remove the entry in the table and try // If the peer is not actually connected, remove the entry in the table and try
// to reconnect. // to reconnect.
warn!("Destination for {} not found in peers: {}", dst, addr); warn!("Destination for {} not found in peers: {}", dst, addr_nice(addr));
self.table.remove(&dst); self.table.remove(&dst);
self.connect_sock(addr)?; self.connect_sock(addr)?;
} }
@ -631,6 +689,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
self.broadcast_msg(&mut msg)?; self.broadcast_msg(&mut msg)?;
} else { } else {
debug!("No destination for {} found, dropping", dst); debug!("No destination for {} found, dropping", dst);
self.traffic.count_dropped_payload(end - start);
} }
} }
} }
@ -714,7 +773,7 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
} else { } else {
self.peers.add(node_id, peer, peer_timeout); self.peers.add(node_id, peer, peer_timeout);
if self.learning && !ranges.is_empty() { if self.learning && !ranges.is_empty() {
warn!("Ignoring claimed addresses received from {} in learning mode.", peer); warn!("Ignoring claimed addresses received from {} in learning mode.", addr_nice(peer));
} else { } else {
for range in ranges { for range in ranges {
self.table.learn(range.base, Some(range.prefix_len), peer); self.table.learn(range.base, Some(range.prefix_len), peer);
@ -755,7 +814,8 @@ impl<D: Device, P: Protocol, T: Table, S: Socket, TS: TimeSource> GenericCloud<D
self.traffic.count_in_traffic(src, size); self.traffic.count_in_traffic(src, size);
self.handle_net_message(src, msg) self.handle_net_message(src, msg)
}) { }) {
error!("Error: {}, from: {}", e, src); error!("Error: {}, from: {}", e, addr_nice(src));
self.traffic.count_invalid_protocol(size);
} }
} }

View File

@ -58,6 +58,7 @@ pub struct Config {
pub daemonize: bool, pub daemonize: bool,
pub pid_file: Option<String>, pub pid_file: Option<String>,
pub stats_file: Option<String>, pub stats_file: Option<String>,
pub statsd_server: Option<String>,
pub user: Option<String>, pub user: Option<String>,
pub group: Option<String> pub group: Option<String>
} }
@ -87,6 +88,7 @@ impl Default for Config {
daemonize: false, daemonize: false,
pid_file: None, pid_file: None,
stats_file: None, stats_file: None,
statsd_server: None,
user: None, user: None,
group: None group: None
} }
@ -163,6 +165,9 @@ impl Config {
if let Some(val) = file.stats_file { if let Some(val) = file.stats_file {
self.stats_file = Some(val); self.stats_file = Some(val);
} }
if let Some(val) = file.statsd_server {
self.statsd_server = Some(val);
}
if let Some(val) = file.user { if let Some(val) = file.user {
self.user = Some(val); self.user = Some(val);
} }
@ -172,76 +177,79 @@ impl Config {
} }
pub fn merge_args(&mut self, mut args: Args) { pub fn merge_args(&mut self, mut args: Args) {
if let Some(val) = args.flag_type { if let Some(val) = args.type_ {
self.device_type = val; self.device_type = val;
} }
if let Some(val) = args.flag_device { if let Some(val) = args.device {
self.device_name = val; self.device_name = val;
} }
if let Some(val) = args.flag_device_path { if let Some(val) = args.device_path {
self.device_path = Some(val); self.device_path = Some(val);
} }
if let Some(val) = args.flag_ifup { if let Some(val) = args.ifup {
self.ifup = Some(val); self.ifup = Some(val);
} }
if let Some(val) = args.flag_ifdown { if let Some(val) = args.ifdown {
self.ifdown = Some(val); self.ifdown = Some(val);
} }
if let Some(val) = args.flag_crypto { if let Some(val) = args.crypto {
self.crypto = val; self.crypto = val;
} }
if let Some(val) = args.flag_shared_key { if let Some(val) = args.key {
self.shared_key = Some(val); self.shared_key = Some(val);
} }
if let Some(val) = args.flag_network_id { if let Some(val) = args.network_id {
warn!("The --network-id argument is deprecated, please use --magic instead."); warn!("The --network-id argument is deprecated, please use --magic instead.");
self.magic = Some(val); self.magic = Some(val);
} }
if let Some(val) = args.flag_magic { if let Some(val) = args.magic {
self.magic = Some(val); self.magic = Some(val);
} }
if let Some(val) = args.flag_listen { if let Some(val) = args.listen {
self.listen = parse_listen(&val); self.listen = parse_listen(&val);
} }
self.peers.append(&mut args.flag_connect); self.peers.append(&mut args.connect);
if let Some(val) = args.flag_peer_timeout { if let Some(val) = args.peer_timeout {
self.peer_timeout = val; self.peer_timeout = val;
} }
if let Some(val) = args.flag_keepalive { if let Some(val) = args.keepalive {
self.keepalive = Some(val); self.keepalive = Some(val);
} }
if let Some(val) = args.flag_beacon_store { if let Some(val) = args.beacon_store {
self.beacon_store = Some(val); self.beacon_store = Some(val);
} }
if let Some(val) = args.flag_beacon_load { if let Some(val) = args.beacon_load {
self.beacon_load = Some(val); self.beacon_load = Some(val);
} }
if let Some(val) = args.flag_beacon_interval { if let Some(val) = args.beacon_interval {
self.beacon_interval = val; self.beacon_interval = val;
} }
if let Some(val) = args.flag_mode { if let Some(val) = args.mode {
self.mode = val; self.mode = val;
} }
if let Some(val) = args.flag_dst_timeout { if let Some(val) = args.dst_timeout {
self.dst_timeout = val; self.dst_timeout = val;
} }
self.subnets.append(&mut args.flag_subnet); self.subnets.append(&mut args.subnets);
if args.flag_no_port_forwarding { if args.no_port_forwarding {
self.port_forwarding = false; self.port_forwarding = false;
} }
if args.flag_daemon { if args.daemon {
self.daemonize = true; self.daemonize = true;
} }
if let Some(val) = args.flag_pid_file { if let Some(val) = args.pid_file {
self.pid_file = Some(val); self.pid_file = Some(val);
} }
if let Some(val) = args.flag_stats_file { if let Some(val) = args.stats_file {
self.stats_file = Some(val); self.stats_file = Some(val);
} }
if let Some(val) = args.flag_user { if let Some(val) = args.statsd_server {
self.statsd_server = Some(val);
}
if let Some(val) = args.user {
self.user = Some(val); self.user = Some(val);
} }
if let Some(val) = args.flag_group { if let Some(val) = args.group {
self.group = Some(val); self.group = Some(val);
} }
} }
@ -298,6 +306,7 @@ pub struct ConfigFile {
pub port_forwarding: Option<bool>, pub port_forwarding: Option<bool>,
pub pid_file: Option<String>, pub pid_file: Option<String>,
pub stats_file: Option<String>, pub stats_file: Option<String>,
pub statsd_server: Option<String>,
pub user: Option<String>, pub user: Option<String>,
pub group: Option<String> pub group: Option<String>
} }
@ -332,6 +341,7 @@ user: nobody
group: nogroup group: nogroup
pid_file: /run/vpncloud.run pid_file: /run/vpncloud.run
stats_file: /var/log/vpncloud.stats stats_file: /var/log/vpncloud.stats
statsd_server: example.com:1234
"; ";
assert_eq!(serde_yaml::from_str::<ConfigFile>(config_file).unwrap(), ConfigFile { assert_eq!(serde_yaml::from_str::<ConfigFile>(config_file).unwrap(), ConfigFile {
device_type: Some(Type::Tun), device_type: Some(Type::Tun),
@ -357,7 +367,8 @@ stats_file: /var/log/vpncloud.stats
user: Some("nobody".to_string()), user: Some("nobody".to_string()),
group: Some("nogroup".to_string()), group: Some("nogroup".to_string()),
pid_file: Some("/run/vpncloud.run".to_string()), pid_file: Some("/run/vpncloud.run".to_string()),
stats_file: Some("/var/log/vpncloud.stats".to_string()) stats_file: Some("/var/log/vpncloud.stats".to_string()),
statsd_server: Some("example.com:1234".to_string())
}) })
} }
@ -388,7 +399,8 @@ fn config_merge() {
user: Some("nobody".to_string()), user: Some("nobody".to_string()),
group: Some("nogroup".to_string()), group: Some("nogroup".to_string()),
pid_file: Some("/run/vpncloud.run".to_string()), pid_file: Some("/run/vpncloud.run".to_string()),
stats_file: Some("/var/log/vpncloud.stats".to_string()) stats_file: Some("/var/log/vpncloud.stats".to_string()),
statsd_server: Some("example.com:1234".to_string())
}); });
assert_eq!(config, Config { assert_eq!(config, Config {
device_type: Type::Tun, device_type: Type::Tun,
@ -414,33 +426,35 @@ fn config_merge() {
group: Some("nogroup".to_string()), group: Some("nogroup".to_string()),
pid_file: Some("/run/vpncloud.run".to_string()), pid_file: Some("/run/vpncloud.run".to_string()),
stats_file: Some("/var/log/vpncloud.stats".to_string()), stats_file: Some("/var/log/vpncloud.stats".to_string()),
statsd_server: Some("example.com:1234".to_string()),
..Default::default() ..Default::default()
}); });
config.merge_args(Args { config.merge_args(Args {
flag_type: Some(Type::Tap), type_: Some(Type::Tap),
flag_device: Some("vpncloud0".to_string()), device: Some("vpncloud0".to_string()),
flag_device_path: Some("/dev/null".to_string()), device_path: Some("/dev/null".to_string()),
flag_ifup: Some("ifconfig $IFNAME 10.0.1.2/16 mtu 1400 up".to_string()), ifup: Some("ifconfig $IFNAME 10.0.1.2/16 mtu 1400 up".to_string()),
flag_ifdown: Some("ifconfig $IFNAME down".to_string()), ifdown: Some("ifconfig $IFNAME down".to_string()),
flag_crypto: Some(CryptoMethod::ChaCha20), crypto: Some(CryptoMethod::ChaCha20),
flag_shared_key: Some("anothersecret".to_string()), key: Some("anothersecret".to_string()),
flag_magic: Some("hash:mynet".to_string()), magic: Some("hash:mynet".to_string()),
flag_listen: Some("3211".to_string()), listen: Some("3211".to_string()),
flag_peer_timeout: Some(1801), peer_timeout: Some(1801),
flag_keepalive: Some(850), keepalive: Some(850),
flag_dst_timeout: Some(301), dst_timeout: Some(301),
flag_beacon_store: Some("/run/vpncloud.beacon.out2".to_string()), beacon_store: Some("/run/vpncloud.beacon.out2".to_string()),
flag_beacon_load: Some("/run/vpncloud.beacon.in2".to_string()), beacon_load: Some("/run/vpncloud.beacon.in2".to_string()),
flag_beacon_interval: Some(3600), beacon_interval: Some(3600),
flag_mode: Some(Mode::Switch), mode: Some(Mode::Switch),
flag_subnet: vec![], subnets: vec![],
flag_connect: vec!["another:3210".to_string()], connect: vec!["another:3210".to_string()],
flag_no_port_forwarding: true, no_port_forwarding: true,
flag_daemon: true, daemon: true,
flag_pid_file: Some("/run/vpncloud-mynet.run".to_string()), pid_file: Some("/run/vpncloud-mynet.run".to_string()),
flag_stats_file: Some("/var/log/vpncloud-mynet.stats".to_string()), stats_file: Some("/var/log/vpncloud-mynet.stats".to_string()),
flag_user: Some("root".to_string()), statsd_server: Some("example.com:2345".to_string()),
flag_group: Some("root".to_string()), user: Some("root".to_string()),
group: Some("root".to_string()),
..Default::default() ..Default::default()
}); });
assert_eq!(config, Config { assert_eq!(config, Config {
@ -471,6 +485,7 @@ fn config_merge() {
group: Some("root".to_string()), group: Some("root".to_string()),
pid_file: Some("/run/vpncloud-mynet.run".to_string()), pid_file: Some("/run/vpncloud-mynet.run".to_string()),
stats_file: Some("/var/log/vpncloud-mynet.stats".to_string()), stats_file: Some("/var/log/vpncloud-mynet.stats".to_string()),
statsd_server: Some("example.com:2345".to_string()),
daemonize: true daemonize: true
}); });
} }

View File

@ -2,7 +2,7 @@
// Copyright (C) 2015-2020 Dennis Schwerdel // Copyright (C) 2015-2020 Dennis Schwerdel
// This software is licensed under GPL-3 or newer (see LICENSE.md) // This software is licensed under GPL-3 or newer (see LICENSE.md)
use std::num::NonZeroU32; use std::{num::NonZeroU32, str::FromStr};
use ring::{aead::*, pbkdf2, rand::*}; use ring::{aead::*, pbkdf2, rand::*};
@ -19,6 +19,17 @@ pub enum CryptoMethod {
#[serde(rename = "aes256")] #[serde(rename = "aes256")]
AES256 AES256
} }
impl FromStr for CryptoMethod {
type Err = &'static str;
fn from_str(text: &str) -> Result<Self, Self::Err> {
Ok(match &text.to_lowercase() as &str {
"chacha20" | "chacha" => Self::ChaCha20,
"aes256" | "aes" => Self::AES256,
_ => return Err("Unknown method")
})
}
}
pub struct CryptoData { pub struct CryptoData {
crypto_key: LessSafeKey, crypto_key: LessSafeKey,

View File

@ -6,7 +6,8 @@ use std::{
collections::VecDeque, collections::VecDeque,
fmt, fs, fmt, fs,
io::{self, Error as IoError, ErrorKind, Read, Write}, io::{self, Error as IoError, ErrorKind, Read, Write},
os::unix::io::{AsRawFd, RawFd} os::unix::io::{AsRawFd, RawFd},
str::FromStr
}; };
use super::types::Error; use super::types::Error;
@ -23,7 +24,7 @@ pub enum Type {
/// Tun interface: This interface transports IP packets. /// Tun interface: This interface transports IP packets.
#[serde(rename = "tun")] #[serde(rename = "tun")]
Tun, Tun,
/// Tap interface: This insterface transports Ethernet frames. /// Tap interface: This interface transports Ethernet frames.
#[serde(rename = "tap")] #[serde(rename = "tap")]
Tap, Tap,
/// Dummy interface: This interface does nothing. /// Dummy interface: This interface does nothing.
@ -41,6 +42,18 @@ impl fmt::Display for Type {
} }
} }
impl FromStr for Type {
type Err = &'static str;
fn from_str(text: &str) -> Result<Self, Self::Err> {
Ok(match &text.to_lowercase() as &str {
"tun" => Self::Tun,
"tap" => Self::Tap,
"dummy" => Self::Dummy,
_ => return Err("Unknown device type")
})
}
}
pub trait Device: AsRawFd { pub trait Device: AsRawFd {
/// Returns the type of this device /// Returns the type of this device

View File

@ -14,7 +14,7 @@ use fnv::FnvHasher;
use super::{ use super::{
types::{Address, Error, Protocol, Table}, types::{Address, Error, Protocol, Table},
util::{Duration, Time, TimeSource} util::{addr_nice, Duration, Time, TimeSource}
}; };
/// An ethernet frame dissector /// An ethernet frame dissector
@ -110,9 +110,15 @@ impl<TS: TimeSource> Table for SwitchTable<TS> {
/// Write out the table /// Write out the table
fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error> { fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error> {
let now = TS::now(); let now = TS::now();
writeln!(out, "Switch table:")?; writeln!(out, "switch_table:")?;
for (addr, val) in &self.table { for (addr, val) in &self.table {
writeln!(out, " - {} => {} (ttl: {} s)", addr, val.address, val.timeout - now)?; writeln!(
out,
" - \"{}\": {{ peer: \"{}\", ttl_secs: {} }}",
addr,
addr_nice(val.address),
val.timeout - now
)?;
} }
Ok(()) Ok(())
} }
@ -124,7 +130,7 @@ impl<TS: TimeSource> Table for SwitchTable<TS> {
match self.table.entry(key) { match self.table.entry(key) {
Entry::Vacant(entry) => { Entry::Vacant(entry) => {
entry.insert(SwitchTableValue { address: addr, timeout: deadline }); entry.insert(SwitchTableValue { address: addr, timeout: deadline });
info!("Learned address {} => {}", key, addr); info!("Learned address {} => {}", key, addr_nice(addr));
} }
Entry::Occupied(mut entry) => { Entry::Occupied(mut entry) => {
let mut entry = entry.get_mut(); let mut entry = entry.get_mut();
@ -165,6 +171,10 @@ impl<TS: TimeSource> Table for SwitchTable<TS> {
self.table.remove(&key); self.table.remove(&key);
} }
} }
fn len(&self) -> usize {
self.table.len()
}
} }

View File

@ -11,7 +11,10 @@ use std::{
use fnv::FnvHasher; use fnv::FnvHasher;
use super::types::{Address, Error, Protocol, Table}; use super::{
types::{Address, Error, Protocol, Table},
util::addr_nice
};
/// An IP packet dissector /// An IP packet dissector
@ -85,7 +88,7 @@ impl Table for RoutingTable {
Some(val) => val, Some(val) => val,
None => addr.len * 8 None => addr.len * 8
}; };
info!("New routing entry: {}/{} => {}", addr, prefix_len, address); info!("New routing entry: {}/{} => {}", addr, prefix_len, addr_nice(address));
// Round the prefix length down to the next multiple of 8 and extraxt a prefix of that // Round the prefix length down to the next multiple of 8 and extraxt a prefix of that
// length. // length.
let group_len = prefix_len as usize / 8; let group_len = prefix_len as usize / 8;
@ -153,10 +156,16 @@ impl Table for RoutingTable {
/// Write out the table /// Write out the table
fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error> { fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error> {
writeln!(out, "Routing table:")?; writeln!(out, "routing_table:")?;
for entries in self.0.values() { for entries in self.0.values() {
for entry in entries { for entry in entries {
writeln!(out, " - {}/{} => {}", entry.bytes, entry.prefix_len, entry.address)?; writeln!(
out,
" - \"{}/{}\": {{ peer: \"{}\" }}",
entry.bytes,
entry.prefix_len,
addr_nice(entry.address)
)?;
} }
} }
Ok(()) Ok(())
@ -175,6 +184,10 @@ impl Table for RoutingTable {
entry.retain(|entr| &entr.address != addr); entry.retain(|entr| &entr.address != addr);
} }
} }
fn len(&self) -> usize {
self.0.len()
}
} }

View File

@ -30,7 +30,7 @@ pub mod traffic;
pub mod types; pub mod types;
pub mod udpmessage; pub mod udpmessage;
use docopt::Docopt; use structopt::StructOpt;
use std::{ use std::{
fs::{self, File, Permissions}, fs::{self, File, Permissions},
@ -59,41 +59,131 @@ use crate::{
const VERSION: u8 = 1; const VERSION: u8 = 1;
const MAGIC: HeaderMagic = *b"vpn\x01"; const MAGIC: HeaderMagic = *b"vpn\x01";
static USAGE: &str = include_str!("usage.txt");
#[derive(StructOpt, Debug, Default)]
#[derive(Deserialize, Debug, Default)]
pub struct Args { pub struct Args {
flag_config: Option<String>, /// Read configuration options from the specified file.
flag_type: Option<Type>, #[structopt(long)]
flag_device_path: Option<String>, config: Option<String>,
flag_mode: Option<Mode>,
flag_shared_key: Option<String>, /// Set the type of network ("tap" or "tun")
flag_crypto: Option<CryptoMethod>, #[structopt(name = "type", short, long)]
flag_subnet: Vec<String>, type_: Option<Type>,
flag_device: Option<String>,
flag_listen: Option<String>, /// Set the path of the base device
flag_network_id: Option<String>, #[structopt(long)]
flag_magic: Option<String>, device_path: Option<String>,
flag_connect: Vec<String>,
flag_peer_timeout: Option<Duration>, /// The mode of the VPN ("normal", "router", "switch", or "hub")
flag_keepalive: Option<Duration>, #[structopt(short, long)]
flag_dst_timeout: Option<Duration>, mode: Option<Mode>,
flag_beacon_store: Option<String>,
flag_beacon_load: Option<String>, /// The shared key to encrypt all traffic
flag_beacon_interval: Option<Duration>, #[structopt(short, long, aliases=&["shared-key", "secret-key", "secret"])]
flag_verbose: bool, key: Option<String>,
flag_quiet: bool,
flag_ifup: Option<String>, /// The encryption method to use ("aes256", or "chacha20")
flag_ifdown: Option<String>, #[structopt(long)]
flag_version: bool, crypto: Option<CryptoMethod>,
flag_no_port_forwarding: bool,
flag_daemon: bool, /// The local subnets to use
flag_pid_file: Option<String>, #[structopt(short, long)]
flag_stats_file: Option<String>, subnets: Vec<String>,
flag_user: Option<String>,
flag_group: Option<String>, /// Name of the virtual device
flag_log_file: Option<String> #[structopt(short, long)]
device: Option<String>,
/// The port number (or ip:port) on which to listen for data
#[structopt(short, long)]
listen: Option<String>,
/// Optional token that identifies the network. (DEPRECATED)
#[structopt(long)]
network_id: Option<String>,
/// Override the 4-byte magic header of each packet
#[structopt(long)]
magic: Option<String>,
/// Address of a peer to connect to
#[structopt(short, long)]
connect: Vec<String>,
/// Peer timeout in seconds
#[structopt(long)]
peer_timeout: Option<Duration>,
/// Periodically send message to keep connections alive
#[structopt(long)]
keepalive: Option<Duration>,
/// Switch table entry timeout in seconds
#[structopt(long)]
dst_timeout: Option<Duration>,
/// The file path or |command to store the beacon
#[structopt(long)]
beacon_store: Option<String>,
/// The file path or |command to load the beacon
#[structopt(long)]
beacon_load: Option<String>,
/// Beacon store/load interval in seconds
#[structopt(long)]
beacon_interval: Option<Duration>,
/// Print debug information
#[structopt(short, long, conflicts_with = "quiet")]
verbose: bool,
/// Only print errors and warnings
#[structopt(short, long)]
quiet: bool,
/// A command to setup the network interface
#[structopt(long)]
ifup: Option<String>,
/// A command to bring down the network interface
#[structopt(long)]
ifdown: Option<String>,
/// Print the version and exit
#[structopt(long)]
version: bool,
/// Disable automatic port forwarding
#[structopt(long)]
no_port_forwarding: bool,
/// Run the process in the background
#[structopt(long)]
daemon: bool,
/// Store the process id in this file when daemonizing
#[structopt(long)]
pid_file: Option<String>,
/// Print statistics to this file
#[structopt(long)]
stats_file: Option<String>,
/// Send statistics to this statsd server
#[structopt(long)]
statsd_server: Option<String>,
/// Run as other user
#[structopt(long)]
user: Option<String>,
/// Run as other group
#[structopt(long)]
group: Option<String>,
/// Print logs also to this file
#[structopt(long)]
log_file: Option<String>
} }
struct DualLogger { struct DualLogger {
@ -326,23 +416,23 @@ fn run<P: Protocol>(config: Config) {
} }
fn main() { fn main() {
let args: Args = Docopt::new(USAGE).and_then(|d| d.deserialize()).unwrap_or_else(|e| e.exit()); let args: Args = Args::from_args();
if args.flag_version { if args.version {
println!("VpnCloud v{}, protocol version {}", env!("CARGO_PKG_VERSION"), VERSION); println!("VpnCloud v{}, protocol version {}", env!("CARGO_PKG_VERSION"), VERSION);
return return
} }
let logger = try_fail!(DualLogger::new(args.flag_log_file.as_ref()), "Failed to open logfile: {}"); let logger = try_fail!(DualLogger::new(args.log_file.as_ref()), "Failed to open logfile: {}");
log::set_boxed_logger(Box::new(logger)).unwrap(); log::set_boxed_logger(Box::new(logger)).unwrap();
assert!(!args.flag_verbose || !args.flag_quiet); assert!(!args.verbose || !args.quiet);
log::set_max_level(if args.flag_verbose { log::set_max_level(if args.verbose {
log::LevelFilter::Debug log::LevelFilter::Debug
} else if args.flag_quiet { } else if args.quiet {
log::LevelFilter::Error log::LevelFilter::Error
} else { } else {
log::LevelFilter::Info log::LevelFilter::Info
}); });
let mut config = Config::default(); let mut config = Config::default();
if let Some(ref file) = args.flag_config { if let Some(ref file) = args.config {
info!("Reading config file '{}'", file); info!("Reading config file '{}'", file);
let f = try_fail!(File::open(file), "Failed to open config file: {:?}"); let f = try_fail!(File::open(file), "Failed to open config file: {:?}");
let config_file = try_fail!(serde_yaml::from_reader(f), "Failed to load config file: {:?}"); let config_file = try_fail!(serde_yaml::from_reader(f), "Failed to load config file: {:?}");

View File

@ -5,10 +5,15 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
io::{self, Write}, io::{self, Write},
net::SocketAddr net::SocketAddr,
ops::AddAssign
}; };
use super::{cloud::Hash, types::Address, util::Bytes}; use super::{
cloud::Hash,
types::Address,
util::{addr_nice, Bytes}
};
#[derive(Default)] #[derive(Default)]
@ -24,6 +29,19 @@ pub struct TrafficEntry {
pub idle_periods: usize pub idle_periods: usize
} }
impl AddAssign<&TrafficEntry> for TrafficEntry {
fn add_assign(&mut self, other: &TrafficEntry) {
self.out_bytes_total += other.out_bytes_total;
self.out_packets_total += other.out_packets_total;
self.out_bytes += other.out_bytes;
self.out_packets += other.out_packets;
self.in_bytes_total += other.in_bytes_total;
self.in_packets_total += other.in_packets_total;
self.in_bytes += other.in_bytes;
self.in_packets += other.in_packets;
}
}
impl TrafficEntry { impl TrafficEntry {
#[inline] #[inline]
fn count_out(&mut self, bytes: usize) { fn count_out(&mut self, bytes: usize) {
@ -58,7 +76,8 @@ impl TrafficEntry {
#[derive(Default)] #[derive(Default)]
pub struct TrafficStats { pub struct TrafficStats {
peers: HashMap<SocketAddr, TrafficEntry, Hash>, peers: HashMap<SocketAddr, TrafficEntry, Hash>,
payload: HashMap<(Address, Address), TrafficEntry, Hash> payload: HashMap<(Address, Address), TrafficEntry, Hash>,
pub dropped: TrafficEntry
} }
impl TrafficStats { impl TrafficStats {
@ -82,6 +101,14 @@ impl TrafficStats {
self.payload.entry((remote, local)).or_insert_with(TrafficEntry::default).count_in(bytes); self.payload.entry((remote, local)).or_insert_with(TrafficEntry::default).count_in(bytes);
} }
pub fn count_invalid_protocol(&mut self, bytes: usize) {
self.dropped.count_in(bytes)
}
pub fn count_dropped_payload(&mut self, bytes: usize) {
self.dropped.count_out(bytes)
}
pub fn period(&mut self, cleanup_idle: Option<usize>) { pub fn period(&mut self, cleanup_idle: Option<usize>) {
for entry in self.peers.values_mut() { for entry in self.peers.values_mut() {
entry.period(); entry.period();
@ -89,6 +116,7 @@ impl TrafficStats {
for entry in self.payload.values_mut() { for entry in self.payload.values_mut() {
entry.period(); entry.period();
} }
self.dropped.period();
if let Some(periods) = cleanup_idle { if let Some(periods) = cleanup_idle {
self.peers.retain(|_, entry| entry.idle_periods < periods); self.peers.retain(|_, entry| entry.idle_periods < periods);
self.payload.retain(|_, entry| entry.idle_periods < periods); self.payload.retain(|_, entry| entry.idle_periods < periods);
@ -103,28 +131,73 @@ impl TrafficStats {
self.payload.iter() self.payload.iter()
} }
pub fn total_peer_traffic(&self) -> TrafficEntry {
let mut total = TrafficEntry::default();
for e in self.peers.values() {
total += e
}
total
}
pub fn total_payload_traffic(&self) -> TrafficEntry {
let mut total = TrafficEntry::default();
for e in self.payload.values() {
total += e
}
total
}
#[inline] #[inline]
pub fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error> { pub fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error> {
writeln!(out, "Peer traffic:")?; writeln!(out, "peer_traffic:")?;
let mut peers: Vec<_> = self.get_peer_traffic().collect(); let mut peers: Vec<_> = self.get_peer_traffic().collect();
peers.sort_unstable_by_key(|(_, data)| (data.out_bytes + data.in_bytes)); peers.sort_unstable_by_key(|(_, data)| (data.out_bytes + data.in_bytes));
for (addr, data) in peers.iter().rev() { for (addr, data) in peers.iter().rev() {
writeln!(out, " - {}: in={}/s, out={}/s", addr, Bytes(data.in_bytes / 60), Bytes(data.out_bytes / 60))?; writeln!(
out,
" - peer: \"{}\"\n in: {{ display: \"{}/s\", bytes: {}, packets: {} }}\n out: {{ display: \"{}/s\", bytes: {}, packets: {} }}",
addr_nice(**addr),
Bytes(data.in_bytes / 60),
data.in_bytes,
data.in_packets,
Bytes(data.out_bytes / 60),
data.out_bytes,
data.out_packets
)?;
} }
writeln!(out)?; writeln!(out)?;
writeln!(out, "Payload traffic:")?; writeln!(out, "payload_traffic:")?;
let mut payload: Vec<_> = self.get_payload_traffic().collect(); let mut payload: Vec<_> = self.get_payload_traffic().collect();
payload.sort_unstable_by_key(|(_, data)| (data.out_bytes + data.in_bytes)); payload.sort_unstable_by_key(|(_, data)| (data.out_bytes + data.in_bytes));
for ((remote, local), data) in payload.iter().rev() { for ((remote, local), data) in payload.iter().rev() {
writeln!( writeln!(
out, out,
" - {} <-> {}: in={}/s, out={}/s", " - addrs: [\"{}\", \"{}\"]\n in: {{ display: \"{}/s\", bytes: {}, packets: {} }}\n out: {{ display: \"{}/s\", bytes: {}, packets: {} }}",
remote, remote,
local, local,
Bytes(data.in_bytes / 60), Bytes(data.in_bytes / 60),
Bytes(data.out_bytes / 60) data.in_bytes,
data.in_packets,
Bytes(data.out_bytes / 60),
data.out_bytes,
data.out_packets
)?; )?;
} }
writeln!(out)?;
writeln!(
out,
"invalid_protocol_traffic: {{ display: \"{}/s\", bytes: {}, packets: {} }}",
Bytes(self.dropped.in_bytes / 60),
self.dropped.in_bytes,
self.dropped.in_packets
)?;
writeln!(
out,
"dropped_payload_traffic: {{ display: \"{}/s\", bytes: {}, packets: {} }}",
Bytes(self.dropped.out_bytes / 60),
self.dropped.out_bytes,
self.dropped.out_packets
)?;
Ok(()) Ok(())
} }
} }

View File

@ -206,6 +206,19 @@ impl fmt::Display for Mode {
} }
} }
} }
impl FromStr for Mode {
type Err = &'static str;
fn from_str(text: &str) -> Result<Self, Self::Err> {
Ok(match &text.to_lowercase() as &str {
"normal" => Self::Normal,
"hub" => Self::Hub,
"switch" => Self::Switch,
"router" => Self::Router,
_ => return Err("Unknown mode")
})
}
}
pub trait Table { pub trait Table {
fn learn(&mut self, _: Address, _: Option<u8>, _: SocketAddr); fn learn(&mut self, _: Address, _: Option<u8>, _: SocketAddr);
@ -214,6 +227,7 @@ pub trait Table {
fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error>; fn write_out<W: Write>(&self, out: &mut W) -> Result<(), io::Error>;
fn remove(&mut self, _: &Address) -> bool; fn remove(&mut self, _: &Address) -> bool;
fn remove_all(&mut self, _: &SocketAddr); fn remove_all(&mut self, _: &SocketAddr);
fn len(&self) -> usize;
} }
pub trait Protocol: Sized { pub trait Protocol: Sized {

View File

@ -1,43 +0,0 @@
Usage:
vpncloud [options] [--config <file>] [-t <type>] [-d <name>] [-l <port>] [-c <addr>...] [-s <subnet>...]
Options:
--config <file> Read configuration options from the
specified file.
-t <type>, --type <type> Set the type of network ("tap" or "tun").
--device-path <path> Set the path of the base device.
-d <name>, --device <name> Name of the virtual device.
-m <mode>, --mode <mode> The mode of the VPN ("hub", "switch",
"router", or "normal").
-l <port>, --listen <port> The port number on which to listen for data.
-c <addr>, --connect <addr> Address of a peer to connect to.
-s <subnet>, --subnet <subnet> The local subnets to use.
--magic <hex> Override the 4-byte magic header of each
packet.
--network-id <id> Optional token that identifies the network.
(DEPRECATED)
--shared-key <key> The shared key to encrypt all traffic.
--crypto <method> The encryption method to use ("aes256", or
"chacha20").
--peer-timeout <secs> Peer timeout in seconds.
--keepalive <secs> Periodically send message to keep
connections alive.
--dst-timeout <secs> Switch table entry timeout in seconds.
--beacon-store <path|command> The file or command to store the beacon.
--beacon-load <path|command> The file or command to load the beacon.
--beacon-interval <secs> Beacon store/load interval in seconds.
--ifup <command> A command to setup the network interface.
--ifdown <command> A command to bring down the network
interface.
--pid-file <file> Store the process id in this file when
daemonizing.
--user <user> Run as other user.
--group <group> Run as other group.
--log-file <file> Print logs also to this file.
--stats-file <file> Print statistics to this file.
--no-port-forwarding Disable automatic port forward.
--daemon Run the process in the background.
-v, --verbose Print debug information.
-q, --quiet Only print errors and warnings.
-h, --help Display the help.
-V, --version Print the version and exit.

View File

@ -31,6 +31,15 @@ pub fn bytes_to_hex(bytes: &[u8]) -> String {
s s
} }
pub fn addr_nice(addr: SocketAddr) -> SocketAddr {
if let SocketAddr::V6(v6addr) = addr {
if let Some(ip) = v6addr.ip().to_ipv4() {
return (ip, addr.port()).into()
}
}
addr
}
pub struct Encoder; pub struct Encoder;