From 2e4c93f1d38f6e816bf52bcbce6a4ae87ca261e9 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Sat, 30 Nov 2024 01:37:04 +0800 Subject: [PATCH 01/13] Using proxy version of tentacle Signed-off-by: Eval EXEC --- Cargo.lock | 417 ++++++++++++++++++++++++++++++------- network/Cargo.toml | 6 +- util/app-config/Cargo.toml | 4 +- 3 files changed, 341 insertions(+), 86 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f98a9ae83..c9ccb239d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,6 +27,31 @@ dependencies = [ "generic-array", ] +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.3.8" @@ -155,6 +180,12 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + [[package]] name = "arrayvec" version = "0.7.6" @@ -256,7 +287,7 @@ dependencies = [ "sha1", "sync_wrapper 1.0.1", "tokio", - "tokio-tungstenite 0.24.0", + "tokio-tungstenite", "tower 0.5.1", "tower-layer", "tower-service", @@ -299,6 +330,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.21.7" @@ -402,6 +439,19 @@ dependencies = [ "cty", ] +[[package]] +name = "blake3" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -445,6 +495,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "byte_string" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11aade7a05aa8c3a351cedc44c3fc45806430543382fcc4743a9b757a2a0b4ed" + [[package]] name = "byteorder" version = "1.5.0" @@ -481,7 +537,7 @@ dependencies = [ "sha2", "ssri", "tempfile", - "thiserror 1.0.64", + "thiserror", "tokio", "tokio-stream", "walkdir", @@ -845,7 +901,7 @@ dependencies = [ "faster-hex", "rand 0.8.5", "secp256k1", - "thiserror 1.0.64", + "thiserror", ] [[package]] @@ -912,7 +968,7 @@ dependencies = [ "anyhow", "ckb-occupied-capacity", "derive_more 1.0.0", - "thiserror 1.0.64", + "thiserror", ] [[package]] @@ -923,7 +979,7 @@ dependencies = [ "ckb-logger", "ckb-types", "ckb-util", - "thiserror 1.0.64", + "thiserror", ] [[package]] @@ -942,7 +998,7 @@ dependencies = [ "faster-hex", "serde", "serde_json", - "thiserror 1.0.64", + "thiserror", ] [[package]] @@ -1026,7 +1082,7 @@ dependencies = [ "numext-fixed-uint", "rhai", "serde_json", - "thiserror 1.0.64", + "thiserror", ] [[package]] @@ -2056,6 +2112,12 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "convert_case" version = "0.4.0" @@ -2218,6 +2280,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -2239,6 +2313,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "ctrlc" version = "3.4.5" @@ -2476,6 +2559,27 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d978bd5d343e8ab9b5c0fc8d93ff9c602fdc96616ffff9c05ac7a155419b824" +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "elliptic-curve", + "signature", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + [[package]] name = "either" version = "1.13.0" @@ -2485,6 +2589,24 @@ dependencies = [ "serde", ] +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "encode_unicode" version = "0.3.6" @@ -2618,6 +2740,16 @@ dependencies = [ "libc", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "fiat-crypto" version = "0.2.9" @@ -2830,6 +2962,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -2856,6 +2989,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.31.1" @@ -2952,6 +3095,17 @@ dependencies = [ "smallvec", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "h2" version = "0.4.6" @@ -3103,7 +3257,7 @@ dependencies = [ "ipnet", "once_cell", "rand 0.8.5", - "thiserror 1.0.64", + "thiserror", "tinyvec", "tokio", "tracing", @@ -3126,7 +3280,7 @@ dependencies = [ "rand 0.8.5", "resolv-conf", "smallvec", - "thiserror 1.0.64", + "thiserror", "tokio", "tracing", ] @@ -3487,7 +3641,7 @@ checksum = "3afe8830d5802f769dc0be20a87f9f116798c896650cb6266eb5c19a3c109eed" dependencies = [ "js-sys", "num-traits", - "thiserror 1.0.64", + "thiserror", "tokio", "wasm-bindgen", "web-sys", @@ -3822,7 +3976,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -3960,7 +4114,7 @@ checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" dependencies = [ "miette-derive", "once_cell", - "thiserror 1.0.64", + "thiserror", "unicode-width", ] @@ -4223,7 +4377,7 @@ dependencies = [ "numext-constructor", "rand 0.7.3", "serde", - "thiserror 1.0.64", + "thiserror", ] [[package]] @@ -4340,6 +4494,27 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", +] + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", +] + [[package]] name = "parking" version = "2.2.1" @@ -4446,7 +4621,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", - "thiserror 1.0.64", + "thiserror", "ucd-trie", ] @@ -4674,6 +4849,18 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -4709,6 +4896,15 @@ dependencies = [ "syn 2.0.94", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -4754,7 +4950,7 @@ dependencies = [ "memchr", "parking_lot 0.12.3", "protobuf", - "thiserror 1.0.64", + "thiserror", ] [[package]] @@ -5142,6 +5338,25 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ring-compat" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccce7bae150b815f0811db41b8312fcb74bffa4cab9cee5429ee00f356dd5bd4" +dependencies = [ + "aead", + "digest", + "ecdsa", + "ed25519", + "generic-array", + "p256", + "p384", + "pkcs8", + "rand_core 0.6.4", + "ring", + "signature", +] + [[package]] name = "rsa" version = "0.9.6" @@ -5314,6 +5529,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "subtle", + "zeroize", +] + [[package]] name = "secp256k1" version = "0.30.0" @@ -5369,6 +5597,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" +[[package]] +name = "sendfd" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604b71b8fc267e13bb3023a2c901126c8f349393666a6d98ac1ae5729b701798" +dependencies = [ + "libc", + "tokio", +] + [[package]] name = "sentry" version = "0.34.0" @@ -5482,7 +5720,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "thiserror 1.0.64", + "thiserror", "time", "url", "uuid", @@ -5606,6 +5844,54 @@ dependencies = [ "digest", ] +[[package]] +name = "shadowsocks" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ecb3780dfbc654de9383758015b9bb95c6e32fecace36ebded09d67e854d130" +dependencies = [ + "async-trait", + "base64 0.22.1", + "blake3", + "byte_string", + "bytes", + "cfg-if", + "futures", + "libc", + "log", + "once_cell", + "percent-encoding", + "pin-project", + "sendfd", + "serde", + "serde_json", + "serde_urlencoded", + "shadowsocks-crypto", + "socket2", + "spin", + "thiserror", + "tokio", + "tokio-tfo", + "url", + "windows-sys 0.59.0", +] + +[[package]] +name = "shadowsocks-crypto" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc77ecb3a97509d22751b76665894fcffad2d10df8758f4e3f20c92ccde6bf4f" +dependencies = [ + "aes-gcm", + "cfg-if", + "chacha20poly1305", + "hkdf", + "md-5", + "rand 0.8.5", + "ring-compat", + "sha1", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -5743,7 +6029,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1008d95d2ec2d062959352527be30e10fec42a1aa5e5a48d990a5ff0fb9bdc0" dependencies = [ "anyhow", - "thiserror 1.0.64", + "thiserror", ] [[package]] @@ -5803,7 +6089,7 @@ dependencies = [ "sha2", "smallvec", "sqlformat", - "thiserror 1.0.64", + "thiserror", "tokio", "tokio-stream", "tracing", @@ -5887,7 +6173,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 1.0.64", + "thiserror", "tracing", "whoami", ] @@ -5925,7 +6211,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 1.0.64", + "thiserror", "tracing", "whoami", ] @@ -5966,7 +6252,7 @@ dependencies = [ "serde", "sha-1", "sha2", - "thiserror 1.0.64", + "thiserror", "xxhash-rust", ] @@ -6095,9 +6381,8 @@ dependencies = [ [[package]] name = "tentacle" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a3374cb0b9cf25499dcb2e9ecf199af2f778b8d40dd01c413536de5b1574a2b" +version = "0.6.6" +source = "git+https://github.com/eval-exec/tentacle.git?branch=exec/proxy-and-onion#3330101ae8049957c144bedfc94184a001972300" dependencies = [ "async-trait", "bytes", @@ -6112,14 +6397,16 @@ dependencies = [ "nohash-hasher", "parking_lot 0.12.3", "rand 0.8.5", + "shadowsocks", "socket2", "tentacle-multiaddr", "tentacle-secio", - "thiserror 1.0.64", + "thiserror", "tokio", - "tokio-tungstenite 0.26.1", + "tokio-tungstenite", "tokio-util", "tokio-yamux", + "url", "wasm-bindgen", "wasm-bindgen-futures", "winapi", @@ -6128,11 +6415,13 @@ dependencies = [ [[package]] name = "tentacle-multiaddr" version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9e71b28bf0bbf274b92f47cb2c5b42755d84a11e2246cf7bcb7b65c89483b9" +source = "git+https://github.com/eval-exec/tentacle.git?branch=exec/proxy-and-onion#3330101ae8049957c144bedfc94184a001972300" dependencies = [ + "arrayref", "bs58", + "byteorder", "bytes", + "data-encoding", "serde", "sha2", "unsigned-varint", @@ -6141,8 +6430,7 @@ dependencies = [ [[package]] name = "tentacle-secio" version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d53673d63399e1d557c2e884b045d242811079d3b2f17a569310e5c3f1db33" +source = "git+https://github.com/eval-exec/tentacle.git?branch=exec/proxy-and-onion#3330101ae8049957c144bedfc94184a001972300" dependencies = [ "bs58", "bytes", @@ -6218,16 +6506,7 @@ version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ - "thiserror-impl 1.0.64", -] - -[[package]] -name = "thiserror" -version = "2.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" -dependencies = [ - "thiserror-impl 2.0.9", + "thiserror-impl", ] [[package]] @@ -6241,17 +6520,6 @@ dependencies = [ "syn 2.0.94", ] -[[package]] -name = "thiserror-impl" -version = "2.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.94", -] - [[package]] name = "thread-id" version = "4.2.2" @@ -6388,6 +6656,7 @@ dependencies = [ "bytes", "libc", "mio", + "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", "socket2", @@ -6440,27 +6709,32 @@ dependencies = [ ] [[package]] -name = "tokio-tungstenite" -version = "0.24.0" +name = "tokio-tfo" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +checksum = "3fb4382c6371e29365853d2b71e915d5398df46312a2158097d8bb3f54d0f1b4" dependencies = [ - "futures-util", + "cfg-if", + "futures", + "libc", "log", + "once_cell", + "pin-project", + "socket2", "tokio", - "tungstenite 0.24.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-tungstenite" -version = "0.26.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4bf6fecd69fcdede0ec680aaf474cdab988f9de6bc73d3758f0160e3b7025a" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", "tokio", - "tungstenite 0.26.1", + "tungstenite", ] [[package]] @@ -6479,8 +6753,7 @@ dependencies = [ [[package]] name = "tokio-yamux" version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "966579a01e6900c22634f5915fda56358496e71067f3dd26572f9fbe85f4b62e" +source = "git+https://github.com/eval-exec/tentacle.git?branch=exec/proxy-and-onion#3330101ae8049957c144bedfc94184a001972300" dependencies = [ "bytes", "futures", @@ -6663,25 +6936,7 @@ dependencies = [ "log", "rand 0.8.5", "sha1", - "thiserror 1.0.64", - "utf-8", -] - -[[package]] -name = "tungstenite" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413083a99c579593656008130e29255e54dcaae495be556cc26888f211648c24" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 1.1.0", - "httparse", - "log", - "rand 0.8.5", - "sha1", - "thiserror 2.0.9", + "thiserror", "utf-8", ] @@ -7113,7 +7368,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] diff --git a/network/Cargo.toml b/network/Cargo.toml index bb68ffc550..be5321476e 100644 --- a/network/Cargo.toml +++ b/network/Cargo.toml @@ -34,10 +34,10 @@ serde_json = "1.0" bloom-filters = "0.1" ckb-spawn = { path = "../util/spawn", version = "= 0.121.0-pre" } bitflags = "1.0" -p2p = { version = "0.6.2", package = "tentacle", default-features = false } +p2p = { git="https://github.com/eval-exec/tentacle.git", branch="exec/proxy-and-onion", package = "tentacle", default-features = false } [target.'cfg(not(target_family = "wasm"))'.dependencies] -p2p = { version = "0.6.2", package = "tentacle", default-features = false, features = [ +p2p = { git="https://github.com/eval-exec/tentacle.git", branch="exec/proxy-and-onion", package = "tentacle", default-features = false, features = [ "upnp", "parking_lot", "openssl-vendored", @@ -48,7 +48,7 @@ p2p = { version = "0.6.2", package = "tentacle", default-features = false, featu socket2 = "0.5" [target.'cfg(target_family = "wasm")'.dependencies] -p2p = { version = "0.6.2", package = "tentacle", default-features = false, features = [ +p2p = { git="https://github.com/eval-exec/tentacle.git", branch="exec/proxy-and-onion", package = "tentacle", default-features = false, features = [ "wasm-timer", ] } idb = "0.6" diff --git a/util/app-config/Cargo.toml b/util/app-config/Cargo.toml index 8e12714fd6..f938e204d2 100644 --- a/util/app-config/Cargo.toml +++ b/util/app-config/Cargo.toml @@ -22,8 +22,8 @@ ckb-pow = { path = "../../pow", version = "= 0.121.0-pre" } ckb-resource = { path = "../../resource", version = "= 0.121.0-pre" } ckb-build-info = { path = "../build-info", version = "= 0.121.0-pre" } ckb-types = { path = "../types", version = "= 0.121.0-pre" } -secio = { version = "0.6", package = "tentacle-secio" } -multiaddr = { version = "0.3.0", package = "tentacle-multiaddr" } +secio = { git = "https://github.com/eval-exec/tentacle.git", branch="exec/proxy-and-onion", package = "tentacle-secio" } +multiaddr = { git = "https://github.com/eval-exec/tentacle.git", branch="exec/proxy-and-onion", package = "tentacle-multiaddr" } rand = "0.8" sentry = { version = "0.34.0", optional = true } ckb-systemtime = { path = "../systemtime", version = "= 0.121.0-pre" } From 200df23aa858b42e17d2fd5a7b8de6b792e655f1 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Fri, 10 Jan 2025 17:21:17 +0800 Subject: [PATCH 02/13] Add proxy support for ckb --- network/src/network.rs | 9 +++++++++ util/app-config/src/configs/network.rs | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/network/src/network.rs b/network/src/network.rs index bc19edf9ac..d2d167d595 100644 --- a/network/src/network.rs +++ b/network/src/network.rs @@ -28,6 +28,7 @@ use ckb_systemtime::{Duration, Instant}; use ckb_util::{Condvar, Mutex, RwLock}; use futures::{channel::mpsc::Sender, Future}; use ipnetwork::IpNetwork; +use p2p::service::ProxyConfig; use p2p::{ async_trait, builder::ServiceBuilder, @@ -1014,6 +1015,14 @@ impl NetworkService { }; init.transform(TransportType::Tcp); service_builder = service_builder.tcp_config(bind_fn); + + if config.proxy_config.enable { + let proxy_config = Some(ProxyConfig { + proxy_url: config.proxy_config.proxy_url.clone(), + }); + service_builder = + service_builder.tcp_proxy_config(proxy_config); + } } } TransportType::Ws | TransportType::Wss => { diff --git a/util/app-config/src/configs/network.rs b/util/app-config/src/configs/network.rs index b29de05146..d1ee4176ed 100644 --- a/util/app-config/src/configs/network.rs +++ b/util/app-config/src/configs/network.rs @@ -95,6 +95,16 @@ pub struct Config { #[cfg(target_family = "wasm")] #[serde(skip)] pub secret_key: [u8; 32], + + #[serde(default)] + pub proxy_config: ProxyConfig, +} + +/// Proxy related config options +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct ProxyConfig { + pub enable: bool, + pub proxy_url: String, } /// Chain synchronization config options. From 1a095459c084df68c39fcd08a1fc83c2b4a852ef Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Fri, 10 Jan 2025 17:23:26 +0800 Subject: [PATCH 03/13] TcpSocketConfig bind_fn should take aware of SocketContext --- network/src/errors.rs | 2 ++ network/src/lib.rs | 1 + network/src/network.rs | 42 ++++++++++++++++++-------- network/src/proxy.rs | 30 ++++++++++++++++++ util/app-config/src/configs/network.rs | 1 + 5 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 network/src/proxy.rs diff --git a/network/src/errors.rs b/network/src/errors.rs index 0e3bb8d496..4814159db0 100644 --- a/network/src/errors.rs +++ b/network/src/errors.rs @@ -27,6 +27,8 @@ pub enum Error { Dial(String), /// Peer store error PeerStore(PeerStoreError), + /// Config error + Config(String), } /// Error from tentacle diff --git a/network/src/lib.rs b/network/src/lib.rs index c672dab65a..90be01fbcd 100644 --- a/network/src/lib.rs +++ b/network/src/lib.rs @@ -16,6 +16,7 @@ mod peer; pub mod peer_registry; pub mod peer_store; mod protocols; +mod proxy; mod services; #[cfg(test)] diff --git a/network/src/network.rs b/network/src/network.rs index d2d167d595..38dfc5b89c 100644 --- a/network/src/network.rs +++ b/network/src/network.rs @@ -19,7 +19,7 @@ use crate::services::{ dump_peer_store::DumpPeerStoreService, outbound_peer::OutboundPeerService, protocol_type_checker::ProtocolTypeCheckerService, }; -use crate::{Behaviour, CKBProtocol, Peer, PeerIndex, ProtocolId, ServiceControl}; +use crate::{proxy, Behaviour, CKBProtocol, Peer, PeerIndex, ProtocolId, ServiceControl}; use ckb_app_config::{default_support_all_protocols, NetworkConfig, SupportProtocol}; use ckb_logger::{debug, error, info, trace, warn}; use ckb_spawn::Spawn; @@ -121,6 +121,12 @@ impl NetworkState { let peer_store = Mutex::new(PeerStore::load_from_dir_or_default( config.peer_store_path(), )); + info!("Loaded the peer store."); + if config.proxy_config.enable { + proxy::check_proxy_url(&config.proxy_config.proxy_url) + .map_err(|reason| Error::Config(reason))?; + } + let bootnodes = config.bootnodes(); let peer_registry = PeerRegistry::new( @@ -991,6 +997,15 @@ impl NetworkService { if init.is_ready() { break; } + let proxy_config_enable = config.proxy_config.enable; + + if proxy_config_enable { + let proxy_config = ProxyConfig { + proxy_url: config.proxy_config.proxy_url.clone(), + }; + service_builder = service_builder.tcp_proxy_config(Some(proxy_config)); + } + match find_type(multi_addr) { TransportType::Tcp => { // only bind once @@ -999,7 +1014,7 @@ impl NetworkService { } if let Some(addr) = multiaddr_to_socketaddr(multi_addr) { let domain = socket2::Domain::for_address(addr); - let bind_fn = move |socket: p2p::service::TcpSocket| { + let bind_fn = move |socket: p2p::service::TcpSocket, context: p2p::service::TransformerContext| { let socket_ref = socket2::SockRef::from(&socket); #[cfg(all( unix, @@ -1009,20 +1024,14 @@ impl NetworkService { socket_ref.set_reuse_port(true)?; socket_ref.set_reuse_address(true)?; if socket_ref.domain()? == domain { - socket_ref.bind(&addr.into())?; + if !(proxy_config_enable && matches!(context.state, p2p::service::SocketState::Dial)) { + socket_ref.bind(&addr.into())?; + } } Ok(socket) }; init.transform(TransportType::Tcp); service_builder = service_builder.tcp_config(bind_fn); - - if config.proxy_config.enable { - let proxy_config = Some(ProxyConfig { - proxy_url: config.proxy_config.proxy_url.clone(), - }); - service_builder = - service_builder.tcp_proxy_config(proxy_config); - } } } TransportType::Ws | TransportType::Wss => { @@ -1032,7 +1041,7 @@ impl NetworkService { } if let Some(addr) = multiaddr_to_socketaddr(multi_addr) { let domain = socket2::Domain::for_address(addr); - let bind_fn = move |socket: p2p::service::TcpSocket| { + let bind_fn = move |socket: p2p::service::TcpSocket, context: p2p::service::TransformerContext| { let socket_ref = socket2::SockRef::from(&socket); #[cfg(all( unix, @@ -1042,7 +1051,14 @@ impl NetworkService { socket_ref.set_reuse_port(true)?; socket_ref.set_reuse_address(true)?; if socket_ref.domain()? == domain { - socket_ref.bind(&addr.into())?; + if !(proxy_config_enable + && matches!( + context.state, + p2p::service::SocketState::Dial + )) + { + socket_ref.bind(&addr.into())?; + } } Ok(socket) }; diff --git a/network/src/proxy.rs b/network/src/proxy.rs new file mode 100644 index 0000000000..2aa855de95 --- /dev/null +++ b/network/src/proxy.rs @@ -0,0 +1,30 @@ +use ckb_app_config::Url; + +pub(crate) fn check_proxy_url(proxy_url: &str) -> Result<(), String> { + let parsed_url = Url::parse(proxy_url).map_err(|e| e.to_string())?; + if parsed_url.host_str().is_none() { + return Err(format!("missing host in proxy url: {}", proxy_url)); + } + let scheme = parsed_url.scheme(); + if scheme.ne("socks5") { + return Err(format!("CKB doesn't support proxy scheme: {}", scheme)); + } + Ok(()) +} + +#[test] +fn parse_socks5_url() { + let result = Url::parse("socks5://username:password@localhost:1080"); + assert!(result.is_ok()); + let parsed_url = result.unwrap(); + dbg!(&parsed_url); + assert_eq!(parsed_url.scheme(), "socks5"); + // username + assert_eq!(parsed_url.username(), "username"); + // password + assert_eq!(parsed_url.password(), Some("password")); + // host + assert_eq!(parsed_url.host_str(), Some("localhost")); + // port + assert_eq!(parsed_url.port(), Some(1080)); +} diff --git a/util/app-config/src/configs/network.rs b/util/app-config/src/configs/network.rs index d1ee4176ed..fc786c47d9 100644 --- a/util/app-config/src/configs/network.rs +++ b/util/app-config/src/configs/network.rs @@ -104,6 +104,7 @@ pub struct Config { #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct ProxyConfig { pub enable: bool, + // like: socks5://username:password@127.0.0.1:1080 pub proxy_url: String, } From 7cdab66625c397b566cc88019e3061b01d936d89 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Wed, 25 Dec 2024 12:26:19 +0800 Subject: [PATCH 04/13] `IdentifyMessage::decode` allow failure on Unsupported MultiAddr --- network/src/protocols/identify/protocol.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/network/src/protocols/identify/protocol.rs b/network/src/protocols/identify/protocol.rs index 1c15fc5f58..e68a083e53 100644 --- a/network/src/protocols/identify/protocol.rs +++ b/network/src/protocols/identify/protocol.rs @@ -1,3 +1,4 @@ +use ckb_logger::warn; use p2p::{bytes::Bytes, multiaddr::Multiaddr}; use ckb_types::{packed, prelude::*}; @@ -69,7 +70,12 @@ impl<'a> IdentifyMessage<'a> { Multiaddr::try_from(reader.observed_addr().bytes().raw_data().to_vec()).ok()?; let mut listen_addrs = Vec::with_capacity(reader.listen_addrs().len()); for addr in reader.listen_addrs().iter() { - listen_addrs.push(Multiaddr::try_from(addr.bytes().raw_data().to_vec()).ok()?) + match Multiaddr::try_from(addr.bytes().raw_data().to_vec()) { + Ok(multi_addr) => { + listen_addrs.push(multi_addr); + } + Err(err) => warn!("failed to decode listen_addr to MultiAddr: {}", err), + } } Some(IdentifyMessage { From ad1a43bd5b1d283f6bdbf353d6ee726b5eb2456e Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Mon, 30 Dec 2024 14:19:10 +0800 Subject: [PATCH 05/13] Remove ProxyConfig#enable field --- network/src/network.rs | 20 +++++++++----------- util/app-config/src/configs/network.rs | 3 +-- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/network/src/network.rs b/network/src/network.rs index 38dfc5b89c..aa542df220 100644 --- a/network/src/network.rs +++ b/network/src/network.rs @@ -122,9 +122,8 @@ impl NetworkState { config.peer_store_path(), )); info!("Loaded the peer store."); - if config.proxy_config.enable { - proxy::check_proxy_url(&config.proxy_config.proxy_url) - .map_err(|reason| Error::Config(reason))?; + if let Some(ref proxy_url) = config.proxy_config.proxy_url { + proxy::check_proxy_url(proxy_url).map_err(|reason| Error::Config(reason))?; } let bootnodes = config.bootnodes(); @@ -997,14 +996,13 @@ impl NetworkService { if init.is_ready() { break; } - let proxy_config_enable = config.proxy_config.enable; - - if proxy_config_enable { - let proxy_config = ProxyConfig { - proxy_url: config.proxy_config.proxy_url.clone(), - }; - service_builder = service_builder.tcp_proxy_config(Some(proxy_config)); - } + let proxy_config_enable = config.proxy_config.proxy_url.is_some(); + service_builder = service_builder.tcp_proxy_config( + config + .proxy_config + .proxy_url + .map(|proxy_url| ProxyConfig { proxy_url }), + ); match find_type(multi_addr) { TransportType::Tcp => { diff --git a/util/app-config/src/configs/network.rs b/util/app-config/src/configs/network.rs index fc786c47d9..eaeaf7fbcd 100644 --- a/util/app-config/src/configs/network.rs +++ b/util/app-config/src/configs/network.rs @@ -103,9 +103,8 @@ pub struct Config { /// Proxy related config options #[derive(Clone, Debug, Serialize, Deserialize, Default)] pub struct ProxyConfig { - pub enable: bool, // like: socks5://username:password@127.0.0.1:1080 - pub proxy_url: String, + pub proxy_url: Option, } /// Chain synchronization config options. From 0dfbf8552e4e9180cba4b8409694252f37f40944 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 31 Dec 2024 16:04:49 +0800 Subject: [PATCH 06/13] Use `NetworkAddresses` to represent regular_addrs and onion_addrs Signed-off-by: Eval EXEC --- network/src/address.rs | 71 ++++++++++++++++++++++++++++++++++++++++++ network/src/lib.rs | 1 + network/src/network.rs | 3 +- network/src/peer.rs | 3 +- 4 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 network/src/address.rs diff --git a/network/src/address.rs b/network/src/address.rs new file mode 100644 index 0000000000..a4dc0f226f --- /dev/null +++ b/network/src/address.rs @@ -0,0 +1,71 @@ +use p2p::multiaddr::{MultiAddr, Protocol}; + +#[derive(Default)] +pub struct NetworkAddresses { + pub regular_addresses: Vec, + + // onion addresses can't be solved by multiaddr_to_socketaddr or socketaddr_to_multiaddr + pub onion_addresses: Vec, +} + +impl NetworkAddresses { + pub fn push(&mut self, address: MultiAddr) { + if address + .iter() + .any(|proto| matches!(proto, Protocol::Onion3(_))) + { + self.onion_addresses.push(address); + } else { + self.regular_addresses.push(address); + } + } + + // contains + pub fn contains(&self, address: &MultiAddr) -> bool { + self.regular_addresses.contains(address) || self.onion_addresses.contains(address) + } +} + +impl IntoIterator for NetworkAddresses { + type Item = MultiAddr; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.regular_addresses + .into_iter() + .chain(self.onion_addresses.into_iter()) + .collect::>() + .into_iter() + } +} + +// convert Vec to NetworkAddresses +impl From> for NetworkAddresses { + fn from(addresses: Vec) -> Self { + let mut regular_addresses = Vec::new(); + let mut onion_addresses = Vec::new(); + for address in addresses { + if address + .iter() + .any(|proto| matches!(proto, Protocol::Onion3(_))) + { + onion_addresses.push(address); + } else { + regular_addresses.push(address); + } + } + NetworkAddresses { + regular_addresses, + onion_addresses, + } + } +} + +// convert NetworkAddresses to Vec +impl From for Vec { + fn from(addresses: NetworkAddresses) -> Self { + let mut result = addresses.regular_addresses; + result.extend(addresses.onion_addresses); + result + } +} diff --git a/network/src/lib.rs b/network/src/lib.rs index 90be01fbcd..db60bf34c7 100644 --- a/network/src/lib.rs +++ b/network/src/lib.rs @@ -6,6 +6,7 @@ //! And implemented several basic protocols: identify, discovery, ping, feeler, disconnect_message //! +mod address; mod behaviour; /// compress module pub mod compress; diff --git a/network/src/network.rs b/network/src/network.rs index aa542df220..897b3076d3 100644 --- a/network/src/network.rs +++ b/network/src/network.rs @@ -1,4 +1,5 @@ //! Global state struct and start function +use crate::address::NetworkAddresses; use crate::errors::Error; #[cfg(not(target_family = "wasm"))] use crate::errors::P2PError; @@ -74,7 +75,7 @@ pub struct NetworkState { pub(crate) peer_registry: RwLock, pub(crate) peer_store: Mutex, /// Node listened addresses - pub(crate) listened_addrs: RwLock>, + pub(crate) listened_addrs: RwLock, dialing_addrs: RwLock>, /// Node public addresses, /// includes manually public addrs and remote peer observed addrs diff --git a/network/src/peer.rs b/network/src/peer.rs index fe7ee3dfb3..3c649c7ef3 100644 --- a/network/src/peer.rs +++ b/network/src/peer.rs @@ -1,3 +1,4 @@ +use crate::address::NetworkAddresses; use crate::network_group::Group; use crate::{ multiaddr::Multiaddr, protocols::identify::Flags, ProtocolId, ProtocolVersion, SessionType, @@ -21,7 +22,7 @@ pub struct Peer { /// Peer address pub connected_addr: Multiaddr, /// Peer listen addresses - pub listened_addrs: Vec, + pub listened_addrs: NetworkAddresses, /// Peer info from identify protocol message pub identify_info: Option, /// Ping/Pong message last received time From fd2b59a840065fb64da1f12768f1b8ec9fe9786e Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Tue, 31 Dec 2024 16:49:29 +0800 Subject: [PATCH 07/13] let `ckb-network` and `ckb-rpc` use `NetworkAddresses` --- network/src/address.rs | 21 +++++++++++++-------- network/src/network.rs | 5 +++-- network/src/peer.rs | 2 +- network/src/protocols/identify/mod.rs | 2 +- rpc/src/module/net.rs | 8 ++++++-- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/network/src/address.rs b/network/src/address.rs index a4dc0f226f..f921b8d589 100644 --- a/network/src/address.rs +++ b/network/src/address.rs @@ -1,6 +1,6 @@ use p2p::multiaddr::{MultiAddr, Protocol}; -#[derive(Default)] +#[derive(Default, Clone, Debug)] pub struct NetworkAddresses { pub regular_addresses: Vec, @@ -24,18 +24,23 @@ impl NetworkAddresses { pub fn contains(&self, address: &MultiAddr) -> bool { self.regular_addresses.contains(address) || self.onion_addresses.contains(address) } + + // len + pub fn len(&self) -> usize { + self.regular_addresses.len() + self.onion_addresses.len() + } } -impl IntoIterator for NetworkAddresses { - type Item = MultiAddr; - type IntoIter = std::vec::IntoIter; +// implement iter() for NetworkAddresses, don't take ownership +impl<'a> IntoIterator for &'a NetworkAddresses { + type Item = &'a MultiAddr; + type IntoIter = + std::iter::Chain, std::slice::Iter<'a, MultiAddr>>; fn into_iter(self) -> Self::IntoIter { self.regular_addresses - .into_iter() - .chain(self.onion_addresses.into_iter()) - .collect::>() - .into_iter() + .iter() + .chain(self.onion_addresses.iter()) } } diff --git a/network/src/network.rs b/network/src/network.rs index 897b3076d3..0fcb393b7c 100644 --- a/network/src/network.rs +++ b/network/src/network.rs @@ -143,7 +143,7 @@ impl NetworkState { peer_registry: RwLock::new(peer_registry), dialing_addrs: RwLock::new(HashMap::default()), public_addrs: RwLock::new(public_addrs), - listened_addrs: RwLock::new(Vec::new()), + listened_addrs: RwLock::new(NetworkAddresses::default()), pending_observed_addrs: RwLock::new(HashSet::default()), local_private_key, local_peer_id, @@ -365,7 +365,7 @@ impl NetworkState { None } }) - .chain(listened_addrs.iter().map(|addr| (addr.to_owned(), 1))) + .chain(listened_addrs.into_iter().map(|addr| (addr.to_owned(), 1))) .map(|(addr, score)| (addr.to_string(), score)) .collect() } @@ -1002,6 +1002,7 @@ impl NetworkService { config .proxy_config .proxy_url + .clone() .map(|proxy_url| ProxyConfig { proxy_url }), ); diff --git a/network/src/peer.rs b/network/src/peer.rs index 3c649c7ef3..f6235b5dd4 100644 --- a/network/src/peer.rs +++ b/network/src/peer.rs @@ -55,7 +55,7 @@ impl Peer { ) -> Self { Peer { connected_addr, - listened_addrs: Vec::new(), + listened_addrs: NetworkAddresses::default(), identify_info: None, ping_rtt: None, last_ping_protocol_message_received_at: None, diff --git a/network/src/protocols/identify/mod.rs b/network/src/protocols/identify/mod.rs index 84f2f3ffd7..81926db734 100644 --- a/network/src/protocols/identify/mod.rs +++ b/network/src/protocols/identify/mod.rs @@ -510,7 +510,7 @@ impl Callback for IdentifyCallback { ); let flags = self.network_state.with_peer_registry_mut(|reg| { if let Some(peer) = reg.get_peer_mut(session.id) { - peer.listened_addrs = addrs.clone(); + peer.listened_addrs = addrs.clone().into(); peer.identify_info .as_ref() .map(|a| a.flags) diff --git a/rpc/src/module/net.rs b/rpc/src/module/net.rs index cbc2f5ad7f..28a8d8da34 100644 --- a/rpc/src/module/net.rs +++ b/rpc/src/module/net.rs @@ -5,7 +5,11 @@ use ckb_jsonrpc_types::{ BannedAddr, LocalNode, LocalNodeProtocol, NodeAddress, PeerSyncState, RemoteNode, RemoteNodeProtocol, SyncState, Timestamp, }; -use ckb_network::{extract_peer_id, multiaddr::Multiaddr, NetworkController}; +use ckb_network::{ + extract_peer_id, + multiaddr::{MultiAddr, Multiaddr}, + NetworkController, +}; use ckb_sync::SyncShared; use ckb_systemtime::unix_time_as_millis; use ckb_types::prelude::{Pack, Unpack}; @@ -588,7 +592,7 @@ impl NetRpc for NetRpcImpl { .iter() .map(|(peer_index, peer)| { let addresses: HashSet<_> = std::iter::once(peer.connected_addr.clone()) - .chain(peer.listened_addrs.iter().cloned()) + .chain(peer.listened_addrs.into_iter().cloned()) .collect(); let node_addresses = addresses From 43d3bbbfe2377d0d8cfe24e60df9a4fcf6921764 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Fri, 10 Jan 2025 17:08:50 +0800 Subject: [PATCH 08/13] Add OnionConfig --- network/src/network.rs | 11 +++-------- util/app-config/src/configs/network.rs | 11 ++++++++++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/network/src/network.rs b/network/src/network.rs index 0fcb393b7c..67f99fcab9 100644 --- a/network/src/network.rs +++ b/network/src/network.rs @@ -29,7 +29,6 @@ use ckb_systemtime::{Duration, Instant}; use ckb_util::{Condvar, Mutex, RwLock}; use futures::{channel::mpsc::Sender, Future}; use ipnetwork::IpNetwork; -use p2p::service::ProxyConfig; use p2p::{ async_trait, builder::ServiceBuilder, @@ -998,13 +997,9 @@ impl NetworkService { break; } let proxy_config_enable = config.proxy_config.proxy_url.is_some(); - service_builder = service_builder.tcp_proxy_config( - config - .proxy_config - .proxy_url - .clone() - .map(|proxy_url| ProxyConfig { proxy_url }), - ); + service_builder = service_builder + .tcp_proxy_config(config.proxy_config.proxy_url.clone()) + .tcp_onion_config(config.onion_config.onion_server.clone()); match find_type(multi_addr) { TransportType::Tcp => { diff --git a/util/app-config/src/configs/network.rs b/util/app-config/src/configs/network.rs index eaeaf7fbcd..3f10209544 100644 --- a/util/app-config/src/configs/network.rs +++ b/util/app-config/src/configs/network.rs @@ -97,7 +97,9 @@ pub struct Config { pub secret_key: [u8; 32], #[serde(default)] - pub proxy_config: ProxyConfig, + pub proxy: ProxyConfig, + #[serde(default)] + pub onion: OnionConfig, } /// Proxy related config options @@ -107,6 +109,13 @@ pub struct ProxyConfig { pub proxy_url: Option, } +/// Onion related config options +#[derive(Clone, Debug, Serialize, Deserialize, Default)] +pub struct OnionConfig { + // like: socks5://username:password@127.0.0.1:1080 + pub onion_url: Option, +} + /// Chain synchronization config options. #[derive(Clone, Debug, Serialize, Deserialize, Default)] #[serde(deny_unknown_fields)] From c5e2b7b4a924f72adbcbacec558732a8809d05f4 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Mon, 13 Jan 2025 14:13:35 +0800 Subject: [PATCH 09/13] add ckb-onion workspace member crate Signed-off-by: Eval EXEC --- Cargo.lock | 249 +++++++++++++++++++++++++++++++++++------- Cargo.toml | 1 + util/onion/Cargo.toml | 23 ++++ util/onion/src/lib.rs | 0 4 files changed, 233 insertions(+), 40 deletions(-) create mode 100644 util/onion/Cargo.toml create mode 100644 util/onion/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c9ccb239d7..a5e55cede3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -336,6 +336,18 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base32" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "base64" version = "0.21.7" @@ -452,6 +464,16 @@ dependencies = [ "constant_time_eq", ] +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding", + "generic-array", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -461,6 +483,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + [[package]] name = "bloom-filters" version = "0.1.2" @@ -522,7 +550,7 @@ version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a61ff12b19d89c752c213316b87fdb4a587f073d219b893cc56974b8c9f39bf7" dependencies = [ - "digest", + "digest 0.10.7", "either", "futures", "hex", @@ -534,7 +562,7 @@ dependencies = [ "serde_derive", "serde_json", "sha1", - "sha2", + "sha2 0.10.8", "ssri", "tempfile", "thiserror", @@ -1423,6 +1451,22 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ckb-onion" +version = "0.121.0-pre" +dependencies = [ + "base64 0.22.1", + "ckb-async-runtime", + "ckb-channel", + "ckb-error", + "ckb-logger", + "ckb-stop-handler", + "tempfile", + "tentacle-multiaddr", + "tokio", + "torut", +] + [[package]] name = "ckb-pow" version = "0.121.0-pre" @@ -2303,6 +2347,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "ctor" version = "0.1.26" @@ -2338,6 +2392,19 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -2509,13 +2576,22 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "const-oid", "crypto-common", "subtle", @@ -2567,7 +2643,16 @@ checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", "elliptic-curve", - "signature", + "signature 2.2.0", +] + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature 1.6.4", ] [[package]] @@ -2577,7 +2662,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", - "signature", + "signature 2.2.0", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek 3.2.0", + "ed25519 1.5.3", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "zeroize", ] [[package]] @@ -2597,7 +2696,7 @@ checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", - "digest", + "digest 0.10.7", "ff", "generic-array", "group", @@ -3291,7 +3390,17 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "hmac", + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest 0.9.0", ] [[package]] @@ -3300,7 +3409,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -3939,6 +4048,15 @@ dependencies = [ "syn 2.0.94", ] +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + [[package]] name = "keyed_priority_queue" version = "0.3.2" @@ -3965,9 +4083,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.167" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libloading" @@ -3976,7 +4094,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -4079,7 +4197,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest", + "digest 0.10.7", ] [[package]] @@ -4656,7 +4774,7 @@ checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" dependencies = [ "once_cell", "pest", - "sha2", + "sha2 0.10.8", ] [[package]] @@ -5345,16 +5463,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccce7bae150b815f0811db41b8312fcb74bffa4cab9cee5429ee00f356dd5bd4" dependencies = [ "aead", - "digest", + "digest 0.10.7", "ecdsa", - "ed25519", + "ed25519 2.2.3", "generic-array", "p256", "p384", "pkcs8", "rand_core 0.6.4", "ring", - "signature", + "signature 2.2.0", ] [[package]] @@ -5364,14 +5482,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" dependencies = [ "const-oid", - "digest", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", "pkcs1", "pkcs8", "rand_core 0.6.4", - "signature", + "signature 2.2.0", "spki", "subtle", "zeroize", @@ -5819,7 +5937,7 @@ checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] @@ -5830,7 +5948,20 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", ] [[package]] @@ -5841,7 +5972,19 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug", ] [[package]] @@ -5916,13 +6059,19 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + [[package]] name = "signature" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core 0.6.4", ] @@ -6086,7 +6235,7 @@ dependencies = [ "rustls-pemfile", "serde", "serde_json", - "sha2", + "sha2 0.10.8", "smallvec", "sqlformat", "thiserror", @@ -6125,7 +6274,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.8", "sqlx-core", "sqlx-mysql", "sqlx-postgres", @@ -6148,7 +6297,7 @@ dependencies = [ "byteorder", "bytes", "crc", - "digest", + "digest 0.10.7", "dotenvy", "either", "futures-channel", @@ -6158,7 +6307,7 @@ dependencies = [ "generic-array", "hex", "hkdf", - "hmac", + "hmac 0.12.1", "itoa", "log", "md-5", @@ -6169,7 +6318,7 @@ dependencies = [ "rsa", "serde", "sha1", - "sha2", + "sha2 0.10.8", "smallvec", "sqlx-core", "stringprep", @@ -6197,7 +6346,7 @@ dependencies = [ "futures-util", "hex", "hkdf", - "hmac", + "hmac 0.12.1", "home", "itoa", "log", @@ -6207,7 +6356,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "sha2", + "sha2 0.10.8", "smallvec", "sqlx-core", "stringprep", @@ -6246,12 +6395,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da7a2b3c2bc9693bcb40870c4e9b5bf0d79f9cb46273321bf855ec513e919082" dependencies = [ "base64 0.21.7", - "digest", + "digest 0.10.7", "hex", "miette", "serde", "sha-1", - "sha2", + "sha2 0.10.8", "thiserror", "xxhash-rust", ] @@ -6423,7 +6572,7 @@ dependencies = [ "bytes", "data-encoding", "serde", - "sha2", + "sha2 0.10.8", "unsigned-varint", ] @@ -6437,7 +6586,7 @@ dependencies = [ "chacha20poly1305", "futures", "getrandom 0.2.15", - "hmac", + "hmac 0.12.1", "log", "molecule", "openssl", @@ -6446,7 +6595,7 @@ dependencies = [ "rand_core 0.6.4", "ring", "secp256k1", - "sha2", + "sha2 0.10.8", "tokio", "tokio-util", "unsigned-varint", @@ -6648,9 +6797,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "bytes", @@ -6667,9 +6816,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", @@ -6804,6 +6953,26 @@ dependencies = [ "tracing", ] +[[package]] +name = "torut" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99febc413f26cf855b3a309c5872edff5c31e0ffe9c2fce5681868761df36f69" +dependencies = [ + "base32", + "base64 0.13.1", + "derive_more 0.99.18", + "ed25519-dalek", + "hex", + "hmac 0.11.0", + "rand 0.7.3", + "serde", + "serde_derive", + "sha2 0.9.9", + "sha3", + "tokio", +] + [[package]] name = "tower" version = "0.4.13" @@ -7368,7 +7537,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -7647,7 +7816,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 4.1.3", "rand_core 0.6.4", "serde", "zeroize", diff --git a/Cargo.toml b/Cargo.toml index 77d4b8f44d..8643119fba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ members = [ "util/occupied-capacity/macros", "util/fixed-hash/macros", "util/logger-service", + "util/onion", "util/runtime", "util/stop-handler", "util/metrics", diff --git a/util/onion/Cargo.toml b/util/onion/Cargo.toml new file mode 100644 index 0000000000..4b041c3440 --- /dev/null +++ b/util/onion/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "ckb-onion" +version = "0.121.0-pre" +authors = ["Nervos Core Dev "] +edition = "2021" +license = "MIT" +description = "CKB command line arguments and config options." +homepage = "https://github.com/nervosnetwork/ckb" +repository = "https://github.com/nervosnetwork/ckb" + +[dependencies] +base64 = "0.22.1" +tokio = { version = "1.43.0", features = [ "full", "macros" ]} +torut = "0.2.1" +ckb-error = { path = "../../error", version = "= 0.121.0-pre" } +ckb-channel = { path = "../channel", version = "= 0.121.0-pre" } +ckb-async-runtime = { path = "../runtime", version = "= 0.121.0-pre" } +ckb-logger = { path = "../logger", version = "= 0.121.0-pre" } +ckb-stop-handler = { path = "../stop-handler", version = "= 0.121.0-pre" } +multiaddr = { git = "https://github.com/eval-exec/tentacle.git", branch="exec/proxy-and-onion", package = "tentacle-multiaddr" } + +[dev-dependencies] +tempfile.workspace = true diff --git a/util/onion/src/lib.rs b/util/onion/src/lib.rs new file mode 100644 index 0000000000..e69de29bb2 From 9cddb68a2751b13f2ba30e46b821a9e368b90b5a Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Wed, 15 Jan 2025 17:45:45 +0800 Subject: [PATCH 10/13] Add ckb-onion as dependency of ckb-launcher --- Cargo.lock | 1 + util/launcher/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index a5e55cede3..c45d60ec05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1154,6 +1154,7 @@ dependencies = [ "ckb-logger", "ckb-network", "ckb-network-alert", + "ckb-onion", "ckb-resource", "ckb-rpc", "ckb-shared", diff --git a/util/launcher/Cargo.toml b/util/launcher/Cargo.toml index 3801fae6fe..2d6dd06c0a 100644 --- a/util/launcher/Cargo.toml +++ b/util/launcher/Cargo.toml @@ -31,6 +31,7 @@ ckb-channel = { path = "../channel", version = "= 0.121.0-pre" } ckb-tx-pool = { path = "../../tx-pool", version = "= 0.121.0-pre" } ckb-light-client-protocol-server = { path = "../light-client-protocol-server", version = "= 0.121.0-pre" } ckb-block-filter = { path = "../../block-filter", version = "= 0.121.0-pre" } +ckb-onion = { path = "../onion", version = "= 0.121.0-pre" } [features] with_sentry = [ From b86515320fa61f07101aa49b416de1a221c98026 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Fri, 17 Jan 2025 16:58:58 +0800 Subject: [PATCH 11/13] Add `[network.proxy]` and `[network.onion]` config to `ckb.toml` --- resource/ckb.toml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/resource/ckb.toml b/resource/ckb.toml index 95240520df..f3856f3ee9 100644 --- a/resource/ckb.toml +++ b/resource/ckb.toml @@ -110,6 +110,16 @@ support_protocols = ["Ping", "Discovery", "Identify", "Feeler", "DisconnectMessa # [network.sync.header_map] # memory_limit = "256MB" +# [network.proxy] +# proxy_url = "socks5://127.0.0.1:7891" + +# [network.onion] +# listen_on_onion = false +# onion_service_target = "127.0.0.1:8115" +# onion_server = "127.0.0.1:9050" +# tor_controller = "127.0.0.1:9051" +# tor_password = "" + [rpc] # By default RPC only binds to localhost, thus it only allows accessing from the same machine. # From 67985d5633a8a3edcd65ca8462eb917a7b87a532 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Fri, 24 Jan 2025 14:39:29 +0800 Subject: [PATCH 12/13] Install tor dependency for ckb-onion Integration Tests --- .github/workflows/ci_integration_tests_macos.yaml | 1 + .github/workflows/ci_integration_tests_ubuntu.yaml | 4 ++-- .github/workflows/ci_integration_tests_windows.yaml | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci_integration_tests_macos.yaml b/.github/workflows/ci_integration_tests_macos.yaml index f33e78237e..fceed3e186 100644 --- a/.github/workflows/ci_integration_tests_macos.yaml +++ b/.github/workflows/ci_integration_tests_macos.yaml @@ -54,6 +54,7 @@ jobs: runs-on: macos-13 steps: - uses: actions/checkout@v3 + - run: brew install tor - run: | if [[ ${{ needs.prologue.outputs.os_skip }} == run ]] && [[ ${{ needs.prologue.outputs.job_skip }} == run ]];then devtools/ci/ci_main.sh diff --git a/.github/workflows/ci_integration_tests_ubuntu.yaml b/.github/workflows/ci_integration_tests_ubuntu.yaml index 06b94b6abe..7aee0479a3 100644 --- a/.github/workflows/ci_integration_tests_ubuntu.yaml +++ b/.github/workflows/ci_integration_tests_ubuntu.yaml @@ -60,7 +60,7 @@ jobs: toolchain: 1.81.0 - run: rustup component add rustfmt - run: rustup component add clippy - - run: sudo apt-get update && sudo apt-get install -y libssl-dev pkg-config libclang-dev + - run: sudo apt-get update && sudo apt-get install -y libssl-dev pkg-config libclang-dev tor - uses: actions/checkout@v3 - run: | if [[ ${{ needs.prologue.outputs.os_skip }} == run ]] && [[ ${{ needs.prologue.outputs.job_skip }} == run ]];then @@ -89,7 +89,7 @@ jobs: toolchain: 1.81.0 - run: rustup component add rustfmt - run: rustup component add clippy - - run: sudo apt-get update && sudo apt-get install -y libssl-dev pkg-config libclang-dev + - run: sudo apt-get update && sudo apt-get install -y libssl-dev pkg-config libclang-dev tor - uses: actions/checkout@v3 - name: build ckb and run bats cli test run: | diff --git a/.github/workflows/ci_integration_tests_windows.yaml b/.github/workflows/ci_integration_tests_windows.yaml index edcc871789..3399f3ea5a 100644 --- a/.github/workflows/ci_integration_tests_windows.yaml +++ b/.github/workflows/ci_integration_tests_windows.yaml @@ -66,6 +66,7 @@ jobs: scoop install git scoop bucket add extras scoop install llvm + scoop install tor - run: | if [[ ${{ needs.prologue.outputs.os_skip }} == run ]] && [[ ${{ needs.prologue.outputs.job_skip }} == run ]];then devtools/ci/ci_main.sh From ab4728294d9bdfd0d2391404bc6582fe275fa8dc Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Wed, 15 Jan 2025 22:30:04 +0800 Subject: [PATCH 13/13] Add ckb-onion integration test Signed-off-by: Eval EXEC --- ckb-bin/src/subcommand/run.rs | 1 + network/src/network.rs | 23 ++- network/src/peer_store/addr_manager.rs | 8 +- network/src/protocols/identify/mod.rs | 2 +- test/Cargo.toml | 2 +- test/src/main.rs | 2 + test/src/node.rs | 39 +++++ test/src/specs/mod.rs | 2 + test/src/specs/tor/mod.rs | 46 ++++++ test/src/specs/tor/tor_basic.rs | 86 ++++++++++ test/src/specs/tor/tor_connect.rs | 150 +++++++++++++++++ util/app-config/src/configs/network.rs | 34 +++- util/launcher/src/lib.rs | 104 +++++++++++- util/onion/src/lib.rs | 18 ++ util/onion/src/onion_service.rs | 218 +++++++++++++++++++++++++ util/onion/src/tests/mod.rs | 20 +++ 16 files changed, 742 insertions(+), 13 deletions(-) create mode 100644 test/src/specs/tor/mod.rs create mode 100644 test/src/specs/tor/tor_basic.rs create mode 100644 test/src/specs/tor/tor_connect.rs create mode 100644 util/onion/src/onion_service.rs create mode 100644 util/onion/src/tests/mod.rs diff --git a/ckb-bin/src/subcommand/run.rs b/ckb-bin/src/subcommand/run.rs index f65f8d1f49..2b4c2d292b 100644 --- a/ckb-bin/src/subcommand/run.rs +++ b/ckb-bin/src/subcommand/run.rs @@ -7,6 +7,7 @@ use ckb_build_info::Version; use ckb_launcher::Launcher; use ckb_logger::info; use ckb_logger::warn; +use ckb_network::multiaddr::Multiaddr; use ckb_resource::{Resource, TemplateContext}; use ckb_stop_handler::{broadcast_exit_signals, wait_all_ckb_services_exit}; diff --git a/network/src/network.rs b/network/src/network.rs index 67f99fcab9..f9bdadd3f5 100644 --- a/network/src/network.rs +++ b/network/src/network.rs @@ -122,7 +122,8 @@ impl NetworkState { config.peer_store_path(), )); info!("Loaded the peer store."); - if let Some(ref proxy_url) = config.proxy_config.proxy_url { + + if let Some(ref proxy_url) = config.proxy.proxy_url { proxy::check_proxy_url(proxy_url).map_err(|reason| Error::Config(reason))?; } @@ -348,6 +349,12 @@ impl NetworkState { .collect() } + /// After onion service created, + /// ckb use this method to add onion address to public_addr + pub fn add_public_addr(&self, addr: Multiaddr) { + self.public_addrs.write().insert(addr); + } + pub(crate) fn connection_status(&self) -> ConnectionStatus { self.peer_registry.read().connection_status() } @@ -954,7 +961,7 @@ impl NetworkService { .max_connection_number(1024) .set_send_buffer_size(config.max_send_buffer()) .set_channel_size(config.channel_size()) - .timeout(Duration::from_secs(5)); + .timeout(Duration::from_secs(50)); #[cfg(not(target_family = "wasm"))] { @@ -996,10 +1003,11 @@ impl NetworkService { if init.is_ready() { break; } - let proxy_config_enable = config.proxy_config.proxy_url.is_some(); + let proxy_config_enable = + config.proxy.proxy_url.is_some() || config.onion.onion_server.is_some(); service_builder = service_builder - .tcp_proxy_config(config.proxy_config.proxy_url.clone()) - .tcp_onion_config(config.onion_config.onion_server.clone()); + .tcp_proxy_config(config.proxy.proxy_url.clone()) + .tcp_onion_config(config.onion.onion_server.clone()); match find_type(multi_addr) { TransportType::Tcp => { @@ -1329,6 +1337,11 @@ impl NetworkController { self.network_state.add_node(&self.p2p_control, address) } + /// Add a public_addr to NetworkState.public_addrs + pub fn add_public_addr(&self, public_addr: Multiaddr) { + self.network_state.add_public_addr(public_addr) + } + /// Disconnect session with peer id pub fn remove_node(&self, peer_id: &PeerId) { if let Some(session_id) = self diff --git a/network/src/peer_store/addr_manager.rs b/network/src/peer_store/addr_manager.rs index 62e96ee169..4f89df85cf 100644 --- a/network/src/peer_store/addr_manager.rs +++ b/network/src/peer_store/addr_manager.rs @@ -71,8 +71,12 @@ impl AddrManager { } } None => { - if addr_info.is_connectable(now_ms) && filter(&addr_info) { - addr_infos.push(addr_info); + if filter(&addr_info) { + if addr_info.is_connectable(now_ms) { + addr_infos.push(addr_info); + } else if addr_info.addr.to_string().starts_with("/onion3/") { + addr_infos.push(addr_info); + } } } } diff --git a/network/src/protocols/identify/mod.rs b/network/src/protocols/identify/mod.rs index 81926db734..acb8ec5e34 100644 --- a/network/src/protocols/identify/mod.rs +++ b/network/src/protocols/identify/mod.rs @@ -228,7 +228,7 @@ impl ServiceProtocol for IdentifyProtocol { .filter(|addr| { multiaddr_to_socketaddr(addr) .map(|socket_addr| !self.global_ip_only || is_reachable(socket_addr.ip())) - .unwrap_or(false) + .unwrap_or(true) }) .take(MAX_ADDRS) .cloned() diff --git a/test/Cargo.toml b/test/Cargo.toml index 552251f1de..ca9300d5c0 100644 --- a/test/Cargo.toml +++ b/test/Cargo.toml @@ -33,7 +33,7 @@ ckb-db = { path = "../db", version = "= 0.121.0-pre" } ckb-store = { path = "../store", version = "= 0.121.0-pre" } ckb-shared = { path = "../shared", version = "= 0.121.0-pre" } tempfile = "3" -reqwest = { version = "0.12", features = ["blocking", "json"] } +reqwest = { version = "0.12", features = ["blocking", "json", "socks"] } rand = "0.8" ckb-systemtime = { path = "../util/systemtime", version = "= 0.121.0-pre" } serde_json = "1.0" diff --git a/test/src/main.rs b/test/src/main.rs index d03e672e59..e9ca339b94 100644 --- a/test/src/main.rs +++ b/test/src/main.rs @@ -606,6 +606,8 @@ fn all_specs() -> Vec> { Box::new(CheckVmBExtension), Box::new(RandomlyKill), Box::new(SyncChurn), + Box::new(TorServiceContainsPublicAddr), + Box::new(TorConnect::new()), ]; specs.shuffle(&mut thread_rng()); specs diff --git a/test/src/node.rs b/test/src/node.rs index 24b511f263..5155aefee5 100644 --- a/test/src/node.rs +++ b/test/src/node.rs @@ -216,6 +216,19 @@ impl Node { self.inner.rpc_listen.clone() } + pub fn get_onion_public_addr(&self) -> Option { + let onion_public_addr = self + .rpc_client() + .local_node_info() + .addresses + .iter() + .filter(|addr| addr.address.contains("/onion3/")) + .collect::>() + .first() + .map(|addr| addr.address.clone()); + onion_public_addr + } + pub fn p2p_address(&self) -> String { format!("{}/p2p/{}", self.p2p_listen(), self.node_id()) } @@ -290,6 +303,32 @@ impl Node { } } + pub fn connect_onion(&self, peer: &Self) { + wait_until(30, || peer.get_onion_public_addr().is_some()); + + let onion_pub_address = peer + .get_onion_public_addr() + .expect("peer onion address is not found"); + + info!( + "got peer:{}'s onion address: {}", + peer.node_id(), + onion_pub_address + ); + + self.rpc_client() + .add_node(peer.node_id(), onion_pub_address); + let connected = wait_until(6000, || { + self.rpc_client() + .get_peers() + .iter() + .any(|p| p.node_id == peer.node_id()) + }); + if !connected { + panic!("Connect outbound peer timeout, node id: {}", peer.node_id()); + } + } + pub fn connect_uncheck(&self, peer: &Self) { self.rpc_client() .add_node(peer.node_id(), peer.p2p_listen()); diff --git a/test/src/specs/mod.rs b/test/src/specs/mod.rs index d981a242a2..63d8f3c841 100644 --- a/test/src/specs/mod.rs +++ b/test/src/specs/mod.rs @@ -8,6 +8,7 @@ mod p2p; mod relay; mod rpc; mod sync; +mod tor; mod tx_pool; pub use alert::*; @@ -20,6 +21,7 @@ pub use p2p::*; pub use relay::*; pub use rpc::*; pub use sync::*; +pub use tor::*; pub use tx_pool::*; use crate::Node; diff --git a/test/src/specs/tor/mod.rs b/test/src/specs/tor/mod.rs new file mode 100644 index 0000000000..24b821551f --- /dev/null +++ b/test/src/specs/tor/mod.rs @@ -0,0 +1,46 @@ +mod tor_basic; +mod tor_connect; + +use std::process::Child; + +use ckb_logger::info; +pub use tor_basic::*; +pub use tor_connect::*; + +use crate::utils::find_available_port; + +#[derive(Clone, Debug)] +struct TorServer { + tor_command_path: String, + socks_port: u16, + control_port: u16, +} + +impl TorServer { + pub fn new() -> Self { + TorServer { + tor_command_path: std::option_env!("TOR_COMMAND_PATH") + .unwrap_or("tor") + .to_string(), + socks_port: find_available_port(), + control_port: find_available_port(), + } + } + + fn build_tor_args(&self) -> Vec { + vec![ + "--SocksPort".to_string(), + self.socks_port.to_string(), + "--ControlPort".to_string(), + self.control_port.to_string(), + ] + } + + fn tor_start(&self) -> Child { + let mut cmd = std::process::Command::new(&self.tor_command_path); + let cmd = cmd.args(self.build_tor_args().clone()); + let child = cmd.spawn().unwrap(); + info!("tor started:({:?}) ; pid: {}", &self, child.id()); + child + } +} diff --git a/test/src/specs/tor/tor_basic.rs b/test/src/specs/tor/tor_basic.rs new file mode 100644 index 0000000000..c3532c156d --- /dev/null +++ b/test/src/specs/tor/tor_basic.rs @@ -0,0 +1,86 @@ +use crate::utils::find_available_port; +use crate::{Node, Spec}; +use ckb_logger::{error, info}; +use std::process::Child; + +use super::TorServer; + +// create a sender and receiver for tor_server signal +static TOR_SERVER_PROCESS: std::sync::LazyLock>> = + std::sync::LazyLock::new(|| std::sync::Mutex::new(None)); + +static TOR_SERVER: std::sync::OnceLock = std::sync::OnceLock::new(); + +struct TorServerGuard {} + +impl Drop for TorServerGuard { + fn drop(&mut self) { + let mut child = TOR_SERVER_PROCESS.lock().unwrap(); + let child = child.as_mut().unwrap(); + info!("killing tor server... {}", child.id()); + match child.kill() { + Ok(_) => { + info!("tor server exit success"); + } + Err(e) => { + error!("tor server exit failed: {:?}", e); + } + }; + } +} + +pub struct TorServiceContainsPublicAddr; + +impl Spec for TorServiceContainsPublicAddr { + crate::setup!(num_nodes: 1); + + fn before_run(&self) -> Vec { + let tor_server = TorServer::new(); + + TOR_SERVER.set(tor_server.clone()); + + let tor_server_process = tor_server.tor_start(); + *TOR_SERVER_PROCESS.lock().unwrap() = Some(tor_server_process); + + std::thread::sleep(std::time::Duration::from_secs(5)); + + let mut node0 = Node::new(self.name(), "node0"); + node0.modify_app_config(|config: &mut ckb_app_config::CKBAppConfig| { + config.network.onion.listen_on_onion = true; + config.network.onion.onion_server = + Some(format!("127.0.0.1:{}", tor_server.socks_port)); + config.network.onion.tor_controller = format!("127.0.0.1:{}", tor_server.control_port); + }); + + node0.start(); + + vec![node0] + } + + fn run(&self, nodes: &mut Vec) { + // when _tor_server_guard dropped, the tor server will be killed by Drop + let _tor_server_guard = TorServerGuard {}; + + let node = &nodes[0]; + + let rpc_client = node.rpc_client(); + let node_info = rpc_client.local_node_info(); + + let node_onion_addrs: Vec<_> = node_info + .addresses + .iter() + .filter(|addr| { + // check contains the onion address + info!("addr: {:?}", addr.address); + addr.address.contains("/onion3") + }) + .collect(); + assert!( + !node_onion_addrs.is_empty(), + "node should contains onion address" + ); + + let node_onion_p2p_addr: String = node_onion_addrs.first().unwrap().address.clone(); + info!("node_onion_p2p_addr: {}", node_onion_p2p_addr); + } +} diff --git a/test/src/specs/tor/tor_connect.rs b/test/src/specs/tor/tor_connect.rs new file mode 100644 index 0000000000..b5328f6ef1 --- /dev/null +++ b/test/src/specs/tor/tor_connect.rs @@ -0,0 +1,150 @@ +use std::process::Child; + +use ckb_logger::{error, info}; + +use crate::{utils::wait_until, Node, Spec}; + +use super::TorServer; + +pub struct TorConnect { + tor_server: TorServer, + tor_server_process: std::process::Child, +} + +impl TorConnect { + pub fn new() -> Self { + let tor_server = TorServer::new(); + let tor_server_process = tor_server.tor_start(); + TorConnect { + tor_server, + tor_server_process, + } + } +} + +impl Drop for TorConnect { + fn drop(&mut self) { + match self.tor_server_process.kill() { + Ok(_) => info!("tor server process killed"), + Err(e) => error!("tor server process kill failed: {:?}", e), + } + } +} + +impl Spec for TorConnect { + crate::setup!(num_nodes: 3); + + fn before_run(&self) -> Vec { + let mut nodes = (0..self.setup().num_nodes) + .map(|i| Node::new(self.name(), &format!("node{i}"))) + .collect::>(); + nodes.iter_mut().for_each(|node| { + node.modify_app_config(|config: &mut ckb_app_config::CKBAppConfig| { + config.logger.filter = Some("ckb-network=trace,info".to_string()); + + config.network.connect_outbound_interval_secs = 15; + + config.network.onion.listen_on_onion = true; + + // config.network.onion.onion_server = Some(format!("socks5://127.0.0.1:9050")); + // config.network.onion.tor_controller = format!("127.0.0.1:9051"); + + config.network.onion.onion_server = + Some(format!("socks5://127.0.0.1:{}", self.tor_server.socks_port)); + + config.network.onion.tor_controller = + format!("127.0.0.1:{}", self.tor_server.control_port); + + let p2p_addr = config.network.listen_addresses.first().unwrap().to_string(); + + let p2p_port: u16 = p2p_addr.split("/tcp/").last().unwrap().parse().unwrap(); + info!("node p2p listen port: {}", p2p_port); + + config.network.onion.onion_service_target = Some(format!("127.0.0.1:{}", p2p_port)); + }); + + node.start(); + }); + nodes + } + + fn run(&self, nodes: &mut Vec) { + let node0 = &nodes[0]; + let node1 = &nodes[1]; + let node2 = &nodes[2]; + + node0.mine_until_out_bootstrap_period(); + info!("node0 tip: {}", node0.get_tip_block_number()); + nodes.iter().for_each(|node| node.mine_until_out_ibd_mode()); + + info!( + "node0 {} connecting to node1 {}", + node0.node_id(), + node1.node_id() + ); + node1.connect_onion(node0); + info!( + "node0 {} connecting to node2 {}", + node0.node_id(), + node2.node_id() + ); + node2.connect_onion(node0); + info!( + "node0 {} and node1 {} connected, node0 {} and node2{} conencted", + node0.get_onion_public_addr().unwrap(), + node1.get_onion_public_addr().unwrap(), + node0.get_onion_public_addr().unwrap(), + node2.get_onion_public_addr().unwrap(), + ); + + let node1_node2_connected = wait_until(180, || { + let nodes_peers: Vec> = nodes + .iter() + .map(|node| { + let node_peers: Vec = node + .rpc_client() + .get_peers() + .iter() + .map(|addr| { + addr.addresses + .iter() + .map(|addr| addr.address.to_owned()) + .collect::>() + }) + .flatten() + .into_iter() + .collect(); + node_peers + }) + .collect(); + let node0_peers = nodes_peers[0].clone(); + let node1_peers = nodes_peers[1].clone(); + let node2_peers = nodes_peers[2].clone(); + + info!("node0_peers: {:?}", node0_peers); + info!("node1_peers: {:?}", node1_peers); + info!("node2_peers: {:?}", node2_peers); + node1_peers + .into_iter() + .filter(|addr| addr.starts_with("/onion3/")) + .collect::>() + .contains(&node2.get_onion_public_addr().unwrap()) + && node2_peers + .into_iter() + .filter(|addr| addr.starts_with("/onion3/")) + .collect::>() + .contains(&node1.get_onion_public_addr().unwrap()) + }); + assert!( + node1_node2_connected, + "node1 {} and node2 {} not connected", + node1.get_onion_public_addr().unwrap(), + node2.get_onion_public_addr().unwrap(), + ); + info!( + "node1 {} and node2 {} are connected", + node1.get_onion_public_addr().unwrap(), + node2.get_onion_public_addr().unwrap(), + ) + } +} diff --git a/util/app-config/src/configs/network.rs b/util/app-config/src/configs/network.rs index 3f10209544..7e011c1045 100644 --- a/util/app-config/src/configs/network.rs +++ b/util/app-config/src/configs/network.rs @@ -111,9 +111,32 @@ pub struct ProxyConfig { /// Onion related config options #[derive(Clone, Debug, Serialize, Deserialize, Default)] +#[serde(deny_unknown_fields)] pub struct OnionConfig { - // like: socks5://username:password@127.0.0.1:1080 - pub onion_url: Option, + // Automatically create Tor onion service, default: true + #[serde(default = "default_listen_on_onion")] + pub listen_on_onion: bool, + // onion service target, if CKB's p2p listen address not on default 127.0.0.1:8115, you should set this + pub onion_service_target: Option, + // Tor server url: like: 127.0.0.1:9050 + pub onion_server: Option, + // path to store onion private key, default is ./data/network/onion/onion_private_key + pub onion_private_key_path: Option, + // tor controllr url, example: 127.0.0.1:9050 + #[serde(default = "default_tor_controller")] + pub tor_controller: String, + // tor controller hashed password + pub tor_password: Option, +} + +/// By default, allow ckb to listen on onion address +const fn default_listen_on_onion() -> bool { + true +} + +/// By default, use tor controller on "127.0.0.1:9051" +fn default_tor_controller() -> String { + "127.0.0.1:9051".to_string() } /// Chain synchronization config options. @@ -271,6 +294,13 @@ impl Config { path } + /// Gets the onion network private key path. + pub fn onion_private_key_path(&self) -> PathBuf { + let mut path = self.path.clone(); + path.push("onion_private_key"); + path + } + /// Gets the peer store path. pub fn peer_store_path(&self) -> PathBuf { let mut path = self.path.clone(); diff --git a/util/launcher/src/lib.rs b/util/launcher/src/lib.rs index 8bf7105b16..edc6651ab4 100644 --- a/util/launcher/src/lib.rs +++ b/util/launcher/src/lib.rs @@ -3,7 +3,7 @@ //! ckb launcher is helps to launch ckb node. use ckb_app_config::{ - BlockAssemblerConfig, ExitCode, RpcConfig, RpcModule, RunArgs, SupportProtocol, + BlockAssemblerConfig, ExitCode, RpcConfig, RpcModule, RunArgs, SupportProtocol, Url, }; use ckb_async_runtime::Handle; use ckb_block_filter::filter::BlockFilter as BlockFilterService; @@ -12,13 +12,15 @@ use ckb_chain::ChainController; use ckb_channel::Receiver; use ckb_jsonrpc_types::ScriptHashType; use ckb_light_client_protocol_server::LightClientProtocol; -use ckb_logger::info; use ckb_logger::internal::warn; +use ckb_logger::{error, info}; +use ckb_network::Error; use ckb_network::{ network::TransportType, observe_listen_port_occupancy, CKBProtocol, Flags, NetworkController, NetworkService, NetworkState, SupportProtocols, }; use ckb_network_alert::alert_relayer::AlertRelayer; +use ckb_onion::OnionServiceConfig; use ckb_resource::Resource; use ckb_rpc::{RpcServer, ServiceBuilder}; use ckb_shared::shared_builder::{SharedBuilder, SharedPackage}; @@ -29,6 +31,7 @@ use ckb_tx_pool::service::TxVerificationResult; use ckb_types::prelude::*; use ckb_verification::GenesisVerifier; use ckb_verification_traits::Verifier; +use std::net::{Ipv4Addr, SocketAddr}; use std::sync::Arc; const SECP256K1_BLAKE160_SIGHASH_ALL_ARG_LEN: usize = 20; @@ -266,6 +269,99 @@ impl Launcher { } } + /// Start onion service + pub fn start_onion_service(&self, network_controller: NetworkController) -> Result<(), Error> { + if !self.args.config.network.onion.listen_on_onion { + info!("onion_config.listen_on_onion is false, CKB won't listen on the onion hidden netork"); + return Ok(()); + } + let onion_config = self.args.config.network.onion.clone(); + let onion_server: String = { + match ( + onion_config.onion_server, + self.args.config.network.proxy.proxy_url.clone(), + ) { + (Some(onion_server), _) => onion_server, + (None, Some(proxy_url)) => { + let proxy_url = Url::parse(&proxy_url) + .map_err(|err| Error::Config(format!("parse proxy_url failed: {}", err)))?; + match (proxy_url.host_str(), proxy_url.port()) { + (Some(host), Some(port)) => format!("{}:{}", host, port), + _ => { + error!("CKB tried to use the proxy url: {proxy_url} as onion server, but failed to parse it"); + return Err(Error::Config("Failed to parse proxy url".to_string())); + } + } + } + _ => { + info!("Neither onion_server nor proxy_url is set in the config file, CKB won't listen on the onion hidden network"); + return Ok(()); + } + } + }; + let onion_service_target: SocketAddr = { + match onion_config.onion_service_target { + Some(onion_service_target) => onion_service_target.parse().map_err(|err| { + Error::Config(format!("Failed to parse onion_service_target: {}", err)) + })?, + None => SocketAddr::new(std::net::IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8115), + } + }; + + { + // check tor_controller is listening + let tor_controller_addr = onion_config.tor_controller.parse().map_err(|err| { + Error::Config(format!("Failed to parse tor_controller address: {}", err)) + })?; + match std::net::TcpStream::connect_timeout( + &tor_controller_addr, + std::time::Duration::from_secs(2), + ) { + Ok(_c) => { + info!( + "CKB has confirmed that onion_conifg.tor_controller is listening on {}, trying to listen on the onion hidden network by the tor_controller", + onion_config.tor_controller + ); + } + Err(_err) => { + eprintln!("tor_controller is not listening on {}, CKB won't try to listen on the onion hidden network", tor_controller_addr); + return Ok(()); + } + } + } + + let onion_service_config: OnionServiceConfig = OnionServiceConfig { + onion_server, + onion_private_key_path: onion_config.onion_private_key_path.unwrap_or( + self.args + .config + .network + .onion_private_key_path() + .display() + .to_string(), + ), + tor_controller: onion_config.tor_controller, + tor_password: onion_config.tor_password, + onion_service_target, + }; + let onion_service = ckb_onion::onion_service::OnionService::new( + self.async_handle.clone(), + onion_service_config, + ) + .map_err(|err| Error::Config(format!("Failed to create onion service: {}", err)))?; + let node_id = network_controller.node_id(); + self.async_handle.spawn(async move { + match onion_service.start(node_id).await { + Ok(onion_service_addr) => { + info!("CKB has started listening on the onion hidden network, the onion service address is: {}", onion_service_addr); + network_controller.add_public_addr(onion_service_addr); + }, + Err(err) => error!("CKB failed to start listening on the onion hidden network: {}", err), + } + }); + Ok(()) + } + /// Start network service and rpc serve pub fn start_network_and_rpc( &self, @@ -445,6 +541,10 @@ impl Launcher { let _rpc = RpcServer::new(rpc_config, io_handler, self.rpc_handle.clone()); + if let Err(err) = self.start_onion_service(network_controller.clone()) { + error!("Failed to start onion service: {}", err); + } + network_controller } } diff --git a/util/onion/src/lib.rs b/util/onion/src/lib.rs index e69de29bb2..8dafb6d204 100644 --- a/util/onion/src/lib.rs +++ b/util/onion/src/lib.rs @@ -0,0 +1,18 @@ +use std::net::SocketAddr; + +pub mod onion_service; +mod tests; + +pub struct OnionServiceConfig { + // Tor server url: like: 127.0.0.1:9050 + pub onion_server: String, + // path to store onion private key, default is ./data/network/onion/onion_private_key + pub onion_private_key_path: String, + // tor controllr url, example: 127.0.0.1:9050 + pub tor_controller: String, + // tor controller hashed password + pub tor_password: Option, + // onion service will bind to CKB's p2p listen address, default is "127.0.0.1:8115" + // if you want to use other address, you should set it to the address you want + pub onion_service_target: SocketAddr, +} diff --git a/util/onion/src/onion_service.rs b/util/onion/src/onion_service.rs new file mode 100644 index 0000000000..19a5857f73 --- /dev/null +++ b/util/onion/src/onion_service.rs @@ -0,0 +1,218 @@ +use base64::Engine; +use ckb_async_runtime::Handle; +use ckb_channel::Receiver; +use ckb_error::{Error, InternalErrorKind}; +use ckb_logger::{debug, error, info}; +use multiaddr::{MultiAddr, Multiaddr, Onion3Addr}; +use std::{ + borrow::Cow, + net::{IpAddr, Ipv4Addr, SocketAddr}, + str::FromStr, +}; +use tokio::net::TcpStream; +use tokio::{fs::File, io::AsyncReadExt}; +use torut::{ + control::{TorAuthData, TorAuthMethod, UnauthenticatedConn, COOKIE_LENGTH}, + onion::TorSecretKeyV3, +}; + +use crate::OnionServiceConfig; + +pub struct OnionService { + key: TorSecretKeyV3, + config: OnionServiceConfig, + handle: Handle, +} +impl OnionService { + pub fn new(handle: Handle, config: OnionServiceConfig) -> Result { + let key = if std::fs::exists(&config.onion_private_key_path).map_err(|err| { + InternalErrorKind::Other + .other(format!("Failed to check onion private key path: {:?}", err)) + })? { + let raw = base64::engine::general_purpose::STANDARD + .decode(std::fs::read_to_string(&config.onion_private_key_path).unwrap()) + .map_err(|err| { + InternalErrorKind::Other + .other(format!("Failed to decode onion private key: {:?}", err)) + })?; + let raw = raw.as_slice(); + + if raw.len() != 64 { + return Err(InternalErrorKind::Other + .other("Invalid secret key length") + .into()); + } + let mut buf = [0u8; 64]; + buf.clone_from_slice(&raw[..]); + TorSecretKeyV3::from(buf) + } else { + let key = torut::onion::TorSecretKeyV3::generate(); + info!( + "Generated new onion service v3 key for address: {}", + key.public().get_onion_address() + ); + + std::fs::write( + &config.onion_private_key_path, + base64::engine::general_purpose::STANDARD.encode(key.as_bytes()), + ) + .map_err(|err| { + InternalErrorKind::Other + .other(format!("Failed to write onion private key: {:?}", err)) + })?; + + key + }; + + let onion_service = OnionService { + config, + key, + handle, + }; + Ok(onion_service) + } + + pub async fn start(&self, node_id: String) -> Result { + let s = TcpStream::connect(&format!("{}", self.config.tor_controller)) + .await + .map_err(|err| { + InternalErrorKind::Other + .other(format!("Failed to connect to tor controller: {:?}", err)) + })?; + + let mut utc = UnauthenticatedConn::new(s); + let proto_info = utc.load_protocol_info().await.map_err(|err| { + InternalErrorKind::Other.other(format!("Failed to load protocol info: {:?}", err)) + })?; + + proto_info.auth_methods.iter().for_each(|m| { + debug!("Tor Server supports auth method: {:?}", m); + }); + + if proto_info.auth_methods.contains(&TorAuthMethod::Null) { + utc.authenticate(&TorAuthData::Null).await.map_err(|err| { + InternalErrorKind::Other + .other(format!("Failed to authenticate with null: {:?}", err)) + })?; + } else if proto_info + .auth_methods + .contains(&TorAuthMethod::HashedPassword) + && self.config.tor_password.is_some() + { + utc.authenticate(&TorAuthData::HashedPassword(Cow::Owned( + self.config + .tor_password + .as_ref() + .expect("tor password exists") + .to_owned(), + ))) + .await + .map_err(|err| { + InternalErrorKind::Other + .other(format!("Failed to authenticate with password: {:?}", err)) + })?; + } else if proto_info.auth_methods.contains(&TorAuthMethod::Cookie) + || proto_info.auth_methods.contains(&TorAuthMethod::SafeCookie) + { + let cookie = { + let mut cookie_file = File::open( + proto_info + .cookie_file + .as_ref() + .ok_or_else(|| { + InternalErrorKind::Other + .other("Tor server did not provide cookie file path") + })? + .as_ref(), + ) + .await + .map_err(|err| { + InternalErrorKind::Other.other(format!("Failed to open cookie file: {:?}", err)) + })?; + + let mut cookie = Vec::new(); + cookie_file.read_to_end(&mut cookie).await.map_err(|err| { + InternalErrorKind::Other.other(format!("Failed to read cookie file: {:?}", err)) + })?; + assert_eq!(cookie.len(), COOKIE_LENGTH); + cookie + }; + let tor_auth_data = { + if proto_info.auth_methods.contains(&TorAuthMethod::Cookie) { + debug!("Using Cookie auth method..."); + TorAuthData::Cookie(Cow::Owned(cookie)) + } else { + debug!("Using SafeCookie auth method..."); + TorAuthData::SafeCookie(Cow::Owned(cookie)) + } + }; + utc.authenticate(&tor_auth_data).await.map_err(|err| { + InternalErrorKind::Other + .other(format!("Failed to authenticate with cookie: {:?}", err)) + })?; + } else { + return Err(InternalErrorKind::Other + .other("Tor server does not support any authentication method") + .into()); + } + + let mut ac = utc.into_authenticated().await; + ac.set_async_event_handler(Some(|_| async move { Ok(()) })); + + info!("Adding onion service v3..."); + ac.add_onion_v3( + &self.key, + false, + false, + false, + None, + &mut [(8115, self.config.onion_service_target)].iter(), + ) + .await + .map_err(|err| { + InternalErrorKind::Other.other(format!("Failed to add onion service: {:?}", err)) + })?; + info!("Added onion service v3!"); + + let tor_address_without_dot_onion = self + .key + .public() + .get_onion_address() + .get_address_without_dot_onion(); + + let onion_multi_addr_str = format!( + "/onion3/{}:8115/p2p/{}", + tor_address_without_dot_onion, node_id + ); + let onion_multi_addr = MultiAddr::from_str(&onion_multi_addr_str).map_err(|err| { + InternalErrorKind::Other.other(format!( + "Failed to parse onion address {} to multi_addr: {:?}", + onion_multi_addr_str, err + )) + })?; + + self.handle.spawn(async move { + let stop_rx = ckb_stop_handler::new_tokio_exit_rx(); + stop_rx.cancelled().await; + // wait stop_rx + info!("OnionService received stop signal, exiting..."); + + info!("Deleting created onion service..."); + // delete onion service so it works no more + if let Err(err) = ac + .del_onion(&tor_address_without_dot_onion) + .await + .map_err(|err| { + InternalErrorKind::Other + .other(format!("Failed to delete onion service: {:?}", err)) + }) + { + error!("Failed to delete onion service: {:?}", err); + } else { + info!("Deleted created onion service! It runs no more!"); + } + }); + + Ok(onion_multi_addr) + } +} diff --git a/util/onion/src/tests/mod.rs b/util/onion/src/tests/mod.rs new file mode 100644 index 0000000000..1e0d3dcd32 --- /dev/null +++ b/util/onion/src/tests/mod.rs @@ -0,0 +1,20 @@ +use std::net::SocketAddr; + +#[tokio::test] +async fn test_start_onion_by_controller() { + let tmp_dir = tempfile::tempdir().unwrap(); + let config = crate::OnionServiceConfig { + tor_controller: "127.0.0.1:9051".to_string(), + onion_private_key_path: tmp_dir + .path() + .join("test_tor_secret_path") + .to_string_lossy() + .to_string(), + onion_server: "127.0.0.:9050".to_string(), + tor_password: None, + onion_service_target: "127.0.0.1:9051".parse().unwrap(), + }; + let handle = ckb_async_runtime::new_background_runtime(); + let onion_service = crate::onion_service::OnionService::new(handle, config).unwrap(); + onion_service.start().await.unwrap(); +}