diff --git a/.github/workflows/golang.yml b/.github/workflows/golang.yml index d096a330..ea2f7dde 100644 --- a/.github/workflows/golang.yml +++ b/.github/workflows/golang.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - go-version: [1.18.x, 1.19.x, 1.20.x, stable] + go-version: [1.20.x, 1.21.x, stable] runs-on: ubuntu-latest steps: diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index ce4ab4d9..00000000 --- a/Cargo.lock +++ /dev/null @@ -1,1008 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[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 = "aes" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aes-gcm" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209b47e8954a928e1d72e86eca7000ebb6655fe1436d33eefc2201cad027e237" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "aho-corasick" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" -dependencies = [ - "memchr", -] - -[[package]] -name = "arrayref" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" - -[[package]] -name = "bitflags" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "combine" -version = "4.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "cpufeatures" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" -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 = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - -[[package]] -name = "deranged" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "equivalent" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" - -[[package]] -name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "error-chain" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" - -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - -[[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]] -name = "getrandom" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "ghash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "hashbrown" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hkdf" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "ipnetwork" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" -dependencies = [ - "serde", -] - -[[package]] -name = "itoa" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" - -[[package]] -name = "libc" -version = "0.2.147" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" - -[[package]] -name = "log" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -dependencies = [ - "log 0.4.19", -] - -[[package]] -name = "log" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "metadeps" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b122901b3a675fac8cecf68dcb2f0d3036193bc861d1ac0e1c337f7d5254c2" -dependencies = [ - "error-chain", - "pkg-config", - "toml 0.2.1", -] - -[[package]] -name = "no-std-net" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" - -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[package]] -name = "pnet" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd959a8268165518e2bf5546ba84c7b3222744435616381df3c456fe8d983576" -dependencies = [ - "ipnetwork", - "pnet_base", - "pnet_datalink", - "pnet_packet", - "pnet_sys", - "pnet_transport", -] - -[[package]] -name = "pnet_base" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "872e46346144ebf35219ccaa64b1dffacd9c6f188cd7d012bd6977a2a838f42e" -dependencies = [ - "no-std-net", -] - -[[package]] -name = "pnet_datalink" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c302da22118d2793c312a35fb3da6846cb0fab6c3ad53fd67e37809b06cdafce" -dependencies = [ - "ipnetwork", - "libc", - "pnet_base", - "pnet_sys", - "winapi", -] - -[[package]] -name = "pnet_macros" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a780e80005c2e463ec25a6e9f928630049a10b43945fea83207207d4a7606f4" -dependencies = [ - "proc-macro2", - "quote", - "regex", - "syn 1.0.109", -] - -[[package]] -name = "pnet_macros_support" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d932134f32efd7834eb8b16d42418dac87086347d1bc7d142370ef078582bc" -dependencies = [ - "pnet_base", -] - -[[package]] -name = "pnet_packet" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bde678bbd85cb1c2d99dc9fc596e57f03aa725f84f3168b0eaf33eeccb41706" -dependencies = [ - "glob", - "pnet_base", - "pnet_macros", - "pnet_macros_support", -] - -[[package]] -name = "pnet_sys" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf7a58b2803d818a374be9278a1fe8f88fce14b936afbe225000cfcd9c73f16" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "pnet_transport" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "813d1c0e4defbe7ee22f6fe1755f122b77bfb5abe77145b1b5baaf463cab9249" -dependencies = [ - "libc", - "pnet_base", - "pnet_packet", - "pnet_sys", -] - -[[package]] -name = "polyval" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro2" -version = "1.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "protobuf" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55bad9126f378a853655831eb7363b7b01b81d19f8cb1218861086ca4a1a61e" -dependencies = [ - "once_cell", - "protobuf-support", - "thiserror", -] - -[[package]] -name = "protobuf-support" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d4d7b8601c814cfb36bcebb79f0e61e45e1e93640cf778837833bbed05c372" -dependencies = [ - "thiserror", -] - -[[package]] -name = "quote" -version = "1.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redis" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ea8c51b5dc1d8e5fd3350ec8167f464ec0995e79f2e90a075b63371500d557f" -dependencies = [ - "combine", - "itoa", - "percent-encoding", - "ryu", - "sha1_smol", - "url", -] - -[[package]] -name = "regex" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89089e897c013b3deb627116ae56a6955a72b8bed395c9526af31c9fe528b484" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa250384981ea14565685dea16a9ccc4d1c541a13f82b9c168572264d1df8c56" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" - -[[package]] -name = "rust_dark_decoy" -version = "0.0.1" -dependencies = [ - "aes-gcm", - "arrayref", - "cc", - "digest", - "errno", - "hex", - "hkdf", - "ipnetwork", - "libc", - "log 0.4.19", - "pnet", - "protobuf", - "rand", - "redis", - "serde", - "sha2", - "time", - "toml 0.7.6", - "tuntap", - "zmq", -] - -[[package]] -name = "ryu" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" - -[[package]] -name = "serde" -version = "1.0.188" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.188" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "serde_spanned" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" -dependencies = [ - "serde", -] - -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - -[[package]] -name = "sha2" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c16a64ba9387ef3fdae4f9c1a7f07a0997fce91985c0336f1ddc1822b3b37802" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d14928354b01c4d6a4f0e549069adef399a284e7995c7ccca94e8a07a5346c59" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "time" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48" -dependencies = [ - "deranged", - "itoa", - "libc", - "num_threads", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" - -[[package]] -name = "time-macros" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572" -dependencies = [ - "time-core", -] - -[[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 = "toml" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" - -[[package]] -name = "toml" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.19.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tuntap" -version = "0.0.1" -source = "git+https://github.com/ewust/tuntap.rs#470550b5c891808f99f5b69a7203756fdff0f3ca" -dependencies = [ - "bitflags 0.7.0", - "libc", - "log 0.3.9", -] - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "unicode-bidi" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - -[[package]] -name = "unicode-ident" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "url" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.48.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" - -[[package]] -name = "winnow" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" -dependencies = [ - "memchr", -] - -[[package]] -name = "zmq" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aad98a7a617d608cd9e1127147f630d24af07c7cd95ba1533246d96cbdd76c66" -dependencies = [ - "bitflags 1.3.2", - "libc", - "log 0.4.19", - "zmq-sys", -] - -[[package]] -name = "zmq-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d33a2c51dde24d5b451a2ed4b488266df221a5eaee2ee519933dc46b9a9b3648" -dependencies = [ - "libc", - "metadeps", -] diff --git a/Cargo.toml b/Cargo.toml index 4bd682fc..e91a6756 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,24 +1,26 @@ + [package] -name = "rust_dark_decoy" +name = "detector_rs" version = "0.0.1" authors = ["Eric Wustrow "] -include = ["src/*"] +include = ["cmd/detector/src/*"] links="tapdance" build="build.rs" +[lib] +name = "detector_rs" +crate-type = ["rlib", "staticlib"] +path = "cmd/detector/src/lib.rs" + [build-dependencies] cc="^1.0.3" - -[lib] -name = "rust_dark_decoy" -crate-type = ["rlib", "staticlib"] [dependencies] toml = "0.7" serde = {version="1.0", features=["derive"]} libc = "0.2" aes-gcm = { version="0.10", features=["aes"]} -time = {version="0.3.28", features=["macros", "formatting", "local-offset"]} +time = {version="0.3.28", features=["macros", "formatting", "local-offset"]} pnet = "0.33" arrayref = "0.3" log = "0.4" diff --git a/Makefile b/Makefile index ceb5f130..40af9f5a 100644 --- a/Makefile +++ b/Makefile @@ -3,38 +3,38 @@ CC = ${CROSS_COMPILE}gcc #--platform=native DEBUG_OR_RELEASE = release -RUST_LIB=./target/release/librust_dark_decoy.a -TD_LIB=./libtapdance/libtapdance.a +RUST_LIB=./target/release/libdetector_rs.a +TD_LIB=./cmd/detector/libtapdance/libtapdance.a LIBS=${RUST_LIB} ${TD_LIB} -L/usr/local/lib -lpcap -lpfring -lzmq -lcrypto -lpthread -lrt -lgmp -ldl -lm CFLAGS = -Wall -DENABLE_BPF -DHAVE_PF_RING -DHAVE_PF_RING_ZC -DTAPDANCE_USE_PF_RING_ZERO_COPY -O2 # -g -PROTO_RS_PATH=src/signalling.rs +PROTO_RS_PATH=./cmd/detector/src/signalling.rs EXE_DIR=./bin all: rust libtd conjure app registration-server ${PROTO_RS_PATH} sim: rust libtd conjure-sim app registration-server ${PROTO_RS_PATH} -rust: ./src/*.rs - cargo build --${DEBUG_OR_RELEASE} +rust: + cd ./cmd/detector/ && cargo build --${DEBUG_OR_RELEASE} test: - cargo test --${DEBUG_OR_RELEASE} + cd ./cmd/detector/ && cargo test --${DEBUG_OR_RELEASE} app: [ -d $(EXE_DIR) ] || mkdir -p $(EXE_DIR) go build -o ${EXE_DIR}/application ./cmd/application libtd: - cd ./libtapdance/ && make libtapdance.a + cd ./cmd/detector/libtapdance/ && make libtapdance.a -conjure: detect.c loadkey.c rust_util.c rust libtapdance +conjure: rust ./cmd/detector/libtapdance [ -d $(EXE_DIR) ] || mkdir -p $(EXE_DIR) - ${CC} ${CFLAGS} -o ${EXE_DIR}/$@ detect.c loadkey.c rust_util.c ${LIBS} + ${CC} ${CFLAGS} -o ${EXE_DIR}/$@ ./cmd/detector/detect.c ./cmd/detector/loadkey.c ./cmd/detector/rust_util.c ${LIBS} -conjure-sim: detect.c loadkey.c rust_util.c rust libtapdance +conjure-sim: rust ./cmd/detector/libtapdance [ -d $(EXE_DIR) ] || mkdir -p $(EXE_DIR) - ${CC} -Wall -O2 -o ${EXE_DIR}/conjure detect.c loadkey.c rust_util.c ${LIBS} + ${CC} -Wall -O2 -o ${EXE_DIR}/conjure ./cmd/detector/detect.c ./cmd/detector/loadkey.c ./cmd/detector/rust_util.c ${LIBS} registration-server: [ -d $(EXE_DIR) ] || mkdir -p $(EXE_DIR) @@ -84,7 +84,7 @@ endif $(RM) -rf backup clean: - cargo clean + cd ./cmd/detector/ && cargo clean $(RM) -rf *.o *~ ${EXE_DIR} cd ./libtapdance/ && make clean diff --git a/build.rs b/build.rs index 0896ba5d..f7c62ba9 100644 --- a/build.rs +++ b/build.rs @@ -2,7 +2,7 @@ extern crate cc; fn main() { cc::Build::new() - .file("libtapdance/tapdance.c") + .file("cmd/detector/libtapdance/tapdance.c") .include("src") .compile("libtapdance.a"); } diff --git a/cmd/application/conns.go b/cmd/application/conns.go index 290b0c4b..f35240f2 100644 --- a/cmd/application/conns.go +++ b/cmd/application/conns.go @@ -16,8 +16,8 @@ import ( "syscall" "time" + "github.com/refraction-networking/conjure/pkg/log" cj "github.com/refraction-networking/conjure/pkg/station/lib" - "github.com/refraction-networking/conjure/pkg/station/log" "github.com/refraction-networking/conjure/pkg/transports" ) diff --git a/cmd/application/conns_test.go b/cmd/application/conns_test.go index 158d59a7..473ccc2a 100644 --- a/cmd/application/conns_test.go +++ b/cmd/application/conns_test.go @@ -12,8 +12,8 @@ import ( "time" "github.com/refraction-networking/conjure/internal/conjurepath" + "github.com/refraction-networking/conjure/pkg/log" cj "github.com/refraction-networking/conjure/pkg/station/lib" - "github.com/refraction-networking/conjure/pkg/station/log" ) // MockGeoIP is a mock implementation of the geoip.GeoIP interface. diff --git a/cmd/application/go.mod b/cmd/application/go.mod index 5b3b2d2f..1831fac9 100644 --- a/cmd/application/go.mod +++ b/cmd/application/go.mod @@ -1,3 +1,42 @@ module github.com/refraction-networking/conjure/cmd/application go 1.20 + +replace github.com/refraction-networking/conjure => ../../ + +require ( + github.com/refraction-networking/conjure v0.0.0-00010101000000-000000000000 + github.com/stretchr/testify v1.8.4 + google.golang.org/protobuf v1.31.0 +) + +require ( + github.com/BurntSushi/toml v1.3.2 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dchest/siphash v1.2.3 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect + github.com/google/gopacket v1.1.19 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/libp2p/go-reuseport v0.4.0 // indirect + github.com/mroth/weightedrand v1.0.0 // indirect + github.com/oschwald/geoip2-golang v1.9.0 // indirect + github.com/oschwald/maxminddb-golang v1.12.0 // indirect + github.com/pebbe/zmq4 v1.2.10 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pion/dtls/v2 v2.2.7 // indirect + github.com/pion/logging v0.2.2 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/sctp v1.8.8 // indirect + github.com/pion/stun v0.6.1 // indirect + github.com/pion/transport/v2 v2.2.3 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/refraction-networking/ed25519 v0.1.2 // indirect + github.com/refraction-networking/obfs4 v0.1.2 // indirect + gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.5.0 // indirect + golang.org/x/crypto v0.13.0 // indirect + golang.org/x/net v0.15.0 // indirect + golang.org/x/sys v0.12.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/cmd/application/go.sum b/cmd/application/go.sum index 9313dee5..dd07c5ff 100644 --- a/cmd/application/go.sum +++ b/cmd/application/go.sum @@ -1,4 +1,141 @@ -github.com/refraction-networking/conjure v0.6.0-dtlsbeta h1:4k0Y93MR6sgLQUs2nFyUZO0pdSx5JWDPjFq/EpuVsnQ= -github.com/refraction-networking/conjure v0.6.0-dtlsbeta/go.mod h1:/Ah4d0Pa8tIjKHaZhA/50l0E+IehYmzewSg46SfG7hw= -github.com/refraction-networking/conjure v0.6.0 h1:kDOWPE9WY+zquJsXDifxjUh98LlqJB+fhlEyoqQdlug= -github.com/refraction-networking/conjure v0.6.0/go.mod h1:iRRZEI3nZsBLn1Er6xPwGwi68XNCKlno4kkWlMvMSk8= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= +github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= +github.com/mroth/weightedrand v1.0.0 h1:V8JeHChvl2MP1sAoXq4brElOcza+jxLkRuwvtQu8L3E= +github.com/mroth/weightedrand v1.0.0/go.mod h1:3p2SIcC8al1YMzGhAIoXD+r9olo/g/cdJgAD905gyNE= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc= +github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y= +github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= +github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= +github.com/pebbe/zmq4 v1.2.10 h1:wQkqRZ3CZeABIeidr3e8uQZMMH5YAykA/WN0L5zkd1c= +github.com/pebbe/zmq4 v1.2.10/go.mod h1:nqnPueOapVhE2wItZ0uOErngczsJdLOGkebMxaO8r48= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/sctp v1.8.8 h1:5EdnnKI4gpyR1a1TwbiS/wxEgcUWBHsc7ILAjARJB+U= +github.com/pion/sctp v1.8.8/go.mod h1:igF9nZBrjh5AtmKc7U30jXltsFHicFCXSmWA2GWRaWs= +github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.3 h1:XcOE3/x41HOSKbl1BfyY1TF1dERx7lVvlMCbXU7kfvA= +github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/refraction-networking/ed25519 v0.1.2 h1:08kJZUkAlY7a7cZGosl1teGytV+QEoNxPO7NnRvAB+g= +github.com/refraction-networking/ed25519 v0.1.2/go.mod h1:nxYLUAYt/hmNpAh64PNSQ/tQ9gTIB89wCaGKJlRtZ9I= +github.com/refraction-networking/obfs4 v0.1.2 h1:J842O4fGSkd2W8ogYj0KN6gqVVY+Cpqodw9qFGL7wVU= +github.com/refraction-networking/obfs4 v0.1.2/go.mod h1:wAl/+gWiLsrcykJA3nKJHx89f5/gXGM8UKvty7+mvbM= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.5.0 h1:rzdY78Ox2T+VlXcxGxELF+6VyUXlZBhmRqZu5etLm+c= +gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.5.0/go.mod h1:70bhd4JKW/+1HLfm+TMrgHJsUHG4coelMWwiVEJ2gAg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/application/main.go b/cmd/application/main.go index 11b619de..4fe9bfc6 100644 --- a/cmd/application/main.go +++ b/cmd/application/main.go @@ -12,8 +12,8 @@ import ( "time" "github.com/refraction-networking/conjure/pkg/dtls/dnat" + "github.com/refraction-networking/conjure/pkg/log" cj "github.com/refraction-networking/conjure/pkg/station/lib" - "github.com/refraction-networking/conjure/pkg/station/log" "github.com/refraction-networking/conjure/pkg/transports/connecting/dtls" "github.com/refraction-networking/conjure/pkg/transports/wrapping/min" "github.com/refraction-networking/conjure/pkg/transports/wrapping/obfs4" diff --git a/cmd/cli/README.md b/cmd/cli/README.md new file mode 100644 index 00000000..acb7db1b --- /dev/null +++ b/cmd/cli/README.md @@ -0,0 +1,82 @@ +# Conjure Client Test CLI + +# Build +After [downloading Golang, TD and dependencies:](../README.md) + +```sh + cd conjure/cmd/cli # works even if GOPATH is not set + go build -a . +``` + +# Usage + +Simply run + +```sh +./cli -connect-addr="" +``` + +to listen to local connections on default 10500 port. + +Then, you'll have a few options: + +## Configure HTTP proxy + +You will need to ask your particular application(e.g. browser) to use 127.0.0.1:10500 as HTTP proxy. +In Firefox (both mobile and desktop) I prefer to type ```about:config``` into address line and set the following: + +```conf +network.proxy.http_port = 10500 +network.proxy.http = 127.0.0.1 +network.proxy.ssl_port = 10500 +network.proxy.ssl = 127.0.0.1 +network.proxy.type = 1 +``` + +To disable proxying you may simply set ```network.proxy.type``` back to ```5``` or ```0```. + +The same settings are available in Firefox GUI: Preferences->Advanced->Network->Settings + +## Configure ssh SOCKS proxy + +If you have access to some ssh server, say `socksserver`, you can set up ssh SOCKS tunnel. +First, modify and add the following to `.ssh/config`: + +```ssh +Host socksserver-td +Hostname 123.456.789.012 +User cookiemonster +ProxyCommand nc -X connect -x 127.0.0.1:10500 %h %p +``` + +then run `ssh -D1234 socksserver-td -4` + +Now in Firefox you could just go to Preferences->Advanced->Network->Settings and set SOCKSv5 host to localhost:1234. + +## Some utilities use following enivoronment variables: + + ```bash +export https_proxy=127.0.0.1:10500 +export http_proxy=127.0.0.1:10500 +wget https://twitter.com +``` + +Most of the popular utilities also have a flag to specify a proxy. + +## Docker + +A simple dockerfile is provided that instantiates a golang environment in which to +run the cli. This is primarily meant to be used with [the GNS3 simulation +environment](https://github.com/refraction-networking/conjure/wiki/GNS3-Simulation). + +To build the docker environemnt use: + +```sh +# run from repo root +docker build -t conjure/cli -f cmd/cli/cli.dockerfile cmd/cli/ +``` + +The environment can then be attached to using a `docker exec` or using telnet +in the case of gns3. See the [wiki page](https://docs.gns3.com/docs/emulators/create-a-docker-container-for-gns3) +for local docker image builds in gns3 for more details on setting up local +docker appliances in gns3. diff --git a/cmd/cli/cli.dockerfile b/cmd/cli/cli.dockerfile new file mode 100644 index 00000000..e3a40f52 --- /dev/null +++ b/cmd/cli/cli.dockerfile @@ -0,0 +1,11 @@ +FROM golang:latest + +RUN apt-get update +RUN apt-get install -y -f libzmq3-dev + +WORKDIR /go/src/github/refracction-networking/conjure +COPY cmd/cli /cli + +RUN go mod download +RUN go mod tidy +RUN go install ./cmd/cli diff --git a/cmd/cli/go.mod b/cmd/cli/go.mod new file mode 100644 index 00000000..e69de29b diff --git a/cmd/cli/main.go b/cmd/cli/main.go new file mode 100644 index 00000000..ef031a11 --- /dev/null +++ b/cmd/cli/main.go @@ -0,0 +1,318 @@ +package main + +import ( + "encoding/hex" + "errors" + "flag" + "fmt" + "io" + "net" + "os" + "strings" + "sync" + "time" + + "github.com/pkg/profile" + "github.com/refraction-networking/conjure" + "github.com/refraction-networking/conjure/pkg/client/assets" + "github.com/refraction-networking/conjure/pkg/log" + "github.com/refraction-networking/conjure/pkg/phantoms" + "github.com/refraction-networking/conjure/pkg/registrars/decoy-registrar" + "github.com/refraction-networking/conjure/pkg/registrars/registration" + transports "github.com/refraction-networking/conjure/pkg/transports/client" + pb "github.com/refraction-networking/conjure/proto" +) + +const ( + defaultAPIEndpoint = "https://registration.refraction.network/api/register" + defaultBDAPIEndpoint = "https://registration.refraction.network/api/register-bidirectional" + defaultConnectionDelay = 750 * time.Millisecond +) + +func main() { + defer profile.Start().Stop() + + var port = flag.Int("port", 10500, "TapDance will listen for connections on this port.") + var excludeV6 = flag.Bool("disable-ipv6", false, "Explicitly disable IPv6 decoys. Default(false): enable IPv6 only if interface with global IPv6 address is available.") + var proxyHeader = flag.Bool("proxy", false, "Send the proxy header with all packets from station to covert host") + var decoy = flag.String("decoy", "", "Sets single decoy. ClientConf won't be requested. "+ + "Accepts \"SNI,IP\" or simply \"SNI\" — IP will be resolved. "+ + "Examples: \"site.io,1.2.3.4\", \"site.io\"") + var assetsLocation = flag.String("assetsdir", "./assets/", "Folder to read assets from.") + var width = flag.Uint("w", 5, "Number of registrations sent for each connection initiated") + var debug = flag.Bool("debug", false, "Enable debug level logs") + var trace = flag.Bool("trace", false, "Enable trace level logs") + var connectTarget = flag.String("connect-addr", "", "If set, conjure will transparently connect to provided address, which must be either hostname:port or ip:port. "+ + "Default(unset): connects client to forwardproxy, to which CONNECT request is yet to be written.") + + var APIRegistration = flag.String("api-endpoint", "", "If set, API endpoint to use when performing API registration. Defaults to https://registration.refraction.network/api/register (or register-bidirectional for bdapi)") + var registrar = flag.String("registrar", "decoy", "One of decoy, api, bdapi, dns, bddns.") + var transport = flag.String("transport", "min", `The transport to use for Conjure connections. Current values include "prefix", "min" and "obfs4", "dtls".`) + var randomizeDstPort = flag.Bool("rand-dst-port", true, `enable destination port randomization for the transport connection`) + var prefixID = flag.Int("prefix-id", -1, "ID of the prefix to send, used with the `transport=\"prefix\"` option. Default is Random. See prefix transport for options") + var disableOverrides = flag.Bool("disable-overrides", false, "Informs the registrar that chosen parameters will be used, only applicable to bidirectional reg methods") + var phantomNet = flag.String("phantom", "", "Target phantom subnet. Must overlap with ClientConf, and will be achieved by brute force of seeds until satisfied") + + flag.Usage = func() { + fmt.Fprintf(os.Stderr, "Dark Decoy CLI\n$./cli -connect-addr= [OPTIONS] \n\nOptions:\n") + flag.PrintDefaults() + } + flag.Parse() + + if *connectTarget == "" { + log.Errorf("dark decoys require -connect-addr to be set\n") + flag.Usage() + + os.Exit(1) + } + + v6Support := !*excludeV6 + + _, err := conjure.AssetsSetDir(*assetsLocation) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to parse assets: %s", err) + os.Exit(1) + } + + if *decoy != "" { + err := setSingleDecoyHost(*decoy) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to set single decoy host: %s\n", err) + flag.Usage() + os.Exit(255) + } + } + + // Check that the provided phantom net overlaps with at least one of our phatom options + if *phantomNet != "" { + // Load phantoms + subnets, err := phantoms.GetUnweightedSubnetList(assets.Assets().GetPhantomSubnets()) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to get Phantom subnets: %v\n", err) + os.Exit(255) + } + + // Check that the provided phantom parses as a CIDR range + _, phantomRange, err := net.ParseCIDR(*phantomNet) + if err != nil { + fmt.Fprintf(os.Stderr, "Error parsing phantom subnet %s: %v\n", *phantomNet, err) + flag.Usage() + os.Exit(255) + } + + // Iterate through all subnets, see if any overlap with the phantomRange + found := false + for _, subnet := range subnets { + if subnet.Contains(phantomRange.IP) || phantomRange.Contains(subnet.IP) { + found = true + break + } + } + if !found { + fmt.Fprintf(os.Stderr, "Error: provided phantom net %v does not overlap with any phantoms in ClientConf\n", *phantomNet) + os.Exit(255) + } + } + + if *debug { + log.SetLevel(log.DebugLevel) + log.Debug("Debug logging enabled") + } + if *trace { + log.SetLevel(log.TraceLevel) + log.Trace("Trace logging enabled") + } + + fmt.Printf("Using Station Pubkey: %s\n", hex.EncodeToString(conjure.GetPubkey()[:])) + + var params any + var t conjure.Transport + switch *transport { + case "prefix": + pID := int32(*prefixID) + params = &pb.PrefixTransportParams{RandomizeDstPort: randomizeDstPort, PrefixId: &pID} + default: + params = &pb.GenericTransportParams{RandomizeDstPort: randomizeDstPort} + } + + t, err = transports.NewWithParams(*transport, params) + if err != nil { + e := fmt.Errorf("error finding or creating transport %v: %v", *transport, err) + log.Println(e) + os.Exit(1) + } + + err = connectDirect(*APIRegistration, *registrar, *connectTarget, *port, *proxyHeader, v6Support, *width, t, *disableOverrides, *phantomNet) + if err != nil { + log.Println(err) + os.Exit(1) + } +} + +func connectDirect(apiEndpoint string, registrar string, connectTarget string, localPort int, proxyHeader bool, v6Support bool, width uint, t conjure.Transport, disableOverrides bool, phantomNet string) error { + if _, _, err := net.SplitHostPort(connectTarget); err != nil { + return fmt.Errorf("failed to parse host and port from connectTarget %s: %v", + connectTarget, err) + + } + + l, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: localPort}) + if err != nil { + return fmt.Errorf("error listening on port %v: %v", localPort, err) + } + + dialer := conjure.Dialer{ + UseProxyHeader: proxyHeader, + IPSupport: v6Support, + RegDelay: defaultConnectionDelay, + Transport: t, + PhantomNet: phantomNet, + DisableRegistrarOverrides: disableOverrides, + } + + decoyRegistrar := decoy.NewDecoyRegistrar() + decoyRegistrar.Width = width + switch registrar { + case "decoy": + dialer.Registrar = decoyRegistrar + case "api": + if apiEndpoint == "" { + apiEndpoint = defaultAPIEndpoint + } + dialer.Registrar, err = registration.NewAPIRegistrar(®istration.Config{ + Target: apiEndpoint, + Bidirectional: false, + MaxRetries: 3, + SecondaryRegistrar: decoyRegistrar, + }) + if err != nil { + return fmt.Errorf("error creating API registrar: %w", err) + } + case "bdapi": + if apiEndpoint == "" { + apiEndpoint = defaultBDAPIEndpoint + } + dialer.Registrar, err = registration.NewAPIRegistrar(®istration.Config{ + Target: apiEndpoint, + Bidirectional: true, + MaxRetries: 3, + SecondaryRegistrar: decoyRegistrar, + }) + if err != nil { + return fmt.Errorf("error creating API registrar: %w", err) + } + case "dns": + dnsConf := conjure.Assets().GetDNSRegConf() + dialer.Registrar, err = newDNSRegistrarFromConf(dnsConf, false, 3, conjure.Assets().GetPubkey()[:]) + if err != nil { + return fmt.Errorf("error creating DNS registrar: %w", err) + } + case "bddns": + dnsConf := conjure.Assets().GetDNSRegConf() + dialer.Registrar, err = newDNSRegistrarFromConf(dnsConf, true, 3, conjure.Assets().GetPubkey()[:]) + if err != nil { + return fmt.Errorf("error creating DNS registrar: %w", err) + } + default: + return fmt.Errorf("unknown registrar %v", registrar) + } + + for { + clientConn, err := l.AcceptTCP() + if err != nil { + return fmt.Errorf("error accepting client connection %v: ", err) + } + + go manageConn(dialer, connectTarget, clientConn) + } +} + +func manageConn(dialer conjure.Dialer, connectTarget string, clientConn *net.TCPConn) { + tdConn, err := dialer.Dial("tcp", connectTarget) + if err != nil || tdConn == nil { + fmt.Printf("failed to dial %s: %v\n", connectTarget, err) + return + } + + // Copy data from the client application into the DarkDecoy connection. + // TODO: proper connection management with idle timeout + var wg sync.WaitGroup + wg.Add(2) + go func() { + io.Copy(tdConn, clientConn) + wg.Done() + tdConn.Close() + }() + go func() { + io.Copy(clientConn, tdConn) + wg.Done() + clientConn.CloseWrite() + }() + wg.Wait() + log.Debug("copy loop ended") +} + +func setSingleDecoyHost(decoy string) error { + splitDecoy := strings.Split(decoy, ",") + + var ip string + switch len(splitDecoy) { + case 1: + ips, err := net.LookupHost(decoy) + if err != nil { + return err + } + ip = ips[0] + case 2: + ip = splitDecoy[1] + if net.ParseIP(ip) == nil { + return errors.New("provided IP address \"" + ip + "\" is invalid") + } + default: + return errors.New("\"" + decoy + "\" contains too many commas") + } + + sni := splitDecoy[0] + + decoySpec := pb.InitTLSDecoySpec(ip, sni) + conjure.Assets().GetClientConfPtr().DecoyList = + &pb.DecoyList{ + TlsDecoys: []*pb.TLSDecoySpec{ + decoySpec, + }, + } + maxUint32 := ^uint32(0) // max generation: station won't send ClientConf + conjure.Assets().GetClientConfPtr().Generation = &maxUint32 + log.Infof("Single decoy parsed. SNI: %s, IP: %s", sni, ip) + return nil +} + +// NewDNSRegistrarFromConf creates a DNSRegistrar from DnsRegConf protobuf. Uses the pubkey in conf as default. If it is not supplied (nil), uses fallbackKey instead. +func newDNSRegistrarFromConf(conf *pb.DnsRegConf, bidirectional bool, maxTries int, fallbackKey []byte) (*registration.DNSRegistrar, error) { + pubkey := conf.Pubkey + if pubkey == nil { + pubkey = fallbackKey + } + var method registration.DNSTransportMethodType + switch *conf.DnsRegMethod { + case pb.DnsRegMethod_UDP: + method = registration.UDP + case pb.DnsRegMethod_DOT: + method = registration.DoT + case pb.DnsRegMethod_DOH: + method = registration.DoH + default: + return nil, errors.New("unknown reg method in conf") + } + + return registration.NewDNSRegistrar(®istration.Config{ + DNSTransportMethod: method, + Target: *conf.Target, + BaseDomain: *conf.Domain, + Pubkey: pubkey, + UTLSDistribution: *conf.UtlsDistribution, + MaxRetries: maxTries, + Bidirectional: bidirectional, + STUNAddr: *conf.StunServer, + }) +} diff --git a/detect.c b/cmd/detector/detect.c similarity index 100% rename from detect.c rename to cmd/detector/detect.c diff --git a/libtapdance/Makefile b/cmd/detector/libtapdance/Makefile similarity index 100% rename from libtapdance/Makefile rename to cmd/detector/libtapdance/Makefile diff --git a/libtapdance/curve25519-donna-c64.c b/cmd/detector/libtapdance/curve25519-donna-c64.c similarity index 100% rename from libtapdance/curve25519-donna-c64.c rename to cmd/detector/libtapdance/curve25519-donna-c64.c diff --git a/libtapdance/decode.c b/cmd/detector/libtapdance/decode.c similarity index 100% rename from libtapdance/decode.c rename to cmd/detector/libtapdance/decode.c diff --git a/libtapdance/elligator2.c b/cmd/detector/libtapdance/elligator2.c similarity index 100% rename from libtapdance/elligator2.c rename to cmd/detector/libtapdance/elligator2.c diff --git a/libtapdance/elligator2.h b/cmd/detector/libtapdance/elligator2.h similarity index 100% rename from libtapdance/elligator2.h rename to cmd/detector/libtapdance/elligator2.h diff --git a/libtapdance/forge_socket.h b/cmd/detector/libtapdance/forge_socket.h similarity index 100% rename from libtapdance/forge_socket.h rename to cmd/detector/libtapdance/forge_socket.h diff --git a/cmd/detector/libtapdance/genkey b/cmd/detector/libtapdance/genkey new file mode 100755 index 00000000..59f05fe2 Binary files /dev/null and b/cmd/detector/libtapdance/genkey differ diff --git a/libtapdance/genkey.c b/cmd/detector/libtapdance/genkey.c similarity index 100% rename from libtapdance/genkey.c rename to cmd/detector/libtapdance/genkey.c diff --git a/libtapdance/loadkey.c b/cmd/detector/libtapdance/loadkey.c similarity index 100% rename from libtapdance/loadkey.c rename to cmd/detector/libtapdance/loadkey.c diff --git a/libtapdance/loadkey.h b/cmd/detector/libtapdance/loadkey.h similarity index 100% rename from libtapdance/loadkey.h rename to cmd/detector/libtapdance/loadkey.h diff --git a/libtapdance/ssl_api.c b/cmd/detector/libtapdance/ssl_api.c similarity index 100% rename from libtapdance/ssl_api.c rename to cmd/detector/libtapdance/ssl_api.c diff --git a/libtapdance/ssl_api.h b/cmd/detector/libtapdance/ssl_api.h similarity index 100% rename from libtapdance/ssl_api.h rename to cmd/detector/libtapdance/ssl_api.h diff --git a/libtapdance/tapdance.c b/cmd/detector/libtapdance/tapdance.c similarity index 100% rename from libtapdance/tapdance.c rename to cmd/detector/libtapdance/tapdance.c diff --git a/libtapdance/tapdance.h b/cmd/detector/libtapdance/tapdance.h similarity index 100% rename from libtapdance/tapdance.h rename to cmd/detector/libtapdance/tapdance.h diff --git a/libtapdance/tapdance_rst_spoof.c b/cmd/detector/libtapdance/tapdance_rst_spoof.c similarity index 100% rename from libtapdance/tapdance_rst_spoof.c rename to cmd/detector/libtapdance/tapdance_rst_spoof.c diff --git a/libtapdance/tapdance_rust_util.c b/cmd/detector/libtapdance/tapdance_rust_util.c similarity index 100% rename from libtapdance/tapdance_rust_util.c rename to cmd/detector/libtapdance/tapdance_rust_util.c diff --git a/libtapdance/test-tapdance.c b/cmd/detector/libtapdance/test-tapdance.c similarity index 100% rename from libtapdance/test-tapdance.c rename to cmd/detector/libtapdance/test-tapdance.c diff --git a/loadkey.c b/cmd/detector/loadkey.c similarity index 100% rename from loadkey.c rename to cmd/detector/loadkey.c diff --git a/loadkey.h b/cmd/detector/loadkey.h similarity index 100% rename from loadkey.h rename to cmd/detector/loadkey.h diff --git a/pfutils.c b/cmd/detector/pfutils.c similarity index 100% rename from pfutils.c rename to cmd/detector/pfutils.c diff --git a/rust_foreign_interface.h b/cmd/detector/rust_foreign_interface.h similarity index 100% rename from rust_foreign_interface.h rename to cmd/detector/rust_foreign_interface.h diff --git a/rust_util.c b/cmd/detector/rust_util.c similarity index 100% rename from rust_util.c rename to cmd/detector/rust_util.c diff --git a/src/c_api.rs b/cmd/detector/src/c_api.rs similarity index 100% rename from src/c_api.rs rename to cmd/detector/src/c_api.rs diff --git a/src/elligator.rs b/cmd/detector/src/elligator.rs similarity index 100% rename from src/elligator.rs rename to cmd/detector/src/elligator.rs diff --git a/src/flow_tracker.rs b/cmd/detector/src/flow_tracker.rs similarity index 100% rename from src/flow_tracker.rs rename to cmd/detector/src/flow_tracker.rs diff --git a/src/lib.rs b/cmd/detector/src/lib.rs similarity index 100% rename from src/lib.rs rename to cmd/detector/src/lib.rs diff --git a/src/logging.rs b/cmd/detector/src/logging.rs similarity index 100% rename from src/logging.rs rename to cmd/detector/src/logging.rs diff --git a/src/process_packet.rs b/cmd/detector/src/process_packet.rs similarity index 100% rename from src/process_packet.rs rename to cmd/detector/src/process_packet.rs diff --git a/src/sessions.rs b/cmd/detector/src/sessions.rs similarity index 100% rename from src/sessions.rs rename to cmd/detector/src/sessions.rs diff --git a/src/signalling.rs b/cmd/detector/src/signalling.rs similarity index 100% rename from src/signalling.rs rename to cmd/detector/src/signalling.rs diff --git a/src/util.rs b/cmd/detector/src/util.rs similarity index 100% rename from src/util.rs rename to cmd/detector/src/util.rs diff --git a/cmd/registration-server/go.mod b/cmd/registration-server/go.mod index 2b3124a7..f17c55e8 100644 --- a/cmd/registration-server/go.mod +++ b/cmd/registration-server/go.mod @@ -2,4 +2,42 @@ module github.com/refraction-networking/conjure/cmd/regserver go 1.18 -require github.com/gorilla/mux v1.8.0 // indirect +replace github.com/refraction-networking/conjure => ../../ + +require ( + github.com/BurntSushi/toml v1.3.2 + github.com/refraction-networking/conjure v1.0.0-dev + github.com/stretchr/testify v1.8.4 + google.golang.org/protobuf v1.31.0 +) + +require ( + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dchest/siphash v1.2.3 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/flynn/noise v1.0.0 // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect + github.com/gorilla/mux v1.8.0 // indirect + github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/libp2p/go-reuseport v0.4.0 // indirect + github.com/mroth/weightedrand v1.0.0 // indirect + github.com/oschwald/geoip2-golang v1.9.0 // indirect + github.com/oschwald/maxminddb-golang v1.12.0 // indirect + github.com/pebbe/zmq4 v1.2.10 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pion/dtls/v2 v2.2.7 // indirect + github.com/pion/logging v0.2.2 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/sctp v1.8.8 // indirect + github.com/pion/stun v0.6.1 // indirect + github.com/pion/transport/v2 v2.2.3 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/refraction-networking/ed25519 v0.1.2 // indirect + github.com/refraction-networking/obfs4 v0.1.2 // indirect + gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.5.0 // indirect + golang.org/x/crypto v0.13.0 // indirect + golang.org/x/net v0.15.0 // indirect + golang.org/x/sys v0.12.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/cmd/registration-server/go.sum b/cmd/registration-server/go.sum index 53502880..21802bf2 100644 --- a/cmd/registration-server/go.sum +++ b/cmd/registration-server/go.sum @@ -1,2 +1,139 @@ +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= +github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= +github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= +github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= +github.com/mroth/weightedrand v1.0.0 h1:V8JeHChvl2MP1sAoXq4brElOcza+jxLkRuwvtQu8L3E= +github.com/mroth/weightedrand v1.0.0/go.mod h1:3p2SIcC8al1YMzGhAIoXD+r9olo/g/cdJgAD905gyNE= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc= +github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y= +github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= +github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= +github.com/pebbe/zmq4 v1.2.10 h1:wQkqRZ3CZeABIeidr3e8uQZMMH5YAykA/WN0L5zkd1c= +github.com/pebbe/zmq4 v1.2.10/go.mod h1:nqnPueOapVhE2wItZ0uOErngczsJdLOGkebMxaO8r48= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/sctp v1.8.8 h1:5EdnnKI4gpyR1a1TwbiS/wxEgcUWBHsc7ILAjARJB+U= +github.com/pion/sctp v1.8.8/go.mod h1:igF9nZBrjh5AtmKc7U30jXltsFHicFCXSmWA2GWRaWs= +github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v2 v2.2.3 h1:XcOE3/x41HOSKbl1BfyY1TF1dERx7lVvlMCbXU7kfvA= +github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/refraction-networking/ed25519 v0.1.2 h1:08kJZUkAlY7a7cZGosl1teGytV+QEoNxPO7NnRvAB+g= +github.com/refraction-networking/ed25519 v0.1.2/go.mod h1:nxYLUAYt/hmNpAh64PNSQ/tQ9gTIB89wCaGKJlRtZ9I= +github.com/refraction-networking/obfs4 v0.1.2 h1:J842O4fGSkd2W8ogYj0KN6gqVVY+Cpqodw9qFGL7wVU= +github.com/refraction-networking/obfs4 v0.1.2/go.mod h1:wAl/+gWiLsrcykJA3nKJHx89f5/gXGM8UKvty7+mvbM= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.5.0 h1:rzdY78Ox2T+VlXcxGxELF+6VyUXlZBhmRqZu5etLm+c= +gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.5.0/go.mod h1:70bhd4JKW/+1HLfm+TMrgHJsUHG4coelMWwiVEJ2gAg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd/registration-server/main.go b/cmd/registration-server/main.go index dfe59731..5959ebe4 100644 --- a/cmd/registration-server/main.go +++ b/cmd/registration-server/main.go @@ -13,6 +13,7 @@ import ( "github.com/BurntSushi/toml" + "github.com/refraction-networking/conjure/pkg/log" "github.com/refraction-networking/conjure/pkg/metrics" "github.com/refraction-networking/conjure/pkg/regserver/apiregserver" "github.com/refraction-networking/conjure/pkg/regserver/dnsregserver" @@ -23,7 +24,7 @@ import ( "github.com/refraction-networking/conjure/pkg/transports/wrapping/obfs4" "github.com/refraction-networking/conjure/pkg/transports/wrapping/prefix" pb "github.com/refraction-networking/conjure/proto" - log "github.com/sirupsen/logrus" + "google.golang.org/protobuf/proto" ) @@ -158,12 +159,6 @@ func main() { } } - logFormatter := &log.TextFormatter{ - FullTimestamp: true, - } - - log.SetFormatter(logFormatter) - conf, err := loadConfig(configPath) if err != nil { log.Fatalf("error occurred while parsing config: %v", err) @@ -186,7 +181,7 @@ func main() { log.Fatal(err) } - metrics := metrics.NewMetrics(log.NewEntry(log.StandardLogger()), time.Duration(conf.LogMetricsInterval)*time.Second) + metrics := metrics.NewMetrics(log.Default(), time.Duration(conf.LogMetricsInterval)*time.Second) var processor *regprocessor.RegProcessor @@ -220,7 +215,7 @@ func main() { log.Fatal(err) } - dnsRegServer, err = dnsregserver.NewDNSRegServer(conf.Domain, conf.DNSListenAddr, dnsPrivKey[:32], processor, conf.latestClientConf.GetGeneration(), log.WithField("registrar", "DNS"), metrics) + dnsRegServer, err = dnsregserver.NewDNSRegServer(conf.Domain, conf.DNSListenAddr, dnsPrivKey[:32], processor, conf.latestClientConf.GetGeneration(), log.Default(), metrics) if err != nil { log.Fatal(err) } @@ -229,7 +224,7 @@ func main() { } if !dnsOnly { - apiRegServer, err = apiregserver.NewAPIRegServer(conf.APIPort, processor, conf.latestClientConf, log.WithField("registrar", "API"), logClientIP, metrics) + apiRegServer, err = apiregserver.NewAPIRegServer(conf.APIPort, processor, conf.latestClientConf, log.Default(), logClientIP, metrics) if err != nil { log.Fatal(err) } diff --git a/conjure.go b/conjure.go new file mode 100644 index 00000000..0439ac2c --- /dev/null +++ b/conjure.go @@ -0,0 +1,53 @@ +package conjure + +import ( + "github.com/refraction-networking/conjure/pkg/client/assets" + "github.com/refraction-networking/conjure/pkg/core/interfaces" + transports "github.com/refraction-networking/conjure/pkg/transports/client" + pb "github.com/refraction-networking/conjure/proto" +) + +type Assets assets.ClientInterface + +func GetAssets() Assets { + return assets.Assets() +} + +func SetAssetsDir(dir string) (Assets, error) { + return assets.AssetsSetDir(dir) +} + +var ( + // ErrUnknownTransport provided id or name does npt match any enabled transport. + ErrUnknownTransport = transports.ErrUnknownTransport +) + +// Transport provides a generic interface for utilities that allow the client to dial and connect to +// a phantom address when creating a Conjure connection. +type Transport interfaces.Transport + +// Registrar defines the interface for a module completing the initial portion of the conjure +// protocol which registers the clients intent to connect, along with the specifics of the session +// they wish to establish. +type Registrar interfaces.Registrar + +// GetTransportByName returns transport by name +func GetTransportByName(name string) (interfaces.Transport, bool) { + return transports.GetTransportByName(name) +} + +// GetTransportByID returns transport by name +func GetTransportByID(id pb.TransportType) (interfaces.Transport, bool) { + return transports.GetTransportByID(id) +} + +// GetTransportWithParams returns a new Transport and attempts to set the parameters provided +func GetTransportWithParams(name string, params any) (interfaces.Transport, error) { + return transports.NewWithParams(name, params) +} + +// GetTransportWithParamsByID returns a new Transport by Type ID, if one exists, and attempts to set the +// parameters provided. +func GetTransportWithParamsByID(id pb.TransportType, params any) (interfaces.Transport, error) { + return transports.NewWithParamsByID(id, params) +} diff --git a/dialer.go b/dialer.go new file mode 100644 index 00000000..6a6a6e6c --- /dev/null +++ b/dialer.go @@ -0,0 +1,204 @@ +package conjure + +import ( + "context" + "errors" + "fmt" + "net" + "strings" + "sync" + + "github.com/refraction-networking/conjure/pkg/client" + "github.com/refraction-networking/conjure/pkg/core/interfaces" + pb "github.com/refraction-networking/conjure/proto" +) + +// IPSupport is a bitmask of supported IP versions. +type IPSupport client.IPSupport + +const ( + // V4 indicates that client support for IPv4 is enabled. + V4 IPSupport = 1 << iota + // V6 indicates that client support for IPv6 is enabled. + V6 +) + +// Dialer contains options and implements advanced functions for establishing TapDance connection. +type Dialer struct { + // If not specified, the default system dialer will be used. Will be ignored if DialWithLaddr + // is specified. + // + // THIS IS REQUIRED TO INTERFACE WITH ANDROID PROXY APPLICATIONS + // we use their dialer to prevent connection loopback into our own proxy + // connection when tunneling the whole device. + // + // Deprecated: Dialer does not allow specifying the local address used for NAT traversal in some + // transports. Use DialWithLaddr instead. + Dialer func(context.Context, string, string) (net.Conn, error) + + // DialWithLaddr allows a custom dialer to be used for the underlying TCP/UDP connection. + // If not specified, the default system dialer will be used. If both this and the Dialer option + // are specified, DialWithLaddr will be used. + // + // THIS IS REQUIRED TO INTERFACE WITH ANDROID PROXY APPLICATIONS + // we use their dialer to prevent connection loopback into our own proxy + // connection when tunneling the whole device. + DialWithLaddr interfaces.DialFunc + + // The type of registrar to use when performing Conjure registrations. + Registrar interfaces.Registrar + + // DisableRegistrarOverrides Indicates whether the client will allow the registrar to provide + // alternative parameters that may work better in substitute for the deterministically selected + // parameters. This only works for bidirectional registration methods where the client receives + // a RegistrationResponse. + DisableRegistrarOverrides bool + + // The type of transport to use for Conjure connections. + Transport interfaces.Transport + + // // RegDelay is the delay duration to wait for registration ingest. + // RegDelay time.Duration + + UseProxyHeader bool + IPv IPSupport + + // Subnet that we want to limit to (or empty if they're all fine) this is used for debug only. + PhantomNet string + + // Assets provide stations configuration including available Phantom Subnets and decoy hosts + // to be used with the decoy-registrar. If neither the Assets nor the AssetsPath is specified, + // the default assets path will be used. If no assets are found an error is returned. + Assets *pb.ClientConf + AssetsPath string +} + +// Dial connects to the address on the named network. +// +// The only supported network at this time: "tcp". +// The address has the form "host:port". +// The host must be a literal IP address, or a host name that can be +// resolved to IP addresses. +// To avoid abuse, only certain whitelisted ports are allowed. +// +// Example: Dial("tcp", "golang.org:80") +func Dial(network, address string) (net.Conn, error) { + var d Dialer + return d.Dial(network, address) +} + +// Dial connects to the address on the named network. +func (d *Dialer) Dial(network, address string) (net.Conn, error) { + return d.DialContext(context.Background(), network, address) +} + +// DialContext connects to the address on the named network using the provided context. +// Long deadline is advised, since conjure may try multiple registration strategies. +// +// The only supported network at this time: "tcp". +// The address has the form "host:port". +// The host must be a literal IP address, or a host name that can be +// resolved to IP addresses. +// To avoid abuse, only certain whitelisted ports are allowed. +// +// Example: Dial("tcp", "golang.org:80") +func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + if network != "tcp" { + return nil, &net.OpError{Op: "dial", Net: network, Err: net.UnknownNetworkError(network)} + } + if len(address) > 0 { + _, _, err := net.SplitHostPort(address) + if err != nil { + return nil, err + } + } + + if d.DialWithLaddr != nil && d.Dialer != nil { + return nil, fmt.Errorf("both DialWithLaddr and Dialer are defined, only define DialWithLaddr") + } + + if d.Dialer != nil { + d.DialWithLaddr = func(ctx context.Context, network, laddr, raddr string) (net.Conn, error) { + if laddr != "" { + return nil, errUnsupportedLaddr + } + return d.Dialer(ctx, network, raddr) + } + } + + if d.DialWithLaddr == nil { + // custom dialer is not set, use default + defaultDialer := net.Dialer{} + dialMutex := sync.Mutex{} + d.DialWithLaddr = func(ctx context.Context, network, laddr, raddr string) (net.Conn, error) { + localAddr, err := resolveAddr(network, laddr) + if err != nil { + return nil, fmt.Errorf("error resolving laddr: %v", err) + } + + dialMutex.Lock() + defer dialMutex.Unlock() + + defaultDialer.LocalAddr = localAddr + + return defaultDialer.DialContext(ctx, network, raddr) + } + } + + // Conjure + var cjSession *client.ConjureSession + + if d.Transport == nil { + return nil, errors.New("missing transport") + } + + // If specified, only select a phantom from a given range + if d.PhantomNet != "" { + _, phantomRange, err := net.ParseCIDR(d.PhantomNet) + if err != nil { + return nil, errors.New("Invalid Phantom network goal") + } + cjSession = client.FindConjureSessionInRange(address, d.Transport, phantomRange) + if cjSession == nil { + return nil, errors.New("Failed to find Phantom in target subnet") + } + } else { + cjSession = client.MakeConjureSession(address, d.Transport) + } + + cjSession.Dialer = d.DialWithLaddr + cjSession.UseProxyHeader = d.UseProxyHeader + cjSession.DisableRegistrarOverrides = d.DisableRegistrarOverrides + cjSession.V6Support = client.IPSupport(d.IPv) + + if len(address) == 0 { + return nil, errors.New("Conjure requires a target address to be set") + } + return client.DialConjure(ctx, cjSession, d.Registrar) +} + +// DialProxy establishes direct connection to TapDance station proxy. +// Users are expected to send HTTP CONNECT request next. +func (d *Dialer) DialProxy() (net.Conn, error) { + return d.DialProxyContext(context.Background()) +} + +// DialProxyContext establishes direct connection to TapDance station proxy using the provided context. +// Users are expected to send HTTP CONNECT request next. +func (d *Dialer) DialProxyContext(ctx context.Context) (net.Conn, error) { + return d.DialContext(ctx, "tcp", "") +} + +func resolveAddr(network, addrStr string) (net.Addr, error) { + if addrStr == "" { + return nil, nil + } + + if strings.Contains(network, "tcp") { + return net.ResolveTCPAddr(network, addrStr) + } + + return net.ResolveUDPAddr(network, addrStr) +} + +var errUnsupportedLaddr = fmt.Errorf("dialer does not support laddr") diff --git a/go.mod b/go.mod index ffbc4a62..96bfba57 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,11 @@ module github.com/refraction-networking/conjure -go 1.18 +go 1.20 require ( github.com/BurntSushi/toml v1.3.2 github.com/flynn/noise v1.0.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/golang/protobuf v1.5.3 github.com/google/gopacket v1.1.19 github.com/gorilla/mux v1.8.0 github.com/hashicorp/golang-lru v1.0.2 @@ -21,10 +20,8 @@ require ( github.com/pion/stun v0.6.1 github.com/pion/transport/v2 v2.2.3 github.com/refraction-networking/ed25519 v0.1.2 - github.com/refraction-networking/gotapdance v1.7.1 github.com/refraction-networking/obfs4 v0.1.2 - github.com/refraction-networking/utls v1.3.3 - github.com/sirupsen/logrus v1.9.3 + github.com/refraction-networking/utls v1.5.3 github.com/stretchr/testify v1.8.4 gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.5.0 golang.org/x/crypto v0.13.0 @@ -37,16 +34,16 @@ require ( require ( github.com/andybalholm/brotli v1.0.5 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cloudflare/circl v1.3.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dchest/siphash v1.2.3 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/gaukas/godicttls v0.0.4 // indirect github.com/klauspost/compress v1.16.7 // indirect - github.com/onsi/gomega v1.27.6 // indirect github.com/oschwald/maxminddb-golang v1.12.0 // indirect github.com/pion/randutil v0.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/sergeyfrolov/bsbuffer v0.0.0-20180903213811-94e85abb8507 // indirect + github.com/quic-go/quic-go v0.37.4 // indirect golang.org/x/text v0.13.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) @@ -54,5 +51,3 @@ require ( replace github.com/pion/dtls/v2 => github.com/mingyech/dtls/v2 v2.0.0 replace github.com/pion/transport/v2 => github.com/mingyech/transport/v2 v2.0.0 - -replace github.com/refraction-networking/gotapdance => github.com/refraction-networking/gotapdance v1.7.3-0.20230914182507-7d8ccbce6eb2 diff --git a/go.sum b/go.sum index ee478b6d..6b4a7883 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/ github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -16,15 +18,16 @@ github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwU github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= @@ -48,8 +51,8 @@ github.com/mroth/weightedrand v1.0.0 h1:V8JeHChvl2MP1sAoXq4brElOcza+jxLkRuwvtQu8 github.com/mroth/weightedrand v1.0.0/go.mod h1:3p2SIcC8al1YMzGhAIoXD+r9olo/g/cdJgAD905gyNE= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc= github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y= github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= @@ -66,21 +69,16 @@ github.com/pion/sctp v1.8.8 h1:5EdnnKI4gpyR1a1TwbiS/wxEgcUWBHsc7ILAjARJB+U= github.com/pion/sctp v1.8.8/go.mod h1:igF9nZBrjh5AtmKc7U30jXltsFHicFCXSmWA2GWRaWs= github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/quic-go/quic-go v0.37.4 h1:ke8B73yMCWGq9MfrCCAw0Uzdm7GaViC3i39dsIdDlH4= +github.com/quic-go/quic-go v0.37.4/go.mod h1:YsbH1r4mSHPJcLF4k4zruUkLBqctEMBDR6VPvcYjIsU= github.com/refraction-networking/ed25519 v0.1.2 h1:08kJZUkAlY7a7cZGosl1teGytV+QEoNxPO7NnRvAB+g= github.com/refraction-networking/ed25519 v0.1.2/go.mod h1:nxYLUAYt/hmNpAh64PNSQ/tQ9gTIB89wCaGKJlRtZ9I= -github.com/refraction-networking/gotapdance v1.7.3-0.20230914182507-7d8ccbce6eb2 h1:bjm9kj/WjSHJyEi6pxNrviGv90N7+LtlrTtE/s3KIVU= -github.com/refraction-networking/gotapdance v1.7.3-0.20230914182507-7d8ccbce6eb2/go.mod h1:svhsxN8LGv3FSL1RKLFXG74tWEXQ8m1xb9rFEZF2abk= github.com/refraction-networking/obfs4 v0.1.2 h1:J842O4fGSkd2W8ogYj0KN6gqVVY+Cpqodw9qFGL7wVU= github.com/refraction-networking/obfs4 v0.1.2/go.mod h1:wAl/+gWiLsrcykJA3nKJHx89f5/gXGM8UKvty7+mvbM= -github.com/refraction-networking/utls v1.3.3 h1:f/TBLX7KBciRyFH3bwupp+CE4fzoYKCirhdRcC490sw= -github.com/refraction-networking/utls v1.3.3/go.mod h1:DlecWW1LMlMJu+9qpzzQqdHDT/C2LAe03EdpLUz/RL8= -github.com/sergeyfrolov/bsbuffer v0.0.0-20180903213811-94e85abb8507 h1:ML7ZNtcln5UBo5Wv7RIv9Xg3Pr5VuRCWLFXEwda54Y4= -github.com/sergeyfrolov/bsbuffer v0.0.0-20180903213811-94e85abb8507/go.mod h1:DbI1gxrXI2jRGw7XGEUZQOOMd6PsnKzRrCKabvvMrwM= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/refraction-networking/utls v1.5.3 h1:Ds5Ocg1+MC1ahNx5iBEcHe0jHeLaA/fLey61EENm7ro= +github.com/refraction-networking/utls v1.5.3/go.mod h1:SPuDbBmgLGp8s+HLNc83FuavwZCFoMmExj+ltUHiHUw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -121,7 +119,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -146,13 +143,13 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o= google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/go.work.sum b/go.work.sum index 49ce3a4a..f962b607 100644 --- a/go.work.sum +++ b/go.work.sum @@ -17,8 +17,6 @@ github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNu github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= @@ -40,17 +38,36 @@ github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2U github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= -github.com/refraction-networking/gotapdance v1.6.2 h1:pDC12wdSCE4Afh31NcNAIcjIhO6Mb/qiIscwbGOhhRA= -github.com/refraction-networking/gotapdance v1.6.2/go.mod h1:m82n2v+yNr3+E/dttji+qO2hEjcXgIYj2szuieEMTts= +github.com/refraction-networking/utls v1.5.3 h1:Ds5Ocg1+MC1ahNx5iBEcHe0jHeLaA/fLey61EENm7ro= +github.com/refraction-networking/utls v1.5.3/go.mod h1:SPuDbBmgLGp8s+HLNc83FuavwZCFoMmExj+ltUHiHUw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= +gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.5.0 h1:rzdY78Ox2T+VlXcxGxELF+6VyUXlZBhmRqZu5etLm+c= +gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.5.0/go.mod h1:70bhd4JKW/+1HLfm+TMrgHJsUHG4coelMWwiVEJ2gAg= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= @@ -61,6 +78,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 h1: google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o= +google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/internal/transport_integration_test.go b/internal/transport_integration_test.go index dccdca71..d8712d06 100644 --- a/internal/transport_integration_test.go +++ b/internal/transport_integration_test.go @@ -16,8 +16,8 @@ import ( "github.com/refraction-networking/conjure/internal/testutils" "github.com/refraction-networking/conjure/pkg/core" "github.com/refraction-networking/conjure/pkg/core/interfaces" + "github.com/refraction-networking/conjure/pkg/log" "github.com/refraction-networking/conjure/pkg/station/lib" - "github.com/refraction-networking/conjure/pkg/station/log" "github.com/refraction-networking/conjure/pkg/transports" "github.com/refraction-networking/conjure/pkg/transports/wrapping/min" "github.com/refraction-networking/conjure/pkg/transports/wrapping/obfs4" diff --git a/pkg/client/assets/assets.go b/pkg/client/assets/assets.go index 23f15b65..9fd5d054 100644 --- a/pkg/client/assets/assets.go +++ b/pkg/client/assets/assets.go @@ -11,8 +11,8 @@ import ( "strings" "sync" + "github.com/refraction-networking/conjure/pkg/log" ps "github.com/refraction-networking/conjure/pkg/phantoms" - "github.com/refraction-networking/conjure/pkg/station/log" pb "github.com/refraction-networking/conjure/proto" "google.golang.org/protobuf/proto" @@ -26,6 +26,13 @@ const ( sendLimitMin = 14400 ) +// ClientInterface is an interface for accessing assets +type ClientInterface interface { + GetClientConfig() *pb.ClientConf + SetClientConfig(*pb.ClientConf) error + GetPublicKey() *[32]byte +} + type assets struct { sync.RWMutex path string @@ -33,8 +40,6 @@ type assets struct { config *pb.ClientConf filenameClientConf string - - socksAddr string } // could reset this internally to refresh assets and avoid woes of singleton testing @@ -136,11 +141,26 @@ func initAssets(path string) error { path: path, config: &defaultClientConf, filenameClientConf: "ClientConf", - socksAddr: "", } err := assetsInstance.readConfigs() return err } +func (a *assets) GetClientConfig() *pb.ClientConf { + return a.config +} +func (a *assets) SetClientConfig(clientConf *pb.ClientConf) error { + a.Lock() + defer a.Unlock() + a.config = clientConf + return a.saveClientConf() +} + +func (a *assets) GetPublicKey() *[32]byte { + if a.config == nil { + return nil + } + return a.GetConjurePubkey() +} func (a *assets) GetAssetsDir() string { a.RLock() @@ -279,14 +299,15 @@ func (a *assets) GetV6Decoy() *pb.TLSDecoySpec { return chosenDecoy } -func (a *assets) GetPubkey() *[32]byte { - a.RLock() - defer a.RUnlock() +// // Deprecated - Tapdance Public Key +// func (a *assets) GetPubkey() *[32]byte { +// a.RLock() +// defer a.RUnlock() - var pKey [32]byte - copy(pKey[:], a.config.GetDefaultPubkey().GetKey()[:]) - return &pKey -} +// var pKey [32]byte +// copy(pKey[:], a.config.GetDefaultPubkey().GetKey()[:]) +// return &pKey +// } func (a *assets) GetConjurePubkey() *[32]byte { a.RLock() @@ -388,11 +409,6 @@ func (a *assets) saveClientConf() error { return os.Rename(tmpFilename, filename) } -// SetStatsSocksAddr - Provide a socks address for reporting stats from the client in the form "addr:port" -func (a *assets) SetStatsSocksAddr(addr string) { - a.socksAddr = addr -} - // GetPhantomSubnets - func (a *assets) GetPhantomSubnets() *pb.PhantomSubnetsList { a.RLock() diff --git a/pkg/client/assets/assets_test.go b/pkg/client/assets/assets_test.go index 929ef45b..4304b816 100644 --- a/pkg/client/assets/assets_test.go +++ b/pkg/client/assets/assets_test.go @@ -13,7 +13,7 @@ import ( "testing" "github.com/refraction-networking/conjure/internal/conjurepath" - "github.com/refraction-networking/conjure/pkg/station/log" + "github.com/refraction-networking/conjure/pkg/log" pb "github.com/refraction-networking/conjure/proto" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" diff --git a/pkg/client/common.go b/pkg/client/common.go new file mode 100644 index 00000000..31e732e3 --- /dev/null +++ b/pkg/client/common.go @@ -0,0 +1,15 @@ +package client + +// Fixed-Size-Payload has a 1 byte flags field. +// bit 0 (1 << 7) determines if flow is bidirectional(0) or upload-only(1) +// bit 1 (1 << 6) enables dark-decoys +// bits 2-5 are unassigned +// bit 6 determines whether PROXY-protocol-formatted string will be sent +// bit 7 (1 << 0) signals to use TypeLen outer proto +var ( + flagUploadOnly = uint8(1 << 7) + flagProxyHeader = uint8(1 << 1) + flagUseTIL = uint8(1 << 0) +) + +var defaultFlags = flagUseTIL diff --git a/pkg/client/conjure.go b/pkg/client/conjure.go new file mode 100644 index 00000000..6893d1f3 --- /dev/null +++ b/pkg/client/conjure.go @@ -0,0 +1,539 @@ +package client + +import ( + "context" + "crypto/rand" + "encoding/binary" + "errors" + "fmt" + mrand "math/rand" + "net" + "strconv" + "sync" + "time" + + "github.com/refraction-networking/conjure/pkg/client/assets" + "github.com/refraction-networking/conjure/pkg/core" + "github.com/refraction-networking/conjure/pkg/core/interfaces" + "github.com/refraction-networking/conjure/pkg/log" + ps "github.com/refraction-networking/conjure/pkg/phantoms" + pb "github.com/refraction-networking/conjure/proto" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/anypb" +) + +// ErrNoOpenConns indicates that the client Failed to establish a connection with any phantom addr +var ErrNoOpenConns = errors.New("no open connections") + +// DialConjure - Perform Registration and Dial on an existing Conjure session +func DialConjure(ctx context.Context, cjSession *ConjureSession, registrationMethod interfaces.Registrar) (net.Conn, error) { + + if cjSession == nil { + return nil, fmt.Errorf("No Session Provided") + } + + // Prepare registrar specific keys + err := registrationMethod.PrepareRegKeys(getStationKey()) + if err != nil { + return nil, err + } + // Choose Phantom Address in Register depending on v6 support. + reg, err := registrationMethod.Register(ctx, cjSession) + if err != nil { + log.Debugf("%v Failed to register: %v", cjSession.IDString(), err) + return nil, err + } + + registration, ok := reg.(*ConjureReg) + if !ok { + return nil, fmt.Errorf("Unknown registration Returned") + } + + tp, isConnecting := cjSession.Transport.(interfaces.ConnectingTransport) + if isConnecting { + if tp.DisableRegDelay() { + cjSession.RegDelay = 0 + } + } + + sleepWithContext(ctx, cjSession.RegDelay) + + log.Debugf("%v Attempting to Connect using %s ...", cjSession.IDString(), registration.Transport.Name()) + return registration.Connect(ctx, cjSession.Dialer) +} + +// ConjureReg - Registration structure created for each individual registration within a session. +type ConjureReg struct { + interfaces.Transport + *ConjureSession + + phantom4 *net.IP + phantom6 *net.IP + phantomDstPort uint16 + useProxyHeader bool + covertAddress string + v6Support IPSupport + + m sync.Mutex + + // THIS IS REQUIRED TO INTERFACE WITH PSIPHON ANDROID + // we use their dialer to prevent connection loopback into our own proxy + // connection when tunneling the whole device. + Dialer func(context.Context, string, string) (net.Conn, error) +} + +func (reg *ConjureReg) connect(ctx context.Context, addr string, dialer dialFunc) (net.Conn, error) { + //[reference] Create Context with deadline + deadline, deadlineAlreadySet := ctx.Deadline() + if !deadlineAlreadySet { + //[reference] randomized timeout to Dial phantom address + deadline = time.Now().Add(reg.getRandomDuration(0, 1461*2, 2453*3)) + } + childCtx, childCancelFunc := context.WithDeadline(ctx, deadline) + defer childCancelFunc() + + //[reference] Connect to Phantom Host + phantomAddr := net.JoinHostPort(addr, strconv.Itoa(int(reg.phantomDstPort))) + + return dialer(childCtx, "tcp", "", phantomAddr) +} + +func (reg *ConjureReg) getFirstConnection(ctx context.Context, dialer dialFunc, phantoms []*net.IP) (net.Conn, error) { + connChannel := make(chan resultTuple, len(phantoms)) + for _, p := range phantoms { + if p == nil { + connChannel <- resultTuple{nil, fmt.Errorf("nil addr")} + continue + } + go func(phantom *net.IP) { + conn, err := reg.connect(ctx, phantom.String(), dialer) + if err != nil { + log.Infof("%v failed to dial phantom %v: %v", reg.IDString(), phantom.String(), err) + connChannel <- resultTuple{nil, err} + return + } + log.Infof("%v Connected to phantom %v using transport %s", reg.IDString(), net.JoinHostPort(phantom.String(), strconv.Itoa(int(reg.phantomDstPort))), reg.Transport) + connChannel <- resultTuple{conn, nil} + }(p) + } + + open := len(phantoms) + for open > 0 { + rt := <-connChannel + if rt.err != nil { + open-- + continue + } + + // If we made it here we're returning the connection, so + // set up a goroutine to close the others + go func() { + // Close all but one connection (the good one) + for open > 1 { + t := <-connChannel + if t.err == nil { + t.conn.Close() + } + open-- + } + }() + + return rt.conn, nil + } + + return nil, ErrNoOpenConns +} + +// Connect - Use a registration (result of calling Register) to connect to a phantom +// Note: This is hacky but should work for v4, v6, or both as any nil phantom addr will +// return a dial error and be ignored. +func (reg *ConjureReg) Connect(ctx context.Context, dialer dialFunc) (net.Conn, error) { + phantoms := []*net.IP{reg.phantom4, reg.phantom6} + + // Prepare the transport by generating any necessary keys + pubKey := getStationKey() + err := reg.Transport.PrepareKeys(pubKey, reg.Keys.SharedSecret, reg.Keys.Reader) + if err != nil { + return nil, err + } + + switch transport := reg.Transport.(type) { + case interfaces.WrappingTransport: + conn, err := reg.getFirstConnection(ctx, dialer, phantoms) + if err != nil { + log.Infof("%v failed to form phantom connection: %v", reg.IDString(), err) + return nil, err + } + + conn, err = transport.WrapConn(conn) + if err != nil { + log.Infof("WrapConn failed") + return nil, err + } + + return conn, nil + case interfaces.ConnectingTransport: + transportDialer, err := transport.WrapDial(dialer) + if err != nil { + return nil, fmt.Errorf("error wrapping transport dialer: %v", err) + } + + conn, err := reg.getFirstConnection(ctx, transportDialer, phantoms) + if err != nil { + return nil, fmt.Errorf("failed to dialing connecting transport: %v", err) + } + + return conn, nil + } + + return nil, fmt.Errorf("transport does not implement any transport interface") +} + +// UnpackRegResp unpacks the RegistrationResponse message sent back by the station. This unpacks +// any field overrides sent by the registrar. When using a bidirectional registration method +// the server chooses the phantom IP and Port by default. Overrides to transport parameters +// are applied when reg.DisableRegistrarOverrides is false. +func (reg *ConjureReg) UnpackRegResp(regResp *pb.RegistrationResponse) error { + if regResp == nil { + return nil + } + + if (reg.v6Support&V4) == V4 && (reg.v6Support&V6) == V6 { + // Case where cjSession.V6Support == both + // Save the ipv4address in the Conjure Reg struct (phantom4) to return + ip4 := make(net.IP, 4) + addr4 := regResp.GetIpv4Addr() + binary.BigEndian.PutUint32(ip4, addr4) + reg.phantom4 = &ip4 + + // Save the ipv6address in the Conjure Reg struct (phantom6) to return + addr6 := net.IP(regResp.GetIpv6Addr()) + reg.phantom6 = &addr6 + } else if reg.v6Support&V4 == V4 { + // Save the ipv4address in the Conjure Reg struct (phantom4) to return + ip4 := make(net.IP, 4) + addr4 := regResp.GetIpv4Addr() + binary.BigEndian.PutUint32(ip4, addr4) + reg.phantom4 = &ip4 + } else if reg.v6Support&V6 == V6 { + // Save the ipv6address in the Conjure Reg struct (phantom6) to return + addr6 := net.IP(regResp.GetIpv6Addr()) + reg.phantom6 = &addr6 + } else { + return fmt.Errorf("unknown v4/v6 support") + } + + p := uint16(regResp.GetDstPort()) + if p != 0 { + reg.phantomDstPort = p + } else if reg.phantomDstPort == 0 { + // If a bidirectional registrar does not support randomization (or doesn't set the port in the + // registration response we default to the original port we used for all transports). + reg.phantomDstPort = 443 + } + + maybeTP := regResp.GetTransportParams() + if maybeTP != nil && !reg.DisableRegistrarOverrides { + // If an error occurs while setting transport parameters give up as continuing would likely + // lead to incongruence between the client and station and an unserviceable connection. + params, err := reg.Transport.ParseParams(maybeTP) + if err != nil { + return fmt.Errorf("Param Parse error: %w", err) + } + err = reg.Transport.SetParams(params, true) + if err != nil { + return fmt.Errorf("Param Parse error: %w", err) + } + } else if maybeTP != nil && reg.DisableRegistrarOverrides { + return fmt.Errorf("registrar failed to respect disabled overrides") + } + + // Client config -- check if not nil in the registration response + if regResp.GetClientConf() != nil { + currGen := assets.Assets().GetGeneration() + incomingGen := regResp.GetClientConf().GetGeneration() + log.Debugf("received clientconf in regResponse w/ gen %d", incomingGen) + if currGen < incomingGen { + log.Debugf("Updating clientconf %d -> %d", currGen, incomingGen) + _err := assets.Assets().SetClientConf(regResp.GetClientConf()) + if _err != nil { + log.Warnf("could not set ClientConf in bidirectional API: %v", _err.Error()) + } + } + } + + return nil +} + +func (reg *ConjureReg) getPbTransport() pb.TransportType { + return reg.Transport.ID() +} + +func (reg *ConjureReg) getPbTransportParams() (*anypb.Any, error) { + var m proto.Message + m, err := reg.Transport.GetParams() + if err != nil { + return nil, err + } else if m == nil { + return nil, nil + } + return anypb.New(m) +} + +func (reg *ConjureReg) generateFlags() *pb.RegistrationFlags { + flags := &pb.RegistrationFlags{} + mask := defaultFlags + if reg.useProxyHeader { + mask |= flagProxyHeader + } + + uploadOnly := mask&flagUploadOnly == flagUploadOnly + proxy := mask&flagProxyHeader == flagProxyHeader + til := mask&flagUseTIL == flagUseTIL + + flags.UploadOnly = &uploadOnly + flags.ProxyHeader = &proxy + flags.Use_TIL = &til + + return flags +} + +func (reg *ConjureReg) generateClientToStation(ctx context.Context) (*pb.ClientToStation, error) { + var covert *string + if len(reg.covertAddress) > 0 { + //[TODO]{priority:medium} this isn't the correct place to deal with signaling to the station + //transition = pb.C2S_Transition_C2S_SESSION_COVERT_INIT + covert = ®.covertAddress + } + + //[reference] Generate ClientToStation protobuf + // transition := pb.C2S_Transition_C2S_SESSION_INIT + currentGen := assets.Assets().GetGeneration() + currentLibVer := core.CurrentClientLibraryVersion() + transport := reg.getPbTransport() + + err := reg.Transport.Prepare(ctx, reg.ConjureSession.Dialer) + if err != nil { + return nil, fmt.Errorf("error preparing transport: %v", err) + } + + transportParams, err := reg.getPbTransportParams() + if err != nil { + log.Debugf("%s failed to marshal transport parameters ", reg.IDString()) + } + + // remove type url to save space for DNS registration + // for server side changes see https://github.com/refraction-networking/conjure/pull/163 + transportParams.TypeUrl = "" + + initProto := &pb.ClientToStation{ + ClientLibVersion: ¤tLibVer, + CovertAddress: covert, + DecoyListGeneration: ¤tGen, + V6Support: reg.ConjureSession.GetV6Support(), + V4Support: reg.ConjureSession.GetV4Support(), + Transport: &transport, + Flags: reg.generateFlags(), + TransportParams: transportParams, + + DisableRegistrarOverrides: ®.ConjureSession.DisableRegistrarOverrides, + + //[TODO]{priority:medium} specify width in C2S because different width might + // be useful in different regions (constant for now.) + } + + for (proto.Size(initProto)+core.AES_GCM_TAG_SIZE)%3 != 0 { + initProto.Padding = append(initProto.Padding, byte(0)) + } + + return initProto, nil +} + +// Phantom4 returns the ipv4 phantom address +func (reg *ConjureReg) Phantom4() net.IP { + return *reg.phantom4 +} + +// Phantom6 returns the ipv6 phantom address +func (reg *ConjureReg) Phantom6() net.IP { + return *reg.phantom6 +} + +func (reg *ConjureReg) digestStats() string { + //[TODO]{priority:eventually} add decoy details to digest + if reg == nil || reg.stats == nil { + return "{result:\"no stats tracked\"}" + } + + reg.m.Lock() + defer reg.m.Unlock() + return fmt.Sprintf("{result:\"success\", tcp_to_decoy:%v, tls_to_decoy:%v, total_time_to_connect:%v}", + reg.stats.GetTcpToDecoy(), + reg.stats.GetTlsToDecoy(), + reg.stats.GetTotalTimeToConnect()) +} + +func sleepWithContext(ctx context.Context, duration time.Duration) { + timer := time.NewTimer(duration) + defer timer.Stop() + select { + case <-timer.C: + case <-ctx.Done(): + } +} + +// var phantomSubnets = []conjurePhantomSubnet{ +// {subnet: "192.122.190.0/24", weight: 90.0}, +// {subnet: "2001:48a8:687f:1::/64", weight: 90.0}, +// {subnet: "141.219.0.0/16", weight: 10.0}, +// {subnet: "35.8.0.0/16", weight: 10.0}, +// } + +// SelectPhantom - select one phantom IP address based on shared secret +func SelectPhantom(seed []byte, support IPSupport) (*net.IP, *net.IP, bool, error) { + phantomSubnets := assets.Assets().GetPhantomSubnets() + + if (support&V4 == V4) && (support&V6 == V6) { + phantomIPv4, err := ps.SelectPhantom(seed, phantomSubnets, ps.V4Only, true) + if err != nil { + return nil, nil, false, err + } + phantomIPv6, err := ps.SelectPhantom(seed, phantomSubnets, ps.V6Only, true) + if err != nil { + return nil, nil, false, err + } + return phantomIPv4.IP(), phantomIPv6.IP(), phantomIPv4.SupportRandomPort() && phantomIPv6.SupportRandomPort(), nil + } else if support&V4 == V4 { + phantomIPv4, err := ps.SelectPhantom(seed, phantomSubnets, ps.V4Only, true) + if err != nil { + return nil, nil, false, err + } + return phantomIPv4.IP(), nil, phantomIPv4.SupportRandomPort(), nil + } else if support&V6 == V6 { + phantomIPv6, err := ps.SelectPhantom(seed, phantomSubnets, ps.V6Only, true) + if err != nil { + return nil, nil, false, err + } + return nil, phantomIPv6.IP(), phantomIPv6.SupportRandomPort(), nil + } else { + return nil, nil, false, fmt.Errorf("unknown v4/v6 support") + } +} + +func getStationKey() [32]byte { + return *assets.Assets().GetConjurePubkey() +} + +// getRandomDuration returns a random duration that +func (reg *ConjureReg) getRandomDuration(base, min, max int) time.Duration { + addon := getRandInt(min, max) / 1000 // why this min and max??? + rtt := rttInt(reg.getTCPToDecoy()) + return time.Millisecond * time.Duration(base+rtt*addon) +} + +// Tries to get crypto random int in range [min, max] +// In case of crypto failure -- return insecure pseudorandom +func getRandInt(min int, max int) int { + // I can't believe Golang is making me do that + // Flashback to awful C/C++ libraries + diff := max - min + if diff < 0 { + // r.logger.Warningf("getRandInt(): max is less than min") + min = max + diff *= -1 + } else if diff == 0 { + return min + } + var v int64 + err := binary.Read(rand.Reader, binary.LittleEndian, &v) + if v < 0 { + v *= -1 + } + if err != nil { + log.Warnf("Unable to securely get getRandInt(): " + err.Error()) + v = mrand.Int63() + } + return min + int(v%int64(diff+1)) +} + +func (reg *ConjureReg) getTCPToDecoy() uint32 { + if reg == nil { + return 0 + } + reg.m.Lock() + defer reg.m.Unlock() + if reg.stats != nil { + return reg.stats.GetTcpToDecoy() + } + return 0 +} + +func rttInt(millis uint32) int { + defaultValue := 300 + if millis == 0 { + return defaultValue + } + return int(millis) +} + +// RegError - Registration Error passed during registration to indicate failure mode +type RegError struct { + code uint + msg string +} + +func NewRegError(code uint, msg string) RegError { + return RegError{code: code, msg: msg} +} + +func (err RegError) Error() string { + return fmt.Sprintf("Registration Error [%v]: %v", err.CodeStr(), err.msg) +} + +func (err RegError) Code() uint { + return err.code +} + +// CodeStr - Get desctriptor associated with error code +func (err RegError) CodeStr() string { + switch err.code { + case Unreachable: + return "UNREACHABLE" + case DialFailure: + return "DIAL_FAILURE" + case NotImplemented: + return "NOT_IMPLEMENTED" + case TLSError: + return "TLS_ERROR" + default: + return "UNKNOWN" + } +} + +// removeLaddr removes the laddr field in dialer +func removeLaddr(dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) func(ctx context.Context, network, raddr string) (net.Conn, error) { + return func(ctx context.Context, network, addr string) (net.Conn, error) { + return dialer(ctx, network, "", addr) + } +} + +const ( + // Unreachable -Dial Error Unreachable -- likely network unavailable (i.e. ipv6 error) + Unreachable = iota + + // DialFailure - Dial Error Other than unreachable + DialFailure + + // NotImplemented - Related Function Not Implemented + NotImplemented + + // TLSError (Expired, Wrong-Host, Untrusted-Root, ...) + TLSError + + // Unknown - Error occurred without obvious explanation + Unknown +) + +func init() { + sessionsTotal.Store(0) +} diff --git a/pkg/client/conjure_overrides_test.go b/pkg/client/conjure_overrides_test.go new file mode 100644 index 00000000..5c1a3afe --- /dev/null +++ b/pkg/client/conjure_overrides_test.go @@ -0,0 +1,44 @@ +package client + +import ( + "testing" + + "github.com/refraction-networking/conjure/pkg/transports/wrapping/prefix" + pb "github.com/refraction-networking/conjure/proto" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/anypb" +) + +func TestConjureTransportOverride(t *testing.T) { + reg := ConjureReg{v6Support: V4 | V6} + reg.ConjureSession = &ConjureSession{} + reg.ConjureSession.DisableRegistrarOverrides = false + reg.Transport = &prefix.ClientTransport{} + + err := reg.UnpackRegResp(nil) + require.Nil(t, err) + + regResp := &pb.RegistrationResponse{} + + err = reg.UnpackRegResp(regResp) + require.Nil(t, err) + + var id int32 = -2 + truePtr := true + tp := &pb.PrefixTransportParams{ + PrefixId: &id, + Prefix: []byte("aaaa"), + RandomizeDstPort: &truePtr, + } + apb, _ := anypb.New(tp) + regResp = &pb.RegistrationResponse{ + TransportParams: apb, + } + + // Make sure that when overrides are allowed, they are applied even if it is not a prefix that + // is included in the default prefixes that the client knows about. + err = reg.UnpackRegResp(regResp) + require.Nil(t, err) + require.Equal(t, []byte("aaaa"), reg.Transport.(*prefix.ClientTransport).Prefix.Bytes()) + require.Equal(t, prefix.PrefixID(id), reg.Transport.(*prefix.ClientTransport).Prefix.ID()) +} diff --git a/pkg/client/conjure_test.go b/pkg/client/conjure_test.go new file mode 100644 index 00000000..84298eea --- /dev/null +++ b/pkg/client/conjure_test.go @@ -0,0 +1,243 @@ +package client + +import ( + "context" + "crypto/hmac" + "encoding/hex" + "fmt" + "io" + "net" + "syscall" + "testing" + + "github.com/refraction-networking/conjure/pkg/client/assets" + "github.com/refraction-networking/conjure/pkg/core" + "github.com/refraction-networking/conjure/pkg/log" + "github.com/refraction-networking/conjure/pkg/phantoms" + pb "github.com/refraction-networking/conjure/proto" + tls "github.com/refraction-networking/utls" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTLSFailure(t *testing.T) { + + testUrls := map[string]string{ + "expiredTlsUrl": "expired.badssl.com", // x509: certificate has expired or is not yet valid + "wrongHostTlsUrl": "wrong.host.badssl.com", + "untrustedRootTlsUrl": "untrusted-root.badssl.com", + "revokedTlsUrl": "revoked.badssl.com", + "pinningTlsUrl": "pinning-test.badssl.com", + } + + simpleRequest := "GET / HTTP/1.1\r\nHOST:%s\r\n\r\n" + + for issue, url := range testUrls { + + dialConn, err := net.Dial("tcp", url+":443") + if err != nil { + t.Fatalf("Failed when we shouldn't have: %v", err) + } + defer dialConn.Close() + + config := tls.Config{ServerName: url} + tlsConn := tls.UClient(dialConn, &config, tls.HelloChrome_62) + defer tlsConn.Close() + + request := fmt.Sprintf(simpleRequest, url) + + _, err = tlsConn.Write([]byte(request)) + if err != nil { + t.Logf("%v - %v: [%v]", issue, url, err) + } else { + t.Logf("%v - %v: ", issue, url) + } + } + +} + +func TestSelectBoth(t *testing.T) { + seed := []byte{ + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, + } + + phantomIPAddr4, phantomIPAddr6, _, err := SelectPhantom(seed, V4|V6) + require.Nil(t, err, "encountered err while selecting IPs") + require.NotNil(t, phantomIPAddr4, "Failed to select IPv4 address (support: both") + require.Equal(t, "192.122.190.252", phantomIPAddr4.String(), "Incorrect Address chosen") + require.NotNil(t, phantomIPAddr6, "Failed to select IPv6 address (support: both") + require.Equal(t, "2001:48a8:687f:1:fc9d:ee40:b05d:6656", phantomIPAddr6.String(), "Incorrect Address chosen") +} + +func TestConjureHMAC(t *testing.T) { + // generated using + // echo "customString" | hmac256 "1abcd2efgh3ijkl4" + // soln1Str := "d209c99ea22606e5b990a770247b0cd005c157208cb7194fef407fe3fa7e9266" + soln1Str := "d10b84f9e2cc57bb4294b8929a3fca25cce7f95eb226fa5bcddc5417e1d2eac2" + + soln1 := make([]byte, hex.DecodedLen(len(soln1Str))) + _, e := hex.Decode(soln1, []byte(soln1Str)) + require.Nil(t, e, "Failed to decode hex string") + + test1 := core.ConjureHMAC([]byte("1abcd2efgh3ijkl4"), "customString") + test1Str := make([]byte, hex.EncodedLen(len(test1))) + hex.Encode(test1Str, test1) + + if len(test1) != len(soln1) { + t.Fatalf("Wrong hash Length:\n%s\n%s", soln1Str, test1Str) + } + + if !hmac.Equal(test1, soln1) { + t.Fatalf("Wrong hash returned:\n%s\n%s", soln1Str, test1Str) + } +} + +func TestGenerateKeys(t *testing.T) { + var fakePubkey [32]byte + k, _ := hex.DecodeString("00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF") + copy(fakePubkey[:], k) + keys, err := core.GenerateClientSharedKeys(fakePubkey) + if err != nil { + t.Fatalf("Failed to generate Conjure Keys: %v", err) + } + if keys == nil { + t.Fatalf("Incorrect Keys generated: %v", keys.SharedSecret) + } +} + +func TestRegDigest(t *testing.T) { + reg := ConjureReg{ConjureSession: &ConjureSession{}} + soln1 := "{result:\"no stats tracked\"}" + + if reg.digestStats() != soln1 { + t.Fatalf("Incorrect stats digest returned") + } + + testRTT := uint32(1000) + reg.stats = &pb.SessionStats{ + TotalTimeToConnect: &testRTT, + TcpToDecoy: &testRTT} + + soln2 := "{result:\"success\", tcp_to_decoy:1000, tls_to_decoy:0, total_time_to_connect:1000}" + if reg.digestStats() != soln2 { + t.Fatalf("Incorrect stats digest returned") + } + + reg.stats.TlsToDecoy = &testRTT + + soln3 := "{result:\"success\", tcp_to_decoy:1000, tls_to_decoy:1000, total_time_to_connect:1000}" + if reg.digestStats() != soln3 { + t.Fatalf("Incorrect stats digest returned") + } +} + +func TestCheckV6Decoys(t *testing.T) { + _, err := assets.AssetsSetDir("./assets") + require.ErrorIs(t, err, syscall.ENOENT) // ignore assets not found - expected + + decoysV6 := assets.Assets().GetV6Decoys() + numDecoys := len(decoysV6) + + for _, decoy := range decoysV6 { + if decoy.Ipv4Addr != nil { + // If a decoys Ipv4 address is defined it will ignore the IPv6 address + numDecoys-- + } + } + + // t.Logf("V6 Decoys: %v", numDecoys) + // if numDecoys < 5 { + // t.Fatalf("Not enough V6 decoys in ClientConf (has: %v, need at least: %v)", numDecoys, 5) + // } +} + +func TestGetFirstConnection(t *testing.T) { + type params struct { + ips []*net.IP + dialErr error + retErr error + } + + ip1 := net.IPv4(1, 1, 1, 1) + ip2 := net.IPv6loopback + + testCases := []params{ + {nil, nil, ErrNoOpenConns}, + {[]*net.IP{}, nil, ErrNoOpenConns}, + {[]*net.IP{&ip1}, nil, nil}, + {[]*net.IP{nil}, nil, ErrNoOpenConns}, + {[]*net.IP{&ip1, &ip1}, nil, nil}, + {[]*net.IP{&ip1, &ip2}, nil, nil}, + {[]*net.IP{&ip2, &ip1}, nil, nil}, + {[]*net.IP{&ip2, &ip2}, nil, nil}, + {[]*net.IP{&ip1, nil}, nil, nil}, + {[]*net.IP{nil, &ip1}, nil, nil}, + {[]*net.IP{&ip2, nil}, nil, nil}, + } + + for i, c := range testCases { + testGetFirstConn(t, c.ips, c.dialErr, c.retErr, i) + } +} + +func testGetFirstConn(t *testing.T, addrList []*net.IP, dialErr error, retErr error, i int) { + reg := ConjureReg{ + ConjureSession: &ConjureSession{}, + phantomDstPort: 443, + } + + cl, _ := net.Pipe() + defer cl.Close() + + dialFn := func(ctx context.Context, network, laddr, raddr string) (net.Conn, error) { + return cl, dialErr + } + + c, err := reg.getFirstConnection(context.Background(), dialFn, addrList) + if retErr != nil { + require.ErrorIs(t, err, retErr, i) + } else { + require.Nil(t, err, i) + require.NotNil(t, c, i) + } +} + +func TestAssetsPhantomsBasics(t *testing.T) { + phantomSet := assets.Assets().GetPhantomSubnets() + assert.NotNil(t, phantomSet) +} + +func TestAssetsPhantoms(t *testing.T) { + log.SetOutput(io.Discard) + dir1 := t.TempDir() + + var testPhantoms = phantoms.GetDefaultPhantomSubnets() + + _, err := assets.AssetsSetDir(dir1) + require.ErrorIs(t, err, syscall.ENOENT) // ignore assets not found - expected + + err = assets.Assets().SetPhantomSubnets(testPhantoms) + if err != nil { + t.Fatal(err) + } + + seed, err := hex.DecodeString("5a87133b68da3468988a21659a12ed2ece07345c8c1a5b08459ffdea4218d12f") + require.Nil(t, err) + + addr4, addr6, _, err := SelectPhantom(seed, V4|V6) + require.Nil(t, err) + require.Equal(t, "192.122.190.178", addr4.String()) + require.Equal(t, "2001:48a8:687f:1:b292:3bab:bade:351f", addr6.String()) + + addr4, addr6, _, err = SelectPhantom(seed, V6) + require.Nil(t, err) + require.Nil(t, addr4) + require.Equal(t, "2001:48a8:687f:1:b292:3bab:bade:351f", addr6.String()) + + addr4, addr6, _, err = SelectPhantom(seed, V4) + require.Nil(t, err) + require.Equal(t, "192.122.190.178", addr4.String()) + require.Nil(t, addr6) + +} diff --git a/pkg/client/ipv.go b/pkg/client/ipv.go new file mode 100644 index 00000000..2750272c --- /dev/null +++ b/pkg/client/ipv.go @@ -0,0 +1,23 @@ +package client + +// IPSupport is a bitmask of supported IP versions. +type IPSupport int + +func (s IPSupport) String() string { + if (s&V4 == V4) && (s&V6 == V6) { + return "Both" + } else if s&V4 == V4 { + return "V4" + } else if s&V6 == V6 { + return "V6" + } else { + return "unknown" + } +} + +const ( + // V4 indicates that a client session supports attempting IPv4 connections + V4 IPSupport = 1 << iota + // V6 indicates that a client session supports attempting IPv4 connections + V6 +) diff --git a/pkg/client/session.go b/pkg/client/session.go new file mode 100644 index 00000000..2e9b467c --- /dev/null +++ b/pkg/client/session.go @@ -0,0 +1,233 @@ +package client + +import ( + "context" + "encoding/hex" + "fmt" + "net" + "strconv" + "sync/atomic" + "time" + + "github.com/refraction-networking/conjure/pkg/core" + "github.com/refraction-networking/conjure/pkg/core/interfaces" + "github.com/refraction-networking/conjure/pkg/log" + pb "github.com/refraction-networking/conjure/proto" + "google.golang.org/protobuf/proto" +) + +var sessionsTotal atomic.Uint64 + +// Simple type alias for brevity +type dialFunc = func(ctx context.Context, network, laddr, raddr string) (net.Conn, error) + +// ConjureSession - Create a session with details for registration and connection +type ConjureSession struct { + Keys *core.SharedKeys + V6Support IPSupport + UseProxyHeader bool + SessionID uint64 + Phantom *net.IP + Transport interfaces.Transport + CovertAddress string + // rtt uint // tracked in stats + + DisableRegistrarOverrides bool + + // TcpDialer allows the caller to provide a custom dialer for outgoing proxy connections. + // + // THIS IS REQUIRED TO INTERFACE WITH PSIPHON ANDROID + // we use their dialer to prevent connection loopback into our own proxy + // connection when tunneling the whole device. + Dialer dialFunc + + // RegDelay is the delay duration to wait for registration ingest. + RegDelay time.Duration + + // performance tracking + stats *pb.SessionStats +} + +// MakeConjureSessionSilent creates a conjure session without logging anything +func MakeConjureSessionSilent(covert string, transport interfaces.Transport) *ConjureSession { + keys, err := core.GenerateClientSharedKeys(getStationKey()) + + if err != nil { + return nil + } + //[TODO]{priority:NOW} move v6support initialization to assets so it can be tracked across dials + cjSession := &ConjureSession{ + Keys: keys, + V6Support: V4 | V6, + UseProxyHeader: false, + Transport: transport, + CovertAddress: covert, + SessionID: sessionsTotal.Add(1), + DisableRegistrarOverrides: false, + } + + return cjSession +} + +func LogConjureSession(cjSession *ConjureSession) { + + keys := cjSession.Keys + + sharedSecretStr := make([]byte, hex.EncodedLen(len(keys.SharedSecret))) + hex.Encode(sharedSecretStr, keys.SharedSecret) + log.Debugf("%v Shared Secret - %s", cjSession.IDString(), sharedSecretStr) + + log.Debugf("%v covert %s", cjSession.IDString(), cjSession.CovertAddress) + + reprStr := make([]byte, hex.EncodedLen(len(keys.Representative))) + hex.Encode(reprStr, keys.Representative) + log.Debugf("%v Representative - %s", cjSession.IDString(), reprStr) + +} + +func MakeConjureSession(covert string, transport interfaces.Transport) *ConjureSession { + + cjSession := MakeConjureSessionSilent(covert, transport) + if cjSession == nil { + return nil + } + + // Print out the session details (debug) + LogConjureSession(cjSession) + + return cjSession +} + +func FindConjureSessionInRange(covert string, transport interfaces.Transport, phantomSubnet *net.IPNet) *ConjureSession { + + count := 0 + log.Debugf("Searching for a seed for phantom subnet %v...", phantomSubnet) + for count < 100000 { + // Generate a random session + cjSession := MakeConjureSessionSilent(covert, transport) + count += 1 + + // Get the phantoms this seed would generate + phantom4, phantom6, _, err := SelectPhantom(cjSession.Keys.ConjureSeed, cjSession.V6Support) + if err != nil { + log.Warnf("%v failed to select Phantom: %v", cjSession.IDString(), err) + } + + // See if our phantoms are in the subnet + if phantomSubnet.Contains(*phantom4) || phantomSubnet.Contains(*phantom6) { + log.Debugf("Generated %d sessions to find one in %v", count, phantomSubnet) + // Print out what we got + LogConjureSession(cjSession) + + return cjSession + } + } + log.Warnf("Failed to find a session in %v", phantomSubnet) + return nil +} + +// IDString - Get the ID string for the session +func (cjSession *ConjureSession) IDString() string { + if cjSession.Keys == nil || cjSession.Keys.SharedSecret == nil { + return fmt.Sprintf("[%v-000000]", strconv.FormatUint(cjSession.SessionID, 10)) + } + + secret := make([]byte, hex.EncodedLen(len(cjSession.Keys.SharedSecret))) + n := hex.Encode(secret, cjSession.Keys.SharedSecret) + if n < 6 { + return fmt.Sprintf("[%v-000000]", strconv.FormatUint(cjSession.SessionID, 10)) + } + return fmt.Sprintf("[%v-%s]", strconv.FormatUint(cjSession.SessionID, 10), secret[:6]) +} + +// String - Print the string for debug and/or logging +func (cjSession *ConjureSession) String() string { + return cjSession.IDString() + // expand for debug?? +} + +// conjureReg generates ConjureReg from the corresponding ConjureSession +func (cjSession *ConjureSession) conjureReg() *ConjureReg { + return &ConjureReg{ + ConjureSession: cjSession, + v6Support: cjSession.V6Support, + covertAddress: cjSession.CovertAddress, + Transport: cjSession.Transport, + Dialer: removeLaddr(cjSession.Dialer), + useProxyHeader: cjSession.UseProxyHeader, + } +} + +// BidirectionalRegData returns a C2SWrapper for bidirectional registration +func (cjSession *ConjureSession) BidirectionalRegData(ctx context.Context, regSource *pb.RegistrationSource) (*ConjureReg, *pb.C2SWrapper, error) { + reg := cjSession.conjureReg() + + c2s, err := reg.generateClientToStation(ctx) + if err != nil { + return nil, nil, err + } + + return reg, &pb.C2SWrapper{ + SharedSecret: cjSession.Keys.SharedSecret, + RegistrationPayload: c2s, + RegistrationSource: regSource, + }, nil + +} + +// UnidirectionalRegData returns a C2SWrapper for unidirectional registration +func (cjSession *ConjureSession) UnidirectionalRegData(ctx context.Context, regSource *pb.RegistrationSource) (*ConjureReg, *pb.C2SWrapper, error) { + reg := cjSession.conjureReg() + + phantom4, phantom6, supportRandomPort, err := SelectPhantom(cjSession.Keys.ConjureSeed, cjSession.V6Support) + if err != nil { + log.Warnf("%v failed to select Phantom: %v", cjSession.IDString(), err) + return nil, nil, err + } + + reg.phantom4 = phantom4 + reg.phantom6 = phantom6 + err = cjSession.Transport.SetParams(&pb.GenericTransportParams{RandomizeDstPort: proto.Bool(supportRandomPort)}, true) + if err != nil { + return nil, nil, err + } + reg.phantomDstPort, err = cjSession.Transport.GetDstPort(reg.Keys.ConjureSeed) + if err != nil { + return nil, nil, err + } + + c2s, err := reg.generateClientToStation(ctx) + if err != nil { + return nil, nil, err + } + + return reg, &pb.C2SWrapper{ + SharedSecret: cjSession.Keys.SharedSecret, + RegistrationPayload: c2s, + RegistrationSource: regSource, + }, nil +} + +// GetV6Support created for the sake of removing ConjureReg +func (cjSession *ConjureSession) GetV6Support() *bool { + support := true + if cjSession.V6Support&V6 == 0 { + support = false + } + return &support +} + +// GetV4Support created for the sake of removing ConjureReg +func (cjSession *ConjureSession) GetV4Support() *bool { + // for now return true and register both + support := true + if cjSession.V6Support&V4 == 0 { + support = false + } + return &support +} + +type resultTuple struct { + conn net.Conn + err error +} diff --git a/pkg/core/interfaces/interfaces.go b/pkg/core/interfaces/interfaces.go index f086d86c..6330ccb6 100644 --- a/pkg/core/interfaces/interfaces.go +++ b/pkg/core/interfaces/interfaces.go @@ -10,7 +10,18 @@ import ( "google.golang.org/protobuf/types/known/anypb" ) -type dialFunc = func(ctx context.Context, network, laddr, raddr string) (net.Conn, error) +// Registrar defines the interface for a module completing the initial portion of the conjure +// protocol which registers the clients intent to connect, along with the specifics of the session +// they wish to establish. +type Registrar interface { + Register(context.Context, any) (any, error) + + // PrepareRegKeys prepares key materials specific to the registrar + PrepareRegKeys(pubkey [32]byte) error +} + +// DialFunc is a function type alias for dialing a connection. +type DialFunc = func(ctx context.Context, network, laddr, raddr string) (net.Conn, error) // Transport provides a generic interface for utilities that allow the client to dial and connect to // a phantom address when creating a Conjure connection. @@ -52,6 +63,8 @@ type Transport interface { PrepareKeys(pubkey [32]byte, sharedSecret []byte, dRand io.Reader) error } +// WrappingTransport defines the interface for reactive transports that receive and then wrap +// client connections from the station perspective. type WrappingTransport interface { Transport @@ -59,42 +72,17 @@ type WrappingTransport interface { WrapConn(conn net.Conn) (net.Conn, error) } +// ConnectingTransport defines the interface for proactive transports that dial out from the station +// as a means of creating the proxy connection with the client. type ConnectingTransport interface { Transport - WrapDial(dialer dialFunc) (dialFunc, error) + WrapDial(dialer DialFunc) (DialFunc, error) DisableRegDelay() bool } -// Overrides makes it possible to treat an array of overrides as a single override note that the -// subsequent overrides are not aware of those that come before so they may end up undoing their -// changes. -type Overrides []RegOverride - -// Override implements the RegOverride interface. -func (o Overrides) Override(reg *pb.C2SWrapper, randReader io.Reader) error { - var err error - for _, override := range o { - err = override.Override(reg, randReader) - if err != nil { - return err - } - } - return nil -} - -// RegOverride provides a generic way for the station to mutate an incoming registration before -// handing it off to the stations or returning it to the client as part of the RegResponse protobuf. -type RegOverride interface { - Override(*pb.C2SWrapper, io.Reader) error -} - -// DNAT used by the station side DTLS transport implementation to warm up the DNAT table such that -// we are able to handle incoming client connections. -type DNAT interface { - AddEntry(clientAddr *net.IP, clientPort uint16, phantomIP *net.IP, phantomPort uint16) error -} - -// DnatBuilder function type alias for building a DNAT object -type DnatBuilder func() (DNAT, error) +// Registration is a generic interface for the registration structure used by clients to establish +// a connection after registering their session with the station. This acts as a kind of ticket, +// holding the information necessary to (re-)establish the connection to the phantom. +type Registration interface{} diff --git a/pkg/station/lib/transports.go b/pkg/core/interfaces/station_side.go similarity index 57% rename from pkg/station/lib/transports.go rename to pkg/core/interfaces/station_side.go index 7a9a783d..a6e10a70 100644 --- a/pkg/station/lib/transports.go +++ b/pkg/core/interfaces/station_side.go @@ -1,18 +1,39 @@ -package lib +package interfaces import ( "bytes" "context" + "io" "net" - "github.com/refraction-networking/conjure/pkg/transports" pb "github.com/refraction-networking/conjure/proto" "google.golang.org/protobuf/types/known/anypb" ) -// Transport defines the interface for the manager to interface with variable transports that wrap +// RegistrationSS provides an abstraction around station tracked registrations. +type RegistrationSS interface { + SharedSecret() []byte + GetRegistrationAddress() string + GetSrcPort() uint16 + GetDstPort() uint16 + PhantomIP() *net.IP + + // Transport management functions + TransportType() pb.TransportType + TransportParams() any + SetTransportKeys(interface{}) error + TransportKeys() interface{} + TransportReader() io.Reader +} + +// RegManager provides an abstraction for the RegistrationManager which tracks registrations. +type RegManager interface { + GetRegistrations(phantomAddr net.IP) map[string]RegistrationSS +} + +// TransportSS defines the interface for the manager to interface with variable transports that wrap // the traffic sent by clients. -type Transport interface { +type TransportSS interface { // The human-friendly name of the transport. Name() string @@ -22,7 +43,7 @@ type Transport interface { // GetIdentifier takes in a registration and returns an identifier for it. This identifier // should be unique for each registration on a given phantom; registrations on different // phantoms can have the same identifier. - GetIdentifier(transports.Registration) string + GetIdentifier(RegistrationSS) string // GetProto returns the IP protocol used by the transport. Typical transports will use TCP or // UDP, if something beyond these is required you will need to update the enum in the protobuf @@ -45,11 +66,11 @@ type Transport interface { ParamStrings(p any) []string } -// WrappingTransport describes any transport that is able to passively +// WrappingTransportSS describes any transport that is able to passively // listen to incoming network connections and identify itself, then actively // wrap the connection. -type WrappingTransport interface { - Transport +type WrappingTransportSS interface { + TransportSS // WrapConnection attempts to wrap the given connection in the transport. It takes the // information gathered so far on the connection in data, attempts to identify itself, and if it @@ -69,15 +90,47 @@ type WrappingTransport interface { // yet been enough data sent to be conclusive), they should return transports.ErrTryAgain. If // the transport can be conclusively determined to not exist on the connection, implementations // should return transports.ErrNotTransport. - WrapConnection(data *bytes.Buffer, conn net.Conn, phantom net.IP, rm transports.RegManager) (reg transports.Registration, wrapped net.Conn, err error) + WrapConnection(data *bytes.Buffer, conn net.Conn, phantom net.IP, rm RegManager) (reg RegistrationSS, wrapped net.Conn, err error) } -// ConnectingTransport describes transports that actively form an outgoing connection to clients to +// ConnectingTransportSS describes transports that actively form an outgoing connection to clients to // initiate the conversation. -type ConnectingTransport interface { - Transport +type ConnectingTransportSS interface { + TransportSS // Connect attempts to connect to the client from the phantom address derived in the // registration. - Connect(context.Context, transports.Registration) (net.Conn, error) + Connect(context.Context, RegistrationSS) (net.Conn, error) +} + +// RegOverride provides a generic way for the station to mutate an incoming registration before +// handing it off to the stations or returning it to the client as part of the RegResponse protobuf. +type RegOverride interface { + Override(*pb.C2SWrapper, io.Reader) error } + +// Overrides makes it possible to treat an array of overrides as a single override note that the +// subsequent overrides are not aware of those that come before so they may end up undoing their +// changes. +type Overrides []RegOverride + +// Override implements the RegOverride interface. +func (o Overrides) Override(reg *pb.C2SWrapper, randReader io.Reader) error { + var err error + for _, override := range o { + err = override.Override(reg, randReader) + if err != nil { + return err + } + } + return nil +} + +// DNAT used by the station side DTLS transport implementation to warm up the DNAT table such that +// we are able to handle incoming client connections. +type DNAT interface { + AddEntry(clientAddr *net.IP, clientPort uint16, phantomIP *net.IP, phantomPort uint16) error +} + +// DnatBuilder function type alias for building a DNAT object +type DnatBuilder func() (DNAT, error) diff --git a/pkg/core/keys.go b/pkg/core/keys.go index 59be88c2..12b93ed0 100644 --- a/pkg/core/keys.go +++ b/pkg/core/keys.go @@ -15,6 +15,12 @@ import ( "golang.org/x/crypto/hkdf" ) +// AES_GCM_TAG_SIZE the size of the aesgcm tag used when generating the client to +// station message. +// +//lint:ignore ST1003 This is a preferred style in this case. +const AES_GCM_TAG_SIZE = 16 + // ConjureSharedKeys contains keys that the station is required to keep. type ConjureSharedKeys struct { SharedSecret []byte diff --git a/pkg/station/log/logger.go b/pkg/log/logger.go similarity index 98% rename from pkg/station/log/logger.go rename to pkg/log/logger.go index 2744f38c..753dc264 100644 --- a/pkg/station/log/logger.go +++ b/pkg/log/logger.go @@ -267,6 +267,11 @@ func New(out io.Writer, prefix string, flag int) *Logger { return &Logger{Logger: log.New(out, prefix, flag), level: level} } +// Default returns a new logger struct with default values. +func Default() *Logger { + return &Logger{Logger: log.Default(), level: level} +} + // SetLevel Sets the log level for the log package function calls, func (l *Logger) SetLevel(ll Level) { l.level = ll diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index 5876926d..61bb5515 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -1,21 +1,22 @@ package metrics import ( + "fmt" "sync" "time" - log "github.com/sirupsen/logrus" + "github.com/refraction-networking/conjure/pkg/log" ) // Metrics provides an interface to log operational counters type Metrics struct { metricsMap map[string]int rwMutex sync.RWMutex - logger log.FieldLogger + logger *log.Logger } // NewMetrics creates a Metrics object using the provided logger and starts logging every provided logPeriod -func NewMetrics(logger log.FieldLogger, logPeriod time.Duration) *Metrics { +func NewMetrics(logger *log.Logger, logPeriod time.Duration) *Metrics { m := &Metrics{ logger: logger, rwMutex: sync.RWMutex{}, @@ -38,11 +39,14 @@ func (m *Metrics) Add(name string, val int) { func (m *Metrics) log() { loggerWithFields := m.logger - m.rwMutex.RLock() - for key, val := range m.metricsMap { - loggerWithFields = loggerWithFields.WithField(key, val) - } - m.rwMutex.RUnlock() + // embedded function to allow for scoped defer of mutex unlock + func() { + m.rwMutex.RLock() + defer m.rwMutex.RUnlock() + for key, val := range m.metricsMap { + loggerWithFields.SetPrefix(fmt.Sprintf("%s: %d", key, val)) + } + }() loggerWithFields.Infof("current metrics") } diff --git a/pkg/registrars/decoy-registrar/decoy-registrar.go b/pkg/registrars/decoy-registrar/decoy-registrar.go index 51b8b964..24f2bece 100644 --- a/pkg/registrars/decoy-registrar/decoy-registrar.go +++ b/pkg/registrars/decoy-registrar/decoy-registrar.go @@ -3,21 +3,20 @@ package decoy import ( "context" "fmt" + golog "log" "math/big" "net" + "os" "sync" "time" + "github.com/refraction-networking/conjure/pkg/client" "github.com/refraction-networking/conjure/pkg/client/assets" "github.com/refraction-networking/conjure/pkg/core" + "github.com/refraction-networking/conjure/pkg/log" "github.com/refraction-networking/conjure/pkg/registrars/lib" pb "github.com/refraction-networking/conjure/proto" tls "github.com/refraction-networking/utls" - - // td imports assets, RegError, generateHTTPRequestBeginning - td "github.com/refraction-networking/gotapdance/tapdance" - - "github.com/sirupsen/logrus" ) // timeout for sending TD request and getting a response @@ -41,17 +40,20 @@ var ( tdFlagUseTIL = uint8(1 << 0) ) -var default_flags = tdFlagUseTIL +var defaultFlags = tdFlagUseTIL +// DialFunc is a function that establishes network connections to decoys. This Dial does not require +// a local address. type DialFunc = func(ctx context.Context, network, addr string) (net.Conn, error) +// DecoyRegistrar implements the Registrar interface for the Decoy Registration method. type DecoyRegistrar struct { // dialContex is a custom dialer to use when establishing TCP connections // to decoys. When nil, Dialer.dialContex will be used. dialContex DialFunc - logger logrus.FieldLogger + logger *log.Logger // Fields taken from ConjureReg struct m sync.Mutex @@ -65,21 +67,19 @@ type DecoyRegistrar struct { ClientHelloID tls.ClientHelloID } +// NewDecoyRegistrar returns a decoy registrar with the default `net` dialer. func NewDecoyRegistrar() *DecoyRegistrar { - return &DecoyRegistrar{ - logger: td.Logger(), - ClientHelloID: tls.HelloChrome_62, - Width: 5, - } + d := &net.Dialer{} + return NewDecoyRegistrarWithDialFn(d.DialContext) } -// NewDecoyRegistrarWithDialer returns a decoy registrar with custom dialer. +// NewDecoyRegistrarWithDialFn returns a decoy registrar with custom dialer. // -// Deprecated: Set dialer in tapdace.Dialer.DialerWithLaddr instead. -func NewDecoyRegistrarWithDialer(dialer DialFunc) *DecoyRegistrar { +// Deprecated: Set dialer in Dialer.DialWithLaddr instead. +func NewDecoyRegistrarWithDialFn(dialer DialFunc) *DecoyRegistrar { return &DecoyRegistrar{ dialContex: dialer, - logger: td.Logger(), + logger: log.New(os.Stdout, "reg: Decoy, ", golog.Ldate|golog.Lmicroseconds), ClientHelloID: tls.HelloChrome_62, Width: 5, } @@ -113,11 +113,11 @@ func (r *DecoyRegistrar) PrepareRegKeys(pubkey [32]byte) error { // getRandomDurationByRTT returns a random duration between min and max in milliseconds adding base. func (r *DecoyRegistrar) getRandomDurationByRTT(base, min, max int) time.Duration { addon := getRandInt(min, max) / 1000 // why this min and max??? - rtt := rttInt(r.getTcpToDecoy()) + rtt := rttInt(r.getTCPToDecoy()) return time.Millisecond * time.Duration(base+rtt*addon) } -func (r *DecoyRegistrar) getTcpToDecoy() uint32 { +func (r *DecoyRegistrar) getTCPToDecoy() uint32 { if r == nil { return 0 } @@ -166,7 +166,7 @@ func (r *DecoyRegistrar) createTLSConn(dialConn net.Conn, address string, hostna return tlsConn, nil } -func (r *DecoyRegistrar) createRequest(tlsConn *tls.UConn, decoy *pb.TLSDecoySpec, cjSession *td.ConjureSession) ([]byte, error) { +func (r *DecoyRegistrar) createRequest(tlsConn *tls.UConn, decoy *pb.TLSDecoySpec, cjSession *client.ConjureSession) ([]byte, error) { //[reference] generate and encrypt variable size payload vsp, err := generateVSP(cjSession) if err != nil { @@ -204,21 +204,21 @@ func (r *DecoyRegistrar) createRequest(tlsConn *tls.UConn, decoy *pb.TLSDecoySpe return httpRequest, nil } -func (r *DecoyRegistrar) Register(cjSession *td.ConjureSession, ctx context.Context) (*td.ConjureReg, error) { - logger := r.logger.WithFields(logrus.Fields{"type": "unidirectional", "sessionID": cjSession.IDString()}) - - logger.Debugf("Registering V4 and V6 via DecoyRegistrar") +// Register implements the conjure Registrar interface. +func (r *DecoyRegistrar) Register(ctx context.Context, cjSession *client.ConjureSession) (*client.ConjureReg, error) { + fields := fmt.Sprintf("type:unidirectional, sessionID:%v", cjSession.IDString()) + r.logger.Debugf("Registering V4 and V6 via DecoyRegistrar [%s]", fields) reg, _, err := cjSession.UnidirectionalRegData(ctx, pb.RegistrationSource_API.Enum()) if err != nil { - logger.Errorf("Failed to prepare registration data: %v", err) + r.logger.Errorf("Failed to prepare registration data [%s]: %v", fields, err) return nil, lib.ErrRegFailed } // Choose N (width) decoys from decoylist - decoys, err := selectDecoys(cjSession.Keys.SharedSecret, cjSession.V6Support.Include(), r.Width) + decoys, err := selectDecoys(cjSession.Keys.SharedSecret, uint(cjSession.V6Support), r.Width) if err != nil { - logger.Warnf("failed to select decoys: %v", err) + r.logger.Warnf("failed to select decoys [%s]: %v", fields, err) return nil, err } @@ -233,13 +233,13 @@ func (r *DecoyRegistrar) Register(cjSession *td.ConjureSession, ctx context.Cont width := uint(len(decoys)) if width < r.Width { - logger.Warnf("Using width %v (default %v)", width, r.Width) + r.logger.Warnf("Using width %v (default %v)", width, r.Width) } //[reference] Send registrations to each decoy dialErrors := make(chan error, width) for _, decoy := range decoys { - logger.Debugf("Sending Reg: %v, %v", decoy.GetHostname(), decoy.GetIpAddrStr()) + r.logger.Debugf("[%s] Sending Reg: %v, %v", fields, decoy.GetHostname(), decoy.GetIpAddrStr()) //decoyAddr := decoy.GetIpAddrStr() go r.Send(ctx, cjSession, decoy, dialErrors) } @@ -248,8 +248,8 @@ func (r *DecoyRegistrar) Register(cjSession *td.ConjureSession, ctx context.Cont var unreachableCount uint = 0 for err := range dialErrors { if err != nil { - logger.Debugf("%v", err) - if dialErr, ok := err.(td.RegError); ok && dialErr.Code() == td.Unreachable { + r.logger.Debugf("[%s] %v", fields, err) + if dialErr, ok := err.(client.RegError); ok && dialErr.Code() == client.Unreachable { // If we failed because ipv6 network was unreachable try v4 only. unreachableCount++ if unreachableCount < width { @@ -259,25 +259,28 @@ func (r *DecoyRegistrar) Register(cjSession *td.ConjureSession, ctx context.Cont } } } - //[reference] if we succeed or fail for any other reason then the network is reachable and we can continue + //[reference] if we succeed or fail for any other reason then the network is reachable and + //we can continue break } //[reference] if ALL fail to dial return error (retry in parent if ipv6 unreachable) if unreachableCount == width { - logger.Debugf("NETWORK UNREACHABLE") - return nil, td.NewRegError(td.Unreachable, "All decoys failed to register -- Dial Unreachable") + r.logger.Debugf("NETWORK UNREACHABLE [%s]", fields) + return nil, client.NewRegError(client.Unreachable, "All decoys failed to register -- Dial Unreachable") } // randomized sleeping here to break the intraflow signal toSleep := r.getRandomDurationByRTT(3000, 212, 3449) - logger.Debugf("Successfully sent registrations, sleeping for: %v", toSleep) + r.logger.Debugf("[%s] Successfully sent registrations, sleeping for: %v", fields, toSleep) lib.SleepWithContext(ctx, toSleep) return reg, nil } -func (r *DecoyRegistrar) Send(ctx context.Context, cjSession *td.ConjureSession, decoy *pb.TLSDecoySpec, dialError chan error) { +// Send constructs a decoy registration and sends the encoded request to the decoy completing the +// registration. +func (r *DecoyRegistrar) Send(ctx context.Context, cjSession *client.ConjureSession, decoy *pb.TLSDecoySpec, dialError chan error) { deadline, deadlineAlreadySet := ctx.Deadline() if !deadlineAlreadySet { @@ -295,7 +298,7 @@ func (r *DecoyRegistrar) Send(ctx context.Context, cjSession *td.ConjureSession, r.setTCPToDecoy(durationToU32ptrMs(time.Since(tcpToDecoyStartTs))) if err != nil { if opErr, ok := err.(*net.OpError); ok && opErr.Err.Error() == "connect: network is unreachable" { - dialError <- td.NewRegError(td.Unreachable, err.Error()) + dialError <- client.NewRegError(client.Unreachable, err.Error()) return } dialError <- err @@ -312,7 +315,7 @@ func (r *DecoyRegistrar) Send(ctx context.Context, cjSession *td.ConjureSession, if err != nil { dialConn.Close() msg := fmt.Sprintf("%v - %v createConn: %v", decoy.GetHostname(), decoy.GetIpAddrStr(), err.Error()) - dialError <- td.NewRegError(td.TLSError, msg) + dialError <- client.NewRegError(client.TLSError, msg) return } r.setTLSToDecoy(durationToU32ptrMs(time.Since(tlsToDecoyStartTs))) @@ -321,7 +324,7 @@ func (r *DecoyRegistrar) Send(ctx context.Context, cjSession *td.ConjureSession, httpRequest, err := r.createRequest(tlsConn, decoy, cjSession) if err != nil { msg := fmt.Sprintf("%v - %v createReq: %v", decoy.GetHostname(), decoy.GetIpAddrStr(), err.Error()) - dialError <- td.NewRegError(td.TLSError, msg) + dialError <- client.NewRegError(client.TLSError, msg) return } @@ -332,7 +335,7 @@ func (r *DecoyRegistrar) Send(ctx context.Context, cjSession *td.ConjureSession, // Logger().Errorf("%v - %v Could not send Conjure registration request, error: %v", decoy.GetHostname(), decoy.GetIpAddrStr(), err.Error()) tlsConn.Close() msg := fmt.Sprintf("%v - %v Write: %v", decoy.GetHostname(), decoy.GetIpAddrStr(), err.Error()) - dialError <- td.NewRegError(td.TLSError, msg) + dialError <- client.NewRegError(client.TLSError, msg) return } @@ -340,25 +343,21 @@ func (r *DecoyRegistrar) Send(ctx context.Context, cjSession *td.ConjureSession, readAndClose(dialConn, time.Second*15) } -const ( - v4 uint = iota - v6 - both -) - // SelectDecoys - Get an array of `width` decoys to be used for registration func selectDecoys(sharedSecret []byte, version uint, width uint) ([]*pb.TLSDecoySpec, error) { + vX := client.IPSupport(version) + //[reference] prune to v6 only decoys if useV6 is true var allDecoys []*pb.TLSDecoySpec - switch version { - case v6: + if vX&client.V6 == client.V6 && vX&client.V4 == client.V4 { + allDecoys = assets.Assets().GetAllDecoys() + } else if vX&client.V6 == client.V6 { allDecoys = assets.Assets().GetV6Decoys() - case v4: + + } else if vX&client.V4 == client.V4 { allDecoys = assets.Assets().GetV4Decoys() - case both: - allDecoys = assets.Assets().GetAllDecoys() - default: + } else { allDecoys = assets.Assets().GetAllDecoys() } diff --git a/pkg/registrars/decoy-registrar/decoy-registrar_test.go b/pkg/registrars/decoy-registrar/decoy-registrar_test.go index 5104e9a1..1a967e87 100644 --- a/pkg/registrars/decoy-registrar/decoy-registrar_test.go +++ b/pkg/registrars/decoy-registrar/decoy-registrar_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/require" "github.com/refraction-networking/conjure/internal/conjurepath" + "github.com/refraction-networking/conjure/pkg/client" "github.com/refraction-networking/conjure/pkg/client/assets" ) @@ -24,11 +25,11 @@ func TestSelectDecoys(t *testing.T) { seed, err := hex.DecodeString("5a87133b68da3468988a21659a12ed2ece07345c8c1a5b08459ffdea4218d12f") require.Nil(t, err) - decoys, err := selectDecoys(seed, v6, 5) + decoys, err := selectDecoys(seed, uint(client.V6), 5) require.Nil(t, err) require.True(t, len(decoys) >= 5, "Not enough decoys returned from selection.") - decoys, err = selectDecoys(seed, v4, 5) + decoys, err = selectDecoys(seed, uint(client.V4), 5) require.Nil(t, err) require.True(t, len(decoys) >= 5, "Not enough decoys returned from selection.") } @@ -76,7 +77,7 @@ func TestSelectDecoysErrorHandling(t *testing.T) { // ====[ ClientConf file doesn't exist ]===== // => still using default configuration path since there was not file to update - decoy, err := selectDecoys(seed, both, 1) + decoy, err := selectDecoys(seed, uint(client.V4|client.V6), 1) require.Nil(t, err) require.NotNil(t, decoy) assert.Equal(t, "tapdance1.freeaeskey.xyz", decoy[0].GetHostname()) @@ -90,7 +91,7 @@ func TestSelectDecoysErrorHandling(t *testing.T) { } // => still using default configuration path since there was not file to update - decoy, err = selectDecoys(seed, both, 1) + decoy, err = selectDecoys(seed, uint(client.V4|client.V6), 1) require.Nil(t, err) require.NotNil(t, decoy) assert.Equal(t, "tapdance1.freeaeskey.xyz", decoy[0].GetHostname()) diff --git a/pkg/registrars/decoy-registrar/utils.go b/pkg/registrars/decoy-registrar/utils.go index e8611bd3..e9d693a6 100644 --- a/pkg/registrars/decoy-registrar/utils.go +++ b/pkg/registrars/decoy-registrar/utils.go @@ -11,18 +11,15 @@ import ( "strings" "time" + "github.com/refraction-networking/conjure/pkg/client" + "github.com/refraction-networking/conjure/pkg/client/assets" "github.com/refraction-networking/conjure/pkg/core" - "github.com/refraction-networking/conjure/pkg/station/log" + "github.com/refraction-networking/conjure/pkg/log" pb "github.com/refraction-networking/conjure/proto" - td "github.com/refraction-networking/gotapdance/tapdance" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" ) -// utils.go contains functions needed for the decoy-registrar specifically -// that do not have a ConjureReg, ConjureSession, DecoyRegistrar, etc receiver. -// Most functions are taken from gotapdance/tapdance/utils.go - // The key argument should be the AES key, either 16 or 32 bytes // to select AES-128 or AES-256. func aesGcmEncrypt(plaintext []byte, key []byte, iv []byte) ([]byte, error) { @@ -187,7 +184,7 @@ func readAndClose(c net.Conn, readDeadline time.Duration) { // receiver, but eventually we may want to change the receiver type to *ConjureSession, // or use type alias to another name so we can define functions with that receiver here. -func getPbTransportParams(cjSession *td.ConjureSession) (*anypb.Any, error) { +func getPbTransportParams(cjSession *client.ConjureSession) (*anypb.Any, error) { var m proto.Message m, err := cjSession.Transport.GetParams() if err != nil { @@ -198,7 +195,7 @@ func getPbTransportParams(cjSession *td.ConjureSession) (*anypb.Any, error) { return anypb.New(m) } -func generateVSP(cjSession *td.ConjureSession) ([]byte, error) { +func generateVSP(cjSession *client.ConjureSession) ([]byte, error) { c2s, err := generateClientToStation(cjSession) if err != nil { return nil, err @@ -207,7 +204,7 @@ func generateVSP(cjSession *td.ConjureSession) ([]byte, error) { return proto.Marshal(c2s) } -func generateClientToStation(cjSession *td.ConjureSession) (*pb.ClientToStation, error) { +func generateClientToStation(cjSession *client.ConjureSession) (*pb.ClientToStation, error) { var covert *string if len(cjSession.CovertAddress) > 0 { //[TODO]{priority:medium} this isn't the correct place to deal with signaling to the station @@ -217,7 +214,7 @@ func generateClientToStation(cjSession *td.ConjureSession) (*pb.ClientToStation, //[reference] Generate ClientToStation protobuf // transition := pb.C2S_Transition_C2S_SESSION_INIT - currentGen := td.Assets().GetGeneration() + currentGen := assets.Assets().GetGeneration() currentLibVer := core.CurrentClientLibraryVersion() transport := cjSession.Transport.ID() @@ -250,16 +247,16 @@ func generateClientToStation(cjSession *td.ConjureSession) (*pb.ClientToStation, // initProto.MaskedDecoyServerName = ®.phantomSNI // } - for (proto.Size(initProto)+td.AES_GCM_TAG_SIZE)%3 != 0 { + for (proto.Size(initProto)+core.AES_GCM_TAG_SIZE)%3 != 0 { initProto.Padding = append(initProto.Padding, byte(0)) } return initProto, nil } -func generateFlags(cjSession *td.ConjureSession) *pb.RegistrationFlags { +func generateFlags(cjSession *client.ConjureSession) *pb.RegistrationFlags { flags := &pb.RegistrationFlags{} - mask := default_flags + mask := defaultFlags if cjSession.UseProxyHeader { mask |= tdFlagProxyHeader } diff --git a/pkg/registrars/registration/api-registrar.go b/pkg/registrars/registration/api-registrar.go index e3d3b244..12b860cf 100644 --- a/pkg/registrars/registration/api-registrar.go +++ b/pkg/registrars/registration/api-registrar.go @@ -5,14 +5,16 @@ import ( "context" "fmt" "io" + golog "log" "net/http" - "strconv" + "os" "time" + "github.com/refraction-networking/conjure/pkg/client" + "github.com/refraction-networking/conjure/pkg/core/interfaces" + "github.com/refraction-networking/conjure/pkg/log" "github.com/refraction-networking/conjure/pkg/registrars/lib" pb "github.com/refraction-networking/conjure/proto" - "github.com/refraction-networking/gotapdance/tapdance" - "github.com/sirupsen/logrus" "google.golang.org/protobuf/proto" ) @@ -47,10 +49,10 @@ type APIRegistrar struct { // be attempted. If it is non-nil, after failing to register // (retrying MaxRetries times) we will fall back to // the Register method on this field. - secondaryRegistrar tapdance.Registrar + secondaryRegistrar interfaces.Registrar // Logger to use. - logger logrus.FieldLogger + logger *log.Logger } func NewAPIRegistrar(config *Config) (*APIRegistrar, error) { @@ -61,7 +63,7 @@ func NewAPIRegistrar(config *Config) (*APIRegistrar, error) { maxRetries: config.MaxRetries, secondaryRegistrar: config.SecondaryRegistrar, client: config.HTTPClient, - logger: tapdance.Logger().WithField("registrar", "API"), + logger: log.New(os.Stdout, "reg: API, ", golog.Ldate|golog.Lmicroseconds), }, nil } @@ -71,8 +73,8 @@ func (r *APIRegistrar) PrepareRegKeys(pubkey [32]byte) error { } // registerUnidirectional sends unidirectional registration data to the registration server -func (r *APIRegistrar) registerUnidirectional(cjSession *tapdance.ConjureSession, ctx context.Context) (*tapdance.ConjureReg, error) { - logger := r.logger.WithFields(logrus.Fields{"type": "unidirectional", "sessionID": cjSession.IDString()}) +func (r *APIRegistrar) registerUnidirectional(ctx context.Context, cjSession *client.ConjureSession) (*client.ConjureReg, error) { + logger := log.New(os.Stdout, fmt.Sprintf("type: unidirectional, sessionID: %s", cjSession.IDString()), golog.Ldate|golog.Lmicroseconds) reg, protoPayload, err := cjSession.UnidirectionalRegData(ctx, pb.RegistrationSource_API.Enum()) if err != nil { @@ -89,10 +91,9 @@ func (r *APIRegistrar) registerUnidirectional(cjSession *tapdance.ConjureSession r.setHTTPClient(reg) for tries := 0; tries < r.maxRetries+1; tries++ { - logger := logger.WithField("attempt", strconv.Itoa(tries+1)+"/"+strconv.Itoa(r.maxRetries+1)) err = r.executeHTTPRequest(ctx, payload, logger) if err != nil { - logger.Warnf("error in registration attempt: %v", err) + logger.Warnf("error in registration attempt %d/%d: %v", tries+1, r.maxRetries+1, err) continue } logger.Debugf("registration succeeded") @@ -100,19 +101,20 @@ func (r *APIRegistrar) registerUnidirectional(cjSession *tapdance.ConjureSession } // If we make it here, we failed API registration - logger.WithField("attempts", r.maxRetries+1).Warnf("all registration attempt(s) failed") + logger.Warnf("attempts: %d, all registration attempt(s) failed", r.maxRetries+1) if r.secondaryRegistrar != nil { logger.Debugf("trying secondary registration method") - return r.secondaryRegistrar.Register(cjSession, ctx) + r, err := r.secondaryRegistrar.Register(ctx, cjSession) + return r.(*client.ConjureReg), err } return nil, lib.ErrRegFailed } // registerBidirectional sends bidirectional registration data to the registration server and reads the response -func (r *APIRegistrar) registerBidirectional(cjSession *tapdance.ConjureSession, ctx context.Context) (*tapdance.ConjureReg, error) { - logger := r.logger.WithFields(logrus.Fields{"type": "bidirectional", "sessionID": cjSession.IDString()}) +func (r *APIRegistrar) registerBidirectional(ctx context.Context, cjSession *client.ConjureSession) (*client.ConjureReg, error) { + logger := log.New(os.Stdout, fmt.Sprintf("type: bidirectional, sessionID: %s", cjSession.IDString()), golog.Ldate|golog.Lmicroseconds) reg, protoPayload, err := cjSession.BidirectionalRegData(ctx, pb.RegistrationSource_BidirectionalAPI.Enum()) if err != nil { @@ -129,11 +131,9 @@ func (r *APIRegistrar) registerBidirectional(cjSession *tapdance.ConjureSession, r.setHTTPClient(reg) for tries := 0; tries < r.maxRetries+1; tries++ { - logger := logger.WithField("attempt", strconv.Itoa(tries+1)+"/"+strconv.Itoa(r.maxRetries+1)) - regResp, err := r.executeHTTPRequestBidirectional(ctx, payload, logger) if err != nil { - logger.Warnf("error in registration attempt: %v", err) + logger.Warnf("error in registration attempt %d/%d: %v", tries+1, r.maxRetries+1, err) continue } @@ -146,17 +146,16 @@ func (r *APIRegistrar) registerBidirectional(cjSession *tapdance.ConjureSession, } // If we make it here, we failed API registration - logger.WithField("attempts", r.maxRetries+1).Warnf("all registration attempt(s) failed") - if r.secondaryRegistrar != nil { - logger.Debugf("trying secondary registration method") - return r.secondaryRegistrar.Register(cjSession, ctx) + logger.Debugf("attempts: %d, trying secondary registration method", r.maxRetries+1) + r, err := r.secondaryRegistrar.Register(ctx, cjSession) + return r.(*client.ConjureReg), err } return nil, lib.ErrRegFailed } -func (r *APIRegistrar) setHTTPClient(reg *tapdance.ConjureReg) { +func (r *APIRegistrar) setHTTPClient(reg *client.ConjureReg) { if r.client == nil { // Transports should ideally be re-used for TCP connection pooling, // but each registration is most likely making precisely one request, @@ -168,17 +167,17 @@ func (r *APIRegistrar) setHTTPClient(reg *tapdance.ConjureReg) { } } -func (r APIRegistrar) Register(cjSession *tapdance.ConjureSession, ctx context.Context) (*tapdance.ConjureReg, error) { +func (r APIRegistrar) Register(ctx context.Context, cjSession *client.ConjureSession) (*client.ConjureReg, error) { defer lib.SleepWithContext(ctx, r.connectionDelay) if r.bidirectional { - return r.registerBidirectional(cjSession, ctx) + return r.registerBidirectional(ctx, cjSession) } - return r.registerUnidirectional(cjSession, ctx) + return r.registerUnidirectional(ctx, cjSession) } -func (r APIRegistrar) executeHTTPRequest(ctx context.Context, payload []byte, logger logrus.FieldLogger) error { +func (r APIRegistrar) executeHTTPRequest(ctx context.Context, payload []byte, logger *log.Logger) error { req, err := http.NewRequestWithContext(ctx, "POST", r.endpoint, bytes.NewReader(payload)) if err != nil { logger.Warnf("failed to create HTTP request to registration endpoint %s: %v", r.endpoint, err) @@ -200,19 +199,19 @@ func (r APIRegistrar) executeHTTPRequest(ctx context.Context, payload []byte, lo return nil } -func (r APIRegistrar) executeHTTPRequestBidirectional(ctx context.Context, payload []byte, logger logrus.FieldLogger) (*pb.RegistrationResponse, error) { +func (r APIRegistrar) executeHTTPRequestBidirectional(ctx context.Context, payload []byte, logger *log.Logger) (*pb.RegistrationResponse, error) { // Create an instance of the ConjureReg struct to return; this will hold the updated phantom4 and phantom6 addresses received from registrar response regResp := &pb.RegistrationResponse{} // Make new HTTP request with given context, registrar, and paylaod req, err := http.NewRequestWithContext(ctx, "POST", r.endpoint, bytes.NewReader(payload)) if err != nil { - logger.Warnf("%v failed to create HTTP request to registration endpoint %s: %v", r.endpoint, err) + logger.Warnf("failed to create HTTP request to registration endpoint %s: %v", r.endpoint, err) return regResp, err } resp, err := r.client.Do(req) if err != nil { - logger.Warnf("%v failed to do HTTP request to registration endpoint %s: %v", r.endpoint, err) + logger.Warnf("failed to do HTTP request to registration endpoint %s: %v", r.endpoint, err) return regResp, err } defer resp.Body.Close() diff --git a/pkg/registrars/registration/api-registrar_test.go b/pkg/registrars/registration/api-registrar_test.go index 84a4bd1e..b3d16b42 100644 --- a/pkg/registrars/registration/api-registrar_test.go +++ b/pkg/registrars/registration/api-registrar_test.go @@ -5,15 +5,18 @@ import ( "context" "encoding/binary" "io" + golog "log" "net" "net/http" "net/http/httptest" + "os" "testing" + "github.com/refraction-networking/conjure/pkg/client" + "github.com/refraction-networking/conjure/pkg/client/assets" + "github.com/refraction-networking/conjure/pkg/log" transports "github.com/refraction-networking/conjure/pkg/transports/client" pb "github.com/refraction-networking/conjure/proto" - "github.com/refraction-networking/gotapdance/tapdance" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" ) @@ -24,9 +27,9 @@ func TestAPIRegistrar(t *testing.T) { transport, err := transports.New("min") require.Nil(t, err) - _, err = tapdance.AssetsSetDir("./tests/assets") + _, err = assets.AssetsSetDir("./tests/assets") require.Nil(t, err) - session := tapdance.MakeConjureSession("1.2.3.4:1234", transport) + session := client.MakeConjureSession("1.2.3.4:1234", transport) server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { @@ -57,10 +60,10 @@ func TestAPIRegistrar(t *testing.T) { endpoint: server.URL, client: server.Client(), bidirectional: false, - logger: logrus.New(), + logger: log.New(os.Stdout, "", golog.Ldate|golog.Lmicroseconds), } - _, err = registrar.Register(session, context.TODO()) + _, err = registrar.Register(context.TODO(), session) require.Nil(t, err) server.Close() @@ -72,7 +75,7 @@ func TestAPIRegistrarBidirectional(t *testing.T) { transport, err := transports.New("min") require.Nil(t, err) // Make Conjure session with covert address - session := tapdance.MakeConjureSession("1.2.3.4:1234", transport) + session := client.MakeConjureSession("1.2.3.4:1234", transport) addr4 := binary.BigEndian.Uint32(net.ParseIP("127.0.0.1").To4()) addr6 := net.ParseIP("2001:48a8:687f:1:41d3:ff12:45b:73c8") var port uint32 = 80 @@ -122,12 +125,12 @@ func TestAPIRegistrarBidirectional(t *testing.T) { endpoint: server.URL, client: server.Client(), bidirectional: true, - logger: logrus.New(), + logger: log.New(os.Stdout, "", golog.Ldate|golog.Lmicroseconds), } // register.Register() connects to server set up above and sends registration info // "response" will store the RegistrationResponse protobuf that the server replies with - response, err := registrar.Register(session, context.TODO()) + response, err := registrar.Register(context.TODO(), session) if err != nil { t.Fatalf("bidirectional registrar failed with error: %v", err) } diff --git a/pkg/registrars/registration/config.go b/pkg/registrars/registration/config.go index 75dec8ac..aa2b626a 100644 --- a/pkg/registrars/registration/config.go +++ b/pkg/registrars/registration/config.go @@ -5,7 +5,7 @@ import ( "net/http" "time" - "github.com/refraction-networking/gotapdance/tapdance" + "github.com/refraction-networking/conjure/pkg/core/interfaces" ) type Config struct { @@ -39,7 +39,7 @@ type Config struct { Bidirectional bool // SecondaryRegistrar is the secondary registrar to use when the main one fails - SecondaryRegistrar tapdance.Registrar + SecondaryRegistrar interfaces.Registrar // HTTPClient is the HTTP client to use for the API registrar HTTPClient *http.Client diff --git a/pkg/registrars/registration/decoy-registrar.go b/pkg/registrars/registration/decoy-registrar.go index b7e2a632..72326a7a 100644 --- a/pkg/registrars/registration/decoy-registrar.go +++ b/pkg/registrars/registration/decoy-registrar.go @@ -2,16 +2,15 @@ package registration import ( dr "github.com/refraction-networking/conjure/pkg/registrars/decoy-registrar" + tls "github.com/refraction-networking/utls" ) -// NewDecoyRegistrar returns a decoy registrar.. +// NewDecoyRegistrar returns a decoy registrar with default width and ClientHello ID. func NewDecoyRegistrar() *dr.DecoyRegistrar { return dr.NewDecoyRegistrar() } -// NewDecoyRegistrarWithDialer returns a decoy registrar with custom dialer. -// -// Deprecated: Set dialer in tapdace.Dialer.DialerWithLaddr instead. -func NewDecoyRegistrarWithDialer(dialer dr.DialFunc) *dr.DecoyRegistrar { - return dr.NewDecoyRegistrarWithDialer(dialer) -} +// NewDecoyRegistrarWith returns a decoy registrar with custom width and ClientHello ID. +func NewDecoyRegistrarWith(width uint, chID tls.ClientHelloID) *dr.DecoyRegistrar { + return dr.NewDecoyRegistrar() +} \ No newline at end of file diff --git a/pkg/registrars/registration/dns-registrar.go b/pkg/registrars/registration/dns-registrar.go index 1e8123b4..0cd695a1 100644 --- a/pkg/registrars/registration/dns-registrar.go +++ b/pkg/registrars/registration/dns-registrar.go @@ -4,16 +4,18 @@ import ( "context" "errors" "fmt" + golog "log" "net" - "strconv" + "os" "time" "github.com/pion/stun" + "github.com/refraction-networking/conjure/pkg/client" + "github.com/refraction-networking/conjure/pkg/core/interfaces" + "github.com/refraction-networking/conjure/pkg/log" "github.com/refraction-networking/conjure/pkg/registrars/dns-registrar/requester" "github.com/refraction-networking/conjure/pkg/registrars/lib" pb "github.com/refraction-networking/conjure/proto" - "github.com/refraction-networking/gotapdance/tapdance" - "github.com/sirupsen/logrus" "google.golang.org/protobuf/proto" ) @@ -23,7 +25,7 @@ type DNSRegistrar struct { connectionDelay time.Duration bidirectional bool ip []byte - logger logrus.FieldLogger + logger *log.Logger } func createRequester(config *Config) (*requester.Requester, error) { @@ -63,7 +65,7 @@ func NewDNSRegistrar(config *Config) (*DNSRegistrar, error) { return nil, fmt.Errorf("error creating requester: %v", err) } - ip, err := getPublicIp(config.STUNAddr) + ip, err := getPublicIP(config.STUNAddr) if err != nil { return nil, fmt.Errorf("failed to get public IP: %v", err) } @@ -74,17 +76,17 @@ func NewDNSRegistrar(config *Config) (*DNSRegistrar, error) { maxRetries: config.MaxRetries, bidirectional: config.Bidirectional, connectionDelay: config.Delay, - logger: tapdance.Logger().WithField("registrar", "DNS"), + logger: log.New(os.Stdout, "", golog.Ldate|golog.Lmicroseconds), }, nil } // registerUnidirectional sends unidirectional registration data to the registration server -func (r *DNSRegistrar) registerUnidirectional(ctx context.Context, cjSession *tapdance.ConjureSession) (*tapdance.ConjureReg, error) { - logger := r.logger.WithFields(logrus.Fields{"type": "unidirectional", "sessionID": cjSession.IDString()}) +func (r *DNSRegistrar) registerUnidirectional(ctx context.Context, cjSession *client.ConjureSession) (interfaces.Registration, error) { + fields := fmt.Sprintf("type: unidirectional, sessionID: %s", cjSession.IDString()) reg, protoPayload, err := cjSession.UnidirectionalRegData(ctx, pb.RegistrationSource_DNS.Enum()) if err != nil { - logger.Errorf("Failed to prepare registration data: %v", err) + r.logger.Errorf("Failed to prepare registration data [%s]: %v", fields, err) return nil, lib.ErrRegFailed } @@ -99,38 +101,37 @@ func (r *DNSRegistrar) registerUnidirectional(ctx context.Context, cjSession *ta payload, err := proto.Marshal(protoPayload) if err != nil { - logger.Errorf("failed to marshal ClientToStation payload: %v", err) + r.logger.Errorf("failed to marshal ClientToStation payload [%s]: %v", fields, err) return nil, lib.ErrRegFailed } - logger.Debugf("DNS payload length: %d", len(payload)) + r.logger.Debugf("DNS payload length [%s]: %d", fields, len(payload)) for i := 0; i < r.maxRetries+1; i++ { - logger := logger.WithField("attempt", strconv.Itoa(i+1)+"/"+strconv.Itoa(r.maxRetries)) _, err := r.req.RequestAndRecv(payload) if err != nil { - logger.Warnf("error in registration attempt: %v", err) + r.logger.Warnf("error in registration attempt %d/%d: %v", i+1, r.maxRetries, err) continue } // for unidirectional registration, do not check for response and immediatly return - logger.Debugf("registration succeeded") + r.logger.Debugf("registration succeeded [%s]", fields) return reg, nil } - logger.WithField("maxTries", r.maxRetries).Warnf("all registration attempt(s) failed") + r.logger.Warnf("registration attempt(s) failed") return nil, lib.ErrRegFailed } // registerBidirectional sends bidirectional registration data to the registration server and reads the response -func (r *DNSRegistrar) registerBidirectional(ctx context.Context, cjSession *tapdance.ConjureSession) (*tapdance.ConjureReg, error) { - logger := r.logger.WithFields(logrus.Fields{"type": "bidirectional", "sessionID": cjSession.IDString()}) +func (r *DNSRegistrar) registerBidirectional(ctx context.Context, cjSession *client.ConjureSession) (interfaces.Registration, error) { + fields := fmt.Sprintf("type: unidirectional, sessionID: %s", cjSession.IDString()) reg, protoPayload, err := cjSession.BidirectionalRegData(ctx, pb.RegistrationSource_BidirectionalDNS.Enum()) if err != nil { - logger.Errorf("Failed to prepare registration data: %v", err) + r.logger.Errorf("Failed to prepare registration data [%s]: %v", fields, err) return nil, lib.ErrRegFailed } @@ -145,50 +146,48 @@ func (r *DNSRegistrar) registerBidirectional(ctx context.Context, cjSession *tap payload, err := proto.Marshal(protoPayload) if err != nil { - logger.Errorf("failed to marshal ClientToStation payload: %v", err) + r.logger.Errorf("failed to marshal ClientToStation payload [%s]: %v", fields, err) return nil, lib.ErrRegFailed } - logger.Debugf("DNS payload length: %d", len(payload)) + r.logger.Debugf("DNS payload length: %d", len(payload)) for i := 0; i < r.maxRetries+1; i++ { - logger := logger.WithField("attempt", strconv.Itoa(i+1)+"/"+strconv.Itoa(r.maxRetries)) - bdResponse, err := r.req.RequestAndRecv(payload) if err != nil { - logger.Warnf("error in sending request to DNS registrar: %v", err) + r.logger.Warnf("error in sending request to DNS registrar in attempt %d/%d: %v", i+1, r.maxRetries+1, err) continue } dnsResp := &pb.DnsResponse{} err = proto.Unmarshal(bdResponse, dnsResp) if err != nil { - logger.Warnf("error in storing Registrtion Response protobuf: %v", err) + r.logger.Warnf("error in storing Registration Response protobuf: %v", err) continue } if !dnsResp.GetSuccess() { - logger.Warnf("registrar indicates that registration failed") + r.logger.Warnf("registrar indicates that registration failed") continue } if dnsResp.GetClientconfOutdated() { - logger.Warnf("registrar indicates that ClinetConf is outdated") + r.logger.Warnf("registrar indicates that ClientConf is outdated") } err = reg.UnpackRegResp(dnsResp.GetBidirectionalResponse()) if err != nil { - logger.Warnf("failed to unpack registration response: %v", err) + r.logger.Warnf("failed to unpack registration response: %v", err) continue } return reg, nil } - logger.WithField("maxTries", r.maxRetries).Warnf("all registration attemps failed") + r.logger.Warnf("registration attempt(s) failed") return nil, lib.ErrRegFailed } // Register prepares and sends the registration request. -func (r *DNSRegistrar) Register(cjSession *tapdance.ConjureSession, ctx context.Context) (*tapdance.ConjureReg, error) { +func (r *DNSRegistrar) Register(ctx context.Context, cjSession *client.ConjureSession) (interfaces.Registration, error) { defer lib.SleepWithContext(ctx, r.connectionDelay) if r.bidirectional { @@ -197,7 +196,7 @@ func (r *DNSRegistrar) Register(cjSession *tapdance.ConjureSession, ctx context. return r.registerUnidirectional(ctx, cjSession) } -func getPublicIp(server string) ([]byte, error) { +func getPublicIP(server string) ([]byte, error) { c, err := stun.Dial("udp4", server) if err != nil { diff --git a/pkg/regserver/apiregserver/apiregserver.go b/pkg/regserver/apiregserver/apiregserver.go index 1634f016..f59984c9 100644 --- a/pkg/regserver/apiregserver/apiregserver.go +++ b/pkg/regserver/apiregserver/apiregserver.go @@ -11,11 +11,11 @@ import ( "sync" "github.com/gorilla/mux" + "github.com/refraction-networking/conjure/pkg/log" "github.com/refraction-networking/conjure/pkg/metrics" "github.com/refraction-networking/conjure/pkg/regserver/regprocessor" "github.com/refraction-networking/conjure/pkg/station/lib" pb "github.com/refraction-networking/conjure/proto" - log "github.com/sirupsen/logrus" "google.golang.org/protobuf/proto" ) @@ -29,7 +29,7 @@ type APIRegServer struct { latestClientConf *pb.ClientConf // Latest clientConf for sharing over RegistrationResponse channel. ccMutex sync.RWMutex processor registrar - logger log.FieldLogger + logger *log.Logger logClientIP bool metrics *metrics.Metrics } @@ -118,14 +118,14 @@ func (s *APIRegServer) getC2SFromReq(w http.ResponseWriter, r *http.Request) (*p in, err := io.ReadAll(r.Body) if err != nil { - s.logger.Errorf("failed to read request body:", err) + s.logger.Errorf("failed to read request body: %s", err) http.Error(w, "Failed to read request body", http.StatusBadRequest) return nil, errors.New("failed to read request body") } payload := &pb.C2SWrapper{} if err = proto.Unmarshal(in, payload); err != nil { - s.logger.Errorf("failed to decode protobuf body:", err) + s.logger.Errorf("failed to decode protobuf body: %s", err) http.Error(w, "Failed to decode protobuf body", http.StatusBadRequest) return nil, errors.New("failed to decode protobuf body") } @@ -142,22 +142,23 @@ func (s *APIRegServer) register(w http.ResponseWriter, r *http.Request) { return } - logFields := log.Fields{"http_method": r.Method, "content_length": r.ContentLength, "registration_type": "unidirectional"} + logFields := fmt.Sprintf("http_method: %s, content_length: %d, registration_type: %s", + r.Method, + r.ContentLength, + "unidirectional") + if s.logClientIP { - logFields["ip_address"] = clientAddr.String() + logFields += fmt.Sprintf(", client_ip: %s", clientAddr.String()) } - reqLogger := s.logger.WithFields(logFields) - reqLogger.Debugf("recived new request") + s.logger.Debugf("received new request: [%s]", logFields) payload, err := s.getC2SFromReq(w, r) if err != nil { - reqLogger.Errorf("registration failed: %v", err) + s.logger.Errorf("registration failed: %v", err) return } - reqLogger = reqLogger.WithField("reg_id", hex.EncodeToString(payload.GetSharedSecret())) - var clientAddrBytes = make([]byte, 16) if clientAddr != nil { clientAddrBytes = []byte(clientAddr.To16()) @@ -170,7 +171,7 @@ func (s *APIRegServer) register(w http.ResponseWriter, r *http.Request) { return } - reqLogger.Debugf("registration successful") + s.logger.Debugf("registration successful: [%s]", logFields) // We could send an HTTP response earlier to avoid waiting // while the zmq socket is locked, but this ensures that @@ -187,20 +188,22 @@ func (s *APIRegServer) registerBidirectional(w http.ResponseWriter, r *http.Requ return } - logFields := log.Fields{"http_method": r.Method, "content_length": r.ContentLength, "registration_type": "bidirectional"} + logFields := fmt.Sprintf("http_method: %s, content_length: %d, registration_type: %s", + r.Method, + r.ContentLength, + "bidirectional") + if s.logClientIP { - logFields["ip_address"] = clientAddr.String() + logFields += fmt.Sprintf(", client_ip: %s", clientAddr.String()) } - reqLogger := s.logger.WithFields(logFields) - - reqLogger.Debugf("received new request") + s.logger.Debugf("received new request: [%s]", logFields) payload, err := s.getC2SFromReq(w, r) if err != nil { return } - reqLogger = reqLogger.WithField("reg_id", hex.EncodeToString(payload.GetSharedSecret())) + logFields += fmt.Sprintf(", reg_id: %s", hex.EncodeToString(payload.GetSharedSecret())) var clientAddrBytes = make([]byte, 16) if clientAddr != nil { @@ -224,7 +227,7 @@ func (s *APIRegServer) registerBidirectional(w http.ResponseWriter, r *http.Requ case lib.ErrLegacyAddrSelectBug: http.Error(w, "bad seed", http.StatusBadRequest) default: - reqLogger.Errorf("failed to create registration response: %v", err) + s.logger.Errorf("failed to create registration response: %v, [%s]", err, logFields) w.WriteHeader(http.StatusInternalServerError) } return @@ -240,17 +243,17 @@ func (s *APIRegServer) registerBidirectional(w http.ResponseWriter, r *http.Requ // Marshal (serialize) registration response object and then write it to w body, err := proto.Marshal(regResp) if err != nil { - reqLogger.Errorf("failed to write registration into response: %v", err) + s.logger.Errorf("failed to write registration into response: %v, [%s]", err, logFields) return } _, err = w.Write(body) if err != nil { - reqLogger.Errorf("failed to write registration into response: %v", err) + s.logger.Errorf("failed to write registration into response: %v, [%s]", err, logFields) return } - reqLogger.Debugf("registration successful") + s.logger.Debugf("registration successful %s", logFields) } // registerBidirectional() @@ -316,7 +319,7 @@ func (s *APIRegServer) ListenAndServe() error { return err } -func NewAPIRegServer(apiPort uint16, regprocessor *regprocessor.RegProcessor, latestCC *pb.ClientConf, logger log.FieldLogger, logClientIP bool, metrics *metrics.Metrics) (*APIRegServer, error) { +func NewAPIRegServer(apiPort uint16, regprocessor *regprocessor.RegProcessor, latestCC *pb.ClientConf, logger *log.Logger, logClientIP bool, metrics *metrics.Metrics) (*APIRegServer, error) { if regprocessor == nil || latestCC == nil || logger == nil { return nil, errors.New("arguments cannot be nil") } diff --git a/pkg/regserver/apiregserver/apiregserver_test.go b/pkg/regserver/apiregserver/apiregserver_test.go index f4a65469..862f6a2d 100644 --- a/pkg/regserver/apiregserver/apiregserver_test.go +++ b/pkg/regserver/apiregserver/apiregserver_test.go @@ -6,19 +6,20 @@ import ( "encoding/hex" "fmt" "io" + golog "log" "net" "net/http" "net/http/httptest" + "os" "reflect" "sync" "testing" - "time" zmq "github.com/pebbe/zmq4" + "github.com/refraction-networking/conjure/pkg/log" "github.com/refraction-networking/conjure/pkg/metrics" "github.com/refraction-networking/conjure/pkg/regserver/regprocessor" pb "github.com/refraction-networking/conjure/proto" - log "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" ) @@ -38,9 +39,9 @@ func init() { func newAPIREgServer() APIRegServer { return APIRegServer{ - logger: log.New(), + logger: log.New(os.Stdout, "reg: API, ", golog.Ldate|golog.Lmicroseconds), logClientIP: true, - metrics: metrics.NewMetrics(log.NewEntry(log.StandardLogger()), 5*time.Second), + metrics: metrics.NewMetrics(log.New(io.Discard, "", 0), 5), } } diff --git a/pkg/regserver/dnsregserver/dnsregserver.go b/pkg/regserver/dnsregserver/dnsregserver.go index 5745b8c0..8b69a479 100644 --- a/pkg/regserver/dnsregserver/dnsregserver.go +++ b/pkg/regserver/dnsregserver/dnsregserver.go @@ -6,11 +6,12 @@ import ( "fmt" "sync/atomic" + "github.com/refraction-networking/conjure/pkg/log" "github.com/refraction-networking/conjure/pkg/metrics" "github.com/refraction-networking/conjure/pkg/registrars/dns-registrar/responder" "github.com/refraction-networking/conjure/pkg/regserver/regprocessor" pb "github.com/refraction-networking/conjure/proto" - log "github.com/sirupsen/logrus" + "google.golang.org/protobuf/proto" ) @@ -25,12 +26,12 @@ type DNSRegServer struct { dnsResponder *responder.Responder processor registrar latestCCGen uint32 - logger log.FieldLogger + logger *log.Logger metrics *metrics.Metrics } // NewDNSRegServer creates a new DNSRegServer object. -func NewDNSRegServer(domain string, udpAddr string, privkey []byte, regprocessor *regprocessor.RegProcessor, latestClientConfGeneration uint32, logger log.FieldLogger, metrics *metrics.Metrics) (*DNSRegServer, error) { +func NewDNSRegServer(domain string, udpAddr string, privkey []byte, regprocessor *regprocessor.RegProcessor, latestClientConfGeneration uint32, logger *log.Logger, metrics *metrics.Metrics) (*DNSRegServer, error) { if domain == "" || udpAddr == "" || privkey == nil || regprocessor == nil || logger == nil { return nil, errors.New("all arguments must not be nil") @@ -54,6 +55,7 @@ func NewDNSRegServer(domain string, udpAddr string, privkey []byte, regprocessor }, nil } +// ListenAndServe starts the DNS registration server. func (s *DNSRegServer) ListenAndServe() error { err := s.dnsResponder.RecvAndRespond(s.processRequest) if err != nil { @@ -68,12 +70,12 @@ func (s *DNSRegServer) processRequest(reqIn []byte) ([]byte, error) { c2sPayload := &pb.C2SWrapper{} err := proto.Unmarshal(reqIn, c2sPayload) if err != nil { - s.logger.Errorf("Error in recieved request unmarshal: [%v]", err) + s.logger.Errorf("Error in received request unmarshal: [%v]", err) return nil, err } - reqLogger := s.logger.WithField("regid", hex.EncodeToString(c2sPayload.GetSharedSecret())) - reqLogger.Tracef("Request received: [%+v]", c2sPayload) + fields := fmt.Sprintf("reg_id: %s", hex.EncodeToString(c2sPayload.GetSharedSecret())) + s.logger.Tracef("Request received: [%s] [%+v]", fields, c2sPayload) clientconfOutdated := false if c2sPayload.RegistrationPayload.GetDecoyListGeneration() < atomic.LoadUint32(&s.latestCCGen) { @@ -86,18 +88,18 @@ func (s *DNSRegServer) processRequest(reqIn []byte) ([]byte, error) { reqIsBd := c2sPayload.GetRegistrationSource() == pb.RegistrationSource_BidirectionalDNS if reqIsBd { - reqLogger = s.logger.WithField("registration-type", "bidirectional") + fields += ", registration-type: bidirectional" var regResponse *pb.RegistrationResponse regResponse, err = s.processor.RegisterBidirectional(c2sPayload, pb.RegistrationSource_BidirectionalDNS, nil) dnsResp.BidirectionalResponse = regResponse } else { - reqLogger = s.logger.WithField("registration-type", "unidirectional") + fields += ", registration-type: unidirectional" err = s.processor.RegisterUnidirectional(c2sPayload, pb.RegistrationSource_DNS, nil) } // if registration publish failed, immediately return if err != nil { - reqLogger.Errorf("registration publish failed: %v", err) + s.logger.Errorf("registration publish failed [%s]: %v", fields, err) regSuccess := false dnsResp.Success = ®Success @@ -110,21 +112,22 @@ func (s *DNSRegServer) processRequest(reqIn []byte) ([]byte, error) { regSuccess := true dnsResp.Success = ®Success - reqLogger.Debugf("registration request successful") + s.logger.Debugf("registration request successful [%s]", fields) responsePayload, err := proto.Marshal(dnsResp) if err != nil { - reqLogger.Errorf("response marshal failed") + s.logger.Errorf("response marshal failed, [%s]: %v", fields, err) return nil, errors.New("response marshal failed") } return responsePayload, nil } // Close closes the underlying dns responder. -func (f *DNSRegServer) Close() error { - return f.dnsResponder.Close() +func (s *DNSRegServer) Close() error { + return s.dnsResponder.Close() } -// Close closes the underlying dns responder. -func (f *DNSRegServer) UpdateLatestCCGen(gen uint32) { - atomic.StoreUint32(&f.latestCCGen, gen) +// UpdateLatestCCGen helps the DNS registration server to dynamically reload configuration, updating +// the latest client configuration generation number. +func (s *DNSRegServer) UpdateLatestCCGen(gen uint32) { + atomic.StoreUint32(&s.latestCCGen, gen) } diff --git a/pkg/regserver/dnsregserver/dnsregserver_test.go b/pkg/regserver/dnsregserver/dnsregserver_test.go index 7df9c127..033ba435 100644 --- a/pkg/regserver/dnsregserver/dnsregserver_test.go +++ b/pkg/regserver/dnsregserver/dnsregserver_test.go @@ -4,14 +4,15 @@ import ( "encoding/binary" "encoding/hex" "fmt" + "io" "net" "testing" - "time" + "github.com/refraction-networking/conjure/pkg/log" "github.com/refraction-networking/conjure/pkg/metrics" "github.com/refraction-networking/conjure/pkg/regserver/regprocessor" pb "github.com/refraction-networking/conjure/proto" - log "github.com/sirupsen/logrus" + "google.golang.org/protobuf/proto" ) @@ -29,9 +30,10 @@ func init() { } func newDNSRegServer() DNSRegServer { + l := log.New(io.Discard, "", 0) return DNSRegServer{ - logger: log.New(), - metrics: metrics.NewMetrics(log.NewEntry(log.StandardLogger()), 5*time.Second), + logger: l, + metrics: metrics.NewMetrics(l, 5), } } diff --git a/pkg/regserver/regprocessor/regprocessor_test.go b/pkg/regserver/regprocessor/regprocessor_test.go index b5c2c6d8..ac2e9dc2 100644 --- a/pkg/regserver/regprocessor/regprocessor_test.go +++ b/pkg/regserver/regprocessor/regprocessor_test.go @@ -4,16 +4,17 @@ import ( "crypto/ed25519" "encoding/binary" "encoding/hex" + "io" "net" "sync" "testing" - "time" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" zmq "github.com/pebbe/zmq4" "github.com/refraction-networking/conjure/pkg/core/interfaces" + "github.com/refraction-networking/conjure/pkg/log" "github.com/refraction-networking/conjure/pkg/metrics" "github.com/refraction-networking/conjure/pkg/regserver/overrides" "github.com/refraction-networking/conjure/pkg/station/lib" @@ -21,7 +22,6 @@ import ( "github.com/refraction-networking/conjure/pkg/transports/wrapping/min" "github.com/refraction-networking/conjure/pkg/transports/wrapping/prefix" pb "github.com/refraction-networking/conjure/proto" - log "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" ) @@ -32,7 +32,7 @@ var ( func mockRegProcessor() RegProcessor { return RegProcessor{ - metrics: metrics.NewMetrics(log.NewEntry(log.StandardLogger()), 5*time.Second), + metrics: metrics.NewMetrics(log.New(io.Discard, "", 0), 5), } } diff --git a/pkg/station/lib/detector_channel.go b/pkg/station/lib/detector_channel.go index 02405623..2c5044f2 100644 --- a/pkg/station/lib/detector_channel.go +++ b/pkg/station/lib/detector_channel.go @@ -8,7 +8,7 @@ import ( "github.com/go-redis/redis/v8" - "github.com/refraction-networking/conjure/pkg/station/log" + "github.com/refraction-networking/conjure/pkg/log" ) var client *redis.Client diff --git a/pkg/station/lib/lib.go b/pkg/station/lib/lib.go new file mode 100644 index 00000000..f2f24a06 --- /dev/null +++ b/pkg/station/lib/lib.go @@ -0,0 +1,11 @@ +package lib + +import "github.com/refraction-networking/conjure/pkg/core/interfaces" + +type Transport interfaces.TransportSS + +type Registration interfaces.RegistrationSS + +type WrappingTransport interfaces.WrappingTransportSS + +type ConnectingTransport interfaces.ConnectingTransportSS diff --git a/pkg/station/lib/proxies.go b/pkg/station/lib/proxies.go index 9aee3f9b..c767db11 100644 --- a/pkg/station/lib/proxies.go +++ b/pkg/station/lib/proxies.go @@ -14,7 +14,7 @@ import ( "syscall" "time" - "github.com/refraction-networking/conjure/pkg/station/log" + "github.com/refraction-networking/conjure/pkg/log" ) const proxyStallTimeout = 30 * time.Second diff --git a/pkg/station/lib/proxies_test.go b/pkg/station/lib/proxies_test.go index 805d9ed3..de806307 100644 --- a/pkg/station/lib/proxies_test.go +++ b/pkg/station/lib/proxies_test.go @@ -18,7 +18,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/refraction-networking/conjure/pkg/station/log" + "github.com/refraction-networking/conjure/pkg/log" ) var errNotExist = errors.New("not implemented") diff --git a/pkg/station/lib/registration.go b/pkg/station/lib/registration.go index 5fbef6ba..4c942922 100644 --- a/pkg/station/lib/registration.go +++ b/pkg/station/lib/registration.go @@ -16,10 +16,10 @@ import ( "time" "github.com/refraction-networking/conjure/pkg/core" + "github.com/refraction-networking/conjure/pkg/core/interfaces" + "github.com/refraction-networking/conjure/pkg/log" "github.com/refraction-networking/conjure/pkg/station/geoip" "github.com/refraction-networking/conjure/pkg/station/liveness" - "github.com/refraction-networking/conjure/pkg/station/log" - "github.com/refraction-networking/conjure/pkg/transports" pb "github.com/refraction-networking/conjure/proto" "google.golang.org/protobuf/proto" @@ -29,10 +29,6 @@ import ( // send validated registrations over in order to notify all detector cores. const DETECTOR_REG_CHANNEL string = "dark_decoy_map" -// AES_GCM_TAG_SIZE the size of the aesgcm tag used when generating the client to -// station message. -const AES_GCM_TAG_SIZE = 16 - // RegistrationManager manages registration tracking for the station. type RegistrationManager struct { *RegConfig @@ -226,10 +222,10 @@ func (regManager *RegistrationManager) RegistrationExists(reg *DecoyRegistration } // GetRegistrations returns registrations associated with a specific phantom address. -func (regManager *RegistrationManager) GetRegistrations(phantomAddr net.IP) map[string]transports.Registration { +func (regManager *RegistrationManager) GetRegistrations(phantomAddr net.IP) map[string]interfaces.RegistrationSS { regs := regManager.registeredDecoys.getRegistrations(phantomAddr) - convertedRegs := make(map[string]transports.Registration) + convertedRegs := make(map[string]interfaces.RegistrationSS) for id, reg := range regs { convertedRegs[id] = reg } @@ -427,7 +423,7 @@ func (reg *DecoyRegistration) GenerateClientToStation() *pb.ClientToStation { Transport: ®.Transport, } - for (proto.Size(initProto)+AES_GCM_TAG_SIZE)%3 != 0 { + for (proto.Size(initProto)+core.AES_GCM_TAG_SIZE)%3 != 0 { initProto.Padding = append(initProto.Padding, byte(0)) } diff --git a/pkg/station/lib/registration_ingest.go b/pkg/station/lib/registration_ingest.go index 6a70fa40..c9881a29 100644 --- a/pkg/station/lib/registration_ingest.go +++ b/pkg/station/lib/registration_ingest.go @@ -14,8 +14,9 @@ import ( "google.golang.org/protobuf/types/known/anypb" "github.com/refraction-networking/conjure/pkg/core" + "github.com/refraction-networking/conjure/pkg/core/interfaces" + "github.com/refraction-networking/conjure/pkg/log" "github.com/refraction-networking/conjure/pkg/station/liveness" - "github.com/refraction-networking/conjure/pkg/station/log" pb "github.com/refraction-networking/conjure/proto" ) @@ -502,7 +503,7 @@ func handleConnectingTpReg(regManager *RegistrationManager, reg *DecoyRegistrati for tptype, tp := range regManager.GetConnectingTransports() { if tptype == reg.Transport { // correct transport name ctx, cancelFunc := context.WithTimeout(context.Background(), 15*time.Second) - go func(transport ConnectingTransport) { + go func(transport interfaces.ConnectingTransportSS) { defer cancelFunc() cc, err := regManager.GeoIP.CC(reg.registrationAddr) diff --git a/pkg/station/lib/registration_ingest_test.go b/pkg/station/lib/registration_ingest_test.go index f1712f65..557d4972 100644 --- a/pkg/station/lib/registration_ingest_test.go +++ b/pkg/station/lib/registration_ingest_test.go @@ -6,7 +6,7 @@ import ( "os" "testing" - "github.com/refraction-networking/conjure/pkg/station/log" + "github.com/refraction-networking/conjure/pkg/log" pb "github.com/refraction-networking/conjure/proto" "github.com/stretchr/testify/require" diff --git a/pkg/station/lib/registration_stats.go b/pkg/station/lib/registration_stats.go index edaebb39..bf02a7f2 100644 --- a/pkg/station/lib/registration_stats.go +++ b/pkg/station/lib/registration_stats.go @@ -6,7 +6,7 @@ import ( "sync/atomic" "time" - "github.com/refraction-networking/conjure/pkg/station/log" + "github.com/refraction-networking/conjure/pkg/log" pb "github.com/refraction-networking/conjure/proto" ) diff --git a/pkg/station/lib/stats.go b/pkg/station/lib/stats.go index 09526b8c..09d714de 100644 --- a/pkg/station/lib/stats.go +++ b/pkg/station/lib/stats.go @@ -8,7 +8,7 @@ import ( "sync/atomic" "time" - "github.com/refraction-networking/conjure/pkg/station/log" + "github.com/refraction-networking/conjure/pkg/log" pb "github.com/refraction-networking/conjure/proto" ) diff --git a/pkg/station/lib/transports_mock.go b/pkg/station/lib/transports_mock.go index a31fe3e0..6a717a1a 100644 --- a/pkg/station/lib/transports_mock.go +++ b/pkg/station/lib/transports_mock.go @@ -5,7 +5,7 @@ import ( "net" "github.com/refraction-networking/conjure/pkg/core" - "github.com/refraction-networking/conjure/pkg/transports" + "github.com/refraction-networking/conjure/pkg/core/interfaces" pb "github.com/refraction-networking/conjure/proto" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" @@ -24,7 +24,7 @@ type mockTransport struct { func (*mockTransport) Name() string { return "MockTransport" } func (*mockTransport) LogPrefix() string { return "MOCK" } -func (*mockTransport) GetIdentifier(d transports.Registration) string { +func (*mockTransport) GetIdentifier(d interfaces.RegistrationSS) string { return string(core.ConjureHMAC(d.SharedSecret(), "MockTransportHMACString")) } diff --git a/pkg/station/lib/zmq_proxy.go b/pkg/station/lib/zmq_proxy.go index 4d6ea305..921fabfd 100644 --- a/pkg/station/lib/zmq_proxy.go +++ b/pkg/station/lib/zmq_proxy.go @@ -13,7 +13,7 @@ import ( zmq "github.com/pebbe/zmq4" - "github.com/refraction-networking/conjure/pkg/station/log" + "github.com/refraction-networking/conjure/pkg/log" ) // ZMQConfig - Configuration options relevant to the ZMQ Proxy utility diff --git a/pkg/station/liveness/cached.go b/pkg/station/liveness/cached.go index 778883d6..ff91e491 100644 --- a/pkg/station/liveness/cached.go +++ b/pkg/station/liveness/cached.go @@ -8,7 +8,7 @@ import ( "sync/atomic" "time" - "github.com/refraction-networking/conjure/pkg/station/log" + "github.com/refraction-networking/conjure/pkg/log" ) // CachedLivenessTester implements LivenessTester interface with caching, diff --git a/pkg/station/liveness/liveness.go b/pkg/station/liveness/liveness.go index 1750eb89..d890f333 100644 --- a/pkg/station/liveness/liveness.go +++ b/pkg/station/liveness/liveness.go @@ -8,7 +8,7 @@ import ( "sync/atomic" "time" - "github.com/refraction-networking/conjure/pkg/station/log" + "github.com/refraction-networking/conjure/pkg/log" ) // ErrCachedPhantom provides a constant expected error returned for cached diff --git a/pkg/transports/client/transports.go b/pkg/transports/client/transports.go index ded6d0e5..c4d5fa7f 100644 --- a/pkg/transports/client/transports.go +++ b/pkg/transports/client/transports.go @@ -129,13 +129,18 @@ func init() { } } -func ConfigFromTransportType(transportType pb.TransportType, randomizePortDefault bool) (cj.Transport, error) { - switch transportType { - case pb.TransportType_Min: - return &min.ClientTransport{Parameters: &pb.GenericTransportParams{RandomizeDstPort: &randomizePortDefault}}, nil - case pb.TransportType_Obfs4: - return &obfs4.ClientTransport{Parameters: &pb.GenericTransportParams{RandomizeDstPort: &randomizePortDefault}}, nil - default: - return nil, errors.New("unknown transport by TransportType try using TransportConfig") - } -} +// func ConfigFromTransportType(transportType pb.TransportType, randomizePortDefault bool) (cj.Transport, error) { +// switch transportType { +// case pb.TransportType_Min: +// return &min.ClientTransport{Parameters: &pb.GenericTransportParams{RandomizeDstPort: &randomizePortDefault}}, nil +// case pb.TransportType_Obfs4: +// return &obfs4.ClientTransport{Parameters: &pb.GenericTransportParams{RandomizeDstPort: &randomizePortDefault}}, nil +// case pb.TransportType_Prefix: +// p := &prefix.ClientTransport{} +// var id int32 = -1 +// err := p.SetParams(&pb.PrefixTransportParams{RandomizeDstPort: &randomizePortDefault, PrefixId: &id}) +// return p, err +// default: +// return nil, errors.New("unknown transport by TransportType try using TransportConfig") +// } +// } diff --git a/pkg/transports/connecting/dtls/dtls.go b/pkg/transports/connecting/dtls/dtls.go index b4b671a5..40da6563 100644 --- a/pkg/transports/connecting/dtls/dtls.go +++ b/pkg/transports/connecting/dtls/dtls.go @@ -35,7 +35,7 @@ func (Transport) LogPrefix() string { } // GetIdentifier returns an identifier unique a registration -func (Transport) GetIdentifier(reg transports.Registration) string { +func (Transport) GetIdentifier(reg interfaces.RegistrationSS) string { return string(core.ConjureHMAC(reg.SharedSecret(), "dtlsTrasportHMACString")) } @@ -62,8 +62,8 @@ func NewTransport(logAuthFail func(*net.IP), logOtherFail func(*net.IP), logDial }, nil } -// Connect takes a registraion and returns a dtls Conn connected to the client -func (t *Transport) Connect(ctx context.Context, reg transports.Registration) (net.Conn, error) { +// Connect takes a registration and returns a dtls Conn connected to the client +func (t *Transport) Connect(ctx context.Context, reg interfaces.RegistrationSS) (net.Conn, error) { if reg.TransportType() != pb.TransportType_DTLS { return nil, transports.ErrNotTransport } diff --git a/pkg/transports/registration.go b/pkg/transports/registration.go deleted file mode 100644 index 09699164..00000000 --- a/pkg/transports/registration.go +++ /dev/null @@ -1,28 +0,0 @@ -package transports - -import ( - "io" - "net" - - pb "github.com/refraction-networking/conjure/proto" -) - -// Registration provides an abstraction around station tracked registrations. -type Registration interface { - SharedSecret() []byte - GetRegistrationAddress() string - GetDstPort() uint16 - PhantomIP() *net.IP - - // Transport management functions - TransportType() pb.TransportType - TransportParams() any - SetTransportKeys(interface{}) error - TransportKeys() interface{} - TransportReader() io.Reader -} - -// RegManager provides an abstraction for the RegistrationManager which tracks registrations. -type RegManager interface { - GetRegistrations(phantomAddr net.IP) map[string]Registration -} diff --git a/pkg/transports/wrapping/min/min.go b/pkg/transports/wrapping/min/min.go index 68193bfa..0b36ed83 100644 --- a/pkg/transports/wrapping/min/min.go +++ b/pkg/transports/wrapping/min/min.go @@ -6,6 +6,7 @@ import ( "net" core "github.com/refraction-networking/conjure/pkg/core" + "github.com/refraction-networking/conjure/pkg/core/interfaces" "github.com/refraction-networking/conjure/pkg/transports" pb "github.com/refraction-networking/conjure/proto" "google.golang.org/protobuf/types/known/anypb" @@ -43,7 +44,7 @@ func (Transport) LogPrefix() string { return "MIN" } // GetIdentifier takes in a registration and returns an identifier for it. This // identifier should be unique for each registration on a given phantom; // registrations on different phantoms can have the same identifier. -func (Transport) GetIdentifier(d transports.Registration) string { +func (Transport) GetIdentifier(d interfaces.RegistrationSS) string { return string(core.ConjureHMAC(d.SharedSecret(), hmacString)) } @@ -87,7 +88,7 @@ func (t Transport) ParamStrings(p any) []string { // // If the returned error is nil or non-nil and non-{ transports.ErrTryAgain, // transports.ErrNotTransport }, the caller may no longer use data or conn. -func (Transport) WrapConnection(data *bytes.Buffer, c net.Conn, originalDst net.IP, regManager transports.RegManager) (transports.Registration, net.Conn, error) { +func (Transport) WrapConnection(data *bytes.Buffer, c net.Conn, originalDst net.IP, regManager interfaces.RegManager) (interfaces.RegistrationSS, net.Conn, error) { if data.Len() < minTagLength { return nil, nil, transports.ErrTryAgain } diff --git a/pkg/transports/wrapping/obfs4/obfs4.go b/pkg/transports/wrapping/obfs4/obfs4.go index a5da39d0..dac7b920 100644 --- a/pkg/transports/wrapping/obfs4/obfs4.go +++ b/pkg/transports/wrapping/obfs4/obfs4.go @@ -5,6 +5,7 @@ import ( "fmt" "net" + "github.com/refraction-networking/conjure/pkg/core/interfaces" "github.com/refraction-networking/conjure/pkg/transports" pb "github.com/refraction-networking/conjure/proto" "github.com/refraction-networking/obfs4/common/drbg" @@ -34,7 +35,7 @@ func (Transport) Name() string { return "obfs4" } func (Transport) LogPrefix() string { return "OBFS4" } // GetIdentifier implements the station Transport interface -func (Transport) GetIdentifier(r transports.Registration) string { +func (Transport) GetIdentifier(r interfaces.RegistrationSS) string { if r == nil { return "" } else if r.TransportKeys() == nil { @@ -88,7 +89,7 @@ func (t Transport) ParamStrings(p any) []string { } // WrapConnection implements the station Transport interface -func (Transport) WrapConnection(data *bytes.Buffer, c net.Conn, phantom net.IP, regManager transports.RegManager) (transports.Registration, net.Conn, error) { +func (Transport) WrapConnection(data *bytes.Buffer, c net.Conn, phantom net.IP, regManager interfaces.RegManager) (interfaces.RegistrationSS, net.Conn, error) { if data.Len() < ClientMinHandshakeLength { return nil, nil, transports.ErrTryAgain } @@ -158,10 +159,10 @@ func (Transport) WrapConnection(data *bytes.Buffer, c net.Conn, phantom net.IP, // This function makes the assumption that any identifier with length 52 is an obfs4 registration. // This may not be strictly true, but any other identifier will simply fail to form a connection and // should be harmless. -func getObfs4Registrations(regManager transports.RegManager, darkDecoyAddr net.IP) []transports.Registration { - var regs []transports.Registration +func getObfs4Registrations(regManager interfaces.RegManager, phantomAddr net.IP) []interfaces.RegistrationSS { + var regs []interfaces.RegistrationSS - for identifier, r := range regManager.GetRegistrations(darkDecoyAddr) { + for identifier, r := range regManager.GetRegistrations(phantomAddr) { if len(identifier) == ntor.PublicKeyLength+ntor.NodeIDLength { regs = append(regs, r) } @@ -194,29 +195,3 @@ func (Transport) GetDstPort(libVersion uint, seed []byte, params any) (uint16, e return 443, nil } - -// func generateObfs4Keys(rand io.Reader) (core.Obfs4Keys, error) { -// keys := Obfs4Keys{ -// PrivateKey: new(ntor.PrivateKey), -// PublicKey: new(ntor.PublicKey), -// NodeID: new(ntor.NodeID), -// } - -// _, err := rand.Read(keys.PrivateKey[:]) -// if err != nil { -// return keys, err -// } - -// keys.PrivateKey[0] &= 248 -// keys.PrivateKey[31] &= 127 -// keys.PrivateKey[31] |= 64 - -// pub, err := curve25519.X25519(keys.PrivateKey[:], curve25519.Basepoint) -// if err != nil { -// return keys, err -// } -// copy(keys.PublicKey[:], pub) - -// _, err = rand.Read(keys.NodeID[:]) -// return keys, err -// } diff --git a/pkg/transports/wrapping/prefix/prefix.go b/pkg/transports/wrapping/prefix/prefix.go index 414153d5..b2d60bf1 100644 --- a/pkg/transports/wrapping/prefix/prefix.go +++ b/pkg/transports/wrapping/prefix/prefix.go @@ -7,6 +7,7 @@ import ( "net" "github.com/refraction-networking/conjure/pkg/core" + "github.com/refraction-networking/conjure/pkg/core/interfaces" "github.com/refraction-networking/conjure/pkg/transports" pb "github.com/refraction-networking/conjure/proto" "google.golang.org/protobuf/types/known/anypb" @@ -184,7 +185,7 @@ func (Transport) LogPrefix() string { return "PREF" } // GetIdentifier takes in a registration and returns an identifier for it. This // identifier should be unique for each registration on a given phantom; // registrations on different phantoms can have the same identifier. -func (Transport) GetIdentifier(d transports.Registration) string { +func (Transport) GetIdentifier(d interfaces.RegistrationSS) string { return string(core.ConjureHMAC(d.SharedSecret(), "PrefixTransportHMACString")) } @@ -268,7 +269,7 @@ func (t Transport) GetDstPort(libVersion uint, seed []byte, params any) (uint16, // // If the returned error is nil or non-nil and non-{ transports.ErrTryAgain, // transports.ErrNotTransport }, the caller may no longer use data or conn. -func (t Transport) WrapConnection(data *bytes.Buffer, c net.Conn, originalDst net.IP, regManager transports.RegManager) (transports.Registration, net.Conn, error) { +func (t Transport) WrapConnection(data *bytes.Buffer, c net.Conn, originalDst net.IP, regManager interfaces.RegManager) (interfaces.RegistrationSS, net.Conn, error) { if data.Len() < minTagLength { return nil, nil, transports.ErrTryAgain } @@ -281,7 +282,7 @@ func (t Transport) WrapConnection(data *bytes.Buffer, c net.Conn, originalDst ne return reg, transports.PrependToConn(c, data), nil } -func (t Transport) tryFindReg(data *bytes.Buffer, originalDst net.IP, regManager transports.RegManager) (transports.Registration, error) { +func (t Transport) tryFindReg(data *bytes.Buffer, originalDst net.IP, regManager interfaces.RegManager) (interfaces.RegistrationSS, error) { if data.Len() == 0 { return nil, transports.ErrTryAgain }