├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── example.config.toml ├── hook ├── Cargo.toml └── src │ └── lib.rs ├── mitmca ├── Cargo.toml └── src │ └── lib.rs └── src ├── check.rs ├── config.rs ├── gen.rs ├── main.rs ├── proxy.rs ├── proxy ├── fragment.rs ├── localdoh.rs ├── mitm.rs └── socks5.rs └── util.rs /.gitignore: -------------------------------------------------------------------------------- 1 | **/target 2 | **/*.rs.bk 3 | **/*.txt 4 | **/*.dat 5 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "1.1.3" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "anyhow" 31 | version = "1.0.98" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" 34 | 35 | [[package]] 36 | name = "argh" 37 | version = "0.1.13" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "34ff18325c8a36b82f992e533ece1ec9f9a9db446bd1c14d4f936bac88fcd240" 40 | dependencies = [ 41 | "argh_derive", 42 | "argh_shared", 43 | "rust-fuzzy-search", 44 | ] 45 | 46 | [[package]] 47 | name = "argh_derive" 48 | version = "0.1.13" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "adb7b2b83a50d329d5d8ccc620f5c7064028828538bdf5646acd60dc1f767803" 51 | dependencies = [ 52 | "argh_shared", 53 | "proc-macro2", 54 | "quote", 55 | "syn 2.0.101", 56 | ] 57 | 58 | [[package]] 59 | name = "argh_shared" 60 | version = "0.1.13" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "a464143cc82dedcdc3928737445362466b7674b5db4e2eb8e869846d6d84f4f6" 63 | dependencies = [ 64 | "serde", 65 | ] 66 | 67 | [[package]] 68 | name = "asn1-rs" 69 | version = "0.6.2" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" 72 | dependencies = [ 73 | "asn1-rs-derive", 74 | "asn1-rs-impl", 75 | "displaydoc", 76 | "nom", 77 | "num-traits", 78 | "rusticata-macros", 79 | "thiserror 1.0.69", 80 | "time", 81 | ] 82 | 83 | [[package]] 84 | name = "asn1-rs-derive" 85 | version = "0.5.1" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" 88 | dependencies = [ 89 | "proc-macro2", 90 | "quote", 91 | "syn 2.0.101", 92 | "synstructure", 93 | ] 94 | 95 | [[package]] 96 | name = "asn1-rs-impl" 97 | version = "0.2.0" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" 100 | dependencies = [ 101 | "proc-macro2", 102 | "quote", 103 | "syn 2.0.101", 104 | ] 105 | 106 | [[package]] 107 | name = "async-trait" 108 | version = "0.1.88" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" 111 | dependencies = [ 112 | "proc-macro2", 113 | "quote", 114 | "syn 2.0.101", 115 | ] 116 | 117 | [[package]] 118 | name = "atomic-waker" 119 | version = "1.1.2" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 122 | 123 | [[package]] 124 | name = "autocfg" 125 | version = "1.4.0" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 128 | 129 | [[package]] 130 | name = "backtrace" 131 | version = "0.3.75" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" 134 | dependencies = [ 135 | "addr2line", 136 | "cfg-if", 137 | "libc", 138 | "miniz_oxide", 139 | "object", 140 | "rustc-demangle", 141 | "windows-targets 0.52.6", 142 | ] 143 | 144 | [[package]] 145 | name = "base64" 146 | version = "0.22.1" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 149 | 150 | [[package]] 151 | name = "bitflags" 152 | version = "2.9.0" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" 155 | 156 | [[package]] 157 | name = "bytes" 158 | version = "1.10.1" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" 161 | 162 | [[package]] 163 | name = "cache_2q" 164 | version = "0.10.1" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "c3421ff4fcec8bd015d28aa32c56dcda49dca55d119cb9b0455951e33d4f5f9d" 167 | dependencies = [ 168 | "linked-hash-map", 169 | ] 170 | 171 | [[package]] 172 | name = "cc" 173 | version = "1.2.22" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" 176 | dependencies = [ 177 | "shlex", 178 | ] 179 | 180 | [[package]] 181 | name = "cfg-if" 182 | version = "1.0.0" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 185 | 186 | [[package]] 187 | name = "critical-section" 188 | version = "1.2.0" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" 191 | 192 | [[package]] 193 | name = "crossbeam-channel" 194 | version = "0.5.15" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" 197 | dependencies = [ 198 | "crossbeam-utils", 199 | ] 200 | 201 | [[package]] 202 | name = "crossbeam-epoch" 203 | version = "0.9.18" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 206 | dependencies = [ 207 | "crossbeam-utils", 208 | ] 209 | 210 | [[package]] 211 | name = "crossbeam-utils" 212 | version = "0.8.21" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 215 | 216 | [[package]] 217 | name = "data-encoding" 218 | version = "2.9.0" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" 221 | 222 | [[package]] 223 | name = "der-parser" 224 | version = "9.0.0" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" 227 | dependencies = [ 228 | "asn1-rs", 229 | "displaydoc", 230 | "nom", 231 | "num-bigint", 232 | "num-traits", 233 | "rusticata-macros", 234 | ] 235 | 236 | [[package]] 237 | name = "deranged" 238 | version = "0.4.0" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" 241 | dependencies = [ 242 | "powerfmt", 243 | ] 244 | 245 | [[package]] 246 | name = "directories" 247 | version = "6.0.0" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" 250 | dependencies = [ 251 | "dirs-sys", 252 | ] 253 | 254 | [[package]] 255 | name = "dirs-sys" 256 | version = "0.5.0" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" 259 | dependencies = [ 260 | "libc", 261 | "option-ext", 262 | "redox_users", 263 | "windows-sys 0.59.0", 264 | ] 265 | 266 | [[package]] 267 | name = "displaydoc" 268 | version = "0.2.5" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 271 | dependencies = [ 272 | "proc-macro2", 273 | "quote", 274 | "syn 2.0.101", 275 | ] 276 | 277 | [[package]] 278 | name = "enum-as-inner" 279 | version = "0.6.1" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" 282 | dependencies = [ 283 | "heck", 284 | "proc-macro2", 285 | "quote", 286 | "syn 2.0.101", 287 | ] 288 | 289 | [[package]] 290 | name = "equivalent" 291 | version = "1.0.2" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 294 | 295 | [[package]] 296 | name = "fdeflate" 297 | version = "0.3.7" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" 300 | dependencies = [ 301 | "simd-adler32", 302 | ] 303 | 304 | [[package]] 305 | name = "fnv" 306 | version = "1.0.7" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 309 | 310 | [[package]] 311 | name = "form_urlencoded" 312 | version = "1.2.1" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 315 | dependencies = [ 316 | "percent-encoding", 317 | ] 318 | 319 | [[package]] 320 | name = "futures" 321 | version = "0.3.31" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 324 | dependencies = [ 325 | "futures-channel", 326 | "futures-core", 327 | "futures-executor", 328 | "futures-io", 329 | "futures-sink", 330 | "futures-task", 331 | "futures-util", 332 | ] 333 | 334 | [[package]] 335 | name = "futures-channel" 336 | version = "0.3.31" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 339 | dependencies = [ 340 | "futures-core", 341 | "futures-sink", 342 | ] 343 | 344 | [[package]] 345 | name = "futures-core" 346 | version = "0.3.31" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 349 | 350 | [[package]] 351 | name = "futures-executor" 352 | version = "0.3.31" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 355 | dependencies = [ 356 | "futures-core", 357 | "futures-task", 358 | "futures-util", 359 | ] 360 | 361 | [[package]] 362 | name = "futures-io" 363 | version = "0.3.31" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 366 | 367 | [[package]] 368 | name = "futures-macro" 369 | version = "0.3.31" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 372 | dependencies = [ 373 | "proc-macro2", 374 | "quote", 375 | "syn 2.0.101", 376 | ] 377 | 378 | [[package]] 379 | name = "futures-sink" 380 | version = "0.3.31" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 383 | 384 | [[package]] 385 | name = "futures-task" 386 | version = "0.3.31" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 389 | 390 | [[package]] 391 | name = "futures-util" 392 | version = "0.3.31" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 395 | dependencies = [ 396 | "futures-channel", 397 | "futures-core", 398 | "futures-io", 399 | "futures-macro", 400 | "futures-sink", 401 | "futures-task", 402 | "memchr", 403 | "pin-project-lite", 404 | "pin-utils", 405 | "slab", 406 | ] 407 | 408 | [[package]] 409 | name = "generator" 410 | version = "0.8.4" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" 413 | dependencies = [ 414 | "cfg-if", 415 | "libc", 416 | "log", 417 | "rustversion", 418 | "windows", 419 | ] 420 | 421 | [[package]] 422 | name = "getrandom" 423 | version = "0.2.16" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" 426 | dependencies = [ 427 | "cfg-if", 428 | "libc", 429 | "wasi 0.11.0+wasi-snapshot-preview1", 430 | ] 431 | 432 | [[package]] 433 | name = "getrandom" 434 | version = "0.3.3" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" 437 | dependencies = [ 438 | "cfg-if", 439 | "libc", 440 | "r-efi", 441 | "wasi 0.14.2+wasi-0.2.4", 442 | ] 443 | 444 | [[package]] 445 | name = "gimli" 446 | version = "0.31.1" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 449 | 450 | [[package]] 451 | name = "h2" 452 | version = "0.4.10" 453 | source = "registry+https://github.com/rust-lang/crates.io-index" 454 | checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" 455 | dependencies = [ 456 | "atomic-waker", 457 | "bytes", 458 | "fnv", 459 | "futures-core", 460 | "futures-sink", 461 | "http", 462 | "indexmap", 463 | "slab", 464 | "tokio", 465 | "tokio-util", 466 | "tracing", 467 | ] 468 | 469 | [[package]] 470 | name = "hashbrown" 471 | version = "0.15.3" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" 474 | 475 | [[package]] 476 | name = "heck" 477 | version = "0.5.0" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 480 | 481 | [[package]] 482 | name = "hickory-proto" 483 | version = "0.25.2" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502" 486 | dependencies = [ 487 | "async-trait", 488 | "bitflags", 489 | "bytes", 490 | "cfg-if", 491 | "data-encoding", 492 | "enum-as-inner", 493 | "futures-channel", 494 | "futures-io", 495 | "futures-util", 496 | "h2", 497 | "http", 498 | "idna", 499 | "ipnet", 500 | "once_cell", 501 | "rand", 502 | "ring", 503 | "rustls", 504 | "rustls-pki-types", 505 | "thiserror 2.0.12", 506 | "time", 507 | "tinyvec", 508 | "tokio", 509 | "tokio-rustls", 510 | "tracing", 511 | "url", 512 | ] 513 | 514 | [[package]] 515 | name = "hickory-resolver" 516 | version = "0.25.2" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a" 519 | dependencies = [ 520 | "cfg-if", 521 | "futures-util", 522 | "hickory-proto", 523 | "ipconfig", 524 | "moka", 525 | "once_cell", 526 | "parking_lot", 527 | "rand", 528 | "resolv-conf", 529 | "rustls", 530 | "smallvec", 531 | "thiserror 2.0.12", 532 | "tokio", 533 | "tokio-rustls", 534 | "tracing", 535 | ] 536 | 537 | [[package]] 538 | name = "http" 539 | version = "1.3.1" 540 | source = "registry+https://github.com/rust-lang/crates.io-index" 541 | checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" 542 | dependencies = [ 543 | "bytes", 544 | "fnv", 545 | "itoa", 546 | ] 547 | 548 | [[package]] 549 | name = "http-body" 550 | version = "1.0.1" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 553 | dependencies = [ 554 | "bytes", 555 | "http", 556 | ] 557 | 558 | [[package]] 559 | name = "http-body-util" 560 | version = "0.1.3" 561 | source = "registry+https://github.com/rust-lang/crates.io-index" 562 | checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" 563 | dependencies = [ 564 | "bytes", 565 | "futures-core", 566 | "http", 567 | "http-body", 568 | "pin-project-lite", 569 | ] 570 | 571 | [[package]] 572 | name = "httparse" 573 | version = "1.10.1" 574 | source = "registry+https://github.com/rust-lang/crates.io-index" 575 | checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" 576 | 577 | [[package]] 578 | name = "httpdate" 579 | version = "1.0.3" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 582 | 583 | [[package]] 584 | name = "hyper" 585 | version = "1.6.0" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" 588 | dependencies = [ 589 | "bytes", 590 | "futures-channel", 591 | "futures-util", 592 | "h2", 593 | "http", 594 | "http-body", 595 | "httparse", 596 | "httpdate", 597 | "itoa", 598 | "pin-project-lite", 599 | "smallvec", 600 | "tokio", 601 | "want", 602 | ] 603 | 604 | [[package]] 605 | name = "hyper-util" 606 | version = "0.1.11" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" 609 | dependencies = [ 610 | "bytes", 611 | "futures-util", 612 | "http", 613 | "http-body", 614 | "hyper", 615 | "pin-project-lite", 616 | "tokio", 617 | ] 618 | 619 | [[package]] 620 | name = "icu_collections" 621 | version = "2.0.0" 622 | source = "registry+https://github.com/rust-lang/crates.io-index" 623 | checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" 624 | dependencies = [ 625 | "displaydoc", 626 | "potential_utf", 627 | "yoke", 628 | "zerofrom", 629 | "zerovec", 630 | ] 631 | 632 | [[package]] 633 | name = "icu_locale_core" 634 | version = "2.0.0" 635 | source = "registry+https://github.com/rust-lang/crates.io-index" 636 | checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" 637 | dependencies = [ 638 | "displaydoc", 639 | "litemap", 640 | "tinystr", 641 | "writeable", 642 | "zerovec", 643 | ] 644 | 645 | [[package]] 646 | name = "icu_normalizer" 647 | version = "2.0.0" 648 | source = "registry+https://github.com/rust-lang/crates.io-index" 649 | checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" 650 | dependencies = [ 651 | "displaydoc", 652 | "icu_collections", 653 | "icu_normalizer_data", 654 | "icu_properties", 655 | "icu_provider", 656 | "smallvec", 657 | "zerovec", 658 | ] 659 | 660 | [[package]] 661 | name = "icu_normalizer_data" 662 | version = "2.0.0" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" 665 | 666 | [[package]] 667 | name = "icu_properties" 668 | version = "2.0.0" 669 | source = "registry+https://github.com/rust-lang/crates.io-index" 670 | checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" 671 | dependencies = [ 672 | "displaydoc", 673 | "icu_collections", 674 | "icu_locale_core", 675 | "icu_properties_data", 676 | "icu_provider", 677 | "potential_utf", 678 | "zerotrie", 679 | "zerovec", 680 | ] 681 | 682 | [[package]] 683 | name = "icu_properties_data" 684 | version = "2.0.0" 685 | source = "registry+https://github.com/rust-lang/crates.io-index" 686 | checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" 687 | 688 | [[package]] 689 | name = "icu_provider" 690 | version = "2.0.0" 691 | source = "registry+https://github.com/rust-lang/crates.io-index" 692 | checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" 693 | dependencies = [ 694 | "displaydoc", 695 | "icu_locale_core", 696 | "stable_deref_trait", 697 | "tinystr", 698 | "writeable", 699 | "yoke", 700 | "zerofrom", 701 | "zerotrie", 702 | "zerovec", 703 | ] 704 | 705 | [[package]] 706 | name = "idna" 707 | version = "1.0.3" 708 | source = "registry+https://github.com/rust-lang/crates.io-index" 709 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 710 | dependencies = [ 711 | "idna_adapter", 712 | "smallvec", 713 | "utf8_iter", 714 | ] 715 | 716 | [[package]] 717 | name = "idna_adapter" 718 | version = "1.2.1" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" 721 | dependencies = [ 722 | "icu_normalizer", 723 | "icu_properties", 724 | ] 725 | 726 | [[package]] 727 | name = "indexmap" 728 | version = "2.9.0" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" 731 | dependencies = [ 732 | "equivalent", 733 | "hashbrown", 734 | ] 735 | 736 | [[package]] 737 | name = "ipconfig" 738 | version = "0.3.2" 739 | source = "registry+https://github.com/rust-lang/crates.io-index" 740 | checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" 741 | dependencies = [ 742 | "socket2", 743 | "widestring", 744 | "windows-sys 0.48.0", 745 | "winreg", 746 | ] 747 | 748 | [[package]] 749 | name = "ipnet" 750 | version = "2.11.0" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" 753 | 754 | [[package]] 755 | name = "itoa" 756 | version = "1.0.15" 757 | source = "registry+https://github.com/rust-lang/crates.io-index" 758 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 759 | 760 | [[package]] 761 | name = "lazy_static" 762 | version = "1.5.0" 763 | source = "registry+https://github.com/rust-lang/crates.io-index" 764 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 765 | 766 | [[package]] 767 | name = "libc" 768 | version = "0.2.172" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" 771 | 772 | [[package]] 773 | name = "libloading" 774 | version = "0.8.7" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" 777 | dependencies = [ 778 | "cfg-if", 779 | "windows-targets 0.53.0", 780 | ] 781 | 782 | [[package]] 783 | name = "libredox" 784 | version = "0.1.3" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 787 | dependencies = [ 788 | "bitflags", 789 | "libc", 790 | ] 791 | 792 | [[package]] 793 | name = "linked-hash-map" 794 | version = "0.5.6" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" 797 | 798 | [[package]] 799 | name = "litemap" 800 | version = "0.8.0" 801 | source = "registry+https://github.com/rust-lang/crates.io-index" 802 | checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" 803 | 804 | [[package]] 805 | name = "lock_api" 806 | version = "0.4.12" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 809 | dependencies = [ 810 | "autocfg", 811 | "scopeguard", 812 | ] 813 | 814 | [[package]] 815 | name = "log" 816 | version = "0.4.27" 817 | source = "registry+https://github.com/rust-lang/crates.io-index" 818 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 819 | 820 | [[package]] 821 | name = "loom" 822 | version = "0.7.2" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" 825 | dependencies = [ 826 | "cfg-if", 827 | "generator", 828 | "scoped-tls", 829 | "tracing", 830 | "tracing-subscriber", 831 | ] 832 | 833 | [[package]] 834 | name = "matchers" 835 | version = "0.1.0" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 838 | dependencies = [ 839 | "regex-automata 0.1.10", 840 | ] 841 | 842 | [[package]] 843 | name = "memchr" 844 | version = "2.7.4" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 847 | 848 | [[package]] 849 | name = "minimal-lexical" 850 | version = "0.2.1" 851 | source = "registry+https://github.com/rust-lang/crates.io-index" 852 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 853 | 854 | [[package]] 855 | name = "miniz_oxide" 856 | version = "0.8.8" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" 859 | dependencies = [ 860 | "adler2", 861 | ] 862 | 863 | [[package]] 864 | name = "mio" 865 | version = "1.0.3" 866 | source = "registry+https://github.com/rust-lang/crates.io-index" 867 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 868 | dependencies = [ 869 | "libc", 870 | "wasi 0.11.0+wasi-snapshot-preview1", 871 | "windows-sys 0.52.0", 872 | ] 873 | 874 | [[package]] 875 | name = "mitmca" 876 | version = "0.1.0" 877 | dependencies = [ 878 | "cache_2q", 879 | "pem", 880 | "psl", 881 | "rand", 882 | "rcgen", 883 | "rustls", 884 | "rustls-webpki", 885 | "thiserror 2.0.12", 886 | "time", 887 | ] 888 | 889 | [[package]] 890 | name = "moka" 891 | version = "0.12.10" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926" 894 | dependencies = [ 895 | "crossbeam-channel", 896 | "crossbeam-epoch", 897 | "crossbeam-utils", 898 | "loom", 899 | "parking_lot", 900 | "portable-atomic", 901 | "rustc_version", 902 | "smallvec", 903 | "tagptr", 904 | "thiserror 1.0.69", 905 | "uuid", 906 | ] 907 | 908 | [[package]] 909 | name = "nom" 910 | version = "7.1.3" 911 | source = "registry+https://github.com/rust-lang/crates.io-index" 912 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 913 | dependencies = [ 914 | "memchr", 915 | "minimal-lexical", 916 | ] 917 | 918 | [[package]] 919 | name = "nosni-hook" 920 | version = "0.1.0" 921 | dependencies = [ 922 | "libc", 923 | "libloading", 924 | "once_cell", 925 | ] 926 | 927 | [[package]] 928 | name = "nosni-proxy" 929 | version = "0.4.0" 930 | dependencies = [ 931 | "anyhow", 932 | "argh", 933 | "directories", 934 | "fdeflate", 935 | "futures", 936 | "hickory-resolver", 937 | "http", 938 | "http-body-util", 939 | "hyper", 940 | "hyper-util", 941 | "mitmca", 942 | "once_cell", 943 | "percent-encoding", 944 | "rand", 945 | "rcgen", 946 | "ruzstd", 947 | "serde", 948 | "tokio", 949 | "tokio-rustls", 950 | "toml", 951 | "tower-happy-eyeballs", 952 | "tower-layer", 953 | "tower-util", 954 | "webpki-roots 0.26.11", 955 | ] 956 | 957 | [[package]] 958 | name = "nu-ansi-term" 959 | version = "0.46.0" 960 | source = "registry+https://github.com/rust-lang/crates.io-index" 961 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 962 | dependencies = [ 963 | "overload", 964 | "winapi", 965 | ] 966 | 967 | [[package]] 968 | name = "num-bigint" 969 | version = "0.4.6" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" 972 | dependencies = [ 973 | "num-integer", 974 | "num-traits", 975 | ] 976 | 977 | [[package]] 978 | name = "num-conv" 979 | version = "0.1.0" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 982 | 983 | [[package]] 984 | name = "num-integer" 985 | version = "0.1.46" 986 | source = "registry+https://github.com/rust-lang/crates.io-index" 987 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 988 | dependencies = [ 989 | "num-traits", 990 | ] 991 | 992 | [[package]] 993 | name = "num-traits" 994 | version = "0.2.19" 995 | source = "registry+https://github.com/rust-lang/crates.io-index" 996 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 997 | dependencies = [ 998 | "autocfg", 999 | ] 1000 | 1001 | [[package]] 1002 | name = "object" 1003 | version = "0.36.7" 1004 | source = "registry+https://github.com/rust-lang/crates.io-index" 1005 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 1006 | dependencies = [ 1007 | "memchr", 1008 | ] 1009 | 1010 | [[package]] 1011 | name = "oid-registry" 1012 | version = "0.7.1" 1013 | source = "registry+https://github.com/rust-lang/crates.io-index" 1014 | checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" 1015 | dependencies = [ 1016 | "asn1-rs", 1017 | ] 1018 | 1019 | [[package]] 1020 | name = "once_cell" 1021 | version = "1.21.3" 1022 | source = "registry+https://github.com/rust-lang/crates.io-index" 1023 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 1024 | dependencies = [ 1025 | "critical-section", 1026 | "portable-atomic", 1027 | ] 1028 | 1029 | [[package]] 1030 | name = "option-ext" 1031 | version = "0.2.0" 1032 | source = "registry+https://github.com/rust-lang/crates.io-index" 1033 | checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" 1034 | 1035 | [[package]] 1036 | name = "overload" 1037 | version = "0.1.1" 1038 | source = "registry+https://github.com/rust-lang/crates.io-index" 1039 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 1040 | 1041 | [[package]] 1042 | name = "parking_lot" 1043 | version = "0.12.3" 1044 | source = "registry+https://github.com/rust-lang/crates.io-index" 1045 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 1046 | dependencies = [ 1047 | "lock_api", 1048 | "parking_lot_core", 1049 | ] 1050 | 1051 | [[package]] 1052 | name = "parking_lot_core" 1053 | version = "0.9.10" 1054 | source = "registry+https://github.com/rust-lang/crates.io-index" 1055 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1056 | dependencies = [ 1057 | "cfg-if", 1058 | "libc", 1059 | "redox_syscall", 1060 | "smallvec", 1061 | "windows-targets 0.52.6", 1062 | ] 1063 | 1064 | [[package]] 1065 | name = "pem" 1066 | version = "3.0.5" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" 1069 | dependencies = [ 1070 | "base64", 1071 | "serde", 1072 | ] 1073 | 1074 | [[package]] 1075 | name = "percent-encoding" 1076 | version = "2.3.1" 1077 | source = "registry+https://github.com/rust-lang/crates.io-index" 1078 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1079 | 1080 | [[package]] 1081 | name = "pin-project" 1082 | version = "0.4.30" 1083 | source = "registry+https://github.com/rust-lang/crates.io-index" 1084 | checksum = "3ef0f924a5ee7ea9cbcea77529dba45f8a9ba9f622419fe3386ca581a3ae9d5a" 1085 | dependencies = [ 1086 | "pin-project-internal", 1087 | ] 1088 | 1089 | [[package]] 1090 | name = "pin-project-internal" 1091 | version = "0.4.30" 1092 | source = "registry+https://github.com/rust-lang/crates.io-index" 1093 | checksum = "851c8d0ce9bebe43790dedfc86614c23494ac9f423dd618d3a61fc693eafe61e" 1094 | dependencies = [ 1095 | "proc-macro2", 1096 | "quote", 1097 | "syn 1.0.109", 1098 | ] 1099 | 1100 | [[package]] 1101 | name = "pin-project-lite" 1102 | version = "0.2.16" 1103 | source = "registry+https://github.com/rust-lang/crates.io-index" 1104 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 1105 | 1106 | [[package]] 1107 | name = "pin-utils" 1108 | version = "0.1.0" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1111 | 1112 | [[package]] 1113 | name = "portable-atomic" 1114 | version = "1.11.0" 1115 | source = "registry+https://github.com/rust-lang/crates.io-index" 1116 | checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" 1117 | 1118 | [[package]] 1119 | name = "potential_utf" 1120 | version = "0.1.2" 1121 | source = "registry+https://github.com/rust-lang/crates.io-index" 1122 | checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" 1123 | dependencies = [ 1124 | "zerovec", 1125 | ] 1126 | 1127 | [[package]] 1128 | name = "powerfmt" 1129 | version = "0.2.0" 1130 | source = "registry+https://github.com/rust-lang/crates.io-index" 1131 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1132 | 1133 | [[package]] 1134 | name = "ppv-lite86" 1135 | version = "0.2.21" 1136 | source = "registry+https://github.com/rust-lang/crates.io-index" 1137 | checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" 1138 | dependencies = [ 1139 | "zerocopy", 1140 | ] 1141 | 1142 | [[package]] 1143 | name = "proc-macro2" 1144 | version = "1.0.95" 1145 | source = "registry+https://github.com/rust-lang/crates.io-index" 1146 | checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 1147 | dependencies = [ 1148 | "unicode-ident", 1149 | ] 1150 | 1151 | [[package]] 1152 | name = "psl" 1153 | version = "2.1.108" 1154 | source = "registry+https://github.com/rust-lang/crates.io-index" 1155 | checksum = "b4d0b873458f19667df558849359edcc4786da36ce54c8668fd5d1c36c22b080" 1156 | dependencies = [ 1157 | "psl-types", 1158 | ] 1159 | 1160 | [[package]] 1161 | name = "psl-types" 1162 | version = "2.0.11" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" 1165 | 1166 | [[package]] 1167 | name = "quote" 1168 | version = "1.0.40" 1169 | source = "registry+https://github.com/rust-lang/crates.io-index" 1170 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 1171 | dependencies = [ 1172 | "proc-macro2", 1173 | ] 1174 | 1175 | [[package]] 1176 | name = "r-efi" 1177 | version = "5.2.0" 1178 | source = "registry+https://github.com/rust-lang/crates.io-index" 1179 | checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" 1180 | 1181 | [[package]] 1182 | name = "rand" 1183 | version = "0.9.1" 1184 | source = "registry+https://github.com/rust-lang/crates.io-index" 1185 | checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" 1186 | dependencies = [ 1187 | "rand_chacha", 1188 | "rand_core", 1189 | ] 1190 | 1191 | [[package]] 1192 | name = "rand_chacha" 1193 | version = "0.9.0" 1194 | source = "registry+https://github.com/rust-lang/crates.io-index" 1195 | checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 1196 | dependencies = [ 1197 | "ppv-lite86", 1198 | "rand_core", 1199 | ] 1200 | 1201 | [[package]] 1202 | name = "rand_core" 1203 | version = "0.9.3" 1204 | source = "registry+https://github.com/rust-lang/crates.io-index" 1205 | checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" 1206 | dependencies = [ 1207 | "getrandom 0.3.3", 1208 | ] 1209 | 1210 | [[package]] 1211 | name = "rcgen" 1212 | version = "0.13.1" 1213 | source = "git+https://github.com/quininer/rcgen?branch=signbyparams#264208ba48a7ae8d058fdd8e0c40cf4cec9ec300" 1214 | dependencies = [ 1215 | "pem", 1216 | "ring", 1217 | "rustls-pki-types", 1218 | "time", 1219 | "x509-parser", 1220 | "yasna", 1221 | ] 1222 | 1223 | [[package]] 1224 | name = "redox_syscall" 1225 | version = "0.5.12" 1226 | source = "registry+https://github.com/rust-lang/crates.io-index" 1227 | checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" 1228 | dependencies = [ 1229 | "bitflags", 1230 | ] 1231 | 1232 | [[package]] 1233 | name = "redox_users" 1234 | version = "0.5.0" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" 1237 | dependencies = [ 1238 | "getrandom 0.2.16", 1239 | "libredox", 1240 | "thiserror 2.0.12", 1241 | ] 1242 | 1243 | [[package]] 1244 | name = "regex" 1245 | version = "1.11.1" 1246 | source = "registry+https://github.com/rust-lang/crates.io-index" 1247 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 1248 | dependencies = [ 1249 | "aho-corasick", 1250 | "memchr", 1251 | "regex-automata 0.4.9", 1252 | "regex-syntax 0.8.5", 1253 | ] 1254 | 1255 | [[package]] 1256 | name = "regex-automata" 1257 | version = "0.1.10" 1258 | source = "registry+https://github.com/rust-lang/crates.io-index" 1259 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 1260 | dependencies = [ 1261 | "regex-syntax 0.6.29", 1262 | ] 1263 | 1264 | [[package]] 1265 | name = "regex-automata" 1266 | version = "0.4.9" 1267 | source = "registry+https://github.com/rust-lang/crates.io-index" 1268 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 1269 | dependencies = [ 1270 | "aho-corasick", 1271 | "memchr", 1272 | "regex-syntax 0.8.5", 1273 | ] 1274 | 1275 | [[package]] 1276 | name = "regex-syntax" 1277 | version = "0.6.29" 1278 | source = "registry+https://github.com/rust-lang/crates.io-index" 1279 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 1280 | 1281 | [[package]] 1282 | name = "regex-syntax" 1283 | version = "0.8.5" 1284 | source = "registry+https://github.com/rust-lang/crates.io-index" 1285 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1286 | 1287 | [[package]] 1288 | name = "resolv-conf" 1289 | version = "0.7.4" 1290 | source = "registry+https://github.com/rust-lang/crates.io-index" 1291 | checksum = "95325155c684b1c89f7765e30bc1c42e4a6da51ca513615660cb8a62ef9a88e3" 1292 | 1293 | [[package]] 1294 | name = "ring" 1295 | version = "0.17.14" 1296 | source = "registry+https://github.com/rust-lang/crates.io-index" 1297 | checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" 1298 | dependencies = [ 1299 | "cc", 1300 | "cfg-if", 1301 | "getrandom 0.2.16", 1302 | "libc", 1303 | "untrusted", 1304 | "windows-sys 0.52.0", 1305 | ] 1306 | 1307 | [[package]] 1308 | name = "rust-fuzzy-search" 1309 | version = "0.1.1" 1310 | source = "registry+https://github.com/rust-lang/crates.io-index" 1311 | checksum = "a157657054ffe556d8858504af8a672a054a6e0bd9e8ee531059100c0fa11bb2" 1312 | 1313 | [[package]] 1314 | name = "rustc-demangle" 1315 | version = "0.1.24" 1316 | source = "registry+https://github.com/rust-lang/crates.io-index" 1317 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1318 | 1319 | [[package]] 1320 | name = "rustc_version" 1321 | version = "0.4.1" 1322 | source = "registry+https://github.com/rust-lang/crates.io-index" 1323 | checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" 1324 | dependencies = [ 1325 | "semver", 1326 | ] 1327 | 1328 | [[package]] 1329 | name = "rusticata-macros" 1330 | version = "4.1.0" 1331 | source = "registry+https://github.com/rust-lang/crates.io-index" 1332 | checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" 1333 | dependencies = [ 1334 | "nom", 1335 | ] 1336 | 1337 | [[package]] 1338 | name = "rustls" 1339 | version = "0.23.27" 1340 | source = "registry+https://github.com/rust-lang/crates.io-index" 1341 | checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" 1342 | dependencies = [ 1343 | "log", 1344 | "once_cell", 1345 | "ring", 1346 | "rustls-pki-types", 1347 | "rustls-webpki", 1348 | "subtle", 1349 | "zeroize", 1350 | ] 1351 | 1352 | [[package]] 1353 | name = "rustls-pki-types" 1354 | version = "1.12.0" 1355 | source = "registry+https://github.com/rust-lang/crates.io-index" 1356 | checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" 1357 | dependencies = [ 1358 | "zeroize", 1359 | ] 1360 | 1361 | [[package]] 1362 | name = "rustls-webpki" 1363 | version = "0.103.3" 1364 | source = "registry+https://github.com/rust-lang/crates.io-index" 1365 | checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" 1366 | dependencies = [ 1367 | "ring", 1368 | "rustls-pki-types", 1369 | "untrusted", 1370 | ] 1371 | 1372 | [[package]] 1373 | name = "rustversion" 1374 | version = "1.0.20" 1375 | source = "registry+https://github.com/rust-lang/crates.io-index" 1376 | checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" 1377 | 1378 | [[package]] 1379 | name = "ruzstd" 1380 | version = "0.8.1" 1381 | source = "registry+https://github.com/rust-lang/crates.io-index" 1382 | checksum = "3640bec8aad418d7d03c72ea2de10d5c646a598f9883c7babc160d91e3c1b26c" 1383 | dependencies = [ 1384 | "twox-hash", 1385 | ] 1386 | 1387 | [[package]] 1388 | name = "scoped-tls" 1389 | version = "1.0.1" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" 1392 | 1393 | [[package]] 1394 | name = "scopeguard" 1395 | version = "1.2.0" 1396 | source = "registry+https://github.com/rust-lang/crates.io-index" 1397 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1398 | 1399 | [[package]] 1400 | name = "semver" 1401 | version = "1.0.26" 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" 1403 | checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" 1404 | 1405 | [[package]] 1406 | name = "serde" 1407 | version = "1.0.219" 1408 | source = "registry+https://github.com/rust-lang/crates.io-index" 1409 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 1410 | dependencies = [ 1411 | "serde_derive", 1412 | ] 1413 | 1414 | [[package]] 1415 | name = "serde_derive" 1416 | version = "1.0.219" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 1419 | dependencies = [ 1420 | "proc-macro2", 1421 | "quote", 1422 | "syn 2.0.101", 1423 | ] 1424 | 1425 | [[package]] 1426 | name = "serde_spanned" 1427 | version = "0.6.8" 1428 | source = "registry+https://github.com/rust-lang/crates.io-index" 1429 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 1430 | dependencies = [ 1431 | "serde", 1432 | ] 1433 | 1434 | [[package]] 1435 | name = "sharded-slab" 1436 | version = "0.1.7" 1437 | source = "registry+https://github.com/rust-lang/crates.io-index" 1438 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 1439 | dependencies = [ 1440 | "lazy_static", 1441 | ] 1442 | 1443 | [[package]] 1444 | name = "shlex" 1445 | version = "1.3.0" 1446 | source = "registry+https://github.com/rust-lang/crates.io-index" 1447 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1448 | 1449 | [[package]] 1450 | name = "signal-hook-registry" 1451 | version = "1.4.5" 1452 | source = "registry+https://github.com/rust-lang/crates.io-index" 1453 | checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" 1454 | dependencies = [ 1455 | "libc", 1456 | ] 1457 | 1458 | [[package]] 1459 | name = "simd-adler32" 1460 | version = "0.3.7" 1461 | source = "registry+https://github.com/rust-lang/crates.io-index" 1462 | checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" 1463 | 1464 | [[package]] 1465 | name = "slab" 1466 | version = "0.4.9" 1467 | source = "registry+https://github.com/rust-lang/crates.io-index" 1468 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1469 | dependencies = [ 1470 | "autocfg", 1471 | ] 1472 | 1473 | [[package]] 1474 | name = "smallvec" 1475 | version = "1.15.0" 1476 | source = "registry+https://github.com/rust-lang/crates.io-index" 1477 | checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" 1478 | 1479 | [[package]] 1480 | name = "socket2" 1481 | version = "0.5.9" 1482 | source = "registry+https://github.com/rust-lang/crates.io-index" 1483 | checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" 1484 | dependencies = [ 1485 | "libc", 1486 | "windows-sys 0.52.0", 1487 | ] 1488 | 1489 | [[package]] 1490 | name = "stable_deref_trait" 1491 | version = "1.2.0" 1492 | source = "registry+https://github.com/rust-lang/crates.io-index" 1493 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1494 | 1495 | [[package]] 1496 | name = "subtle" 1497 | version = "2.6.1" 1498 | source = "registry+https://github.com/rust-lang/crates.io-index" 1499 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1500 | 1501 | [[package]] 1502 | name = "syn" 1503 | version = "1.0.109" 1504 | source = "registry+https://github.com/rust-lang/crates.io-index" 1505 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1506 | dependencies = [ 1507 | "proc-macro2", 1508 | "quote", 1509 | "unicode-ident", 1510 | ] 1511 | 1512 | [[package]] 1513 | name = "syn" 1514 | version = "2.0.101" 1515 | source = "registry+https://github.com/rust-lang/crates.io-index" 1516 | checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" 1517 | dependencies = [ 1518 | "proc-macro2", 1519 | "quote", 1520 | "unicode-ident", 1521 | ] 1522 | 1523 | [[package]] 1524 | name = "synstructure" 1525 | version = "0.13.2" 1526 | source = "registry+https://github.com/rust-lang/crates.io-index" 1527 | checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" 1528 | dependencies = [ 1529 | "proc-macro2", 1530 | "quote", 1531 | "syn 2.0.101", 1532 | ] 1533 | 1534 | [[package]] 1535 | name = "tagptr" 1536 | version = "0.2.0" 1537 | source = "registry+https://github.com/rust-lang/crates.io-index" 1538 | checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" 1539 | 1540 | [[package]] 1541 | name = "thiserror" 1542 | version = "1.0.69" 1543 | source = "registry+https://github.com/rust-lang/crates.io-index" 1544 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1545 | dependencies = [ 1546 | "thiserror-impl 1.0.69", 1547 | ] 1548 | 1549 | [[package]] 1550 | name = "thiserror" 1551 | version = "2.0.12" 1552 | source = "registry+https://github.com/rust-lang/crates.io-index" 1553 | checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" 1554 | dependencies = [ 1555 | "thiserror-impl 2.0.12", 1556 | ] 1557 | 1558 | [[package]] 1559 | name = "thiserror-impl" 1560 | version = "1.0.69" 1561 | source = "registry+https://github.com/rust-lang/crates.io-index" 1562 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 1563 | dependencies = [ 1564 | "proc-macro2", 1565 | "quote", 1566 | "syn 2.0.101", 1567 | ] 1568 | 1569 | [[package]] 1570 | name = "thiserror-impl" 1571 | version = "2.0.12" 1572 | source = "registry+https://github.com/rust-lang/crates.io-index" 1573 | checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" 1574 | dependencies = [ 1575 | "proc-macro2", 1576 | "quote", 1577 | "syn 2.0.101", 1578 | ] 1579 | 1580 | [[package]] 1581 | name = "thread_local" 1582 | version = "1.1.8" 1583 | source = "registry+https://github.com/rust-lang/crates.io-index" 1584 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 1585 | dependencies = [ 1586 | "cfg-if", 1587 | "once_cell", 1588 | ] 1589 | 1590 | [[package]] 1591 | name = "time" 1592 | version = "0.3.41" 1593 | source = "registry+https://github.com/rust-lang/crates.io-index" 1594 | checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" 1595 | dependencies = [ 1596 | "deranged", 1597 | "itoa", 1598 | "num-conv", 1599 | "powerfmt", 1600 | "serde", 1601 | "time-core", 1602 | "time-macros", 1603 | ] 1604 | 1605 | [[package]] 1606 | name = "time-core" 1607 | version = "0.1.4" 1608 | source = "registry+https://github.com/rust-lang/crates.io-index" 1609 | checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" 1610 | 1611 | [[package]] 1612 | name = "time-macros" 1613 | version = "0.2.22" 1614 | source = "registry+https://github.com/rust-lang/crates.io-index" 1615 | checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" 1616 | dependencies = [ 1617 | "num-conv", 1618 | "time-core", 1619 | ] 1620 | 1621 | [[package]] 1622 | name = "tinystr" 1623 | version = "0.8.1" 1624 | source = "registry+https://github.com/rust-lang/crates.io-index" 1625 | checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" 1626 | dependencies = [ 1627 | "displaydoc", 1628 | "zerovec", 1629 | ] 1630 | 1631 | [[package]] 1632 | name = "tinyvec" 1633 | version = "1.9.0" 1634 | source = "registry+https://github.com/rust-lang/crates.io-index" 1635 | checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" 1636 | dependencies = [ 1637 | "tinyvec_macros", 1638 | ] 1639 | 1640 | [[package]] 1641 | name = "tinyvec_macros" 1642 | version = "0.1.1" 1643 | source = "registry+https://github.com/rust-lang/crates.io-index" 1644 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 1645 | 1646 | [[package]] 1647 | name = "tokio" 1648 | version = "1.45.0" 1649 | source = "registry+https://github.com/rust-lang/crates.io-index" 1650 | checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" 1651 | dependencies = [ 1652 | "backtrace", 1653 | "bytes", 1654 | "libc", 1655 | "mio", 1656 | "parking_lot", 1657 | "pin-project-lite", 1658 | "signal-hook-registry", 1659 | "socket2", 1660 | "tokio-macros", 1661 | "windows-sys 0.52.0", 1662 | ] 1663 | 1664 | [[package]] 1665 | name = "tokio-macros" 1666 | version = "2.5.0" 1667 | source = "registry+https://github.com/rust-lang/crates.io-index" 1668 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 1669 | dependencies = [ 1670 | "proc-macro2", 1671 | "quote", 1672 | "syn 2.0.101", 1673 | ] 1674 | 1675 | [[package]] 1676 | name = "tokio-rustls" 1677 | version = "0.26.2" 1678 | source = "registry+https://github.com/rust-lang/crates.io-index" 1679 | checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" 1680 | dependencies = [ 1681 | "rustls", 1682 | "tokio", 1683 | ] 1684 | 1685 | [[package]] 1686 | name = "tokio-util" 1687 | version = "0.7.15" 1688 | source = "registry+https://github.com/rust-lang/crates.io-index" 1689 | checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" 1690 | dependencies = [ 1691 | "bytes", 1692 | "futures-core", 1693 | "futures-sink", 1694 | "pin-project-lite", 1695 | "tokio", 1696 | ] 1697 | 1698 | [[package]] 1699 | name = "toml" 1700 | version = "0.8.22" 1701 | source = "registry+https://github.com/rust-lang/crates.io-index" 1702 | checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" 1703 | dependencies = [ 1704 | "serde", 1705 | "serde_spanned", 1706 | "toml_datetime", 1707 | "toml_edit", 1708 | ] 1709 | 1710 | [[package]] 1711 | name = "toml_datetime" 1712 | version = "0.6.9" 1713 | source = "registry+https://github.com/rust-lang/crates.io-index" 1714 | checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" 1715 | dependencies = [ 1716 | "serde", 1717 | ] 1718 | 1719 | [[package]] 1720 | name = "toml_edit" 1721 | version = "0.22.26" 1722 | source = "registry+https://github.com/rust-lang/crates.io-index" 1723 | checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" 1724 | dependencies = [ 1725 | "indexmap", 1726 | "serde", 1727 | "serde_spanned", 1728 | "toml_datetime", 1729 | "toml_write", 1730 | "winnow", 1731 | ] 1732 | 1733 | [[package]] 1734 | name = "toml_write" 1735 | version = "0.1.1" 1736 | source = "registry+https://github.com/rust-lang/crates.io-index" 1737 | checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" 1738 | 1739 | [[package]] 1740 | name = "tower-happy-eyeballs" 1741 | version = "0.1.0" 1742 | source = "git+https://github.com/quininer/tower-happy-eyeballs#0ab017d8bc97e965f47f88fa7fd8f3b11faab4e4" 1743 | dependencies = [ 1744 | "futures-core", 1745 | "futures-util", 1746 | "pin-project-lite", 1747 | "tokio", 1748 | "tower-layer", 1749 | "tower-service", 1750 | ] 1751 | 1752 | [[package]] 1753 | name = "tower-layer" 1754 | version = "0.3.3" 1755 | source = "registry+https://github.com/rust-lang/crates.io-index" 1756 | checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 1757 | 1758 | [[package]] 1759 | name = "tower-service" 1760 | version = "0.3.3" 1761 | source = "registry+https://github.com/rust-lang/crates.io-index" 1762 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 1763 | 1764 | [[package]] 1765 | name = "tower-util" 1766 | version = "0.3.1" 1767 | source = "registry+https://github.com/rust-lang/crates.io-index" 1768 | checksum = "d1093c19826d33807c72511e68f73b4a0469a3f22c2bd5f7d5212178b4b89674" 1769 | dependencies = [ 1770 | "futures-core", 1771 | "futures-util", 1772 | "pin-project", 1773 | "tower-service", 1774 | ] 1775 | 1776 | [[package]] 1777 | name = "tracing" 1778 | version = "0.1.41" 1779 | source = "registry+https://github.com/rust-lang/crates.io-index" 1780 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 1781 | dependencies = [ 1782 | "pin-project-lite", 1783 | "tracing-core", 1784 | ] 1785 | 1786 | [[package]] 1787 | name = "tracing-core" 1788 | version = "0.1.33" 1789 | source = "registry+https://github.com/rust-lang/crates.io-index" 1790 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 1791 | dependencies = [ 1792 | "once_cell", 1793 | "valuable", 1794 | ] 1795 | 1796 | [[package]] 1797 | name = "tracing-log" 1798 | version = "0.2.0" 1799 | source = "registry+https://github.com/rust-lang/crates.io-index" 1800 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 1801 | dependencies = [ 1802 | "log", 1803 | "once_cell", 1804 | "tracing-core", 1805 | ] 1806 | 1807 | [[package]] 1808 | name = "tracing-subscriber" 1809 | version = "0.3.19" 1810 | source = "registry+https://github.com/rust-lang/crates.io-index" 1811 | checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" 1812 | dependencies = [ 1813 | "matchers", 1814 | "nu-ansi-term", 1815 | "once_cell", 1816 | "regex", 1817 | "sharded-slab", 1818 | "smallvec", 1819 | "thread_local", 1820 | "tracing", 1821 | "tracing-core", 1822 | "tracing-log", 1823 | ] 1824 | 1825 | [[package]] 1826 | name = "try-lock" 1827 | version = "0.2.5" 1828 | source = "registry+https://github.com/rust-lang/crates.io-index" 1829 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1830 | 1831 | [[package]] 1832 | name = "twox-hash" 1833 | version = "2.1.0" 1834 | source = "registry+https://github.com/rust-lang/crates.io-index" 1835 | checksum = "e7b17f197b3050ba473acf9181f7b1d3b66d1cf7356c6cc57886662276e65908" 1836 | 1837 | [[package]] 1838 | name = "unicode-ident" 1839 | version = "1.0.18" 1840 | source = "registry+https://github.com/rust-lang/crates.io-index" 1841 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 1842 | 1843 | [[package]] 1844 | name = "untrusted" 1845 | version = "0.9.0" 1846 | source = "registry+https://github.com/rust-lang/crates.io-index" 1847 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1848 | 1849 | [[package]] 1850 | name = "url" 1851 | version = "2.5.4" 1852 | source = "registry+https://github.com/rust-lang/crates.io-index" 1853 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 1854 | dependencies = [ 1855 | "form_urlencoded", 1856 | "idna", 1857 | "percent-encoding", 1858 | ] 1859 | 1860 | [[package]] 1861 | name = "utf8_iter" 1862 | version = "1.0.4" 1863 | source = "registry+https://github.com/rust-lang/crates.io-index" 1864 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1865 | 1866 | [[package]] 1867 | name = "uuid" 1868 | version = "1.16.0" 1869 | source = "registry+https://github.com/rust-lang/crates.io-index" 1870 | checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" 1871 | dependencies = [ 1872 | "getrandom 0.3.3", 1873 | ] 1874 | 1875 | [[package]] 1876 | name = "valuable" 1877 | version = "0.1.1" 1878 | source = "registry+https://github.com/rust-lang/crates.io-index" 1879 | checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 1880 | 1881 | [[package]] 1882 | name = "want" 1883 | version = "0.3.1" 1884 | source = "registry+https://github.com/rust-lang/crates.io-index" 1885 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1886 | dependencies = [ 1887 | "try-lock", 1888 | ] 1889 | 1890 | [[package]] 1891 | name = "wasi" 1892 | version = "0.11.0+wasi-snapshot-preview1" 1893 | source = "registry+https://github.com/rust-lang/crates.io-index" 1894 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1895 | 1896 | [[package]] 1897 | name = "wasi" 1898 | version = "0.14.2+wasi-0.2.4" 1899 | source = "registry+https://github.com/rust-lang/crates.io-index" 1900 | checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" 1901 | dependencies = [ 1902 | "wit-bindgen-rt", 1903 | ] 1904 | 1905 | [[package]] 1906 | name = "webpki-roots" 1907 | version = "0.26.11" 1908 | source = "registry+https://github.com/rust-lang/crates.io-index" 1909 | checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" 1910 | dependencies = [ 1911 | "webpki-roots 1.0.0", 1912 | ] 1913 | 1914 | [[package]] 1915 | name = "webpki-roots" 1916 | version = "1.0.0" 1917 | source = "registry+https://github.com/rust-lang/crates.io-index" 1918 | checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" 1919 | dependencies = [ 1920 | "rustls-pki-types", 1921 | ] 1922 | 1923 | [[package]] 1924 | name = "widestring" 1925 | version = "1.2.0" 1926 | source = "registry+https://github.com/rust-lang/crates.io-index" 1927 | checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" 1928 | 1929 | [[package]] 1930 | name = "winapi" 1931 | version = "0.3.9" 1932 | source = "registry+https://github.com/rust-lang/crates.io-index" 1933 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1934 | dependencies = [ 1935 | "winapi-i686-pc-windows-gnu", 1936 | "winapi-x86_64-pc-windows-gnu", 1937 | ] 1938 | 1939 | [[package]] 1940 | name = "winapi-i686-pc-windows-gnu" 1941 | version = "0.4.0" 1942 | source = "registry+https://github.com/rust-lang/crates.io-index" 1943 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1944 | 1945 | [[package]] 1946 | name = "winapi-x86_64-pc-windows-gnu" 1947 | version = "0.4.0" 1948 | source = "registry+https://github.com/rust-lang/crates.io-index" 1949 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1950 | 1951 | [[package]] 1952 | name = "windows" 1953 | version = "0.58.0" 1954 | source = "registry+https://github.com/rust-lang/crates.io-index" 1955 | checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" 1956 | dependencies = [ 1957 | "windows-core", 1958 | "windows-targets 0.52.6", 1959 | ] 1960 | 1961 | [[package]] 1962 | name = "windows-core" 1963 | version = "0.58.0" 1964 | source = "registry+https://github.com/rust-lang/crates.io-index" 1965 | checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" 1966 | dependencies = [ 1967 | "windows-implement", 1968 | "windows-interface", 1969 | "windows-result", 1970 | "windows-strings", 1971 | "windows-targets 0.52.6", 1972 | ] 1973 | 1974 | [[package]] 1975 | name = "windows-implement" 1976 | version = "0.58.0" 1977 | source = "registry+https://github.com/rust-lang/crates.io-index" 1978 | checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" 1979 | dependencies = [ 1980 | "proc-macro2", 1981 | "quote", 1982 | "syn 2.0.101", 1983 | ] 1984 | 1985 | [[package]] 1986 | name = "windows-interface" 1987 | version = "0.58.0" 1988 | source = "registry+https://github.com/rust-lang/crates.io-index" 1989 | checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" 1990 | dependencies = [ 1991 | "proc-macro2", 1992 | "quote", 1993 | "syn 2.0.101", 1994 | ] 1995 | 1996 | [[package]] 1997 | name = "windows-result" 1998 | version = "0.2.0" 1999 | source = "registry+https://github.com/rust-lang/crates.io-index" 2000 | checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" 2001 | dependencies = [ 2002 | "windows-targets 0.52.6", 2003 | ] 2004 | 2005 | [[package]] 2006 | name = "windows-strings" 2007 | version = "0.1.0" 2008 | source = "registry+https://github.com/rust-lang/crates.io-index" 2009 | checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" 2010 | dependencies = [ 2011 | "windows-result", 2012 | "windows-targets 0.52.6", 2013 | ] 2014 | 2015 | [[package]] 2016 | name = "windows-sys" 2017 | version = "0.48.0" 2018 | source = "registry+https://github.com/rust-lang/crates.io-index" 2019 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 2020 | dependencies = [ 2021 | "windows-targets 0.48.5", 2022 | ] 2023 | 2024 | [[package]] 2025 | name = "windows-sys" 2026 | version = "0.52.0" 2027 | source = "registry+https://github.com/rust-lang/crates.io-index" 2028 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2029 | dependencies = [ 2030 | "windows-targets 0.52.6", 2031 | ] 2032 | 2033 | [[package]] 2034 | name = "windows-sys" 2035 | version = "0.59.0" 2036 | source = "registry+https://github.com/rust-lang/crates.io-index" 2037 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 2038 | dependencies = [ 2039 | "windows-targets 0.52.6", 2040 | ] 2041 | 2042 | [[package]] 2043 | name = "windows-targets" 2044 | version = "0.48.5" 2045 | source = "registry+https://github.com/rust-lang/crates.io-index" 2046 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 2047 | dependencies = [ 2048 | "windows_aarch64_gnullvm 0.48.5", 2049 | "windows_aarch64_msvc 0.48.5", 2050 | "windows_i686_gnu 0.48.5", 2051 | "windows_i686_msvc 0.48.5", 2052 | "windows_x86_64_gnu 0.48.5", 2053 | "windows_x86_64_gnullvm 0.48.5", 2054 | "windows_x86_64_msvc 0.48.5", 2055 | ] 2056 | 2057 | [[package]] 2058 | name = "windows-targets" 2059 | version = "0.52.6" 2060 | source = "registry+https://github.com/rust-lang/crates.io-index" 2061 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2062 | dependencies = [ 2063 | "windows_aarch64_gnullvm 0.52.6", 2064 | "windows_aarch64_msvc 0.52.6", 2065 | "windows_i686_gnu 0.52.6", 2066 | "windows_i686_gnullvm 0.52.6", 2067 | "windows_i686_msvc 0.52.6", 2068 | "windows_x86_64_gnu 0.52.6", 2069 | "windows_x86_64_gnullvm 0.52.6", 2070 | "windows_x86_64_msvc 0.52.6", 2071 | ] 2072 | 2073 | [[package]] 2074 | name = "windows-targets" 2075 | version = "0.53.0" 2076 | source = "registry+https://github.com/rust-lang/crates.io-index" 2077 | checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" 2078 | dependencies = [ 2079 | "windows_aarch64_gnullvm 0.53.0", 2080 | "windows_aarch64_msvc 0.53.0", 2081 | "windows_i686_gnu 0.53.0", 2082 | "windows_i686_gnullvm 0.53.0", 2083 | "windows_i686_msvc 0.53.0", 2084 | "windows_x86_64_gnu 0.53.0", 2085 | "windows_x86_64_gnullvm 0.53.0", 2086 | "windows_x86_64_msvc 0.53.0", 2087 | ] 2088 | 2089 | [[package]] 2090 | name = "windows_aarch64_gnullvm" 2091 | version = "0.48.5" 2092 | source = "registry+https://github.com/rust-lang/crates.io-index" 2093 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 2094 | 2095 | [[package]] 2096 | name = "windows_aarch64_gnullvm" 2097 | version = "0.52.6" 2098 | source = "registry+https://github.com/rust-lang/crates.io-index" 2099 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2100 | 2101 | [[package]] 2102 | name = "windows_aarch64_gnullvm" 2103 | version = "0.53.0" 2104 | source = "registry+https://github.com/rust-lang/crates.io-index" 2105 | checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" 2106 | 2107 | [[package]] 2108 | name = "windows_aarch64_msvc" 2109 | version = "0.48.5" 2110 | source = "registry+https://github.com/rust-lang/crates.io-index" 2111 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 2112 | 2113 | [[package]] 2114 | name = "windows_aarch64_msvc" 2115 | version = "0.52.6" 2116 | source = "registry+https://github.com/rust-lang/crates.io-index" 2117 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2118 | 2119 | [[package]] 2120 | name = "windows_aarch64_msvc" 2121 | version = "0.53.0" 2122 | source = "registry+https://github.com/rust-lang/crates.io-index" 2123 | checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" 2124 | 2125 | [[package]] 2126 | name = "windows_i686_gnu" 2127 | version = "0.48.5" 2128 | source = "registry+https://github.com/rust-lang/crates.io-index" 2129 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 2130 | 2131 | [[package]] 2132 | name = "windows_i686_gnu" 2133 | version = "0.52.6" 2134 | source = "registry+https://github.com/rust-lang/crates.io-index" 2135 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2136 | 2137 | [[package]] 2138 | name = "windows_i686_gnu" 2139 | version = "0.53.0" 2140 | source = "registry+https://github.com/rust-lang/crates.io-index" 2141 | checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" 2142 | 2143 | [[package]] 2144 | name = "windows_i686_gnullvm" 2145 | version = "0.52.6" 2146 | source = "registry+https://github.com/rust-lang/crates.io-index" 2147 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2148 | 2149 | [[package]] 2150 | name = "windows_i686_gnullvm" 2151 | version = "0.53.0" 2152 | source = "registry+https://github.com/rust-lang/crates.io-index" 2153 | checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" 2154 | 2155 | [[package]] 2156 | name = "windows_i686_msvc" 2157 | version = "0.48.5" 2158 | source = "registry+https://github.com/rust-lang/crates.io-index" 2159 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 2160 | 2161 | [[package]] 2162 | name = "windows_i686_msvc" 2163 | version = "0.52.6" 2164 | source = "registry+https://github.com/rust-lang/crates.io-index" 2165 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2166 | 2167 | [[package]] 2168 | name = "windows_i686_msvc" 2169 | version = "0.53.0" 2170 | source = "registry+https://github.com/rust-lang/crates.io-index" 2171 | checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" 2172 | 2173 | [[package]] 2174 | name = "windows_x86_64_gnu" 2175 | version = "0.48.5" 2176 | source = "registry+https://github.com/rust-lang/crates.io-index" 2177 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 2178 | 2179 | [[package]] 2180 | name = "windows_x86_64_gnu" 2181 | version = "0.52.6" 2182 | source = "registry+https://github.com/rust-lang/crates.io-index" 2183 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2184 | 2185 | [[package]] 2186 | name = "windows_x86_64_gnu" 2187 | version = "0.53.0" 2188 | source = "registry+https://github.com/rust-lang/crates.io-index" 2189 | checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" 2190 | 2191 | [[package]] 2192 | name = "windows_x86_64_gnullvm" 2193 | version = "0.48.5" 2194 | source = "registry+https://github.com/rust-lang/crates.io-index" 2195 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 2196 | 2197 | [[package]] 2198 | name = "windows_x86_64_gnullvm" 2199 | version = "0.52.6" 2200 | source = "registry+https://github.com/rust-lang/crates.io-index" 2201 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2202 | 2203 | [[package]] 2204 | name = "windows_x86_64_gnullvm" 2205 | version = "0.53.0" 2206 | source = "registry+https://github.com/rust-lang/crates.io-index" 2207 | checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" 2208 | 2209 | [[package]] 2210 | name = "windows_x86_64_msvc" 2211 | version = "0.48.5" 2212 | source = "registry+https://github.com/rust-lang/crates.io-index" 2213 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 2214 | 2215 | [[package]] 2216 | name = "windows_x86_64_msvc" 2217 | version = "0.52.6" 2218 | source = "registry+https://github.com/rust-lang/crates.io-index" 2219 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2220 | 2221 | [[package]] 2222 | name = "windows_x86_64_msvc" 2223 | version = "0.53.0" 2224 | source = "registry+https://github.com/rust-lang/crates.io-index" 2225 | checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" 2226 | 2227 | [[package]] 2228 | name = "winnow" 2229 | version = "0.7.10" 2230 | source = "registry+https://github.com/rust-lang/crates.io-index" 2231 | checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" 2232 | dependencies = [ 2233 | "memchr", 2234 | ] 2235 | 2236 | [[package]] 2237 | name = "winreg" 2238 | version = "0.50.0" 2239 | source = "registry+https://github.com/rust-lang/crates.io-index" 2240 | checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" 2241 | dependencies = [ 2242 | "cfg-if", 2243 | "windows-sys 0.48.0", 2244 | ] 2245 | 2246 | [[package]] 2247 | name = "wit-bindgen-rt" 2248 | version = "0.39.0" 2249 | source = "registry+https://github.com/rust-lang/crates.io-index" 2250 | checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" 2251 | dependencies = [ 2252 | "bitflags", 2253 | ] 2254 | 2255 | [[package]] 2256 | name = "writeable" 2257 | version = "0.6.1" 2258 | source = "registry+https://github.com/rust-lang/crates.io-index" 2259 | checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" 2260 | 2261 | [[package]] 2262 | name = "x509-parser" 2263 | version = "0.16.0" 2264 | source = "registry+https://github.com/rust-lang/crates.io-index" 2265 | checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" 2266 | dependencies = [ 2267 | "asn1-rs", 2268 | "data-encoding", 2269 | "der-parser", 2270 | "lazy_static", 2271 | "nom", 2272 | "oid-registry", 2273 | "ring", 2274 | "rusticata-macros", 2275 | "thiserror 1.0.69", 2276 | "time", 2277 | ] 2278 | 2279 | [[package]] 2280 | name = "yasna" 2281 | version = "0.5.2" 2282 | source = "registry+https://github.com/rust-lang/crates.io-index" 2283 | checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" 2284 | dependencies = [ 2285 | "time", 2286 | ] 2287 | 2288 | [[package]] 2289 | name = "yoke" 2290 | version = "0.8.0" 2291 | source = "registry+https://github.com/rust-lang/crates.io-index" 2292 | checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" 2293 | dependencies = [ 2294 | "serde", 2295 | "stable_deref_trait", 2296 | "yoke-derive", 2297 | "zerofrom", 2298 | ] 2299 | 2300 | [[package]] 2301 | name = "yoke-derive" 2302 | version = "0.8.0" 2303 | source = "registry+https://github.com/rust-lang/crates.io-index" 2304 | checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" 2305 | dependencies = [ 2306 | "proc-macro2", 2307 | "quote", 2308 | "syn 2.0.101", 2309 | "synstructure", 2310 | ] 2311 | 2312 | [[package]] 2313 | name = "zerocopy" 2314 | version = "0.8.25" 2315 | source = "registry+https://github.com/rust-lang/crates.io-index" 2316 | checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" 2317 | dependencies = [ 2318 | "zerocopy-derive", 2319 | ] 2320 | 2321 | [[package]] 2322 | name = "zerocopy-derive" 2323 | version = "0.8.25" 2324 | source = "registry+https://github.com/rust-lang/crates.io-index" 2325 | checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" 2326 | dependencies = [ 2327 | "proc-macro2", 2328 | "quote", 2329 | "syn 2.0.101", 2330 | ] 2331 | 2332 | [[package]] 2333 | name = "zerofrom" 2334 | version = "0.1.6" 2335 | source = "registry+https://github.com/rust-lang/crates.io-index" 2336 | checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 2337 | dependencies = [ 2338 | "zerofrom-derive", 2339 | ] 2340 | 2341 | [[package]] 2342 | name = "zerofrom-derive" 2343 | version = "0.1.6" 2344 | source = "registry+https://github.com/rust-lang/crates.io-index" 2345 | checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 2346 | dependencies = [ 2347 | "proc-macro2", 2348 | "quote", 2349 | "syn 2.0.101", 2350 | "synstructure", 2351 | ] 2352 | 2353 | [[package]] 2354 | name = "zeroize" 2355 | version = "1.8.1" 2356 | source = "registry+https://github.com/rust-lang/crates.io-index" 2357 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2358 | 2359 | [[package]] 2360 | name = "zerotrie" 2361 | version = "0.2.2" 2362 | source = "registry+https://github.com/rust-lang/crates.io-index" 2363 | checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" 2364 | dependencies = [ 2365 | "displaydoc", 2366 | "yoke", 2367 | "zerofrom", 2368 | ] 2369 | 2370 | [[package]] 2371 | name = "zerovec" 2372 | version = "0.11.2" 2373 | source = "registry+https://github.com/rust-lang/crates.io-index" 2374 | checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" 2375 | dependencies = [ 2376 | "yoke", 2377 | "zerofrom", 2378 | "zerovec-derive", 2379 | ] 2380 | 2381 | [[package]] 2382 | name = "zerovec-derive" 2383 | version = "0.11.1" 2384 | source = "registry+https://github.com/rust-lang/crates.io-index" 2385 | checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" 2386 | dependencies = [ 2387 | "proc-macro2", 2388 | "quote", 2389 | "syn 2.0.101", 2390 | ] 2391 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nosni-proxy" 3 | version = "0.4.0" 4 | authors = ["quininer "] 5 | edition = "2021" 6 | description = "No SNI" 7 | license = "CC0-1.0" 8 | 9 | [workspace] 10 | members = [ "mitmca", "hook" ] 11 | 12 | [workspace.dependencies] 13 | rcgen = { git = "https://github.com/quininer/rcgen", branch = "signbyparams" } 14 | rustls = { version = "0.23", default-features = false, features = [ "std" ] } 15 | rand = "0.9" 16 | 17 | [dependencies] 18 | once_cell = "1" 19 | anyhow = "1" 20 | futures = "0.3" 21 | tokio-rustls = { version = "0.26", default-features = false, features = [ "tls12", "ring" ] } 22 | webpki-roots = "0.26" 23 | tokio = { version = "1", features = [ "full" ] } 24 | http = "1" 25 | hyper = { version = "1", features = [ "client", "server", "http1", "http2" ] } 26 | hyper-util = { version = "0.1", features = [ "tokio", "server", "http1", "http2" ] } 27 | http-body-util = "0.1" 28 | percent-encoding = "2" 29 | fdeflate = "0.3" 30 | ruzstd = "0.8" 31 | hickory-resolver = { version = "0.25", features = [ "https-ring" ] } 32 | mitmca = { path = "mitmca" } 33 | 34 | tower-layer = "0.3" 35 | tower-util = "0.3" 36 | tower-happy-eyeballs = { git = "https://github.com/quininer/tower-happy-eyeballs" } 37 | 38 | rand = { workspace = true } 39 | rcgen = { workspace = true } 40 | 41 | argh = "0.1" 42 | serde = { version = "1", features = ["derive"] } 43 | toml = "0.8" 44 | directories = "6" 45 | 46 | [features] 47 | default = [ "dnssec" ] 48 | dnssec = [ "hickory-resolver/dnssec-ring" ] 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # No SNI 2 | 3 | All browsers send SNI, but not all websites require SNI. 4 | Removing SNI from these requests is a good way to protect privacy. 5 | 6 | ## Usage 7 | 8 | ``` 9 | $ vim .config/nosni-proxy/config.toml 10 | $ nosni-proxy 11 | ``` 12 | 13 | and set your HTTP proxy address to `127.0.0.1:1087`. 14 | 15 | ## license 16 | 17 | [CC0 1.0 Universal License](https://creativecommons.org/publicdomain/zero/1.0/) 18 | -------------------------------------------------------------------------------- /example.config.toml: -------------------------------------------------------------------------------- 1 | [mitm] 2 | bind = "127.0.0.1:1087" 3 | alpn = "h2, http%2F1.1" 4 | cert = "./ca-cert.pem" 5 | key = "./ca.pem" 6 | 7 | [fragment] 8 | bind = "127.0.0.1:1077" 9 | size = [50, 120] 10 | delay = [100, 300] 11 | 12 | [doh] 13 | addr = "127.0.0.1:443" 14 | name = "your-doh-server" 15 | sni = false 16 | dnssec = true 17 | 18 | [mapping] 19 | "your.domain" = { sni = "fake.domain", addr = "127.0.0.1" } 20 | "your2.domain" = { addr = "your3.domain", alpn = [ "http/1.1" ] } 21 | -------------------------------------------------------------------------------- /hook/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nosni-hook" 3 | version = "0.1.0" 4 | authors = ["quininer "] 5 | edition = "2021" 6 | 7 | [lib] 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | once_cell = "1" 12 | libloading = "0.8" 13 | libc = "0.2" 14 | -------------------------------------------------------------------------------- /hook/src/lib.rs: -------------------------------------------------------------------------------- 1 | use libc::{ c_int, c_long, c_void }; 2 | use libloading::{ Library, Symbol }; 3 | use once_cell::sync::Lazy; 4 | 5 | 6 | type SslCtrlSymbol<'a> = Symbol< 7 | 'a, 8 | fn(ssl: *mut c_void, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long 9 | >; 10 | 11 | static OPENSSL: Lazy = Lazy::new(|| unsafe { 12 | Library::new("/usr/lib/libssl.so").unwrap() 13 | }); 14 | static SSL_CTRL_SYMBOLS: Lazy> = Lazy::new(|| unsafe { 15 | OPENSSL.get(b"SSL_ctrl\0").unwrap() 16 | }); 17 | 18 | #[no_mangle] 19 | pub extern "C" fn SSL_ctrl(ssl: *mut c_void, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long { 20 | const SSL_CTRL_SET_TLSEXT_HOSTNAME: usize = 55; 21 | 22 | if cmd == SSL_CTRL_SET_TLSEXT_HOSTNAME as _ { 23 | 1 24 | } else { 25 | (SSL_CTRL_SYMBOLS)(ssl, cmd, larg, parg) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /mitmca/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mitmca" 3 | version = "0.1.0" 4 | authors = ["quininer "] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | thiserror = "2" 9 | psl = "2" 10 | cache_2q = "0.10" 11 | rand = { workspace = true } 12 | rustls = { workspace = true } 13 | pem = "3" 14 | rcgen = { workspace = true, features = [ "x509-parser" ] } 15 | time = "0.3" 16 | 17 | [dev-dependencies] 18 | webpki = { package = "rustls-webpki", version = "0.103", default-features = false, features = [ "ring" ] } 19 | -------------------------------------------------------------------------------- /mitmca/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryFrom; 2 | use std::borrow::Cow; 3 | use thiserror::Error; 4 | use time::{ OffsetDateTime, Duration }; 5 | use psl::{ Psl, List }; 6 | use cache_2q::Cache; 7 | 8 | 9 | pub struct Entry { 10 | kp: rcgen::KeyPair, 11 | params: rcgen::CertificateParams, 12 | skder: rustls::pki_types::PrivateKeyDer<'static> 13 | } 14 | 15 | pub struct CertStore { 16 | pub entry: Entry, 17 | cache: Cache> 18 | } 19 | 20 | #[derive(Debug, Error)] 21 | pub enum Error { 22 | #[error("pem parse error: {0}")] 23 | Pem(#[from] pem::PemError), 24 | 25 | #[error("rcgen error: {0}")] 26 | Rcgen(#[from] rcgen::Error), 27 | 28 | #[error("load certs failed")] 29 | LoadCerts(&'static str), 30 | 31 | #[error("rustls error: {0}")] 32 | Rustls(#[from] rustls::Error) 33 | } 34 | 35 | impl CertStore { 36 | pub fn get(&mut self, name: &str) -> Result { 37 | let CertStore { entry, cache } = self; 38 | 39 | let name = take_generic(name); 40 | let cert = match cache.entry(name.into_owned()) { 41 | cache_2q::Entry::Occupied(e) => e.get().clone(), 42 | cache_2q::Entry::Vacant(e) => { 43 | let cert = entry.make(e.key())?; 44 | e.insert(cert).clone() 45 | } 46 | }; 47 | 48 | let config = rustls::ServerConfig::builder() 49 | .with_no_client_auth() 50 | .with_single_cert(vec![cert], entry.skder.clone_key())?; 51 | Ok(config) 52 | } 53 | } 54 | 55 | impl From for CertStore { 56 | fn from(entry: Entry) -> CertStore { 57 | CertStore { entry, cache: Cache::new(32) } 58 | } 59 | } 60 | 61 | impl Entry { 62 | pub fn from_pem(cert_input: &str, key_input: &str) -> Result { 63 | let key_input = pem::parse(key_input)?; 64 | let skder = >::try_from(key_input.contents()) 65 | .map_err(Error::LoadCerts)? 66 | .clone_key(); 67 | let kp = rcgen::KeyPair::try_from(&skder)?; 68 | let params = rcgen::CertificateParams::from_ca_cert_pem(cert_input)?; 69 | Ok(Entry { kp, params, skder }) 70 | } 71 | 72 | pub fn make(&self, cn: &str) -> Result, Error> { 73 | thread_local!{ 74 | static TODAY: OffsetDateTime = OffsetDateTime::now_utc(); 75 | } 76 | 77 | let mut params = rcgen::CertificateParams::default(); 78 | params.subject_alt_names.push(rcgen::SanType::DnsName(cn.parse()?)); 79 | params.serial_number = Some(rand::random::().into()); 80 | params.distinguished_name.push(rcgen::DnType::OrganizationName, "MITM CA"); 81 | params.distinguished_name.push(rcgen::DnType::CommonName, cn); 82 | TODAY.with(|today| { 83 | params.not_before = *today - Duration::days(1); 84 | params.not_after = *today + Duration::weeks(1); 85 | }); 86 | 87 | let cert = params.signed_by2(&self.kp, &self.params, &self.kp)?; 88 | 89 | Ok(cert.into()) 90 | } 91 | } 92 | 93 | fn take_generic(name: &str) -> Cow<'_, str> { 94 | static LIST: List = List; 95 | 96 | if let Some(suffix) = LIST.suffix(name.as_bytes()) { 97 | let end = name.len() - suffix.as_bytes().len(); 98 | let pos = name[..end] 99 | .trim_end_matches('.') 100 | .find('.') 101 | .unwrap_or(0); 102 | 103 | let mut name2 = String::new(); 104 | if !name[..pos].is_empty() { 105 | name2.push('*'); 106 | } 107 | name2.push_str(&name[pos..]); 108 | Cow::Owned(name2) 109 | } else { 110 | Cow::Borrowed(name) 111 | } 112 | } 113 | 114 | #[test] 115 | fn test_generic() { 116 | assert_eq!(take_generic("test"), "test"); 117 | assert_eq!(take_generic("test.com"), "test.com"); 118 | assert_eq!(take_generic("a.test.com"), "*.test.com"); 119 | assert_eq!(take_generic("a.b.test.com"), "*.b.test.com"); 120 | } 121 | 122 | #[test] 123 | fn test_mitmca() { 124 | let kp = rcgen::KeyPair::generate().unwrap(); 125 | let mut params = rcgen::CertificateParams::default(); 126 | params.subject_alt_names.push(rcgen::SanType::DnsName("localhost".parse().unwrap())); 127 | params.distinguished_name.push(rcgen::DnType::OrganizationName, "MITM CA"); 128 | params.distinguished_name.push(rcgen::DnType::CommonName, "MITM CA"); 129 | params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained); 130 | let ca_cert = params.clone().self_signed(&kp).unwrap(); 131 | let skder = rustls::pki_types::PrivateKeyDer::try_from(kp.serialized_der()).unwrap(); 132 | let skder = skder.clone_key(); 133 | 134 | let entry = Entry { kp, params, skder }; 135 | 136 | let ca_cert_der = ca_cert.der(); 137 | let trust_anchor = webpki::anchor_from_trusted_cert(ca_cert_der).unwrap(); 138 | let cert = entry.make("localhost.dev").unwrap(); 139 | 140 | let end_entity_cert = webpki::EndEntityCert::try_from(&cert).unwrap(); 141 | end_entity_cert.verify_for_usage( 142 | webpki::ALL_VERIFICATION_ALGS, 143 | &[trust_anchor], 144 | &[], 145 | rustls::pki_types::UnixTime::now(), 146 | webpki::KeyUsage::server_auth(), 147 | None, 148 | None 149 | ).unwrap(); 150 | } 151 | -------------------------------------------------------------------------------- /src/check.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::io::{ self, Write }; 3 | use std::sync::Arc; 4 | use std::path::PathBuf; 5 | use std::time::Duration; 6 | use std::convert::TryFrom; 7 | use std::net::SocketAddr; 8 | use futures::future::TryFutureExt; 9 | use tokio::net::TcpStream; 10 | use tokio_rustls::{ rustls, TlsConnector }; 11 | use hyper::{ header, Uri, Method, Request }; 12 | use hyper::client::conn; 13 | use hyper_util::rt::{ TokioExecutor, TokioIo }; 14 | use http_body_util::BodyExt; 15 | use hickory_resolver::config::{ ResolverConfig, NameServerConfigGroup }; 16 | use directories::ProjectDirs; 17 | use argh::FromArgs; 18 | use anyhow::Context; 19 | use crate::config::Config; 20 | 21 | 22 | /// No SNI checker 23 | #[derive(FromArgs)] 24 | #[argh(subcommand, name = "check")] 25 | pub struct Options { 26 | /// check target 27 | #[argh(positional)] 28 | target: Uri, 29 | 30 | /// specify addr 31 | #[argh(option, short = 'a')] 32 | addr: Option, 33 | 34 | /// specify user agent 35 | #[argh(option, short = 'u')] 36 | user_agent: Option, 37 | 38 | /// custom SNI, default empty 39 | #[argh(option, short = 's')] 40 | sni: Option, 41 | 42 | /// config path 43 | #[argh(option, short = 'c')] 44 | config: Option, 45 | 46 | /// force no sni 47 | #[argh(switch)] 48 | force_no_sni: bool, 49 | 50 | /// show body 51 | #[argh(switch)] 52 | show_body: bool 53 | } 54 | 55 | impl Options { 56 | pub async fn exec(self) -> anyhow::Result<()> { 57 | let resolver_fut = async { 58 | let config_path = self.config 59 | .clone() 60 | .or_else(|| { 61 | ProjectDirs::from("", "", env!("CARGO_PKG_NAME")) 62 | .map(|dir| dir.config_dir().join("config.toml")) 63 | }) 64 | .context("missing config")?; 65 | let config: Config = toml::from_str(&fs::read_to_string(&config_path)?)?; 66 | 67 | if let Some(ref doh) = config.doh { 68 | use tokio_rustls::rustls; 69 | 70 | let mut root_cert_store = rustls::RootCertStore::empty(); 71 | root_cert_store.roots = webpki_roots::TLS_SERVER_ROOTS.into(); 72 | let mut tls_config = rustls::ClientConfig::builder() 73 | .with_root_certificates(root_cert_store) 74 | .with_no_client_auth(); 75 | tls_config.alpn_protocols = vec![b"h2".to_vec()]; 76 | tls_config.enable_sni = doh.sni; 77 | tls_config.enable_early_data = true; 78 | 79 | let server = NameServerConfigGroup::from_ips_https( 80 | &[doh.addr.ip()], doh.addr.port(), 81 | doh.name.clone(), false 82 | ); 83 | let dns_config = ResolverConfig::from_parts(None, Vec::new(), server); 84 | 85 | let mut builder = hickory_resolver::Resolver::builder_with_config( 86 | dns_config, 87 | hickory_resolver::name_server::TokioConnectionProvider::default() 88 | ); 89 | builder.options_mut().tls_config = tls_config; 90 | builder.options_mut().timeout = Duration::from_secs(2); 91 | builder.options_mut().attempts = 1; 92 | 93 | #[cfg(feature = "dnssec")] { 94 | builder.options_mut().validate = doh.dnssec; 95 | } 96 | 97 | Ok(builder.build()) as anyhow::Result<_> 98 | } else { 99 | Ok(hickory_resolver::TokioResolver::builder_tokio()?.build()) 100 | } 101 | }; 102 | 103 | let addr = if let Some(addr) = self.addr { 104 | addr 105 | } else { 106 | let resolver = resolver_fut.await?; 107 | let host = self.target.host().context("not found host")?; 108 | let ips = resolver.lookup_ip(host).await?; 109 | let ips = ips.iter().collect::>(); 110 | 111 | println!("ips: {:?}", ips); 112 | 113 | let ip = ips.first().cloned().context("not found addr")?; 114 | (ip, self.target.port_u16().unwrap_or(443)).into() 115 | }; 116 | let sni = self.sni 117 | .as_deref() 118 | .or_else(|| self.target.host()) 119 | .and_then(|host| rustls::pki_types::ServerName::try_from(host).ok()) 120 | .map(|host| host.to_owned()) 121 | .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "invalid dnsname"))?; 122 | 123 | let mut root_cert_store = rustls::RootCertStore::empty(); 124 | root_cert_store.roots = webpki_roots::TLS_SERVER_ROOTS.into(); 125 | let mut tls_config = rustls::ClientConfig::builder() 126 | .with_root_certificates(root_cert_store) 127 | .with_no_client_auth(); 128 | tls_config.alpn_protocols = vec!["h2".into(), "http/1.1".into()]; 129 | tls_config.enable_sni = if self.force_no_sni { 130 | false 131 | } else { 132 | self.sni.is_some() 133 | }; 134 | 135 | let connector = TlsConnector::from(Arc::new(tls_config)); 136 | 137 | let mut request = Request::new(String::new()); 138 | *request.method_mut() = Method::GET; 139 | *request.uri_mut() = self.target.clone(); 140 | if let Some(ua) = self.user_agent.clone() { 141 | request.headers_mut() 142 | .insert(header::USER_AGENT, ua); 143 | } 144 | 145 | let stream = TcpStream::connect(&addr).await?; 146 | let stream = connector.connect(sni, stream).await?; 147 | let stream = TokioIo::new(stream); 148 | 149 | let builder = conn::http2::Builder::new(TokioExecutor::new()); 150 | let (mut sender, conn) = builder.handshake::<_, String>(stream) 151 | .await 152 | .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?; 153 | 154 | tokio::spawn(conn.map_err(|err| eprintln!("conn error: {:?}", err))); 155 | 156 | let response = sender.send_request(request) 157 | .map_err(|err| io::Error::new(io::ErrorKind::Other, err)) 158 | .await?; 159 | 160 | let (parts, mut body) = response.into_parts(); 161 | println!("parts:\n {:#?}", parts); 162 | 163 | if self.show_body { 164 | let stdout = io::stdout(); 165 | let mut stdout = stdout.lock(); 166 | 167 | while let Some(data) = body.frame().await { 168 | let data = data?; 169 | if let Some(data) = data.data_ref() { 170 | stdout.write_all(data)?; 171 | } 172 | } 173 | 174 | stdout.flush()?; 175 | } 176 | 177 | Ok(()) 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | use std::net::{ SocketAddr, IpAddr }; 3 | use std::collections::HashMap; 4 | use serde::Deserialize; 5 | 6 | 7 | #[derive(Deserialize)] 8 | pub struct Config { 9 | pub mitm: Option, 10 | pub fragment: Option, 11 | pub doh: Option, 12 | pub localdoh: Option, 13 | pub mapping: HashMap, 14 | } 15 | 16 | #[derive(Deserialize, Clone)] 17 | pub struct Fragment { 18 | pub bind: SocketAddr, 19 | pub size: (u16, u16), 20 | pub delay: Option<(u64, u64)>, 21 | } 22 | 23 | #[derive(Deserialize, Clone)] 24 | pub struct LocalDoh { 25 | pub name: String, 26 | pub bind: SocketAddr 27 | } 28 | 29 | #[derive(Deserialize)] 30 | pub struct Mitm { 31 | pub bind: SocketAddr, 32 | pub alpn: Vec, 33 | pub cert: PathBuf, 34 | pub key: PathBuf, 35 | } 36 | 37 | #[derive(Deserialize)] 38 | pub struct Rule { 39 | #[serde(default)] 40 | pub alpn: Vec, 41 | pub sni: Option, 42 | pub addr: Option>, 43 | #[serde(default, rename = "force-no-sni")] 44 | pub force_no_sni: bool, 45 | } 46 | 47 | #[derive(Deserialize)] 48 | #[serde(untagged)] 49 | pub enum StrOrList { 50 | Str(String), 51 | List(Vec) 52 | } 53 | 54 | #[derive(Deserialize)] 55 | pub struct Doh { 56 | pub addr: SocketAddr, 57 | pub name: String, 58 | 59 | #[serde(default)] 60 | pub sni: bool, 61 | 62 | #[cfg_attr(not(feature = "dnssec"), allow(dead_code))] 63 | #[serde(default)] 64 | pub dnssec: bool 65 | } 66 | -------------------------------------------------------------------------------- /src/gen.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::io::{ self, BufRead, Write }; 3 | use argh::FromArgs; 4 | use rand::{ TryRngCore, rngs::OsRng }; 5 | 6 | 7 | /// local CA certs generator 8 | #[derive(FromArgs)] 9 | #[argh(subcommand, name = "gen")] 10 | pub struct Options { 11 | /// crets file prefix 12 | #[argh(positional)] 13 | name: String 14 | } 15 | 16 | impl Options { 17 | pub fn exec(self) -> anyhow::Result<()> { 18 | let mut rng = OsRng; 19 | let name = self.name.as_str(); 20 | 21 | let stdin = io::stdin(); 22 | let mut stdin = stdin.lock(); 23 | let stdout = io::stdout(); 24 | let mut stdout = stdout.lock(); 25 | let mut line = String::new(); 26 | 27 | macro_rules! readline { 28 | ( $prompt:expr ) => {{ 29 | line.clear(); 30 | write!(&mut stdout, $prompt)?; 31 | stdout.flush()?; 32 | stdin.read_line(&mut line)?; 33 | line.as_str() 34 | }} 35 | } 36 | 37 | let input = readline!("subject alt names> "); 38 | let mut list = Vec::new(); 39 | for san in input.split(',') { 40 | let san = san.parse()?; 41 | list.push(rcgen::SanType::DnsName(san)); 42 | } 43 | let on = readline!("organization name> ").to_owned(); 44 | let cn = readline!("common name> ").to_owned(); 45 | 46 | let mut params = rcgen::CertificateParams::default(); 47 | params.serial_number = Some(rng.try_next_u64().unwrap().into()); 48 | params.subject_alt_names = list; 49 | params.distinguished_name.push(rcgen::DnType::OrganizationName, on); 50 | params.distinguished_name.push(rcgen::DnType::CommonName, cn); 51 | params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained); 52 | 53 | let kp = rcgen::KeyPair::generate()?; 54 | let ca_cert = params.self_signed(&kp)?; 55 | 56 | let cert = ca_cert.pem(); 57 | let key = kp.serialize_pem(); 58 | 59 | fs::write(format!("{}-ca-cert.pem", name), cert.as_bytes())?; 60 | fs::write(format!("{}-ca.pem", name), key.as_bytes())?; 61 | 62 | Ok(()) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod util; 2 | mod config; 3 | mod proxy; 4 | mod gen; 5 | mod check; 6 | 7 | use argh::FromArgs; 8 | 9 | /// No SNI tools 10 | #[derive(FromArgs)] 11 | struct Options { 12 | #[argh(subcommand)] 13 | subcmd: SubCommands, 14 | } 15 | 16 | #[derive(FromArgs)] 17 | #[argh(subcommand)] 18 | enum SubCommands { 19 | Proxy(proxy::Options), 20 | Check(check::Options), 21 | Gen(gen::Options), 22 | } 23 | 24 | #[tokio::main(flavor = "multi_thread")] 25 | async fn main() -> anyhow::Result<()> { 26 | let options: Options = argh::from_env(); 27 | 28 | match options.subcmd { 29 | SubCommands::Proxy(cmd) => cmd.exec().await?, 30 | SubCommands::Check(cmd) => cmd.exec().await?, 31 | SubCommands::Gen(cmd) => cmd.exec()? 32 | } 33 | 34 | Ok(()) 35 | } 36 | -------------------------------------------------------------------------------- /src/proxy.rs: -------------------------------------------------------------------------------- 1 | mod socks5; 2 | mod mitm; 3 | mod fragment; 4 | mod localdoh; 5 | 6 | use std::fs; 7 | use std::time::Duration; 8 | use std::sync::Arc; 9 | use std::path::{ PathBuf, Path }; 10 | use tokio::net::TcpListener; 11 | use tokio::task::JoinSet; 12 | use tokio::sync::Mutex; 13 | use hickory_resolver::config::{ ResolverConfig, NameServerConfigGroup }; 14 | use anyhow::format_err; 15 | use argh::FromArgs; 16 | use directories::ProjectDirs; 17 | use mitmca::{ Entry, CertStore }; 18 | use crate::config::Config; 19 | 20 | 21 | /// No SNI local proxy 22 | #[derive(FromArgs)] 23 | #[argh(subcommand, name = "proxy")] 24 | pub struct Options { 25 | /// config path 26 | #[argh(option, short = 'c')] 27 | config: Option, 28 | } 29 | 30 | struct Shared { 31 | config: Config, 32 | resolver: hickory_resolver::TokioResolver, 33 | } 34 | 35 | impl Options { 36 | pub async fn exec(self) -> anyhow::Result<()> { 37 | let config_path = self.config 38 | .or_else(|| { 39 | ProjectDirs::from("", "", env!("CARGO_PKG_NAME")) 40 | .map(|dir| dir.config_dir().join("config.toml")) 41 | }) 42 | .ok_or_else(|| format_err!("missing config"))?; 43 | 44 | let shared = { 45 | let config: Config = toml::from_str(&fs::read_to_string(&config_path)?)?; 46 | 47 | let resolver = if let Some(ref doh) = config.doh { 48 | use tokio_rustls::rustls; 49 | 50 | let mut root_cert_store = rustls::RootCertStore::empty(); 51 | root_cert_store.roots = webpki_roots::TLS_SERVER_ROOTS.into(); 52 | let mut tls_config = rustls::ClientConfig::builder() 53 | .with_root_certificates(root_cert_store) 54 | .with_no_client_auth(); 55 | tls_config.alpn_protocols = vec![b"h2".to_vec()]; 56 | tls_config.enable_sni = doh.sni; 57 | tls_config.enable_early_data = true; 58 | 59 | let server = NameServerConfigGroup::from_ips_https( 60 | &[doh.addr.ip()], doh.addr.port(), 61 | doh.name.clone(), false 62 | ); 63 | let dns_config = ResolverConfig::from_parts(None, Vec::new(), server); 64 | 65 | let mut builder = hickory_resolver::Resolver::builder_with_config( 66 | dns_config, 67 | hickory_resolver::name_server::TokioConnectionProvider::default() 68 | ); 69 | builder.options_mut().tls_config = tls_config; 70 | builder.options_mut().timeout = Duration::from_secs(2); 71 | builder.options_mut().attempts = 1; 72 | 73 | #[cfg(feature = "dnssec")] { 74 | builder.options_mut().validate = doh.dnssec; 75 | } 76 | 77 | builder.build() 78 | } else { 79 | hickory_resolver::TokioResolver::builder_tokio()?.build() 80 | }; 81 | 82 | Arc::new(Shared { config, resolver }) 83 | }; 84 | 85 | let mut maybe_ca = None; 86 | let mut joinset: JoinSet> = JoinSet::new(); 87 | 88 | if let Some(config) = shared.config.mitm.as_ref() { 89 | let proxy = { 90 | let cert_path = config_path 91 | .parent() 92 | .unwrap_or(&config_path) 93 | .join(&config.cert); 94 | let key_path = config_path 95 | .parent() 96 | .unwrap_or(&config_path) 97 | .join(&config.key); 98 | let ca = Arc::new(Mutex::new(read_root_cert(&cert_path, &key_path)?)); 99 | maybe_ca = Some(ca.clone()); 100 | 101 | mitm::Proxy { ca, shared: shared.clone() } 102 | }; 103 | let listener = TcpListener::bind(config.bind).await?; 104 | 105 | println!("mitm listen: {:?}", listener.local_addr()); 106 | 107 | joinset.spawn(async move { 108 | loop { 109 | let (stream, _) = listener.accept().await?; 110 | let req_id: u64 = rand::random(); 111 | let proxy = proxy.clone(); 112 | tokio::spawn(async move { 113 | if let Err(err) = proxy.call(req_id, stream).await { 114 | eprintln!("[{:x}] proxy connect error: {:?}", req_id, err) 115 | } 116 | }); 117 | } 118 | }); 119 | } 120 | 121 | if let Some(config) = shared.config.fragment.clone() { 122 | let listener = TcpListener::bind(&config.bind).await?; 123 | let proxy = Arc::new(fragment::Proxy { config, shared: shared.clone() }); 124 | 125 | println!("fragment listen: {:?}", listener.local_addr()); 126 | 127 | joinset.spawn(async move { 128 | loop { 129 | let (stream, _) = listener.accept().await?; 130 | let req_id: u64 = rand::random(); 131 | let proxy = proxy.clone(); 132 | tokio::spawn(async move { 133 | if let Err(err) = proxy.call(req_id, stream).await { 134 | eprintln!("[{:x}] fragment connect error: {:?}", req_id, err) 135 | } 136 | }); 137 | } 138 | }); 139 | } 140 | 141 | if let Some(((localdoh_config, doh_config), ca)) = shared.config.localdoh.as_ref() 142 | .zip(shared.config.doh.as_ref()) 143 | .zip(maybe_ca) 144 | { 145 | let listener = TcpListener::bind(&localdoh_config.bind).await?; 146 | let proxy = localdoh::Proxy::new(ca, localdoh_config, doh_config).await?; 147 | let proxy = Arc::new(proxy); 148 | 149 | println!("localdoh listen: {:?}", listener.local_addr()); 150 | 151 | joinset.spawn(async move { 152 | loop { 153 | let (stream, _) = listener.accept().await?; 154 | let req_id: u64 = rand::random(); 155 | let proxy = proxy.clone(); 156 | tokio::spawn(async move { 157 | if let Err(err) = proxy.call(req_id, stream).await { 158 | eprintln!("[{:x}] localdoh proxy error: {:?}", req_id, err) 159 | } 160 | }); 161 | } 162 | }); 163 | } 164 | 165 | while let Some(result) = joinset.join_next().await { 166 | let () = result??; 167 | } 168 | 169 | Ok(()) 170 | } 171 | } 172 | 173 | fn read_root_cert(cert_path: &Path, key_path: &Path) -> anyhow::Result { 174 | let cert_buf = fs::read_to_string(cert_path)?; 175 | let key_buf = fs::read_to_string(key_path)?; 176 | let entry = Entry::from_pem(&cert_buf, &key_buf)?; 177 | Ok(CertStore::from(entry)) 178 | } 179 | -------------------------------------------------------------------------------- /src/proxy/fragment.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::sync::Arc; 3 | use std::net::{ SocketAddr, IpAddr, Ipv4Addr }; 4 | use std::time::Duration; 5 | use anyhow::Context; 6 | 7 | use tokio::io::copy_bidirectional; 8 | use tokio::io::{ AsyncReadExt, AsyncWriteExt }; 9 | use tokio::time::{ sleep, timeout }; 10 | use tokio::net::TcpStream; 11 | 12 | use futures::future::{ self, FutureExt, TryFutureExt }; 13 | use futures::stream::{ self, StreamExt }; 14 | use tower_layer::Layer; 15 | use tower_util::{ service_fn, ServiceExt }; 16 | use tower_happy_eyeballs::HappyEyeballsLayer; 17 | 18 | use crate::config::{ StrOrList, Fragment }; 19 | use crate::proxy::{ socks5, Shared }; 20 | 21 | 22 | pub struct Proxy { 23 | pub config: Fragment, 24 | pub shared: Arc 25 | } 26 | 27 | impl Proxy { 28 | pub async fn call(self: Arc, req_id: u64, mut stream: TcpStream) -> anyhow::Result<()> { 29 | // local handshake 30 | // 31 | // Get target addr 32 | let addr = socks5::handshake(&mut stream) 33 | .await 34 | .context("socks5 handshake")?; 35 | 36 | println!("[{:x}] start connect: {:?}", req_id, addr); 37 | 38 | let maybe_remote = match &addr { 39 | socks5::Address::Addr(addr) => TcpStream::connect(addr).await.context("remote connect with address"), 40 | socks5::Address::Domain(hostname, port) => { 41 | let lookup = match self.shared.config.mapping.get(hostname) 42 | .and_then(|rule| rule.addr.as_ref()) 43 | { 44 | Some(StrOrList::Str(name)) => self.shared.resolver.lookup_ip(name) 45 | .map_ok(|ips| ips.into_iter().collect::>()) 46 | .boxed(), 47 | Some(StrOrList::List(list)) => future::ready(Ok(list.clone())).boxed(), 48 | None => self.shared.resolver.lookup_ip(hostname.clone()) 49 | .map_ok(|ips| ips.into_iter().collect::>()) 50 | .boxed() 51 | }; 52 | 53 | let ips = timeout(Duration::from_secs(5), lookup).await 54 | .map_err(anyhow::Error::from) 55 | .and_then(|ret| ret.map_err(anyhow::Error::from)) 56 | .with_context(|| format!("dns lookup failure: {}", hostname))?; 57 | 58 | remote_connect(ips, *port).await.context("remote connect") 59 | } 60 | }; 61 | 62 | let mut remote = match maybe_remote { 63 | Ok(remote) => { 64 | let addr = remote.local_addr().context("get remote local addr failed")?; 65 | socks5::response(&mut stream, 0, addr).await.context("socks5 response")?; 66 | remote 67 | }, 68 | Err(err) => { 69 | let reply = err.chain() 70 | .find(|err| { 71 | let kind = err.downcast_ref::().map(|err| err.kind()); 72 | kind == Some(io::ErrorKind::ConnectionRefused) 73 | }) 74 | .map(|_| 5) 75 | .unwrap_or(1); 76 | 77 | let maybe_addr = match addr { 78 | socks5::Address::Addr(addr) => addr, 79 | socks5::Address::Domain(_, port) => SocketAddr::from((Ipv4Addr::LOCALHOST, port)) 80 | }; 81 | socks5::response(&mut stream, reply, maybe_addr).await.context("socks5 response")?; 82 | return Err(err); 83 | } 84 | }; 85 | 86 | let mut header = [0; 5]; 87 | stream.read_exact(&mut header).await?; 88 | 89 | let ty = header[0]; 90 | let ver = u16::from_be_bytes([header[1], header[2]]); 91 | let len = u16::from_be_bytes([header[3], header[4]]); 92 | 93 | if ty == HANDSHAKE_TYPE && ver & 0xff00 == TLS { 94 | let mut hello = vec![0; len.into()]; 95 | stream.read_exact(&mut hello).await?; 96 | 97 | let mut pos = 0; 98 | 99 | while hello.len() > pos { 100 | let len = hello.len() - pos; 101 | let len = len.try_into().context("bad length")?; 102 | let (len, dur) = fragment(len, &self.config); 103 | 104 | let mut header = header; 105 | header[3..].copy_from_slice(&len.to_be_bytes()); 106 | 107 | remote.write_all(&header).await?; 108 | remote.write_all(&hello[pos..][..len.into()]).await?; 109 | pos += usize::from(len); 110 | remote.flush().await?; 111 | 112 | if let Some(dur) = dur { 113 | sleep(dur).await; 114 | } 115 | } 116 | } else { 117 | remote.write_all(&header).await?; 118 | } 119 | 120 | println!("[{:x}] connected: {:?}", req_id, remote.peer_addr()); 121 | 122 | copy_bidirectional(&mut stream, &mut remote) 123 | .await 124 | .map(drop) 125 | .context("bidirectional copy stream error")?; 126 | 127 | Ok(()) 128 | } 129 | } 130 | 131 | const HANDSHAKE_TYPE: u8 = 0x16; 132 | const TLS: u16 = 0x0300; 133 | 134 | pub async fn remote_connect(ips: I, port: u16) 135 | -> anyhow::Result 136 | where 137 | I: IntoIterator 138 | { 139 | let make_conn = service_fn(|ip| TcpStream::connect((ip, port))); 140 | 141 | let remote = HappyEyeballsLayer::new() 142 | .layer(make_conn) 143 | .oneshot(stream::iter(ips).fuse()).await?; 144 | 145 | Ok(remote) 146 | } 147 | 148 | fn fragment(len: u16, config: &Fragment) -> (u16, Option) { 149 | use rand::Rng; 150 | 151 | let mut rng = rand::rng(); 152 | 153 | let len = { 154 | let start = std::cmp::min(len, config.size.0); 155 | let end = std::cmp::min(len, config.size.1); 156 | rng.random_range(start..=end) 157 | }; 158 | let dur = config.delay.map(|delay| { 159 | let start = std::cmp::min(delay.0, delay.1); 160 | let end = std::cmp::max(delay.0, delay.1); 161 | Duration::from_millis(rng.random_range(start..=end)) 162 | }); 163 | 164 | (len, dur) 165 | } 166 | -------------------------------------------------------------------------------- /src/proxy/localdoh.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::sync::Arc; 3 | use std::net::SocketAddr; 4 | 5 | use futures::TryFutureExt; 6 | use tokio::sync::Mutex; 7 | use tokio::net::TcpStream; 8 | use hyper::body::Incoming; 9 | use hyper::client::conn::http2::SendRequest; 10 | use hyper_util::rt::{ TokioExecutor, TokioTimer, TokioIo }; 11 | use tokio_rustls::{ rustls, TlsConnector, TlsAcceptor }; 12 | 13 | use mitmca::CertStore; 14 | use crate::config::{Doh, LocalDoh}; 15 | use crate::util::{ ZlibDecompressor, ZstdDecompressor, LOCAL_SESSION_CACHE, REMOTE_SESSION_CACHE }; 16 | 17 | 18 | pub struct Proxy { 19 | acceptor: TlsAcceptor, 20 | connector: TlsConnector, 21 | dnsaddr: SocketAddr, 22 | dnsname: rustls::pki_types::ServerName<'static>, 23 | hostname: http::uri::Authority, 24 | server: hyper::server::conn::http2::Builder, 25 | client: hyper::client::conn::http2::Builder, 26 | send_req: Mutex>>, 27 | } 28 | 29 | impl Proxy { 30 | pub async fn new(ca: Arc>, localdoh_config: &LocalDoh, doh_config: &Doh) 31 | -> anyhow::Result 32 | { 33 | let acceptor = { 34 | let mut tls_config = ca.lock().await.get(&localdoh_config.name)?; 35 | tls_config.session_storage = LOCAL_SESSION_CACHE.clone(); 36 | tls_config.alpn_protocols = vec![b"h2".into()]; 37 | TlsAcceptor::from(Arc::new(tls_config)) 38 | }; 39 | 40 | let connector = { 41 | let mut root_cert_store = rustls::RootCertStore::empty(); 42 | root_cert_store.roots = webpki_roots::TLS_SERVER_ROOTS.into(); 43 | let mut tls_config = rustls::ClientConfig::builder() 44 | .with_root_certificates(root_cert_store) 45 | .with_no_client_auth(); 46 | tls_config.alpn_protocols = vec![b"h2".into()]; 47 | tls_config.enable_sni = doh_config.sni; 48 | tls_config.enable_early_data = true; 49 | tls_config.resumption = REMOTE_SESSION_CACHE.clone(); 50 | tls_config.cert_decompressors = vec![&ZlibDecompressor, &ZstdDecompressor]; 51 | TlsConnector::from(Arc::new(tls_config)) 52 | }; 53 | 54 | let dnsname = rustls::pki_types::ServerName::try_from(doh_config.name.as_str()) 55 | .map_err(|_| anyhow::format_err!("bad dnsname: {:?}", doh_config.name))?; 56 | 57 | let mut server = hyper::server::conn::http2::Builder::new(TokioExecutor::default()); 58 | server.timer(TokioTimer::new()); 59 | let mut client = hyper::client::conn::http2::Builder::new(TokioExecutor::default()); 60 | client.timer(TokioTimer::new()); 61 | 62 | Ok(Proxy { 63 | acceptor, 64 | connector, 65 | server, 66 | client, 67 | dnsaddr: doh_config.addr, 68 | dnsname: dnsname.to_owned(), 69 | hostname: http::uri::Authority::from_maybe_shared(doh_config.name.clone())?, 70 | send_req: Mutex::new(None) 71 | }) 72 | } 73 | 74 | pub async fn call(self: Arc, req_id: u64, stream: TcpStream) -> anyhow::Result<()> { 75 | async fn call(proxy: &Proxy, req_id: u64, mut req: http::Request) 76 | -> anyhow::Result> 77 | { 78 | let mut parts = req.uri().clone().into_parts(); 79 | parts.authority = Some(proxy.hostname.clone()); 80 | *req.uri_mut() = http::Uri::from_parts(parts)?; 81 | 82 | let mut send_req = proxy.send_req.lock().await; 83 | 84 | if let Some(send_req2) = send_req.as_ref() { 85 | if send_req2.is_closed() { 86 | *send_req = None; 87 | } 88 | } 89 | 90 | if send_req.is_none() { 91 | let remote = TcpStream::connect(&proxy.dnsaddr).await?; 92 | remote.set_nodelay(true)?; 93 | let remote = proxy.connector.connect(proxy.dnsname.to_owned(), remote).await?; 94 | remote.get_ref().0.set_nodelay(false)?; 95 | 96 | println!("[{}] new remote doh connect: {:?}", req_id, remote.get_ref().0.peer_addr()); 97 | 98 | let (send_req2, conn) = proxy.client.handshake::<_, Incoming>(TokioIo::new(remote)).await?; 99 | tokio::spawn(conn.map_err(move |err| { 100 | if (&err as &dyn std::error::Error).downcast_ref::() 101 | .filter(|err| err.kind() == io::ErrorKind::UnexpectedEof) 102 | .is_none() 103 | { 104 | eprintln!("[{}] remote http2 error: {:?}", req_id, err); 105 | } 106 | })); 107 | 108 | *send_req = Some(send_req2); 109 | } 110 | 111 | let mut send_req2 = send_req.take().unwrap(); 112 | let resp = send_req2.send_request(req).await?; 113 | *send_req = Some(send_req2); 114 | 115 | Ok(resp) as anyhow::Result> 116 | } 117 | 118 | let svc = hyper::service::service_fn(|req| { 119 | let proxy = self.clone(); 120 | async move { 121 | call(&proxy, req_id, req).await 122 | } 123 | }); 124 | 125 | let local = self.acceptor.accept(stream).await?; 126 | 127 | println!("[{:x}] start serve: {:?}", req_id, local.get_ref().0.local_addr()); 128 | 129 | if let Err(err) = self.server.serve_connection(TokioIo::new(local), svc).await { 130 | eprintln!("[{}] local http2 error: {:?}", req_id, err); 131 | } 132 | 133 | Ok(()) 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/proxy/mitm.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::time::Duration; 3 | use std::convert::TryFrom; 4 | use std::sync::Arc; 5 | use std::net::{ SocketAddr, IpAddr, Ipv4Addr }; 6 | use std::collections::HashMap; 7 | use anyhow::Context; 8 | use once_cell::sync::Lazy; 9 | 10 | use tokio::sync::{ Mutex, RwLock }; 11 | use tokio::net::TcpStream; 12 | use tokio::time::timeout; 13 | use tokio::io::copy_bidirectional; 14 | use tokio_rustls::{ rustls, TlsConnector, client::TlsStream }; 15 | 16 | use futures::future::{ self, FutureExt, TryFutureExt }; 17 | use futures::stream::{ self, StreamExt }; 18 | use tower_layer::Layer; 19 | use tower_util::{ service_fn, ServiceExt }; 20 | use tower_happy_eyeballs::HappyEyeballsLayer; 21 | 22 | use mitmca::CertStore; 23 | use crate::proxy::{ socks5, Shared }; 24 | use crate::config::{ StrOrList, Rule }; 25 | use crate::util::{ ZlibDecompressor, ZstdDecompressor, LOCAL_SESSION_CACHE, REMOTE_SESSION_CACHE }; 26 | 27 | 28 | static LOCAL_ALPN_CACHE: Lazy>>>> = 29 | Lazy::new(|| RwLock::new(HashMap::new())); 30 | 31 | #[derive(Clone)] 32 | pub struct Proxy { 33 | pub ca: Arc>, 34 | pub shared: Arc 35 | } 36 | 37 | impl Proxy { 38 | pub async fn call(self, req_id: u64, mut stream: TcpStream) -> anyhow::Result<()> { 39 | // local handshake 40 | // 41 | // Get target addr 42 | let addr = socks5::handshake(&mut stream) 43 | .await 44 | .context("socks5 handshake")?; 45 | 46 | println!("[{:x}] start connect: {:?}", req_id, addr); 47 | 48 | let (start_handshake, remote, hostname) = match addr { 49 | socks5::Address::Addr(addr) => { 50 | // socks5 response 51 | socks5::response(&mut stream, 0, addr).await.context("socks5 response")?; 52 | 53 | // local tls handshake 54 | let acceptor = rustls::server::Acceptor::default(); 55 | let start_handshake = tokio_rustls::LazyConfigAcceptor::new(acceptor, stream) 56 | .await 57 | .context("local tls accept")?; 58 | 59 | // Get hostname 60 | let hostname = start_handshake.client_hello() 61 | .server_name() 62 | .map(String::from) 63 | .context("local tls no server name")?; 64 | 65 | // remote connect 66 | let ips = std::iter::once(addr.ip()); 67 | let remote = remote_connect(&self.shared, hostname.clone(), ips, addr.port()) 68 | .await 69 | .context("remote connect")?; 70 | 71 | (start_handshake, remote, hostname) 72 | }, 73 | socks5::Address::Domain(hostname, port) => { 74 | // dns query & remote connect 75 | let remote = async { 76 | let lookup = match self.shared.config.mapping.get(&hostname) 77 | .and_then(|rule| rule.addr.as_ref()) 78 | { 79 | Some(StrOrList::Str(name)) => self.shared.resolver.lookup_ip(name) 80 | .map_ok(|ips| ips.into_iter().collect::>()) 81 | .boxed(), 82 | Some(StrOrList::List(list)) => future::ready(Ok(list.clone())).boxed(), 83 | None => self.shared.resolver.lookup_ip(hostname.clone()) 84 | .map_ok(|ips| ips.into_iter().collect::>()) 85 | .boxed() 86 | }; 87 | let ips = timeout(Duration::from_secs(5), lookup).await 88 | .map_err(anyhow::Error::from) 89 | .and_then(|ret| ret.map_err(anyhow::Error::from)) 90 | .with_context(|| format!("dns lookup failure: {}", hostname))?; 91 | 92 | remote_connect(&self.shared, hostname.clone(), ips, port) 93 | .await 94 | .context("remote connect") 95 | }; 96 | 97 | // socks5 error response 98 | let remote = match remote.await { 99 | Ok(remote) => remote, 100 | Err(err) => { 101 | let reply = err.chain() 102 | .find(|err| { 103 | let kind = err.downcast_ref::().map(|err| err.kind()); 104 | kind == Some(io::ErrorKind::ConnectionRefused) 105 | }) 106 | .map(|_| 5) 107 | .unwrap_or(1); 108 | 109 | let fake_addr = SocketAddr::from((Ipv4Addr::LOCALHOST, port)); 110 | socks5::response(&mut stream, reply, fake_addr).await.context("socks5 response")?; 111 | return Err(err); 112 | } 113 | }; 114 | 115 | // socks5 response 116 | let addr = remote.get_ref().0.local_addr().context("get remote local addr failed")?; 117 | socks5::response(&mut stream, 0, addr).await.context("socks5 response")?; 118 | 119 | // tls handshake 120 | let acceptor = rustls::server::Acceptor::default(); 121 | let start_handshake = tokio_rustls::LazyConfigAcceptor::new(acceptor, stream) 122 | .await 123 | .context("local tls accept")?; 124 | 125 | (start_handshake, remote, hostname) 126 | } 127 | }; 128 | 129 | // start local tls handshake 130 | let tls_config = { 131 | let (_io, session) = remote.get_ref(); 132 | let alpn = session.alpn_protocol() 133 | .map(|proto| vec![Vec::from(proto)]) 134 | .unwrap_or_else(Vec::new); 135 | let mut tls_config = self.ca.lock().await.get(&hostname)?; 136 | tls_config.session_storage = LOCAL_SESSION_CACHE.clone(); 137 | tls_config.alpn_protocols = alpn; 138 | Arc::new(tls_config) 139 | }; 140 | let local_alpn = start_handshake.client_hello().alpn() 141 | .map(|list| list.map(|s| s.into()).collect::>()) 142 | .unwrap_or_default(); 143 | 144 | let mut remote = remote; 145 | let mut local = match start_handshake.into_stream(tls_config).await { 146 | Ok(local) => local, 147 | Err(err) => { 148 | if err.get_ref() 149 | .and_then(|err| err.downcast_ref::()) 150 | .filter(|err| matches!(err, rustls::Error::NoApplicationProtocol)) 151 | .is_some() 152 | { 153 | let mut map = LOCAL_ALPN_CACHE.write().await; 154 | map.insert(hostname, local_alpn); 155 | } 156 | 157 | return Err(err).context("local tls handshake"); 158 | } 159 | }; 160 | 161 | { 162 | let (io, _) = remote.get_ref(); 163 | println!("[{:x}] connected: {:?}", req_id, io.peer_addr()); 164 | } 165 | 166 | copy_bidirectional(&mut local, &mut remote) 167 | .await 168 | .map(drop) 169 | // ignore `peer closed connection without sending TLS close_notify` 170 | .or_else(|err| if err.kind() == io::ErrorKind::UnexpectedEof { 171 | Ok(()) 172 | } else { 173 | Err(err) 174 | }) 175 | .context("bidirectional copy stream error")?; 176 | 177 | Ok(()) 178 | } 179 | } 180 | 181 | #[allow(dead_code)] 182 | mod v5 { 183 | pub const VERSION: u8 = 5; 184 | 185 | pub const METH_NO_AUTH: u8 = 0; 186 | pub const METH_GSSAPI: u8 = 1; 187 | pub const METH_USER_PASS: u8 = 2; 188 | 189 | pub const CMD_CONNECT: u8 = 1; 190 | pub const CMD_BIND: u8 = 2; 191 | pub const CMD_UDP_ASSOCIATE: u8 = 3; 192 | 193 | pub const ATYP_IPV4: u8 = 1; 194 | pub const ATYP_IPV6: u8 = 4; 195 | pub const ATYP_DOMAIN: u8 = 3; 196 | } 197 | 198 | async fn build_tls_connector(shared: &Shared, server_name: &str) 199 | -> anyhow::Result<(TlsConnector, rustls::pki_types::ServerName<'static>)> 200 | { 201 | static DEFAULT_RULE: Rule = Rule { 202 | alpn: Vec::new(), 203 | sni: None, 204 | addr: None, 205 | force_no_sni: false 206 | }; 207 | 208 | let rule = shared.config.mapping.get(server_name).unwrap_or(&DEFAULT_RULE); 209 | let dnsname = rule.sni 210 | .as_deref() 211 | .unwrap_or(server_name); 212 | let dnsname = rustls::pki_types::ServerName::try_from(dnsname) 213 | .map_err(|_| anyhow::format_err!("bad dnsname: {:?}", dnsname))?; 214 | let dnsname = dnsname.to_owned(); 215 | 216 | let mut root_cert_store = rustls::RootCertStore::empty(); 217 | root_cert_store.roots = webpki_roots::TLS_SERVER_ROOTS.into(); 218 | let mut tls_config = rustls::ClientConfig::builder() 219 | .with_root_certificates(root_cert_store) 220 | .with_no_client_auth(); 221 | tls_config.alpn_protocols = if rule.alpn.is_empty() { 222 | let map = LOCAL_ALPN_CACHE.read().await; 223 | if let Some(alpn) = map.get(server_name) { 224 | alpn.clone() 225 | } else if let Some(mitm) = shared.config.mitm.as_ref() { 226 | mitm.alpn.iter() 227 | .map(|protocol| Vec::from(protocol.as_bytes())) 228 | .collect() 229 | } else { 230 | Vec::new() 231 | } 232 | } else { 233 | rule.alpn.iter() 234 | .map(|protocol| Vec::from(protocol.as_bytes())) 235 | .collect() 236 | }; 237 | tls_config.enable_sni = if rule.force_no_sni { 238 | false 239 | } else { 240 | rule.sni.is_some() 241 | }; 242 | tls_config.resumption = REMOTE_SESSION_CACHE.clone(); 243 | tls_config.cert_decompressors = vec![&ZlibDecompressor, &ZstdDecompressor]; 244 | 245 | Ok((TlsConnector::from(Arc::new(tls_config)), dnsname)) 246 | } 247 | 248 | pub async fn remote_connect(shared: &Shared, server_name: String, ips: I, port: u16) 249 | -> anyhow::Result> 250 | where 251 | I: IntoIterator 252 | { 253 | let (tls_connector, dnsname) = build_tls_connector(shared, &server_name).await?; 254 | 255 | let make_conn = service_fn(|ip| { 256 | TcpStream::connect((ip, port)) 257 | .and_then(|stream| { 258 | let ret = stream.set_nodelay(true) 259 | .map(|_| stream); 260 | future::ready(ret) 261 | }) 262 | .and_then(|stream| tls_connector.connect(dnsname.clone(), stream)) 263 | }); 264 | 265 | let remote = HappyEyeballsLayer::new() 266 | .layer(make_conn) 267 | .oneshot(stream::iter(ips).fuse()).await?; 268 | 269 | let (io, _session) = remote.get_ref(); 270 | io.set_nodelay(false)?; 271 | Ok(remote) 272 | } 273 | -------------------------------------------------------------------------------- /src/proxy/socks5.rs: -------------------------------------------------------------------------------- 1 | use std::net::{ SocketAddr, IpAddr }; 2 | use std::marker::Unpin; 3 | 4 | use tokio::io::{ 5 | AsyncRead, AsyncWrite, 6 | AsyncReadExt, AsyncWriteExt 7 | }; 8 | 9 | 10 | #[derive(Debug)] 11 | pub enum Address { 12 | Addr(SocketAddr), 13 | Domain(String, u16) 14 | } 15 | 16 | #[allow(dead_code)] 17 | mod v5 { 18 | pub const VERSION: u8 = 5; 19 | 20 | pub const METH_NO_AUTH: u8 = 0; 21 | pub const METH_GSSAPI: u8 = 1; 22 | pub const METH_USER_PASS: u8 = 2; 23 | 24 | pub const CMD_CONNECT: u8 = 1; 25 | pub const CMD_BIND: u8 = 2; 26 | pub const CMD_UDP_ASSOCIATE: u8 = 3; 27 | 28 | pub const ATYP_IPV4: u8 = 1; 29 | pub const ATYP_IPV6: u8 = 4; 30 | pub const ATYP_DOMAIN: u8 = 3; 31 | } 32 | 33 | pub async fn handshake(stream: &mut S) 34 | -> anyhow::Result
35 | where 36 | S: AsyncRead + AsyncWrite + Unpin 37 | { 38 | // read version 39 | { 40 | let version = stream.read_u8().await?; 41 | if version != v5::VERSION { 42 | anyhow::bail!("unimplemented version: {}", version); 43 | } 44 | } 45 | 46 | // read auth method 47 | { 48 | let len = stream.read_u8().await?; 49 | let len: usize = len.into(); 50 | let mut buf = [0; 256]; 51 | stream.read_exact(&mut buf[..len]).await?; 52 | if !buf[..len].contains(&v5::METH_NO_AUTH) { 53 | anyhow::bail!("no supported auth method given"); 54 | } 55 | } 56 | 57 | // write version and auth method 58 | stream.write_all(&[v5::VERSION, v5::METH_NO_AUTH]).await?; 59 | stream.flush().await?; 60 | 61 | // read version 62 | { 63 | let version = stream.read_u8().await?; 64 | if version != v5::VERSION { 65 | anyhow::bail!("didn't confirm with v5 version: {}", version); 66 | } 67 | } 68 | 69 | // read cmd 70 | { 71 | let cmd = stream.read_u8().await?; 72 | if cmd != v5::CMD_CONNECT { 73 | anyhow::bail!("unsupported command: {}", cmd); 74 | } 75 | } 76 | 77 | // read addr 78 | let addr = { 79 | let _ = stream.read_u8().await?; // reserved 80 | let atyp = stream.read_u8().await?; 81 | match atyp { 82 | v5::ATYP_IPV4 => { 83 | let mut buf = [0; 4]; 84 | stream.read_exact(&mut buf).await?; 85 | let port = stream.read_u16().await?; 86 | Address::Addr(SocketAddr::from((buf, port))) 87 | }, 88 | v5::ATYP_IPV6 => { 89 | let mut buf = [0; 16]; 90 | stream.read_exact(&mut buf).await?; 91 | let port = stream.read_u16().await?; 92 | Address::Addr(SocketAddr::from((buf, port))) 93 | }, 94 | v5::ATYP_DOMAIN => { 95 | let len = stream.read_u8().await?; 96 | let len: usize = len.into(); 97 | let mut buf = vec![0; len]; 98 | stream.read_exact(&mut buf).await?; 99 | let domain = String::from_utf8(buf)?; 100 | let port = stream.read_u16().await?; 101 | 102 | if let Ok(addr) = domain.parse::() { 103 | Address::Addr(SocketAddr::from((addr, port))) 104 | } else { 105 | Address::Domain(domain, port) 106 | } 107 | }, 108 | _ => anyhow::bail!("unknown ATYP received: {}", atyp) 109 | } 110 | }; 111 | 112 | Ok(addr) 113 | } 114 | 115 | pub async fn response(stream: &mut S, reply: u8, addr: SocketAddr) 116 | -> anyhow::Result<()> 117 | where 118 | S: AsyncRead + AsyncWrite + Unpin 119 | { 120 | let mut buf = [0; 4]; 121 | 122 | buf[0] = v5::VERSION; // version 123 | buf[1] = reply; // reply field 124 | buf[2] = 0x0; // reserved 125 | 126 | match addr { 127 | SocketAddr::V4(addr) => { 128 | buf[3] = v5::ATYP_IPV4; 129 | stream.write_all(&buf).await?; 130 | stream.write_all(&addr.ip().octets()).await?; 131 | stream.write_all(&addr.port().to_be_bytes()).await?; 132 | }, 133 | SocketAddr::V6(addr) => { 134 | buf[3] = v5::ATYP_IPV6; 135 | stream.write_all(&buf).await?; 136 | stream.write_all(&addr.ip().octets()).await?; 137 | stream.write_all(&addr.port().to_be_bytes()).await?; 138 | } 139 | } 140 | 141 | stream.flush().await?; 142 | 143 | Ok(()) 144 | } 145 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use once_cell::sync::Lazy; 3 | use tokio_rustls::rustls; 4 | use tokio_rustls::rustls::compress::{ CertDecompressor, DecompressionFailed }; 5 | use tokio_rustls::rustls::CertificateCompressionAlgorithm; 6 | 7 | 8 | pub static LOCAL_SESSION_CACHE: Lazy> = 9 | Lazy::new(|| rustls::server::ServerSessionMemoryCache::new(64)); 10 | pub static REMOTE_SESSION_CACHE: Lazy = 11 | Lazy::new(|| rustls::client::Resumption::in_memory_sessions(64)); 12 | 13 | #[derive(Debug)] 14 | pub struct ZlibDecompressor; 15 | 16 | impl CertDecompressor for ZlibDecompressor { 17 | fn decompress( 18 | &self, 19 | input: &[u8], 20 | output: &mut [u8], 21 | ) -> Result<(), DecompressionFailed> { 22 | fdeflate::Decompressor::new().read(input, output, 0, true) 23 | .ok() 24 | .filter(|(_consumed, produced)| *produced == output.len()) 25 | .map(drop) 26 | .ok_or(DecompressionFailed) 27 | } 28 | 29 | fn algorithm(&self) -> CertificateCompressionAlgorithm { 30 | CertificateCompressionAlgorithm::Zlib 31 | } 32 | } 33 | 34 | #[derive(Debug)] 35 | pub struct ZstdDecompressor; 36 | 37 | impl CertDecompressor for ZstdDecompressor { 38 | fn decompress( 39 | &self, 40 | input: &[u8], 41 | output: &mut [u8], 42 | ) -> Result<(), DecompressionFailed> { 43 | use std::io::Read; 44 | 45 | let mut decoder = ruzstd::decoding::StreamingDecoder::new(input) 46 | .map_err(|_| DecompressionFailed)?; 47 | decoder.read_exact(output).map_err(|_| DecompressionFailed) 48 | } 49 | 50 | fn algorithm(&self) -> CertificateCompressionAlgorithm { 51 | CertificateCompressionAlgorithm::Zstd 52 | } 53 | } 54 | --------------------------------------------------------------------------------