This commit is contained in:
Pascal Engélibert 2025-11-05 14:17:38 +01:00
commit 90a9196a9d
10 changed files with 1124 additions and 52 deletions

2
.cargo/config.toml Normal file
View file

@ -0,0 +1,2 @@
[build]
rustflags = ["--cfg", "tokio_unstable"]

3
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"rust-analyzer.showUnlinkedFileNotification": false
}

711
Cargo.lock generated
View file

@ -2,6 +2,12 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "adler2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "1.1.3" version = "1.1.3"
@ -11,6 +17,12 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "anyhow"
version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]] [[package]]
name = "argp" name = "argp"
version = "0.4.0" version = "0.4.0"
@ -71,6 +83,23 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "async-trait"
version = "0.1.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.5.0" version = "1.5.0"
@ -101,6 +130,61 @@ dependencies = [
"fs_extra", "fs_extra",
] ]
[[package]]
name = "axum"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18ed336352031311f4e0b4dd2ff392d4fbb370777c9d18d7fc9d7359f73871"
dependencies = [
"axum-core",
"bytes",
"futures-util",
"http",
"http-body",
"http-body-util",
"itoa",
"matchit",
"memchr",
"mime",
"percent-encoding",
"pin-project-lite",
"serde_core",
"sync_wrapper",
"tower",
"tower-layer",
"tower-service",
]
[[package]]
name = "axum-core"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22"
dependencies = [
"bytes",
"futures-core",
"http",
"http-body",
"http-body-util",
"mime",
"pin-project-lite",
"sync_wrapper",
"tower-layer",
"tower-service",
]
[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "bindgen" name = "bindgen"
version = "0.72.1" version = "0.72.1"
@ -138,6 +222,12 @@ version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.10.1" version = "1.10.1"
@ -191,6 +281,70 @@ dependencies = [
"cc", "cc",
] ]
[[package]]
name = "console-api"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8599749b6667e2f0c910c1d0dff6901163ff698a52d5a39720f61b5be4b20d3"
dependencies = [
"futures-core",
"prost",
"prost-types",
"tonic",
"tonic-prost",
"tracing-core",
]
[[package]]
name = "console-subscriber"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb4915b7d8dd960457a1b6c380114c2944f728e7c65294ab247ae6b6f1f37592"
dependencies = [
"console-api",
"crossbeam-channel",
"crossbeam-utils",
"futures-task",
"hdrhistogram",
"humantime",
"hyper-util",
"prost",
"prost-types",
"serde",
"serde_json",
"thread_local",
"tokio",
"tokio-stream",
"tonic",
"tracing",
"tracing-core",
"tracing-subscriber",
]
[[package]]
name = "crc32fast"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [
"cfg-if",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]] [[package]]
name = "data-encoding" name = "data-encoding"
version = "2.9.0" version = "2.9.0"
@ -243,6 +397,12 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]] [[package]]
name = "fast-tlsh" name = "fast-tlsh"
version = "0.1.10" version = "0.1.10"
@ -264,6 +424,22 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127"
[[package]]
name = "flate2"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "foreign-types" name = "foreign-types"
version = "0.3.2" version = "0.3.2"
@ -285,6 +461,58 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
[[package]]
name = "futures-channel"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [
"futures-core",
]
[[package]]
name = "futures-core"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-macro"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]]
name = "futures-task"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
name = "futures-util"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-core",
"futures-macro",
"futures-task",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]] [[package]]
name = "getopts" name = "getopts"
version = "0.2.24" version = "0.2.24"
@ -323,6 +551,44 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
[[package]]
name = "h2"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386"
dependencies = [
"atomic-waker",
"bytes",
"fnv",
"futures-core",
"futures-sink",
"http",
"indexmap",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
[[package]]
name = "hdrhistogram"
version = "7.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d"
dependencies = [
"base64 0.21.7",
"byteorder",
"flate2",
"nom",
"num-traits",
]
[[package]] [[package]]
name = "hex-simd" name = "hex-simd"
version = "0.8.0" version = "0.8.0"
@ -333,6 +599,125 @@ dependencies = [
"vsimd", "vsimd",
] ]
[[package]]
name = "http"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]]
name = "http-body"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
"http",
]
[[package]]
name = "http-body-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
dependencies = [
"bytes",
"futures-core",
"http",
"http-body",
"pin-project-lite",
]
[[package]]
name = "httparse"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
[[package]]
name = "httpdate"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "humantime"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424"
[[package]]
name = "hyper"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e"
dependencies = [
"atomic-waker",
"bytes",
"futures-channel",
"futures-core",
"h2",
"http",
"http-body",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"pin-utils",
"smallvec",
"tokio",
"want",
]
[[package]]
name = "hyper-timeout"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0"
dependencies = [
"hyper",
"hyper-util",
"pin-project-lite",
"tokio",
"tower-service",
]
[[package]]
name = "hyper-util"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"http",
"http-body",
"hyper",
"libc",
"pin-project-lite",
"socket2",
"tokio",
"tower-service",
"tracing",
]
[[package]]
name = "indexmap"
version = "2.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.13.0" version = "0.13.0"
@ -386,18 +771,49 @@ version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
[[package]]
name = "matchers"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
dependencies = [
"regex-automata",
]
[[package]]
name = "matchit"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.6" version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "mime"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]] [[package]]
name = "minimal-lexical" name = "minimal-lexical"
version = "0.2.1" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
"simd-adler32",
]
[[package]] [[package]]
name = "mio" name = "mio"
version = "1.1.0" version = "1.1.0"
@ -415,11 +831,16 @@ version = "0.1.0"
dependencies = [ dependencies = [
"argp", "argp",
"aws-lc-rs", "aws-lc-rs",
"console-subscriber",
"fast-tlsh", "fast-tlsh",
"futures-util",
"memchr",
"regex",
"sslrelay", "sslrelay",
"static_cell", "static_cell",
"tokio", "tokio",
"tokio-rustls", "tokio-rustls",
"tokio-util",
"x509-parser", "x509-parser",
] ]
@ -526,12 +947,44 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e"
[[package]]
name = "percent-encoding"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "pin-project"
version = "1.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.16" version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.32" version = "0.3.32"
@ -569,6 +1022,38 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "prost"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d"
dependencies = [
"bytes",
"prost-derive",
]
[[package]]
name = "prost-derive"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425"
dependencies = [
"anyhow",
"itertools",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "prost-types"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72"
dependencies = [
"prost",
]
[[package]] [[package]]
name = "pulldown-cmark" name = "pulldown-cmark"
version = "0.9.6" version = "0.9.6"
@ -690,6 +1175,12 @@ dependencies = [
"untrusted 0.9.0", "untrusted 0.9.0",
] ]
[[package]]
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.228" version = "1.0.228"
@ -697,6 +1188,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [ dependencies = [
"serde_core", "serde_core",
"serde_derive",
] ]
[[package]] [[package]]
@ -719,12 +1211,52 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "serde_json"
version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
"serde_core",
]
[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
dependencies = [
"lazy_static",
]
[[package]] [[package]]
name = "shlex" name = "shlex"
version = "1.3.0" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "simd-adler32"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "slab"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.6.1" version = "0.6.1"
@ -774,6 +1306,12 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "sync_wrapper"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
[[package]] [[package]]
name = "synstructure" name = "synstructure"
version = "0.13.2" version = "0.13.2"
@ -805,6 +1343,15 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "thread_local"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.44" version = "0.3.44"
@ -848,6 +1395,7 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
"socket2", "socket2",
"tokio-macros", "tokio-macros",
"tracing",
"windows-sys 0.61.2", "windows-sys 0.61.2",
] ]
@ -872,6 +1420,154 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "tokio-stream"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tokio-util"
version = "0.7.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tonic"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203"
dependencies = [
"async-trait",
"axum",
"base64 0.22.1",
"bytes",
"h2",
"http",
"http-body",
"http-body-util",
"hyper",
"hyper-timeout",
"hyper-util",
"percent-encoding",
"pin-project",
"socket2",
"sync_wrapper",
"tokio",
"tokio-stream",
"tower",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tonic-prost"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67"
dependencies = [
"bytes",
"prost",
"tonic",
]
[[package]]
name = "tower"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
dependencies = [
"futures-core",
"futures-util",
"indexmap",
"pin-project-lite",
"slab",
"sync_wrapper",
"tokio",
"tokio-util",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
[[package]]
name = "tower-service"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
dependencies = [
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
dependencies = [
"matchers",
"once_cell",
"regex-automata",
"sharded-slab",
"thread_local",
"tracing",
"tracing-core",
]
[[package]]
name = "try-lock"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]] [[package]]
name = "unicase" name = "unicase"
version = "2.8.1" version = "2.8.1"
@ -902,6 +1598,12 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "valuable"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]] [[package]]
name = "vcpkg" name = "vcpkg"
version = "0.2.15" version = "0.2.15"
@ -920,6 +1622,15 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64"
[[package]]
name = "want"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
dependencies = [
"try-lock",
]
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.1+wasi-snapshot-preview1" version = "0.11.1+wasi-snapshot-preview1"

View file

@ -6,9 +6,14 @@ edition = "2024"
[dependencies] [dependencies]
argp = "0.4.0" argp = "0.4.0"
aws-lc-rs = "1.14.1" aws-lc-rs = "1.14.1"
tlsh = { package = "fast-tlsh", version = "0.1.10", features = ["easy-functions"] } console-subscriber = "0.5.0"
futures-util = "0.3.31"
memchr = "2.7.6"
regex = "1.12.2"
sslrelay = { path = "../sslrelay-lib" } sslrelay = { path = "../sslrelay-lib" }
static_cell = "2.1.1" static_cell = "2.1.1"
tokio = { version = "1.48.0", features = ["io-util", "macros", "net", "rt", "rt-multi-thread", "sync"]} tlsh = { package = "fast-tlsh", version = "0.1.10", features = ["easy-functions"] }
tokio = { version = "1.48.0", features = ["io-util", "macros", "net", "rt", "rt-multi-thread", "sync", "time", "tracing"]}
tokio-rustls = "0.26.4" tokio-rustls = "0.26.4"
tokio-util = { version = "0.7.6", features = ["codec"] }
x509-parser = "0.18.0" x509-parser = "0.18.0"

View file

@ -10,6 +10,12 @@ It relies on the server name extension in TLS (SNI). Requests without server nam
For experimental purpose. Do not use on an open network where security matters. For experimental purpose. Do not use on an open network where security matters.
## Build
```bash
RUSTFLAGS="--cfg tokio_unstable" cargo build --release
```
## Record file format ## Record file format
The record file is a list of records. Each record follows this format: The record file is a list of records. Each record follows this format:

View file

@ -3,11 +3,15 @@ use crate::{
record::{Direction, Records}, record::{Direction, Records},
}; };
use std::{net::ToSocketAddrs, sync::Arc}; use futures_util::StreamExt;
use std::{
net::ToSocketAddrs,
sync::{Arc, atomic::AtomicU32},
};
use tokio::{ use tokio::{
io::{AsyncReadExt, AsyncWriteExt}, io::AsyncWriteExt,
net::TcpStream, net::TcpStream,
sync::oneshot, sync::{Semaphore, oneshot},
}; };
use tokio_rustls::{ use tokio_rustls::{
TlsConnector, TlsConnector,
@ -17,6 +21,7 @@ use tokio_rustls::{
pki_types::ServerName, pki_types::ServerName,
}, },
}; };
use tokio_util::codec::Framed;
#[derive(Debug)] #[derive(Debug)]
struct DummyCertVerifier; struct DummyCertVerifier;
@ -82,6 +87,11 @@ pub async fn play(
repeat: u32, repeat: u32,
) { ) {
sync_receiver.await.unwrap(); sync_receiver.await.unwrap();
// Semaphore used to limit the number of concurrent clients.
// Its handle is released when the task panics.
let limiter = Arc::new(Semaphore::new(32));
let counter = Arc::new(AtomicU32::new(0));
let total = records.len() * repeat as usize;
let mut handles = Vec::new(); let mut handles = Vec::new();
let connect_to = connect_to.to_socket_addrs().unwrap().next().unwrap(); let connect_to = connect_to.to_socket_addrs().unwrap().next().unwrap();
match tls_mode { match tls_mode {
@ -92,58 +102,159 @@ pub async fn play(
.with_custom_certificate_verifier(Arc::new(DummyCertVerifier)) .with_custom_certificate_verifier(Arc::new(DummyCertVerifier))
.with_no_client_auth(), .with_no_client_auth(),
); );
for (_id, (server_name, records)) in records.iter() { for (id, (server_name, records)) in records.iter() {
let connector = TlsConnector::from(config.clone()); let connector = TlsConnector::from(config.clone());
let counter = counter.clone();
let limiter = limiter.clone();
handles.push(tokio::spawn(async move { handles.push(tokio::spawn(async move {
let limiter = limiter.acquire().await.unwrap();
let server_name = let server_name =
ServerName::try_from(String::from_utf8(server_name.clone()).unwrap()) ServerName::try_from(String::from_utf8(server_name.clone()).unwrap())
.unwrap(); .unwrap();
for _i in 0..repeat { for _i in 0..repeat {
let stream = TcpStream::connect(connect_to).await.unwrap(); let stream = TcpStream::connect(connect_to).await.unwrap();
let mut stream = connector let stream = connector
.connect(server_name.clone(), stream) .connect(server_name.clone(), stream)
.await .await
.unwrap(); .unwrap();
let mut stream = Framed::new(stream, crate::http::HttpCodec {});
for (direction, data) in records { for (direction, data) in records {
match direction { match direction {
Direction::ClientToServer => { Direction::ClientToServer => {
stream.write_all(data).await.unwrap(); println!("[CLT] ({id}) >> {}", data.len());
stream.get_mut().write_all(data).await.unwrap();
} }
Direction::ServerToClient => { Direction::ServerToClient => {
let mut buf = Vec::new(); println!("[CLT] ({id}) << {}", data.len());
stream.read_buf(&mut buf).await.ok(); // let mut buf = Vec::new();
// stream.read_buf(&mut buf).await.ok();
//let mut buf = vec![0; data.len().saturating_sub(50).max(1)];
//let resp = stream.next().await.unwrap().unwrap();
let resp = tokio::time::timeout(
std::time::Duration::from_millis(500),
stream.next(),
)
.await
.unwrap()
.unwrap()
.unwrap();
dbg!(resp.len());
//crate::http::decode_http(&mut buf, &mut stream).await;
} }
} }
} }
stream.shutdown().await.unwrap(); stream.get_mut().shutdown().await.unwrap();
let cnt = counter.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
println!("Client: {} / {}", cnt + 1, total);
} }
drop(limiter);
})); }));
//tokio::time::sleep(std::time::Duration::from_millis(500)).await;
} }
} }
TlsMode::None | TlsMode::Server => { TlsMode::None | TlsMode::Server => {
for (_id, (_server_name, records)) in records.iter() { for (id, (_server_name, records)) in records.iter() {
/*if *id != 33 {
continue
}*/
let counter = counter.clone();
let limiter = limiter.clone();
handles.push(tokio::spawn(async move { handles.push(tokio::spawn(async move {
dbg!(limiter.available_permits());
let limiter = limiter.acquire().await.unwrap();
//let mut buf = Vec::new();
for _i in 0..repeat { for _i in 0..repeat {
let mut stream = TcpStream::connect(connect_to).await.unwrap(); dbg!();
let stream = TcpStream::connect(connect_to).await.unwrap();
let mut stream = Framed::new(stream, crate::http::HttpCodec {});
/*let mut skip_recv = false;
for (direction, data) in records { for (direction, data) in records {
match direction { match direction {
Direction::ClientToServer => { Direction::ClientToServer => {
skip_recv = false;
println!("[CLT] ({id}) >> {}", data.len());
stream.write_all(data).await.unwrap(); stream.write_all(data).await.unwrap();
} }
Direction::ServerToClient => { Direction::ServerToClient => {
let mut buf = Vec::new(); if skip_recv {
stream.read_buf(&mut buf).await.ok(); continue;
}
println!("[CLT] ({id}) << {}", data.len());
//let mut buf = Vec::new();
//stream.read_buf(&mut buf).await.ok();
//let mut buf = vec![0; data.len().saturating_sub(50).max(1)];
let mut buf = vec![0; data.len()];
match tokio::time::timeout(
std::time::Duration::from_millis(500),
stream.readable(),
)
.await
{
Ok(r) => {
r.unwrap();
}
Err(_) => {
println!("[CLT] timeout recv ({id})");
break;
}
}
// TODO utiliser crate::http ici
match tokio::time::timeout(
std::time::Duration::from_millis(500),
stream.read_exact(&mut buf),
)
.await
{
Ok(r) => {
r.unwrap();
}
Err(_) => {
println!("[CLT] skip recv ({id})");
skip_recv = true;
} }
} }
} }
stream.shutdown().await.unwrap();
} }
}*/
for (direction, data) in records {
match direction {
Direction::ClientToServer => {
println!("[CLT] ({id}) >> {}", data.len());
stream.get_mut().write_all(data).await.unwrap();
}
Direction::ServerToClient => {
println!("[CLT] ({id}) << {}", data.len());
//let mut buf = Vec::new();
//stream.read_buf(&mut buf).await.ok();
//let mut buf = vec![0; data.len().saturating_sub(50).max(1)];
let resp = tokio::time::timeout(
std::time::Duration::from_millis(500),
stream.next(),
)
.await
.unwrap()
.unwrap()
.unwrap();
//let resp = stream.next().await.unwrap().unwrap();
dbg!(resp.len());
//crate::http::decode_http(&mut buf, &mut stream).await;
//buf.clear();
}
}
}
dbg!();
stream.get_mut().shutdown().await.unwrap();
let cnt = counter.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
println!("Client: {} / {}", cnt + 1, total);
}
drop(limiter);
})); }));
//tokio::time::sleep(std::time::Duration::from_millis(500)).await;
} }
} }
} }
for handle in handles { for handle in handles {
handle.await.unwrap(); handle.await.unwrap();
} }
//std::process::exit(0); std::process::exit(0);
} }

120
src/http.rs Normal file
View file

@ -0,0 +1,120 @@
use regex::bytes::Regex;
use std::sync::LazyLock;
use tokio::io::AsyncReadExt;
use tokio_util::codec::{Decoder, Encoder};
static REGEX_CONTENT_LENGTH: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r#"[cC]ontent-[lL]ength: *(\d+)\r\n"#).unwrap());
pub async fn _decode_http<R: AsyncReadExt + Unpin>(buf: &mut Vec<u8>, stream: &mut R) {
dbg!();
loop {
dbg!();
if let Some(mut end_index) = memchr::memmem::find(buf, b"\r\n\r\n") {
end_index += 4;
if let Some(captures) = REGEX_CONTENT_LENGTH.captures(buf) {
if let Some(content_length) = captures.get(1) {
// Read body
let content_length: usize = str::from_utf8(content_length.as_bytes())
.unwrap()
.parse()
.unwrap();
while buf.len() < end_index + content_length {
dbg!();
match tokio::time::timeout(
std::time::Duration::from_millis(500),
stream.read_buf(buf),
)
.await
{
Ok(Ok(_n)) => {}
Ok(Err(e)) => {
println!("[http] error reading: {e:?}");
break;
}
Err(_e) => {
// timeout
break;
}
}
}
break;
} else {
// Erroneous Content-Type
break;
}
} else {
// Header ended without Content-Type => no body
break;
}
}
match tokio::time::timeout(std::time::Duration::from_millis(500), stream.read_buf(buf))
.await
{
Ok(Ok(n)) => {
println!("[http] read {n}");
}
Ok(Err(e)) => {
println!("[http] error reading: {e:?}");
break;
}
Err(_e) => {
// timeout
break;
}
}
}
}
pub struct HttpCodec {}
impl Decoder for HttpCodec {
type Item = Vec<u8>;
type Error = std::io::Error;
fn decode(
&mut self,
src: &mut tokio_util::bytes::BytesMut,
) -> Result<Option<Self::Item>, Self::Error> {
if let Some(mut end_index) = memchr::memmem::find(src, b"\r\n\r\n") {
end_index += 4;
if let Some(captures) = REGEX_CONTENT_LENGTH.captures(src) {
if let Some(content_length) = captures.get(1) {
// Read body
let content_length: usize = str::from_utf8(content_length.as_bytes())
.unwrap()
.parse()
.unwrap();
if src.len() >= end_index + content_length {
//dbg!(content_length);
let out = src.to_vec();
src.clear();
Ok(Some(out))
} else {
Ok(None)
}
} else {
// Invalid Content-Length
Err(std::io::ErrorKind::InvalidData.into())
}
} else {
// Header ended without Content-Type => no body
let out = src.to_vec();
src.clear();
Ok(Some(out))
}
} else {
Ok(None)
}
}
}
impl Encoder<Vec<u8>> for HttpCodec {
type Error = std::io::Error;
fn encode(
&mut self,
_item: Vec<u8>,
_dst: &mut tokio_util::bytes::BytesMut,
) -> Result<(), Self::Error> {
Ok(())
}
}

View file

@ -1,6 +1,7 @@
#![feature(let_chains)] #![feature(let_chains)]
mod client; mod client;
mod http;
mod record; mod record;
mod server; mod server;
@ -53,6 +54,9 @@ struct OptPlay {
/// Repeat N times /// Repeat N times
#[argp(option, short = 'r', default = "1")] #[argp(option, short = 'r', default = "1")]
repeat: u32, repeat: u32,
/// Only play this record
#[argp(option)]
record: Option<u64>,
} }
/// Print records /// Print records
@ -93,7 +97,13 @@ async fn main() {
_ => panic!("TLS mode must be one of none,client,server,both."), _ => panic!("TLS mode must be one of none,client,server,both."),
}; };
let records = RECORDS.init(record::read_record_file(&opt.record_file)); let records = RECORDS.init(record::read_record_file(&opt.record_file));
if let Some(only_record) = subopt.record {
records.retain(|id, _| *id == only_record);
}
let (sync_sender, sync_receiver) = oneshot::channel(); let (sync_sender, sync_receiver) = oneshot::channel();
console_subscriber::init();
let client = tokio::spawn(client::play( let client = tokio::spawn(client::play(
records, records,
tls_mode, tls_mode,

View file

@ -212,7 +212,7 @@ pub fn print_records(records: &Records, print_packets: bool) {
} }
} }
if print_packets { if print_packets {
let data = if data.len() >= 256 { let data = if data.len() >= 256 && *direction == Direction::ServerToClient {
&data[0..256] &data[0..256]
} else { } else {
data.as_slice() data.as_slice()

View file

@ -3,12 +3,9 @@ use crate::{
record::{Direction, Records}, record::{Direction, Records},
}; };
use futures_util::stream::StreamExt;
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
use tokio::{ use tokio::{io::AsyncWriteExt, net::TcpListener, sync::oneshot};
io::{AsyncReadExt, AsyncWriteExt},
net::TcpListener,
sync::oneshot,
};
use tokio_rustls::rustls::{ use tokio_rustls::rustls::{
pki_types::{ pki_types::{
CertificateDer, PrivateKeyDer, CertificateDer, PrivateKeyDer,
@ -17,6 +14,7 @@ use tokio_rustls::rustls::{
server::ResolvesServerCertUsingSni, server::ResolvesServerCertUsingSni,
sign::CertifiedKey, sign::CertifiedKey,
}; };
use tokio_util::codec::Framed;
use x509_parser::prelude::GeneralName; use x509_parser::prelude::GeneralName;
pub async fn play( pub async fn play(
@ -27,7 +25,7 @@ pub async fn play(
sync_sender: oneshot::Sender<()>, sync_sender: oneshot::Sender<()>,
) { ) {
let mut response_map = HashMap::new(); let mut response_map = HashMap::new();
for (_id, (server_name, records)) in records.iter() { for (id, (server_name, records)) in records.iter() {
let mut hash = None; let mut hash = None;
let mut responses = Vec::new(); let mut responses = Vec::new();
for (direction, data) in records { for (direction, data) in records {
@ -36,7 +34,7 @@ pub async fn play(
if let Some(hash) = hash if let Some(hash) = hash
&& !responses.is_empty() && !responses.is_empty()
{ {
response_map.insert((server_name.to_vec(), hash), responses); response_map.insert((server_name.to_vec(), hash), (id, responses));
responses = Vec::new(); responses = Vec::new();
} }
hash = Some( hash = Some(
@ -52,17 +50,21 @@ pub async fn play(
if let Some(hash) = hash if let Some(hash) = hash
&& !responses.is_empty() && !responses.is_empty()
{ {
response_map.insert((server_name.to_vec(), hash), responses); response_map.insert((server_name.to_vec(), hash), (id, responses));
} }
} }
let response_map = Arc::new(response_map);
match tls_mode { match tls_mode {
TlsMode::Both | TlsMode::Server => { TlsMode::Both | TlsMode::Server => {
let mut resolver = ResolvesServerCertUsingSni::new(); let mut resolver = ResolvesServerCertUsingSni::new();
let config = tokio_rustls::rustls::ServerConfig::builder() let config = tokio_rustls::rustls::ServerConfig::builder()
.with_no_client_auth() .with_no_client_auth()
.with_cert_resolver(Arc::new(ResolvesServerCertUsingSni::new())); .with_cert_resolver(Arc::new(ResolvesServerCertUsingSni::new()));
for file in std::fs::read_dir(cert_path).unwrap() { for file in std::fs::read_dir(cert_path).unwrap_or_else(|e| {
panic!("Cannot read certificate directory `{cert_path}`: {e:?}")
}) {
match file { match file {
Ok(file) => { Ok(file) => {
if file.file_name().as_encoded_bytes().ends_with(b".crt") { if file.file_name().as_encoded_bytes().ends_with(b".crt") {
@ -77,7 +79,7 @@ pub async fn play(
let (_rem, cert) = let (_rem, cert) =
x509_parser::parse_x509_certificate(&data).unwrap(); x509_parser::parse_x509_certificate(&data).unwrap();
if !cert.is_ca() { if !cert.is_ca() {
println!("File: {:?}", file.file_name()); //println!("File: {:?}", file.file_name());
let mut key_path = file.path().to_path_buf(); let mut key_path = file.path().to_path_buf();
key_path.pop(); key_path.pop();
let file_name = let file_name =
@ -110,7 +112,7 @@ pub async fn play(
.iter() .iter()
{ {
if let GeneralName::DNSName(name) = name { if let GeneralName::DNSName(name) = name {
resolver.add(dbg!(name), cert_key.clone()).unwrap(); resolver.add(name, cert_key.clone()).unwrap();
} }
} }
} }
@ -130,9 +132,7 @@ pub async fn play(
.with_cert_resolver(Arc::new(resolver)), .with_cert_resolver(Arc::new(resolver)),
); );
//let acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(config));
let listener = TcpListener::bind(listen_addr).await.unwrap(); let listener = TcpListener::bind(listen_addr).await.unwrap();
let response_map = Arc::new(response_map);
sync_sender.send(()).unwrap(); sync_sender.send(()).unwrap();
loop { loop {
let config = config.clone(); let config = config.clone();
@ -143,28 +143,12 @@ pub async fn play(
); );
//let acceptor = acceptor.clone(); //let acceptor = acceptor.clone();
let response_map = response_map.clone(); let response_map = response_map.clone();
let fut = async move { /*let fut = async move {
/*let mut server_name = None;
let mut stream = acceptor
.accept_with(stream, |conn| {
server_name = conn.server_name().map(String::from)
})
.await
.unwrap();
let server_name = server_name.unwrap();*/
let accepted = acceptor.await.unwrap(); let accepted = acceptor.await.unwrap();
let server_name = accepted.client_hello().server_name().unwrap().to_string(); let server_name = accepted.client_hello().server_name().unwrap().to_string();
let mut stream = accepted.into_stream(config).await.unwrap(); let mut stream = accepted.into_stream(config).await.unwrap();
let mut req = Vec::new(); let mut req = Vec::new();
// TODO if there is a body http::decode_http(&mut req, &mut stream).await;
while !req.ends_with(b"\r\n\r\n") {
if stream.read_buf(&mut req).await.unwrap() == 0 {
break;
}
}
if let Ok(req) = str::from_utf8(&req) {
println!("{req}");
}
let req_hash = tlsh::hash_buf(&req) let req_hash = tlsh::hash_buf(&req)
.map_or_else(|_| req.clone(), |h| h.to_string().into_bytes()); .map_or_else(|_| req.clone(), |h| h.to_string().into_bytes());
let mut best = None; let mut best = None;
@ -183,15 +167,54 @@ pub async fn play(
} }
} }
if let Some((hash, _diff)) = best { if let Some((hash, _diff)) = best {
let responses = response_map let (id, responses) = response_map
.get(&(server_name.as_bytes().to_vec(), hash.clone())) .get(&(server_name.as_bytes().to_vec(), hash.clone()))
.unwrap(); .unwrap();
for &res in responses { for &res in responses {
println!("[SRV] response for ({}): {} bytes", id, res.len());
stream.write_all(res).await.unwrap(); stream.write_all(res).await.unwrap();
stream.flush().await.unwrap(); stream.flush().await.unwrap();
} }
} else { } else {
eprintln!("No response found for SNI=`{server_name}`"); println!("No response found for SNI=`{server_name}`");
}
stream.shutdown().await.unwrap();
};*/
let fut = async move {
let accepted = acceptor.await.unwrap();
let server_name = accepted.client_hello().server_name().unwrap().to_string();
let stream = accepted.into_stream(config).await.unwrap();
let mut stream = Framed::new(stream, crate::http::HttpCodec {});
let req = stream.next().await.unwrap().unwrap();
let req_hash = tlsh::hash_buf(&req)
.map_or_else(|_| req.clone(), |h| h.to_string().into_bytes());
let mut best = None;
for (i_server_name, hash) in response_map.keys() {
if i_server_name != server_name.as_bytes() {
continue;
}
let diff = compare(&req_hash, hash);
if let Some((best_hash, best_diff)) = &mut best {
if diff < *best_diff {
*best_hash = hash;
*best_diff = diff;
}
} else {
best = Some((hash, diff));
}
}
let stream = stream.get_mut();
if let Some((hash, _diff)) = best {
let (id, responses) = response_map
.get(&(server_name.as_bytes().to_vec(), hash.clone()))
.unwrap();
for &res in responses {
println!("[SRV] response for ({}): {} bytes", id, res.len());
stream.write_all(res).await.unwrap();
stream.flush().await.unwrap();
}
} else {
println!("No response found for SNI=`{server_name}`");
} }
stream.shutdown().await.unwrap(); stream.shutdown().await.unwrap();
}; };
@ -201,7 +224,88 @@ pub async fn play(
} }
} }
TlsMode::None | TlsMode::Client => { TlsMode::None | TlsMode::Client => {
// TODO let listener = TcpListener::bind(listen_addr).await.unwrap_or_else(|e| {
println!("Server: Cannot listen: {e:?}");
std::process::exit(1)
});
sync_sender.send(()).unwrap();
loop {
let (stream, _peer_addr) = listener.accept().await.unwrap();
let response_map = response_map.clone();
/*let fut = async move {
println!("[SRV] New task");
let mut req = Vec::new();
http::decode_http(&mut req, &mut stream).await;
let req_hash = tlsh::hash_buf(&req)
.map_or_else(|_| req.clone(), |h| h.to_string().into_bytes());
let mut best = None;
for (i_server_name, hash) in response_map.keys() {
let diff = compare(&req_hash, hash);
if let Some((best_server_name, best_hash, best_diff)) = &mut best {
if diff < *best_diff {
*best_server_name = i_server_name;
*best_hash = hash;
*best_diff = diff;
}
} else {
best = Some((i_server_name, hash, diff));
}
}
if let Some((server_name, hash, _diff)) = best {
let (id, responses) = response_map
.get(&(server_name.clone(), hash.clone()))
.unwrap();
for &res in responses {
println!("[SRV] response for ({}): {} bytes", id, res.len());
stream.write_all(res).await.unwrap();
stream.flush().await.unwrap();
}
} else {
println!("[SRV] No response found");
}
//println!("Server shutdown");
stream.shutdown().await.unwrap();
};*/
let fut = async move {
println!("[SRV] New task");
let mut stream = Framed::new(stream, crate::http::HttpCodec {});
let req = stream.next().await.unwrap().unwrap();
let req_hash = tlsh::hash_buf(&req)
.map_or_else(|_| req.clone(), |h| h.to_string().into_bytes());
let mut best = None;
for (i_server_name, hash) in response_map.keys() {
let diff = compare(&req_hash, hash);
if let Some((best_server_name, best_hash, best_diff)) = &mut best {
if diff < *best_diff {
*best_server_name = i_server_name;
*best_hash = hash;
*best_diff = diff;
}
} else {
best = Some((i_server_name, hash, diff));
}
}
let stream = stream.get_mut();
if let Some((server_name, hash, _diff)) = best {
let (id, responses) = response_map
.get(&(server_name.clone(), hash.clone()))
.unwrap();
for &res in responses {
println!("[SRV] response for ({}): {} bytes", id, res.len());
stream.write_all(res).await.unwrap();
stream.flush().await.unwrap();
}
} else {
println!("[SRV] No response found");
}
//println!("Server shutdown");
stream.shutdown().await.unwrap();
};
// Using a variable for the future allows it to be detected by tokio-console
tokio::spawn(async move {
fut.await;
});
}
} }
} }
} }