├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md └── src ├── lib.rs └── main.rs /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.95" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" 34 | 35 | [[package]] 36 | name = "autocfg" 37 | version = "1.4.0" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 40 | 41 | [[package]] 42 | name = "backtrace" 43 | version = "0.3.74" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 46 | dependencies = [ 47 | "addr2line", 48 | "cfg-if", 49 | "libc", 50 | "miniz_oxide", 51 | "object", 52 | "rustc-demangle", 53 | "windows-targets", 54 | ] 55 | 56 | [[package]] 57 | name = "base64" 58 | version = "0.13.1" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" 61 | 62 | [[package]] 63 | name = "base64" 64 | version = "0.21.7" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 67 | 68 | [[package]] 69 | name = "bitflags" 70 | version = "2.7.0" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" 73 | 74 | [[package]] 75 | name = "block-buffer" 76 | version = "0.10.4" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 79 | dependencies = [ 80 | "generic-array", 81 | ] 82 | 83 | [[package]] 84 | name = "byteorder" 85 | version = "1.5.0" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 88 | 89 | [[package]] 90 | name = "bytes" 91 | version = "1.9.0" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" 94 | 95 | [[package]] 96 | name = "cc" 97 | version = "1.2.9" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" 100 | dependencies = [ 101 | "shlex", 102 | ] 103 | 104 | [[package]] 105 | name = "cfg-if" 106 | version = "1.0.0" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 109 | 110 | [[package]] 111 | name = "core-foundation" 112 | version = "0.9.4" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 115 | dependencies = [ 116 | "core-foundation-sys", 117 | "libc", 118 | ] 119 | 120 | [[package]] 121 | name = "core-foundation-sys" 122 | version = "0.8.7" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 125 | 126 | [[package]] 127 | name = "cpufeatures" 128 | version = "0.2.16" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" 131 | dependencies = [ 132 | "libc", 133 | ] 134 | 135 | [[package]] 136 | name = "crypto-common" 137 | version = "0.1.6" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 140 | dependencies = [ 141 | "generic-array", 142 | "typenum", 143 | ] 144 | 145 | [[package]] 146 | name = "data-encoding" 147 | version = "2.6.0" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" 150 | 151 | [[package]] 152 | name = "digest" 153 | version = "0.10.7" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 156 | dependencies = [ 157 | "block-buffer", 158 | "crypto-common", 159 | ] 160 | 161 | [[package]] 162 | name = "displaydoc" 163 | version = "0.2.5" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 166 | dependencies = [ 167 | "proc-macro2", 168 | "quote", 169 | "syn", 170 | ] 171 | 172 | [[package]] 173 | name = "either" 174 | version = "1.13.0" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 177 | 178 | [[package]] 179 | name = "encoding_rs" 180 | version = "0.8.35" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 183 | dependencies = [ 184 | "cfg-if", 185 | ] 186 | 187 | [[package]] 188 | name = "env_logger" 189 | version = "0.10.2" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" 192 | dependencies = [ 193 | "humantime", 194 | "is-terminal", 195 | "log", 196 | "regex", 197 | "termcolor", 198 | ] 199 | 200 | [[package]] 201 | name = "equivalent" 202 | version = "1.0.1" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 205 | 206 | [[package]] 207 | name = "errno" 208 | version = "0.3.10" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" 211 | dependencies = [ 212 | "libc", 213 | "windows-sys 0.59.0", 214 | ] 215 | 216 | [[package]] 217 | name = "fastrand" 218 | version = "2.3.0" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 221 | 222 | [[package]] 223 | name = "fnv" 224 | version = "1.0.7" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 227 | 228 | [[package]] 229 | name = "foreign-types" 230 | version = "0.3.2" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 233 | dependencies = [ 234 | "foreign-types-shared", 235 | ] 236 | 237 | [[package]] 238 | name = "foreign-types-shared" 239 | version = "0.1.1" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 242 | 243 | [[package]] 244 | name = "form_urlencoded" 245 | version = "1.2.1" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 248 | dependencies = [ 249 | "percent-encoding", 250 | ] 251 | 252 | [[package]] 253 | name = "fortifynet_proxy" 254 | version = "2.0.0" 255 | dependencies = [ 256 | "anyhow", 257 | "env_logger", 258 | "futures", 259 | "hyper", 260 | "log", 261 | "rustls", 262 | "rustls-pemfile", 263 | "thiserror", 264 | "tokio", 265 | "tokio-rustls", 266 | "tokio-socks", 267 | "tokio-tungstenite 0.20.1", 268 | "url", 269 | "warp", 270 | ] 271 | 272 | [[package]] 273 | name = "futures" 274 | version = "0.3.31" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" 277 | dependencies = [ 278 | "futures-channel", 279 | "futures-core", 280 | "futures-executor", 281 | "futures-io", 282 | "futures-sink", 283 | "futures-task", 284 | "futures-util", 285 | ] 286 | 287 | [[package]] 288 | name = "futures-channel" 289 | version = "0.3.31" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 292 | dependencies = [ 293 | "futures-core", 294 | "futures-sink", 295 | ] 296 | 297 | [[package]] 298 | name = "futures-core" 299 | version = "0.3.31" 300 | source = "registry+https://github.com/rust-lang/crates.io-index" 301 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 302 | 303 | [[package]] 304 | name = "futures-executor" 305 | version = "0.3.31" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" 308 | dependencies = [ 309 | "futures-core", 310 | "futures-task", 311 | "futures-util", 312 | ] 313 | 314 | [[package]] 315 | name = "futures-io" 316 | version = "0.3.31" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 319 | 320 | [[package]] 321 | name = "futures-macro" 322 | version = "0.3.31" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 325 | dependencies = [ 326 | "proc-macro2", 327 | "quote", 328 | "syn", 329 | ] 330 | 331 | [[package]] 332 | name = "futures-sink" 333 | version = "0.3.31" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 336 | 337 | [[package]] 338 | name = "futures-task" 339 | version = "0.3.31" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 342 | 343 | [[package]] 344 | name = "futures-util" 345 | version = "0.3.31" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 348 | dependencies = [ 349 | "futures-channel", 350 | "futures-core", 351 | "futures-io", 352 | "futures-macro", 353 | "futures-sink", 354 | "futures-task", 355 | "memchr", 356 | "pin-project-lite", 357 | "pin-utils", 358 | "slab", 359 | ] 360 | 361 | [[package]] 362 | name = "generic-array" 363 | version = "0.14.7" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 366 | dependencies = [ 367 | "typenum", 368 | "version_check", 369 | ] 370 | 371 | [[package]] 372 | name = "getrandom" 373 | version = "0.2.15" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 376 | dependencies = [ 377 | "cfg-if", 378 | "libc", 379 | "wasi", 380 | ] 381 | 382 | [[package]] 383 | name = "gimli" 384 | version = "0.31.1" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 387 | 388 | [[package]] 389 | name = "h2" 390 | version = "0.3.26" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" 393 | dependencies = [ 394 | "bytes", 395 | "fnv", 396 | "futures-core", 397 | "futures-sink", 398 | "futures-util", 399 | "http 0.2.12", 400 | "indexmap", 401 | "slab", 402 | "tokio", 403 | "tokio-util", 404 | "tracing", 405 | ] 406 | 407 | [[package]] 408 | name = "hashbrown" 409 | version = "0.15.2" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 412 | 413 | [[package]] 414 | name = "headers" 415 | version = "0.3.9" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" 418 | dependencies = [ 419 | "base64 0.21.7", 420 | "bytes", 421 | "headers-core", 422 | "http 0.2.12", 423 | "httpdate", 424 | "mime", 425 | "sha1", 426 | ] 427 | 428 | [[package]] 429 | name = "headers-core" 430 | version = "0.2.0" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" 433 | dependencies = [ 434 | "http 0.2.12", 435 | ] 436 | 437 | [[package]] 438 | name = "hermit-abi" 439 | version = "0.4.0" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" 442 | 443 | [[package]] 444 | name = "http" 445 | version = "0.2.12" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" 448 | dependencies = [ 449 | "bytes", 450 | "fnv", 451 | "itoa", 452 | ] 453 | 454 | [[package]] 455 | name = "http" 456 | version = "1.2.0" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" 459 | dependencies = [ 460 | "bytes", 461 | "fnv", 462 | "itoa", 463 | ] 464 | 465 | [[package]] 466 | name = "http-body" 467 | version = "0.4.6" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" 470 | dependencies = [ 471 | "bytes", 472 | "http 0.2.12", 473 | "pin-project-lite", 474 | ] 475 | 476 | [[package]] 477 | name = "httparse" 478 | version = "1.9.5" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" 481 | 482 | [[package]] 483 | name = "httpdate" 484 | version = "1.0.3" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 487 | 488 | [[package]] 489 | name = "humantime" 490 | version = "2.1.0" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 493 | 494 | [[package]] 495 | name = "hyper" 496 | version = "0.14.32" 497 | source = "registry+https://github.com/rust-lang/crates.io-index" 498 | checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" 499 | dependencies = [ 500 | "bytes", 501 | "futures-channel", 502 | "futures-core", 503 | "futures-util", 504 | "h2", 505 | "http 0.2.12", 506 | "http-body", 507 | "httparse", 508 | "httpdate", 509 | "itoa", 510 | "pin-project-lite", 511 | "socket2", 512 | "tokio", 513 | "tower-service", 514 | "tracing", 515 | "want", 516 | ] 517 | 518 | [[package]] 519 | name = "icu_collections" 520 | version = "1.5.0" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 523 | dependencies = [ 524 | "displaydoc", 525 | "yoke", 526 | "zerofrom", 527 | "zerovec", 528 | ] 529 | 530 | [[package]] 531 | name = "icu_locid" 532 | version = "1.5.0" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 535 | dependencies = [ 536 | "displaydoc", 537 | "litemap", 538 | "tinystr", 539 | "writeable", 540 | "zerovec", 541 | ] 542 | 543 | [[package]] 544 | name = "icu_locid_transform" 545 | version = "1.5.0" 546 | source = "registry+https://github.com/rust-lang/crates.io-index" 547 | checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 548 | dependencies = [ 549 | "displaydoc", 550 | "icu_locid", 551 | "icu_locid_transform_data", 552 | "icu_provider", 553 | "tinystr", 554 | "zerovec", 555 | ] 556 | 557 | [[package]] 558 | name = "icu_locid_transform_data" 559 | version = "1.5.0" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" 562 | 563 | [[package]] 564 | name = "icu_normalizer" 565 | version = "1.5.0" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 568 | dependencies = [ 569 | "displaydoc", 570 | "icu_collections", 571 | "icu_normalizer_data", 572 | "icu_properties", 573 | "icu_provider", 574 | "smallvec", 575 | "utf16_iter", 576 | "utf8_iter", 577 | "write16", 578 | "zerovec", 579 | ] 580 | 581 | [[package]] 582 | name = "icu_normalizer_data" 583 | version = "1.5.0" 584 | source = "registry+https://github.com/rust-lang/crates.io-index" 585 | checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" 586 | 587 | [[package]] 588 | name = "icu_properties" 589 | version = "1.5.1" 590 | source = "registry+https://github.com/rust-lang/crates.io-index" 591 | checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 592 | dependencies = [ 593 | "displaydoc", 594 | "icu_collections", 595 | "icu_locid_transform", 596 | "icu_properties_data", 597 | "icu_provider", 598 | "tinystr", 599 | "zerovec", 600 | ] 601 | 602 | [[package]] 603 | name = "icu_properties_data" 604 | version = "1.5.0" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" 607 | 608 | [[package]] 609 | name = "icu_provider" 610 | version = "1.5.0" 611 | source = "registry+https://github.com/rust-lang/crates.io-index" 612 | checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 613 | dependencies = [ 614 | "displaydoc", 615 | "icu_locid", 616 | "icu_provider_macros", 617 | "stable_deref_trait", 618 | "tinystr", 619 | "writeable", 620 | "yoke", 621 | "zerofrom", 622 | "zerovec", 623 | ] 624 | 625 | [[package]] 626 | name = "icu_provider_macros" 627 | version = "1.5.0" 628 | source = "registry+https://github.com/rust-lang/crates.io-index" 629 | checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 630 | dependencies = [ 631 | "proc-macro2", 632 | "quote", 633 | "syn", 634 | ] 635 | 636 | [[package]] 637 | name = "idna" 638 | version = "1.0.3" 639 | source = "registry+https://github.com/rust-lang/crates.io-index" 640 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 641 | dependencies = [ 642 | "idna_adapter", 643 | "smallvec", 644 | "utf8_iter", 645 | ] 646 | 647 | [[package]] 648 | name = "idna_adapter" 649 | version = "1.2.0" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 652 | dependencies = [ 653 | "icu_normalizer", 654 | "icu_properties", 655 | ] 656 | 657 | [[package]] 658 | name = "indexmap" 659 | version = "2.7.0" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" 662 | dependencies = [ 663 | "equivalent", 664 | "hashbrown", 665 | ] 666 | 667 | [[package]] 668 | name = "is-terminal" 669 | version = "0.4.13" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" 672 | dependencies = [ 673 | "hermit-abi", 674 | "libc", 675 | "windows-sys 0.52.0", 676 | ] 677 | 678 | [[package]] 679 | name = "itoa" 680 | version = "1.0.14" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 683 | 684 | [[package]] 685 | name = "libc" 686 | version = "0.2.169" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" 689 | 690 | [[package]] 691 | name = "linux-raw-sys" 692 | version = "0.4.15" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 695 | 696 | [[package]] 697 | name = "litemap" 698 | version = "0.7.4" 699 | source = "registry+https://github.com/rust-lang/crates.io-index" 700 | checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" 701 | 702 | [[package]] 703 | name = "lock_api" 704 | version = "0.4.12" 705 | source = "registry+https://github.com/rust-lang/crates.io-index" 706 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 707 | dependencies = [ 708 | "autocfg", 709 | "scopeguard", 710 | ] 711 | 712 | [[package]] 713 | name = "log" 714 | version = "0.4.22" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 717 | 718 | [[package]] 719 | name = "memchr" 720 | version = "2.7.4" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 723 | 724 | [[package]] 725 | name = "mime" 726 | version = "0.3.17" 727 | source = "registry+https://github.com/rust-lang/crates.io-index" 728 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 729 | 730 | [[package]] 731 | name = "mime_guess" 732 | version = "2.0.5" 733 | source = "registry+https://github.com/rust-lang/crates.io-index" 734 | checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" 735 | dependencies = [ 736 | "mime", 737 | "unicase", 738 | ] 739 | 740 | [[package]] 741 | name = "miniz_oxide" 742 | version = "0.8.3" 743 | source = "registry+https://github.com/rust-lang/crates.io-index" 744 | checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" 745 | dependencies = [ 746 | "adler2", 747 | ] 748 | 749 | [[package]] 750 | name = "mio" 751 | version = "1.0.3" 752 | source = "registry+https://github.com/rust-lang/crates.io-index" 753 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 754 | dependencies = [ 755 | "libc", 756 | "wasi", 757 | "windows-sys 0.52.0", 758 | ] 759 | 760 | [[package]] 761 | name = "multer" 762 | version = "2.1.0" 763 | source = "registry+https://github.com/rust-lang/crates.io-index" 764 | checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" 765 | dependencies = [ 766 | "bytes", 767 | "encoding_rs", 768 | "futures-util", 769 | "http 0.2.12", 770 | "httparse", 771 | "log", 772 | "memchr", 773 | "mime", 774 | "spin", 775 | "version_check", 776 | ] 777 | 778 | [[package]] 779 | name = "native-tls" 780 | version = "0.2.12" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" 783 | dependencies = [ 784 | "libc", 785 | "log", 786 | "openssl", 787 | "openssl-probe", 788 | "openssl-sys", 789 | "schannel", 790 | "security-framework", 791 | "security-framework-sys", 792 | "tempfile", 793 | ] 794 | 795 | [[package]] 796 | name = "object" 797 | version = "0.36.7" 798 | source = "registry+https://github.com/rust-lang/crates.io-index" 799 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 800 | dependencies = [ 801 | "memchr", 802 | ] 803 | 804 | [[package]] 805 | name = "once_cell" 806 | version = "1.20.2" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 809 | 810 | [[package]] 811 | name = "openssl" 812 | version = "0.10.68" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" 815 | dependencies = [ 816 | "bitflags", 817 | "cfg-if", 818 | "foreign-types", 819 | "libc", 820 | "once_cell", 821 | "openssl-macros", 822 | "openssl-sys", 823 | ] 824 | 825 | [[package]] 826 | name = "openssl-macros" 827 | version = "0.1.1" 828 | source = "registry+https://github.com/rust-lang/crates.io-index" 829 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 830 | dependencies = [ 831 | "proc-macro2", 832 | "quote", 833 | "syn", 834 | ] 835 | 836 | [[package]] 837 | name = "openssl-probe" 838 | version = "0.1.5" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 841 | 842 | [[package]] 843 | name = "openssl-sys" 844 | version = "0.9.104" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" 847 | dependencies = [ 848 | "cc", 849 | "libc", 850 | "pkg-config", 851 | "vcpkg", 852 | ] 853 | 854 | [[package]] 855 | name = "parking_lot" 856 | version = "0.12.3" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 859 | dependencies = [ 860 | "lock_api", 861 | "parking_lot_core", 862 | ] 863 | 864 | [[package]] 865 | name = "parking_lot_core" 866 | version = "0.9.10" 867 | source = "registry+https://github.com/rust-lang/crates.io-index" 868 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 869 | dependencies = [ 870 | "cfg-if", 871 | "libc", 872 | "redox_syscall", 873 | "smallvec", 874 | "windows-targets", 875 | ] 876 | 877 | [[package]] 878 | name = "percent-encoding" 879 | version = "2.3.1" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 882 | 883 | [[package]] 884 | name = "pin-project" 885 | version = "1.1.8" 886 | source = "registry+https://github.com/rust-lang/crates.io-index" 887 | checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" 888 | dependencies = [ 889 | "pin-project-internal", 890 | ] 891 | 892 | [[package]] 893 | name = "pin-project-internal" 894 | version = "1.1.8" 895 | source = "registry+https://github.com/rust-lang/crates.io-index" 896 | checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" 897 | dependencies = [ 898 | "proc-macro2", 899 | "quote", 900 | "syn", 901 | ] 902 | 903 | [[package]] 904 | name = "pin-project-lite" 905 | version = "0.2.16" 906 | source = "registry+https://github.com/rust-lang/crates.io-index" 907 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 908 | 909 | [[package]] 910 | name = "pin-utils" 911 | version = "0.1.0" 912 | source = "registry+https://github.com/rust-lang/crates.io-index" 913 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 914 | 915 | [[package]] 916 | name = "pkg-config" 917 | version = "0.3.31" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" 920 | 921 | [[package]] 922 | name = "ppv-lite86" 923 | version = "0.2.20" 924 | source = "registry+https://github.com/rust-lang/crates.io-index" 925 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 926 | dependencies = [ 927 | "zerocopy", 928 | ] 929 | 930 | [[package]] 931 | name = "proc-macro2" 932 | version = "1.0.93" 933 | source = "registry+https://github.com/rust-lang/crates.io-index" 934 | checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" 935 | dependencies = [ 936 | "unicode-ident", 937 | ] 938 | 939 | [[package]] 940 | name = "quote" 941 | version = "1.0.38" 942 | source = "registry+https://github.com/rust-lang/crates.io-index" 943 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 944 | dependencies = [ 945 | "proc-macro2", 946 | ] 947 | 948 | [[package]] 949 | name = "rand" 950 | version = "0.8.5" 951 | source = "registry+https://github.com/rust-lang/crates.io-index" 952 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 953 | dependencies = [ 954 | "libc", 955 | "rand_chacha", 956 | "rand_core", 957 | ] 958 | 959 | [[package]] 960 | name = "rand_chacha" 961 | version = "0.3.1" 962 | source = "registry+https://github.com/rust-lang/crates.io-index" 963 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 964 | dependencies = [ 965 | "ppv-lite86", 966 | "rand_core", 967 | ] 968 | 969 | [[package]] 970 | name = "rand_core" 971 | version = "0.6.4" 972 | source = "registry+https://github.com/rust-lang/crates.io-index" 973 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 974 | dependencies = [ 975 | "getrandom", 976 | ] 977 | 978 | [[package]] 979 | name = "redox_syscall" 980 | version = "0.5.8" 981 | source = "registry+https://github.com/rust-lang/crates.io-index" 982 | checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" 983 | dependencies = [ 984 | "bitflags", 985 | ] 986 | 987 | [[package]] 988 | name = "regex" 989 | version = "1.11.1" 990 | source = "registry+https://github.com/rust-lang/crates.io-index" 991 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 992 | dependencies = [ 993 | "aho-corasick", 994 | "memchr", 995 | "regex-automata", 996 | "regex-syntax", 997 | ] 998 | 999 | [[package]] 1000 | name = "regex-automata" 1001 | version = "0.4.9" 1002 | source = "registry+https://github.com/rust-lang/crates.io-index" 1003 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 1004 | dependencies = [ 1005 | "aho-corasick", 1006 | "memchr", 1007 | "regex-syntax", 1008 | ] 1009 | 1010 | [[package]] 1011 | name = "regex-syntax" 1012 | version = "0.8.5" 1013 | source = "registry+https://github.com/rust-lang/crates.io-index" 1014 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1015 | 1016 | [[package]] 1017 | name = "ring" 1018 | version = "0.17.8" 1019 | source = "registry+https://github.com/rust-lang/crates.io-index" 1020 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 1021 | dependencies = [ 1022 | "cc", 1023 | "cfg-if", 1024 | "getrandom", 1025 | "libc", 1026 | "spin", 1027 | "untrusted", 1028 | "windows-sys 0.52.0", 1029 | ] 1030 | 1031 | [[package]] 1032 | name = "rustc-demangle" 1033 | version = "0.1.24" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1036 | 1037 | [[package]] 1038 | name = "rustix" 1039 | version = "0.38.43" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" 1042 | dependencies = [ 1043 | "bitflags", 1044 | "errno", 1045 | "libc", 1046 | "linux-raw-sys", 1047 | "windows-sys 0.59.0", 1048 | ] 1049 | 1050 | [[package]] 1051 | name = "rustls" 1052 | version = "0.21.12" 1053 | source = "registry+https://github.com/rust-lang/crates.io-index" 1054 | checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" 1055 | dependencies = [ 1056 | "log", 1057 | "ring", 1058 | "rustls-webpki", 1059 | "sct", 1060 | ] 1061 | 1062 | [[package]] 1063 | name = "rustls-pemfile" 1064 | version = "0.2.1" 1065 | source = "registry+https://github.com/rust-lang/crates.io-index" 1066 | checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" 1067 | dependencies = [ 1068 | "base64 0.13.1", 1069 | ] 1070 | 1071 | [[package]] 1072 | name = "rustls-webpki" 1073 | version = "0.101.7" 1074 | source = "registry+https://github.com/rust-lang/crates.io-index" 1075 | checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" 1076 | dependencies = [ 1077 | "ring", 1078 | "untrusted", 1079 | ] 1080 | 1081 | [[package]] 1082 | name = "ryu" 1083 | version = "1.0.18" 1084 | source = "registry+https://github.com/rust-lang/crates.io-index" 1085 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1086 | 1087 | [[package]] 1088 | name = "schannel" 1089 | version = "0.1.27" 1090 | source = "registry+https://github.com/rust-lang/crates.io-index" 1091 | checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" 1092 | dependencies = [ 1093 | "windows-sys 0.59.0", 1094 | ] 1095 | 1096 | [[package]] 1097 | name = "scoped-tls" 1098 | version = "1.0.1" 1099 | source = "registry+https://github.com/rust-lang/crates.io-index" 1100 | checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" 1101 | 1102 | [[package]] 1103 | name = "scopeguard" 1104 | version = "1.2.0" 1105 | source = "registry+https://github.com/rust-lang/crates.io-index" 1106 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1107 | 1108 | [[package]] 1109 | name = "sct" 1110 | version = "0.7.1" 1111 | source = "registry+https://github.com/rust-lang/crates.io-index" 1112 | checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" 1113 | dependencies = [ 1114 | "ring", 1115 | "untrusted", 1116 | ] 1117 | 1118 | [[package]] 1119 | name = "security-framework" 1120 | version = "2.11.1" 1121 | source = "registry+https://github.com/rust-lang/crates.io-index" 1122 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1123 | dependencies = [ 1124 | "bitflags", 1125 | "core-foundation", 1126 | "core-foundation-sys", 1127 | "libc", 1128 | "security-framework-sys", 1129 | ] 1130 | 1131 | [[package]] 1132 | name = "security-framework-sys" 1133 | version = "2.14.0" 1134 | source = "registry+https://github.com/rust-lang/crates.io-index" 1135 | checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" 1136 | dependencies = [ 1137 | "core-foundation-sys", 1138 | "libc", 1139 | ] 1140 | 1141 | [[package]] 1142 | name = "serde" 1143 | version = "1.0.217" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" 1146 | dependencies = [ 1147 | "serde_derive", 1148 | ] 1149 | 1150 | [[package]] 1151 | name = "serde_derive" 1152 | version = "1.0.217" 1153 | source = "registry+https://github.com/rust-lang/crates.io-index" 1154 | checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" 1155 | dependencies = [ 1156 | "proc-macro2", 1157 | "quote", 1158 | "syn", 1159 | ] 1160 | 1161 | [[package]] 1162 | name = "serde_json" 1163 | version = "1.0.135" 1164 | source = "registry+https://github.com/rust-lang/crates.io-index" 1165 | checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" 1166 | dependencies = [ 1167 | "itoa", 1168 | "memchr", 1169 | "ryu", 1170 | "serde", 1171 | ] 1172 | 1173 | [[package]] 1174 | name = "serde_urlencoded" 1175 | version = "0.7.1" 1176 | source = "registry+https://github.com/rust-lang/crates.io-index" 1177 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1178 | dependencies = [ 1179 | "form_urlencoded", 1180 | "itoa", 1181 | "ryu", 1182 | "serde", 1183 | ] 1184 | 1185 | [[package]] 1186 | name = "sha1" 1187 | version = "0.10.6" 1188 | source = "registry+https://github.com/rust-lang/crates.io-index" 1189 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1190 | dependencies = [ 1191 | "cfg-if", 1192 | "cpufeatures", 1193 | "digest", 1194 | ] 1195 | 1196 | [[package]] 1197 | name = "shlex" 1198 | version = "1.3.0" 1199 | source = "registry+https://github.com/rust-lang/crates.io-index" 1200 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1201 | 1202 | [[package]] 1203 | name = "signal-hook-registry" 1204 | version = "1.4.2" 1205 | source = "registry+https://github.com/rust-lang/crates.io-index" 1206 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 1207 | dependencies = [ 1208 | "libc", 1209 | ] 1210 | 1211 | [[package]] 1212 | name = "slab" 1213 | version = "0.4.9" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1216 | dependencies = [ 1217 | "autocfg", 1218 | ] 1219 | 1220 | [[package]] 1221 | name = "smallvec" 1222 | version = "1.13.2" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1225 | 1226 | [[package]] 1227 | name = "socket2" 1228 | version = "0.5.8" 1229 | source = "registry+https://github.com/rust-lang/crates.io-index" 1230 | checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" 1231 | dependencies = [ 1232 | "libc", 1233 | "windows-sys 0.52.0", 1234 | ] 1235 | 1236 | [[package]] 1237 | name = "spin" 1238 | version = "0.9.8" 1239 | source = "registry+https://github.com/rust-lang/crates.io-index" 1240 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1241 | 1242 | [[package]] 1243 | name = "stable_deref_trait" 1244 | version = "1.2.0" 1245 | source = "registry+https://github.com/rust-lang/crates.io-index" 1246 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1247 | 1248 | [[package]] 1249 | name = "syn" 1250 | version = "2.0.96" 1251 | source = "registry+https://github.com/rust-lang/crates.io-index" 1252 | checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" 1253 | dependencies = [ 1254 | "proc-macro2", 1255 | "quote", 1256 | "unicode-ident", 1257 | ] 1258 | 1259 | [[package]] 1260 | name = "synstructure" 1261 | version = "0.13.1" 1262 | source = "registry+https://github.com/rust-lang/crates.io-index" 1263 | checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 1264 | dependencies = [ 1265 | "proc-macro2", 1266 | "quote", 1267 | "syn", 1268 | ] 1269 | 1270 | [[package]] 1271 | name = "tempfile" 1272 | version = "3.15.0" 1273 | source = "registry+https://github.com/rust-lang/crates.io-index" 1274 | checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" 1275 | dependencies = [ 1276 | "cfg-if", 1277 | "fastrand", 1278 | "getrandom", 1279 | "once_cell", 1280 | "rustix", 1281 | "windows-sys 0.59.0", 1282 | ] 1283 | 1284 | [[package]] 1285 | name = "termcolor" 1286 | version = "1.4.1" 1287 | source = "registry+https://github.com/rust-lang/crates.io-index" 1288 | checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" 1289 | dependencies = [ 1290 | "winapi-util", 1291 | ] 1292 | 1293 | [[package]] 1294 | name = "thiserror" 1295 | version = "1.0.69" 1296 | source = "registry+https://github.com/rust-lang/crates.io-index" 1297 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1298 | dependencies = [ 1299 | "thiserror-impl", 1300 | ] 1301 | 1302 | [[package]] 1303 | name = "thiserror-impl" 1304 | version = "1.0.69" 1305 | source = "registry+https://github.com/rust-lang/crates.io-index" 1306 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 1307 | dependencies = [ 1308 | "proc-macro2", 1309 | "quote", 1310 | "syn", 1311 | ] 1312 | 1313 | [[package]] 1314 | name = "tinystr" 1315 | version = "0.7.6" 1316 | source = "registry+https://github.com/rust-lang/crates.io-index" 1317 | checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 1318 | dependencies = [ 1319 | "displaydoc", 1320 | "zerovec", 1321 | ] 1322 | 1323 | [[package]] 1324 | name = "tokio" 1325 | version = "1.43.0" 1326 | source = "registry+https://github.com/rust-lang/crates.io-index" 1327 | checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" 1328 | dependencies = [ 1329 | "backtrace", 1330 | "bytes", 1331 | "libc", 1332 | "mio", 1333 | "parking_lot", 1334 | "pin-project-lite", 1335 | "signal-hook-registry", 1336 | "socket2", 1337 | "tokio-macros", 1338 | "windows-sys 0.52.0", 1339 | ] 1340 | 1341 | [[package]] 1342 | name = "tokio-macros" 1343 | version = "2.5.0" 1344 | source = "registry+https://github.com/rust-lang/crates.io-index" 1345 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 1346 | dependencies = [ 1347 | "proc-macro2", 1348 | "quote", 1349 | "syn", 1350 | ] 1351 | 1352 | [[package]] 1353 | name = "tokio-native-tls" 1354 | version = "0.3.1" 1355 | source = "registry+https://github.com/rust-lang/crates.io-index" 1356 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 1357 | dependencies = [ 1358 | "native-tls", 1359 | "tokio", 1360 | ] 1361 | 1362 | [[package]] 1363 | name = "tokio-rustls" 1364 | version = "0.24.1" 1365 | source = "registry+https://github.com/rust-lang/crates.io-index" 1366 | checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" 1367 | dependencies = [ 1368 | "rustls", 1369 | "tokio", 1370 | ] 1371 | 1372 | [[package]] 1373 | name = "tokio-socks" 1374 | version = "0.5.2" 1375 | source = "registry+https://github.com/rust-lang/crates.io-index" 1376 | checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f" 1377 | dependencies = [ 1378 | "either", 1379 | "futures-util", 1380 | "thiserror", 1381 | "tokio", 1382 | ] 1383 | 1384 | [[package]] 1385 | name = "tokio-tungstenite" 1386 | version = "0.20.1" 1387 | source = "registry+https://github.com/rust-lang/crates.io-index" 1388 | checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" 1389 | dependencies = [ 1390 | "futures-util", 1391 | "log", 1392 | "native-tls", 1393 | "tokio", 1394 | "tokio-native-tls", 1395 | "tungstenite 0.20.1", 1396 | ] 1397 | 1398 | [[package]] 1399 | name = "tokio-tungstenite" 1400 | version = "0.21.0" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" 1403 | dependencies = [ 1404 | "futures-util", 1405 | "log", 1406 | "tokio", 1407 | "tungstenite 0.21.0", 1408 | ] 1409 | 1410 | [[package]] 1411 | name = "tokio-util" 1412 | version = "0.7.13" 1413 | source = "registry+https://github.com/rust-lang/crates.io-index" 1414 | checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" 1415 | dependencies = [ 1416 | "bytes", 1417 | "futures-core", 1418 | "futures-sink", 1419 | "pin-project-lite", 1420 | "tokio", 1421 | ] 1422 | 1423 | [[package]] 1424 | name = "tower-service" 1425 | version = "0.3.3" 1426 | source = "registry+https://github.com/rust-lang/crates.io-index" 1427 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 1428 | 1429 | [[package]] 1430 | name = "tracing" 1431 | version = "0.1.41" 1432 | source = "registry+https://github.com/rust-lang/crates.io-index" 1433 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 1434 | dependencies = [ 1435 | "log", 1436 | "pin-project-lite", 1437 | "tracing-core", 1438 | ] 1439 | 1440 | [[package]] 1441 | name = "tracing-core" 1442 | version = "0.1.33" 1443 | source = "registry+https://github.com/rust-lang/crates.io-index" 1444 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 1445 | dependencies = [ 1446 | "once_cell", 1447 | ] 1448 | 1449 | [[package]] 1450 | name = "try-lock" 1451 | version = "0.2.5" 1452 | source = "registry+https://github.com/rust-lang/crates.io-index" 1453 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1454 | 1455 | [[package]] 1456 | name = "tungstenite" 1457 | version = "0.20.1" 1458 | source = "registry+https://github.com/rust-lang/crates.io-index" 1459 | checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" 1460 | dependencies = [ 1461 | "byteorder", 1462 | "bytes", 1463 | "data-encoding", 1464 | "http 0.2.12", 1465 | "httparse", 1466 | "log", 1467 | "native-tls", 1468 | "rand", 1469 | "sha1", 1470 | "thiserror", 1471 | "url", 1472 | "utf-8", 1473 | ] 1474 | 1475 | [[package]] 1476 | name = "tungstenite" 1477 | version = "0.21.0" 1478 | source = "registry+https://github.com/rust-lang/crates.io-index" 1479 | checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" 1480 | dependencies = [ 1481 | "byteorder", 1482 | "bytes", 1483 | "data-encoding", 1484 | "http 1.2.0", 1485 | "httparse", 1486 | "log", 1487 | "rand", 1488 | "sha1", 1489 | "thiserror", 1490 | "url", 1491 | "utf-8", 1492 | ] 1493 | 1494 | [[package]] 1495 | name = "typenum" 1496 | version = "1.17.0" 1497 | source = "registry+https://github.com/rust-lang/crates.io-index" 1498 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1499 | 1500 | [[package]] 1501 | name = "unicase" 1502 | version = "2.8.1" 1503 | source = "registry+https://github.com/rust-lang/crates.io-index" 1504 | checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" 1505 | 1506 | [[package]] 1507 | name = "unicode-ident" 1508 | version = "1.0.14" 1509 | source = "registry+https://github.com/rust-lang/crates.io-index" 1510 | checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" 1511 | 1512 | [[package]] 1513 | name = "untrusted" 1514 | version = "0.9.0" 1515 | source = "registry+https://github.com/rust-lang/crates.io-index" 1516 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1517 | 1518 | [[package]] 1519 | name = "url" 1520 | version = "2.5.4" 1521 | source = "registry+https://github.com/rust-lang/crates.io-index" 1522 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 1523 | dependencies = [ 1524 | "form_urlencoded", 1525 | "idna", 1526 | "percent-encoding", 1527 | ] 1528 | 1529 | [[package]] 1530 | name = "utf-8" 1531 | version = "0.7.6" 1532 | source = "registry+https://github.com/rust-lang/crates.io-index" 1533 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 1534 | 1535 | [[package]] 1536 | name = "utf16_iter" 1537 | version = "1.0.5" 1538 | source = "registry+https://github.com/rust-lang/crates.io-index" 1539 | checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 1540 | 1541 | [[package]] 1542 | name = "utf8_iter" 1543 | version = "1.0.4" 1544 | source = "registry+https://github.com/rust-lang/crates.io-index" 1545 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1546 | 1547 | [[package]] 1548 | name = "vcpkg" 1549 | version = "0.2.15" 1550 | source = "registry+https://github.com/rust-lang/crates.io-index" 1551 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1552 | 1553 | [[package]] 1554 | name = "version_check" 1555 | version = "0.9.5" 1556 | source = "registry+https://github.com/rust-lang/crates.io-index" 1557 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1558 | 1559 | [[package]] 1560 | name = "want" 1561 | version = "0.3.1" 1562 | source = "registry+https://github.com/rust-lang/crates.io-index" 1563 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1564 | dependencies = [ 1565 | "try-lock", 1566 | ] 1567 | 1568 | [[package]] 1569 | name = "warp" 1570 | version = "0.3.7" 1571 | source = "registry+https://github.com/rust-lang/crates.io-index" 1572 | checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" 1573 | dependencies = [ 1574 | "bytes", 1575 | "futures-channel", 1576 | "futures-util", 1577 | "headers", 1578 | "http 0.2.12", 1579 | "hyper", 1580 | "log", 1581 | "mime", 1582 | "mime_guess", 1583 | "multer", 1584 | "percent-encoding", 1585 | "pin-project", 1586 | "scoped-tls", 1587 | "serde", 1588 | "serde_json", 1589 | "serde_urlencoded", 1590 | "tokio", 1591 | "tokio-tungstenite 0.21.0", 1592 | "tokio-util", 1593 | "tower-service", 1594 | "tracing", 1595 | ] 1596 | 1597 | [[package]] 1598 | name = "wasi" 1599 | version = "0.11.0+wasi-snapshot-preview1" 1600 | source = "registry+https://github.com/rust-lang/crates.io-index" 1601 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1602 | 1603 | [[package]] 1604 | name = "winapi-util" 1605 | version = "0.1.9" 1606 | source = "registry+https://github.com/rust-lang/crates.io-index" 1607 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 1608 | dependencies = [ 1609 | "windows-sys 0.59.0", 1610 | ] 1611 | 1612 | [[package]] 1613 | name = "windows-sys" 1614 | version = "0.52.0" 1615 | source = "registry+https://github.com/rust-lang/crates.io-index" 1616 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1617 | dependencies = [ 1618 | "windows-targets", 1619 | ] 1620 | 1621 | [[package]] 1622 | name = "windows-sys" 1623 | version = "0.59.0" 1624 | source = "registry+https://github.com/rust-lang/crates.io-index" 1625 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1626 | dependencies = [ 1627 | "windows-targets", 1628 | ] 1629 | 1630 | [[package]] 1631 | name = "windows-targets" 1632 | version = "0.52.6" 1633 | source = "registry+https://github.com/rust-lang/crates.io-index" 1634 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1635 | dependencies = [ 1636 | "windows_aarch64_gnullvm", 1637 | "windows_aarch64_msvc", 1638 | "windows_i686_gnu", 1639 | "windows_i686_gnullvm", 1640 | "windows_i686_msvc", 1641 | "windows_x86_64_gnu", 1642 | "windows_x86_64_gnullvm", 1643 | "windows_x86_64_msvc", 1644 | ] 1645 | 1646 | [[package]] 1647 | name = "windows_aarch64_gnullvm" 1648 | version = "0.52.6" 1649 | source = "registry+https://github.com/rust-lang/crates.io-index" 1650 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1651 | 1652 | [[package]] 1653 | name = "windows_aarch64_msvc" 1654 | version = "0.52.6" 1655 | source = "registry+https://github.com/rust-lang/crates.io-index" 1656 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1657 | 1658 | [[package]] 1659 | name = "windows_i686_gnu" 1660 | version = "0.52.6" 1661 | source = "registry+https://github.com/rust-lang/crates.io-index" 1662 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1663 | 1664 | [[package]] 1665 | name = "windows_i686_gnullvm" 1666 | version = "0.52.6" 1667 | source = "registry+https://github.com/rust-lang/crates.io-index" 1668 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1669 | 1670 | [[package]] 1671 | name = "windows_i686_msvc" 1672 | version = "0.52.6" 1673 | source = "registry+https://github.com/rust-lang/crates.io-index" 1674 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1675 | 1676 | [[package]] 1677 | name = "windows_x86_64_gnu" 1678 | version = "0.52.6" 1679 | source = "registry+https://github.com/rust-lang/crates.io-index" 1680 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1681 | 1682 | [[package]] 1683 | name = "windows_x86_64_gnullvm" 1684 | version = "0.52.6" 1685 | source = "registry+https://github.com/rust-lang/crates.io-index" 1686 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1687 | 1688 | [[package]] 1689 | name = "windows_x86_64_msvc" 1690 | version = "0.52.6" 1691 | source = "registry+https://github.com/rust-lang/crates.io-index" 1692 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1693 | 1694 | [[package]] 1695 | name = "write16" 1696 | version = "1.0.0" 1697 | source = "registry+https://github.com/rust-lang/crates.io-index" 1698 | checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 1699 | 1700 | [[package]] 1701 | name = "writeable" 1702 | version = "0.5.5" 1703 | source = "registry+https://github.com/rust-lang/crates.io-index" 1704 | checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 1705 | 1706 | [[package]] 1707 | name = "yoke" 1708 | version = "0.7.5" 1709 | source = "registry+https://github.com/rust-lang/crates.io-index" 1710 | checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 1711 | dependencies = [ 1712 | "serde", 1713 | "stable_deref_trait", 1714 | "yoke-derive", 1715 | "zerofrom", 1716 | ] 1717 | 1718 | [[package]] 1719 | name = "yoke-derive" 1720 | version = "0.7.5" 1721 | source = "registry+https://github.com/rust-lang/crates.io-index" 1722 | checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 1723 | dependencies = [ 1724 | "proc-macro2", 1725 | "quote", 1726 | "syn", 1727 | "synstructure", 1728 | ] 1729 | 1730 | [[package]] 1731 | name = "zerocopy" 1732 | version = "0.7.35" 1733 | source = "registry+https://github.com/rust-lang/crates.io-index" 1734 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 1735 | dependencies = [ 1736 | "byteorder", 1737 | "zerocopy-derive", 1738 | ] 1739 | 1740 | [[package]] 1741 | name = "zerocopy-derive" 1742 | version = "0.7.35" 1743 | source = "registry+https://github.com/rust-lang/crates.io-index" 1744 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 1745 | dependencies = [ 1746 | "proc-macro2", 1747 | "quote", 1748 | "syn", 1749 | ] 1750 | 1751 | [[package]] 1752 | name = "zerofrom" 1753 | version = "0.1.5" 1754 | source = "registry+https://github.com/rust-lang/crates.io-index" 1755 | checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" 1756 | dependencies = [ 1757 | "zerofrom-derive", 1758 | ] 1759 | 1760 | [[package]] 1761 | name = "zerofrom-derive" 1762 | version = "0.1.5" 1763 | source = "registry+https://github.com/rust-lang/crates.io-index" 1764 | checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" 1765 | dependencies = [ 1766 | "proc-macro2", 1767 | "quote", 1768 | "syn", 1769 | "synstructure", 1770 | ] 1771 | 1772 | [[package]] 1773 | name = "zerovec" 1774 | version = "0.10.4" 1775 | source = "registry+https://github.com/rust-lang/crates.io-index" 1776 | checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 1777 | dependencies = [ 1778 | "yoke", 1779 | "zerofrom", 1780 | "zerovec-derive", 1781 | ] 1782 | 1783 | [[package]] 1784 | name = "zerovec-derive" 1785 | version = "0.10.3" 1786 | source = "registry+https://github.com/rust-lang/crates.io-index" 1787 | checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 1788 | dependencies = [ 1789 | "proc-macro2", 1790 | "quote", 1791 | "syn", 1792 | ] 1793 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fortifynet_proxy" 3 | version = "2.0.0" 4 | edition = "2021" 5 | license = "MIT" 6 | authors = ["Jenin Sutradhar"] 7 | description = "A flexible asynchronous proxy server library written in Rust." 8 | 9 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 10 | 11 | [dependencies] 12 | tokio = { version = "1", features = ["full"] } 13 | hyper = { version = "0.14", features = ["client","http1","server","tcp"] } 14 | log = "0.4" 15 | env_logger = "0.10" 16 | thiserror = "1" 17 | anyhow = "1" 18 | rustls = "0.21" 19 | tokio-rustls = "0.24" 20 | tokio-tungstenite = { version = "0.20", features = ["native-tls"] } 21 | warp = "0.3" 22 | futures = "0.3" 23 | url = "2.5" 24 | # socks5-impl = "0.6.0" 25 | rustls-pemfile = "0.2" 26 | tokio-socks = "0.5.2" 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Jenin Sutradhar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🛡️ FortifyNet Proxy v2 2 | 3 | [![crates.io](https://img.shields.io/crates/v/fortifynet_proxy.svg)](https://crates.io/crates/fortifynet_proxy) 4 | [![docs.rs](https://docs.rs/fortifynet_proxy/badge.svg)](https://docs.rs/fortifynet_proxy) 5 | [![GitHub](https://img.shields.io/github/stars/JeninSutradhar/fortifynet_proxy?style=social)](https://github.com/JeninSutradhar/fortifynet_proxy) 6 | 7 | **FortifyNet Proxy** is a powerful and flexible asynchronous proxy server library written in Rust. It's designed to be a robust and reusable foundation for building various types of proxy servers, including HTTP, HTTPS, and SOCKS5, with a focus on performance, security, and ease of use. 8 | 9 | ## Features 10 | 11 | * **Asynchronous Architecture:** Built using `tokio` for handling numerous concurrent connections with optimal efficiency. 12 | * **HTTP/HTTPS Proxying:** Seamlessly forwards HTTP and HTTPS traffic, ensuring compatibility and security using `hyper` and `tokio-rustls`. 13 | * **SOCKS5 Proxy Support:** Capable of routing traffic through SOCKS5 proxies using `tokio-socks`, enabling advanced network configurations. 14 | * **Request Caching:** Implements an in-memory cache to store responses for frequently accessed resources to reduce load and improve response times. 15 | * **Real-Time Metrics:** Provides built-in real-time traffic statistics, response time analysis, and error tracking. 16 | * **Dashboard:** Includes a simple web-based dashboard using `warp` for live monitoring of the server. 17 | * **Highly Configurable:** Offers a flexible `ProxyConfig` struct to customize various proxy server settings. 18 | * **Authentication:** Supports basic username/password authentication for controlling proxy access. 19 | * **Dynamic Target Resolution**: Resolves the host address from the request and redirects the request dynamically. 20 | 21 | ## 📦 Installation 22 | 23 | To use FortifyNet Proxy in your Rust project, add the following line to your `Cargo.toml` file: 24 | 25 | ```toml 26 | [dependencies] 27 | fortifynet_proxy = "2.0.0" # Or the latest Version 28 | tokio = { version = "1", features = ["full"] } 29 | hyper = { version = "0.14", features = ["client","http1","server","tcp"] } 30 | log = "0.4" 31 | env_logger = "0.10" 32 | thiserror = "1" 33 | anyhow = "1" 34 | rustls = "0.21" 35 | tokio-rustls = "0.24" 36 | tokio-socks = "0.3" 37 | url = "2.5" 38 | warp = "0.3" 39 | rustls-pemfile = "1.1" 40 | ``` 41 | 42 | ## Basic Usage 43 | 44 | Here's how you can quickly set up a basic HTTP proxy server with FortifyNet Proxy: 45 | 46 | 1. **Set up your main file (`main.rs`)** 47 | 48 | ```rust 49 | use fortifynet_proxy::{start_proxy_server, ProxyConfig}; 50 | use log::info; 51 | 52 | #[tokio::main] 53 | async fn main() -> anyhow::Result<()> { 54 | 55 | // Create a proxy configuration with default values 56 | let config = ProxyConfig { 57 | ip_address: "127.0.0.1".to_string(), 58 | port: 8080, 59 | authentication: false, 60 | username: "admin".to_string(), 61 | password: "password".to_string(), 62 | cache_enabled: true, 63 | socks5_address: None, 64 | https_enabled: false, 65 | certificate_path: None, 66 | private_key_path: None, 67 | target_address: Some("http://localhost".to_string()) // target for non-socks connection 68 | }; 69 | info!("Starting Proxy server with configuration: {:?}", config); 70 | // Start the proxy server with the provided configuration 71 | start_proxy_server(config).await?; 72 | Ok(()) 73 | } 74 | ``` 75 | 76 | 2. **Start the Proxy Server:** 77 | 78 | Run `cargo run` in your terminal. The proxy server will start listening for connections. You can monitor the server's output for logs and metrics. 79 | 80 | 3. **Configure Your Client:** 81 | 82 | * **Web Browser:** 83 | * **Proxy Type:** HTTP 84 | * **Address:** `127.0.0.1` 85 | * **Port:** `8080` (or the port you configured) 86 | 87 | * **`curl` Command:** 88 | 89 | ```bash 90 | curl -v --proxy http://127.0.0.1:8080 http://www.example.com 91 | ``` 92 | * **HTTPS Proxy:** 93 | If you enable `https_enabled` then your proxy will be listening to https requests and you need to configure your client for https proxy, you also need to create the certificate and key files. 94 | ```bash 95 | curl -v --proxy https://127.0.0.1:8080 https://www.example.com 96 | ``` 97 | 98 | 4. **Access Metrics Dashboard** 99 | Open a web browser and navigate to `http://127.0.0.1:`. For the above example, this is `http://127.0.0.1:9080`. 100 | 101 | ## Advanced Usage 102 | 103 | ### Enabling Authentication 104 | 105 | To secure your proxy server with basic authentication: 106 | 107 | ```rust 108 | let config = ProxyConfig { 109 | ip_address: "127.0.0.1".to_string(), 110 | port: 8080, 111 | authentication: true, // Enable authentication 112 | username: "admin".to_string(), 113 | password: "password".to_string(), 114 | cache_enabled: true, 115 | socks5_address: None, 116 | https_enabled: false, 117 | certificate_path: None, 118 | private_key_path: None, 119 | target_address: None, 120 | }; 121 | ``` 122 | When `authentication` is enabled, the user will have to provide the authentication header. 123 | 124 | ### Using a SOCKS5 Proxy 125 | 126 | To forward your requests through a SOCKS5 proxy: 127 | 128 | ```rust 129 | let config = ProxyConfig { 130 | ip_address: "127.0.0.1".to_string(), 131 | port: 8080, 132 | authentication: false, 133 | username: "".to_string(), 134 | password: "".to_string(), 135 | cache_enabled: true, 136 | socks5_address: Some("127.0.0.1:1080".to_string()), // Using SOCKS5 137 | https_enabled: false, 138 | certificate_path: None, 139 | private_key_path: None, 140 | target_address: None, 141 | }; 142 | ``` 143 | 144 | * Use the `curl` command with the `--socks5` option. 145 | 146 | ```bash 147 | curl -v --socks5 127.0.0.1:1080 http://www.example.com 148 | ``` 149 | 150 | ### Enabling HTTPS Support 151 | 152 | To enable HTTPS for secure connections, you need to specify the certificate and key file paths 153 | 154 | ```rust 155 | let config = ProxyConfig { 156 | ip_address: "127.0.0.1".to_string(), 157 | port: 8080, 158 | authentication: false, 159 | username: "".to_string(), 160 | password: "".to_string(), 161 | cache_enabled: true, 162 | socks5_address: None, 163 | https_enabled: true, // Enable HTTPS 164 | certificate_path: Some("cert.pem".to_string()), 165 | private_key_path: Some("key.pem".to_string()), 166 | target_address: None, 167 | }; 168 | ``` 169 | You will also need to generate your own certificates and key files. 170 | ```bash 171 | openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost' 172 | ``` 173 | * **Important Note**: Always use valid certificates from a trusted CA in production environments. 174 | 175 | ### Specify Target Address 176 | 177 | If you are not using SOCKS5 and want to use direct connection and forward your request to a specific address you can use the `target_address` field. 178 | 179 | ```rust 180 | let config = ProxyConfig { 181 | ip_address: "127.0.0.1".to_string(), 182 | port: 8080, 183 | authentication: false, 184 | username: "".to_string(), 185 | password: "".to_string(), 186 | cache_enabled: true, 187 | socks5_address: None, 188 | https_enabled: false, 189 | certificate_path: None, 190 | private_key_path: None, 191 | target_address: Some("http://www.google.com".to_string()), 192 | }; 193 | ``` 194 | 195 | ### Advanced Configuration Options 196 | 197 | The `ProxyConfig` struct offers several configuration options, allowing you to customize your proxy server: 198 | 199 | * `ip_address`: Binds the proxy to a specific IP address (e.g., "0.0.0.0" for all interfaces). 200 | * `port`: Specifies the port on which the proxy server listens. 201 | * `authentication`: Enables or disables basic authentication for the proxy. 202 | * `username` and `password`: Set the username and password for authentication (if enabled). 203 | * `cache_enabled`: Enables or disables response caching. 204 | * `socks5_address`: Sets an optional SOCKS5 server address for routing traffic. 205 | * `https_enabled`: Enables or disables HTTPS support. 206 | * `certificate_path` and `private_key_path`: Set the paths to the SSL certificates and key file if HTTPS is enabled. 207 | * `target_address`: Sets the target address for direct connections. 208 | 209 | ## Real-Time Metrics and Monitoring 210 | ![image](https://github.com/user-attachments/assets/83b04616-8d94-45cf-96be-7a57a1665480) 211 | 212 | * **Live Metrics**: Access the dashboard at `http://127.0.0.1:` in your browser to view real-time metrics about the proxy server, including total requests, average response times, cache hit/miss rates, and error counts. 213 | * **Console Logs**: Check the console output where the proxy server is running for detailed logs of incoming connections, requests, responses, and any errors encountered. 214 | 215 | ## Improvements from Previous Versions 216 | 217 | * **Dynamic Target Resolution**: Previously the proxy would forward all requests to a static target, but now it forwards the request to the actual target specified in the request URL. 218 | * **Corrected Direct Connection Handling**: Fixed the issues for direct connection by creating a complete URL. 219 | * **Corrected SOCKS5 Connections**: Fixed the SOCKS5 connect logic by using host and port separately. 220 | * **Improved Caching**: Caching logic is improved to make the proxy more robust. 221 | * **Enhanced Error Handling**: Improved error handling with `anyhow` and comprehensive logging. 222 | * **Code Clarity**: Improved the readability of code and proper documentation. 223 | * **Metrics**: Metrics has been implemented to get the required data regarding the traffic. 224 | * **Dashboard**: Dashboard has been implemented to get view the metrics. 225 | * **Documentation**: A comprehensive documentation is added to explain every feature. 226 | 227 | ## 🔗 Further Resources 228 | 229 | * **Project Crate**: [https://crates.io/crates/fortifynet_proxy](https://crates.io/crates/fortifynet_proxy) 230 | * **GitHub Repository**: [https://github.com/JeninSutradhar/fortifynet_proxy](https://github.com/JeninSutradhar/fortifynet_proxy) 231 | * **GitHub Official**: [https://github.com/JeninSutradhar/](https://github.com/JeninSutradhar/) 232 | 233 | ## ⚖️ License 234 | 235 | Licensed under the MIT License. See the `LICENSE` file for details. 236 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # FortifyNet Proxy 2 | //! 3 | //! A flexible and asynchronous proxy server library built with Rust. 4 | //! 5 | //! This crate provides a robust foundation for building various proxy servers, 6 | //! including HTTP, HTTPS, and SOCKS5 proxies. It also features built-in 7 | //! metrics, caching, and a simple dashboard for monitoring. 8 | //! 9 | //! ## Features 10 | //! 11 | //! * **Asynchronous I/O:** Built with `tokio` for efficient handling of concurrent connections. 12 | //! * **HTTP/HTTPS Proxying:** Handles both HTTP and HTTPS traffic using `hyper` and `tokio-rustls`. 13 | //! * **SOCKS5 Proxy Support:** Supports proxying through SOCKS5 servers using `tokio-socks`. 14 | //! * **Request Caching:** Implements a simple in-memory cache for responses. 15 | //! * **Built-in Metrics:** Provides real-time traffic statistics, error tracking, and response time analysis. 16 | //! * **Basic Dashboard:** Includes a simple web-based dashboard using `warp` for live metrics. 17 | //! * **Configurable:** Highly configurable through the `ProxyConfig` struct. 18 | //! 19 | //! ## Getting Started 20 | //! 21 | //! To use this library, add the following to your `Cargo.toml`: 22 | //! 23 | //! ```toml 24 | //! [dependencies] 25 | //! fortifynet_proxy = "1.1.9" # Or the latest version 26 | //! tokio = { version = "1", features = ["full"] } 27 | //! hyper = { version = "0.14", features = ["client","http1","server","tcp"] } 28 | //! log = "0.4" 29 | //! env_logger = "0.10" 30 | //! thiserror = "1" 31 | //! anyhow = "1" 32 | //! rustls = "0.21" 33 | //! tokio-rustls = "0.24" 34 | //! tokio-socks = "0.3" 35 | //! url = "2.5" 36 | //! warp = "0.3" 37 | //! rustls-pemfile = "1.1" 38 | //! ``` 39 | //! 40 | //! Then, in your `main.rs` or library code, use the `start_proxy_server` function to start a proxy server. 41 | //! 42 | //! ```rust 43 | //! use fortifynet_proxy::{start_proxy_server, ProxyConfig}; 44 | //! use log::info; 45 | //! 46 | //! #[tokio::main] 47 | //! async fn main() -> anyhow::Result<()> { 48 | //! 49 | //! // Create a proxy configuration with default values 50 | //! let config = ProxyConfig { 51 | //! ip_address: "127.0.0.1".to_string(), 52 | //! port: 8080, 53 | //! authentication: false, 54 | //! username: "admin".to_string(), 55 | //! password: "password".to_string(), 56 | //! cache_enabled: true, 57 | //! socks5_address: None, 58 | //! https_enabled: false, 59 | //! certificate_path: None, 60 | //! private_key_path: None, 61 | //! target_address: Some("http://www.example.com".to_string()), 62 | //! }; 63 | //! info!("Starting Proxy server with configuration: {:?}", config); 64 | //! // Start the proxy server with the provided configuration 65 | //! start_proxy_server(config).await?; 66 | //! Ok(()) 67 | //! } 68 | //! ``` 69 | //! 70 | use std::{ 71 | collections::HashMap, 72 | net::SocketAddr, 73 | sync::{Arc, Mutex}, 74 | time::Duration, 75 | }; 76 | 77 | use anyhow::{Context, Result}; 78 | use hyper::{ 79 | body::{Bytes, to_bytes}, 80 | client::{Client, HttpConnector}, 81 | header::{HeaderValue, HOST}, 82 | service::service_fn, 83 | Body, Method, Request, Response, StatusCode, 84 | }; 85 | use log::{debug, error, info, warn}; 86 | use std::str::FromStr; 87 | use tokio::{ 88 | io::{AsyncReadExt, AsyncWriteExt}, 89 | net::{TcpListener, TcpStream}, 90 | }; 91 | use tokio_rustls::{ 92 | rustls::{Certificate, PrivateKey, ServerConfig}, 93 | TlsAcceptor, 94 | }; 95 | use tokio_socks::tcp::Socks5Stream; 96 | use url::Url; 97 | use warp::http::Response as WarpResponse; 98 | use warp::Filter; 99 | 100 | // Constants for metrics 101 | const METRICS_UPDATE_INTERVAL: Duration = Duration::from_secs(5); 102 | 103 | /// Configuration for the proxy server. 104 | #[derive(Clone, Debug)] 105 | pub struct ProxyConfig { 106 | /// IP address to bind the server to. Defaults to `127.0.0.1`. 107 | pub ip_address: String, 108 | /// Port number to bind the server to. Defaults to `8080`. 109 | pub port: u16, 110 | /// Flag indicating whether authentication is required. Defaults to `false`. 111 | pub authentication: bool, 112 | /// Username for authentication. Only used if `authentication` is `true`. 113 | pub username: String, 114 | /// Password for authentication. Only used if `authentication` is `true`. 115 | pub password: String, 116 | /// Flag indicating whether caching is enabled. Defaults to `true`. 117 | pub cache_enabled: bool, 118 | /// SOCKS5 proxy address (optional). If provided, all traffic is routed through this SOCKS5 proxy server. 119 | pub socks5_address: Option, 120 | /// Flag indicating whether HTTPS support is enabled. Defaults to `false`. 121 | pub https_enabled: bool, 122 | /// Path to SSL certificate file for HTTPS. Only used if `https_enabled` is `true`. 123 | pub certificate_path: Option, 124 | /// Path to SSL private key file for HTTPS. Only used if `https_enabled` is `true`. 125 | pub private_key_path: Option, 126 | /// Target address to send requests when not using socks5 127 | pub target_address: Option, 128 | } 129 | 130 | // Implementing Default Method for ProxyConfig 131 | impl Default for ProxyConfig { 132 | /// Returns a new `ProxyConfig` instance with default values 133 | fn default() -> Self { 134 | Self { 135 | ip_address: "127.0.0.1".to_string(), 136 | port: 8080, 137 | authentication: false, 138 | username: "".to_string(), 139 | password: "".to_string(), 140 | cache_enabled: true, 141 | socks5_address: None, 142 | https_enabled: false, 143 | certificate_path: None, 144 | private_key_path: None, 145 | target_address: None, 146 | } 147 | } 148 | } 149 | 150 | /// Struct to hold and manage metrics 151 | #[derive(Default, Clone, Debug)] 152 | pub struct Metrics { 153 | /// Total number of requests handled by the proxy. 154 | pub total_requests: u64, 155 | /// A vector of durations, representing the response times for each request. 156 | pub response_times: Vec, 157 | /// Total number of cache hits. 158 | pub cache_hits: u64, 159 | /// Total number of cache misses. 160 | pub cache_misses: u64, 161 | /// A hashmap of error counts, with the keys representing status codes of errors. 162 | pub error_counts: HashMap, 163 | } 164 | 165 | impl Metrics { 166 | /// Records a new request, updating `total_requests` and `response_times`. 167 | pub fn record_request(&mut self, duration: Duration) { 168 | self.total_requests += 1; 169 | self.response_times.push(duration); 170 | } 171 | 172 | /// Records a cache hit, incrementing `cache_hits`. 173 | pub fn record_cache_hit(&mut self) { 174 | self.cache_hits += 1; 175 | } 176 | 177 | /// Records a cache miss, incrementing `cache_misses`. 178 | pub fn record_cache_miss(&mut self) { 179 | self.cache_misses += 1; 180 | } 181 | 182 | /// Records an error, incrementing the corresponding entry in `error_counts`. 183 | pub fn record_error(&mut self, status_code: u16) { 184 | *self.error_counts.entry(status_code).or_insert(0) += 1; 185 | } 186 | 187 | /// Gets the average response time of all the requests. 188 | pub fn get_average_response_time(&self) -> Duration { 189 | if self.response_times.is_empty() { 190 | return Duration::from_secs(0); 191 | } 192 | let sum: Duration = self.response_times.iter().sum(); 193 | sum / (self.response_times.len() as u32) 194 | } 195 | } 196 | 197 | /// Structure for the global state of the proxy server 198 | pub struct ProxyState { 199 | /// The proxy configuration 200 | pub config: ProxyConfig, 201 | /// Cache for storing responses 202 | pub cache: Arc>>>, 203 | /// Metrics for collecting proxy stats 204 | pub metrics: Arc>, 205 | /// HTTP client to be used for making requests 206 | pub http_client: Client, 207 | } 208 | 209 | impl ProxyState { 210 | /// Creates a new proxy state with the given configuration. 211 | pub fn new(config: ProxyConfig) -> Self { 212 | ProxyState { 213 | config, 214 | cache: Arc::new(Mutex::new(HashMap::new())), 215 | metrics: Arc::new(Mutex::new(Metrics::default())), 216 | http_client: Client::new(), //create a new client 217 | } 218 | } 219 | } 220 | 221 | /// Handles an incoming client connection, authenticates the user if needed, and forwards the request to be handled further. 222 | async fn handle_client_connection( 223 | mut stream: TcpStream, 224 | state: Arc, 225 | addr: SocketAddr, 226 | ) -> Result<()> { 227 | debug!("Handling connection from: {}", addr); 228 | // Check if authentication is required and handle authentication 229 | if state.config.authentication && !handle_authentication(&mut stream, &state.config).await? { 230 | return Ok(()); 231 | } 232 | 233 | if state.config.https_enabled { 234 | handle_https_connection(stream, state, addr).await 235 | } else { 236 | handle_http_connection(stream, state, addr).await 237 | } 238 | } 239 | 240 | /// Handles authentication for incoming client connections 241 | async fn handle_authentication(stream: &mut TcpStream, config: &ProxyConfig) -> Result { 242 | let mut login_buffer = [0; 1024]; 243 | 244 | // Read login data from the client 245 | let bytes_read = stream.peek(&mut login_buffer).await?; 246 | let login_data = String::from_utf8_lossy(&login_buffer[..bytes_read]); 247 | debug!("Received login data: {}", login_data); 248 | 249 | // Check if the login data matches the configured username and password 250 | if login_data.contains(&format!("{}:{}", config.username, config.password)) { 251 | //consume the login data and return true 252 | stream.read(&mut login_buffer[..bytes_read]).await?; 253 | info!("Successful login"); 254 | Ok(true) 255 | } else { 256 | // If authentication fails, send a 401 Unauthorized response to the client 257 | let response = b"HTTP/1.1 401 Unauthorized\r\n\r\n"; 258 | stream.write_all(response).await?; 259 | warn!("Failed login attempt"); 260 | Ok(false) 261 | } 262 | } 263 | 264 | /// Handles HTTP requests 265 | async fn handle_http_connection( 266 | stream: TcpStream, 267 | state: Arc, 268 | addr: SocketAddr, 269 | ) -> Result<()> { 270 | debug!("Handling HTTP connection from: {}", addr); 271 | let service = service_fn(move |req| { 272 | let state = state.clone(); 273 | async move { handle_http_request(req, state).await } 274 | }); 275 | let http = hyper::server::conn::Http::new().serve_connection(stream, service); 276 | 277 | if let Err(err) = http.await { 278 | error!("Error serving HTTP connection from {}: {}", addr, err); 279 | return Err(err.into()); 280 | } 281 | Ok(()) 282 | } 283 | /// Handles HTTPS connections 284 | async fn handle_https_connection( 285 | stream: TcpStream, 286 | state: Arc, 287 | addr: SocketAddr, 288 | ) -> Result<()> { 289 | debug!("Handling HTTPS connection from: {}", addr); 290 | let tls_acceptor = create_tls_acceptor(&state.config)?; 291 | 292 | match tls_acceptor.accept(stream).await { 293 | Ok(tls_stream) => { 294 | let service = service_fn(move |req: hyper::Request| { 295 | let state = state.clone(); 296 | async move { handle_http_request(req, state).await } 297 | }); 298 | 299 | let http = hyper::server::conn::Http::new().serve_connection(tls_stream, service); 300 | 301 | if let Err(err) = http.await { 302 | error!("Error serving HTTPS connection from {}: {}", addr, err); 303 | return Err(err.into()); 304 | } 305 | Ok(()) 306 | } 307 | Err(e) => { 308 | error!("TLS handshake failed with {}: {}", addr, e); 309 | Err(e.into()) 310 | } 311 | } 312 | } 313 | 314 | /// Creates a TLS acceptor for HTTPS 315 | fn create_tls_acceptor(config: &ProxyConfig) -> Result { 316 | let cert_path = config 317 | .certificate_path 318 | .as_ref() 319 | .context("Certificate path required for HTTPS")?; 320 | let key_path = config 321 | .private_key_path 322 | .as_ref() 323 | .context("Private key path required for HTTPS")?; 324 | 325 | let cert_file = std::fs::File::open(cert_path).context("Failed to open cert file")?; 326 | let mut cert_reader = std::io::BufReader::new(cert_file); 327 | let certs: Vec = rustls_pemfile::certs(&mut cert_reader) 328 | .context("Failed to read certificate")? 329 | .into_iter() 330 | .map(Certificate) 331 | .collect(); 332 | 333 | let key_file = std::fs::File::open(key_path).context("Failed to open key file")?; 334 | let mut key_reader = std::io::BufReader::new(key_file); 335 | let keys: Vec = rustls_pemfile::pkcs8_private_keys(&mut key_reader) 336 | .context("Failed to read private key")? 337 | .into_iter() 338 | .map(PrivateKey) 339 | .collect(); 340 | 341 | if keys.is_empty() { 342 | anyhow::bail!("No private keys found in key file"); 343 | } 344 | 345 | let mut server_config = ServerConfig::builder() 346 | .with_safe_defaults() 347 | .with_no_client_auth() 348 | .with_single_cert(certs, keys.first().unwrap().clone()) 349 | .map_err(|err| anyhow::anyhow!("Invalid certificate or private key: {}", err))?; 350 | 351 | server_config.alpn_protocols.push(b"http/1.1".to_vec()); 352 | 353 | Ok(TlsAcceptor::from(Arc::new(server_config))) 354 | } 355 | 356 | /// Handles an HTTP request, checks cache, forwards the request to the target server, and updates the metrics and cache accordingly 357 | async fn handle_http_request(req: Request, state: Arc) -> Result> { 358 | let start = std::time::Instant::now(); 359 | let (parts, body) = req.into_parts(); 360 | let uri = parts.uri.clone(); 361 | let method = parts.method.clone(); 362 | let url_string = uri.to_string(); 363 | debug!("Incoming request: {} {}", method, url_string); 364 | let mut response_to_client = Response::new(Body::empty()); 365 | 366 | // Check cache 367 | if state.config.cache_enabled && method == Method::GET { 368 | let cache = state.cache.lock().unwrap(); 369 | if let Some(response_body) = cache.get(&url_string) { 370 | let duration = start.elapsed(); 371 | state.metrics.lock().unwrap().record_cache_hit(); 372 | info!("Cache hit for: {}, took: {:?}", url_string, duration); 373 | *response_to_client.status_mut() = StatusCode::OK; 374 | *response_to_client.body_mut() = Body::from(Bytes::copy_from_slice(response_body)); 375 | return Ok(response_to_client); 376 | } else { 377 | state.metrics.lock().unwrap().record_cache_miss(); 378 | debug!("Cache miss for: {}", url_string); 379 | } 380 | } 381 | 382 | // Forward the request to the target server 383 | let mut forward_response = forward_request(parts, body, state.clone()).await?; 384 | let status = forward_response.status(); 385 | let duration = start.elapsed(); 386 | 387 | //Update Metrics 388 | { 389 | let mut metrics = state.metrics.lock().unwrap(); 390 | metrics.record_request(duration); 391 | if !status.is_success() { 392 | metrics.record_error(status.as_u16()); 393 | } 394 | } 395 | debug!("Forwarded request to server, took: {:?}", duration); 396 | 397 | // Cache response 398 | if state.config.cache_enabled && method == Method::GET && status.is_success() { 399 | match to_bytes(forward_response.body_mut()).await { 400 | Ok(full_response) => { 401 | let mut cache = state.cache.lock().unwrap(); 402 | cache.insert(url_string.clone(), full_response.to_vec()); 403 | info!( 404 | "Cache insert for: {}, took: {:?} and response status: {}", 405 | url_string, duration, status 406 | ); 407 | response_to_client = forward_response; 408 | } 409 | Err(e) => { 410 | error!( 411 | "Error reading response body for caching {}: {}", 412 | url_string, e 413 | ); 414 | // If caching fails, still return the original response 415 | response_to_client = forward_response; 416 | } 417 | } 418 | } else { 419 | response_to_client = forward_response; 420 | } 421 | info!( 422 | "Request for: {}, took: {:?} and response status: {}", 423 | url_string, duration, status 424 | ); 425 | Ok(response_to_client) 426 | } 427 | 428 | /// Forwards a request to the upstream server 429 | async fn forward_request( 430 | parts: hyper::http::request::Parts, 431 | body: Body, 432 | state: Arc, 433 | ) -> Result> { 434 | let uri_to_use = parts.uri.clone(); 435 | debug!("Forwarding request to: {}", uri_to_use.to_string()); 436 | debug!("Request headers: {:?}", parts.headers); 437 | 438 | let response = if let Some(socks5_addr) = &state.config.socks5_address { 439 | debug!("Using SOCKS5 proxy: {}", socks5_addr); 440 | let mut uri_string = parts.uri.to_string(); 441 | if uri_string.starts_with("http://") { 442 | uri_string = uri_string.replace("http://", ""); 443 | } else if uri_string.starts_with("https://") { 444 | uri_string = uri_string.replace("https://", ""); 445 | } 446 | let url = Url::from_str(&format!("http://{}", uri_string))?; 447 | let proxy_addr = SocketAddr::from_str(socks5_addr) 448 | .map_err(|e| anyhow::anyhow!("Failed to parse SOCKS5 address: {}", e))?; 449 | 450 | let stream = Socks5Stream::connect( 451 | proxy_addr, 452 | (url.host_str().unwrap(), url.port().unwrap_or(80)), 453 | ) 454 | .await?; 455 | let (mut sender, conn) = hyper::client::conn::handshake(stream).await?; 456 | tokio::spawn(async move { 457 | if let Err(err) = conn.await { 458 | error!("Connection error on SOCKS5 connection: {}", err); 459 | } 460 | }); 461 | let mut req = Request::from_parts(parts, body); 462 | req.headers_mut() 463 | .insert(HOST, HeaderValue::from_str(url.host_str().unwrap())?); 464 | 465 | debug!("Sending request through SOCKS5 proxy"); 466 | sender 467 | .send_request(req) 468 | .await 469 | .context("Failed to make request through socks5 proxy") 470 | } else { 471 | debug!( 472 | "Attempting direct connection for: {}", 473 | uri_to_use.to_string() 474 | ); 475 | let target_host = state 476 | .config 477 | .target_address 478 | .as_ref() 479 | .map_or( 480 | "http://localhost".to_string(), //set default target to localhost if target address is not present 481 | |url| url.clone(), 482 | ); 483 | let target_url = format!("{}{}", target_host, uri_to_use); 484 | let client = state.http_client.clone(); 485 | let mut req = Request::from_parts(parts, body); 486 | let url = Url::from_str(target_url.as_str()) 487 | .map_err(|e| anyhow::anyhow!("Failed to parse URI: {}", e))?; 488 | 489 | req.headers_mut() 490 | .insert( 491 | HOST, 492 | HeaderValue::from_str(url.host_str().unwrap()) 493 | .map_err(|e| anyhow::anyhow!("Failed to make Host Header: {}", e))? 494 | ); 495 | *req.uri_mut() = url.to_string().parse().unwrap(); 496 | debug!("Direct connection request: {:?}", req); 497 | client 498 | .request(req) 499 | .await 500 | .context("Failed to make request through direct connection") 501 | }; 502 | 503 | match response { 504 | Ok(response) => { 505 | debug!( 506 | "Received response from {}: status {}", 507 | uri_to_use, 508 | response.status() 509 | ); 510 | Ok(response) 511 | } 512 | Err(err) => { 513 | error!("Error forwarding request to {}: {}", uri_to_use, err); 514 | Ok(Response::builder() 515 | .status(StatusCode::INTERNAL_SERVER_ERROR) 516 | .body(Body::from(format!( 517 | "Failed to forward request to {}: {}", 518 | uri_to_use, err 519 | ))) 520 | .unwrap()) 521 | } 522 | } 523 | } 524 | 525 | /// Starts the proxy server 526 | pub async fn start_proxy_server(config: ProxyConfig) -> Result<()> { 527 | let state = Arc::new(ProxyState::new(config)); 528 | let state_clone = state.clone(); 529 | let config_clone = state.config.clone(); 530 | let metrics_clone = state.metrics.clone(); 531 | 532 | // Initialize the logger 533 | env_logger::init(); 534 | 535 | // Start metrics update task in background 536 | tokio::spawn(async move { 537 | info!("Starting metrics update task"); 538 | metrics_update_task(metrics_clone).await; 539 | }); 540 | 541 | // Start the dashboard server 542 | tokio::spawn(async move { 543 | info!("Starting metrics dashboard"); 544 | start_metrics_dashboard(config_clone, state_clone).await; 545 | }); 546 | 547 | let bind_address = format!("{}:{}", state.config.ip_address, state.config.port); 548 | let listener = TcpListener::bind(&bind_address) 549 | .await 550 | .context(format!("Failed to bind to address: {}", bind_address))?; 551 | info!("Proxy server listening on: {}", bind_address); 552 | loop { 553 | match listener.accept().await { 554 | Ok((stream, addr)) => { 555 | let state_clone = state.clone(); 556 | tokio::spawn(async move { 557 | info!("New connection from {}", addr); 558 | if let Err(err) = handle_client_connection(stream, state_clone, addr).await { 559 | error!("Error handling client connection from {}: {}", addr, err); 560 | } else { 561 | info!("Connection from {} handled successfully", addr); 562 | } 563 | }); 564 | } 565 | Err(e) => { 566 | error!("Error accepting connection: {}", e); 567 | } 568 | } 569 | } 570 | } 571 | 572 | /// Starts a simple metrics dashboard with warp crate 573 | /// 574 | /// This function starts a simple web server with warp crate that exposes two routes: 575 | /// - /metrics: Displays the current metrics of the proxy server 576 | /// - /: Displays a simple HTML page with a link to the metrics route 577 | /// 578 | /// The metrics route displays the following metrics: 579 | /// - Total requests: The total number of requests handled by the proxy server 580 | /// - Average response time: The average response time of all the requests 581 | /// - Cache hits: The number of cache hits 582 | /// - Cache misses: The number of cache misses 583 | /// - Error counts: The number of errors for each status code 584 | async fn start_metrics_dashboard(config: ProxyConfig, state: Arc) { 585 | info!("Starting metrics dashboard..."); 586 | // Define metrics route 587 | let metrics_route = warp::path!("metrics").map(move || { 588 | info!("Metrics route hit"); 589 | let metrics = state.metrics.lock().unwrap(); 590 | let body = format!( 591 | "

Metrics

\ 592 |
    \ 593 |
  • Total requests: {}
  • \ 594 |
  • Average response time: {:?}
  • \ 595 |
  • Cache hits: {}
  • \ 596 |
  • Cache misses: {}
  • \ 597 |
  • Error counts: {:?}
  • \ 598 |
", 599 | metrics.total_requests, 600 | metrics.get_average_response_time(), 601 | metrics.cache_hits, 602 | metrics.cache_misses, 603 | metrics.error_counts, 604 | ); 605 | // Return an HTML response with the metrics 606 | WarpResponse::builder() 607 | .header("Content-Type", "text/html") 608 | .body(body) 609 | }); 610 | // Define index route 611 | let index_route = warp::path::end().map(move || { 612 | info!("Index route hit"); 613 | let body = format!( 614 | "

FortifyNet Proxy Server

\ 615 |

Welcome to FortifyNet proxy server dashboard.

\ 616 | View Metrics" 617 | ); 618 | // Return an HTML response with a link to the metrics route 619 | WarpResponse::builder() 620 | .header("Content-Type", "text/html") 621 | .body(body) 622 | }); 623 | 624 | // Combine routes 625 | let routes = metrics_route.or(index_route); 626 | 627 | // Bind the metrics dashboard to an address 628 | let dashboard_address = SocketAddr::from(([127, 0, 0, 1], config.port + 1000)); 629 | info!( 630 | "Binding metrics dashboard to address: {}", 631 | dashboard_address 632 | ); 633 | // Start the metrics dashboard 634 | warp::serve(routes).bind(dashboard_address).await; 635 | 636 | info!("Metrics Dashboard Started at http://{}", dashboard_address); 637 | } 638 | 639 | //Periodically prints Metrics every 5 secs 640 | async fn metrics_update_task(metrics: Arc>) { 641 | let mut interval = tokio::time::interval(METRICS_UPDATE_INTERVAL); 642 | loop { 643 | interval.tick().await; 644 | let metrics = metrics.lock().unwrap(); 645 | info!("Current metrics: {:?}", metrics); 646 | } 647 | } 648 | 649 | /// Shuts down the proxy server 650 | pub fn shutdown_proxy_server() { 651 | info!("Shutting down proxy server..."); 652 | std::thread::spawn(move || { 653 | std::thread::sleep(std::time::Duration::from_secs(1)); 654 | std::process::exit(0); 655 | }); 656 | } -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use fortifynet_proxy::{start_proxy_server, ProxyConfig}; 2 | use log::info; 3 | 4 | #[tokio::main] 5 | async fn main() -> anyhow::Result<()> { 6 | // Create a proxy configuration with default values 7 | let config = ProxyConfig { 8 | // The IP address the proxy server will bind to 9 | ip_address: "127.0.0.1".to_string(), 10 | // The port the proxy server will listen on 11 | port: 1234, 12 | // Whether to enable basic authentication 13 | authentication: false, 14 | // The username and password to be used for authentication 15 | username: "admin".to_string(), 16 | password: "password".to_string(), 17 | // Whether to enable response caching 18 | cache_enabled: false, 19 | // The SOCKS5 server to use for proxying 20 | socks5_address: None, 21 | // Whether to enable HTTPS 22 | https_enabled: false, 23 | // The path to the SSL/TLS certificate file 24 | certificate_path: Some("cert.pem".to_string()), 25 | // The path to the SSL/TLS private key file 26 | private_key_path: Some("key.pem".to_string()), 27 | // The target address to proxy requests to 28 | target_address: Some("http://www.google.com".to_string()), // Set the target address 29 | }; 30 | info!("Starting Proxy server with configuration: {:?}", config); 31 | // Start the proxy server with the provided configuration 32 | start_proxy_server(config).await?; 33 | Ok(()) 34 | } 35 | --------------------------------------------------------------------------------