From 0825dcc63d8a293ef476e079e69b7822dd512f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=A9o=20Lohrer?= Date: Thu, 18 Jul 2024 17:08:20 +0200 Subject: [PATCH] initial commit --- .gitignore | 1 + Cargo.lock | 1541 +++++++++++++++++ Cargo.toml | 19 + src/algorithms/diamond_miner.rs | 242 +++ src/algorithms/diamond_miner/grid.rs | 1 + .../diamond_miner/probe_generator.rs | 140 ++ .../diamond_miner/probe_generator/tests.rs | 144 ++ src/algorithms/diamond_miner/runner.rs | 1 + .../diamond_miner/sequential_mapper.rs | 42 + .../diamond_miner/sequential_mapper/tests.rs | 15 + src/algorithms/diamond_miner/types.rs | 8 + src/algorithms/mod.rs | 2 + src/algorithms/utils.rs | 4 + src/algorithms/utils/stopping_point.rs | 174 ++ src/lib.rs | 9 + src/links.rs | 116 ++ src/main.rs | 102 ++ src/probe.rs | 81 + src/receiver.rs | 55 + src/types.rs | 77 + 20 files changed, 2774 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/algorithms/diamond_miner.rs create mode 100644 src/algorithms/diamond_miner/grid.rs create mode 100644 src/algorithms/diamond_miner/probe_generator.rs create mode 100644 src/algorithms/diamond_miner/probe_generator/tests.rs create mode 100644 src/algorithms/diamond_miner/runner.rs create mode 100644 src/algorithms/diamond_miner/sequential_mapper.rs create mode 100644 src/algorithms/diamond_miner/sequential_mapper/tests.rs create mode 100644 src/algorithms/diamond_miner/types.rs create mode 100644 src/algorithms/mod.rs create mode 100644 src/algorithms/utils.rs create mode 100644 src/algorithms/utils/stopping_point.rs create mode 100644 src/lib.rs create mode 100644 src/links.rs create mode 100644 src/main.rs create mode 100644 src/probe.rs create mode 100644 src/receiver.rs create mode 100644 src/types.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..6e6d756 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1541 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[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 = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytecount" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" + +[[package]] +name = "cached" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "355face540df58778b96814c48abb3c2ed67c4878a8087ab1819c1fedeec505f" +dependencies = [ + "ahash", + "cached_proc_macro", + "cached_proc_macro_types", + "hashbrown", + "instant", + "once_cell", + "thiserror", +] + +[[package]] +name = "cached_proc_macro" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d52f526f7cbc875b296856ca8c964a9f6290556922c303a8a3883e3c676e6a1" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cached_proc_macro_types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" + +[[package]] +name = "caracat" +version = "1.0.0" +source = "git+https://github.com/maxmouchet/caracat?branch=main#0a6b14254a6b305e687aefd231a5e5078aa5f7d4" +dependencies = [ + "anyhow", + "chrono", + "circular-queue", + "csv", + "env_logger", + "hex", + "hyperloglog", + "ip_network", + "ip_network_table", + "ip_network_table-deps-treebitmap", + "log", + "pcap", + "pnet 0.33.0", + "rand", + "serde", + "strum", + "zstd", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.48.5", +] + +[[package]] +name = "circular-queue" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d34327ead1c743a10db339de35fb58957564b99d248a67985c55638b22c59b5" +dependencies = [ + "version_check", +] + +[[package]] +name = "clap" +version = "4.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52bdc885e4cacc7f7c9eedc1ef6da641603180c783c41a15c264944deeaab642" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "deku" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819b87cc7a05b3abe3fc38e59b3980a5fd3162f25a247116441a9171d3e84481" +dependencies = [ + "bitvec", + "deku_derive", +] + +[[package]] +name = "deku_derive" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e2ca12572239215a352a74ad7c776d7e8a914f8a23511c6cbedddd887e5009e" +dependencies = [ + "darling", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "env_logger" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyperloglog" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b48034ab5d3a9461c667ec7e1dcfb2b0586de33d9b493b2c8592e6caab9145d" +dependencies = [ + "bytecount", + "rand", + "siphasher", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +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 = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ip_network" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1" + +[[package]] +name = "ip_network_table" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4099b7cfc5c5e2fe8c5edf3f6f7adf7a714c9cc697534f63a5a5da30397cb2c0" +dependencies = [ + "ip_network", + "ip_network_table-deps-treebitmap", +] + +[[package]] +name = "ip_network_table-deps-treebitmap" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e537132deb99c0eb4b752f0346b6a836200eaaa3516dd7e5514b63930a09e5d" + +[[package]] +name = "ipnetwork" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +dependencies = [ + "serde", +] + +[[package]] +name = "is-terminal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" + +[[package]] +name = "libloading" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "no-std-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "pantrace" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2961ad6231005dbee148006c95ac8d275fff40e5b59abb9ad6c6f4199c1c7a3d" +dependencies = [ + "anyhow", + "chrono", + "clap", + "seahash", + "serde", + "serde_json", + "warts", +] + +[[package]] +name = "pcap" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbaa01d616eb84eb35cd085fdeaa8671dc8d951bdc4a75bfc414466e76b039ce" +dependencies = [ + "bitflags 1.3.2", + "errno 0.2.8", + "libc", + "libloading", + "pkg-config", + "regex", + "windows-sys 0.36.1", +] + +[[package]] +name = "pkg-config" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" + +[[package]] +name = "pnet" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd959a8268165518e2bf5546ba84c7b3222744435616381df3c456fe8d983576" +dependencies = [ + "ipnetwork", + "pnet_base 0.33.0", + "pnet_datalink 0.33.0", + "pnet_packet 0.33.0", + "pnet_sys 0.33.0", + "pnet_transport 0.33.0", +] + +[[package]] +name = "pnet" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "130c5b738eeda2dc5796fe2671e49027e6935e817ab51b930a36ec9e6a206a64" +dependencies = [ + "ipnetwork", + "pnet_base 0.34.0", + "pnet_datalink 0.34.0", + "pnet_packet 0.34.0", + "pnet_sys 0.34.0", + "pnet_transport 0.34.0", +] + +[[package]] +name = "pnet_base" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872e46346144ebf35219ccaa64b1dffacd9c6f188cd7d012bd6977a2a838f42e" +dependencies = [ + "no-std-net", +] + +[[package]] +name = "pnet_base" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cf6fb3ab38b68d01ab2aea03ed3d1132b4868fa4e06285f29f16da01c5f4c" +dependencies = [ + "no-std-net", +] + +[[package]] +name = "pnet_datalink" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c302da22118d2793c312a35fb3da6846cb0fab6c3ad53fd67e37809b06cdafce" +dependencies = [ + "ipnetwork", + "libc", + "pnet_base 0.33.0", + "pnet_sys 0.33.0", + "winapi", +] + +[[package]] +name = "pnet_datalink" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad5854abf0067ebbd3967f7d45ebc8976ff577ff0c7bd101c4973ae3c70f98fe" +dependencies = [ + "ipnetwork", + "libc", + "pnet_base 0.34.0", + "pnet_sys 0.34.0", + "winapi", +] + +[[package]] +name = "pnet_macros" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a780e80005c2e463ec25a6e9f928630049a10b43945fea83207207d4a7606f4" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", +] + +[[package]] +name = "pnet_macros" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688b17499eee04a0408aca0aa5cba5fc86401d7216de8a63fdf7a4c227871804" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 2.0.48", +] + +[[package]] +name = "pnet_macros_support" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d932134f32efd7834eb8b16d42418dac87086347d1bc7d142370ef078582bc" +dependencies = [ + "pnet_base 0.33.0", +] + +[[package]] +name = "pnet_macros_support" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eea925b72f4bd37f8eab0f221bbe4c78b63498350c983ffa9dd4bcde7e030f56" +dependencies = [ + "pnet_base 0.34.0", +] + +[[package]] +name = "pnet_packet" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bde678bbd85cb1c2d99dc9fc596e57f03aa725f84f3168b0eaf33eeccb41706" +dependencies = [ + "glob", + "pnet_base 0.33.0", + "pnet_macros 0.33.0", + "pnet_macros_support 0.33.0", +] + +[[package]] +name = "pnet_packet" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a005825396b7fe7a38a8e288dbc342d5034dac80c15212436424fef8ea90ba" +dependencies = [ + "glob", + "pnet_base 0.34.0", + "pnet_macros 0.34.0", + "pnet_macros_support 0.34.0", +] + +[[package]] +name = "pnet_sys" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf7a58b2803d818a374be9278a1fe8f88fce14b936afbe225000cfcd9c73f16" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "pnet_sys" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "417c0becd1b573f6d544f73671070b039051e5ad819cc64aa96377b536128d00" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "pnet_transport" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "813d1c0e4defbe7ee22f6fe1755f122b77bfb5abe77145b1b5baaf463cab9249" +dependencies = [ + "libc", + "pnet_base 0.33.0", + "pnet_packet 0.33.0", + "pnet_sys 0.33.0", +] + +[[package]] +name = "pnet_transport" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2637e14d7de974ee2f74393afccbc8704f3e54e6eb31488715e72481d1662cc3" +dependencies = [ + "libc", + "pnet_base 0.34.0", + "pnet_packet 0.34.0", + "pnet_sys 0.34.0", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rustix" +version = "0.38.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +dependencies = [ + "bitflags 2.4.1", + "errno 0.3.8", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "serde" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "serde_json" +version = "1.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "termcolor" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tournee" +version = "0.1.0" +dependencies = [ + "anyhow", + "cached", + "caracat", + "ip_network", + "itertools", + "log", + "pantrace", + "pnet 0.34.0", + "rand", + "serde", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "warts" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88fc118472322e9a4e4b2581f150377577a727981f6e23e0c3d7ce38194c9297" +dependencies = [ + "chrono", + "deku", +] + +[[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.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.48", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +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" +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.0", +] + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + +[[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.0", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_gnu" +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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.5.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "zstd" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "6.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.9+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..292ad61 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "tournee" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.79" +cached = "0.48.1" +caracat = { git = "https://github.com/maxmouchet/caracat", branch = "main" } +# caracat = "1.0.0" +ip_network = "0.4.1" +itertools = "0.12.0" +log = "0.4.21" +pantrace = "0.6.2" +pnet = "0.34.0" +rand = "0.8.5" +serde = "1.0.195" diff --git a/src/algorithms/diamond_miner.rs b/src/algorithms/diamond_miner.rs new file mode 100644 index 0000000..38048a1 --- /dev/null +++ b/src/algorithms/diamond_miner.rs @@ -0,0 +1,242 @@ +mod probe_generator; +mod sequential_mapper; +mod types; + +use caracat::models::{Probe, Reply, L4}; +use pnet::packet::ip; +pub use probe_generator::*; +pub use sequential_mapper::*; + +use std::collections::{HashMap, HashSet}; +use std::net::IpAddr; +use std::vec; + +use crate::algorithms::utils::general_stopping_point; +use crate::links::get_links_by_ttl; +use crate::types::{Link, Port, TTL}; + +use super::utils::stopping_point; + +// pub struct DiamondMiner<'a> { +pub struct DiamondMiner { + // Configuration parameters dst_addr: IpAddr, + dst_addr: IpAddr, + min_ttl: TTL, + max_ttl: TTL, + src_port: Port, + dst_port: Port, + protocol: L4, + + // Internal state + failure_probability: f64, + mapper_v4: SequentialFlowMapper, + mapper_v6: SequentialFlowMapper, + max_round: u32, + current_round: u32, + probes_sent: HashMap, + // replies_by_round: HashMap, + // replies_by_round: HashMap>, + replies_by_round: HashMap>, +} + +// impl<'a> DiamondMiner<'a> { +#[allow(clippy::too_many_arguments)] +impl DiamondMiner { + pub fn new( + dst_addr: IpAddr, + min_ttl: TTL, + max_ttl: TTL, + src_port: Port, + dst_port: Port, + protocol: L4, + confidence: u32, + max_round: u32, + ) -> Self { + let protocol = match (protocol, dst_addr) { + (L4::ICMP, IpAddr::V4(_)) => L4::ICMP, + (L4::ICMP, IpAddr::V6(_)) => L4::ICMPv6, + (proto, _) => proto, + }; + + let failure_probability = 1.0 - (confidence as f64 / 100.0); + + Self { + dst_addr, + min_ttl, + max_ttl, + src_port, + dst_port, + protocol, + max_round, + failure_probability, + mapper_v4: SequentialFlowMapper::new(1), + mapper_v6: SequentialFlowMapper::new(1), + current_round: 0, + probes_sent: HashMap::new(), + replies_by_round: HashMap::new(), + } + } + + fn links_by_ttl(&self) -> HashMap> { + get_links_by_ttl(self.time_exceeded_replies()) + } + + fn replies(&self) -> Vec<&Reply> { + self.replies_by_round + .values() + .flat_map(|replies| replies.iter()) + .collect::>() + } + + fn time_exceeded_replies(&self) -> Vec<&Reply> { + self.replies() + .iter() + .copied() + .filter(|&r| r.is_time_exceeded()) + .collect::>() + } + + fn nodes_distribution_at_ttl<'a>( + &self, + nodes: Vec<&'a IpAddr>, + ttl: u8, + ) -> HashMap<&'a IpAddr, f64> { + // TODO: check this code + // a routine to fetch the number of replies from a given node at a given TTL + // NOTE: a node may appear at multiple TTLs + fn node_replies(replies: &[&Reply], node: IpAddr, ttl: u8) -> usize { + replies + .iter() + .filter(|r| r.reply_src_addr == node && r.probe_ttl == ttl) + .count() + } + + // total number of observations of links reaching nodes at the current ttl. + // since links are stored with the 'near_ttl', + // we need to fetch them at ttl-1 + + let link_dist: HashMap<&IpAddr, usize> = nodes + .iter() + .map(|&node| (node, node_replies(&self.replies(), *node, ttl))) + .collect(); + + let total: usize = link_dist.values().sum(); + let link_dist: HashMap<&IpAddr, f64> = if total > 0 { + link_dist + .into_iter() + .map(|(k, v)| (k, v as f64 / total as f64)) + .collect() + } else { + // if we did not observe links at the previous ttl + // we won't apply weights to the n_k afterwards + nodes + .iter() + .map(|&node| (node, 1.0 / nodes.len() as f64)) + .collect() + }; + + link_dist + } + + pub fn next_round(&mut self, replies: Vec) -> Vec { + self.current_round += 1; + self.replies_by_round.insert(self.current_round, replies); + + if self.current_round >= self.max_round { + return vec![]; + } + + println!("links_by_ttl: {:?}", self.links_by_ttl()); + println!("probes_sent: {:?}", self.probes_sent); + + let flows_by_ttl: HashMap<_, _> = if self.current_round == 1 { + println!("First round"); + let max_flow = 1; + (self.min_ttl..=self.max_ttl) + .map(|ttl| (ttl, 0..max_flow)) + .collect() + } else { + self.links_by_ttl() + .iter() + .map(|(ttl, links)| { + // let max_flow = stopping_point(links.len(), self.failure_probability); + let max_flow = + general_stopping_point(links.len() + 1, self.failure_probability); + println!("TTL: {}, max_flow: {}", ttl, max_flow); + let start_flow = *self.probes_sent.get(ttl).unwrap_or(&0); + (*ttl, start_flow..max_flow) + }) + .collect() + }; + + println!("current_round: {}", self.current_round); + println!("Flows by TTL: {:?}", flows_by_ttl); + + let mut probes = vec![]; + + for (ttl, flow_range) in flows_by_ttl { + for flow_id in flow_range { + match self.dst_addr { + IpAddr::V4(_) => { + let (ip_offset, port_offset) = self.mapper_v4.offset(flow_id as u128); + + let new_dst_addr: IpAddr = match self.dst_addr { + IpAddr::V4(addr) => { + let ip_offset = ip_offset as u32; + let addr = u32::from(addr); + let new_addr = addr + ip_offset; + IpAddr::V4(new_addr.into()) + } + IpAddr::V6(addr) => { + let addr = u128::from(addr); + let new_addr = addr + ip_offset; + IpAddr::V6(new_addr.into()) + } + }; + + let probe = Probe { + dst_addr: new_dst_addr, + src_port: self.src_port + (port_offset as u16), + dst_port: self.dst_port, + protocol: self.protocol, + ttl, + }; + probes.push(probe); + } + IpAddr::V6(_) => { + let (ip_offset, port_offset) = self.mapper_v6.offset(flow_id as u128); + + let new_dst_addr: IpAddr = match self.dst_addr { + IpAddr::V4(addr) => { + let ip_offset = ip_offset as u32; + let addr = u32::from(addr); + let new_addr = addr + ip_offset; + IpAddr::V4(new_addr.into()) + } + IpAddr::V6(addr) => { + let addr = u128::from(addr); + let new_addr = addr + ip_offset; + IpAddr::V6(new_addr.into()) + } + }; + + let probe = Probe { + dst_addr: new_dst_addr, + src_port: self.src_port + (port_offset as u16), + dst_port: self.dst_port, + protocol: self.protocol, + ttl, + }; + probes.push(probe); + } + } + } + } + + for probe in &probes { + *self.probes_sent.entry(probe.ttl).or_insert(0) += 1; + } + + probes + } +} diff --git a/src/algorithms/diamond_miner/grid.rs b/src/algorithms/diamond_miner/grid.rs new file mode 100644 index 0000000..8453723 --- /dev/null +++ b/src/algorithms/diamond_miner/grid.rs @@ -0,0 +1 @@ +// multi cartesian product ; collected and shuffled diff --git a/src/algorithms/diamond_miner/probe_generator.rs b/src/algorithms/diamond_miner/probe_generator.rs new file mode 100644 index 0000000..9e38ae6 --- /dev/null +++ b/src/algorithms/diamond_miner/probe_generator.rs @@ -0,0 +1,140 @@ +use ip_network::IpNetwork; +use itertools::iproduct; +use rand::{rngs::SmallRng, seq::SliceRandom, SeedableRng}; +use std::net::Ipv6Addr; + +use caracat::models::Probe; +use caracat::models::L4; + +use super::sequential_mapper::SequentialFlowMapper; +use super::types::FlowId; +use super::DEFAULT_PREFIX_LEN_V4; +use super::DEFAULT_PREFIX_LEN_V6; +use super::DEFAULT_PROBE_DST_PORT; +use super::DEFAULT_PROBE_SRC_PORT; + +#[derive(Debug, Clone)] +struct Prefix<'a> { + prefix: &'a str, + protocol: L4, +} + +struct ProbeGenerator<'a> { + prefixes: Vec>, + flow_ids: Vec, + ttls: Vec, + prefix_len_v4: u8, + prefix_len_v6: u8, + probe_src_port: u16, + probe_dst_port: u16, + mapper_v4: SequentialFlowMapper, + mapper_v6: SequentialFlowMapper, + seed: u64, +} + +impl<'a> Default for ProbeGenerator<'a> { + fn default() -> Self { + Self { + prefixes: Default::default(), + flow_ids: Default::default(), + ttls: Default::default(), + prefix_len_v4: DEFAULT_PREFIX_LEN_V4, + prefix_len_v6: DEFAULT_PREFIX_LEN_V6, + probe_src_port: DEFAULT_PROBE_SRC_PORT, + probe_dst_port: DEFAULT_PROBE_DST_PORT, + mapper_v4: Default::default(), + mapper_v6: Default::default(), + seed: Default::default(), + } + } +} + +impl<'a> IntoIterator for ProbeGenerator<'a> { + type Item = Probe; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + let extended_prefixes = self.prefixes.iter().flat_map(|a| { + split_prefix(a.prefix, self.prefix_len_v4, self.prefix_len_v6) + .iter() + .map(|&(af, subprefix, subprefix_size)| (af, subprefix, subprefix_size, a.protocol)) + .collect::>() + }); + + let mut grid: Vec<_> = iproduct!(extended_prefixes, self.ttls, self.flow_ids).collect(); + + let mut rng = SmallRng::seed_from_u64(self.seed); + grid.shuffle(&mut rng); + + let res = grid.iter().map( + |&((af, subprefix, _subprefix_size, protocol), ttl, flow_id)| -> Probe { + let mapper = match af { + 4 => &self.mapper_v4, + 6 => &self.mapper_v6, + _ => panic!("Invalid IP version"), + }; + + let (addr_offset, port_offset) = mapper.offset(flow_id as FlowId); + + Probe { + dst_addr: Ipv6Addr::from( + (u128::from_be_bytes(subprefix.octets()) + addr_offset).to_be_bytes(), + ) + .into(), + src_port: self.probe_src_port + (port_offset as u16), + dst_port: self.probe_dst_port, + ttl, + protocol, + } + }, + ); + res.collect::>().into_iter() + } +} + +fn split_prefix( + prefix: &str, + prefix_len_v4: u8, + prefix_len_v6: u8, +) -> std::vec::Vec<(i32, std::net::Ipv6Addr, u128)> { + let network: IpNetwork = prefix.parse().unwrap(); + + match network { + IpNetwork::V4(net) => { + if net.netmask() == prefix_len_v4 { + return vec![( + 4, + net.network_address().to_ipv6_mapped(), + 1 << (32 - prefix_len_v4), + )]; + } + } + IpNetwork::V6(net) => { + if net.netmask() == prefix_len_v6 { + return vec![(6, net.network_address(), 1 << (128 - prefix_len_v6))]; + } + } + }; + + let res = match network { + IpNetwork::V4(net) => net + .subnets_with_prefix(prefix_len_v4) + .map(|subnet| { + ( + 4, + subnet.network_address().to_ipv6_mapped(), + 1 << (32 - prefix_len_v4), + ) + }) + .collect::>(), + IpNetwork::V6(net) => net + .subnets_with_prefix(prefix_len_v6) + .map(|subnet| (6, subnet.network_address(), 1 << (128 - prefix_len_v6))) + .collect::>(), + }; + assert!(!res.is_empty()); + res +} + +#[cfg(test)] +mod tests; diff --git a/src/algorithms/diamond_miner/probe_generator/tests.rs b/src/algorithms/diamond_miner/probe_generator/tests.rs new file mode 100644 index 0000000..2052827 --- /dev/null +++ b/src/algorithms/diamond_miner/probe_generator/tests.rs @@ -0,0 +1,144 @@ +use std::{collections::HashSet, net::IpAddr}; + +use itertools::Itertools; + +use super::*; + +#[test] +fn test_probe_generator_128() { + let prefixes = vec![Prefix { + prefix: "2001:4860:4860::8888/128", + protocol: L4::ICMP, + }]; + let generator = ProbeGenerator { + prefixes, + flow_ids: vec![10, 11, 12], + ttls: vec![41, 42], + prefix_len_v6: 128, + mapper_v6: SequentialFlowMapper::new(1), + ..Default::default() + }; + let probes = generator.into_iter().collect_vec(); + assert_eq!(probes.len(), 6); + for probe in probes.iter() { + assert_eq!(Ok(probe.dst_addr), "2001:4860:4860::8888".parse()); + assert!((24_010..24_013).contains(&probe.src_port)); + assert_eq!(probe.dst_port, 33_434); + assert!((41..43).contains(&probe.ttl)); + assert_eq!(probe.protocol, L4::ICMP); + } +} + +#[test] +fn test_probe_generator_63() { + let prefixes = vec![Prefix { + prefix: "2001:4860:4860:0000::/63", + protocol: L4::ICMP, + }]; + let generator = ProbeGenerator { + prefixes, + flow_ids: vec![10], + ttls: vec![41], + prefix_len_v6: 64, + mapper_v6: SequentialFlowMapper::new(1 << 64), + ..Default::default() + }; + + let probes: Vec<_> = generator.into_iter().collect(); + assert_eq!(probes.len(), 2); + assert_eq!( + probes + .iter() + .map(|probe| probe.dst_addr) + .collect::>() + .len(), + 2 + ); + + let expected_addr: Vec> = + vec!["2001:4860:4860::a".parse(), "2001:4860:4860:1::a".parse()]; + for probe in probes { + assert!( + expected_addr.contains(&Ok(probe.dst_addr)), + "{}", + probe.dst_addr + ); + assert_eq!(probe.src_port, 24_000); + assert_eq!(probe.dst_port, 33_434); + assert_eq!(probe.ttl, 41); + assert_eq!(probe.protocol, L4::ICMP); + } +} + +#[test] +fn test_probe_generator_32() { + let prefixes = vec![Prefix { + prefix: "8.8.8.8/32", + protocol: L4::UDP, + }]; + let generator = ProbeGenerator { + prefixes, + flow_ids: vec![10, 11, 12], + ttls: vec![41, 42], + prefix_len_v4: 32, + mapper_v4: SequentialFlowMapper::new(1), + ..Default::default() + }; + + let probes: Vec<_> = generator.into_iter().collect(); + assert_eq!(probes.len(), 6); + assert_eq!( + probes + .iter() + .map(|p| format!("{}", p)) + .collect::>() + .len(), + 6 + ); + + for probe in probes { + assert_eq!(Ok(probe.dst_addr), "::ffff:808:808".parse()); + assert!((24_010..24_013).contains(&probe.src_port)); + assert_eq!(probe.dst_port, 33_434); + assert!((41..43).contains(&probe.ttl)); + assert_eq!(probe.protocol, L4::UDP); + } +} + +#[test] +fn test_probe_generator_23() { + let prefixes = vec![Prefix { + prefix: "0.0.0.0/23", + protocol: L4::UDP, + }]; + let generator = ProbeGenerator { + prefixes, + flow_ids: vec![10], + ttls: vec![41], + prefix_len_v4: 24, + mapper_v4: SequentialFlowMapper::new(1 << 8), + ..Default::default() + }; + + let probes: Vec<_> = generator.into_iter().collect(); + + assert_eq!(probes.len(), 2); + assert_eq!( + probes + .iter() + .map(|p| format!("{}", p)) + .collect::>() + .len(), + 2 + ); + + let expected_addr = vec!["::ffff:0:a".parse(), "::ffff:0:10a".parse()]; + + for probe in probes { + assert!(expected_addr.contains(&Ok(probe.dst_addr))); + assert_eq!(probe.src_port, 24_000); + assert_eq!(probe.dst_port, 33_434); + assert_eq!(probe.ttl, 41); + assert_eq!(probe.protocol, L4::UDP); + } +} diff --git a/src/algorithms/diamond_miner/runner.rs b/src/algorithms/diamond_miner/runner.rs new file mode 100644 index 0000000..812b039 --- /dev/null +++ b/src/algorithms/diamond_miner/runner.rs @@ -0,0 +1 @@ +use caracat::models::Reply; \ No newline at end of file diff --git a/src/algorithms/diamond_miner/sequential_mapper.rs b/src/algorithms/diamond_miner/sequential_mapper.rs new file mode 100644 index 0000000..d1b7209 --- /dev/null +++ b/src/algorithms/diamond_miner/sequential_mapper.rs @@ -0,0 +1,42 @@ +use crate::algorithms::diamond_miner::types; + +pub const DEFAULT_PREFIX_LEN_V4: u8 = 24; +pub const DEFAULT_PREFIX_SIZE_V4: types::PrefixSize = 1 << (32 - DEFAULT_PREFIX_LEN_V4); + +pub const DEFAULT_PREFIX_LEN_V6: u8 = 64; +// pub const DEFAULT_PREFIX_SIZE_V6: PrefixSize = 1 << (128 - DEFAULT_PREFIX_LEN_V4); + +pub const DEFAULT_PROBE_SRC_PORT: u16 = 24000; +pub const DEFAULT_PROBE_DST_PORT: u16 = 33434; + +pub struct SequentialFlowMapper { + prefix_size: types::PrefixSize, +} + +impl SequentialFlowMapper { + pub fn new(prefix_size: types::PrefixSize) -> Self { + assert!(prefix_size > 0, "prefix_size must be positive."); + Self { prefix_size } + } + + pub fn flow_id(&self, addr_offset: types::Offset, port_offset: types::Offset) -> types::FlowId { + addr_offset + port_offset + } + + pub fn offset(&self, flow_id: types::FlowId) -> (types::Offset, types::Offset) { + // The returned offset is a tuple of offsets (offset on address, offset on port) + if flow_id < self.prefix_size { + return (flow_id, 0); + } + (self.prefix_size - 1, flow_id - self.prefix_size + 1) + } +} + +impl Default for SequentialFlowMapper { + fn default() -> Self { + SequentialFlowMapper::new(DEFAULT_PREFIX_SIZE_V4) + } +} + +#[cfg(test)] +mod tests; diff --git a/src/algorithms/diamond_miner/sequential_mapper/tests.rs b/src/algorithms/diamond_miner/sequential_mapper/tests.rs new file mode 100644 index 0000000..4a8988b --- /dev/null +++ b/src/algorithms/diamond_miner/sequential_mapper/tests.rs @@ -0,0 +1,15 @@ +use super::*; + +#[test] +fn test_sequential_flow_mapper() { + for &prefix_len in &[23, 24, 28, 32] { + let mapper = SequentialFlowMapper::new(1 << (32 - prefix_len)); + let prefix_size = 1 << (32 - prefix_len); + for flow_id in 0..(prefix_size + 1024) { + let (addr_offset, port_offset) = mapper.offset(flow_id); + let id = mapper.flow_id(addr_offset, port_offset); + + assert_eq!(id, flow_id); + } + } +} diff --git a/src/algorithms/diamond_miner/types.rs b/src/algorithms/diamond_miner/types.rs new file mode 100644 index 0000000..1f5bc1a --- /dev/null +++ b/src/algorithms/diamond_miner/types.rs @@ -0,0 +1,8 @@ +pub(crate) type BaseType = u128; + +pub type PrefixSize = BaseType; + +// PrefixSize should depend on v4 or v6 +pub(crate) type FlowId = BaseType; + +pub(crate) type Offset = BaseType; diff --git a/src/algorithms/mod.rs b/src/algorithms/mod.rs new file mode 100644 index 0000000..d064970 --- /dev/null +++ b/src/algorithms/mod.rs @@ -0,0 +1,2 @@ +pub mod diamond_miner; +pub mod utils; diff --git a/src/algorithms/utils.rs b/src/algorithms/utils.rs new file mode 100644 index 0000000..b142dd4 --- /dev/null +++ b/src/algorithms/utils.rs @@ -0,0 +1,4 @@ +mod stopping_point; +pub use stopping_point::general_prob; +pub use stopping_point::general_stopping_point; +pub use stopping_point::stopping_point; diff --git a/src/algorithms/utils/stopping_point.rs b/src/algorithms/utils/stopping_point.rs new file mode 100644 index 0000000..c2a5446 --- /dev/null +++ b/src/algorithms/utils/stopping_point.rs @@ -0,0 +1,174 @@ +use cached::proc_macro::cached; + +const PROBABILITY_DEFINITION: f64 = 1_000.0; + +const PRE_COMPUTE_SIZE: usize = 64; +const PRE_COMPUTE_MAX_IDX: usize = PRE_COMPUTE_SIZE - 1; + +const STOPPING_POINT_95: [usize; PRE_COMPUTE_SIZE] = [ + 0, 1, 6, 11, 16, 21, 27, 33, 38, 44, 51, 57, 63, 70, 76, 83, 90, 96, 103, 110, 117, 124, 131, + 138, 145, 152, 159, 167, 174, 181, 189, 196, 203, 211, 218, 226, 233, 241, 248, 256, 264, 271, + 279, 287, 294, 302, 310, 318, 326, 333, 341, 349, 357, 365, 373, 381, 389, 397, 405, 413, 421, + 429, 437, 445, +]; + +const STOPPING_POINT_99: [usize; PRE_COMPUTE_SIZE] = [ + 0, 1, 8, 15, 21, 28, 36, 43, 51, 58, 66, 74, 82, 90, 98, 106, 115, 123, 132, 140, 149, 157, + 166, 175, 183, 192, 201, 210, 219, 228, 237, 246, 255, 264, 273, 282, 291, 300, 309, 319, 328, + 337, 347, 356, 365, 375, 384, 393, 403, 412, 422, 431, 441, 450, 460, 470, 479, 489, 499, 508, + 518, 528, 537, 547, +]; + +fn chooses(n: usize, k: usize) -> f64 { + // computes n choose k + if n < k { + return 0.0; + } + if n == k { + return 1.0; + } + + (1..=k).fold(1.0, |acc, j| acc * (n - j + 1) as f64 / j as f64) +} + +fn _stirling2_fact(n: usize, k: usize) -> f64 { + if n == 0 && k == 0 { + return 1.0; + } + if n == 0 || k == 0 { + return 0.0; + } + + (0..=k).fold(0.0, |acc, j| { + acc + if (k - j) % 2 == 0 { + chooses(k, j) * (j as f64).powf(n as f64) + } else { + -chooses(k, j) * (j as f64).powf(n as f64) + } + }) +} + +#[cached] +pub fn general_prob(total_interfaces: usize, n_probes: usize, reached_interfaces: usize) -> f64 { + let stirling = _stirling2_fact(n_probes, reached_interfaces); + let binom = chooses(total_interfaces, reached_interfaces); + stirling * binom / (total_interfaces as f64).powf(n_probes as f64) +} + +#[cached] +fn reach_prob(total_interfaces: usize, n_probes: usize, target_interfaces: usize) -> f64 { + // Initialization: + // We can reach 0 interfaces with probability 1.0, only if we send 0 probes. + // We cannot reach 0 interfaces with 1 or more probes. + // With 0 probes, we cannot reach n > 0 interfaces. + + match (n_probes, target_interfaces) { + (0, 0) => return 1.0, + (0, _) | (_, 0) => return 0.0, + _ => {} + }; + + // We now define our recursion primarily on the number of sent probes. + // We suppose we already sent (n_probes - 1) probes and distinguish between + // the two following cases: + // + // - A: we already reached our target number of interfaces with (n_probes - 1) probes ; or + // - B: we still need to reach one new interface with our last probe. + // + // A : [x] [x] [x] [ ] ------> [x] [x] [x] [ ] + // (after n-1 probes) (after n probes) + // + // B : [x] [x] [ ] [ ] ------> [x] [x] [X] [ ] + // (after n-1 probes) (after n probes) + + let prob_discovered_all_targets = reach_prob(total_interfaces, n_probes - 1, target_interfaces); + let prob_hit_discovered_interface = target_interfaces as f64 / total_interfaces as f64; + + let prob_one_target_left = reach_prob(total_interfaces, n_probes - 1, target_interfaces - 1); + let prob_hit_new_interface = + (total_interfaces - (target_interfaces - 1)) as f64 / total_interfaces as f64; + + prob_discovered_all_targets * prob_hit_discovered_interface + + prob_one_target_left * prob_hit_new_interface +} + +#[cached] +fn _cached_stopping_point(n_interfaces: usize, failure_probability_proxy: u64) -> usize { + (0..) + .find(|&n_probes| { + reach_prob(n_interfaces, n_probes, n_interfaces) + >= (1.0 - (failure_probability_proxy as f64 / PROBABILITY_DEFINITION)) + }) + .unwrap() +} + +pub fn stopping_point(n_interfaces: usize, failure_probability: f64) -> usize { + match ( + n_interfaces, + (failure_probability * PROBABILITY_DEFINITION) as u64, + ) { + (0..=PRE_COMPUTE_MAX_IDX, 50) => STOPPING_POINT_95[n_interfaces], + (0..=PRE_COMPUTE_MAX_IDX, 10) => STOPPING_POINT_99[n_interfaces], + _ => _cached_stopping_point( + n_interfaces, + (failure_probability * PROBABILITY_DEFINITION) as u64, + ), + } +} + +pub fn general_stopping_point(n_interfaces: usize, failure_probability: f64) -> usize { + let mut n_probes = 1; + // let growth_factor = 3; + // let mut previous_n_probes = 0; + while general_prob(n_interfaces, n_probes, n_interfaces) < (1.0 - failure_probability) { + n_probes += 1; + } + n_probes + // while general_prob(n_interfaces, n_probes, n_interfaces) < (1.0 - failure_probability) { + // previous_n_probes = n_probes; + // n_probes *= growth_factor; + // } + + // Vec::from_iter(previous_n_probes..n_probes).partition_point(|&n| { + // general_prob(n_interfaces, n, n_interfaces) < (1.0 - failure_probability) + // }) + previous_n_probes +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn general_stopping_point_0_95() { + assert_eq!( + (0..PRE_COMPUTE_SIZE) + .map(|n| general_stopping_point(n, 0.05)) + .collect::>(), + STOPPING_POINT_95 + ) + } + + // #[test] + // fn stopping_point_0_95() { + // // Using _cached_stopping_point to prove equivalence of the hard coded arrays + // let prob_proxy = (0.05 * PROBABILITY_DEFINITION) as u64; + // assert_eq!( + // (0..PRE_COMPUTE_SIZE) + // .map(|n| _cached_stopping_point(n, prob_proxy)) + // .collect::>(), + // STOPPING_POINT_95 + // ) + // } + + // #[test] + // fn stopping_point_0_99() { + // // Using _cached_stopping_point to prove equivalence of the hard coded arrays + // let prob_proxy = (0.01 * PROBABILITY_DEFINITION) as u64; + // assert_eq!( + // (0..PRE_COMPUTE_SIZE) + // .map(|n| _cached_stopping_point(n, prob_proxy)) + // .collect::>(), + // STOPPING_POINT_99 + // ) + // } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..fbc54ed --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,9 @@ +pub mod algorithms; + +pub mod links; + +pub mod types; + +pub mod receiver; + +pub mod probe; diff --git a/src/links.rs b/src/links.rs new file mode 100644 index 0000000..20d2eed --- /dev/null +++ b/src/links.rs @@ -0,0 +1,116 @@ +use std::collections::HashMap; + +use caracat::models::Reply; +use itertools::iproduct; + +use crate::types::{Flow, Link, ReplyPair, TTL}; + +use std::collections::HashSet; + +pub(crate) fn get_replies_by_ttl(replies: Vec<&Reply>) -> HashMap> { + replies.iter().fold(HashMap::new(), |mut acc, r| { + acc.entry(r.probe_ttl).or_default().push(r); + acc + }) +} + +pub(crate) fn get_replies_by_flow<'a>(replies: &[&'a Reply]) -> HashMap> { + replies.iter().fold(HashMap::new(), |mut acc, &r| { + acc.entry(r.into()).or_default().push(r); + acc + }) +} + +// fn get_pairs_by_flow<'a>(replies: &'a [&'a Reply]) -> HashMap>> { +fn get_pairs_by_flow<'a>(replies: Vec<&'a Reply>) -> HashMap>> { + let mut pairs_by_flow: HashMap>> = HashMap::new(); + let replies_by_flow: HashMap> = + replies.iter().fold(HashMap::new(), |mut acc, &r| { + acc.entry(r.into()).or_default().push(r); + acc + }); + for (flow, flow_replies) in replies_by_flow { + let ttl_replies: HashMap> = + flow_replies.iter().fold(HashMap::new(), |mut acc, &r| { + acc.entry(r.probe_ttl).or_default().push(r); + acc + }); + let (min_ttl, max_ttl) = ( + *ttl_replies.keys().min().unwrap(), + *ttl_replies.keys().max().unwrap(), + ); + for near_ttl in min_ttl..=max_ttl { + let fetch_replies = |ttl| { + ttl_replies + .get(&ttl) + .map(|replies| replies.iter().map(|&reply| Some(reply)).collect::>()) + .unwrap_or(vec![None]) + }; + let near_replies = fetch_replies(near_ttl); + let far_replies = fetch_replies(near_ttl + 1); + iproduct!(near_replies, far_replies).for_each(|replies| { + let pair = ReplyPair { + ttl: near_ttl, + first_reply: replies.0, + second_reply: replies.1, + }; + pairs_by_flow.entry(flow).or_default().push(pair); + }) + } + } + pairs_by_flow +} + +pub(crate) fn _get_pairs_by_flow<'a>(replies: &'a [&'a Reply]) -> HashMap> { + let mut pairs_by_flow: HashMap> = HashMap::new(); + + let replies_by_flow = get_replies_by_flow(&replies); + + for (flow, flow_replies) in replies_by_flow { + let replies_by_ttl = get_replies_by_ttl(flow_replies); + let (min_ttl, max_ttl) = ( + *replies_by_ttl.keys().min().unwrap(), + *replies_by_ttl.keys().max().unwrap(), + ); + + for near_ttl in min_ttl..=max_ttl { + let fetch_replies = |ttl| { + replies_by_ttl + .get(&ttl) + .map(|replies| replies.iter().map(|&reply| Some(reply)).collect::>()) + .unwrap_or(vec![None]) + }; + let near_replies = fetch_replies(near_ttl); + let far_replies = fetch_replies(near_ttl + 1); + iproduct!(near_replies, far_replies).for_each(|replies| { + let pair = ReplyPair { + ttl: near_ttl, + first_reply: replies.0, + second_reply: replies.1, + }; + pairs_by_flow.entry(flow).or_default().push(pair); + }) + } + } + pairs_by_flow +} + +// pub(crate) fn get_links_by_ttl<'a>(replies: &'a [&'a Reply]) -> HashMap>> { +pub(crate) fn get_links_by_ttl(replies: Vec<&Reply>) -> HashMap>> { + let mut links_by_ttl: HashMap> = HashMap::new(); + let pairs_by_flow = get_pairs_by_flow(replies); + + for (_, pairs) in pairs_by_flow { + for pair in pairs { + let link = Link { + ttl: pair.ttl, + near_ip: pair.first_reply.map(|r| &r.reply_src_addr), + far_ip: pair.second_reply.map(|r| &r.reply_src_addr), + }; + + links_by_ttl.entry(pair.ttl).or_default().insert(link); + } + } + + links_by_ttl +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..7d6330e --- /dev/null +++ b/src/main.rs @@ -0,0 +1,102 @@ +use std::fs::File; +use std::net::{IpAddr, Ipv4Addr}; +use std::vec; + +use caracat::high_level::receive_loop::ReceiveLoop; +use caracat::high_level::send_loop::{self, SendLoop}; +// use caracat::high_level::{probe, Config}; +use caracat::high_level::Config; +use caracat::models::Reply; +use caracat::rate_limiter::RateLimiter; + +use caracat::receiver; +use caracat::sender::{self, Sender}; +use itertools::Itertools; +use tournee::algorithms::diamond_miner::DiamondMiner; +use tournee::algorithms::utils::{general_prob, general_stopping_point, stopping_point}; + +use anyhow::Result; +use tournee::probe::probe; + +fn main() -> Result<()> { + println!("Hello, world!"); + for i in 0..64 { + println!("{}", stopping_point(i, 0.01)); + } + println!("Let's go!"); + + // for total_interfaces in 1..=10 + // for n_probes in 1..=10 + // for target_interfaces in 1..=total_interfaces + // print the general_prob(total_interfaces, n_probes, target_interfaces) + + // for total_interfaces in 1..=10 { + // for n_probes in 1..=10 { + // for target_interfaces in 1..=total_interfaces { + // println!( + // "N:{} k:{} n:{} --> p:{}", + // total_interfaces, + // n_probes, + // target_interfaces, + // general_prob(total_interfaces, n_probes, target_interfaces) + // ); + // } + // } + // } + + // for total_interfaces in 1..=10 { + // println!( + // "N:{} stop:{}", + // total_interfaces, + // general_stopping_point(total_interfaces, 0.05) + // ); + // } + + // let dst_addr_str = "12.12.12.12"; + // let dst_addr_str = "103.37.83.226"; + let dst_addr_str = "31.13.29.247"; + let dst_addr = IpAddr::from(dst_addr_str.parse::()?); + let min_ttl = 0; + let max_ttl = 64; + let src_port = 0; + let dst_port = 0; + let protocol = caracat::models::L4::ICMP; + let confidence = 95; + let max_round = 10; + + let mut alg = DiamondMiner::new( + dst_addr, min_ttl, max_ttl, src_port, dst_port, protocol, confidence, max_round, + ); + + let mut probes = alg.next_round(vec![]); + println!("sending {} probes", probes.len()); + + let mut round = 0; + + while !probes.is_empty() { + // print probes per TTL + println!("Probes per TTL:"); + for (ttl, probes) in &probes.iter().group_by(|p| p.ttl) { + println!(" TTL {}: {}", ttl, probes.count()); + } + + let config = Config { + // output_file_csv: Some("temp.csv".into()), + receiver_wait_time: std::time::Duration::from_secs(2), + ..Config::default() + }; + println!("Round: {}", round); + round += 1; + let replies = probe(config, probes.into_iter())?; + println!("received {} replies", replies.len()); + println!( + "time_exceeded_replies: {}", + replies.iter().filter(|r| r.is_time_exceeded()).count() + ); + + probes = alg.next_round(replies); + println!("sending {} probes", probes.len()); + } + + Ok(()) +} diff --git a/src/probe.rs b/src/probe.rs new file mode 100644 index 0000000..cb673b3 --- /dev/null +++ b/src/probe.rs @@ -0,0 +1,81 @@ +use std::thread::sleep; + +use log::info; + +use anyhow::Result; +use caracat::{ + high_level::{Config, SendLoop}, + // logger::StatisticsLogger, + models::{Probe, Reply}, + rate_limiter::RateLimiter, + sender::Sender, + utilities::prefix_filter_from_file, +}; + +use crate::receiver::ReceiveCache; + +pub fn probe<'a, T: Iterator>( + config: Config, + probes: T, + // ) -> Result<(SendStatistics, ReceiveStatistics)> { +) -> Result> { + // info!("{}", config); + + let allowed_prefixes = match config.allowed_prefixes_file { + None => None, + Some(path) => Some(prefix_filter_from_file(&path)?), + }; + + let blocked_prefixes = match config.blocked_prefixes_file { + None => None, + Some(path) => Some(prefix_filter_from_file(&path)?), + }; + + let rate_limiter = RateLimiter::new( + config.probing_rate, + config.batch_size, + config.rate_limiting_method, + ); + // let rate_statistics = rate_limiter.statistics().clone(); + + // let receiver = ReceiveLoop::new( + let mut receiver = ReceiveCache::new( + config.interface.clone(), + // config.output_file_csv, + // config.instance_id, + // config.extra_string, + // config.integrity_check, + ); + // let receiver_statistics = receiver.statistics().clone(); + + let mut prober = SendLoop::new( + config.batch_size, + config.instance_id, + config.min_ttl, + config.max_ttl, + config.max_probes, + config.packets, + allowed_prefixes, + blocked_prefixes, + rate_limiter, + Sender::new(&config.interface, config.instance_id, config.dry_run)?, + ); + // let prober_statistics = prober.statistics().clone(); + + // let logger = StatisticsLogger::new(prober_statistics, rate_statistics, receiver_statistics); + + prober.probe(probes)?; + info!("Waiting {:?} for replies...", config.receiver_wait_time); + sleep(config.receiver_wait_time); + + // TODO: Cleaner way? + // let final_prober_statistics = *prober.statistics().lock().unwrap(); + // let final_receiver_statistics = receiver.statistics().lock().unwrap().clone(); + + let replies = receiver.stop(); + // logger.stop(); + + Ok(replies) + + // Ok((final_prober_statistics, final_receiver_statistics)) +} diff --git a/src/receiver.rs b/src/receiver.rs new file mode 100644 index 0000000..6200be9 --- /dev/null +++ b/src/receiver.rs @@ -0,0 +1,55 @@ +use std::{ + sync::{Arc, Mutex}, + thread::{self, JoinHandle}, +}; + +use caracat::{models::Reply, receiver::Receiver}; + +pub struct ReceiveCache { + handle: JoinHandle<()>, + stopped: Arc>, + pub replies: Arc>>, +} + +impl ReceiveCache { + pub fn new( + interface: String, + ) -> Self { + let stopped = Arc::new(Mutex::new(false)); + let stopped_thr = stopped.clone(); + let replies = Arc::new(Mutex::new(Vec::new())); + let replies_thread = replies.clone(); + + let handle = thread::spawn(move || { + let mut receiver = Receiver::new_batch(&interface).unwrap(); + + loop { + let reply = receiver.next_reply(); + if let Ok(reply) = reply { + replies_thread.lock().unwrap().push(reply); + } + + if *stopped_thr.lock().unwrap() { + break; + } + } + }); + + ReceiveCache { + handle, + stopped, + replies, + } + } + + pub fn stop(&mut self) -> Vec{ + *self.stopped.lock().unwrap() = true; + // // Wait for the thread to finish + // if let Some(handle) = self.handle.take() { + // handle.join().unwrap(); + // } + + // Drain the replies vector + self.replies.lock().unwrap().drain(..).collect() + } +} diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 0000000..e068583 --- /dev/null +++ b/src/types.rs @@ -0,0 +1,77 @@ +use std::net::IpAddr; + +use caracat::models::{Reply, L4}; + +#[derive(Eq, PartialEq, Hash, Clone, Copy)] +enum L4Wrapper { + ICMP, + ICMPv6, + UDP, +} + +impl From for L4Wrapper { + fn from(l4: L4) -> Self { + match l4 { + L4::ICMP => L4Wrapper::ICMP, + L4::ICMPv6 => L4Wrapper::ICMPv6, + L4::UDP => L4Wrapper::UDP, + } + } +} + +impl From for L4Wrapper { + fn from(l4: u8) -> Self { + match l4 { + 1 => L4Wrapper::ICMP, + 58 => L4Wrapper::ICMPv6, + 17 => L4Wrapper::UDP, + _ => panic!("Unknown L4 protocol"), + } + } +} + +impl From<&L4Wrapper> for L4 { + fn from(l4: &L4Wrapper) -> Self { + match l4 { + L4Wrapper::ICMP => L4::ICMP, + L4Wrapper::ICMPv6 => L4::ICMPv6, + L4Wrapper::UDP => L4::UDP, + } + } +} + +pub(crate) type TTL = u8; +pub(crate) type Port = u16; + +#[derive(Eq, PartialEq, Hash, Clone, Copy)] +pub(crate) struct Flow { + pub(crate) protocol: L4Wrapper, + pub(crate) dst_address: IpAddr, + pub(crate) src_port: Port, + pub(crate) dst_port: Port, +} + +impl From<&Reply> for Flow { + fn from(value: &Reply) -> Self { + Flow { + protocol: value.probe_protocol.into(), + dst_address: value.probe_dst_addr, + src_port: value.probe_src_port, + dst_port: value.probe_dst_port, + } + } +} + +#[derive(Eq, Hash, PartialEq, Debug)] +pub(crate) struct Link<'a> { + pub(crate) ttl: TTL, + pub(crate) near_ip: Option<&'a IpAddr>, + pub(crate) far_ip: Option<&'a IpAddr>, +} + +#[derive(Clone, Copy)] +pub(crate) struct ReplyPair<'a> { + pub(crate) ttl: TTL, + pub(crate) first_reply: Option<&'a Reply>, + pub(crate) second_reply: Option<&'a Reply>, +}