Compare commits

..

No commits in common. "master" and "v0.2.0" have entirely different histories.

11 changed files with 576 additions and 938 deletions

BIN
.DS_Store vendored

Binary file not shown.

3
.gitignore vendored
View File

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

710
Cargo.lock generated
View File

@ -1,26 +1,12 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "ahash"
version = "0.8.11"
name = "aho-corasick"
version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
dependencies = [
"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",
"memchr",
]
[[package]]
@ -42,28 +28,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbf56136a5198c7b01a49e3afcbef6cf84597273d298f54432926024107b0109"
[[package]]
name = "autocfg"
version = "1.1.0"
name = "atty"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
checksum = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
dependencies = [
"libc",
"termion",
"winapi",
]
[[package]]
name = "base64"
version = "0.22.1"
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
version = "2.6.0"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "bumpalo"
version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "byteorder"
@ -77,34 +62,25 @@ 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"
@ -112,37 +88,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10bcb9d7dcbf7002aaffbb53eac22906b64cdcc127971dcc387d8eb7c95d5560"
dependencies = [
"quote",
"syn 1.0.60",
"syn",
]
[[package]]
name = "durnitisp"
version = "0.2.3"
version = "0.2.0"
dependencies = [
"anyhow",
"gflags",
"icmp-socket",
"metrics",
"metrics-exporter-prometheus",
"log 0.4.14",
"nursery",
"prometheus",
"resolve",
"socket2 0.5.1",
"socket2",
"stderrlog",
"tiny_http",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "equivalent"
version = "1.0.1"
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foldhash"
version = "0.1.3"
name = "form_urlencoded"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "fuchsia-cprng"
@ -170,7 +149,7 @@ checksum = "07ab1d33648a58677c98ee6ed81ce592e108d4e9847ce62a15302da7e5bfd437"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.60",
"syn",
]
[[package]]
@ -181,32 +160,17 @@ checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.60",
"syn",
]
[[package]]
name = "hashbrown"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98bc3daf82cd6b2f02709427c17f75e1023471f59bc74726bbd27d8a907af605"
checksum = "8c83b37323293113bad20766377951f5b51e0b23fc7cc6694b6b93e6ff02ecf8"
dependencies = [
"byteorder",
"socket2 0.4.4",
"socket2",
]
[[package]]
@ -221,13 +185,23 @@ dependencies = [
]
[[package]]
name = "indexmap"
version = "2.6.0"
name = "idna"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
dependencies = [
"equivalent",
"hashbrown",
"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",
]
[[package]]
@ -249,16 +223,7 @@ checksum = "75c094e94816723ab936484666968f5b58060492e880f3c8d00489a1e244fa51"
dependencies = [
"proc-macro2",
"quote",
"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",
"syn",
]
[[package]]
@ -269,9 +234,18 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.161"
version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff"
[[package]]
name = "lock_api"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312"
dependencies = [
"scopeguard",
]
[[package]]
name = "log"
@ -298,51 +272,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
[[package]]
name = "memoffset"
version = "0.8.0"
name = "memchr"
version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
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"
dependencies = [
"autocfg",
]
[[package]]
name = "metrics"
version = "0.24.0"
name = "numtoa"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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",
]
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
[[package]]
name = "nursery"
@ -351,52 +309,71 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4bd2d4e0cd7c6bb256afbc59a5921c3ead56f05d7696c92e05b6978858b6fa5"
[[package]]
name = "once_cell"
version = "1.20.2"
name = "parking_lot"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
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"
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
dependencies = [
"unicode-ident",
"instant",
"lock_api",
"parking_lot_core",
]
[[package]]
name = "quanta"
version = "0.12.3"
name = "parking_lot_core"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5"
checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272"
dependencies = [
"crossbeam-utils",
"cfg-if",
"instant",
"libc",
"once_cell",
"raw-cpuid",
"wasi",
"web-sys",
"redox_syscall 0.1.57",
"smallvec",
"winapi",
]
[[package]]
name = "quote"
version = "1.0.37"
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
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"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
dependencies = [
"proc-macro2",
]
@ -439,15 +416,6 @@ 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"
@ -457,6 +425,30 @@ 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"
@ -474,16 +466,34 @@ checksum = "4c38e3aecd2b21cb3959637b883bb3714bc7e43f0268b9a29d3743ee3e55cdd2"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.60",
"syn",
]
[[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",
"idna 0.1.5",
"libc",
"log 0.3.9",
"rand 0.3.23",
@ -495,45 +505,34 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "sharded-slab"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
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"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "socket2"
version = "0.4.4"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0"
checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
dependencies = [
"cfg-if",
"libc",
"winapi",
]
[[package]]
name = "socket2"
name = "stderrlog"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc8d618c6641ae355025c449427f9e96b98abf99a772be3cef6708d15c77147a"
checksum = "45a53e2eff3e94a019afa6265e8ee04cb05b9d33fe9f5078b14e4e391d155a38"
dependencies = [
"libc",
"windows-sys",
"atty",
"chrono",
"log 0.4.14",
"termcolor",
"thread_local",
]
[[package]]
@ -548,14 +547,24 @@ dependencies = [
]
[[package]]
name = "syn"
version = "2.0.85"
name = "termcolor"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
"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",
]
[[package]]
@ -575,28 +584,40 @@ checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.60",
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.4"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
dependencies = [
"once_cell",
"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",
]
[[package]]
name = "tiny_http"
version = "0.12.0"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389915df6413a2e74fb181895f933386023c71110878cd0825588928e64cdc82"
checksum = "eded47106b8e52d8ed8119f0ea6e8c0f5881e69783e0297b5a8462958f334bc1"
dependencies = [
"ascii",
"chrono",
"chunked_transfer",
"httpdate",
"log 0.4.14",
"url",
]
[[package]]
@ -614,64 +635,6 @@ 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"
@ -681,12 +644,6 @@ 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"
@ -703,86 +660,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "valuable"
version = "0.1.0"
name = "url"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e"
dependencies = [
"form_urlencoded",
"idna 0.2.0",
"matches",
"percent-encoding",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
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",
]
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "winapi"
@ -800,94 +693,17 @@ 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,20 +1,19 @@
[package]
name = "durnitisp"
version = "0.2.3"
version = "0.2.0"
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"
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"
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"

View File

@ -1,11 +0,0 @@
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
View File

@ -1,76 +0,0 @@
{
"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
}

View File

@ -1,21 +0,0 @@
{
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::{BTreeMap, HashMap},
collections::HashMap,
time::{Duration, Instant},
};
@ -25,9 +25,8 @@ use icmp_socket::{
packet::{Icmpv4Message, Icmpv6Message, WithEchoRequest},
IcmpSocket, IcmpSocket4, IcmpSocket6, Icmpv4Packet, Icmpv6Packet,
};
use metrics::{counter, gauge, histogram};
use nursery::{thread, Nursery};
use tracing::{debug, error, info, instrument, warn};
use log::{debug, error, info};
use prometheus::{CounterVec, GaugeVec};
gflags::define! {
/// The payload to use for the ping requests.
@ -35,8 +34,8 @@ gflags::define! {
}
gflags::define! {
/// The timeout for ping requests in seconds.
--pingTimeout: u64 = 3
/// The timeout for ping requests.
--pingTimeout: u64 = 2048
}
gflags::define! {
@ -61,90 +60,16 @@ fn resolve_host_address(host: &str) -> String {
}
struct State<AddrType> {
sequence: u16,
destinations: HashMap<u16, (String, AddrType)>, // domain, address
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;
}
time_tracker: HashMap<u16, Instant>,
latency_guage: GaugeVec,
ping_counter: CounterVec,
}
struct PingerImpl<Sock: IcmpSocket> {
sock: Sock,
timeout: Duration,
}
trait PacketHandler<PacketType, AddrType>
@ -161,9 +86,7 @@ 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,
@ -182,17 +105,15 @@ impl<'a> PacketHandler<Icmpv6Packet, Ipv6Addr> for &'a mut State<Ipv6Addr> {
},
}) => {
if let Some((domain_name, _addr)) = self.destinations.get(&identifier) {
counter!(
"ping_counter",
&make_ping_count_labels(domain_name, "unreachable")
)
.increment(1);
self.ping_counter
.with(&prometheus::labels! {"result" => "unreachable", "domain" => domain_name})
.inc();
return true;
}
}
Err(e) => {
// We ignore these as well but log it.
error!(err = ?e, "Error parsing Unreachable");
error!("ICMP: Error parsing Unreachable invoking packet {:?}", e);
}
_ => {
// We ignore these
@ -210,16 +131,21 @@ impl<'a> PacketHandler<Icmpv6Packet, Ipv6Addr> for &'a mut State<Ipv6Addr> {
checksum: _,
message:
Icmpv6Message::EchoRequest {
identifier: _,
identifier,
sequence: _,
payload: _,
},
}) => {
// TODO log but otherwise ignore this.
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;
}
}
Err(e) => {
// We ignore these as well but log it.
error!(err = ?e, "Error parsing ParameterProblem");
error!("ICMP: Error parsing Unreachable invoking packet {:?}", e);
}
_ => {
// We ignore these
@ -231,7 +157,32 @@ impl<'a> PacketHandler<Icmpv6Packet, Ipv6Addr> for &'a mut State<Ipv6Addr> {
sequence,
payload: _,
} => {
return self.handle_echo_reply(identifier, sequence);
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);
}
}
_ => {
// We ignore the rest.
@ -246,20 +197,67 @@ 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: _,
} => {
return self.handle_echo_reply(identifier, sequence);
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);
}
}
_ => {
p => {
// We ignore the rest.
info!("Unhandled packet");
info!("ICMP Unhandled packet {:?}", p);
}
}
return false;
@ -281,41 +279,6 @@ 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>
@ -324,14 +287,27 @@ 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() {
self.send_pkt(state, identifier, dest, &domain_name)?;
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);
}
}
}
debug!("Finished sending for domains");
Ok(())
}
@ -357,76 +333,39 @@ where
Ok(response)
}
#[instrument(skip(self, handler))]
fn recv_all<H: PacketHandler<Sock::PacketType, Sock::AddrType>>(&mut self, mut handler: H) {
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;
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();
}
}
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);
}
}
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) {
pub fn start_echo_loop(
domain_names: &Vec<&str>,
ping_latency_guage: GaugeVec,
ping_counter: CounterVec,
) {
let resolved: Vec<(String, IpAddr)> = domain_names
.iter()
.map(|domain_name| {
@ -453,66 +392,48 @@ pub fn schedule_echo_server(domain_names: &Vec<&str>, parent: &mut Nursery) {
let mut v4_destinations = HashMap::new();
let mut v4_id_counter = 42;
for target in v4_targets {
info!(
domain_name = target.0,
address = %target.1,
"Attempting ping"
);
info!("ICMP: Attempting ping to {}({})", target.0, target.1);
v4_destinations.insert(v4_id_counter, target.clone());
v4_id_counter += 1;
}
let v4_state = State {
let mut v4_state = State {
sequence: 0,
destinations: v4_destinations,
time_tracker: BTreeMap::new(),
destination_counter: BTreeMap::new(),
time_tracker: HashMap::new(),
latency_guage: ping_latency_guage.clone(),
ping_counter: ping_counter.clone(),
};
let mut v6_destinations = HashMap::new();
let mut v6_id_counter = 42;
for target in v6_targets {
info!(
domain_name = target.0,
address = %target.1,
"Attempting ping"
);
info!("ICMP: Attempting ping to {}({})", target.0, target.1);
v6_destinations.insert(v6_id_counter, target.clone());
v6_id_counter += 1;
}
let v4_pinger = PingerImpl {
let mut v4_pinger = PingerImpl {
sock: IcmpSocket4::new().expect("Failed to open Icmpv4 Socket"),
timeout: Duration::from_secs(1),
};
let v6_state = State {
let mut v6_state = State {
sequence: 0,
destinations: v6_destinations,
time_tracker: BTreeMap::new(),
destination_counter: BTreeMap::new(),
time_tracker: HashMap::new(),
latency_guage: ping_latency_guage,
ping_counter,
};
let v6_pinger = PingerImpl {
let mut v6_pinger = PingerImpl {
sock: IcmpSocket6::new().expect("Failed to open Icmpv6 Socket"),
timeout: Duration::from_secs(1),
};
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));
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))
}
}

View File

@ -11,16 +11,18 @@
// 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 metrics_exporter_prometheus;
use log::{debug, error, info};
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;
@ -41,11 +43,6 @@ gflags::define! {
--debug = false
}
gflags::define! {
/// Enable trace logging
--trace = false
}
gflags::define! {
/// Comma separated list of hosts to ping
--pingHosts = "google.com"
@ -56,10 +53,9 @@ 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> = STUNHOSTS.flag.split(",").collect();
let stun_servers: Vec<&str> = dbg!(STUNHOSTS.flag).split(",").collect();
if HELP.flag {
println!("durnitisp <options> <list of hostname:port>");
@ -71,32 +67,60 @@ fn main() -> anyhow::Result<()> {
gflags::print_help_and_exit(0);
}
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)
let level = if DEBUG.flag || cfg!(debug_assertions) {
3
} else {
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)
2
};
tracing::subscriber::set_global_default(subscriber_builder.finish())
.expect("setting default subscriber failed");
stderrlog::new()
.verbosity(level)
.timestamp(stderrlog::Timestamp::Millisecond)
.init()?;
let ping_hosts: Vec<&str> = PINGHOSTS.flag.split(",").collect();
let ping_hosts: Vec<&str> = dbg!(PINGHOSTS.flag).split(",").collect();
let builder = metrics_exporter_prometheus::PrometheusBuilder::new();
let prom_handle = builder
.install_recorder()
.expect("Failed to install prometheus exporter");
dbg!(&ping_hosts);
// 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);
@ -107,33 +131,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!(listenhost = LISTENHOST.flag, "attempting to start server");
debug!("attempting to start server on {}", LISTENHOST.flag);
let server = match tiny_http::Server::http(LISTENHOST.flag) {
Ok(server) => server,
Err(err) => {
error!(
?err,
"Error starting render thread. Shutting down all thread.",
);
error!("Error starting render thread {}", err);
error!("Shutting down all threads...");
std::process::exit(1);
}
};
info!(
listenthost = LISTENHOST.flag,
"Listening for metrics request on"
);
info!("Listening for metrics request on {}", LISTENHOST.flag);
loop {
info!("Waiting for request");
match server.recv() {
Ok(req) => {
let response = tiny_http::Response::from_data(prom_handle.render())
.with_status_code(200);
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);
if let Err(e) = req.respond(response) {
error!(err = ?e, "Error responding to request");
error!("Error responding to request {}", e);
}
}
Err(e) => {
error!(err = ?e, "Invalid http request!");
info!("Invalid http request! {}", e);
}
}
}
@ -141,15 +165,30 @@ fn main() -> anyhow::Result<()> {
parent.adopt(Box::new(render_thread));
}
{
icmp::schedule_echo_server(&ping_hosts, &mut parent);
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));
}
// 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()));
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,
)
});
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 metrics::{counter, gauge};
use log::{debug, error, info};
use prometheus::{CounterVec, IntGaugeVec};
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,81 +70,61 @@ fn attempt_stun_connect(addr: SocketAddr) -> Result<SystemTime, ConnectError> {
Ok(SystemTime::now())
}
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");
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);
loop {
let now = SystemTime::now();
info!("Attempting to connect");
info!("Attempting to connect to {}", domain_name);
match attempt_stun_connect(s) {
Ok(finish_time) => {
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);
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);
}
Err(ConnectError::Timeout(finish_time)) => {
info!(
timeout = true,
success = false,
millis = finish_time.duration_since(now).unwrap().as_millis(),
conn_type = "Stun connection",
"Stun connection to {} timedout after {} millis",
domain_name,
finish_time.duration_since(now).unwrap().as_millis()
);
counter!(
"stun_attempt_counter",
&make_count_labels(domain_name, "timeout")
)
.increment(1);
success.set(0);
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);
}
Err(ConnectError::Err(e)) => {
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);
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);
}
Err(ConnectError::Incomplete) => {
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);
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);
}
}

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,21 +32,13 @@ 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() {
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());
}
}
// 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() {
@ -54,7 +46,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) => {
error!(name, err = ?e, "Failed to resolve");
info!("Failed to resolve {} with error {}", name, e);
results.push(None);
}
}