From 4a2e930afc59839126f9055a238d1d6ae101dfb1 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 4 Apr 2024 15:17:59 +0200 Subject: [PATCH 01/24] Introduce idns with a minimal viable query command. --- Cargo.lock | 1067 +++++++++++++++++++++++++++++------- Cargo.toml | 11 +- src/bin/bore.rs | 319 ----------- src/bin/idns.rs | 11 + src/idns/args.rs | 18 + src/idns/commands/mod.rs | 22 + src/idns/commands/query.rs | 313 +++++++++++ src/idns/error.rs | 23 + src/idns/mod.rs | 8 + src/lib.rs | 4 + 10 files changed, 1261 insertions(+), 535 deletions(-) delete mode 100644 src/bin/bore.rs create mode 100644 src/bin/idns.rs create mode 100644 src/idns/args.rs create mode 100644 src/idns/commands/mod.rs create mode 100644 src/idns/commands/query.rs create mode 100644 src/idns/error.rs create mode 100644 src/idns/mod.rs create mode 100644 src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index cd10658..ea545ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,11 +2,109 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-trait" +version = "0.1.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "backtrace" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] [[package]] name = "bitflags" @@ -14,17 +112,66 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "bumpalo" +version = "3.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" + +[[package]] +name = "bytecount" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" + [[package]] name = "bytes" -version = "1.3.0" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] [[package]] name = "cc" -version = "1.0.78" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" [[package]] name = "cfg-if" @@ -34,27 +181,36 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.1.1" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ - "bitflags", + "clap_builder", "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", "clap_lex", - "is-terminal", - "once_cell", "strsim", - "termcolor", + "terminal_size", + "unicase", + "unicode-width", ] [[package]] name = "clap_derive" -version = "4.1.0" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", "syn", @@ -62,141 +218,140 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.1" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "crossbeam-channel" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ - "os_str_bytes", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", ] [[package]] name = "domain" -version = "0.8.0-dev" -source = "git+https://github.com/NLnetLabs/domain.git?branch=main#034adf2a284bccf54edc85e27369d5d8c06546ca" +version = "0.10.0-dev" +source = "git+https://github.com/NLnetLabs/domain.git?branch=main#7cc3de62915776cf598e1a9f3fb91d17fd9a796c" dependencies = [ "bytes", - "futures", - "libc", + "futures-util", + "moka", "octseq", + "pin-project-lite", + "proc-macro2", "rand", "smallvec", "time", "tokio", + "tokio-rustls", ] [[package]] name = "domain-tools" version = "0.1.0" dependencies = [ + "bytes", "clap", "domain", + "tokio", ] [[package]] name = "errno" -version = "0.2.8" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "errno-dragonfly", "libc", - "winapi", + "windows-sys 0.52.0", ] [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "error-chain" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" dependencies = [ - "cc", - "libc", + "version_check", ] [[package]] -name = "futures" -version = "0.3.25" +name = "event-listener" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] -name = "futures-channel" -version = "0.3.25" +name = "fastrand" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" -dependencies = [ - "futures-core", - "futures-sink", -] +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "futures-core" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" - -[[package]] -name = "futures-executor" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "futures-sink" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" - [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ - "futures-channel", "futures-core", - "futures-io", "futures-macro", - "futures-sink", "futures-task", - "memchr", "pin-project-lite", "pin-utils", "slab", @@ -204,95 +359,162 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", "wasi", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "heck" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] -name = "io-lifetimes" -version = "1.0.4" +name = "itoa" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e" -dependencies = [ - "libc", - "windows-sys", -] +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] -name = "is-terminal" -version = "0.4.2" +name = "js-sys" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ - "hermit-abi", - "io-lifetimes", - "rustix", - "windows-sys", + "wasm-bindgen", ] [[package]] name = "libc" -version = "0.2.138" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "linux-raw-sys" -version = "0.1.4" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] -name = "log" -version = "0.4.17" +name = "lock_api" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ - "cfg-if", + "autocfg", + "scopeguard", ] +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "miniz_oxide" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] [[package]] name = "mio" -version = "0.8.5" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", - "log", "wasi", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "moka" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1911e88d5831f748a4097a43862d129e3c6fca831eecac9b8db6d01d93c9de2" +dependencies = [ + "async-lock", + "async-trait", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "futures-util", + "once_cell", + "parking_lot", + "quanta", + "rustc_version", + "skeptic", + "smallvec", + "tagptr", + "thiserror", + "triomphe", + "uuid", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", ] [[package]] name = "octseq" -version = "0.2.0-dev" -source = "git+https://github.com/NLnetLabs/octseq.git#64b0ced5de95d1c5e641c3a63a12ded405b40e69" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ed2eaec452d98ccc1c615dd843fd039d9445f2fb4da114ee7e6af5fcb68be98" dependencies = [ "bytes", "smallvec", @@ -300,21 +522,38 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] [[package]] -name = "os_str_bytes" -version = "6.4.1" +name = "parking_lot_core" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -322,6 +561,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -329,43 +574,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "proc-macro2" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", + "unicode-ident", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "pulldown-cmark" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "proc-macro2", - "quote", - "version_check", + "bitflags 2.5.0", + "memchr", + "unicase", ] [[package]] -name = "proc-macro2" -version = "1.0.50" +name = "quanta" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" dependencies = [ - "unicode-ident", + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi", + "web-sys", + "winapi", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -400,62 +647,217 @@ dependencies = [ "getrandom", ] +[[package]] +name = "raw-cpuid" +version = "11.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d86a7c4638d42c44551f4791a20e687dbb4c3de1f33c43dd71e355cd429def1" +dependencies = [ + "bitflags 2.5.0", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustix" -version = "0.36.7" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ - "bitflags", + "bitflags 2.5.0", "errno", - "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "semver" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +dependencies = [ + "serde", ] [[package]] name = "serde" -version = "1.0.152" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "skeptic" +version = "0.13.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" +dependencies = [ + "bytecount", + "cargo_metadata", + "error-chain", + "glob", + "pulldown-cmark", + "tempfile", + "walkdir", +] [[package]] name = "slab" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.10.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.4.7" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "winapi", + "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "1.0.107" +version = "2.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" dependencies = [ "proc-macro2", "quote", @@ -463,63 +865,157 @@ dependencies = [ ] [[package]] -name = "termcolor" -version = "1.2.0" +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + +[[package]] +name = "tempfile" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ - "winapi-util", + "cfg-if", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "time" -version = "0.3.17" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ + "deranged", + "num-conv", + "powerfmt", "serde", "time-core", ] [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "tokio" -version = "1.24.2" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", - "memchr", "mio", + "num_cpus", "pin-project-lite", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "1.8.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "triomphe" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +dependencies = [ + "getrandom", +] [[package]] name = "version_check" @@ -527,12 +1023,86 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -551,9 +1121,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -566,57 +1136,132 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" 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", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" diff --git a/Cargo.toml b/Cargo.toml index 8dbef3c..eb9b396 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,9 +4,10 @@ version = "0.1.0" edition = "2021" rust-version = "1.65.0" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -#domain = "0.7" -domain = {git="https://github.com/NLnetLabs/domain.git", branch="main", features = ["resolv"]} -clap = { version = "4", features = ["derive"] } +bytes = "1" +clap = { version = "4", features = ["derive", "unstable-doc"] } +domain = { git="https://github.com/NLnetLabs/domain.git", branch="main", features = ["resolv", "unstable-client-transport"]} +tokio = { version = "1.33", features = ["rt-multi-thread"] } + + diff --git a/src/bin/bore.rs b/src/bin/bore.rs deleted file mode 100644 index 2927ac1..0000000 --- a/src/bin/bore.rs +++ /dev/null @@ -1,319 +0,0 @@ -use std::{fmt, io, process}; -use std::net::{UdpSocket, IpAddr, SocketAddr}; -use clap::{Parser}; -use domain::base::{ - Dname, MessageBuilder, Rtype, StaticCompressor, StreamTarget, - message::Message, opt::AllOptData -}; -// use octseq::builder::OctetsBuilder; -use domain::rdata::AllRecordData; -use domain::resolv::stub::conf::ResolvConf; - - -#[derive(Clone, Debug, Parser)] -#[command(author, version, about, long_about = None)] -#[command(author = "Tom Carpay, NLnet Labs")] -#[command(version = "0.1")] -#[command(about = "A Rusty cousin to drill", long_about = None)] -struct GlobalParamArgs { - /// The query name that is going to be resolved - #[arg(value_name="QUERY_NAME")] - qname: Dname>, - - /// The query type of the request. The default is and A record. - #[arg(long, default_value = "A")] - qtype: Rtype, - - /// The server that is query is sent to - #[arg(short = 's', long, value_name="IP_ADDRESS")] - server: Option, - - /// The port of the server that is query is sent to - #[arg(short = 'p', long = "port", value_parser = clap::value_parser!(u16))] - port: Option, - - /// Request no recursion on the DNS message. This is true by default. - #[arg(long = "norecurse")] - no_rd_bit: bool, - - /// Set the DO bit to request DNSSEC records. The default is false. - #[arg(long = "do")] - do_bit: bool, - - /// Request the server NSID. The default is false. - #[arg(long = "nsid")] - nsid: bool, - - /// Use only IPv4 for communication. The default is false. - #[arg(short = '4', long = "do_ipv4")] - do_ipv4: bool, - - /// Use only IPv4 for communication. The default is false. - #[arg(short = '6', long = "do_ipv6")] - do_ipv6: bool, -} - -#[derive(Clone, Debug)] -struct Request { - args: GlobalParamArgs, - upstream: SocketAddr, -} - -impl Request { - fn configure(args: GlobalParamArgs) -> Result { - let mut upstreams = ResolvConf::default(); - - /* Specify which IP version we use */ - let mut ip_version = 0; - if args.do_ipv4 && !args.do_ipv6 { - ip_version = 4; - } - else if !args.do_ipv4 && args.do_ipv6 { - ip_version = 6; - } - if args.do_ipv4 && args.do_ipv6 { - return Err("you cannot specify both -4 and -6".to_string()); - } - - /* Select the default upstream IP if not specified in arguments */ - let upstream: SocketAddr = match (args.server, args.port) { - (Some(addr), Some(port)) => SocketAddr::new(addr, port), - (Some(addr), None) => SocketAddr::new(addr, 0), - (None, Some(port)) => { - // Select this upstream just to have this var non-empty - let mut upstream_socketaddr: SocketAddr = upstreams.servers[0].addr; - - for server in &upstreams.servers { - if ip_version == 4 && server.addr.is_ipv4() { - upstream_socketaddr = server.addr; - } else if ip_version == 6 && server.addr.is_ipv6() { - upstream_socketaddr = server.addr; - } else { - return Err("No upstream IP found for specified IP version".to_string()); - } - } - - upstreams.servers[0].addr.set_port(port); - upstream_socketaddr - }, - (None, None) => upstreams.servers[0].addr, - }; - - - Ok(Request { - args: args.clone(), // @TODO find better way? - upstream, - }) - } - - fn process(self) -> Result<(), BoreError> { - // Bind a UDP socket to a kernel-provided port - let socket = match self.upstream { - SocketAddr::V4(_) => UdpSocket::bind("0.0.0.0:0").expect("couldn't bind to address"), - SocketAddr::V6(_) => UdpSocket::bind("[::]:0").expect("couldn't bind to address"), - }; - - let message = self.create_message()?; - - // Send message off to the server using our socket - socket.send_to(&message.as_dgram_slice(), self.upstream)?; - - // Create recv buffer - let mut buffer = vec![0; 1232]; - - // Recv in buffer - socket.recv_from(&mut buffer)?; - - // Parse the response - let response = Message::from_octets(buffer).map_err(|_| "bad response")?; - self.print_response(response); - - /* Print message information */ - println!("\n;; SERVER: {}", self.upstream); - - Ok(()) - } - - - fn create_message(&self) -> Result>, BoreError> { - // @TODO create the sections individually to gain more control/flexibility - - // Create a message builder wrapping a compressor wrapping a stream - // target. - let mut msg = MessageBuilder::from_target( - StaticCompressor::new( - StreamTarget::new_vec() - ) - ).unwrap(); - - // Set the RD bit and a random ID in the header and proceed to - // the question section. - if !self.args.no_rd_bit { - msg.header_mut().set_rd(true); - } - - msg.header_mut().set_random_id(); - let mut msg = msg.question(); - - // Add a question and proceed to the answer section. - msg.push((&self.args.qname, self.args.qtype)).unwrap(); - - let mut msg = msg.additional(); - - // Add an OPT record. - // @TODO make this configurable - msg.opt(|opt| { - opt.set_udp_payload_size(4096); - - if self.args.nsid { - opt.nsid(b"")?; - } - - if self.args.do_bit { - opt.set_dnssec_ok(true); - } - - Ok(()) - }).unwrap(); - - // Convert the builder into the actual message. - Ok(msg.finish().into_target()) - } - - fn print_response(&self, response: Message>) { - /* Header */ - let header = response.header(); - - println!(";; ->>HEADER<<- opcode: {}, rcode: {}, id: {}", - header.opcode(), header.rcode(), header.id()); - - print!(";; flags: {}", header.flags()); - - let count = response.header_counts(); - println!(" ; QUERY: {}, ANSWER: {}, AUTHORITY: {}, ADDITIONAL: {}\n", - count.qdcount(), count.ancount(), count.nscount(), count.arcount()); - - /* Question */ - println!(";; QUESTION SECTION:"); - - let question_section = response.question(); - - for question in question_section { - println!("; {}", question.unwrap()); - } - - /* Return early if there are no more records */ - if count.ancount() == 0 && count.nscount() == 0 && count.arcount() == 0 { - println!(); - return; - } - - /* Answer */ - println!("\n;; ANSWER SECTION:"); - - /* Unpack and parse with all known record types */ - let answer_section = response.answer().unwrap().limit_to::>(); - - for record in answer_section { - println!("{}", record.unwrap()); - } - - /* Return early if there are no more records */ - if count.nscount() == 0 && count.arcount() == 0 { - println!(); - return; - } - - /* Authority */ - println!("\n;; AUTHORITY SECTION:"); - - let authority_section = response.authority().unwrap().limit_to::>(); - - for record in authority_section { - println!("{}", record.unwrap()); - } - - /* Return early if there are no more records */ - if count.arcount() == 0 { - println!(); - return; - } - - /* Additional */ - println!("\n;; ADDITIONAL SECTION:"); - - let additional_section = response.additional().unwrap().limit_to::>(); - - for record in additional_section { - if record.as_ref().unwrap().rtype() != Rtype::Opt { - println!("{}", record.unwrap()); - } - } - - let opt_record = response.opt().unwrap(); - - println!("\n;; EDNS: version {}; flags: {}; udp: {}", // @TODO remove hardcode UDP - opt_record.version(), opt_record.dnssec_ok(), opt_record.udp_payload_size()); - - for option in opt_record.iter::>() { - let opt = option.unwrap(); - match opt { - AllOptData::Nsid(nsid) => println!("; NSID: {}", nsid), - AllOptData::Dau(dau) => println!("; DAU: {}", dau), - AllOptData::Dhu(dhu) => println!("; DHU: {}", dhu), - AllOptData::N3u(n3u) => println!("; N3U: {}", n3u), - AllOptData::Expire(expire) => println!("; EXPIRE: {}", expire), - AllOptData::TcpKeepalive(tcpkeepalive) => println!("; TCPKEEPALIVE: {}", tcpkeepalive), - AllOptData::Padding(padding) => println!("; PADDING: {}", padding), - AllOptData::ClientSubnet(clientsubnet) => println!("; CLIENTSUBNET: {}", clientsubnet), - AllOptData::Cookie(cookie) => println!("; COOKIE: {}", cookie), - AllOptData::Chain(chain) => println!("; CHAIN: {}", chain), - AllOptData::KeyTag(keytag) => println!("; KEYTAG: {}", keytag), - AllOptData::ExtendedError(extendederror) => println!("; EDE: {}", extendederror), - _ => println!("NO OPT!"), - } - } - } -} - - -struct BoreError { - msg: String, -} - -impl From<&str> for BoreError { - fn from(err: &str) -> Self { - BoreError { msg: err.to_string() } - } -} - -impl From for BoreError { - fn from(err: io::Error) -> Self { - BoreError { msg: err.to_string() } - } -} - -impl fmt::Display for BoreError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(&self.msg) - } -} - - -fn main() { - let args = GlobalParamArgs::parse(); - - let request = match Request::configure(args) { - Ok(request) => request, - Err(err) => { - println!("Bore configure error: {}", err); - process::exit(1); - } - }; - - if let Err(err) = request.process() { - println!("Bore process error: {}", err); - process::exit(1); - } -} - diff --git a/src/bin/idns.rs b/src/bin/idns.rs new file mode 100644 index 0000000..58a81c8 --- /dev/null +++ b/src/bin/idns.rs @@ -0,0 +1,11 @@ +//! The _idns_ binary. + +use clap::Parser; +use domain_tools::idns; + +fn main() { + if let Err(err) = idns::Args::parse().execute() { + eprintln!("{}", err); + } +} + diff --git a/src/idns/args.rs b/src/idns/args.rs new file mode 100644 index 0000000..f9fc2b0 --- /dev/null +++ b/src/idns/args.rs @@ -0,0 +1,18 @@ +//! Global configuration. + +use super::commands::Commands; +use super::error::Error; + + +#[derive(Clone, Debug, clap::Parser)] +pub struct Args { + #[command(subcommand)] + command: Commands, +} + +impl Args { + pub fn execute(self) -> Result<(), Error> { + self.command.execute() + } +} + diff --git a/src/idns/commands/mod.rs b/src/idns/commands/mod.rs new file mode 100644 index 0000000..1f8354f --- /dev/null +++ b/src/idns/commands/mod.rs @@ -0,0 +1,22 @@ +//! The various commands of _idsn._ + +pub mod query; + + +use super::error::Error; + + +#[derive(Clone, Debug, clap::Subcommand)] +pub enum Commands { + /// Query the DNS. + Query(self::query::Args), +} + +impl Commands { + pub fn execute(self) -> Result<(), Error> { + match self { + Self::Query(query) => query.execute(), + } + } +} + diff --git a/src/idns/commands/query.rs b/src/idns/commands/query.rs new file mode 100644 index 0000000..5efff8a --- /dev/null +++ b/src/idns/commands/query.rs @@ -0,0 +1,313 @@ +//! The query command of _idns._ + +use std::collections::HashSet; +use std::net::{IpAddr, SocketAddr}; +use std::str::FromStr; +use bytes::Bytes; +use domain::base::iana::Rtype; +use domain::base::message::Message; +use domain::base::message_builder::MessageBuilder; +use domain::base::name::{Dname, UncertainDname}; +use domain::base::opt::AllOptData; +use domain::net::client; +use domain::net::client::request::{RequestMessage, SendRequest}; +use domain::rdata::AllRecordData; +use domain::resolv::StubResolver; +use domain::resolv::stub::conf::ResolvConf; +use crate::idns::error::Error; + + +#[derive(Clone, Debug, clap::Args)] +pub struct Args { + /// The name of the resource records to look up + #[arg(value_name="QUERY_NAME")] + qname: Dname>, + + /// The record type to look up + #[arg(value_name="QUERY_TYPE", default_value = "A")] + qtype: Rtype, + + /// The server to send the query to. System servers used if missing + #[arg(short, long, value_name="ADDR_OR_HOST")] + server: Option, + + /// The port of the server to send query to. + #[arg(short = 'p', long = "port", requires = "server")] + port: Option, + + /// Use only IPv4 for communication. + #[arg(short = '4', long, conflicts_with = "ipv6")] + ipv4: bool, + + /// Use only IPv6 for communication. + #[arg(short = '6', long, conflicts_with = "ipv4")] + ipv6: bool, + + /// Use only TCP. + #[arg(short, long)] + tcp: bool, + + /// Use the given message ID. Random if missing. + #[arg(long)] + id: Option, + + /// Unset the RD flag in the request. + #[arg(long)] + no_rd: bool, + +} + +impl Args { + pub fn execute(self) -> Result<(), Error> { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() + .block_on(self.async_execute()) + } + + pub async fn async_execute(self) -> Result<(), Error> { + let servers = match self.server { + Some(ServerName::Name(ref host)) => self.host_server(host).await?, + Some(ServerName::Addr(addr)) => self.addr_server(addr), + None => self.default_server(), + }; + + let request = self.create_request(); + let answer = self.send_and_receive(servers, request).await?; + self.print_response(answer); + Ok(()) + } + + /// Resolves a provided server name. + async fn host_server( + &self, server: &UncertainDname> + ) -> Result, Error> { + let resolver = StubResolver::new(); + let answer = match server { + UncertainDname::Absolute(name) => { + resolver.lookup_host(name).await + } + UncertainDname::Relative(name) => { + resolver.search_host(name).await + } + }.map_err(|err| err.to_string())?; + + let mut res = Vec::new(); + for addr in answer.iter() { + if (addr.is_ipv4() && self.ipv6) || (addr.is_ipv6() && self.ipv4) { + continue + } + res.push(SocketAddr::new(addr, self.port.unwrap_or(53))); + } + Ok(res) + } + + /// Resolves a provided server name. + fn addr_server(&self, addr: IpAddr) -> Vec { + vec![SocketAddr::new(addr, self.port.unwrap_or(53))] + } + + /// Create the default server configuration. + fn default_server(&self) -> Vec { + let mut res = HashSet::new(); + for server in ResolvConf::default().servers { + res.insert(server.addr); + } + res.into_iter().collect() + } + + /// Creates a new request message. + fn create_request(&self) -> RequestMessage> { + let mut res = MessageBuilder::new_vec(); + + res.header_mut().set_rd(!self.no_rd); + if let Some(id) = self.id { + res.header_mut().set_id(id) + } + else { + res.header_mut().set_random_id(); + } + + let mut res = res.question(); + res.push((&self.qname, self.qtype)).unwrap(); + + RequestMessage::new(res) + } + + /// Sends the request and returns a response. + async fn send_and_receive( + &self, + mut server: Vec, + request: RequestMessage> + ) -> Result, Error> { + while let Some(addr) = server.pop() { + match self.send_and_receive_single(addr, request.clone()).await { + Ok(answer) => return Ok(answer), + Err(err) => { + if server.is_empty() { + return Err(err) + } + } + } + } + unreachable!() + } + + /// Sends the request to exactyl one server and returns the response. + async fn send_and_receive_single( + &self, + server: SocketAddr, + request: RequestMessage> + ) -> Result, Error> { + let stream_config = client::stream::Config::new(); + let multi_stream_config = client::multi_stream::Config::from( + stream_config + ); + let tcp_connect = client::protocol::TcpConnect::new(server); + if self.tcp { + let (conn, tran) = client::multi_stream::Connection::with_config( + tcp_connect, + multi_stream_config, + ); + tokio::spawn(tran.run()); + conn.send_request(request).get_response().await.map_err(|err| { + err.to_string().into() + }) + } + else { + let dgram_config = client::dgram::Config::new(); + let dgram_stream_config = client::dgram_stream::Config::from_parts( + dgram_config, multi_stream_config + ); + let udp_connect = client::protocol::UdpConnect::new(server); + let (conn, tran) = client::dgram_stream::Connection::with_config( + udp_connect, tcp_connect, dgram_stream_config, + ); + tokio::spawn(tran.run()); + conn.send_request(request).get_response().await.map_err(|err| { + err.to_string().into() + }) + } + } + + fn print_response(&self, response: Message) { + /* Header */ + let header = response.header(); + + println!(";; ->>HEADER<<- opcode: {}, rcode: {}, id: {}", + header.opcode(), header.rcode(), header.id()); + + print!(";; flags: {}", header.flags()); + + let count = response.header_counts(); + println!(" ; QUERY: {}, ANSWER: {}, AUTHORITY: {}, ADDITIONAL: {}\n", + count.qdcount(), count.ancount(), count.nscount(), count.arcount()); + + /* Question */ + println!(";; QUESTION SECTION:"); + + let question_section = response.question(); + + for question in question_section { + println!("; {}", question.unwrap()); + } + + /* Return early if there are no more records */ + if count.ancount() == 0 && count.nscount() == 0 && count.arcount() == 0 { + println!(); + return; + } + + /* Answer */ + println!("\n;; ANSWER SECTION:"); + + /* Unpack and parse with all known record types */ + let answer_section = response.answer().unwrap().limit_to::>(); + + for record in answer_section { + println!("{}", record.unwrap()); + } + + /* Return early if there are no more records */ + if count.nscount() == 0 && count.arcount() == 0 { + println!(); + return; + } + + /* Authority */ + println!("\n;; AUTHORITY SECTION:"); + + let authority_section = response.authority().unwrap().limit_to::>(); + + for record in authority_section { + println!("{}", record.unwrap()); + } + + /* Return early if there are no more records */ + if count.arcount() == 0 { + println!(); + return; + } + + /* Additional */ + println!("\n;; ADDITIONAL SECTION:"); + + let additional_section = response.additional().unwrap().limit_to::>(); + + for record in additional_section { + if record.as_ref().unwrap().rtype() != Rtype::Opt { + println!("{}", record.unwrap()); + } + } + + let opt_record = response.opt().unwrap(); + + println!("\n;; EDNS: version {}; flags: {}; udp: {}", // @TODO remove hardcode UDP + opt_record.version(), opt_record.dnssec_ok(), opt_record.udp_payload_size()); + + for option in opt_record.opt().iter::>() { + let opt = option.unwrap(); + match opt { + AllOptData::Nsid(nsid) => println!("; NSID: {}", nsid), + AllOptData::Dau(dau) => println!("; DAU: {}", dau), + AllOptData::Dhu(dhu) => println!("; DHU: {}", dhu), + AllOptData::N3u(n3u) => println!("; N3U: {}", n3u), + AllOptData::Expire(expire) => println!("; EXPIRE: {}", expire), + AllOptData::TcpKeepalive(tcpkeepalive) => println!("; TCPKEEPALIVE: {}", tcpkeepalive), + AllOptData::Padding(padding) => println!("; PADDING: {}", padding), + AllOptData::ClientSubnet(clientsubnet) => println!("; CLIENTSUBNET: {}", clientsubnet), + AllOptData::Cookie(cookie) => println!("; COOKIE: {}", cookie), + AllOptData::Chain(chain) => println!("; CHAIN: {}", chain), + AllOptData::KeyTag(keytag) => println!("; KEYTAG: {}", keytag), + AllOptData::ExtendedError(extendederror) => println!("; EDE: {}", extendederror), + _ => println!("NO OPT!"), + } + } + } +} + + +//------------ ServerName --------------------------------------------------- + +#[derive(Clone, Debug)] +enum ServerName { + Name(UncertainDname>), + Addr(IpAddr), +} + +impl FromStr for ServerName { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + if let Ok(addr) = IpAddr::from_str(s) { + Ok(ServerName::Addr(addr)) + } + else { + UncertainDname::from_str(s).map(Self::Name).map_err(|_| + "illegal host name" + ) + } + } +} + diff --git a/src/idns/error.rs b/src/idns/error.rs new file mode 100644 index 0000000..5bf757b --- /dev/null +++ b/src/idns/error.rs @@ -0,0 +1,23 @@ +//! Error handling. + +use std::fmt; + + +//------------ Error --------------------------------------------------------- + +pub struct Error { + message: String, +} + +impl From for Error { + fn from(message: String) -> Self { + Self { message } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.message, f) + } +} + diff --git a/src/idns/mod.rs b/src/idns/mod.rs new file mode 100644 index 0000000..62f2ecc --- /dev/null +++ b/src/idns/mod.rs @@ -0,0 +1,8 @@ +//! The actual implementation of _idns._ + +pub use self::args::Args; + +pub mod args; +pub mod error; +pub mod commands; + diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..961e2c2 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,4 @@ +//! The actual implementation of the tools. + +pub mod idns; + From 5d9ebc354d81bf48850b38a906fb1e7db9bea13d Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Tue, 23 Apr 2024 12:57:52 +0200 Subject: [PATCH 02/24] Update domain and refuse AXFR/IXFR. --- Cargo.lock | 339 +++++++++++++++---------------------- src/idns/commands/query.rs | 31 +++- src/idns/error.rs | 6 + 3 files changed, 163 insertions(+), 213 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea545ca..ceb1ab2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,18 +67,20 @@ dependencies = [ [[package]] name = "async-lock" -version = "2.8.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" dependencies = [ - "event-listener", + "event-listener 4.0.3", + "event-listener-strategy", + "pin-project-lite", ] [[package]] name = "async-trait" -version = "0.1.79" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", @@ -120,15 +122,9 @@ checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "bumpalo" -version = "3.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" - -[[package]] -name = "bytecount" -version = "0.6.7" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytes" @@ -136,42 +132,11 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" -[[package]] -name = "camino" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", -] - [[package]] name = "cc" -version = "1.0.90" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" [[package]] name = "cfg-if" @@ -228,6 +193,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "concurrent-queue" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-channel" version = "0.5.12" @@ -264,19 +238,19 @@ dependencies = [ [[package]] name = "domain" version = "0.10.0-dev" -source = "git+https://github.com/NLnetLabs/domain.git?branch=main#7cc3de62915776cf598e1a9f3fb91d17fd9a796c" +source = "git+https://github.com/NLnetLabs/domain.git?branch=main#080b81eee9945090bdf9574a7cff06d8b2fdf1e7" dependencies = [ "bytes", "futures-util", "moka", "octseq", "pin-project-lite", - "proc-macro2", "rand", "smallvec", "time", "tokio", "tokio-rustls", + "tracing", ] [[package]] @@ -300,25 +274,36 @@ dependencies = [ ] [[package]] -name = "error-chain" -version = "0.12.4" +name = "event-listener" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" dependencies = [ - "version_check", + "concurrent-queue", + "parking", + "pin-project-lite", ] [[package]] name = "event-listener" -version = "2.5.3" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] [[package]] -name = "fastrand" -version = "2.0.2" +name = "event-listener-strategy" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.3", + "pin-project-lite", +] [[package]] name = "futures-core" @@ -359,9 +344,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -374,12 +359,6 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "heck" version = "0.5.0" @@ -392,12 +371,6 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - [[package]] name = "js-sys" version = "0.3.69" @@ -463,21 +436,21 @@ dependencies = [ [[package]] name = "moka" -version = "0.12.5" +version = "0.12.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1911e88d5831f748a4097a43862d129e3c6fca831eecac9b8db6d01d93c9de2" +checksum = "9e0d88686dc561d743b40de8269b26eaf0dc58781bde087b0984646602021d08" dependencies = [ "async-lock", "async-trait", "crossbeam-channel", "crossbeam-epoch", "crossbeam-utils", + "event-listener 5.3.0", "futures-util", "once_cell", "parking_lot", "quanta", "rustc_version", - "skeptic", "smallvec", "tagptr", "thiserror", @@ -526,6 +499,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "parking_lot" version = "0.12.1" @@ -575,24 +554,13 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] -[[package]] -name = "pulldown-cmark" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" -dependencies = [ - "bitflags 2.5.0", - "memchr", - "unicase", -] - [[package]] name = "quanta" version = "0.12.3" @@ -610,9 +578,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -697,9 +665,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.32" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags 2.5.0", "errno", @@ -710,9 +678,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.10" +version = "0.21.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" dependencies = [ "log", "ring", @@ -730,21 +698,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "ryu" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "scopeguard" version = "1.2.0" @@ -766,56 +719,27 @@ name = "semver" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" -dependencies = [ - "serde", -] [[package]] name = "serde" -version = "1.0.197" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.198" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "serde_json" -version = "1.0.115" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "skeptic" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" -dependencies = [ - "bytecount", - "cargo_metadata", - "error-chain", - "glob", - "pulldown-cmark", - "tempfile", - "walkdir", -] - [[package]] name = "slab" version = "0.4.9" @@ -855,9 +779,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.58" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -870,18 +794,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" -[[package]] -name = "tempfile" -version = "3.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys 0.52.0", -] - [[package]] name = "terminal_size" version = "0.3.0" @@ -894,18 +806,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ "proc-macro2", "quote", @@ -914,9 +826,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.34" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "num-conv", @@ -969,6 +881,37 @@ dependencies = [ "tokio", ] +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + [[package]] name = "triomphe" version = "0.1.11" @@ -1023,16 +966,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1119,15 +1052,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -1149,7 +1073,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -1169,17 +1093,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -1190,9 +1115,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -1202,9 +1127,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -1214,9 +1139,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -1226,9 +1157,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -1238,9 +1169,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -1250,9 +1181,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -1262,6 +1193,6 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/src/idns/commands/query.rs b/src/idns/commands/query.rs index 5efff8a..14a14ed 100644 --- a/src/idns/commands/query.rs +++ b/src/idns/commands/query.rs @@ -7,7 +7,7 @@ use bytes::Bytes; use domain::base::iana::Rtype; use domain::base::message::Message; use domain::base::message_builder::MessageBuilder; -use domain::base::name::{Dname, UncertainDname}; +use domain::base::name::{Name, UncertainName}; use domain::base::opt::AllOptData; use domain::net::client; use domain::net::client::request::{RequestMessage, SendRequest}; @@ -21,7 +21,7 @@ use crate::idns::error::Error; pub struct Args { /// The name of the resource records to look up #[arg(value_name="QUERY_NAME")] - qname: Dname>, + qname: Name>, /// The record type to look up #[arg(value_name="QUERY_TYPE", default_value = "A")] @@ -55,10 +55,23 @@ pub struct Args { #[arg(long)] no_rd: bool, + /// Disable all sanity checks. + #[arg(long, short = 'f')] + force: bool, + } impl Args { pub fn execute(self) -> Result<(), Error> { + if !self.force { + if self.qtype == Rtype::AXFR || self.qtype == Rtype::IXFR { + return Err( + "Please use the 'xfr' command for zone transfer.\n\ + (Use --force to query anyway.)".into() + ); + } + } + tokio::runtime::Builder::new_multi_thread() .enable_all() .build() @@ -81,14 +94,14 @@ impl Args { /// Resolves a provided server name. async fn host_server( - &self, server: &UncertainDname> + &self, server: &UncertainName> ) -> Result, Error> { let resolver = StubResolver::new(); let answer = match server { - UncertainDname::Absolute(name) => { + UncertainName::Absolute(name) => { resolver.lookup_host(name).await } - UncertainDname::Relative(name) => { + UncertainName::Relative(name) => { resolver.search_host(name).await } }.map_err(|err| err.to_string())?; @@ -154,7 +167,7 @@ impl Args { unreachable!() } - /// Sends the request to exactyl one server and returns the response. + /// Sends the request to exactly one server and returns the response. async fn send_and_receive_single( &self, server: SocketAddr, @@ -256,7 +269,7 @@ impl Args { let additional_section = response.additional().unwrap().limit_to::>(); for record in additional_section { - if record.as_ref().unwrap().rtype() != Rtype::Opt { + if record.as_ref().unwrap().rtype() != Rtype::OPT { println!("{}", record.unwrap()); } } @@ -292,7 +305,7 @@ impl Args { #[derive(Clone, Debug)] enum ServerName { - Name(UncertainDname>), + Name(UncertainName>), Addr(IpAddr), } @@ -304,7 +317,7 @@ impl FromStr for ServerName { Ok(ServerName::Addr(addr)) } else { - UncertainDname::from_str(s).map(Self::Name).map_err(|_| + UncertainName::from_str(s).map(Self::Name).map_err(|_| "illegal host name" ) } diff --git a/src/idns/error.rs b/src/idns/error.rs index 5bf757b..a4ed0e3 100644 --- a/src/idns/error.rs +++ b/src/idns/error.rs @@ -9,6 +9,12 @@ pub struct Error { message: String, } +impl<'a> From<&'a str> for Error { + fn from(message: &'a str) -> Self { + Self { message: message.into() } + } +} + impl From for Error { fn from(message: String) -> Self { Self { message } From 37115e8fd4ca158146eee04876e916b510333229 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Tue, 23 Apr 2024 13:13:38 +0200 Subject: [PATCH 03/24] Add all options from client transport configs. --- src/idns/commands/query.rs | 60 +++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/src/idns/commands/query.rs b/src/idns/commands/query.rs index 14a14ed..f7a435c 100644 --- a/src/idns/commands/query.rs +++ b/src/idns/commands/query.rs @@ -3,6 +3,7 @@ use std::collections::HashSet; use std::net::{IpAddr, SocketAddr}; use std::str::FromStr; +use std::time::Duration; use bytes::Bytes; use domain::base::iana::Rtype; use domain::base::message::Message; @@ -59,6 +60,17 @@ pub struct Args { #[arg(long, short = 'f')] force: bool, + /// Set the timeout for a query. + #[arg(long, value_name="SECONDS")] + timeout: Option, + + /// Set the number of retries over UDP. + #[arg(long)] + retries: Option, + + /// Set the advertised UDP payload size. + #[arg(long)] + udp_payload_size: Option, } impl Args { @@ -173,15 +185,11 @@ impl Args { server: SocketAddr, request: RequestMessage> ) -> Result, Error> { - let stream_config = client::stream::Config::new(); - let multi_stream_config = client::multi_stream::Config::from( - stream_config - ); let tcp_connect = client::protocol::TcpConnect::new(server); if self.tcp { let (conn, tran) = client::multi_stream::Connection::with_config( tcp_connect, - multi_stream_config, + self.multi_stream_config(), ); tokio::spawn(tran.run()); conn.send_request(request).get_response().await.map_err(|err| { @@ -189,13 +197,9 @@ impl Args { }) } else { - let dgram_config = client::dgram::Config::new(); - let dgram_stream_config = client::dgram_stream::Config::from_parts( - dgram_config, multi_stream_config - ); let udp_connect = client::protocol::UdpConnect::new(server); let (conn, tran) = client::dgram_stream::Connection::with_config( - udp_connect, tcp_connect, dgram_stream_config, + udp_connect, tcp_connect, self.dgram_stream_config(), ); tokio::spawn(tran.run()); conn.send_request(request).get_response().await.map_err(|err| { @@ -298,6 +302,42 @@ impl Args { } } } + + fn timeout(&self) -> Option { + self.timeout.map(Duration::from_secs_f32) + } + + fn dgram_config(&self) -> client::dgram::Config { + let mut res = client::dgram::Config::new(); + if let Some(timeout) = self.timeout() { + res.set_read_timeout(timeout); + } + if let Some(retries) = self.retries { + res.set_max_retries(retries) + } + if let Some(size) = self.udp_payload_size { + res.set_udp_payload_size(Some(size)) + } + res + } + + fn stream_config(&self) -> client::stream::Config { + let mut res = client::stream::Config::new(); + if let Some(timeout) = self.timeout() { + res.set_response_timeout(timeout); + } + res + } + + fn multi_stream_config(&self) -> client::multi_stream::Config { + client::multi_stream::Config::from(self.stream_config()) + } + + fn dgram_stream_config(&self) -> client::dgram_stream::Config { + client::dgram_stream::Config::from_parts( + self.dgram_config(), self.multi_stream_config() + ) + } } From 2ac955197746685e433b59b47f471da691da7798 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Wed, 24 Apr 2024 12:18:06 +0200 Subject: [PATCH 04/24] Break out message printing into its own module. --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/idns/commands/query.rs | 104 ++---------------------- src/idns/error.rs | 8 +- src/idns/mod.rs | 1 + src/idns/output/dig.rs | 158 +++++++++++++++++++++++++++++++++++++ src/idns/output/mod.rs | 33 ++++++++ 7 files changed, 207 insertions(+), 101 deletions(-) create mode 100644 src/idns/output/dig.rs create mode 100644 src/idns/output/mod.rs diff --git a/Cargo.lock b/Cargo.lock index ceb1ab2..6960f1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -238,7 +238,7 @@ dependencies = [ [[package]] name = "domain" version = "0.10.0-dev" -source = "git+https://github.com/NLnetLabs/domain.git?branch=main#080b81eee9945090bdf9574a7cff06d8b2fdf1e7" +source = "git+https://github.com/NLnetLabs/domain.git?branch=message-for-slice#b78477b815df89d9341384f9ee6f339feb9f384c" dependencies = [ "bytes", "futures-util", diff --git a/Cargo.toml b/Cargo.toml index eb9b396..d328e6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ rust-version = "1.65.0" [dependencies] bytes = "1" clap = { version = "4", features = ["derive", "unstable-doc"] } -domain = { git="https://github.com/NLnetLabs/domain.git", branch="main", features = ["resolv", "unstable-client-transport"]} +domain = { git="https://github.com/NLnetLabs/domain.git", branch="message-for-slice", features = ["resolv", "unstable-client-transport"]} tokio = { version = "1.33", features = ["rt-multi-thread"] } diff --git a/src/idns/commands/query.rs b/src/idns/commands/query.rs index f7a435c..47bfcf4 100644 --- a/src/idns/commands/query.rs +++ b/src/idns/commands/query.rs @@ -9,13 +9,12 @@ use domain::base::iana::Rtype; use domain::base::message::Message; use domain::base::message_builder::MessageBuilder; use domain::base::name::{Name, UncertainName}; -use domain::base::opt::AllOptData; use domain::net::client; use domain::net::client::request::{RequestMessage, SendRequest}; -use domain::rdata::AllRecordData; use domain::resolv::StubResolver; use domain::resolv::stub::conf::ResolvConf; use crate::idns::error::Error; +use crate::idns::output::OutputFormat; #[derive(Clone, Debug, clap::Args)] @@ -71,6 +70,10 @@ pub struct Args { /// Set the advertised UDP payload size. #[arg(long)] udp_payload_size: Option, + + /// Select the output format. + #[arg(long = "format", default_value = "dig")] + output_format: OutputFormat, } impl Args { @@ -100,7 +103,7 @@ impl Args { let request = self.create_request(); let answer = self.send_and_receive(servers, request).await?; - self.print_response(answer); + self.output_format.print(answer.for_slice_ref())?; Ok(()) } @@ -208,101 +211,6 @@ impl Args { } } - fn print_response(&self, response: Message) { - /* Header */ - let header = response.header(); - - println!(";; ->>HEADER<<- opcode: {}, rcode: {}, id: {}", - header.opcode(), header.rcode(), header.id()); - - print!(";; flags: {}", header.flags()); - - let count = response.header_counts(); - println!(" ; QUERY: {}, ANSWER: {}, AUTHORITY: {}, ADDITIONAL: {}\n", - count.qdcount(), count.ancount(), count.nscount(), count.arcount()); - - /* Question */ - println!(";; QUESTION SECTION:"); - - let question_section = response.question(); - - for question in question_section { - println!("; {}", question.unwrap()); - } - - /* Return early if there are no more records */ - if count.ancount() == 0 && count.nscount() == 0 && count.arcount() == 0 { - println!(); - return; - } - - /* Answer */ - println!("\n;; ANSWER SECTION:"); - - /* Unpack and parse with all known record types */ - let answer_section = response.answer().unwrap().limit_to::>(); - - for record in answer_section { - println!("{}", record.unwrap()); - } - - /* Return early if there are no more records */ - if count.nscount() == 0 && count.arcount() == 0 { - println!(); - return; - } - - /* Authority */ - println!("\n;; AUTHORITY SECTION:"); - - let authority_section = response.authority().unwrap().limit_to::>(); - - for record in authority_section { - println!("{}", record.unwrap()); - } - - /* Return early if there are no more records */ - if count.arcount() == 0 { - println!(); - return; - } - - /* Additional */ - println!("\n;; ADDITIONAL SECTION:"); - - let additional_section = response.additional().unwrap().limit_to::>(); - - for record in additional_section { - if record.as_ref().unwrap().rtype() != Rtype::OPT { - println!("{}", record.unwrap()); - } - } - - let opt_record = response.opt().unwrap(); - - println!("\n;; EDNS: version {}; flags: {}; udp: {}", // @TODO remove hardcode UDP - opt_record.version(), opt_record.dnssec_ok(), opt_record.udp_payload_size()); - - for option in opt_record.opt().iter::>() { - let opt = option.unwrap(); - match opt { - AllOptData::Nsid(nsid) => println!("; NSID: {}", nsid), - AllOptData::Dau(dau) => println!("; DAU: {}", dau), - AllOptData::Dhu(dhu) => println!("; DHU: {}", dhu), - AllOptData::N3u(n3u) => println!("; N3U: {}", n3u), - AllOptData::Expire(expire) => println!("; EXPIRE: {}", expire), - AllOptData::TcpKeepalive(tcpkeepalive) => println!("; TCPKEEPALIVE: {}", tcpkeepalive), - AllOptData::Padding(padding) => println!("; PADDING: {}", padding), - AllOptData::ClientSubnet(clientsubnet) => println!("; CLIENTSUBNET: {}", clientsubnet), - AllOptData::Cookie(cookie) => println!("; COOKIE: {}", cookie), - AllOptData::Chain(chain) => println!("; CHAIN: {}", chain), - AllOptData::KeyTag(keytag) => println!("; KEYTAG: {}", keytag), - AllOptData::ExtendedError(extendederror) => println!("; EDE: {}", extendederror), - _ => println!("NO OPT!"), - } - } - } - fn timeout(&self) -> Option { self.timeout.map(Duration::from_secs_f32) } diff --git a/src/idns/error.rs b/src/idns/error.rs index a4ed0e3..a2e7354 100644 --- a/src/idns/error.rs +++ b/src/idns/error.rs @@ -1,6 +1,6 @@ //! Error handling. -use std::fmt; +use std::{fmt, io}; //------------ Error --------------------------------------------------------- @@ -21,6 +21,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: io::Error) -> Self { + Self { message: err.to_string() } + } +} + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.message, f) diff --git a/src/idns/mod.rs b/src/idns/mod.rs index 62f2ecc..572d161 100644 --- a/src/idns/mod.rs +++ b/src/idns/mod.rs @@ -5,4 +5,5 @@ pub use self::args::Args; pub mod args; pub mod error; pub mod commands; +pub mod output; diff --git a/src/idns/output/dig.rs b/src/idns/output/dig.rs new file mode 100644 index 0000000..1d50d02 --- /dev/null +++ b/src/idns/output/dig.rs @@ -0,0 +1,158 @@ +//! An output format compatible with dig. + +use std::io; +use domain::base::Message; +use domain::base::opt::AllOptData; +use domain::rdata::AllRecordData; + +//------------ write --------------------------------------------------------- + +pub fn write( + msg: Message<&[u8]>, target: &mut impl io::Write +) -> Result<(), io::Error> { + // Header + let header = msg.header(); + let counts = msg.header_counts(); + + writeln!(target, + ";; ->>HEADER<<- opcode: {}, rcode: {}, id: {}", + header.opcode(), header.rcode(), header.id() + )?; + write!(target, ";; flags: {}", header.flags())?; + writeln!(target, + "; QUERY: {}, ANSWER: {}, AUTHORITY: {}, ADDITIONAL: {}\n", + counts.qdcount(), counts.ancount(), counts.nscount(), counts.arcount() + )?; + + if let Some(opt) = msg.opt() { + writeln!(target, "\n;; OPT PSEUDOSECTION:")?; + writeln!(target, + "; EDNS: version {}; flags: {}; udp: {}", + opt.version(), opt.dnssec_ok(), opt.udp_payload_size() + )?; + for option in opt.opt().iter::>() { + use AllOptData::*; + + match option { + Ok(opt) => match opt { + Nsid(nsid) => writeln!(target, "; NSID: {}", nsid)?, + Dau(dau) => writeln!(target, "; DAU: {}", dau)?, + Dhu(dhu) => writeln!(target, "; DHU: {}", dhu)?, + N3u(n3u) => writeln!(target, "; N3U: {}", n3u)?, + Expire(expire) => { + writeln!(target, "; EXPIRE: {}", expire)? + } + TcpKeepalive(opt) => { + writeln!(target, "; TCPKEEPALIVE: {}", opt)? + } + Padding(padding) => { + writeln!(target, "; PADDING: {}", padding)? + } + ClientSubnet(opt) => { + writeln!(target, "; CLIENTSUBNET: {}", opt)? + } + Cookie(cookie) => { + writeln!(target, "; COOKIE: {}", cookie)? + } + Chain(chain) => { + writeln!(target, "; CHAIN: {}", chain)? + } + KeyTag(keytag) => { + writeln!(target, "; KEYTAG: {}", keytag)? + } + ExtendedError(extendederror) => { + writeln!(target, "; EDE: {}", extendederror)? + } + Other(other) => { + writeln!(target, "; {}", other.code())?; + } + _ => writeln!(target, "Unknown OPT")?, + } + Err(err) => { + writeln!(target, "; ERROR: bad option: {}.", err)?; + } + } + } + } + + // Question + let questions = msg.question(); + if counts.qdcount() > 0 { + write!(target, ";; QUESTION SECTION:")?; + for item in questions { + match item { + Ok(item) => writeln!(target, "; {}", item)?, + Err(err) => { + writeln!(target, "; ERROR: bad question: {}.", err)?; + return Ok(()) + } + } + } + } + + /* Answer */ + let section = match questions.answer() { + Ok(section) => section.limit_to::>(), + Err(err) => { + writeln!(target, "; ERROR: bad question: {}.", err)?; + return Ok(()) + } + }; + if counts.ancount() > 0 { + writeln!(target, "\n;; ANSWER SECTION:")?; + for item in section { + match item { + Ok(item) => writeln!(target, "{}", item)?, + Err(err) => { + writeln!(target, "; Error: bad record: {}.", err)?; + return Ok(()) + } + } + } + } + + // Authority + let section = match questions.next_section() { + Ok(section) => section.limit_to::>(), + Err(err) => { + writeln!(target, "; ERROR: bad record: {}.", err)?; + return Ok(()) + } + }; + if counts.nscount() > 0 { + writeln!(target, "\n;; AUTHORITY SECTION:")?; + for item in section { + match item { + Ok(item) => writeln!(target, "{}", item)?, + Err(err) => { + writeln!(target, "; Error: bad record: {}.", err)?; + return Ok(()) + } + } + } + } + + // Additional + let section = match questions.next_section() { + Ok(section) => section.limit_to::>(), + Err(err) => { + writeln!(target, "; ERROR: bad record: {}.", err)?; + return Ok(()) + } + }; + if counts.arcount() > 0 { + writeln!(target, "\n;; ADDITIONAL SECTION:")?; + for item in section { + match item { + Ok(item) => writeln!(target, "{}", item)?, + Err(err) => { + writeln!(target, "; Error: bad record: {}.", err)?; + return Ok(()) + } + } + } + } + + Ok(()) +} + diff --git a/src/idns/output/mod.rs b/src/idns/output/mod.rs new file mode 100644 index 0000000..34f7c16 --- /dev/null +++ b/src/idns/output/mod.rs @@ -0,0 +1,33 @@ +//! Message output formats. + +mod dig; + + +use std::io; +use clap::ValueEnum; +use domain::base::Message; + +//------------ OutputFormat -------------------------------------------------- + +#[derive(Clone, Copy, Debug, ValueEnum)] +pub enum OutputFormat { + /// Similar to dig. + Dig +} + +impl OutputFormat { + pub fn write( + self, msg: Message<&[u8]>, target: &mut impl io::Write + ) -> Result<(), io::Error> { + match self { + Self::Dig => self::dig::write(msg, target) + } + } + + pub fn print( + self, msg: Message<&[u8]> + ) -> Result<(), io::Error> { + self.write(msg, &mut io::stdout().lock()) + } +} + From 299b829a71bf68ee24d216d4cb37cde38a4e4904 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Wed, 24 Apr 2024 17:32:34 +0200 Subject: [PATCH 05/24] Add query --verify. --- src/idns/commands/mod.rs | 2 +- src/idns/commands/query.rs | 171 ++++++++++++++++++++++++++++++++++++- src/idns/error.rs | 20 +++-- src/idns/output/dig.rs | 27 +++--- 4 files changed, 199 insertions(+), 21 deletions(-) diff --git a/src/idns/commands/mod.rs b/src/idns/commands/mod.rs index 1f8354f..d017d93 100644 --- a/src/idns/commands/mod.rs +++ b/src/idns/commands/mod.rs @@ -9,7 +9,7 @@ use super::error::Error; #[derive(Clone, Debug, clap::Subcommand)] pub enum Commands { /// Query the DNS. - Query(self::query::Args), + Query(self::query::Query), } impl Commands { diff --git a/src/idns/commands/query.rs b/src/idns/commands/query.rs index 47bfcf4..21b5969 100644 --- a/src/idns/commands/query.rs +++ b/src/idns/commands/query.rs @@ -8,17 +8,19 @@ use bytes::Bytes; use domain::base::iana::Rtype; use domain::base::message::Message; use domain::base::message_builder::MessageBuilder; -use domain::base::name::{Name, UncertainName}; +use domain::base::name::{Name, ToName, UncertainName}; use domain::net::client; use domain::net::client::request::{RequestMessage, SendRequest}; +use domain::rdata::{AllRecordData, Ns, Soa}; use domain::resolv::StubResolver; -use domain::resolv::stub::conf::ResolvConf; +use domain::resolv::stub; +use domain::resolv::stub::conf::{ResolvConf, ServerConf, Transport}; use crate::idns::error::Error; use crate::idns::output::OutputFormat; #[derive(Clone, Debug, clap::Args)] -pub struct Args { +pub struct Query { /// The name of the resource records to look up #[arg(value_name="QUERY_NAME")] qname: Name>, @@ -71,12 +73,18 @@ pub struct Args { #[arg(long)] udp_payload_size: Option, + /// Verify the answer against an authoritative server. + #[arg(long)] + verify: bool, + /// Select the output format. #[arg(long = "format", default_value = "dig")] output_format: OutputFormat, } -impl Args { +/// # Executing the command +/// +impl Query { pub fn execute(self) -> Result<(), Error> { if !self.force { if self.qtype == Rtype::AXFR || self.qtype == Rtype::IXFR { @@ -104,9 +112,27 @@ impl Args { let request = self.create_request(); let answer = self.send_and_receive(servers, request).await?; self.output_format.print(answer.for_slice_ref())?; + if self.verify { + let auth_answer = self.auth_answer().await?; + if Self::eq_answer( + answer.for_slice_ref(), auth_answer.for_slice_ref() + ) { + println!("\n;; Authoritative answer matches."); + } + else { + println!("\n;; Authoritative answer does not match."); + println!(";; AUTHORITATIVE ANSWER"); + self.output_format.print(auth_answer.for_slice_ref())?; + } + } Ok(()) } +} + +/// # Resolving the server set +/// +impl Query { /// Resolves a provided server name. async fn host_server( &self, server: &UncertainName> @@ -144,7 +170,11 @@ impl Args { } res.into_iter().collect() } +} +/// # Handling the actual query +/// +impl Query { /// Creates a new request message. fn create_request(&self) -> RequestMessage> { let mut res = MessageBuilder::new_vec(); @@ -210,7 +240,11 @@ impl Args { }) } } +} +/// # Server configurations +/// +impl Query { fn timeout(&self) -> Option { self.timeout.map(Duration::from_secs_f32) } @@ -248,6 +282,135 @@ impl Args { } } +/// # Get an authoritative answer +impl Query { + async fn auth_answer(&self) -> Result { + let addrs = { + let resolver = StubResolver::new(); + let apex = self.get_apex(&resolver).await?; + let ns_set = self.get_ns_set(&apex, &resolver).await?; + self.get_ns_addrs(&ns_set, &resolver).await? + }; + + let resolver = StubResolver::from_conf( + ResolvConf { + servers: addrs.into_iter().map(|addr| { + ServerConf::new( + SocketAddr::new(addr, 53), Transport::UdpTcp + ) + }).collect(), + options: Default::default(), + } + ); + + resolver.query((&self.qname, self.qtype)).await.map_err(Into::into) + } + + /// Tries to determine the apex of the zone the requested records live in. + async fn get_apex( + &self, resolv: &StubResolver + ) -> Result>, Error> { + // Ask for the SOA record for the qname. + let response = resolv.query((&self.qname, Rtype::SOA)).await?; + + // The SOA record is in the answer section if the qname is the apex + // or in the authority section with the apex as the owner name + // otherwise. + let mut answer = response.answer()?.limit_to_in::>(); + while let Some(soa) = answer.next() { + let soa = soa?; + if *soa.owner() == self.qname { + return Ok(self.qname.clone()) + } + else { + // Strange SOA in the answer section, let’s continue with + // the authority section. + break; + } + } + + let mut authority = answer.next_section()?.unwrap() + .limit_to_in::>(); + while let Some(soa) = authority.next() { + let soa = soa?; + return Ok(soa.owner().to_name()) + } + + Err("no SOA record".into()) + } + + /// Tries to find the NS set for the given apex name. + async fn get_ns_set( + &self, apex: &Name>, resolv: &StubResolver + ) -> Result>>, Error> { + let response = resolv.query((apex, Rtype::NS)).await?; + let mut res = Vec::new(); + for record in response.answer()?.limit_to_in::>() { + let record = record?; + if *record.owner() != apex { + continue; + } + res.push(record.data().nsdname().to_name()); + } + + // We could technically get the A and AAAA records from the additional + // section, but we’re going to ask anyway, so: meh. + + Ok(res) + } + + /// Tries to get all the addresses for all the name servers. + async fn get_ns_addrs( + &self, ns_set: &[Name>], resolv: &StubResolver + ) -> Result, Error> { + let mut res = HashSet::new(); + for ns in ns_set { + for addr in resolv.lookup_host(ns).await?.iter() { + res.insert(addr); + } + } + Ok(res.into_iter().collect()) + } + + /// Compares the answer section of two messages. + fn eq_answer(left: Message<&[u8]>, right: Message<&[u8]>) -> bool { + if left.header_counts().ancount() != right.header_counts().ancount() { + return false + } + let left = match left.answer() { + Ok(answer) => { + answer.into_records::>().map(|record| { + match record { + Ok(record) => { + let class = record.class(); + let (name, data) = record.into_owner_and_data(); + Some((name, class, data)) + } + Err(_) => None, + } + }).collect::>() + } + Err(_) => return false, + }; + let right = match right.answer() { + Ok(answer) => { + answer.into_records::>().map(|record| { + match record { + Ok(record) => { + let class = record.class(); + let (name, data) = record.into_owner_and_data(); + Some((name, class, data)) + } + Err(_) => None, + } + }).collect::>() + } + Err(_) => return false, + }; + left == right + } +} + //------------ ServerName --------------------------------------------------- diff --git a/src/idns/error.rs b/src/idns/error.rs index a2e7354..71502ba 100644 --- a/src/idns/error.rs +++ b/src/idns/error.rs @@ -1,29 +1,37 @@ //! Error handling. use std::{fmt, io}; +use std::borrow::Cow; +use domain::base::wire::ParseError; //------------ Error --------------------------------------------------------- pub struct Error { - message: String, + message: Cow<'static, str>, } -impl<'a> From<&'a str> for Error { - fn from(message: &'a str) -> Self { - Self { message: message.into() } +impl From<&'static str> for Error { + fn from(message: &'static str) -> Self { + Self { message: Cow::Borrowed(message) } } } impl From for Error { fn from(message: String) -> Self { - Self { message } + Self { message: Cow::Owned(message) } } } impl From for Error { fn from(err: io::Error) -> Self { - Self { message: err.to_string() } + Self::from(err.to_string()) + } +} + +impl From for Error { + fn from(_err: ParseError) -> Self { + Self::from("message parse error") } } diff --git a/src/idns/output/dig.rs b/src/idns/output/dig.rs index 1d50d02..db5a722 100644 --- a/src/idns/output/dig.rs +++ b/src/idns/output/dig.rs @@ -2,6 +2,7 @@ use std::io; use domain::base::Message; +use domain::base::iana::Rtype; use domain::base::opt::AllOptData; use domain::rdata::AllRecordData; @@ -24,7 +25,9 @@ pub fn write( counts.qdcount(), counts.ancount(), counts.nscount(), counts.arcount() )?; - if let Some(opt) = msg.opt() { + let opt = msg.opt(); // We need it further down ... + + if let Some(opt) = opt.as_ref() { writeln!(target, "\n;; OPT PSEUDOSECTION:")?; writeln!(target, "; EDNS: version {}; flags: {}; udp: {}", @@ -91,7 +94,7 @@ pub fn write( } /* Answer */ - let section = match questions.answer() { + let mut section = match questions.answer() { Ok(section) => section.limit_to::>(), Err(err) => { writeln!(target, "; ERROR: bad question: {}.", err)?; @@ -100,7 +103,7 @@ pub fn write( }; if counts.ancount() > 0 { writeln!(target, "\n;; ANSWER SECTION:")?; - for item in section { + while let Some(item) = section.next() { match item { Ok(item) => writeln!(target, "{}", item)?, Err(err) => { @@ -112,8 +115,8 @@ pub fn write( } // Authority - let section = match questions.next_section() { - Ok(section) => section.limit_to::>(), + let mut section = match section.next_section() { + Ok(section) => section.unwrap().limit_to::>(), Err(err) => { writeln!(target, "; ERROR: bad record: {}.", err)?; return Ok(()) @@ -121,7 +124,7 @@ pub fn write( }; if counts.nscount() > 0 { writeln!(target, "\n;; AUTHORITY SECTION:")?; - for item in section { + while let Some(item) = section.next() { match item { Ok(item) => writeln!(target, "{}", item)?, Err(err) => { @@ -133,18 +136,22 @@ pub fn write( } // Additional - let section = match questions.next_section() { - Ok(section) => section.limit_to::>(), + let section = match section.next_section() { + Ok(section) => section.unwrap().limit_to::>(), Err(err) => { writeln!(target, "; ERROR: bad record: {}.", err)?; return Ok(()) } }; - if counts.arcount() > 0 { + if counts.arcount() > 1 || (opt.is_none() && counts.arcount() > 0) { writeln!(target, "\n;; ADDITIONAL SECTION:")?; for item in section { match item { - Ok(item) => writeln!(target, "{}", item)?, + Ok(item) => { + if item.rtype() != Rtype::OPT { + writeln!(target, "{}", item)? + } + } Err(err) => { writeln!(target, "; Error: bad record: {}.", err)?; return Ok(()) From 284d33772b25ee2d14caaae27dbe9dfc3faf017c Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 25 Apr 2024 12:06:07 +0200 Subject: [PATCH 06/24] Add CI. --- .github/FUNDING.yml | 2 ++ .github/workflows/ci.yml | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 .github/FUNDING.yml create mode 100644 .github/workflows/ci.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..2a357c0 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: [NLnetLabs] +custom: ['https://nlnetlabs.nl/funding/'] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..777d5ae --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,32 @@ +name: ci +on: [push, pull_request] +jobs: + test: + name: test + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macOS-latest] + rust: [1.67.0, stable, beta, nightly] + env: + RUSTFLAGS: "-D warnings" + steps: + - name: Checkout repository + uses: actions/checkout@v1 + - name: Install Rust + uses: hecrj/setup-rust-action@v1 + with: + rust-version: ${{ matrix.rust }} + - if: matrix.rust == 'stable' + run: rustup component add clippy + - if: matrix.rust == 'stable' + run: cargo clippy --all-features --all-targets -- -D warnings + - if: matrix.rust == 'stable' && matrix.os == 'ubuntu-latest' + run: cargo fmt --all -- --check + - run: cargo check --no-default-features --all-targets + - run: cargo test --all-features + - if: matrix.rust == 'nightly' + run: | + cargo +nightly update -Z minimal-versions + cargo check --all-features --all-targets + name: Check with minimal-versions From cff491a4944dce4376feacb70b762c161abf7d91 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 25 Apr 2024 14:08:08 +0200 Subject: [PATCH 07/24] Clippy-suggested improvements. --- src/idns/commands/query.rs | 12 +++++------- src/idns/output/dig.rs | 4 ++-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/idns/commands/query.rs b/src/idns/commands/query.rs index 21b5969..f4efb08 100644 --- a/src/idns/commands/query.rs +++ b/src/idns/commands/query.rs @@ -86,6 +86,7 @@ pub struct Query { /// impl Query { pub fn execute(self) -> Result<(), Error> { + #[allow(clippy::collapsible_if)] // There may be more later ... if !self.force { if self.qtype == Rtype::AXFR || self.qtype == Rtype::IXFR { return Err( @@ -317,21 +318,18 @@ impl Query { // or in the authority section with the apex as the owner name // otherwise. let mut answer = response.answer()?.limit_to_in::>(); - while let Some(soa) = answer.next() { + if let Some(soa) = answer.next() { let soa = soa?; if *soa.owner() == self.qname { return Ok(self.qname.clone()) } - else { - // Strange SOA in the answer section, let’s continue with - // the authority section. - break; - } + // Strange SOA in the answer section, let’s continue with + // the authority section. } let mut authority = answer.next_section()?.unwrap() .limit_to_in::>(); - while let Some(soa) = authority.next() { + if let Some(soa) = authority.next() { let soa = soa?; return Ok(soa.owner().to_name()) } diff --git a/src/idns/output/dig.rs b/src/idns/output/dig.rs index db5a722..4d819ec 100644 --- a/src/idns/output/dig.rs +++ b/src/idns/output/dig.rs @@ -103,7 +103,7 @@ pub fn write( }; if counts.ancount() > 0 { writeln!(target, "\n;; ANSWER SECTION:")?; - while let Some(item) = section.next() { + for item in section.by_ref() { match item { Ok(item) => writeln!(target, "{}", item)?, Err(err) => { @@ -124,7 +124,7 @@ pub fn write( }; if counts.nscount() > 0 { writeln!(target, "\n;; AUTHORITY SECTION:")?; - while let Some(item) = section.next() { + for item in section.by_ref() { match item { Ok(item) => writeln!(target, "{}", item)?, Err(err) => { From 2bb58930048996e74c2e627d54df13870583abad Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 25 Apr 2024 14:16:28 +0200 Subject: [PATCH 08/24] No cargo fmt in CI. --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 777d5ae..8942fed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,8 +21,6 @@ jobs: run: rustup component add clippy - if: matrix.rust == 'stable' run: cargo clippy --all-features --all-targets -- -D warnings - - if: matrix.rust == 'stable' && matrix.os == 'ubuntu-latest' - run: cargo fmt --all -- --check - run: cargo check --no-default-features --all-targets - run: cargo test --all-features - if: matrix.rust == 'nightly' From 09785306068246cdce01c1a4c59f0d19184bf7df Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 25 Apr 2024 14:24:19 +0200 Subject: [PATCH 09/24] Rust 1.74, apparently. --- .github/workflows/ci.yml | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8942fed..d63cbb5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macOS-latest] - rust: [1.67.0, stable, beta, nightly] + rust: [1.74.0, stable, beta, nightly] env: RUSTFLAGS: "-D warnings" steps: diff --git a/Cargo.toml b/Cargo.toml index d328e6e..a673eac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "domain-tools" version = "0.1.0" edition = "2021" -rust-version = "1.65.0" +rust-version = "1.74.0" [dependencies] bytes = "1" From 5e8f2f1c64c0d4de0341d27faf787745eb954ced Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Fri, 26 Apr 2024 10:33:12 +0200 Subject: [PATCH 10/24] Rewrite querying. --- src/idns/client.rs | 243 +++++++++++++++++++++++++++++++++++++ src/idns/commands/query.rs | 212 ++++++++++++++++---------------- src/idns/error.rs | 11 +- src/idns/mod.rs | 1 + src/idns/output/dig.rs | 17 ++- src/idns/output/mod.rs | 6 +- 6 files changed, 376 insertions(+), 114 deletions(-) create mode 100644 src/idns/client.rs diff --git a/src/idns/client.rs b/src/idns/client.rs new file mode 100644 index 0000000..8c70d81 --- /dev/null +++ b/src/idns/client.rs @@ -0,0 +1,243 @@ +//! The DNS client for _idns._ + +use std::fmt; +use std::net::SocketAddr; +use std::time::{Duration, SystemTime}; +use bytes::Bytes; +use domain::base::message::Message; +use domain::base::message_builder::MessageBuilder; +use domain::base::name::ToName; +use domain::base::question::Question; +use domain::net::client::{dgram, stream}; +use domain::net::client::protocol::UdpConnect; +use domain::net::client::request::{RequestMessage, SendRequest}; +use domain::resolv::stub::conf; +use tokio::net::TcpStream; +use crate::idns::error::Error; + + +//------------ Client -------------------------------------------------------- + +/// The DNS client used by _idns._ +#[derive(Clone, Debug)] +pub struct Client { + servers: Vec, +} + +impl Client { + /// Creates a client using the system configuration. + pub fn system() -> Self { + let conf = conf::ResolvConf::default(); + Self { + servers: conf.servers.iter().map(|server| { + Server { + addr: server.addr, + transport: server.transport.into(), + timeout: server.request_timeout, + retries: u8::try_from(conf.options.attempts).unwrap_or(2), + udp_payload_size: server.udp_payload_size, + } + }).collect(), + } + } + + pub fn with_servers(servers: Vec) -> Self { + Self { servers } + } + + pub async fn query>>( + &self, question: Q + ) -> Result { + let mut res = MessageBuilder::new_vec(); + + res.header_mut().set_rd(true); + res.header_mut().set_random_id(); + + let mut res = res.question(); + res.push(question.into()).unwrap(); + + self.request(RequestMessage::new(res)).await + } + + pub async fn request( + &self, request: RequestMessage> + ) -> Result { + let mut servers = self.servers.as_slice(); + while let Some((server, tail)) = servers.split_first() { + match self.request_server(request.clone(), server).await { + Ok(answer) => return Ok(answer), + Err(err) => { + if tail.is_empty() { + return Err(err) + } + } + } + servers = tail; + } + unreachable!() + } + + pub async fn request_server( + &self, request: RequestMessage>, server: &Server, + ) -> Result { + match server.transport { + Transport::UdpTcp => self.request_udptcp(request, server).await, + Transport::Tcp => self.request_tcp(request, server).await, + } + } + + pub async fn request_udptcp( + &self, request: RequestMessage>, server: &Server, + ) -> Result { + let answer = self.request_udp(request.clone(), server).await?; + if answer.message.header().tc() { + self.request_tcp(request, server).await + } + else { + Ok(answer) + } + } + + pub async fn request_udp( + &self, request: RequestMessage>, server: &Server, + ) -> Result { + let mut stats = Stats::new(server.addr, Protocol::Udp); + let conn = dgram::Connection::with_config( + UdpConnect::new(server.addr), + Self::dgram_config(server) + ); + let message = conn.send_request(request).get_response().await?; + stats.finalize(); + Ok(Answer { message, stats }) + } + + pub async fn request_tcp( + &self, request: RequestMessage>, server: &Server, + ) -> Result { + let mut stats = Stats::new(server.addr, Protocol::Tcp); + let socket = TcpStream::connect(server.addr).await?; + let (conn, tran) = stream::Connection::with_config( + socket, Self::stream_config(server) + ); + tokio::spawn(tran.run()); + let message = conn.send_request(request).get_response().await?; + stats.finalize(); + Ok(Answer { message, stats }) + } + + fn dgram_config(server: &Server) -> dgram::Config { + let mut res = dgram::Config::new(); + res.set_read_timeout(server.timeout); + res.set_max_retries(server.retries); + res.set_udp_payload_size(Some(server.udp_payload_size)); + res + } + + fn stream_config(server: &Server) -> stream::Config { + let mut res = stream::Config::new(); + res.set_response_timeout(server.timeout); + res + } +} + + +//------------ Server -------------------------------------------------------- + +#[derive(Clone, Debug)] +pub struct Server { + pub addr: SocketAddr, + pub transport: Transport, + pub timeout: Duration, + pub retries: u8, + pub udp_payload_size: u16, +} + + +//------------ Transport ----------------------------------------------------- + +#[derive(Clone, Copy, Debug)] +pub enum Transport { + UdpTcp, + Tcp, +} + +impl From for Transport { + fn from(transport: conf::Transport) -> Self { + match transport { + conf::Transport::UdpTcp => Transport::UdpTcp, + conf::Transport::Tcp => Transport::Tcp, + } + } +} + + +//------------ Answer -------------------------------------------------------- + +/// An answer for a query. +pub struct Answer { + message: Message, + stats: Stats, +} + +impl Answer { + pub fn stats(&self) -> Stats { + self.stats + } + + pub fn msg_slice(&self) -> Message<&[u8]> { + self.message.for_slice_ref() + } +} + +impl AsRef> for Answer { + fn as_ref(&self) -> &Message { + &self.message + } +} + + +//------------ Stats --------------------------------------------------------- + +#[derive(Clone, Copy, Debug)] +pub struct Stats { + pub start: SystemTime, + pub duration: Duration, + pub server_addr: SocketAddr, + pub server_proto: Protocol, +} + +impl Stats { + fn new(server_addr: SocketAddr, server_proto: Protocol) -> Self { + Stats { + start: SystemTime::now(), + duration: Default::default(), + server_addr, + server_proto, + } + } + + fn finalize(&mut self) { + self.duration = self.start.elapsed().unwrap_or_default(); + } +} + + +//------------ Protocol ------------------------------------------------------ + +#[derive(Clone, Copy, Debug)] +pub enum Protocol { + Udp, + Tcp, +} + +impl fmt::Display for Protocol { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str( + match *self { + Protocol::Udp => "UDP", + Protocol::Tcp => "TCP", + } + ) + } +} + diff --git a/src/idns/commands/query.rs b/src/idns/commands/query.rs index f4efb08..6e49588 100644 --- a/src/idns/commands/query.rs +++ b/src/idns/commands/query.rs @@ -1,4 +1,5 @@ //! The query command of _idns._ +#![allow(unused_imports)] use std::collections::HashSet; use std::net::{IpAddr, SocketAddr}; @@ -9,12 +10,14 @@ use domain::base::iana::Rtype; use domain::base::message::Message; use domain::base::message_builder::MessageBuilder; use domain::base::name::{Name, ToName, UncertainName}; -use domain::net::client; -use domain::net::client::request::{RequestMessage, SendRequest}; +use domain::net::client::{dgram, stream}; +use domain::net::client::request::RequestMessage; use domain::rdata::{AllRecordData, Ns, Soa}; -use domain::resolv::StubResolver; -use domain::resolv::stub; -use domain::resolv::stub::conf::{ResolvConf, ServerConf, Transport}; +use domain::resolv::Resolver; +use domain::resolv::lookup::{lookup_host, search_host}; +use domain::resolv::stub::StubResolver; +use domain::resolv::stub::conf::ResolvConf; +use crate::idns::client::{Answer, Client, Server, Transport}; use crate::idns::error::Error; use crate::idns::output::OutputFormat; @@ -49,18 +52,6 @@ pub struct Query { #[arg(short, long)] tcp: bool, - /// Use the given message ID. Random if missing. - #[arg(long)] - id: Option, - - /// Unset the RD flag in the request. - #[arg(long)] - no_rd: bool, - - /// Disable all sanity checks. - #[arg(long, short = 'f')] - force: bool, - /// Set the timeout for a query. #[arg(long, value_name="SECONDS")] timeout: Option, @@ -73,6 +64,18 @@ pub struct Query { #[arg(long)] udp_payload_size: Option, + /// Use the given message ID. Random if missing. + #[arg(long)] + id: Option, + + /// Unset the RD flag in the request. + #[arg(long)] + no_rd: bool, + + /// Disable all sanity checks. + #[arg(long, short = 'f')] + force: bool, + /// Verify the answer against an authoritative server. #[arg(long)] verify: bool, @@ -104,26 +107,25 @@ impl Query { } pub async fn async_execute(self) -> Result<(), Error> { - let servers = match self.server { + let client = match self.server { Some(ServerName::Name(ref host)) => self.host_server(host).await?, Some(ServerName::Addr(addr)) => self.addr_server(addr), - None => self.default_server(), + None => self.system_server(), }; - let request = self.create_request(); - let answer = self.send_and_receive(servers, request).await?; - self.output_format.print(answer.for_slice_ref())?; + let answer = client.request(self.create_request()).await?; + self.output_format.print(&answer)?; if self.verify { let auth_answer = self.auth_answer().await?; if Self::eq_answer( - answer.for_slice_ref(), auth_answer.for_slice_ref() + answer.msg_slice(), auth_answer.msg_slice() ) { println!("\n;; Authoritative answer matches."); } else { println!("\n;; Authoritative answer does not match."); println!(";; AUTHORITATIVE ANSWER"); - self.output_format.print(auth_answer.for_slice_ref())?; + self.output_format.print(&auth_answer)?; } } Ok(()) @@ -136,9 +138,9 @@ impl Query { impl Query { /// Resolves a provided server name. async fn host_server( - &self, server: &UncertainName> - ) -> Result, Error> { - let resolver = StubResolver::new(); + &self, server: &UncertainName>, + ) -> Result { + let resolver = StubResolver::default(); let answer = match server { UncertainName::Absolute(name) => { resolver.lookup_host(name).await @@ -148,28 +150,58 @@ impl Query { } }.map_err(|err| err.to_string())?; - let mut res = Vec::new(); + let mut servers = Vec::new(); for addr in answer.iter() { if (addr.is_ipv4() && self.ipv6) || (addr.is_ipv6() && self.ipv4) { continue } - res.push(SocketAddr::new(addr, self.port.unwrap_or(53))); + servers.push(Server { + addr: SocketAddr::new(addr, self.port.unwrap_or(53)), + transport: self.transport(), + timeout: self.timeout(), + retries: self.retries.unwrap_or(2), + udp_payload_size: self.udp_payload_size.unwrap_or(1232), + }); } - Ok(res) + Ok(Client::with_servers(servers)) } /// Resolves a provided server name. - fn addr_server(&self, addr: IpAddr) -> Vec { - vec![SocketAddr::new(addr, self.port.unwrap_or(53))] + fn addr_server(&self, addr: IpAddr) -> Client { + Client::with_servers(vec![ + Server { + addr: SocketAddr::new(addr, self.port.unwrap_or(53)), + transport: self.transport(), + timeout: self.timeout(), + retries: self.retries(), + udp_payload_size: self.udp_payload_size() + } + ]) } - /// Create the default server configuration. - fn default_server(&self) -> Vec { - let mut res = HashSet::new(); - for server in ResolvConf::default().servers { - res.insert(server.addr); + /// Creates a client based on the system defaults. + fn system_server(&self) -> Client { + let conf = ResolvConf::default(); + Client::with_servers( + conf.servers.iter().map(|server| { + Server { + addr: server.addr, + transport: self.transport(), + timeout: server.request_timeout, + retries: u8::try_from(conf.options.attempts).unwrap_or(2), + udp_payload_size: server.udp_payload_size, + } + }).collect() + ) + } + + fn transport(&self) -> Transport { + if self.tcp { + Transport::Tcp + } + else { + Transport::UdpTcp } - res.into_iter().collect() } } @@ -194,12 +226,13 @@ impl Query { RequestMessage::new(res) } +/* /// Sends the request and returns a response. async fn send_and_receive( &self, mut server: Vec, request: RequestMessage> - ) -> Result, Error> { + ) -> Result<(Message, client::Stats), Error> { while let Some(addr) = server.pop() { match self.send_and_receive_single(addr, request.clone()).await { Ok(answer) => return Ok(answer), @@ -218,93 +251,46 @@ impl Query { &self, server: SocketAddr, request: RequestMessage> - ) -> Result, Error> { - let tcp_connect = client::protocol::TcpConnect::new(server); - if self.tcp { - let (conn, tran) = client::multi_stream::Connection::with_config( - tcp_connect, - self.multi_stream_config(), - ); - tokio::spawn(tran.run()); - conn.send_request(request).get_response().await.map_err(|err| { - err.to_string().into() - }) - } - else { - let udp_connect = client::protocol::UdpConnect::new(server); - let (conn, tran) = client::dgram_stream::Connection::with_config( - udp_connect, tcp_connect, self.dgram_stream_config(), - ); - tokio::spawn(tran.run()); - conn.send_request(request).get_response().await.map_err(|err| { - err.to_string().into() - }) + ) -> Result<(Message, client::Stats), Error> { + if !self.tcp { + let (response, stats) = udp( + request.clone(), server, self.dgram_config() + ).await?; + if !response.header().tc() { + return Ok((response, stats)) + } } + tcp(request, server, self.stream_config()).await } +*/ } -/// # Server configurations +/// # Configurations /// impl Query { - fn timeout(&self) -> Option { - self.timeout.map(Duration::from_secs_f32) - } - - fn dgram_config(&self) -> client::dgram::Config { - let mut res = client::dgram::Config::new(); - if let Some(timeout) = self.timeout() { - res.set_read_timeout(timeout); - } - if let Some(retries) = self.retries { - res.set_max_retries(retries) - } - if let Some(size) = self.udp_payload_size { - res.set_udp_payload_size(Some(size)) - } - res + fn timeout(&self) -> Duration { + Duration::from_secs_f32(self.timeout.unwrap_or(5.)) } - fn stream_config(&self) -> client::stream::Config { - let mut res = client::stream::Config::new(); - if let Some(timeout) = self.timeout() { - res.set_response_timeout(timeout); - } - res + fn retries(&self) -> u8 { + self.retries.unwrap_or(2) } - fn multi_stream_config(&self) -> client::multi_stream::Config { - client::multi_stream::Config::from(self.stream_config()) - } - - fn dgram_stream_config(&self) -> client::dgram_stream::Config { - client::dgram_stream::Config::from_parts( - self.dgram_config(), self.multi_stream_config() - ) + fn udp_payload_size(&self) -> u16 { + self.udp_payload_size.unwrap_or(1232) } } /// # Get an authoritative answer impl Query { - async fn auth_answer(&self) -> Result { - let addrs = { + async fn auth_answer(&self) -> Result { + let servers = { let resolver = StubResolver::new(); let apex = self.get_apex(&resolver).await?; let ns_set = self.get_ns_set(&apex, &resolver).await?; self.get_ns_addrs(&ns_set, &resolver).await? }; - - let resolver = StubResolver::from_conf( - ResolvConf { - servers: addrs.into_iter().map(|addr| { - ServerConf::new( - SocketAddr::new(addr, 53), Transport::UdpTcp - ) - }).collect(), - options: Default::default(), - } - ); - - resolver.query((&self.qname, self.qtype)).await.map_err(Into::into) + Client::with_servers(servers).query((&self.qname, self.qtype)).await } /// Tries to determine the apex of the zone the requested records live in. @@ -360,14 +346,24 @@ impl Query { /// Tries to get all the addresses for all the name servers. async fn get_ns_addrs( &self, ns_set: &[Name>], resolv: &StubResolver - ) -> Result, Error> { + ) -> Result, Error> { let mut res = HashSet::new(); for ns in ns_set { for addr in resolv.lookup_host(ns).await?.iter() { res.insert(addr); } } - Ok(res.into_iter().collect()) + Ok( + res.into_iter().map(|addr| { + Server { + addr: SocketAddr::new(addr, 53), + transport: Transport::UdpTcp, + timeout: self.timeout(), + retries: self.retries(), + udp_payload_size: self.udp_payload_size(), + } + }).collect() + ) } /// Compares the answer section of two messages. diff --git a/src/idns/error.rs b/src/idns/error.rs index 71502ba..5024fb4 100644 --- a/src/idns/error.rs +++ b/src/idns/error.rs @@ -1,12 +1,14 @@ //! Error handling. -use std::{fmt, io}; +use std::{error, fmt, io}; use std::borrow::Cow; use domain::base::wire::ParseError; +use domain::net::client::request; //------------ Error --------------------------------------------------------- +#[derive(Clone, Debug)] pub struct Error { message: Cow<'static, str>, } @@ -35,9 +37,16 @@ impl From for Error { } } +impl From for Error { + fn from(err: request::Error) -> Self { + Self::from(err.to_string()) + } +} + impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.message, f) } } +impl error::Error for Error { } diff --git a/src/idns/mod.rs b/src/idns/mod.rs index 572d161..98bc564 100644 --- a/src/idns/mod.rs +++ b/src/idns/mod.rs @@ -3,6 +3,7 @@ pub use self::args::Args; pub mod args; +pub mod client; pub mod error; pub mod commands; pub mod output; diff --git a/src/idns/output/dig.rs b/src/idns/output/dig.rs index 4d819ec..ac04475 100644 --- a/src/idns/output/dig.rs +++ b/src/idns/output/dig.rs @@ -1,16 +1,18 @@ //! An output format compatible with dig. use std::io; -use domain::base::Message; use domain::base::iana::Rtype; use domain::base::opt::AllOptData; use domain::rdata::AllRecordData; +use crate::idns::client::Answer; //------------ write --------------------------------------------------------- pub fn write( - msg: Message<&[u8]>, target: &mut impl io::Write + answer: &Answer, target: &mut impl io::Write ) -> Result<(), io::Error> { + let msg = answer.msg_slice(); + // Header let header = msg.header(); let counts = msg.header_counts(); @@ -160,6 +162,17 @@ pub fn write( } } + // Stats + let stats = answer.stats(); + writeln!(target, "\n;; Query time: {} msec", stats.duration.as_millis())?; + writeln!(target, + ";; SERVER: {}#{} ({})", + stats.server_addr.ip(), stats.server_addr.port(), + stats.server_proto + )?; + //writeln!(target, ";; WHEN: {}", stats.start)?; + writeln!(target, ";; MSG SIZE rcvd: {}", msg.as_slice().len())?; + Ok(()) } diff --git a/src/idns/output/mod.rs b/src/idns/output/mod.rs index 34f7c16..2c2edbd 100644 --- a/src/idns/output/mod.rs +++ b/src/idns/output/mod.rs @@ -5,7 +5,7 @@ mod dig; use std::io; use clap::ValueEnum; -use domain::base::Message; +use crate::idns::client::Answer; //------------ OutputFormat -------------------------------------------------- @@ -17,7 +17,7 @@ pub enum OutputFormat { impl OutputFormat { pub fn write( - self, msg: Message<&[u8]>, target: &mut impl io::Write + self, msg: &Answer, target: &mut impl io::Write ) -> Result<(), io::Error> { match self { Self::Dig => self::dig::write(msg, target) @@ -25,7 +25,7 @@ impl OutputFormat { } pub fn print( - self, msg: Message<&[u8]> + self, msg: &Answer, ) -> Result<(), io::Error> { self.write(msg, &mut io::stdout().lock()) } From 509c7ef68896501caea9db777ef2debf1720e9c1 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Fri, 26 Apr 2024 12:32:48 +0200 Subject: [PATCH 11/24] Add printing of WHEN time. --- Cargo.lock | 77 ++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/idns/client.rs | 11 +++--- src/idns/output/dig.rs | 10 ++++-- 4 files changed, 92 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6960f1a..2ae6573 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,21 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.13" @@ -144,6 +159,20 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.5", +] + [[package]] name = "clap" version = "4.5.4" @@ -202,6 +231,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + [[package]] name = "crossbeam-channel" version = "0.5.12" @@ -258,6 +293,7 @@ name = "domain-tools" version = "0.1.0" dependencies = [ "bytes", + "chrono", "clap", "domain", "tokio", @@ -371,6 +407,29 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "js-sys" version = "0.3.69" @@ -464,6 +523,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -1058,6 +1126,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.5", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index a673eac..ac964cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ rust-version = "1.74.0" [dependencies] bytes = "1" clap = { version = "4", features = ["derive", "unstable-doc"] } +chrono = { version = "0.4.38", features = [ "alloc", "clock" ] } domain = { git="https://github.com/NLnetLabs/domain.git", branch="message-for-slice", features = ["resolv", "unstable-client-transport"]} tokio = { version = "1.33", features = ["rt-multi-thread"] } diff --git a/src/idns/client.rs b/src/idns/client.rs index 8c70d81..249c928 100644 --- a/src/idns/client.rs +++ b/src/idns/client.rs @@ -2,8 +2,9 @@ use std::fmt; use std::net::SocketAddr; -use std::time::{Duration, SystemTime}; +use std::time::Duration; use bytes::Bytes; +use chrono::{DateTime, Local, TimeDelta}; use domain::base::message::Message; use domain::base::message_builder::MessageBuilder; use domain::base::name::ToName; @@ -200,8 +201,8 @@ impl AsRef> for Answer { #[derive(Clone, Copy, Debug)] pub struct Stats { - pub start: SystemTime, - pub duration: Duration, + pub start: DateTime, + pub duration: TimeDelta, pub server_addr: SocketAddr, pub server_proto: Protocol, } @@ -209,7 +210,7 @@ pub struct Stats { impl Stats { fn new(server_addr: SocketAddr, server_proto: Protocol) -> Self { Stats { - start: SystemTime::now(), + start: Local::now(), duration: Default::default(), server_addr, server_proto, @@ -217,7 +218,7 @@ impl Stats { } fn finalize(&mut self) { - self.duration = self.start.elapsed().unwrap_or_default(); + self.duration = Local::now() - self.start; } } diff --git a/src/idns/output/dig.rs b/src/idns/output/dig.rs index ac04475..0a58b93 100644 --- a/src/idns/output/dig.rs +++ b/src/idns/output/dig.rs @@ -164,13 +164,19 @@ pub fn write( // Stats let stats = answer.stats(); - writeln!(target, "\n;; Query time: {} msec", stats.duration.as_millis())?; + writeln!(target, + "\n;; Query time: {} msec", + stats.duration.num_milliseconds() + )?; writeln!(target, ";; SERVER: {}#{} ({})", stats.server_addr.ip(), stats.server_addr.port(), stats.server_proto )?; - //writeln!(target, ";; WHEN: {}", stats.start)?; + writeln!(target, + ";; WHEN: {}", + stats.start.format("%a %b %d %H:%M:%S %Z %Y") + )?; writeln!(target, ";; MSG SIZE rcvd: {}", msg.as_slice().len())?; Ok(()) From f140d1f45d39db4c4e7984775d7b562cd68374d9 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Fri, 26 Apr 2024 14:18:01 +0200 Subject: [PATCH 12/24] Show a diff for --verify. --- src/idns/client.rs | 4 + src/idns/commands/query.rs | 216 ++++++++++++++++++++----------------- 2 files changed, 121 insertions(+), 99 deletions(-) diff --git a/src/idns/client.rs b/src/idns/client.rs index 249c928..205e7dc 100644 --- a/src/idns/client.rs +++ b/src/idns/client.rs @@ -185,6 +185,10 @@ impl Answer { self.stats } + pub fn message(&self) -> &Message { + &self.message + } + pub fn msg_slice(&self) -> Message<&[u8]> { self.message.for_slice_ref() } diff --git a/src/idns/commands/query.rs b/src/idns/commands/query.rs index 6e49588..f50d463 100644 --- a/src/idns/commands/query.rs +++ b/src/idns/commands/query.rs @@ -1,15 +1,16 @@ //! The query command of _idns._ #![allow(unused_imports)] +use std::fmt; use std::collections::HashSet; use std::net::{IpAddr, SocketAddr}; use std::str::FromStr; use std::time::Duration; use bytes::Bytes; -use domain::base::iana::Rtype; +use domain::base::iana::{Class, Rtype}; use domain::base::message::Message; use domain::base::message_builder::MessageBuilder; -use domain::base::name::{Name, ToName, UncertainName}; +use domain::base::name::{Name, ParsedName, ToName, UncertainName}; use domain::net::client::{dgram, stream}; use domain::net::client::request::RequestMessage; use domain::rdata::{AllRecordData, Ns, Soa}; @@ -117,21 +118,40 @@ impl Query { self.output_format.print(&answer)?; if self.verify { let auth_answer = self.auth_answer().await?; - if Self::eq_answer( - answer.msg_slice(), auth_answer.msg_slice() - ) { - println!("\n;; Authoritative answer matches."); + if let Some(diff) = Self::diff_answers( + auth_answer.message(), answer.message() + )? { + println!("\n;; Authoritative ANSWER does not match."); + println!( + ";; Difference of ANSWER with authoritative server {}:", + auth_answer.stats().server_addr + ); + self.output_diff(diff); } else { - println!("\n;; Authoritative answer does not match."); - println!(";; AUTHORITATIVE ANSWER"); - self.output_format.print(&auth_answer)?; + println!("\n;; Authoritative ANSWER matches."); } } Ok(()) } } +/// # Configuration +/// +impl Query { + fn timeout(&self) -> Duration { + Duration::from_secs_f32(self.timeout.unwrap_or(5.)) + } + + fn retries(&self) -> u8 { + self.retries.unwrap_or(2) + } + + fn udp_payload_size(&self) -> u16 { + self.udp_payload_size.unwrap_or(1232) + } +} + /// # Resolving the server set /// @@ -205,7 +225,7 @@ impl Query { } } -/// # Handling the actual query +/// # Create the actual query /// impl Query { /// Creates a new request message. @@ -225,60 +245,6 @@ impl Query { RequestMessage::new(res) } - -/* - /// Sends the request and returns a response. - async fn send_and_receive( - &self, - mut server: Vec, - request: RequestMessage> - ) -> Result<(Message, client::Stats), Error> { - while let Some(addr) = server.pop() { - match self.send_and_receive_single(addr, request.clone()).await { - Ok(answer) => return Ok(answer), - Err(err) => { - if server.is_empty() { - return Err(err) - } - } - } - } - unreachable!() - } - - /// Sends the request to exactly one server and returns the response. - async fn send_and_receive_single( - &self, - server: SocketAddr, - request: RequestMessage> - ) -> Result<(Message, client::Stats), Error> { - if !self.tcp { - let (response, stats) = udp( - request.clone(), server, self.dgram_config() - ).await?; - if !response.header().tc() { - return Ok((response, stats)) - } - } - tcp(request, server, self.stream_config()).await - } -*/ -} - -/// # Configurations -/// -impl Query { - fn timeout(&self) -> Duration { - Duration::from_secs_f32(self.timeout.unwrap_or(5.)) - } - - fn retries(&self) -> u8 { - self.retries.unwrap_or(2) - } - - fn udp_payload_size(&self) -> u16 { - self.udp_payload_size.unwrap_or(1232) - } } /// # Get an authoritative answer @@ -366,42 +332,61 @@ impl Query { ) } - /// Compares the answer section of two messages. - fn eq_answer(left: Message<&[u8]>, right: Message<&[u8]>) -> bool { - if left.header_counts().ancount() != right.header_counts().ancount() { - return false + /// Produces a diff between two answer sections. + /// + /// Returns `Ok(None)` if the two answer sections are identical apart from + /// the TTLs. + #[allow(clippy::mutable_key_type)] + fn diff_answers( + left: &Message, right: &Message + ) -> Result>, Error> { + // Put all the answers into a two hashsets. + let left = left.answer()?.into_records::>( + ).filter_map( + Result::ok + ).map(|record| { + let class = record.class(); + let (name, data) = record.into_owner_and_data(); + (name, class, data) + }).collect::>(); + + let right = right.answer()?.into_records::>( + ).filter_map( + Result::ok + ).map(|record| { + let class = record.class(); + let (name, data) = record.into_owner_and_data(); + (name, class, data) + }).collect::>(); + + let mut diff = left.intersection(&right).cloned().map(|item| { + (Action::Unchanged, item) + }).collect::>(); + let size = diff.len(); + + diff.extend(left.difference(&right).cloned().map(|item| { + (Action::Removed, item) + })); + + diff.extend(right.difference(&left).cloned().map(|item| { + (Action::Added, item) + })); + + diff.sort_by(|left, right| left.1.cmp(&right.1)); + + if size == diff.len() { + Ok(None) + } + else { + Ok(Some(diff)) + } + } + + /// Prints the content of a diff. + fn output_diff(&self, diff: Vec) { + for item in diff { + println!("{}{} {} {}", item.0, item.1.0, item.1.1, item.1.2); } - let left = match left.answer() { - Ok(answer) => { - answer.into_records::>().map(|record| { - match record { - Ok(record) => { - let class = record.class(); - let (name, data) = record.into_owner_and_data(); - Some((name, class, data)) - } - Err(_) => None, - } - }).collect::>() - } - Err(_) => return false, - }; - let right = match right.answer() { - Ok(answer) => { - answer.into_records::>().map(|record| { - match record { - Ok(record) => { - let class = record.class(); - let (name, data) = record.into_owner_and_data(); - Some((name, class, data)) - } - Err(_) => None, - } - }).collect::>() - } - Err(_) => return false, - }; - left == right } } @@ -429,3 +414,36 @@ impl FromStr for ServerName { } } + +//------------ Action -------------------------------------------------------- + +#[derive(Clone, Copy, Debug)] +enum Action { + Added, + Removed, + Unchanged, +} + +impl fmt::Display for Action { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str( + match *self { + Self::Added => "+ ", + Self::Removed => "- ", + Self::Unchanged => " ", + } + ) + } +} + + +//----------- DiffItem ------------------------------------------------------- + +type DiffItem = ( + Action, + ( + ParsedName, + Class, + AllRecordData> + ) +); From 0c0d72c80fd59d7d171016600d5b9d7efefe9264 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Fri, 26 Apr 2024 14:22:41 +0200 Subject: [PATCH 13/24] Also show record type in diff. --- src/idns/commands/query.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/idns/commands/query.rs b/src/idns/commands/query.rs index f50d463..87caefc 100644 --- a/src/idns/commands/query.rs +++ b/src/idns/commands/query.rs @@ -11,6 +11,7 @@ use domain::base::iana::{Class, Rtype}; use domain::base::message::Message; use domain::base::message_builder::MessageBuilder; use domain::base::name::{Name, ParsedName, ToName, UncertainName}; +use domain::base::rdata::RecordData; use domain::net::client::{dgram, stream}; use domain::net::client::request::RequestMessage; use domain::rdata::{AllRecordData, Ns, Soa}; @@ -385,7 +386,10 @@ impl Query { /// Prints the content of a diff. fn output_diff(&self, diff: Vec) { for item in diff { - println!("{}{} {} {}", item.0, item.1.0, item.1.1, item.1.2); + println!( + "{}{} {} {} {}", + item.0, item.1.0, item.1.1, item.1.2.rtype(), item.1.2 + ); } } } From 36e382926b573d5f4613b10ea36016b1d66f63bd Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Fri, 26 Apr 2024 14:24:14 +0200 Subject: [PATCH 14/24] Remove extra new line. --- src/idns/output/dig.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/idns/output/dig.rs b/src/idns/output/dig.rs index 0a58b93..a4ba507 100644 --- a/src/idns/output/dig.rs +++ b/src/idns/output/dig.rs @@ -23,7 +23,7 @@ pub fn write( )?; write!(target, ";; flags: {}", header.flags())?; writeln!(target, - "; QUERY: {}, ANSWER: {}, AUTHORITY: {}, ADDITIONAL: {}\n", + "; QUERY: {}, ANSWER: {}, AUTHORITY: {}, ADDITIONAL: {}", counts.qdcount(), counts.ancount(), counts.nscount(), counts.arcount() )?; From fe22b38b89da210a626d273abb4e353d72b3f212 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 2 May 2024 09:41:56 +0200 Subject: [PATCH 15/24] Add a --udp option to idns query. --- src/idns/client.rs | 2 ++ src/idns/commands/query.rs | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/idns/client.rs b/src/idns/client.rs index 205e7dc..927d6e6 100644 --- a/src/idns/client.rs +++ b/src/idns/client.rs @@ -82,6 +82,7 @@ impl Client { &self, request: RequestMessage>, server: &Server, ) -> Result { match server.transport { + Transport::Udp => self.request_udp(request, server).await, Transport::UdpTcp => self.request_udptcp(request, server).await, Transport::Tcp => self.request_tcp(request, server).await, } @@ -158,6 +159,7 @@ pub struct Server { #[derive(Clone, Copy, Debug)] pub enum Transport { + Udp, UdpTcp, Tcp, } diff --git a/src/idns/commands/query.rs b/src/idns/commands/query.rs index 87caefc..bacec7b 100644 --- a/src/idns/commands/query.rs +++ b/src/idns/commands/query.rs @@ -54,6 +54,10 @@ pub struct Query { #[arg(short, long)] tcp: bool, + /// Use only UDP. + #[arg(short, long)] + udp: bool, + /// Set the timeout for a query. #[arg(long, value_name="SECONDS")] timeout: Option, @@ -217,7 +221,10 @@ impl Query { } fn transport(&self) -> Transport { - if self.tcp { + if self.udp { + Transport::Udp + } + else if self.tcp { Transport::Tcp } else { From 6dbec4d556fd5b3760346a4520b0f418f82ca6f9 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 2 May 2024 09:43:56 +0200 Subject: [PATCH 16/24] Remove the idns query --id option for now. --- src/idns/commands/query.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/idns/commands/query.rs b/src/idns/commands/query.rs index bacec7b..5f60021 100644 --- a/src/idns/commands/query.rs +++ b/src/idns/commands/query.rs @@ -70,10 +70,6 @@ pub struct Query { #[arg(long)] udp_payload_size: Option, - /// Use the given message ID. Random if missing. - #[arg(long)] - id: Option, - /// Unset the RD flag in the request. #[arg(long)] no_rd: bool, @@ -241,12 +237,6 @@ impl Query { let mut res = MessageBuilder::new_vec(); res.header_mut().set_rd(!self.no_rd); - if let Some(id) = self.id { - res.header_mut().set_id(id) - } - else { - res.header_mut().set_random_id(); - } let mut res = res.question(); res.push((&self.qname, self.qtype)).unwrap(); From 81e040125a1951370a012b367511e9235e4c85ec Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 2 May 2024 10:49:21 +0200 Subject: [PATCH 17/24] Provide man pages. --- doc/idns-query.1 | 167 +++++++++++++++++++++++++++++++++++++++++++++++ doc/idns.1 | 26 ++++++++ 2 files changed, 193 insertions(+) create mode 100644 doc/idns-query.1 create mode 100644 doc/idns.1 diff --git a/doc/idns-query.1 b/doc/idns-query.1 new file mode 100644 index 0000000..ccd8770 --- /dev/null +++ b/doc/idns-query.1 @@ -0,0 +1,167 @@ +.TH "idns-query" "1" "NLnet Labs" + +.SH NAME +idns-query - Send a query to a name server + +.SH SYNOPSIS +.B idns query +[\fIoptions\fR] +.I query_name +[\fIquery_type\fR] + +.SH DESCRIPTION +The +.B idns query +command sends a DNS query to a name server and prints out the response. The +server can either be selected or the resolver configured in the system will +be used. + +The query will be for the domain name given by +.IR query_name . +If +.I query_type +is given, it provides the record type to be queried for. If it is missing, +the record type +.B A +is used. + +A specific name server and port can be selected through the +.B --server +and +.B --port +options. If the latter is missing, the default port is used. If no server +is given, the system’s default servers configured in +.I /etc/resolv.conf +are tried in order and the first received response is printed. + +If neither the +.B --tcp +or +.B --udp +options are given, the query is first sent over UDP. If a response is +received but it indicates that it had to be truncated to fit, it is repeated +over TCP. If one of the options is given, then only this transport +protocol is used. In particular, if +.B --udp +is given, a truncated answer is accepted and printed. + +The output format can be selected through the +.B --format +option. If it is missing, output similar to that of +.BR dig (1) +is used. + +.SH OPTIONS +.TP +.B -s\fR \fIaddr_or_host\fR, \fB--server\fR \fIaddr_or_host +Specifies the name server to send the query to. If present, the query will be +sent to the server given. If a host name is used, the name is resolved using +the system resolver and the query is sent to the resulting addresses and the +first received response is printed. + +If this option is missing, +is given, the system’s default servers configured in +.I /etc/resolv.conf +are tried in order and the first received response is printed. + +.TP +.B --p\fR \fIport\fR, \fB--port\fR \fIport +Specifies the port to use when connecting to the name server. If missing, the +default port will be used. This is 53 for UDP and TCP. + +.TP +.BR -4 ,\ --ipv4 +Indicates that only IPv4 should be used. + +.TP +.BR -6 ,\ --ipv6 +Indicates that only IPv4 should be used. + +.TP +.BR -t ,\ --tcp +Specifies that only TCP should be used. + +.TP +.BR -u ,\ --udp +Specifies that only UDP should be used and the resulting answer be printed +even if it had to be truncated. + +.TP +.BI --timeout \ seconds +Sets the time after sending a query before a server is considered +non-responsive if an answer is not received. + +The +.I +seconds +value can be given with decimal fractions, e.g., 0.2. + +.TP +.BI --retries \ number +The number of times a query is retried over UDP after timing out before a +server is considered non-responsive. This value is ignored for transport +protocols other than UDP. + +.TP +.BI --udp-payload-size \ bytes +Sets the accepted UDP payload size announced in the query to server. If this +option is missing, the default size of 1232 bytes is used. The value is +ignored for transport protocols other than UDP. + +.TP +.B --no-rd +Specifies that the "recursion desired" flag, or RD flag for short, should +not be set in the query. If this option is missing, the flag will be set. + +The flag indicates to a resolver that it should try and gather all necessary +information from their authoritative name servers to create a complete answer +to the query. This process is called "recursion." + +.TP +.BR -f ,\ --force +Requests that no sanity checks are done and the query is to be sent as +specified. + +Normally, +.B idns query +will refuse to do zone transfer queries with query type AXFR or IXFR +because they require special processing. With this option, you can force +it to send these queries, anyway. + +.TP +.B --verify +Requests to compare the received response to the response provided +by one of the authoritative name servers. + +If the resource records in the +answer section differ, a diff between them is provided. Records that appear +in the answer section of the received response only are prefixed with a plus, +records that appard in the answer section of the authoritative response are +prefixed with a minus. + +The records in the authority and additional sections are not compared. + +This option is intended for zones that provide the same answer on all servers +and only one authoritative response is acquired and considered. If the zone's +name servers provided differing answers, re-running the command thus may +result in different output. + +.TP +.BI --format \ format +Selects the data format in which the response should be printed. The +following formats are currently supported: +.RS +.TP +.B dig +The response and some additional information are printed in a format +similar to what +.BR dig (1) +produces. + +This is currently the default format if the option is missing. +.RE + +.TP +.BR -h ,\ --help +Prints some help information. + diff --git a/doc/idns.1 b/doc/idns.1 new file mode 100644 index 0000000..4023766 --- /dev/null +++ b/doc/idns.1 @@ -0,0 +1,26 @@ +.TH "idns" "1" "NLnet Labs" + +.SH NAME +idns - inspect the DNS + +.SH SYNOPSIS +.B idns +[] + +[] + +.SH DESCRIPTION +Inspect the Domain Name System (DNS) in various ways. + +.B idns +provides a number of commands that perform various tasks related to the DNS. + +Please consult the manual pages for these individual commands for more +information. + +.SH IDNS COMMANDS + +.PP +\fBidns-query\fR(1) +.RS 4 +Send a query to a name server. From b8fd622e935491233a7a6f1653a537836f847e53 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 2 May 2024 10:54:18 +0200 Subject: [PATCH 18/24] Clean up idns::commands::query. --- src/idns/commands/query.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/idns/commands/query.rs b/src/idns/commands/query.rs index 5f60021..c0eac12 100644 --- a/src/idns/commands/query.rs +++ b/src/idns/commands/query.rs @@ -1,5 +1,4 @@ //! The query command of _idns._ -#![allow(unused_imports)] use std::fmt; use std::collections::HashSet; @@ -12,11 +11,8 @@ use domain::base::message::Message; use domain::base::message_builder::MessageBuilder; use domain::base::name::{Name, ParsedName, ToName, UncertainName}; use domain::base::rdata::RecordData; -use domain::net::client::{dgram, stream}; use domain::net::client::request::RequestMessage; use domain::rdata::{AllRecordData, Ns, Soa}; -use domain::resolv::Resolver; -use domain::resolv::lookup::{lookup_host, search_host}; use domain::resolv::stub::StubResolver; use domain::resolv::stub::conf::ResolvConf; use crate::idns::client::{Answer, Client, Server, Transport}; @@ -24,6 +20,8 @@ use crate::idns::error::Error; use crate::idns::output::OutputFormat; +//------------ Query --------------------------------------------------------- + #[derive(Clone, Debug, clap::Args)] pub struct Query { /// The name of the resource records to look up From c5c83e450e01214b3fe3d53df2d0e6c5527fca1f Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 2 May 2024 11:11:05 +0200 Subject: [PATCH 19/24] Add a idns man command. --- Cargo.lock | 19 ++++++++++++++ Cargo.toml | 1 + src/idns/commands/help.rs | 55 +++++++++++++++++++++++++++++++++++++++ src/idns/commands/mod.rs | 5 ++++ 4 files changed, 80 insertions(+) create mode 100644 src/idns/commands/help.rs diff --git a/Cargo.lock b/Cargo.lock index 2ae6573..30516dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -296,6 +296,7 @@ dependencies = [ "chrono", "clap", "domain", + "tempfile", "tokio", ] @@ -341,6 +342,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + [[package]] name = "futures-core" version = "0.3.30" @@ -862,6 +869,18 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + [[package]] name = "terminal_size" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index ac964cc..f0e7c00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ bytes = "1" clap = { version = "4", features = ["derive", "unstable-doc"] } chrono = { version = "0.4.38", features = [ "alloc", "clock" ] } domain = { git="https://github.com/NLnetLabs/domain.git", branch="message-for-slice", features = ["resolv", "unstable-client-transport"]} +tempfile = "3.1.0" tokio = { version = "1.33", features = ["rt-multi-thread"] } diff --git a/src/idns/commands/help.rs b/src/idns/commands/help.rs new file mode 100644 index 0000000..d7db464 --- /dev/null +++ b/src/idns/commands/help.rs @@ -0,0 +1,55 @@ +//! The help command of _idns._ + +use std::io::Write; +use std::process::Command; +use tempfile::NamedTempFile; +use crate::idns::error::Error; + + +//------------ Help ---------------------------------------------------------- + +#[derive(Clone, Debug, clap::Args)] +pub struct Help { + /// The command to show the man page for + #[arg(value_name="COMMAND")] + command: Option, +} + +impl Help { + pub fn execute(self) -> Result<(), Error> { + let page = match self.command.as_ref().map(String::as_str) { + None => Self::IDNS_1, + Some("query") => Self::IDNS_QUERY_1, + Some(command) => { + return Err(format!("Unknown command '{}'.", command).into()); + } + }; + + let mut file = NamedTempFile::new().map_err(|err| { + format!( + "Can't display man page: \ + Failed to create temporary file: {}.", + err + ) + })?; + file.write_all(page).map_err(|err| { + format!( + "Can't display man page: \ + Failed to write to temporary file: {}.", + err + ) + })?; + let _ = Command::new("man").arg(file.path()).status().map_err(|err| { + format!("Failed to run man: {}", err) + })?; + Ok(()) + } +} + +impl Help { + const IDNS_1: &'static [u8] = include_bytes!("../../../doc/idns.1"); + const IDNS_QUERY_1: &'static [u8] = include_bytes!( + "../../../doc/idns-query.1" + ); +} + diff --git a/src/idns/commands/mod.rs b/src/idns/commands/mod.rs index d017d93..da31f42 100644 --- a/src/idns/commands/mod.rs +++ b/src/idns/commands/mod.rs @@ -1,5 +1,6 @@ //! The various commands of _idsn._ +pub mod help; pub mod query; @@ -10,12 +11,16 @@ use super::error::Error; pub enum Commands { /// Query the DNS. Query(self::query::Query), + + /// Show the manual pages. + Man(self::help::Help), } impl Commands { pub fn execute(self) -> Result<(), Error> { match self { Self::Query(query) => query.execute(), + Self::Man(help) => help.execute(), } } } From 1d48e44bb400b12371a01ee1d63fc75a30b1a96c Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 2 May 2024 11:15:41 +0200 Subject: [PATCH 20/24] Improved XFR warning. --- src/idns/commands/query.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/idns/commands/query.rs b/src/idns/commands/query.rs index c0eac12..bdd21e4 100644 --- a/src/idns/commands/query.rs +++ b/src/idns/commands/query.rs @@ -93,7 +93,10 @@ impl Query { if !self.force { if self.qtype == Rtype::AXFR || self.qtype == Rtype::IXFR { return Err( - "Please use the 'xfr' command for zone transfer.\n\ + "AXFR and IXFR query types invoke zone transfer which \ + may result in a sequence of responses but only the + first is shown by the 'query' command.\n\ + Please use the 'xfr' command for zone transfer.\n\ (Use --force to query anyway.)".into() ); } From 7e2021ddf33274de264dd07257f28b0155f33783 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 2 May 2024 11:21:59 +0200 Subject: [PATCH 21/24] Improve formatting of XFR warning. --- src/idns/commands/query.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/idns/commands/query.rs b/src/idns/commands/query.rs index bdd21e4..fe4fc08 100644 --- a/src/idns/commands/query.rs +++ b/src/idns/commands/query.rs @@ -94,8 +94,9 @@ impl Query { if self.qtype == Rtype::AXFR || self.qtype == Rtype::IXFR { return Err( "AXFR and IXFR query types invoke zone transfer which \ - may result in a sequence of responses but only the - first is shown by the 'query' command.\n\ + may result in a sequence\n\ + of responses but only the first is shown \ + by the 'query' command.\n\ Please use the 'xfr' command for zone transfer.\n\ (Use --force to query anyway.)".into() ); From 84ccc379e18599f30319799ac38f314a4e3829e1 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 2 May 2024 11:22:11 +0200 Subject: [PATCH 22/24] Clippy-proposed improvements. --- src/idns/commands/help.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/idns/commands/help.rs b/src/idns/commands/help.rs index d7db464..51c3042 100644 --- a/src/idns/commands/help.rs +++ b/src/idns/commands/help.rs @@ -17,7 +17,7 @@ pub struct Help { impl Help { pub fn execute(self) -> Result<(), Error> { - let page = match self.command.as_ref().map(String::as_str) { + let page = match self.command.as_deref() { None => Self::IDNS_1, Some("query") => Self::IDNS_QUERY_1, Some(command) => { From ed41f4868b83b0a094425bffb3e0988c115f406f Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Fri, 3 May 2024 11:27:57 +0200 Subject: [PATCH 23/24] Rename idns into dnsi. --- doc/{idns-query.1 => dnsi-query.1} | 0 doc/{idns.1 => dnsi.1} | 0 src/bin/{idns.rs => dnsi.rs} | 0 src/{idns => dnsi}/args.rs | 0 src/{idns => dnsi}/client.rs | 0 src/{idns => dnsi}/commands/help.rs | 0 src/{idns => dnsi}/commands/mod.rs | 0 src/{idns => dnsi}/commands/query.rs | 0 src/{idns => dnsi}/error.rs | 0 src/{idns => dnsi}/mod.rs | 0 src/{idns => dnsi}/output/dig.rs | 0 src/{idns => dnsi}/output/mod.rs | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename doc/{idns-query.1 => dnsi-query.1} (100%) rename doc/{idns.1 => dnsi.1} (100%) rename src/bin/{idns.rs => dnsi.rs} (100%) rename src/{idns => dnsi}/args.rs (100%) rename src/{idns => dnsi}/client.rs (100%) rename src/{idns => dnsi}/commands/help.rs (100%) rename src/{idns => dnsi}/commands/mod.rs (100%) rename src/{idns => dnsi}/commands/query.rs (100%) rename src/{idns => dnsi}/error.rs (100%) rename src/{idns => dnsi}/mod.rs (100%) rename src/{idns => dnsi}/output/dig.rs (100%) rename src/{idns => dnsi}/output/mod.rs (100%) diff --git a/doc/idns-query.1 b/doc/dnsi-query.1 similarity index 100% rename from doc/idns-query.1 rename to doc/dnsi-query.1 diff --git a/doc/idns.1 b/doc/dnsi.1 similarity index 100% rename from doc/idns.1 rename to doc/dnsi.1 diff --git a/src/bin/idns.rs b/src/bin/dnsi.rs similarity index 100% rename from src/bin/idns.rs rename to src/bin/dnsi.rs diff --git a/src/idns/args.rs b/src/dnsi/args.rs similarity index 100% rename from src/idns/args.rs rename to src/dnsi/args.rs diff --git a/src/idns/client.rs b/src/dnsi/client.rs similarity index 100% rename from src/idns/client.rs rename to src/dnsi/client.rs diff --git a/src/idns/commands/help.rs b/src/dnsi/commands/help.rs similarity index 100% rename from src/idns/commands/help.rs rename to src/dnsi/commands/help.rs diff --git a/src/idns/commands/mod.rs b/src/dnsi/commands/mod.rs similarity index 100% rename from src/idns/commands/mod.rs rename to src/dnsi/commands/mod.rs diff --git a/src/idns/commands/query.rs b/src/dnsi/commands/query.rs similarity index 100% rename from src/idns/commands/query.rs rename to src/dnsi/commands/query.rs diff --git a/src/idns/error.rs b/src/dnsi/error.rs similarity index 100% rename from src/idns/error.rs rename to src/dnsi/error.rs diff --git a/src/idns/mod.rs b/src/dnsi/mod.rs similarity index 100% rename from src/idns/mod.rs rename to src/dnsi/mod.rs diff --git a/src/idns/output/dig.rs b/src/dnsi/output/dig.rs similarity index 100% rename from src/idns/output/dig.rs rename to src/dnsi/output/dig.rs diff --git a/src/idns/output/mod.rs b/src/dnsi/output/mod.rs similarity index 100% rename from src/idns/output/mod.rs rename to src/dnsi/output/mod.rs From 589192cf6bd25cb658523359088273912966f911 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Fri, 3 May 2024 11:29:23 +0200 Subject: [PATCH 24/24] Rename idns into dnsi. --- doc/dnsi-query.1 | 10 +++++----- doc/dnsi.1 | 10 +++++----- src/bin/dnsi.rs | 6 +++--- src/dnsi/client.rs | 6 +++--- src/dnsi/commands/help.rs | 8 ++++---- src/dnsi/commands/query.rs | 8 ++++---- src/dnsi/mod.rs | 2 +- src/dnsi/output/dig.rs | 2 +- src/dnsi/output/mod.rs | 2 +- src/lib.rs | 2 +- 10 files changed, 28 insertions(+), 28 deletions(-) diff --git a/doc/dnsi-query.1 b/doc/dnsi-query.1 index ccd8770..7be4224 100644 --- a/doc/dnsi-query.1 +++ b/doc/dnsi-query.1 @@ -1,17 +1,17 @@ -.TH "idns-query" "1" "NLnet Labs" +.TH "dnsi-query" "1" "NLnet Labs" .SH NAME -idns-query - Send a query to a name server +dnsi-query - Send a query to a name server .SH SYNOPSIS -.B idns query +.B dnsi query [\fIoptions\fR] .I query_name [\fIquery_type\fR] .SH DESCRIPTION The -.B idns query +.B dnsi query command sends a DNS query to a name server and prints out the response. The server can either be selected or the resolver configured in the system will be used. @@ -123,7 +123,7 @@ Requests that no sanity checks are done and the query is to be sent as specified. Normally, -.B idns query +.B dnsi query will refuse to do zone transfer queries with query type AXFR or IXFR because they require special processing. With this option, you can force it to send these queries, anyway. diff --git a/doc/dnsi.1 b/doc/dnsi.1 index 4023766..661798d 100644 --- a/doc/dnsi.1 +++ b/doc/dnsi.1 @@ -1,10 +1,10 @@ -.TH "idns" "1" "NLnet Labs" +.TH "dnsi" "1" "NLnet Labs" .SH NAME -idns - inspect the DNS +dnsi - inspect the DNS .SH SYNOPSIS -.B idns +.B dnsi [] [] @@ -12,7 +12,7 @@ idns - inspect the DNS .SH DESCRIPTION Inspect the Domain Name System (DNS) in various ways. -.B idns +.B dnsi provides a number of commands that perform various tasks related to the DNS. Please consult the manual pages for these individual commands for more @@ -21,6 +21,6 @@ information. .SH IDNS COMMANDS .PP -\fBidns-query\fR(1) +\fBdnsi-query\fR(1) .RS 4 Send a query to a name server. diff --git a/src/bin/dnsi.rs b/src/bin/dnsi.rs index 58a81c8..02762ae 100644 --- a/src/bin/dnsi.rs +++ b/src/bin/dnsi.rs @@ -1,10 +1,10 @@ -//! The _idns_ binary. +//! The _dnsi_ binary. use clap::Parser; -use domain_tools::idns; +use domain_tools::dnsi; fn main() { - if let Err(err) = idns::Args::parse().execute() { + if let Err(err) = dnsi::Args::parse().execute() { eprintln!("{}", err); } } diff --git a/src/dnsi/client.rs b/src/dnsi/client.rs index 927d6e6..6b19b53 100644 --- a/src/dnsi/client.rs +++ b/src/dnsi/client.rs @@ -1,4 +1,4 @@ -//! The DNS client for _idns._ +//! The DNS client for _dnsi._ use std::fmt; use std::net::SocketAddr; @@ -14,12 +14,12 @@ use domain::net::client::protocol::UdpConnect; use domain::net::client::request::{RequestMessage, SendRequest}; use domain::resolv::stub::conf; use tokio::net::TcpStream; -use crate::idns::error::Error; +use crate::dnsi::error::Error; //------------ Client -------------------------------------------------------- -/// The DNS client used by _idns._ +/// The DNS client used by _dnsi._ #[derive(Clone, Debug)] pub struct Client { servers: Vec, diff --git a/src/dnsi/commands/help.rs b/src/dnsi/commands/help.rs index 51c3042..bee63ca 100644 --- a/src/dnsi/commands/help.rs +++ b/src/dnsi/commands/help.rs @@ -1,9 +1,9 @@ -//! The help command of _idns._ +//! The help command of _dnsi._ use std::io::Write; use std::process::Command; use tempfile::NamedTempFile; -use crate::idns::error::Error; +use crate::dnsi::error::Error; //------------ Help ---------------------------------------------------------- @@ -47,9 +47,9 @@ impl Help { } impl Help { - const IDNS_1: &'static [u8] = include_bytes!("../../../doc/idns.1"); + const IDNS_1: &'static [u8] = include_bytes!("../../../doc/dnsi.1"); const IDNS_QUERY_1: &'static [u8] = include_bytes!( - "../../../doc/idns-query.1" + "../../../doc/dnsi-query.1" ); } diff --git a/src/dnsi/commands/query.rs b/src/dnsi/commands/query.rs index fe4fc08..f9d6f0d 100644 --- a/src/dnsi/commands/query.rs +++ b/src/dnsi/commands/query.rs @@ -1,4 +1,4 @@ -//! The query command of _idns._ +//! The query command of _dnsi._ use std::fmt; use std::collections::HashSet; @@ -15,9 +15,9 @@ use domain::net::client::request::RequestMessage; use domain::rdata::{AllRecordData, Ns, Soa}; use domain::resolv::stub::StubResolver; use domain::resolv::stub::conf::ResolvConf; -use crate::idns::client::{Answer, Client, Server, Transport}; -use crate::idns::error::Error; -use crate::idns::output::OutputFormat; +use crate::dnsi::client::{Answer, Client, Server, Transport}; +use crate::dnsi::error::Error; +use crate::dnsi::output::OutputFormat; //------------ Query --------------------------------------------------------- diff --git a/src/dnsi/mod.rs b/src/dnsi/mod.rs index 98bc564..6dab6e9 100644 --- a/src/dnsi/mod.rs +++ b/src/dnsi/mod.rs @@ -1,4 +1,4 @@ -//! The actual implementation of _idns._ +//! The actual implementation of _dnsi._ pub use self::args::Args; diff --git a/src/dnsi/output/dig.rs b/src/dnsi/output/dig.rs index a4ba507..675d461 100644 --- a/src/dnsi/output/dig.rs +++ b/src/dnsi/output/dig.rs @@ -4,7 +4,7 @@ use std::io; use domain::base::iana::Rtype; use domain::base::opt::AllOptData; use domain::rdata::AllRecordData; -use crate::idns::client::Answer; +use crate::dnsi::client::Answer; //------------ write --------------------------------------------------------- diff --git a/src/dnsi/output/mod.rs b/src/dnsi/output/mod.rs index 2c2edbd..0008da9 100644 --- a/src/dnsi/output/mod.rs +++ b/src/dnsi/output/mod.rs @@ -5,7 +5,7 @@ mod dig; use std::io; use clap::ValueEnum; -use crate::idns::client::Answer; +use super::client::Answer; //------------ OutputFormat -------------------------------------------------- diff --git a/src/lib.rs b/src/lib.rs index 961e2c2..4b61fd9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ //! The actual implementation of the tools. -pub mod idns; +pub mod dnsi;