Compare commits

...

18 Commits

Author SHA1 Message Date
d32c27b31c
Merge pull request #3 from durin42/metrics-update
metrics: update crates to latest versions and drop some unused features
2024-11-02 20:41:03 -04:00
Augie Fackler
4755513f5d metrics-exporter-prometheus: drop default features
This prunes quite a bit from the dependency graph that we weren't using anyway.
2024-11-01 21:44:13 -04:00
Augie Fackler
feb6684e8f metrics: update to latest version
Really the only reason I bothered was because the old version brings
in an ahash that fails to compile on macOS Arm or something like that,
but since I'd done the upgrade before for my own packages it wasn't
hard.
2024-10-28 12:23:47 -04:00
5341153a86 Use the metrics facade 2023-03-14 13:17:12 -04:00
f609dcfef3 Bump version to 0.2.2 2023-03-14 11:53:51 -04:00
390b61ee86 Higher resolution ping timings 2023-03-13 20:26:19 -04:00
b45b29e22d Update socket2 2023-02-27 15:19:16 -05:00
347ac8147a Update tiny_http 2023-02-27 15:17:30 -05:00
ca9ce99d49 Update prometheus 2023-02-27 15:16:34 -05:00
b7aafbce25 2022-07-14 21:37:32 -04:00
a91e316aec update tiny_http and socket2 2022-07-14 21:36:48 -04:00
3dc6ded1b0 Update icmp-socket version 2022-07-14 21:34:28 -04:00
2cea3a294e Update to tracing for logs 2022-07-14 21:13:42 -04:00
26ac114f88 create nix package wrapper using flake-compat 2022-03-03 17:45:22 -05:00
425ab1e959 nix flake 2022-03-01 17:53:35 -05:00
39d90db9ab Bump version to v0.2.1 2021-03-01 20:37:40 -05:00
0835ea3ade Fix a bunch of stuff for multi destination pings. 2021-02-26 14:23:36 -05:00
278ef8da04 Allow ip addresses in the pingHosts list 2021-02-20 19:36:25 -05:00
11 changed files with 939 additions and 577 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
target/
.vscode/
.vscode/
result

712
Cargo.lock generated
View File

@ -1,12 +1,26 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "0.7.15"
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"memchr",
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]]
@ -28,27 +42,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbf56136a5198c7b01a49e3afcbef6cf84597273d298f54432926024107b0109"
[[package]]
name = "atty"
version = "0.2.11"
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
dependencies = [
"libc",
"termion",
"winapi",
]
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "autocfg"
version = "1.0.1"
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bitflags"
version = "1.2.1"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "bumpalo"
version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
[[package]]
name = "byteorder"
@ -62,25 +77,34 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"time",
"winapi",
]
[[package]]
name = "chunked_transfer"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7477065d45a8fe57167bf3cf8bcd3729b54cfcb81cca49bda2d038ea89ae82ca"
[[package]]
name = "crossbeam-epoch"
version = "0.9.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
dependencies = [
"cfg-if",
]
[[package]]
name = "ctor"
version = "0.1.18"
@ -88,40 +112,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10bcb9d7dcbf7002aaffbb53eac22906b64cdcc127971dcc387d8eb7c95d5560"
dependencies = [
"quote",
"syn",
"syn 1.0.60",
]
[[package]]
name = "durnitisp"
version = "0.2.0"
version = "0.2.3"
dependencies = [
"anyhow",
"gflags",
"icmp-socket",
"log 0.4.14",
"metrics",
"metrics-exporter-prometheus",
"nursery",
"prometheus",
"resolve",
"socket2",
"stderrlog",
"socket2 0.5.1",
"tiny_http",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "fnv"
version = "1.0.7"
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "form_urlencoded"
version = "1.0.0"
name = "foldhash"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00"
dependencies = [
"matches",
"percent-encoding",
]
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
[[package]]
name = "fuchsia-cprng"
@ -149,7 +170,7 @@ checksum = "07ab1d33648a58677c98ee6ed81ce592e108d4e9847ce62a15302da7e5bfd437"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.60",
]
[[package]]
@ -160,17 +181,32 @@ checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.60",
]
[[package]]
name = "icmp-socket"
version = "0.1.1"
name = "hashbrown"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c83b37323293113bad20766377951f5b51e0b23fc7cc6694b6b93e6ff02ecf8"
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
dependencies = [
"foldhash",
]
[[package]]
name = "httpdate"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "icmp-socket"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98bc3daf82cd6b2f02709427c17f75e1023471f59bc74726bbd27d8a907af605"
dependencies = [
"byteorder",
"socket2",
"socket2 0.4.4",
]
[[package]]
@ -185,23 +221,13 @@ dependencies = [
]
[[package]]
name = "idna"
version = "0.2.0"
name = "indexmap"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "instant"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
dependencies = [
"cfg-if",
"equivalent",
"hashbrown",
]
[[package]]
@ -223,7 +249,16 @@ checksum = "75c094e94816723ab936484666968f5b58060492e880f3c8d00489a1e244fa51"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.60",
]
[[package]]
name = "js-sys"
version = "0.3.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc15e39392125075f60c95ba416f5381ff6c3a948ff02ab12464715adf56c821"
dependencies = [
"wasm-bindgen",
]
[[package]]
@ -234,18 +269,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.84"
version = "0.2.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff"
[[package]]
name = "lock_api"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312"
dependencies = [
"scopeguard",
]
checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
[[package]]
name = "log"
@ -272,35 +298,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
[[package]]
name = "memchr"
version = "2.3.4"
name = "memoffset"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
dependencies = [
"autocfg",
]
[[package]]
name = "numtoa"
version = "0.1.0"
name = "metrics"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
checksum = "8ae428771d17306715c5091d446327d1cfdedc82185c65ba8423ab404e45bf10"
dependencies = [
"ahash",
"portable-atomic",
]
[[package]]
name = "metrics-exporter-prometheus"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85b6f8152da6d7892ff1b7a1c0fa3f435e92b5918ad67035c3bb432111d9a29b"
dependencies = [
"base64",
"indexmap",
"metrics",
"metrics-util",
"quanta",
"thiserror",
]
[[package]]
name = "metrics-util"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15b482df36c13dd1869d73d14d28cd4855fbd6cfc32294bee109908a9f4a4ed7"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
"hashbrown",
"metrics",
"quanta",
"sketches-ddsketch",
]
[[package]]
name = "nursery"
@ -309,71 +351,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4bd2d4e0cd7c6bb256afbc59a5921c3ead56f05d7696c92e05b6978858b6fa5"
[[package]]
name = "parking_lot"
version = "0.11.1"
name = "once_cell"
version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "pin-project-lite"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]]
name = "portable-atomic"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
[[package]]
name = "proc-macro2"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
dependencies = [
"instant",
"lock_api",
"parking_lot_core",
"unicode-ident",
]
[[package]]
name = "parking_lot_core"
version = "0.8.2"
name = "quanta"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272"
checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5"
dependencies = [
"cfg-if",
"instant",
"crossbeam-utils",
"libc",
"redox_syscall 0.1.57",
"smallvec",
"once_cell",
"raw-cpuid",
"wasi",
"web-sys",
"winapi",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "proc-macro2"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
dependencies = [
"unicode-xid",
]
[[package]]
name = "prometheus"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8425533e7122f0c3cc7a37e6244b16ad3a2cc32ae7ac6276e2a75da0d9c200d"
dependencies = [
"cfg-if",
"fnv",
"lazy_static",
"parking_lot",
"protobuf",
"regex",
"thiserror",
]
[[package]]
name = "protobuf"
version = "2.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86473d5f16580f10b131a0bf0afb68f8e029d1835d33a00f37281b05694e5312"
[[package]]
name = "quote"
version = "1.0.8"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
@ -416,6 +439,15 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "raw-cpuid"
version = "11.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0"
dependencies = [
"bitflags",
]
[[package]]
name = "rdrand"
version = "0.4.0"
@ -425,30 +457,6 @@ dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "redox_syscall"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "redox_syscall"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570"
dependencies = [
"bitflags",
]
[[package]]
name = "redox_termios"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f"
dependencies = [
"redox_syscall 0.2.4",
]
[[package]]
name = "ref-cast"
version = "1.0.6"
@ -466,34 +474,16 @@ checksum = "4c38e3aecd2b21cb3959637b883bb3714bc7e43f0268b9a29d3743ee3e55cdd2"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.60",
]
[[package]]
name = "regex"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"thread_local",
]
[[package]]
name = "regex-syntax"
version = "0.6.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
[[package]]
name = "resolve"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19526b305899bea65f26edda78a64f5313958494321ee0ab66bd94b32958614a"
dependencies = [
"idna 0.1.5",
"idna",
"libc",
"log 0.3.9",
"rand 0.3.23",
@ -506,33 +496,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "smallvec"
version = "1.6.1"
name = "sharded-slab"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
dependencies = [
"lazy_static",
]
[[package]]
name = "sketches-ddsketch"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1e9a774a6c28142ac54bb25d25562e6bcf957493a184f15ad4eebccb23e410a"
[[package]]
name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "socket2"
version = "0.3.19"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0"
dependencies = [
"cfg-if",
"libc",
"winapi",
]
[[package]]
name = "stderrlog"
name = "socket2"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45a53e2eff3e94a019afa6265e8ee04cb05b9d33fe9f5078b14e4e391d155a38"
checksum = "bc8d618c6641ae355025c449427f9e96b98abf99a772be3cef6708d15c77147a"
dependencies = [
"atty",
"chrono",
"log 0.4.14",
"termcolor",
"thread_local",
"libc",
"windows-sys",
]
[[package]]
@ -547,24 +548,14 @@ dependencies = [
]
[[package]]
name = "termcolor"
version = "1.1.2"
name = "syn"
version = "2.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
dependencies = [
"winapi-util",
]
[[package]]
name = "termion"
version = "1.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e"
dependencies = [
"libc",
"numtoa",
"redox_syscall 0.2.4",
"redox_termios",
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
@ -584,40 +575,28 @@ checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 1.0.60",
]
[[package]]
name = "thread_local"
version = "1.0.1"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
dependencies = [
"lazy_static",
]
[[package]]
name = "time"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi",
"winapi",
"once_cell",
]
[[package]]
name = "tiny_http"
version = "0.8.0"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eded47106b8e52d8ed8119f0ea6e8c0f5881e69783e0297b5a8462958f334bc1"
checksum = "389915df6413a2e74fb181895f933386023c71110878cd0825588928e64cdc82"
dependencies = [
"ascii",
"chrono",
"chunked_transfer",
"httpdate",
"log 0.4.14",
"url",
]
[[package]]
@ -635,6 +614,64 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tracing"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160"
dependencies = [
"cfg-if",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.60",
]
[[package]]
name = "tracing-core"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
dependencies = [
"lazy_static",
"log 0.4.14",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59"
dependencies = [
"ansi_term",
"sharded-slab",
"smallvec",
"thread_local",
"tracing-core",
"tracing-log",
]
[[package]]
name = "unicode-bidi"
version = "0.3.4"
@ -644,6 +681,12 @@ dependencies = [
"matches",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "unicode-normalization"
version = "0.1.16"
@ -660,22 +703,86 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "url"
version = "2.2.0"
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e"
dependencies = [
"form_urlencoded",
"idna 0.2.0",
"matches",
"percent-encoding",
]
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fe8f61dba8e5d645a4d8132dc7a0a66861ed5e1045d2c0ed940fab33bac0fbe"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046ceba58ff062da072c7cb4ba5b22a37f00a302483f7e2a6cdc18fedbdc1fd3"
dependencies = [
"bumpalo",
"lazy_static",
"log 0.4.14",
"proc-macro2",
"quote",
"syn 1.0.60",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ef9aa01d36cda046f797c57959ff5f3c615c9cc63997a8d545831ec7976819b"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96eb45c1b2ee33545a813a92dbb53856418bf7eb54ab34f7f7ff1448a5b3735d"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.60",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7148f4696fb4960a346eaa60bbfb42a1ac4ebba21f750f75fc1375b098d5ffa"
[[package]]
name = "web-sys"
version = "0.3.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59fe19d70f5dacc03f6e46777213facae5ac3801575d56ca6cbd4c93dcd12310"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
@ -693,17 +800,94 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_i686_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.85",
]

View File

@ -1,19 +1,20 @@
[package]
name = "durnitisp"
version = "0.2.0"
version = "0.2.3"
authors = ["Jeremy Wall <jeremy@marzhillstudios.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tracing = "0.1.35"
tracing-subscriber = "0.3.14"
anyhow = "1"
gflags = "^0.3"
log = "0.4"
nursery = "^0.0.1"
prometheus = "0.11.0"
stderrlog = "0.5.1"
tiny_http = "0.8.0"
socket2 = "0.3.19"
icmp-socket = "0.1.1"
resolve = "^0.2.0"
metrics = "0.24.0"
metrics-exporter-prometheus = {version = "0.16.0", default-features = false}
tiny_http = "0.12.0"
socket2 = "0.5.1"
icmp-socket = "0.2.0"
resolve = "^0.2.0"

11
default.nix Normal file
View File

@ -0,0 +1,11 @@
let
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
in
(import (
fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
sha256 = lock.nodes.flake-compat.locked.narHash;
}
) {
src = ./.;
}).defaultNix

76
flake.lock generated Normal file
View File

@ -0,0 +1,76 @@
{
"nodes": {
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1641205782,
"narHash": "sha256-4jY7RCWUoZ9cKD8co0/4tFARpWB+57+r1bLLvXNJliY=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "b7547d3eed6f32d06102ead8991ec52ab0a4f1a7",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": {
"locked": {
"lastModified": 1644229661,
"narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"naersk": {
"inputs": {
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1671096816,
"narHash": "sha256-ezQCsNgmpUHdZANDCILm3RvtO1xH8uujk/+EqNvzIOg=",
"owner": "nix-community",
"repo": "naersk",
"rev": "d998160d6a076cfe8f9741e56aeec7e267e3e114",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "naersk",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1678724065,
"narHash": "sha256-MjeRjunqfGTBGU401nxIjs7PC9PZZ1FBCZp/bRB3C2M=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b8afc8489dc96f29f69bec50fdc51e27883f89c1",
"type": "github"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"root": {
"inputs": {
"flake-compat": "flake-compat",
"flake-utils": "flake-utils",
"naersk": "naersk"
}
}
},
"root": "root",
"version": 7
}

21
flake.nix Normal file
View File

@ -0,0 +1,21 @@
{
inputs = {
flake-utils.url = "github:numtide/flake-utils";
naersk.url = "github:nix-community/naersk";
flake-compat = { url = github:edolstra/flake-compat; flake = false; };
};
outputs = {self, flake-utils, naersk, flake-compat}:
flake-utils.lib.eachDefaultSystem (system:
let
naersk-lib = naersk.lib."${system}";
in
{
defaultPackage = naersk-lib.buildPackage rec {
pname = "kitchen";
src = ./.;
};
}
);
}

View File

@ -14,7 +14,7 @@
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::ops::Sub;
use std::{
collections::HashMap,
collections::{BTreeMap, HashMap},
time::{Duration, Instant},
};
@ -25,8 +25,9 @@ use icmp_socket::{
packet::{Icmpv4Message, Icmpv6Message, WithEchoRequest},
IcmpSocket, IcmpSocket4, IcmpSocket6, Icmpv4Packet, Icmpv6Packet,
};
use log::{debug, error, info};
use prometheus::{CounterVec, GaugeVec};
use metrics::{counter, gauge, histogram};
use nursery::{thread, Nursery};
use tracing::{debug, error, info, instrument, warn};
gflags::define! {
/// The payload to use for the ping requests.
@ -34,8 +35,8 @@ gflags::define! {
}
gflags::define! {
/// The timeout for ping requests.
--pingTimeout: u64 = 2048
/// The timeout for ping requests in seconds.
--pingTimeout: u64 = 3
}
gflags::define! {
@ -60,16 +61,90 @@ fn resolve_host_address(host: &str) -> String {
}
struct State<AddrType> {
sequence: u16,
destinations: HashMap<u16, (String, AddrType)>, // domain, address
time_tracker: HashMap<u16, Instant>,
latency_guage: GaugeVec,
ping_counter: CounterVec,
time_tracker: BTreeMap<u16, BTreeMap<u16, Instant>>,
destination_counter: BTreeMap<u16, u16>,
// TODO(jwall): Add histogram for latency as well.
}
fn make_ping_count_labels(domain_name: &str, result: &str) -> [(&'static str, String); 2] {
[
("domain", domain_name.to_owned()),
("result", result.to_owned()),
]
}
impl<AddrType: std::fmt::Display> State<AddrType> {
fn handle_echo_reply(&mut self, identifier: u16, sequence: u16) -> bool {
if let Some((domain_name, dest)) = self.destinations.get(&identifier) {
let time_tracker = self.time_tracker.get_mut(&identifier);
let mut result = false;
if let Some(Some(send_time)) = time_tracker.as_ref().map(|m| m.get(&sequence)) {
let elapsed = Instant::now().sub(send_time.clone()).as_micros() as f64 / 1000.00;
// We make a copy here to avoid the borrow above sticking around for too long.
info!(
domain=domain_name,
%dest,
time = elapsed,
seq = sequence,
"Reply",
);
counter!("ping_counter", &make_ping_count_labels(domain_name, "ok")).increment(1);
if elapsed as i32 != 0 {
let labels = [("domain", domain_name.to_owned())];
let latency = gauge!("ping_latency", &labels);
latency.increment(elapsed);
let latency_hist = histogram!("ping_latency_hist_ms", &labels);
latency_hist.record(elapsed);
}
self.time_tracker
.get_mut(&identifier)
.and_then(|m| m.remove(&sequence));
result = true;
} else {
error!(sequence, "Discarding unexpected sequence",);
};
// Check all the other sequences to see if they have expired timeouts yet.
// Record timeout for the expired sequences.
// Remove the timeouts for the expired sequences.
let expired_sequences = self.time_tracker.get(&identifier).map(|m| {
let mut for_delete = Vec::with_capacity(m.len());
let m = m.clone();
{
for (k, send_time) in m.iter() {
if Instant::now().sub(*send_time) >= Duration::from_secs(PINGTIMEOUT.flag) {
info!(
domain=domain_name,
%dest,
seq = sequence,
"Dropped"
);
counter!(
"ping_counter",
&make_ping_count_labels(domain_name, "dropped")
)
.increment(1);
for_delete.push(*k);
}
}
}
for_delete
});
for k in expired_sequences.unwrap_or_default() {
self.time_tracker
.get_mut(&identifier)
.and_then(|m| m.remove(&k));
}
return result;
} else {
warn!(identifier, "Discarding wrong identifier");
}
return false;
}
}
struct PingerImpl<Sock: IcmpSocket> {
sock: Sock,
timeout: Duration,
}
trait PacketHandler<PacketType, AddrType>
@ -86,7 +161,9 @@ impl<'a> PacketHandler<Icmpv6Packet, Ipv6Addr> for &'a mut State<Ipv6Addr> {
return self;
}
#[instrument(level = "debug", skip(self))]
fn handle_pkt(&mut self, pkt: Icmpv6Packet) -> bool {
debug!("handling packet");
match pkt.message {
Icmpv6Message::Unreachable {
_unused,
@ -105,15 +182,17 @@ impl<'a> PacketHandler<Icmpv6Packet, Ipv6Addr> for &'a mut State<Ipv6Addr> {
},
}) => {
if let Some((domain_name, _addr)) = self.destinations.get(&identifier) {
self.ping_counter
.with(&prometheus::labels! {"result" => "unreachable", "domain" => domain_name})
.inc();
counter!(
"ping_counter",
&make_ping_count_labels(domain_name, "unreachable")
)
.increment(1);
return true;
}
}
Err(e) => {
// We ignore these as well but log it.
error!("ICMP: Error parsing Unreachable invoking packet {:?}", e);
error!(err = ?e, "Error parsing Unreachable");
}
_ => {
// We ignore these
@ -131,21 +210,16 @@ impl<'a> PacketHandler<Icmpv6Packet, Ipv6Addr> for &'a mut State<Ipv6Addr> {
checksum: _,
message:
Icmpv6Message::EchoRequest {
identifier,
identifier: _,
sequence: _,
payload: _,
},
}) => {
if let Some((domain_name, _addr)) = self.destinations.get(&identifier) {
self.ping_counter
.with(&prometheus::labels! {"result" => "parameter_problem", "domain" => domain_name})
.inc();
return true;
}
// TODO log but otherwise ignore this.
}
Err(e) => {
// We ignore these as well but log it.
error!("ICMP: Error parsing Unreachable invoking packet {:?}", e);
error!(err = ?e, "Error parsing ParameterProblem");
}
_ => {
// We ignore these
@ -157,32 +231,7 @@ impl<'a> PacketHandler<Icmpv6Packet, Ipv6Addr> for &'a mut State<Ipv6Addr> {
sequence,
payload: _,
} => {
if let Some((domain_name, dest)) = self.destinations.get(&identifier) {
if self.sequence != sequence {
error!("ICMP: Discarding sequence {}", sequence);
return false;
}
let elapsed = if let Some(send_time) = self.time_tracker.get(&identifier) {
Instant::now().sub(send_time.clone()).as_micros() as f64 / 1000.00
} else {
return false;
};
info!(
"ICMP: Reply from {}({}): time={}ms, seq={}",
domain_name, dest, elapsed, sequence,
);
self.ping_counter
.with(&prometheus::labels! {"result" => "ok", "domain" => domain_name})
.inc();
if elapsed as i32 != 0 {
self.latency_guage
.with(&prometheus::labels! {"domain" => domain_name.as_str()})
.set(elapsed);
}
return true;
} else {
info!("ICMP: Discarding wrong identifier {}", identifier);
}
return self.handle_echo_reply(identifier, sequence);
}
_ => {
// We ignore the rest.
@ -197,67 +246,20 @@ impl<'a> PacketHandler<Icmpv4Packet, Ipv4Addr> for &'a mut State<Ipv4Addr> {
return self;
}
#[instrument(level = "debug", skip(self))]
fn handle_pkt(&mut self, pkt: Icmpv4Packet) -> bool {
debug!("handling packet");
match pkt.message {
Icmpv4Message::ParameterProblem {
pointer: _,
padding: _,
header: _,
} => {
self.ping_counter
.with(&prometheus::labels! {"result" => "parameter_problem", "domain" => "unknown"})
.inc();
}
Icmpv4Message::Unreachable { padding: _, header } => {
let dest_addr = Ipv4Addr::new(header[16], header[17], header[18], header[19]);
info!("ICMP: Destination Unreachable response from {}", dest_addr,);
self.ping_counter
.with(&prometheus::labels! {"result" => "unreachable", "domain" => "unknown"})
.inc();
}
Icmpv4Message::TimeExceeded { padding: _, header } => {
let dest_addr = Ipv4Addr::new(header[16], header[17], header[18], header[19]);
info!("ICMP: Timeout for {}", dest_addr);
self.ping_counter
.with(&prometheus::labels! {"result" => "timeout", "domain" => "unknown"})
.inc();
}
Icmpv4Message::EchoReply {
identifier,
sequence,
payload: _,
} => {
if let Some((domain_name, dest)) = self.destinations.get(&identifier) {
let elapsed = if let Some(send_time) = self.time_tracker.get(&identifier) {
Instant::now().sub(send_time.clone()).as_micros() as f64 / 1000.00
} else {
return false;
};
if self.sequence != sequence {
error!(
"ICMP: Discarding sequence {}, expected sequence {}",
sequence, self.sequence
);
return false;
}
info!(
"ICMP: Reply from {}({}): time={}ms, seq={}",
domain_name, dest, elapsed, sequence,
);
self.ping_counter
.with(&prometheus::labels! {"result" => "ok", "domain" => domain_name})
.inc();
self.latency_guage
.with(&prometheus::labels! {"domain" => domain_name.as_str()})
.set(elapsed);
return true;
} else {
info!("ICMP: Discarding wrong identifier {}", identifier);
}
return self.handle_echo_reply(identifier, sequence);
}
p => {
_ => {
// We ignore the rest.
info!("ICMP Unhandled packet {:?}", p);
info!("Unhandled packet");
}
}
return false;
@ -279,6 +281,41 @@ where
fn recv_pkt(&mut self) -> std::io::Result<PacketType>;
fn recv_all<H: PacketHandler<PacketType, AddrType>>(&mut self, handler: H);
fn send_pkt(
&mut self,
state: &mut State<AddrType>,
identifier: u16,
dest: AddrType,
domain_name: &String,
) -> std::io::Result<()> {
let sequence = *state.destination_counter.entry(identifier).or_insert(0);
debug!(
domain=domain_name, %dest, sequence,
"Sending echo request",
);
match self.send_to_destination(dest, identifier, sequence) {
Err(e) => {
counter!("ping_counter", &make_ping_count_labels(domain_name, "err")).increment(1);
error!(
domain=domain_name, %dest, err=?e,
"Error sending. Trying again later",
);
}
Ok(send_time) => {
state
.time_tracker
.entry(identifier)
.or_insert_with(|| BTreeMap::new())
.insert(sequence, send_time);
}
}
state
.destination_counter
.get_mut(&identifier)
.map(|v| *v = v.wrapping_add(1));
Ok(())
}
}
impl<Sock> Pinger<Sock::AddrType, Sock::PacketType> for PingerImpl<Sock>
@ -287,27 +324,14 @@ where
Sock::AddrType: std::fmt::Display + Copy,
Sock::PacketType: WithEchoRequest<Packet = Sock::PacketType>,
{
#[instrument(skip_all)]
fn send_all(&mut self, state: &mut State<Sock::AddrType>) -> std::io::Result<()> {
self.sock.set_timeout(self.timeout)?;
let destinations = state.destinations.clone();
debug!("Attempting to send packets for all domains");
for (identifier, (domain_name, dest)) in destinations.into_iter() {
debug!("ICMP: sending echo request to {}({})", domain_name, dest);
match self.send_to_destination(dest, identifier, state.sequence) {
Err(e) => {
state
.ping_counter
.with(&prometheus::labels! {"result" => "err", "type" => "send"})
.inc();
error!(
"ICMP: error sending to domain: {} and address: {} failed: {:?}, Trying again later",
domain_name, &dest, e
);
}
Ok(send_time) => {
state.time_tracker.insert(identifier, send_time);
}
}
self.send_pkt(state, identifier, dest, &domain_name)?;
}
debug!("Finished sending for domains");
Ok(())
}
@ -333,39 +357,76 @@ where
Ok(response)
}
#[instrument(skip(self, handler))]
fn recv_all<H: PacketHandler<Sock::PacketType, Sock::AddrType>>(&mut self, mut handler: H) {
let expected_len = handler.get_mut_state().time_tracker.len();
for _ in 0..expected_len {
loop {
// Receive loop
match self.recv_pkt() {
Ok(pkt) => {
if handler.handle_pkt(pkt) {
// break out of the recv loop
break;
}
}
Err(e) => {
error!("Error receiving packet: {:?}", e);
handler
.get_mut_state()
.ping_counter
.with(&prometheus::labels! {"result" => "err", "domain" => "unknown"})
.inc();
if handler.get_mut_state().destinations.is_empty() {
debug!("Nothing to send to so skipping for this socket");
return;
};
if handler
.get_mut_state()
.time_tracker
.values()
.find(|item| !item.is_empty())
.is_none()
{
// nothing has been sent yet so no need to try to recv packets
debug!("Nothing to recieve so skipping for this socket");
return;
}
self.sock.set_timeout(None);
let loop_start_time = Instant::now();
loop {
// Receive loop
debug!("Attempting to recieve packets on socket");
match self.recv_pkt() {
Ok(pkt) => {
if handler.handle_pkt(pkt) {
// break out of the recv loop
debug!("Recieved Packet");
return;
}
}
Err(e) => {
error!(err = ?e, "Error receiving packet");
counter!("ping_counter", &make_ping_count_labels("unknown", "err"))
.increment(1);
return;
}
}
if (Instant::now() - loop_start_time) > Duration::from_secs(PINGTIMEOUT.flag) {
info!("Timing out on recieve loop");
return;
}
}
let mut state = handler.get_mut_state();
state.sequence = state.sequence.wrapping_add(1);
}
}
pub fn start_echo_loop(
domain_names: &Vec<&str>,
ping_latency_guage: GaugeVec,
ping_counter: CounterVec,
) {
struct Multi {
v4_state: State<Ipv4Addr>,
v6_state: State<Ipv6Addr>,
v4_pinger: PingerImpl<IcmpSocket4>,
v6_pinger: PingerImpl<IcmpSocket6>,
}
impl Multi {
fn send_all(&mut self) {
self.v4_pinger
.send_all(&mut self.v4_state)
.expect("Error sending packets on socket");
self.v6_pinger
.send_all(&mut self.v6_state)
.expect("Error sending packets on socket");
}
fn recv_all(&mut self) {
self.v4_pinger.recv_all(&mut self.v4_state);
self.v6_pinger.recv_all(&mut self.v6_state);
}
}
#[instrument(name = "ICMP", skip_all)]
pub fn schedule_echo_server(domain_names: &Vec<&str>, parent: &mut Nursery) {
let resolved: Vec<(String, IpAddr)> = domain_names
.iter()
.map(|domain_name| {
@ -392,48 +453,66 @@ pub fn start_echo_loop(
let mut v4_destinations = HashMap::new();
let mut v4_id_counter = 42;
for target in v4_targets {
info!("ICMP: Attempting ping to {}({})", target.0, target.1);
info!(
domain_name = target.0,
address = %target.1,
"Attempting ping"
);
v4_destinations.insert(v4_id_counter, target.clone());
v4_id_counter += 1;
}
let mut v4_state = State {
sequence: 0,
let v4_state = State {
destinations: v4_destinations,
time_tracker: HashMap::new(),
latency_guage: ping_latency_guage.clone(),
ping_counter: ping_counter.clone(),
time_tracker: BTreeMap::new(),
destination_counter: BTreeMap::new(),
};
let mut v6_destinations = HashMap::new();
let mut v6_id_counter = 42;
for target in v6_targets {
info!("ICMP: Attempting ping to {}({})", target.0, target.1);
info!(
domain_name = target.0,
address = %target.1,
"Attempting ping"
);
v6_destinations.insert(v6_id_counter, target.clone());
v6_id_counter += 1;
}
let mut v4_pinger = PingerImpl {
let v4_pinger = PingerImpl {
sock: IcmpSocket4::new().expect("Failed to open Icmpv4 Socket"),
timeout: Duration::from_secs(1),
};
let mut v6_state = State {
sequence: 0,
let v6_state = State {
destinations: v6_destinations,
time_tracker: HashMap::new(),
latency_guage: ping_latency_guage,
ping_counter,
time_tracker: BTreeMap::new(),
destination_counter: BTreeMap::new(),
};
let mut v6_pinger = PingerImpl {
let v6_pinger = PingerImpl {
sock: IcmpSocket6::new().expect("Failed to open Icmpv6 Socket"),
timeout: Duration::from_secs(1),
};
loop {
v4_pinger
.send_all(&mut v4_state)
.expect("Error sending packets on socket");
v6_pinger
.send_all(&mut v6_state)
.expect("Error sending packets on socket");
v4_pinger.recv_all(&mut v4_state);
v6_pinger.recv_all(&mut v6_state);
std::thread::sleep(Duration::from_secs(PINGDELAY.flag))
}
let multi = std::sync::Arc::new(std::sync::Mutex::new(Multi {
v4_pinger,
v6_pinger,
v4_state,
v6_state,
}));
let send_multi = multi.clone();
let send_thread = thread::Pending::new(move || {
info!("Starting send thread");
loop {
{
send_multi.lock().unwrap().send_all();
}
std::thread::sleep(Duration::from_secs(1));
}
});
let recv_thread = thread::Pending::new(move || {
info!("Starting recv thread");
loop {
{
multi.lock().unwrap().recv_all();
}
std::thread::sleep(Duration::from_millis(5));
}
});
parent.schedule(Box::new(send_thread));
parent.schedule(Box::new(recv_thread));
}

View File

@ -11,18 +11,16 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::convert::Into;
use std::sync::Arc;
use gflags;
use log::{debug, error, info};
use metrics_exporter_prometheus;
use nursery::thread;
use nursery::{Nursery, Waitable};
use prometheus::{self, GaugeVec};
use prometheus::{CounterVec, Encoder, IntGaugeVec, Opts, Registry, TextEncoder};
use stderrlog;
use tiny_http;
use tracing::{debug, error, info, instrument, Level};
use tracing_subscriber::FmtSubscriber;
mod icmp;
mod stun;
@ -43,6 +41,11 @@ gflags::define! {
--debug = false
}
gflags::define! {
/// Enable trace logging
--trace = false
}
gflags::define! {
/// Comma separated list of hosts to ping
--pingHosts = "google.com"
@ -53,9 +56,10 @@ gflags::define! {
--stunHosts = "stun.l.google.com:19302,stun.ekiga.net:3478,stun.xten.com:3478,stun.ideasip.com:3478,stun.rixtelecom.se:3478,stun.schlund.de:3478,stun.softjoys.com:3478,stun.stunprotocol.org:3478,stun.voiparound.com:3478,stun.voipbuster.com:3478,stun.voipstunt.com:3478,stun1.noc.ams-ix.net:3478"
}
#[instrument]
fn main() -> anyhow::Result<()> {
gflags::parse();
let stun_servers: Vec<&str> = dbg!(STUNHOSTS.flag).split(",").collect();
let stun_servers: Vec<&str> = STUNHOSTS.flag.split(",").collect();
if HELP.flag {
println!("durnitisp <options> <list of hostname:port>");
@ -67,60 +71,32 @@ fn main() -> anyhow::Result<()> {
gflags::print_help_and_exit(0);
}
let level = if DEBUG.flag || cfg!(debug_assertions) {
3
let subscriber_builder = if DEBUG.flag {
FmtSubscriber::builder()
// all spans/events with a level higher than debug
// will be written to stdout.
.with_max_level(Level::DEBUG)
} else if TRACE.flag {
FmtSubscriber::builder()
// all spans/events with a level will be written to stdout.
.with_max_level(Level::TRACE)
} else {
2
FmtSubscriber::builder()
// all spans/events with a level higher than info (e.g, error, info, warn, etc.)
// will be written to stdout.
.with_max_level(Level::INFO)
};
stderrlog::new()
.verbosity(level)
.timestamp(stderrlog::Timestamp::Millisecond)
.init()?;
tracing::subscriber::set_global_default(subscriber_builder.finish())
.expect("setting default subscriber failed");
let ping_hosts: Vec<&str> = dbg!(PINGHOSTS.flag).split(",").collect();
let ping_hosts: Vec<&str> = PINGHOSTS.flag.split(",").collect();
dbg!(&ping_hosts);
let builder = metrics_exporter_prometheus::PrometheusBuilder::new();
let prom_handle = builder
.install_recorder()
.expect("Failed to install prometheus exporter");
// Create a Registry and register metrics.
let r = Registry::new();
let stun_counter_vec = CounterVec::new(
Opts::new(
"stun_attempt_counter",
"Counter for the good, bad, and total attempts to connect to stun server.",
),
&["result", "domain"],
)
.unwrap();
let stun_success_vec = IntGaugeVec::new(
Opts::new("stun_success", "Stun probe successes"),
&["domain"],
)
.unwrap();
let stun_latency_vec = IntGaugeVec::new(
Opts::new(
"stun_attempt_latency_ms",
"Latency guage in millis per stun domain.",
),
&["domain"],
)
.unwrap();
let ping_latency_vec =
GaugeVec::new(Opts::new("ping_latency", "ICMP Ping latency"), &["domain"]).unwrap();
let ping_counter_vec = CounterVec::new(
Opts::new("ping_counter", "Ping Request Counter"),
&["result", "domain"],
)
.unwrap();
r.register(Box::new(stun_counter_vec.clone()))
.expect("Failed to register stun connection counter");
r.register(Box::new(stun_latency_vec.clone()))
.expect("Failed to register stun latency guage");
r.register(Box::new(stun_success_vec.clone()))
.expect("Failed to register stun success gauge");
r.register(Box::new(ping_latency_vec.clone()))
.expect("Failed to register ping latency guage");
r.register(Box::new(ping_counter_vec.clone()))
.expect("Failed to register ping counter");
let stun_socket_addrs = util::resolve_socket_addrs(&stun_servers).unwrap();
let stun_servers = Arc::new(stun_servers);
let ping_hosts = Arc::new(ping_hosts);
@ -131,33 +107,33 @@ fn main() -> anyhow::Result<()> {
// Introduce a new scope for our Arc to clone before moving it into the thread.
// thread::Handle starts the thread immediately so the render thread will usually start first.
let render_thread = thread::Handle::new(move || {
debug!("attempting to start server on {}", LISTENHOST.flag);
debug!(listenhost = LISTENHOST.flag, "attempting to start server");
let server = match tiny_http::Server::http(LISTENHOST.flag) {
Ok(server) => server,
Err(err) => {
error!("Error starting render thread {}", err);
error!("Shutting down all threads...");
error!(
?err,
"Error starting render thread. Shutting down all thread.",
);
std::process::exit(1);
}
};
info!("Listening for metrics request on {}", LISTENHOST.flag);
info!(
listenthost = LISTENHOST.flag,
"Listening for metrics request on"
);
loop {
info!("Waiting for request");
match server.recv() {
Ok(req) => {
let mut buffer = vec![];
// Gather the metrics.
let encoder = TextEncoder::new();
let metric_families = r.gather();
encoder.encode(&metric_families, &mut buffer).unwrap();
let response = tiny_http::Response::from_data(buffer).with_status_code(200);
let response = tiny_http::Response::from_data(prom_handle.render())
.with_status_code(200);
if let Err(e) = req.respond(response) {
error!("Error responding to request {}", e);
error!(err = ?e, "Error responding to request");
}
}
Err(e) => {
info!("Invalid http request! {}", e);
error!(err = ?e, "Invalid http request!");
}
}
}
@ -165,30 +141,15 @@ fn main() -> anyhow::Result<()> {
parent.adopt(Box::new(render_thread));
}
{
let ping_latency_vec = ping_latency_vec.clone();
let ping_counter_vec = ping_counter_vec.clone();
let ping_thread = thread::Pending::new(move || {
icmp::start_echo_loop(&ping_hosts, ping_latency_vec, ping_counter_vec);
});
parent.schedule(Box::new(ping_thread));
icmp::schedule_echo_server(&ping_hosts, &mut parent);
}
// Then we attempt to start connections to each stun server.
for (i, s) in stun_socket_addrs.iter().enumerate() {
let stun_servers_copy = stun_servers.clone();
let stun_counter_vec_copy = stun_counter_vec.clone();
let stun_latency_vec_copy = stun_latency_vec.clone();
let stun_success_vec_copy = stun_success_vec.clone();
if let Some(s) = s.clone() {
let domain_name = *stun_servers_copy.get(i).unwrap();
let connect_thread = thread::Pending::new(move || {
stun::start_listen_thread(
domain_name,
s.into(),
stun_counter_vec_copy,
stun_latency_vec_copy,
stun_success_vec_copy,
)
});
let connect_thread =
thread::Pending::new(move || stun::start_listen_thread(domain_name, s.into()));
parent.schedule(Box::new(connect_thread));
// Spread the probe threads out so they're somewhat uniformly distributed.
std::thread::sleep(std::time::Duration::from_micros(

View File

@ -13,12 +13,12 @@
// limitations under the License.
use gflags;
use log::{debug, error, info};
use prometheus::{CounterVec, IntGaugeVec};
use metrics::{counter, gauge};
use std::convert::From;
use std::io;
use std::net::{SocketAddr, UdpSocket};
use std::time::SystemTime;
use tracing::{debug, error, info, instrument};
gflags::define! {
/// Read timeout for the stun server udp receive
@ -70,61 +70,81 @@ fn attempt_stun_connect(addr: SocketAddr) -> Result<SystemTime, ConnectError> {
Ok(SystemTime::now())
}
pub fn start_listen_thread(
domain_name: &str,
s: SocketAddr,
stun_counter_vec_copy: CounterVec,
stun_latency_vec_copy: IntGaugeVec,
stun_success_vec_copy: IntGaugeVec,
) {
debug!("started thread for {}", domain_name);
fn make_count_labels(domain_name: &str, result: &str) -> [(&'static str, String); 2] {
[
("domain", domain_name.to_owned()),
("result", result.to_owned()),
]
}
#[instrument(
name = "STUN",
fields(domain=domain_name, socket=%s),
)]
pub fn start_listen_thread(domain_name: &str, s: SocketAddr) {
let labels: [(&str, String); 1] = [("domain", domain_name.to_owned())];
let success = gauge!("stun_success", &labels);
debug!("starting thread");
loop {
let now = SystemTime::now();
info!("Attempting to connect to {}", domain_name);
info!("Attempting to connect");
match attempt_stun_connect(s) {
Ok(finish_time) => {
info!("Success! connecting to {}", domain_name);
stun_counter_vec_copy
.with(&prometheus::labels! {"result" => "ok", "domain" => domain_name})
.inc();
stun_latency_vec_copy
.with(&prometheus::labels! {"domain" => domain_name})
// Technically this could be lossy but we'll chance it anyway.
.set(finish_time.duration_since(now).unwrap().as_millis() as i64);
stun_success_vec_copy
.with(&prometheus::labels! {"domain" => domain_name})
.set(1);
info!(
timeout = false,
success = true,
millis = finish_time.duration_since(now).unwrap().as_millis(),
conn_type = "Stun connection",
);
counter!(
"stun_attempt_counter",
&make_count_labels(domain_name, "ok")
)
.increment(1);
gauge!("stun_attempt_latency_ms", &labels)
.increment(finish_time.duration_since(now).unwrap().as_millis() as f64);
success.set(1);
}
Err(ConnectError::Timeout(finish_time)) => {
info!(
"Stun connection to {} timedout after {} millis",
domain_name,
finish_time.duration_since(now).unwrap().as_millis()
timeout = true,
success = false,
millis = finish_time.duration_since(now).unwrap().as_millis(),
conn_type = "Stun connection",
);
stun_counter_vec_copy
.with(&prometheus::labels! {"result" => "timeout", "domain" => domain_name})
.inc();
stun_success_vec_copy
.with(&prometheus::labels! {"domain" => domain_name})
.set(0);
counter!(
"stun_attempt_counter",
&make_count_labels(domain_name, "timeout")
)
.increment(1);
success.set(0);
}
Err(ConnectError::Err(e)) => {
error!("Error connecting to {}: {}", domain_name, e);
stun_counter_vec_copy
.with(&prometheus::labels! {"result" => "err", "domain" => domain_name})
.inc();
stun_success_vec_copy
.with(&prometheus::labels! {"domain" => domain_name})
.set(0);
error!(
timeout=true, success=false, err = ?e,
conn_type="Stun connection",
);
counter!(
"stun_attempt_counter",
&make_count_labels(domain_name, "err")
)
.increment(1);
success.set(0);
}
Err(ConnectError::Incomplete) => {
error!("Connection to {} was incomplete", domain_name);
stun_counter_vec_copy
.with(&prometheus::labels! {"result" => "incomplete", "domain" => domain_name})
.inc();
stun_success_vec_copy
.with(&prometheus::labels! {"domain" => domain_name})
.set(0);
error!(
timeout = true,
success = false,
err = "Incomplete",
conn_type = "Stun connection",
);
counter!(
"stun_attempt_counter",
&make_count_labels(domain_name, "incomplete")
)
.increment(1);
success.set(0);
}
}

View File

@ -17,9 +17,9 @@ use std::net::IpAddr;
use std::net::{SocketAddr, ToSocketAddrs};
use gflags;
use log::info;
use resolve::config::DnsConfig;
use resolve::resolver::DnsResolver;
use tracing::{error, instrument};
gflags::define! {
/// Allow IPv6 addresses for domain name lookups.
@ -32,13 +32,21 @@ pub fn resolve_hosts<'a>(servers: &'a Vec<&str>) -> io::Result<Vec<Option<IpAddr
config.use_inet6 = ALLOWIPV6.flag;
let resolver = DnsResolver::new(config)?;
for name in servers.iter().cloned() {
// TODO for resolution errors return a more valid error with the domain name.
let mut iter = resolver.resolve_host(name)?;
results.push(iter.next());
match name.parse::<IpAddr>() {
Ok(ip) => {
results.push(Some(ip));
}
Err(_) => {
// TODO for resolution errors return a more valid error with the domain name.
let mut iter = resolver.resolve_host(name)?;
results.push(iter.next());
}
}
}
return Ok(results);
}
#[instrument]
pub fn resolve_socket_addrs<'a>(servers: &'a Vec<&str>) -> io::Result<Vec<Option<SocketAddr>>> {
let mut results = Vec::new();
for name in servers.iter().cloned() {
@ -46,7 +54,7 @@ pub fn resolve_socket_addrs<'a>(servers: &'a Vec<&str>) -> io::Result<Vec<Option
match name.to_socket_addrs() {
Ok(addr) => results.push(addr.into_iter().next()),
Err(e) => {
info!("Failed to resolve {} with error {}", name, e);
error!(name, err = ?e, "Failed to resolve");
results.push(None);
}
}