From 8ef24e151995924f5073e9181a0e0b4ee28f2174 Mon Sep 17 00:00:00 2001 From: chayleaf Date: Thu, 1 Feb 2024 06:48:22 +0700 Subject: [PATCH] v0.2.0: switch to quic --- .gitignore | 1 + Cargo.lock | 673 +++++++++++++++++++++++++++++++++------------------- Cargo.toml | 12 +- src/main.rs | 454 +++++++++++++++++++---------------- 4 files changed, 679 insertions(+), 461 deletions(-) diff --git a/.gitignore b/.gitignore index 1c4547c..644cd27 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target *.conf +*.der diff --git a/Cargo.lock b/Cargo.lock index 5f4ef0c..50f2a2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,42 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "async-shared-timeout" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bf0ee472a0062fe47df725a586b833aa99b7e3b000176ce1b2c608a3c0535cb" -dependencies = [ - "pin-project-lite", - "portable-atomic 0.3.20", - "tokio", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -74,6 +38,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "bitflags" version = "1.3.2" @@ -108,52 +78,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "chacha20" -version = "0.9.1" +name = "core-foundation" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "chacha20poly1305" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" -dependencies = [ - "aead", - "chacha20", - "cipher", - "poly1305", - "zeroize", -] - -[[package]] -name = "chrono" -version = "0.4.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-targets 0.52.0", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", - "zeroize", + "core-foundation-sys", + "libc", ] [[package]] @@ -163,59 +94,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] -name = "cpufeatures" -version = "0.2.12" +name = "deranged" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "rand_core", - "typenum", -] - -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown", - "lock_api", - "once_cell", - "parking_lot_core", + "powerfmt", ] [[package]] name = "fckrkn" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "async-shared-timeout", "bytes", - "chacha20poly1305", - "chrono", - "dashmap", + "quinn", + "rcgen", + "rustls", + "rustls-native-certs 0.7.0", + "rustls-pemfile 2.0.0", "tokio", - "typenum", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", ] [[package]] @@ -235,50 +132,12 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - [[package]] name = "hermit-abi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" -[[package]] -name = "iana-time-zone" -version = "0.1.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - [[package]] name = "js-sys" version = "0.3.67" @@ -294,16 +153,6 @@ version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.20" @@ -333,16 +182,7 @@ checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", - "windows-sys", -] - -[[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", + "windows-sys 0.48.0", ] [[package]] @@ -371,22 +211,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] -name = "opaque-debug" -version = "0.3.0" +name = "openssl-probe" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] -name = "parking_lot_core" -version = "0.9.9" +name = "pem" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310" dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.48.5", + "base64", + "serde", ] [[package]] @@ -396,30 +233,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] -name = "poly1305" -version = "0.8.0" +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] -name = "portable-atomic" -version = "0.3.20" +name = "ppv-lite86" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e30165d31df606f5726b090ec7592c308a0eaf61721ff64c9a3018e344a8753e" -dependencies = [ - "portable-atomic 1.6.0", -] - -[[package]] -name = "portable-atomic" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" @@ -430,6 +253,54 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quinn" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" +dependencies = [ + "bytes", + "rand", + "ring 0.16.20", + "rustc-hash", + "rustls", + "rustls-native-certs 0.6.3", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" +dependencies = [ + "bytes", + "libc", + "socket2", + "tracing", + "windows-sys 0.48.0", +] + [[package]] name = "quote" version = "1.0.35" @@ -439,6 +310,27 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + [[package]] name = "rand_core" version = "0.6.4" @@ -449,12 +341,44 @@ dependencies = [ ] [[package]] -name = "redox_syscall" -version = "0.4.1" +name = "rcgen" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "48406db8ac1f3cbc7dcdb56ec355343817958a356ff430259bb07baf7607e1e1" dependencies = [ - "bitflags", + "pem", + "ring 0.17.7", + "time", + "yasna", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.48.0", ] [[package]] @@ -464,16 +388,153 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] -name = "scopeguard" -version = "1.2.0" +name = "rustc-hash" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] -name = "smallvec" -version = "1.13.1" +name = "rustls" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring 0.17.7", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile 1.0.4", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.0.0", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64", +] + +[[package]] +name = "rustls-pemfile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4" +dependencies = [ + "base64", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e9d979b3ce68192e42760c7810125eb6cf2ea10efae545a156063e61f314e2a" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.7", + "untrusted 0.9.0", +] + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.7", + "untrusted 0.9.0", +] + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] [[package]] name = "socket2" @@ -482,14 +543,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] -name = "subtle" -version = "2.5.0" +name = "spin" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "syn" @@ -502,6 +569,59 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +dependencies = [ + "deranged", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.35.1" @@ -515,7 +635,7 @@ dependencies = [ "pin-project-lite", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -530,10 +650,36 @@ dependencies = [ ] [[package]] -name = "typenum" -version = "1.17.0" +name = "tracing" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] [[package]] name = "unicode-ident" @@ -542,20 +688,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] -name = "universal-hash" -version = "0.5.1" +name = "untrusted" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] -name = "version_check" -version = "0.9.4" +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "wasi" @@ -618,14 +760,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" [[package]] -name = "windows-core" -version = "0.52.0" +name = "web-sys" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" dependencies = [ - "windows-targets 0.52.0", + "js-sys", + "wasm-bindgen", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.48.0" @@ -635,6 +800,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -750,7 +924,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] -name = "zeroize" -version = "1.7.0" +name = "yasna" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] diff --git a/Cargo.toml b/Cargo.toml index 11f0e59..706af9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,15 +1,15 @@ [package] name = "fckrkn" -version = "0.1.0" +version = "0.2.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-shared-timeout = "0.2.0" bytes = "1.5.0" -chacha20poly1305 = "0.10.1" -chrono = "0.4.33" -dashmap = "5.5.3" +quinn = "0.10.2" +rcgen = "0.12.1" +rustls = "0.21.0" +rustls-native-certs = "0.7.0" +rustls-pemfile = "2.0.0" tokio = { version = "1.35.1", features = ["rt-multi-thread", "macros", "net", "sync", "time"] } -typenum = "1.17.0" diff --git a/src/main.rs b/src/main.rs index 2862ae3..73384b2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,176 +1,19 @@ use std::{ collections::HashMap, - mem, + fs, io, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, - sync::{ - atomic::{AtomicU32, Ordering}, - Arc, - }, + path::PathBuf, + str, + sync::Arc, time::Duration, }; -use async_shared_timeout::Timeout; use bytes::BytesMut; -use chacha20poly1305::{aead::Buffer, AeadCore, AeadInPlace, ChaCha20Poly1305, KeyInit}; -use dashmap::DashMap; -use tokio::{net::UdpSocket, sync::mpsc}; -use typenum::Unsigned; - -#[derive(Debug)] -enum BMut<'a> { - Bytes(BytesMut), - Vec(&'a mut Vec), -} - -impl<'a> Buffer for BMut<'a> { - fn extend_from_slice(&mut self, other: &[u8]) -> chacha20poly1305::aead::Result<()> { - match self { - Self::Bytes(x) => x.extend_from_slice(other), - Self::Vec(x) => x.extend_from_slice(other), - } - Ok(()) - } - fn truncate(&mut self, len: usize) { - match self { - Self::Bytes(x) => x.truncate(len), - Self::Vec(x) => x.truncate(len), - } - } -} -impl<'a> AsRef<[u8]> for BMut<'a> { - fn as_ref(&self) -> &[u8] { - match self { - Self::Bytes(x) => x.as_ref(), - Self::Vec(x) => x.as_ref(), - } - } -} -impl<'a> AsMut<[u8]> for BMut<'a> { - fn as_mut(&mut self) -> &mut [u8] { - match self { - Self::Bytes(x) => x.as_mut(), - Self::Vec(x) => x.as_mut(), - } - } -} - -enum ChanOrSock { - Chan(mpsc::Receiver), - Sock(Arc, Vec), -} - -impl ChanOrSock { - async fn recv(&mut self) -> Option> { - match self { - Self::Chan(x) => x.recv().await.map(BMut::Bytes), - Self::Sock(sock, buf) => { - buf.resize(65536, 0); - let len = sock.recv(buf).await.ok()?; - buf.truncate(len); - Some(BMut::Vec(buf)) - } - } - } -} - -static SESSION_ID: AtomicU32 = AtomicU32::new(0); -static PROTOCOL_VERSION: u8 = 0; - -async fn thread( - (mut rx_enc, sock_enc, enc_addr): (ChanOrSock, Arc, SocketAddr), - (mut rx_dec, sock_dec, dec_addr): (ChanOrSock, Arc, SocketAddr), - server: bool, - chans: Arc>>, - cipher_remote: ChaCha20Poly1305, - cipher_local: ChaCha20Poly1305, -) { - let timeout = Timeout::new( - async_shared_timeout::runtime::Tokio::new(), - Duration::from_secs(1), - ); - let session_id = SESSION_ID.fetch_add(1, Ordering::SeqCst).to_be_bytes(); - let remote_to_local = async { - let mut timeout_set = false; - while let Some(mut buf) = rx_enc.recv().await { - if buf.len() < 12 { - continue; - } - let nonce = <[u8; 12]>::try_from(&buf.as_ref()[buf.len() - 12..]).unwrap(); - let time = chrono::Utc::now().timestamp_nanos_opt().unwrap(); - let nonce1 = [ - nonce[4], nonce[5], nonce[6], nonce[7], nonce[8], nonce[9], nonce[10], nonce[11], - ]; - if i64::from_be_bytes(nonce1).abs_diff(time) > 10_000_000_000 { - eprintln!("got invalid nonce"); - continue; - } - buf.truncate(buf.len() - 12); - if let Err(err) = cipher_remote.decrypt_in_place((&nonce).into(), b"", &mut buf) { - eprintln!("decrypt error: {err}"); - continue; - } - if server { - if !timeout_set { - timeout_set = true; - timeout.set_default_timeout(Duration::from_secs(90)); - } - timeout.reset(); - } - - if let Err(err) = sock_dec.as_ref().send_to(buf.as_ref(), dec_addr).await { - eprintln!("decrypted send error: {err}"); - } - } - }; - let local_to_remote = async { - let mut timeout_set = false; - while let Some(mut buf) = rx_dec.recv().await { - let time = chrono::Utc::now() - .timestamp_nanos_opt() - .unwrap() - .to_be_bytes(); - let nonce = [ - PROTOCOL_VERSION, - session_id[0], - session_id[1], - session_id[2], - time[0], - time[1], - time[2], - time[3], - time[4], - time[5], - time[6], - time[7], - ]; - if let Err(err) = cipher_local.encrypt_in_place((&nonce).into(), b"", &mut buf) { - eprintln!("encrypt error: {err}"); - continue; - } - buf.extend_from_slice(&nonce).unwrap(); - if !server { - if !timeout_set { - timeout_set = true; - timeout.set_default_timeout(Duration::from_secs(90)); - } - timeout.reset(); - } - if let Err(err) = sock_enc.as_ref().send_to(buf.as_ref(), enc_addr).await { - eprintln!("encrypted send error: {err}"); - } - } - }; - tokio::select! { - _ = timeout.wait() => {} - _ = remote_to_local => {} - _ = local_to_remote => {} - } - chans.remove(&enc_addr); -} +use quinn::{IdleTimeout, TransportConfig, VarInt}; +use tokio::{net::UdpSocket, time::Instant}; #[tokio::main] -async fn main() { - assert_eq!(::NonceSize::to_usize(), 12); +async fn main() -> Result<(), io::Error> { let mut args = std::env::args().skip(1); let data = std::fs::read_to_string(args.next().unwrap()) .unwrap() @@ -190,63 +33,260 @@ async fn main() { }) .collect::>(); let ver: u8 = data.get("version").unwrap().parse().unwrap(); - assert!(matches!(ver, 0)); + assert!(matches!(ver, 1)); + + let server = data.contains_key("server"); let src: SocketAddr = data.get("bind").unwrap().parse().unwrap(); - let dst: SocketAddr = data.get("connect").unwrap().parse().unwrap(); let h2b = |x: &str| { x.as_bytes() .chunks_exact(2) .map(|x| u8::from_str_radix(std::str::from_utf8(x).unwrap(), 16).unwrap()) .collect::>() }; - let key_local = h2b(data.get("key_local").unwrap()); - let key_remote = h2b(data.get("key_remote").unwrap()); - let server = data.contains_key("server"); - let cipher_local = ChaCha20Poly1305::new_from_slice(&key_local).unwrap(); - let cipher_remote = ChaCha20Poly1305::new_from_slice(&key_remote).unwrap(); - let sock = Arc::new(UdpSocket::bind(src).await.unwrap()); - let chans = Arc::new(DashMap::>::new()); - let mut buf = BytesMut::with_capacity(65536); - loop { - buf.resize(65536, 0); - let Ok((len, addr)) = sock.recv_from(&mut buf).await else { - continue; + let proxy_key = Box::leak(h2b(data.get("key").unwrap())); + + if server { + let dst: SocketAddr = data.get("connect").unwrap().parse().unwrap(); + let (certs, key) = if let (Some(key_path), Some(cert_path)) = ( + data.get("ssl_key").map(PathBuf::from), + data.get("ssl_cert").map(PathBuf::from), + ) { + let key = fs::read(&key_path).unwrap(); + let key = if key_path.extension().map_or(false, |x| x == "der") { + rustls::PrivateKey(key) + } else { + rustls::PrivateKey( + match rustls_pemfile::read_one_from_slice(&key) + .unwrap() + .unwrap() + .0 + { + rustls_pemfile::Item::Sec1Key(x) => x.secret_sec1_der().to_owned(), + rustls_pemfile::Item::Pkcs1Key(x) => x.secret_pkcs1_der().to_owned(), + rustls_pemfile::Item::Pkcs8Key(x) => x.secret_pkcs8_der().to_owned(), + rustls_pemfile::Item::X509Certificate(x) => x.as_ref().to_owned(), + _ => panic!(), + }, + ) + }; + let cert_chain = fs::read(&cert_path).unwrap(); + let cert_chain = if cert_path.extension().map_or(false, |x| x == "der") { + vec![rustls::Certificate(cert_chain)] + } else { + rustls_pemfile::certs(&mut &*cert_chain) + .map(|x| rustls::Certificate(x.unwrap().to_vec())) + .collect() + }; + + (cert_chain, key) + } else { + let cert_path = "cert.der"; + let key_path = "key.der"; + let (cert, key) = match fs::read(cert_path).and_then(|x| Ok((x, fs::read(key_path)?))) { + Ok(x) => x, + Err(ref e) if e.kind() == io::ErrorKind::NotFound => { + let cert = + rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap(); + let key = cert.serialize_private_key_der(); + let cert = cert.serialize_der().unwrap(); + fs::write(cert_path, &cert).unwrap(); + fs::write(key_path, &key).unwrap(); + (cert, key) + } + Err(e) => { + panic!("failed to read certificate: {}", e); + } + }; + + let key = rustls::PrivateKey(key); + let cert = rustls::Certificate(cert); + (vec![cert], key) }; - if let Some(ch) = chans.get(&addr) { - if ch.send(buf.split_to(len)).await.is_ok() { - continue; - } + + let mut server_crypto = rustls::ServerConfig::builder() + .with_safe_defaults() + .with_no_client_auth() + .with_single_cert(certs, key) + .unwrap(); + server_crypto.alpn_protocols = vec![b"hq-29".to_vec()]; + + let mut server_config = quinn::ServerConfig::with_crypto(Arc::new(server_crypto)); + let transport_config = Arc::get_mut(&mut server_config.transport).unwrap(); + transport_config.max_concurrent_uni_streams(0_u8.into()); + transport_config.max_concurrent_bidi_streams(0_u8.into()); + // milliseconds + transport_config.max_idle_timeout(Some(IdleTimeout::from(VarInt::from(90_000u32)))); + + let endpoint = quinn::Endpoint::server(server_config, src)?; + println!("listening on {:?}", endpoint.local_addr()); + + while let Some(conn) = endpoint.accept().await { + let proxy_key = &*proxy_key; + tokio::spawn(async move { + let Ok(connection) = conn.await else { + return; + }; + let Ok(dgram) = connection.read_datagram().await else { + return; + }; + if dgram != proxy_key { + eprintln!("invalid key"); + return; + } + let Ok(sock) = UdpSocket::bind(( + if dst.is_ipv6() { + IpAddr::V6(Ipv6Addr::UNSPECIFIED) + } else { + IpAddr::V4(Ipv4Addr::UNSPECIFIED) + }, + 0, + )) + .await + else { + return; + }; + sock.connect(dst).await.unwrap(); + let remote_to_local = async { + while let Ok(dgram) = connection.read_datagram().await { + let _ = sock.send(&dgram).await; + } + }; + let local_to_remote = async { + let mut buf = BytesMut::with_capacity(65536); + while let Ok(len) = { + buf.resize(65536, 0); + sock.recv(&mut buf).await + } { + let _ = connection.send_datagram(buf.split_to(len).into()); + } + }; + tokio::select! { + _ = local_to_remote => {} + _ = remote_to_local => {} + } + }); } - let (tx, rx) = mpsc::channel(128); - tx.send(buf.split_to(len)).await.unwrap(); - chans.insert(addr, tx); - let sock2 = Arc::new( - UdpSocket::bind(( - if dst.is_ipv6() { + } else { + let dst = data.get("connect").unwrap(); + let resolved = if let Some(ip) = data.get("connect_ip").and_then(|x| x.parse().ok()) { + ip + } else { + let mut resolved = tokio::net::lookup_host(dst) + .await + .unwrap() + .collect::>(); + resolved.sort_by_key(|x| x.is_ipv6()); + resolved.into_iter().next().unwrap() + }; + let hostname = dst + .chars() + .rev() + .collect::() + .split_once(':') + .unwrap() + .1 + .chars() + .rev() + .collect::(); + let mut client_crypto = rustls::ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates({ + let mut roots = rustls::RootCertStore::empty(); + for cert in rustls_native_certs::load_native_certs().unwrap() { + roots + .add(&rustls::Certificate(cert.as_ref().to_vec())) + .unwrap(); + } + if let Some(ssl_cert) = data.get("ssl_cert") { + roots + .add(&rustls::Certificate(fs::read(ssl_cert).unwrap())) + .unwrap(); + } + Arc::new(roots) + }) + .with_no_client_auth(); + + client_crypto.alpn_protocols = vec![b"hq-29".to_vec()]; + + let mut client_config = quinn::ClientConfig::new(Arc::new(client_crypto)); + client_config.transport_config(Arc::new({ + let mut cfg = TransportConfig::default(); + cfg.keep_alive_interval(Some(Duration::from_secs(30))) + .max_concurrent_bidi_streams(0u8.into()) + .max_concurrent_uni_streams(0u8.into()) + .max_idle_timeout(Some(Duration::from_secs(90).try_into().unwrap())); + cfg + })); + let mut endpoint = quinn::Endpoint::client( + ( + if resolved.is_ipv6() { IpAddr::V6(Ipv6Addr::UNSPECIFIED) } else { IpAddr::V4(Ipv4Addr::UNSPECIFIED) }, 0, - )) - .await - .unwrap(), - ); - sock2.connect(dst).await.unwrap(); - let (mut enc, mut dec) = ( - (ChanOrSock::Sock(sock2.clone(), vec![]), sock2, dst), - (ChanOrSock::Chan(rx), sock.clone(), addr), - ); - if server { - mem::swap(&mut enc, &mut dec); + ) + .into(), + )?; + endpoint.set_default_client_config(client_config); + let endpoint = Arc::new(endpoint); + + loop { + let proxy_key = &*proxy_key; + let endpoint = endpoint.clone(); + let hostname = hostname.clone(); + let _ = tokio::spawn(async move { + let conn = endpoint + .connect(resolved, &hostname) + .unwrap() + .await + .unwrap(); + println!("connected"); + let sock = Arc::new(UdpSocket::bind(src).await.unwrap()); + conn.send_datagram(proxy_key.into()).unwrap(); + + let local_to_remote = async { + let mut buf = BytesMut::with_capacity(65536); + buf.resize(65536, 0); + let mut chosen_addr = None; + let mut chosen_time = Instant::now(); + loop { + buf.resize(65536, 0); + let Ok((len, addr)) = sock.recv_from(&mut buf).await else { + continue; + }; + if Some(addr) != chosen_addr { + if chosen_addr.is_none() + || chosen_time + Duration::from_secs(10) > Instant::now() + { + chosen_addr = Some(addr); + let _ = sock.connect(addr).await; + } else { + continue; + } + } + chosen_time = Instant::now(); + if let Err(err) = conn.send_datagram(buf.split_to(len).into()) { + eprintln!("send failed: {err}"); + } + } + }; + let remote_to_local = async { + loop { + let dgram = conn.read_datagram().await.unwrap(); + let _ = sock.send(&dgram).await; + } + }; + tokio::select! { + _ = local_to_remote => {} + _ = remote_to_local => {} + } + }) + .await; + eprintln!("sleeping for 10 seconds..."); + tokio::time::sleep(Duration::from_secs(10)).await; } - tokio::spawn(thread( - enc, - dec, - server, - chans.clone(), - cipher_remote.clone(), - cipher_local.clone(), - )); } + + Ok(()) }