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/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..22663c86 100644 --- a/cmd/application/main.go +++ b/cmd/application/main.go @@ -6,15 +6,11 @@ import ( "net" "os" "os/signal" - "strconv" - "sync" "syscall" - "time" - "github.com/refraction-networking/conjure/pkg/dtls/dnat" + "github.com/refraction-networking/conjure/pkg/log" + "github.com/refraction-networking/conjure/pkg/station" 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" "github.com/refraction-networking/conjure/pkg/transports/wrapping/prefix" @@ -22,7 +18,6 @@ import ( ) var sharedLogger *log.Logger -var logClientIP = false var enabledTransports = map[pb.TransportType]cj.Transport{ pb.TransportType_Min: min.Transport{}, @@ -38,9 +33,10 @@ func main() { // Init stats cj.Stat() + logger := log.New(os.Stdout, "", 0) // parse toml station configuration - conf, err := cj.ParseConfig() + conf, err := station.ConfigFromEnv() if err != nil { log.Fatalf("failed to parse app config: %v", err) } @@ -56,110 +52,20 @@ func main() { } log.SetLevel(logLevel) - connManager := newConnManager(nil) + ctx := context.Background() - conf.RegConfig.ConnectingStats = connManager - - regManager := cj.NewRegistrationManager(conf.RegConfig) - - logIPDTLS := func(logger func(asn uint, cc, tp string)) func(*net.IP) { - return func(ip *net.IP) { - cc, err := regManager.GeoIP.CC(*ip) - if err != nil { - return - } - - var asn uint = 0 - if cc != "unk" { - asn, err = regManager.GeoIP.ASN(*ip) - if err != nil { - return - } - } - - logger(asn, cc, "dtls") - } - } - - dtlsbuilder := dnat.NewDNAT - dtlsTransport, err := dtls.NewTransport(logIPDTLS(connManager.AddAuthFailConnecting), logIPDTLS(connManager.AddOtherFailConnecting), logIPDTLS(connManager.AddCreatedToDialSuccessfulConnecting), logIPDTLS(connManager.AddCreatedToListenSuccessfulConnecting), dtlsbuilder) - - if err != nil { - log.Fatalf("failed to setup dtls: %v", err) - } - enabledTransports[pb.TransportType_DTLS] = dtlsTransport - - sharedLogger = regManager.Logger - logger := sharedLogger - defer regManager.Cleanup() - - // Should we log client IP addresses - logClientIP, err = strconv.ParseBool(os.Getenv("LOG_CLIENT_IP")) + cjStation, err := station.New(ctx, conf) if err != nil { - logger.Errorf("failed parse client ip logging setting: %v\n", err) - logClientIP = false - } - - privkey, err := conf.ParsePrivateKey() - if err != nil { - logger.Fatalf("error parseing private key: %s", err) - } - - var prefixTransport cj.Transport - if conf.DisableDefaultPrefixes { - prefixTransport, err = prefix.New(privkey, conf.PrefixFilePath) - } else { - prefixTransport, err = prefix.Default(privkey, conf.PrefixFilePath) - } - if err != nil { - logger.Errorf("Failed to parse provided custom prefix transport file: %s", err) - } else { - enabledTransports[pb.TransportType_Prefix] = prefixTransport - } - - // Add supported transport options for registration validation - for transportType, transport := range enabledTransports { - err = regManager.AddTransport(transportType, transport) - if err != nil { - logger.Errorf("failed to add transport: %v", err) - } + log.Fatalf("failed to create station: %v", err) } + defer func() { + cjStation.Shutdown() + logger.Infof("shutdown complete") + }() ctx, cancel := context.WithCancel(context.Background()) - wg := new(sync.WaitGroup) - regChan := make(chan interface{}, 10000) - zmqIngester, err := cj.NewZMQIngest(zmqAddress, regChan, privkey, conf.ZMQConfig) - if err != nil { - logger.Fatal("error creating ZMQ Ingest: %w", err) - } - cj.Stat().AddStatsModule(zmqIngester, false) - cj.Stat().AddStatsModule(regManager.LivenessTester, false) - cj.Stat().AddStatsModule(cj.GetProxyStats(), false) - cj.Stat().AddStatsModule(regManager, false) - cj.Stat().AddStatsModule(connManager, true) - - // Periodically clean old registrations - wg.Add(1) - go func(ctx context.Context, wg *sync.WaitGroup) { - defer wg.Done() - - ticker := time.NewTicker(3 * time.Minute) - for { - select { - case <-ticker.C: - regManager.RemoveOldRegistrations() - case <-ctx.Done(): - return - } - } - }(ctx, wg) - - // Receive registration updates from ZMQ Proxy as subscriber - go zmqIngester.RunZMQ(ctx) - wg.Add(1) - go regManager.HandleRegUpdates(ctx, regChan, wg) - go connManager.acceptConnections(ctx, regManager, logger) + go acceptConnections(ctx, cjStation, logger) sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP) @@ -175,15 +81,45 @@ func main() { // parse toml station configuration. If parse fails, log and abort // reload. - newConf, err := cj.ParseConfig() + newConf, err := station.ConfigFromEnv() if err != nil { log.Errorf("failed to parse app config: %v", err) } else { - regManager.OnReload(newConf.RegConfig) + cjStation.OnReload(newConf.RegConfig) } } cancel() - wg.Wait() - logger.Infof("shutdown complete") +} + +func acceptConnections(ctx context.Context, cjStation *station.Station, logger *log.Logger) { + + // listen for and handle incoming proxy traffic + listenAddr := &net.TCPAddr{IP: nil, Port: 41245, Zone: ""} + ln := cjStation.Listen(listenAddr) + if ln == nil { + logger.Fatalf("failed to listen on %v: %v\n", listenAddr) + } + defer ln.Close() + logger.Infof("[STARTUP] Listening on %v\n", ln.Addr()) + + for { + select { + case <-ctx.Done(): + break + default: + newConn, err := ln.Accept() + if err != nil { + logger.Errorf("[ERROR] failed to AcceptTCP on %v: %v\n", ln.Addr(), err) + continue + } + go func(conn net.Conn) { + defer conn.Close() + err := cjStation.ForwardProxy(conn) + if err != nil { + logger.Errorf("[ERROR] failed while proxying: %v\n", err) + } + }(newConn) + } + } } diff --git a/cmd/application/main_old.go b/cmd/application/main_old.go new file mode 100644 index 00000000..b75cebf3 --- /dev/null +++ b/cmd/application/main_old.go @@ -0,0 +1,216 @@ +package main + +import ( + "context" + "flag" + "net" + "os" + "os/signal" + "strconv" + "sync" + "syscall" + "time" + + "github.com/refraction-networking/conjure/pkg/dtls/dnat" + "github.com/refraction-networking/conjure/pkg/log" + "github.com/refraction-networking/conjure/pkg/station" + "github.com/refraction-networking/conjure/pkg/station/connection" + cj "github.com/refraction-networking/conjure/pkg/station/lib" + "github.com/refraction-networking/conjure/pkg/transports/wrapping/min" + "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" +) + +var sharedLogger *log.Logger +var logClientIP = false + +var enabledTransports = map[pb.TransportType]cj.Transport{ + pb.TransportType_Min: min.Transport{}, + pb.TransportType_Obfs4: obfs4.Transport{}, + pb.TransportType_Prefix: prefix.Transport{}, +} + +func main() { + var err error + var zmqAddress string + flag.StringVar(&zmqAddress, "zmq-address", "ipc://@zmq-proxy", "Address of ZMQ proxy") + flag.Parse() + + // Init stats + cj.Stat() + + // parse toml station configuration + conf, err := station.ConfigFromEnv() + if err != nil { + log.Fatalf("failed to parse app config: %v", err) + } + + // parse & set log level for the lib for which sets the default level all + // loggers created by subroutines routines. + var logLevel = log.ErrorLevel + if conf.LogLevel != "" { + logLevel, err = log.ParseLevel(conf.LogLevel) + if err != nil || logLevel == log.UnknownLevel { + log.Fatal(err) + } + } + log.SetLevel(logLevel) + + connManager := connection.NewConnManager(nil) + + conf.RegConfig.ConnectingStats = connManager + + regManager := cj.NewRegistrationManager(conf.RegConfig) + + logIPDTLS := func(logger func(asn uint, cc, tp string)) func(*net.IP) { + return func(ip *net.IP) { + cc, err := regManager.GeoIP.CC(*ip) + if err != nil { + return + } + + var asn uint = 0 + if cc != "unk" { + asn, err = regManager.GeoIP.ASN(*ip) + if err != nil { + return + } + } + + logger(asn, cc, "dtls") + } + } + + dtlsbuilder := dnat.NewDNAT + dtlsTransport, err := connManager.BuildDTLSTransport(dtlsbuilder, logIPDTLS) + + if err != nil { + log.Fatalf("failed to setup dtls: %v", err) + } + enabledTransports[pb.TransportType_DTLS] = dtlsTransport + + sharedLogger = regManager.Logger + logger := sharedLogger + defer regManager.Cleanup() + + // Should we log client IP addresses + logClientIP, err = strconv.ParseBool(os.Getenv("LOG_CLIENT_IP")) + if err != nil { + logger.Errorf("failed parse client ip logging setting: %v\n", err) + logClientIP = false + } + + privkey, err := conf.ParsePrivateKey() + if err != nil { + logger.Fatalf("error parseing private key: %s", err) + } + + var prefixTransport cj.Transport + if conf.DisableDefaultPrefixes { + prefixTransport, err = prefix.New(privkey, conf.PrefixFilePath) + } else { + prefixTransport, err = prefix.Default(privkey, conf.PrefixFilePath) + } + if err != nil { + logger.Errorf("Failed to parse provided custom prefix transport file: %s", err) + } else { + enabledTransports[pb.TransportType_Prefix] = prefixTransport + } + + // Add supported transport options for registration validation + for transportType, transport := range enabledTransports { + err = regManager.AddTransport(transportType, transport) + if err != nil { + logger.Errorf("failed to add transport: %v", err) + } + } + + ctx, cancel := context.WithCancel(context.Background()) + wg := new(sync.WaitGroup) + regChan := make(chan interface{}, 10000) + zmqIngester, err := cj.NewZMQIngest(zmqAddress, regChan, privkey, conf.ZMQConfig) + if err != nil { + logger.Fatal("error creating ZMQ Ingest: %w", err) + } + + cj.Stat().AddStatsModule(zmqIngester, false) + cj.Stat().AddStatsModule(regManager.LivenessTester, false) + cj.Stat().AddStatsModule(cj.GetProxyStats(), false) + cj.Stat().AddStatsModule(regManager, false) + cj.Stat().AddStatsModule(connManager, true) + + // Periodically clean old registrations + wg.Add(1) + go func(ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() + + ticker := time.NewTicker(3 * time.Minute) + for { + select { + case <-ticker.C: + regManager.RemoveOldRegistrations() + case <-ctx.Done(): + return + } + } + }(ctx, wg) + + // Receive registration updates from ZMQ Proxy as subscriber + go zmqIngester.RunZMQ(ctx) + wg.Add(1) + go regManager.HandleRegUpdates(ctx, regChan, wg) + go acceptConnections(ctx, regManager, logger) + + sigCh := make(chan os.Signal, 1) + signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP) + for sig := range sigCh { + // Wait for close signal. + if sig != syscall.SIGHUP { + logger.Infof("received %s ... exiting\n", sig.String()) + break + } + + // Use SigHUP to indicate config reload + logger.Infoln("received SIGHUP ... reloading configs") + + // parse toml station configuration. If parse fails, log and abort + // reload. + newConf, err := station.ConfigFromEnv() + if err != nil { + log.Errorf("failed to parse app config: %v", err) + } else { + regManager.OnReload(newConf.RegConfig) + } + } + + cancel() + wg.Wait() + logger.Infof("shutdown complete") +} + +// func acceptConnections(ctx context.Context, rm *lib.RegistrationManager, logger *log.Logger) { + +// // listen for and handle incoming proxy traffic +// listenAddr := &net.TCPAddr{IP: nil, Port: 41245, Zone: ""} +// ln, err := net.ListenTCP("tcp", listenAddr) +// if err != nil { +// logger.Fatalf("failed to listen on %v: %v\n", listenAddr, err) +// } +// defer ln.Close() +// logger.Infof("[STARTUP] Listening on %v\n", ln.Addr()) + +// for { +// select { +// case <-ctx.Done(): +// break +// default: +// newConn, err := ln.AcceptTCP() +// if err != nil { +// logger.Errorf("[ERROR] failed to AcceptTCP on %v: %v\n", ln.Addr(), err) +// continue +// } +// go cm.handleNewConn(rm, newConn) +// } +// } +// } 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 308ad342..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 ) diff --git a/go.sum b/go.sum index 182d55ef..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.1 h1:yvu+IV2Uf+HKgvoNZVXvEG3q6g6oxYUKK/JGElDFsnA= -github.com/refraction-networking/gotapdance v1.7.1/go.mod h1:Yr51OnDzdkf9gbBxQe7F647sgbGph6UbOsFrpxnT7Tk= 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 7d757ab7..f962b607 100644 --- a/go.work.sum +++ b/go.work.sum @@ -38,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= @@ -59,5 +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/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/pkg/transports/wrapping/internal/tests/phantom_subnets.toml b/internal/test_assets/phantom_subnets.toml similarity index 100% rename from pkg/transports/wrapping/internal/tests/phantom_subnets.toml rename to internal/test_assets/phantom_subnets.toml diff --git a/pkg/transports/wrapping/internal/tests/phantom_subnets_min.toml b/internal/test_assets/phantom_subnets_min.toml similarity index 100% rename from pkg/transports/wrapping/internal/tests/phantom_subnets_min.toml rename to internal/test_assets/phantom_subnets_min.toml diff --git a/pkg/transports/wrapping/internal/tests/tests.go b/internal/testutils/tests.go similarity index 93% rename from pkg/transports/wrapping/internal/tests/tests.go rename to internal/testutils/tests.go index f6b57b5b..961226a4 100644 --- a/pkg/transports/wrapping/internal/tests/tests.go +++ b/internal/testutils/tests.go @@ -1,4 +1,4 @@ -package tests +package testutils import ( "log" @@ -6,6 +6,7 @@ import ( "os" "sync" + "github.com/refraction-networking/conjure/internal/conjurepath" "github.com/refraction-networking/conjure/pkg/core" dd "github.com/refraction-networking/conjure/pkg/station/lib" pb "github.com/refraction-networking/conjure/proto" @@ -20,14 +21,12 @@ type Transport struct { } var SharedSecret = []byte(`6a328b8ec2024dd92dd64332164cc0425ddbde40cb7b81e055bf7b099096d068`) +var TestSubnetPath = conjurepath.Root + "/internal/test_assets/phantom_subnets.toml" // SetupPhantomConnections registers one session with the provided transport and // registration manager using a pre-determined kay and phantom subnet file. func SetupPhantomConnections(manager *dd.RegistrationManager, transport pb.TransportType, params protoreflect.ProtoMessage, libver uint) (clientToPhantom net.Conn, serverFromPhantom net.Conn, reg *dd.DecoyRegistration) { - cwd, _ := os.Getwd() - testSubnetPath := cwd + "/../internal/tests/phantom_subnets.toml" - - return SetupPhantomConnectionsSecret(manager, transport, params, SharedSecret, libver, testSubnetPath) + return SetupPhantomConnectionsSecret(manager, transport, params, SharedSecret, libver, TestSubnetPath) } func SetupPhantomConnectionsSecret(manager *dd.RegistrationManager, transport pb.TransportType, params protoreflect.ProtoMessage, sharedSecret []byte, libver uint, testSubnetPath string) (clientToPhantom net.Conn, serverFromPhantom net.Conn, reg *dd.DecoyRegistration) { diff --git a/internal/transport_integration_test.go b/internal/transport_integration_test.go new file mode 100644 index 00000000..d8712d06 --- /dev/null +++ b/internal/transport_integration_test.go @@ -0,0 +1,244 @@ +package integration_test + +import ( + "bytes" + "crypto/rand" + "errors" + "flag" + "fmt" + "io" + "net" + "os" + "testing" + "time" + + "github.com/refraction-networking/conjure/internal/conjurepath" + "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/transports" + "github.com/refraction-networking/conjure/pkg/transports/wrapping/min" + "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" + "github.com/refraction-networking/ed25519" + "github.com/refraction-networking/ed25519/extra25519" + + "github.com/stretchr/testify/require" + "golang.org/x/crypto/curve25519" +) + +var ( + debug = flag.Bool("debug", false, "enable debug logging") + _true bool = true + _false bool = false +) + +type TestParams interface { + // GetParams returns the protobuf representation of the parameters + GetParams() any + String() string +} + +type stationBuilder = func([32]byte) lib.WrappingTransport + +func TestTransportsEndToEnd(t *testing.T) { + if *debug { + log.SetLevel(log.DebugLevel) + } + testCases := []struct { + stationTransportBuilder stationBuilder + clientTransport interfaces.WrappingTransport + clientParamPermuteGenerator func() []TestParams + }{ + { + func(privKey [32]byte) lib.WrappingTransport { + tr, err := prefix.Default(privKey) + require.Nil(t, err) + return tr + }, + &prefix.ClientTransport{}, + prefixClientParamPermutations, + }, + { + func(privKey [32]byte) lib.WrappingTransport { + return &obfs4.Transport{} + }, + &obfs4.ClientTransport{}, + genericParamPermutations, + }, + { + func(privKey [32]byte) lib.WrappingTransport { + return &min.Transport{} + }, + &min.ClientTransport{}, + genericParamPermutations, + }, + } + for _, testCase := range testCases { + t.Run(testCase.clientTransport.Name(), func(t *testing.T) { + testTransportsEndToEnd(t, testCase.stationTransportBuilder, testCase.clientTransport, testCase.clientParamPermuteGenerator) + }) + } +} + +// Test End to End client WrapConn to Server WrapConnection +func testTransportsEndToEnd(t *testing.T, builder stationBuilder, clientTransport interfaces.WrappingTransport, clientParamPermuteGenerator func() []TestParams) { + testSubnetPath := conjurepath.Root + "/pkg/station/lib/test/phantom_subnets.toml" + os.Setenv("PHANTOM_SUBNET_LOCATION", testSubnetPath) + + _, private, _ := ed25519.GenerateKey(rand.Reader) + + var curve25519Public, curve25519Private [32]byte + extra25519.PrivateKeyToCurve25519(&curve25519Private, private) + curve25519.ScalarBaseMult(&curve25519Public, &curve25519Private) + + message := []byte(`test message!`) + + transport := builder(curve25519Private) + + // Ensure that we test all given parameter permutations as well as nil params + // paramSet := append([]any{nil}, clientParamPermuteGenerator()) + paramSet := append([]TestParams{nil}, clientParamPermuteGenerator()...) + + // for _, flushPolicy := range []int32{DefaultFlush, NoAddedFlush, FlushAfterPrefix} { + // for idx := range defaultPrefixes { + for _, testParams := range paramSet { + + if testParams == nil { + testParams = &nilParams{} + } + params := testParams.GetParams() + clientKeys, err := core.GenerateClientSharedKeys(curve25519Public) + require.Nil(t, err) + + err = clientTransport.SetParams(params) + require.Nil(t, err) + protoParams, err := clientTransport.GetParams() + require.Nil(t, err) + t.Logf("running %s w/ %s", clientTransport.Name(), testParams.String()) + + manager := testutils.SetupRegistrationManager(testutils.Transport{Index: pb.TransportType_Prefix, Transport: transport}) + require.NotNil(t, manager) + c2p, sfp, serverReg := testutils.SetupPhantomConnectionsSecret(manager, pb.TransportType_Prefix, protoParams, clientKeys.SharedSecret, uint(core.CurrentClientLibraryVersion()), testutils.TestSubnetPath) + defer c2p.Close() + defer sfp.Close() + require.NotNil(t, serverReg) + sch := make(chan struct{}, 1) + go func() { + + var c net.Conn + var err error + var buf [10240]byte + received := bytes.Buffer{} + sch <- struct{}{} + + for { + n, err := sfp.Read(buf[:]) + if err != nil { + t.Errorf("error reading from server connection after %d bytes %s", n, err) + t.Fail() + return + } + + received.Write(buf[:n]) + _, c, err = transport.WrapConnection(&received, sfp, serverReg.PhantomIp, manager) + if err == nil { + break + } else if !errors.Is(err, transports.ErrTryAgain) { + if prm, ok := params.(*prefix.ClientParams); ok { + t.Errorf("error getting wrapped connection %s - expected %s, %d", err, prefix.PrefixID(prm.PrefixID).Name(), prm.FlushPolicy) + } else if prm, ok := params.(*pb.PrefixTransportParams); ok { + t.Errorf("error getting wrapped connection %s - expected %s, %d", err, prefix.PrefixID(prm.GetPrefixId()).Name(), prm.GetCustomFlushPolicy()) + } else { + t.Errorf("error getting wrapped connection %s", err) + } + t.Fail() + return + } + } + + recvBuf := make([]byte, len(message)) + _, err = io.ReadFull(c, recvBuf) + require.Nil(t, err, "failed reading from server connection") + _, err = c.Write(recvBuf) + require.Nil(t, err, "failed writing to server connection") + }() + + <-sch + clientErr := clientTransport.PrepareKeys(curve25519Public, serverReg.Keys.SharedSecret, clientKeys.Reader) + require.Nil(t, clientErr) + + clientErr = c2p.SetDeadline(time.Now().Add(15 * time.Second)) + require.Nil(t, clientErr) + + clientConn, clientErr := clientTransport.WrapConn(c2p) + require.Nil(t, clientErr, "error getting wrapped connection") + require.NotNil(t, clientConn, "returned client wrapped connection nil") + + _, clientErr = clientConn.Write(message) + require.Nil(t, clientErr, "failed writing to client connection") + + cbuf := make([]byte, len(message)) + _, clientErr = io.ReadFull(clientConn, cbuf) + require.Nil(t, clientErr, "failed reading from client connection") + require.True(t, bytes.Equal(message, cbuf), "%s\n%s", string(message), string(cbuf)) + } +} + +func genericParamPermutations() []TestParams { + return []TestParams{ + &genericParams{ + &pb.GenericTransportParams{ + RandomizeDstPort: &_true, + }}, + &genericParams{ + &pb.GenericTransportParams{ + RandomizeDstPort: &_false, + }}, + } +} + +type nilParams struct{} + +func (p *nilParams) GetParams() any { + return nil +} + +func (p *nilParams) String() string { + return "nil" +} + +type genericParams struct { + *pb.GenericTransportParams +} + +func (p *genericParams) GetParams() any { + return p.GenericTransportParams +} + +func (p *genericParams) String() string { + return fmt.Sprintf("randDstPort: %t", p.GetRandomizeDstPort()) +} + +// ClientParamPermutations returns a list of client parameters for inclusions in tests that require +// variance. +func prefixClientParamPermutations() []TestParams { + paramSet := []TestParams{} + for _, flushPolicy := range []int32{prefix.DefaultFlush, prefix.NoAddedFlush, prefix.FlushAfterPrefix} { + for idx := prefix.Rand; idx <= prefix.OpenSSH2; idx++ { + for _, rand := range []bool{true, false} { + var p int32 = int32(idx) + params := &prefix.ClientParams{ + PrefixID: p, + RandomizeDstPort: rand, + FlushPolicy: flushPolicy, + } + paramSet = append(paramSet, params) + } + } + } + return paramSet +} 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 5621ace8..1819bee3 100644 --- a/pkg/core/interfaces/interfaces.go +++ b/pkg/core/interfaces/interfaces.go @@ -5,12 +5,25 @@ import ( "io" "net" + "github.com/refraction-networking/conjure/pkg/log" pb "github.com/refraction-networking/conjure/proto" + "google.golang.org/protobuf/proto" "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. @@ -41,7 +54,7 @@ type Transport interface { // Prepare lets the transport use the dialer to prepare. This is called before GetParams to let the // transport prepare stuff such as nat traversal. - Prepare(dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) error + Prepare(ctx context.Context, dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) error // GetDstPort returns the destination port that the client should open the phantom connection with. GetDstPort(seed []byte) (uint16, error) @@ -52,6 +65,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 +74,35 @@ 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 +// ConnectingTpStats is an interface for tracking statistics about the connecting transports +type ConnectingTpStats interface { + AddCreatedConnecting(asn uint, cc string, tp string) + AddCreatedToSuccessfulConnecting(asn uint, cc string, tp string) + AddCreatedToTimeoutConnecting(asn uint, cc string, tp string) + AddSuccessfulToDiscardedConnecting(asn uint, cc string, tp string) + AddOtherFailConnecting(asn uint, cc string, tp string) } -// 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 -} +type Stats interface { + // PrintAndReset is intended to allow each stats module to summarize metrics + // from the current epoch out through the logger and then reset any stats + // that need reset as the start of a new epoch. + PrintAndReset(logger *log.Logger) -// 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 + Reset() } -// 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 2791f50e..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,18 +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) +} - // GetSrcPort reads client source port from transport parameters - GetSrcPort(libVersion uint, seed []byte, parameters any) (uint16, 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/dtls/dnat/dnat.go b/pkg/dtls/dnat/dnat.go index 6d56edcb..3dab3e26 100644 --- a/pkg/dtls/dnat/dnat.go +++ b/pkg/dtls/dnat/dnat.go @@ -103,13 +103,32 @@ type dnat struct { } func (d *dnat) AddEntry(src *net.IP, sport uint16, dst *net.IP, dport uint16) error { - ipLayer := &layers.IPv4{ - Version: 4, - IHL: 5, - TTL: 64, - SrcIP: *src, - DstIP: *dst, - Protocol: layers.IPProtocolUDP, + type networkAndSerializable interface { + gopacket.SerializableLayer + gopacket.NetworkLayer + } + var ipLayer networkAndSerializable + + if src.To4() != nil && dst.To4() != nil { + ipLayer = &layers.IPv4{ + Version: 4, + IHL: 5, + TTL: 64, + SrcIP: *src, + DstIP: *dst, + Protocol: layers.IPProtocolUDP, + } + } else if src.To4() == nil && dst.To4() == nil { + ipLayer = &layers.IPv6{ + Version: 6, + TrafficClass: 0, + HopLimit: 64, + SrcIP: *src, + DstIP: *dst, + NextHeader: layers.IPProtocolUDP, + } + } else { + return fmt.Errorf("both src and dst must be either IPv4 or IPv6") } udpLayer := &layers.UDP{ diff --git a/pkg/dtls/examples/listen/main.go b/pkg/dtls/examples/listen/main.go index 4de9ab69..fd0ed769 100644 --- a/pkg/dtls/examples/listen/main.go +++ b/pkg/dtls/examples/listen/main.go @@ -10,7 +10,7 @@ import ( ) func main() { - var localAddr = flag.String("laddr", "127.0.0.1:6666", "source address") + var localAddr = flag.String("laddr", "[::]:6666", "source address") var secret = flag.String("secret", "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "shared secret") flag.Parse() diff --git a/pkg/dtls/listener.go b/pkg/dtls/listener.go index c66420ef..31753f4c 100644 --- a/pkg/dtls/listener.go +++ b/pkg/dtls/listener.go @@ -72,8 +72,6 @@ func (l *Listener) acceptLoop() { } acceptCh <- newDTLSConn - - close(acceptCh) }() } } @@ -169,7 +167,10 @@ func (l *Listener) AcceptWithContext(ctx context.Context, config *Config) (net.C return &dtls.Conn{}, err } - l.registerCert(connID, clientCert, serverCert) + err = l.registerCert(connID, clientCert, serverCert) + if err != nil { + return nil, fmt.Errorf("error registering cert: %v", err) + } defer l.removeCert(connID) connCh, err := l.registerChannel(connID) @@ -190,10 +191,16 @@ func (l *Listener) AcceptWithContext(ctx context.Context, config *Config) (net.C } } -func (l *Listener) registerCert(connID [handshake.RandomBytesLength]byte, clientCert, serverCert *tls.Certificate) { +func (l *Listener) registerCert(connID [handshake.RandomBytesLength]byte, clientCert, serverCert *tls.Certificate) error { l.connToCertMutex.Lock() defer l.connToCertMutex.Unlock() + + if l.connToCert[connID] != nil { + return fmt.Errorf("seed already registered") + } + l.connToCert[connID] = &certPair{clientCert: clientCert, serverCert: serverCert} + return nil } func (l *Listener) removeCert(connID [handshake.RandomBytesLength]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 b5016d3f..4a8c33ea 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 } @@ -129,7 +129,7 @@ func (r *DecoyRegistrar) getTcpToDecoy() uint32 { return 0 } -func (r DecoyRegistrar) createTLSConn(dialConn net.Conn, address string, hostname string, deadline time.Time) (*tls.UConn, error) { +func (r *DecoyRegistrar) createTLSConn(dialConn net.Conn, address string, hostname string, deadline time.Time) (*tls.UConn, error) { var err error //[reference] TLS to Decoy config := tls.Config{ServerName: hostname} @@ -166,7 +166,7 @@ func (r DecoyRegistrar) createTLSConn(dialConn net.Conn, address string, hostnam 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,28 +204,26 @@ 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()}) +// Register implements the Registrar interface for he DecoyRegistrar type - 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(pb.RegistrationSource_API.Enum()) + 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 } - if r.dialContex != nil { - reg.Dialer = r.dialContex - } - // //[TODO]{priority:later} How to pass context to multiple registration goroutines? if ctx == nil { ctx = context.Background() @@ -233,23 +231,23 @@ func (r DecoyRegistrar) Register(cjSession *td.ConjureSession, ctx context.Conte 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) + go r.send(ctx, cjSession, decoy, dialErrors) } //[reference] Dial errors happen immediately so block until all N dials complete 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 +257,28 @@ func (r DecoyRegistrar) Register(cjSession *td.ConjureSession, ctx context.Conte } } } - //[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 { @@ -289,13 +290,23 @@ func (r *DecoyRegistrar) Send(ctx context.Context, cjSession *td.ConjureSession, //[reference] TCP to decoy tcpToDecoyStartTs := time.Now() + var dial func(ctx context.Context, network, raddr string) (net.Conn, error) + if cjSession.Dialer != nil { + dial = func(ctx context.Context, network, raddr string) (net.Conn, error) { + return cjSession.Dialer(ctx, network, "", raddr) + } + } else { + d := net.Dialer{} + dial = d.DialContext + } + //[Note] decoy.GetIpAddrStr() will get only v4 addr if a decoy has both - dialConn, err := r.dialContex(childCtx, "tcp", decoy.GetIpAddrStr()) + dialConn, err := dial(childCtx, "tcp", decoy.GetIpAddrStr()) 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 +323,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 +332,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 +343,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 +351,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 6c3ca2a2..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,10 +73,10 @@ 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(pb.RegistrationSource_API.Enum()) + reg, protoPayload, err := cjSession.UnidirectionalRegData(ctx, pb.RegistrationSource_API.Enum()) if err != nil { logger.Errorf("Failed to prepare registration data: %v", err) return nil, lib.ErrRegFailed @@ -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,21 +101,22 @@ 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(pb.RegistrationSource_BidirectionalAPI.Enum()) + reg, protoPayload, err := cjSession.BidirectionalRegData(ctx, pb.RegistrationSource_BidirectionalAPI.Enum()) if err != nil { logger.Errorf("Failed to prepare registration data: %v", err) return nil, lib.ErrRegFailed @@ -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..0379d96a 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() } diff --git a/pkg/registrars/registration/dns-registrar.go b/pkg/registrars/registration/dns-registrar.go index 54a4c5fe..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(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(pb.RegistrationSource_DNS.Enum()) + 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(cjSession *tapdance.ConjureSession 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(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(pb.RegistrationSource_BidirectionalDNS.Enum()) + 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,59 +146,57 @@ func (r *DNSRegistrar) registerBidirectional(cjSession *tapdance.ConjureSession) 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 { - return r.registerBidirectional(cjSession) + return r.registerBidirectional(ctx, cjSession) } - return r.registerUnidirectional(cjSession) + 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.go b/pkg/regserver/regprocessor/regprocessor.go index 72469a2a..1926a521 100644 --- a/pkg/regserver/regprocessor/regprocessor.go +++ b/pkg/regserver/regprocessor/regprocessor.go @@ -103,7 +103,7 @@ func NewRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVerbose bool, stationPublicKeys []string) (*RegProcessor, error) { sock, err := zmq.NewSocket(zmq.PUB) if err != nil { - return nil, ErrZmqSocket + return nil, fmt.Errorf("%w: %v", ErrZmqSocket, err) } // XXX: for some weird reason zmq takes just the private key portion of the keypair as the z85 @@ -118,17 +118,17 @@ func newRegProcessor(zmqBindAddr string, zmqPort uint16, privkey []byte, authVer // a change be sure to re-test that the keyed validation works how you expect it to. err = zmq.AuthStart() if err != nil { - return nil, ErrZmqAuthFail + return nil, fmt.Errorf("%w: %v", ErrZmqAuthFail, err) } err = sock.ServerAuthCurve("*", privkeyZ85) if err != nil { - return nil, ErrZmqAuthFail + return nil, fmt.Errorf("%w: %v", ErrZmqAuthFail, err) } err = sock.Bind(fmt.Sprintf("tcp://%s:%d", zmqBindAddr, zmqPort)) if err != nil { - return nil, ErrZmqSocket + return nil, fmt.Errorf("%w: %v", ErrZmqSocket, err) } var regOverrides interfaces.Overrides = nil 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/config.go b/pkg/station/config.go similarity index 65% rename from pkg/station/lib/config.go rename to pkg/station/config.go index 8bfca8ad..a5d91384 100644 --- a/pkg/station/lib/config.go +++ b/pkg/station/config.go @@ -1,19 +1,23 @@ -package lib +package station import ( "fmt" "os" "github.com/BurntSushi/toml" + "github.com/refraction-networking/conjure/pkg/station/connection" + "github.com/refraction-networking/conjure/pkg/station/lib" ) // Config - Station golang configuration struct type Config struct { - *ZMQConfig - *RegConfig + *lib.ZMQConfig + *lib.RegConfig + *connection.ConnManagerConfig // Log verbosity level - LogLevel string `toml:"log_level"` + LogLevel string `toml:"log_level"` + LogClientIP bool `toml:"log_client_ip"` // also available from the CJ_LOG_CLIENT_IP environment variable // Path to private key file PrivateKeyPath string `toml:"privkey_path"` @@ -25,24 +29,25 @@ type Config struct { DisableDefaultPrefixes bool `toml:"disable_default_prefixes"` } -// ParseConfig parses the config from the CJ_STATION_CONFIG environment -// variable. -func ParseConfig() (*Config, error) { - var c Config +// ConfigFromEnv parses the config from the CJ_STATION_CONFIG environment variable. +func ConfigFromEnv() (*Config, error) { var envPath = os.Getenv("CJ_STATION_CONFIG") - _, err := toml.DecodeFile(envPath, &c) + return ParseConfig(envPath) +} + +// ParseConfig parses the config from the given path. +func ParseConfig(path string) (*Config, error) { + var c Config + _, err := toml.DecodeFile(path, &c) if err != nil { - return nil, fmt.Errorf("failed to load config (%s): %v", envPath, err) + return nil, fmt.Errorf("failed to load config (%s): %v", path, err) } - c.ParseBlocklists() + c.RegConfig.ParseBlocklists() return &c, nil } -// PrivateKeyLength is the expected length of the station (ed25519) private key in bytes. -const PrivateKeyLength = 32 - // ParsePrivateKey tries to use either the PrivateKeyPath (`privkey_path`) config variable or the // CJ_PRIVKEY environment variable to locate the file from which it can parse the station private key func (c *Config) ParsePrivateKey() ([32]byte, error) { diff --git a/pkg/station/lib/config_test.go b/pkg/station/config_test.go similarity index 97% rename from pkg/station/lib/config_test.go rename to pkg/station/config_test.go index dfbc133f..b7ec8e69 100644 --- a/pkg/station/lib/config_test.go +++ b/pkg/station/config_test.go @@ -1,4 +1,4 @@ -package lib +package station import ( "os" diff --git a/pkg/station/connection/conn.go b/pkg/station/connection/conn.go new file mode 100644 index 00000000..ee076350 --- /dev/null +++ b/pkg/station/connection/conn.go @@ -0,0 +1,27 @@ +package connection + +import ( + "net" + + "github.com/refraction-networking/conjure/pkg/station/lib" +) + +// Conn is a net.Conn that contains Conjure specific connection information and callback hooks. +type Conn struct { + net.Conn + lib.DecoyRegistration + + closeHook func(*Conn) +} + +// Close allows for a callback to track statistics on connection close. +func (c *Conn) Close() error { + if c.closeHook != nil { + c.closeHook(c) + } + if c.Conn == nil { + return nil + } + + return c.Conn.Close() +} diff --git a/cmd/application/connectingStats.go b/pkg/station/connection/connectingStats.go similarity index 97% rename from cmd/application/connectingStats.go rename to pkg/station/connection/connectingStats.go index 45c99f88..dfa324d5 100644 --- a/cmd/application/connectingStats.go +++ b/pkg/station/connection/connectingStats.go @@ -1,13 +1,13 @@ -package main +package connection import ( "fmt" "sync/atomic" - cj "github.com/refraction-networking/conjure/pkg/station/lib" + "github.com/refraction-networking/conjure/pkg/core/interfaces" ) -var _ cj.ConnectingTpStats = &connStats{} +var _ interfaces.ConnectingTpStats = &connStats{} type connectingCounts struct { numCreatedConnecting int64 diff --git a/pkg/station/connection/conns.go b/pkg/station/connection/conns.go new file mode 100644 index 00000000..23814081 --- /dev/null +++ b/pkg/station/connection/conns.go @@ -0,0 +1,442 @@ +package connection + +import ( + "bytes" + "errors" + "fmt" + "io" + golog "log" + "math/rand" + "net" + "os" + "syscall" + "time" + + "github.com/refraction-networking/conjure/pkg/core/interfaces" + "github.com/refraction-networking/conjure/pkg/log" + cj "github.com/refraction-networking/conjure/pkg/station/lib" + "github.com/refraction-networking/conjure/pkg/transports" + "github.com/refraction-networking/conjure/pkg/transports/connecting/dtls" +) + +// ConnManagerConfig +type ConnManagerConfig struct { + TraceDebugRate int // rate at which to print Debug logging for connections. Rate is computed as 1/n - 0 indicates off. + Logger *log.Logger + LogClientIP bool + NewConnDeadline time.Duration +} + +type connManager struct { + *connStats + *ConnManagerConfig + logger *log.Logger +} + +type ConnHandler interface { + interfaces.ConnectingTpStats + interfaces.Stats + BuildDTLSTransport(dtlsBuilder interfaces.DnatBuilder, logIPDTLS IPLogger) (*dtls.Transport, error) +} + +// NewConnManager returns a connection handler for applying station side transport handling to +// incoming connections +func NewConnManager(conf *ConnManagerConfig) ConnHandler { + return newConnManager(conf) +} +func newConnManager(conf *ConnManagerConfig) *connManager { + if conf == nil { + conf = &ConnManagerConfig{ + NewConnDeadline: 10 * time.Second, + TraceDebugRate: 0, + } + } + + if conf.Logger == nil { + conf.Logger = log.New(os.Stdout, "[CONN] ", golog.Ldate|golog.Lmicroseconds) + } + + return &connManager{ + connStats: &connStats{v4geoIPMap: make(map[uint]*asnCounts), v6geoIPMap: make(map[uint]*asnCounts)}, + ConnManagerConfig: conf, + logger: conf.Logger, + } +} + +// func (cm *connManager) acceptConnections(ctx context.Context, rm *cj.RegistrationManager, logger *log.Logger) { +// // listen for and handle incoming proxy traffic +// listenAddr := &net.TCPAddr{IP: nil, Port: 41245, Zone: ""} +// ln, err := net.ListenTCP("tcp", listenAddr) +// if err != nil { +// logger.Fatalf("failed to listen on %v: %v\n", listenAddr, err) +// } +// defer ln.Close() +// logger.Infof("[STARTUP] Listening on %v\n", ln.Addr()) + +// for { +// select { +// case <-ctx.Done(): +// break +// default: +// newConn, err := ln.AcceptTCP() +// if err != nil { +// logger.Errorf("[ERROR] failed to AcceptTCP on %v: %v\n", ln.Addr(), err) +// continue +// } +// go cm.handleNewConn(rm, newConn) +// } +// } +// } + +func getOriginalDst(fd uintptr) (net.IP, error) { + const SockOptOriginalDst = 80 + if sockOpt, err := syscall.GetsockoptIPv6Mreq(int(fd), syscall.IPPROTO_IP, SockOptOriginalDst); err == nil { + // parse ipv4 + return net.IPv4(sockOpt.Multiaddr[4], sockOpt.Multiaddr[5], sockOpt.Multiaddr[6], sockOpt.Multiaddr[7]), nil + } else if mtuinfo, err := syscall.GetsockoptIPv6MTUInfo(int(fd), syscall.IPPROTO_IPV6, SockOptOriginalDst); err == nil { + // parse ipv6 + return net.IP(mtuinfo.Addr.Addr[:]), nil + } else { + return nil, err + } +} + +// Handle connection from client +// NOTE: this is called as a goroutine +func (cm *connManager) handleNewConn(regManager *cj.RegistrationManager, clientConn *net.TCPConn) { + defer clientConn.Close() + logger := cm.logger + + fd, err := clientConn.File() + if err != nil { + logger.Errorln("failed to get file descriptor on clientConn:", err) + return + } + + fdPtr := fd.Fd() + originalDstIP, err := getOriginalDst(fdPtr) + if err != nil { + logger.Errorln("failed to getOriginalDst from fd:", err) + return + } + + // We need to set the underlying file descriptor back into + // non-blocking mode after calling Fd (which puts it into blocking + // mode), or else deadlines won't work. + err = syscall.SetNonblock(int(fdPtr), true) + if err != nil { + logger.Errorln("failed to set non-blocking mode on fd:", err) + } + fd.Close() + + cm.handleNewTCPConn(regManager, clientConn, originalDstIP) +} + +func getRemoteAsIP(conn net.Conn) (remoteIP net.IP) { + remoteAddr := conn.RemoteAddr() + switch addr := remoteAddr.(type) { + case *net.TCPAddr: + remoteIP = addr.IP + case *net.UDPAddr: + remoteIP = addr.IP + default: + a := remoteAddr.String() + // try parsing the returned address string as host:port + host, _, err := net.SplitHostPort(a) + if err != nil { + // try parsing the returned address string as just an IP address + remoteIP = net.ParseIP(a) + break + } else { + // try parsing the returned host portion of the address as an IP address as opposed to a + // domain name or other string. + remoteIP = net.ParseIP(host) + } + } + return +} + +func (cm *connManager) handleNewTCPConn(regManager *cj.RegistrationManager, clientConn net.Conn, originalDstIP net.IP) { + isIPv4 := originalDstIP.To4() != nil + var originalDst, originalSrc string + if cm.LogClientIP { + originalSrc = clientConn.RemoteAddr().String() + } else { + originalSrc = "_" + } + originalDst = originalDstIP.String() + flowDescription := fmt.Sprintf("%s -> %s ", originalSrc, originalDst) + logger := log.New(os.Stdout, "[CONN] "+flowDescription, golog.Ldate|golog.Lmicroseconds) + + remoteIP := getRemoteAsIP(clientConn) + if remoteIP == nil { + // Socket returned non-IP Remote Address - we can't really use that. If testing w/ pipe try + // wrapping with struct to provide mock RemoteAddr which return a real IP address. + return + } + + var asn uint = 0 + var cc string + var err error + cc, err = regManager.GeoIP.CC(remoteIP) + if err != nil { + logger.Errorln("Failed to get CC:", err) + return + } + if cc != "unk" { + // logger.Infoln("CC not unk:", cc, "ASN:", asn) // TESTING + asn, err = regManager.GeoIP.ASN(remoteIP) + if err != nil { + logger.Errorln("Failed to get ASN:", err) + return + } + } + // logger.Infoln("CC:", cc, "ASN:", asn) // TESTING + + count := regManager.CountRegistrations(originalDstIP) + logger.Debugf("new connection (%d potential registrations)\n", count) + cj.Stat().AddConn() + cm.addCreated(asn, cc, isIPv4) + + // Pick random timeout between 5 and 10 seconds, down to millisecond precision + ms := rand.Int63n(5000) + 5000 + timeout := time.Duration(ms) * time.Millisecond + + // Give the client a deadline to send enough data to identify a transport. + // This can be reset by transports to give more time for handshakes + // after a transport is identified. + deadline := time.Now().Add(timeout) + err = clientConn.SetDeadline(deadline) + if err != nil { + logger.Errorln("error occurred while setting deadline:", err) + } + + if count < 1 { + // Here, reading from the connection would be pointless, but + // since the kernel already ACK'd this connection, we gain no + // benefit from instantly dropping the connection; the jig is + // already up. We should keep reading in line with other code paths + // so the initiator of the connection gains no information + // about the correctness of their connection. + // + // Possible TODO: use NFQUEUE to be able to drop the connection + // in userspace before the SYN-ACK is sent, increasing probe + // resistance. + logger.Debugf("no possible registrations, reading for %v then dropping connection\n", timeout) + cj.Stat().AddMissedReg() + cj.Stat().CloseConn() + cm.createdToDiscard(asn, cc, isIPv4) + + // Copy into io.Discard to keep ACKing until the deadline. + // This should help prevent fingerprinting; if we let the read + // buffer fill up and stopped ACKing after 8192 + (buffer size) + // bytes for obfs4, as an example, that would be quite clear. + _, err = io.Copy(io.Discard, clientConn) + err = generalizeErr(err) + if errors.Is(err, errConnReset) { + // log reset error without client ip + logger.Errorln("error occurred discarding data (read 0 B): rst") + cm.discardToReset(asn, cc, isIPv4) + } else if errors.Is(err, errConnTimeout) { + logger.Errorln("error occurred discarding data (read 0 B): timeout") + cm.discardToTimeout(asn, cc, isIPv4) + } else if errors.Is(err, errConnClosed) { + cm.discardToClose(asn, cc, isIPv4) + } else if err != nil { + //Log any other error + logger.Errorln("error occurred discarding data (read 0 B):", err) + cm.discardToError(asn, cc, isIPv4) + } else { + cm.discardToClose(asn, cc, isIPv4) + } + return + } + + var buf [4096]byte + received := bytes.Buffer{} + possibleTransports := regManager.GetWrappingTransports() + + var reg *cj.DecoyRegistration + var wrapped net.Conn + +readLoop: + for { + if len(possibleTransports) < 1 { + logger.Warnf("ran out of possible transports, reading for %v then giving up\n", time.Until(deadline)) + cj.Stat().ConnErr() + + _, err = io.Copy(io.Discard, clientConn) + err = generalizeErr(err) + if errors.Is(err, errConnReset) { + // log reset error without client ip + logger.Errorf("error occurred discarding data (read %d B): rst\n", received.Len()) + cm.discardToReset(asn, cc, isIPv4) + } else if errors.Is(err, errConnTimeout) { + logger.Errorf("error occurred discarding data (read %d B): timeout\n", received.Len()) + cm.discardToTimeout(asn, cc, isIPv4) + } else if errors.Is(err, errConnClosed) { + cm.discardToClose(asn, cc, isIPv4) + } else if err != nil { + //Log any other error + logger.Errorf("error occurred discarding data (read %d B): %v\n", received.Len(), err) + cm.discardToError(asn, cc, isIPv4) + } else { + cm.discardToClose(asn, cc, isIPv4) + } + + return + } + + n, err := clientConn.Read(buf[:]) + err = generalizeErr(err) + if err != nil { + if errors.Is(err, errConnReset) { + logger.Errorf("got error while reading from connection, giving up after %d bytes: rst\n", received.Len()+n) + if received.Len() == 0 { + cm.createdToReset(asn, cc, isIPv4) + } else { + cm.readToReset(asn, cc, isIPv4) + } + } else if errors.Is(err, errConnTimeout) { + logger.Errorf("got error while reading from connection, giving up after %d bytes: timeout\n", received.Len()+n) + if received.Len() == 0 { + cm.createdToTimeout(asn, cc, isIPv4) + } else { + cm.readToTimeout(asn, cc, isIPv4) + } + } else if errors.Is(err, errConnClosed) { + logger.Errorf("got error while reading from connection, giving up after %d bytes: closed\n", received.Len()+n) + if received.Len() == 0 { + cm.createdToClose(asn, cc, isIPv4) + } else { + cm.readToError(asn, cc, isIPv4) + } + } else { + logger.Errorf("got error while reading from connection, giving up after %d bytes: %v\n", received.Len()+n, err) + if received.Len() == 0 { + cm.createdToError(asn, cc, isIPv4) + } else { + cm.readToError(asn, cc, isIPv4) + } + } + cj.Stat().ConnErr() + return + } + + if received.Len() == 0 { + cm.createdToCheck(asn, cc, isIPv4) + } else { + cm.readToCheck(asn, cc, isIPv4) + } + + received.Write(buf[:n]) + logger.Tracef("read %d bytes so far", received.Len()) + + transports: + for i, t := range possibleTransports { + wrappedReg, wrappedConn, err := t.WrapConnection(&received, clientConn, originalDstIP, regManager) + + err = generalizeErr(err) + if errors.Is(err, transports.ErrTryAgain) { + continue transports + } else if errors.Is(err, transports.ErrNotTransport) { + logger.Tracef("not transport %s, removing from checks\n", t.Name()) + delete(possibleTransports, i) + continue transports + } else if err != nil { + // If we got here, the error might have been produced while attempting + // to wrap the connection, which means received and the connection + // may no longer be valid. We should just give up on this connection. + d := time.Until(deadline) + logger.Warnf("got unexpected error from transport %s, sleeping %v then giving up: %v\n", t.Name(), d, err) + cj.Stat().ConnErr() + cm.checkToError(asn, cc, isIPv4) + time.Sleep(d) + return + } + + ok := false + reg, ok = wrappedReg.(*cj.DecoyRegistration) + if !ok { + logger.Errorf("unexpected returned reg type from transport: %T, expected: %T", wrapped, reg) + delete(possibleTransports, i) + continue transports + } + // set outer wrapped var + wrapped = wrappedConn + + // We found our transport! First order of business: disable deadline + err = wrapped.SetDeadline(time.Time{}) + if err != nil { + logger.Errorln("error occurred while setting deadline:", err) + } + + logger.SetPrefix(fmt.Sprintf("[%s] %s ", t.LogPrefix(), reg.IDString())) + logger.Debugf("registration found {reg_id: %s, phantom: %s, transport: %s}\n", reg.IDString(), originalDstIP, t.Name()) + + regManager.MarkActive(reg) + + cm.checkToFound(asn, cc, isIPv4) + break readLoop + } + + if len(possibleTransports) < 1 { + cm.checkToDiscard(asn, cc, isIPv4) + } else if received.Len() == 0 { + cm.checkToCreated(asn, cc, isIPv4) + } else { + cm.checkToRead(asn, cc, isIPv4) + } + } + + cj.Proxy(reg, wrapped, logger) + cj.Stat().CloseConn() +} + +var ( + // errConnReset replaces the reset error in the halfpipe to remove ips and extra bytes + errConnReset = errors.New("rst") + + // errConnTimeout replaces the ip.timeout error in the halfpipe to remove ips and extra bytes + errConnTimeout = errors.New("timeout") + + // replaces refused error to prevent client IP logging + errConnRefused = errors.New("refused") + + // errUnreachable replaces unreachable error to prevent client IP logging + errUnreachable = errors.New("unreachable") + + // errConnAborted replaces aborted error to prevent client IP logging + errConnAborted = errors.New("aborted") + + // errConnClosed replaces closed errors to prevent client IP logging + errConnClosed = errors.New("closed") +) + +func generalizeErr(err error) error { + switch { + case err == nil: + return nil + case + errors.Is(err, net.ErrClosed), // Errors indicating operation on something already closed. + errors.Is(err, io.EOF), + errors.Is(err, syscall.EPIPE), + errors.Is(err, os.ErrClosed): + return errConnClosed + case errors.Is(err, syscall.ECONNRESET): + return errConnReset + case errors.Is(err, syscall.ECONNREFUSED): + return errConnRefused + case errors.Is(err, syscall.ECONNABORTED): + return errConnAborted + case errors.Is(err, syscall.EHOSTUNREACH): + return errUnreachable + default: + if errN, ok := err.(net.Error); ok && errN.Timeout() { + return errConnTimeout + } + } + + // if it is not a well known error, return it + return err +} diff --git a/cmd/application/conns_test.go b/pkg/station/connection/conns_test.go similarity index 88% rename from cmd/application/conns_test.go rename to pkg/station/connection/conns_test.go index 158d59a7..50022277 100644 --- a/cmd/application/conns_test.go +++ b/pkg/station/connection/conns_test.go @@ -1,4 +1,4 @@ -package main +package connection import ( "fmt" @@ -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. @@ -49,7 +49,7 @@ func TestConnHandleNewTCPConn(t *testing.T) { db := &MockGeoIP{} rm.GeoIP = db - connManager := newConnManager(nil) + connMgr := NewConnManager(nil) ip := net.ParseIP("8.8.8.8") clientConn, serverConn := net.Pipe() defer clientConn.Close() @@ -61,7 +61,7 @@ func TestConnHandleNewTCPConn(t *testing.T) { // Call the handleNewTCPConn function in a separate goroutine go func() { - connManager.handleNewTCPConn(rm, serverConn, ip) + connMgr.(*connManager).handleNewTCPConn(rm, serverConn, ip) wg.Done() }() @@ -94,7 +94,7 @@ func TestConnHandleNewTCPConn(t *testing.T) { func TestConnPrintAndReset(t *testing.T) { logger := log.New(os.Stdout, "[TEST CONN STATS] ", golog.Ldate|golog.Lmicroseconds) - connManager := newConnManager(nil) + connMgr := NewConnManager(nil) v4GeoIPMap := make(map[uint]*asnCounts) v4GeoIPMap[0] = &asnCounts{ cc: "unk", @@ -130,13 +130,13 @@ func TestConnPrintAndReset(t *testing.T) { }, } - connManager.connStats.ipv4.numCreated = 55 - connManager.connStats.ipv4.numCheckToError = 1 - connManager.connStats.ipv6.numReset = 17 - connManager.connStats.v4geoIPMap = v4GeoIPMap - connManager.connStats.v6geoIPMap = v6GeoIPMap - // connManager.connStats.v6geoIPMap = make(map[uint]*asnCounts) - connManager.connStats.PrintAndReset(logger) + connMgr.(*connManager).connStats.ipv4.numCreated = 55 + connMgr.(*connManager).connStats.ipv4.numCheckToError = 1 + connMgr.(*connManager).connStats.ipv6.numReset = 17 + connMgr.(*connManager).connStats.v4geoIPMap = v4GeoIPMap + connMgr.(*connManager).connStats.v6geoIPMap = v6GeoIPMap + // connMgr.(*connManager).connStats.v6geoIPMap = make(map[uint]*asnCounts) + connMgr.(*connManager).connStats.PrintAndReset(logger) } func TestConnHandleConcurrent(t *testing.T) { diff --git a/pkg/station/connection/dtls.go b/pkg/station/connection/dtls.go new file mode 100644 index 00000000..b3f9d062 --- /dev/null +++ b/pkg/station/connection/dtls.go @@ -0,0 +1,20 @@ +package connection + +import ( + "net" + + "github.com/refraction-networking/conjure/pkg/core/interfaces" + "github.com/refraction-networking/conjure/pkg/transports/connecting/dtls" +) + +type IPLogger func(logger func(asn uint, cc, tp string)) func(*net.IP) + +func (cm *connManager) BuildDTLSTransport(dtlsBuilder interfaces.DnatBuilder, logIPDTLS IPLogger) (*dtls.Transport, error) { + return dtls.NewTransport( + logIPDTLS(cm.AddAuthFailConnecting), + logIPDTLS(cm.AddOtherFailConnecting), + logIPDTLS(cm.AddCreatedToDialSuccessfulConnecting), + logIPDTLS(cm.AddCreatedToListenSuccessfulConnecting), + dtlsBuilder, + ) +} diff --git a/cmd/application/conns.go b/pkg/station/connection/stats.go similarity index 76% rename from cmd/application/conns.go rename to pkg/station/connection/stats.go index 290b0c4b..493829ed 100644 --- a/cmd/application/conns.go +++ b/pkg/station/connection/stats.go @@ -1,379 +1,14 @@ -package main +package connection import ( - "bytes" - "context" - "errors" - "fmt" - "io" - golog "log" "math" - "math/rand" - "net" - "os" "sync" "sync/atomic" - "syscall" "time" - cj "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/log" ) -// connManagerConfig -type connManagerConfig struct { - NewConnDeadline string - newConnDeadline time.Duration - TraceDebugRate int // rate at which to print Debug logging for connections. Rate is computed as 1/n - 0 indicates off. -} - -type connManager struct { - *connStats - *connManagerConfig -} - -func newConnManager(conf *connManagerConfig) *connManager { - if conf == nil { - conf = &connManagerConfig{ - NewConnDeadline: "10s", - newConnDeadline: 10 * time.Second, - TraceDebugRate: 0, - } - } - return &connManager{&connStats{v4geoIPMap: make(map[uint]*asnCounts), v6geoIPMap: make(map[uint]*asnCounts)}, conf} -} - -func (cm *connManager) acceptConnections(ctx context.Context, rm *cj.RegistrationManager, logger *log.Logger) { - // listen for and handle incoming proxy traffic - listenAddr := &net.TCPAddr{IP: nil, Port: 41245, Zone: ""} - ln, err := net.ListenTCP("tcp", listenAddr) - if err != nil { - logger.Fatalf("failed to listen on %v: %v\n", listenAddr, err) - } - defer ln.Close() - logger.Infof("[STARTUP] Listening on %v\n", ln.Addr()) - - for { - select { - case <-ctx.Done(): - break - default: - newConn, err := ln.AcceptTCP() - if err != nil { - logger.Errorf("[ERROR] failed to AcceptTCP on %v: %v\n", ln.Addr(), err) - continue - } - go cm.handleNewConn(rm, newConn) - } - } -} - -func getOriginalDst(fd uintptr) (net.IP, error) { - const SockOptOriginalDst = 80 - if sockOpt, err := syscall.GetsockoptIPv6Mreq(int(fd), syscall.IPPROTO_IP, SockOptOriginalDst); err == nil { - // parse ipv4 - return net.IPv4(sockOpt.Multiaddr[4], sockOpt.Multiaddr[5], sockOpt.Multiaddr[6], sockOpt.Multiaddr[7]), nil - } else if mtuinfo, err := syscall.GetsockoptIPv6MTUInfo(int(fd), syscall.IPPROTO_IPV6, SockOptOriginalDst); err == nil { - // parse ipv6 - return net.IP(mtuinfo.Addr.Addr[:]), nil - } else { - return nil, err - } -} - -// Handle connection from client -// NOTE: this is called as a goroutine -func (cm *connManager) handleNewConn(regManager *cj.RegistrationManager, clientConn *net.TCPConn) { - defer clientConn.Close() - logger := sharedLogger - - fd, err := clientConn.File() - if err != nil { - logger.Errorln("failed to get file descriptor on clientConn:", err) - return - } - - fdPtr := fd.Fd() - originalDstIP, err := getOriginalDst(fdPtr) - if err != nil { - logger.Errorln("failed to getOriginalDst from fd:", err) - return - } - - // We need to set the underlying file descriptor back into - // non-blocking mode after calling Fd (which puts it into blocking - // mode), or else deadlines won't work. - err = syscall.SetNonblock(int(fdPtr), true) - if err != nil { - logger.Errorln("failed to set non-blocking mode on fd:", err) - } - fd.Close() - - cm.handleNewTCPConn(regManager, clientConn, originalDstIP) -} - -func getRemoteAsIP(conn net.Conn) (remoteIP net.IP) { - remoteAddr := conn.RemoteAddr() - switch addr := remoteAddr.(type) { - case *net.TCPAddr: - remoteIP = addr.IP - case *net.UDPAddr: - remoteIP = addr.IP - default: - a := remoteAddr.String() - // try parsing the returned address string as host:port - host, _, err := net.SplitHostPort(a) - if err != nil { - // try parsing the returned address string as just an IP address - remoteIP = net.ParseIP(a) - break - } else { - // try parsing the returned host portion of the address as an IP address as opposed to a - // domain name or other string. - remoteIP = net.ParseIP(host) - } - } - return -} - -func (cm *connManager) handleNewTCPConn(regManager *cj.RegistrationManager, clientConn net.Conn, originalDstIP net.IP) { - isIPv4 := originalDstIP.To4() != nil - var originalDst, originalSrc string - if logClientIP { - originalSrc = clientConn.RemoteAddr().String() - } else { - originalSrc = "_" - } - originalDst = originalDstIP.String() - flowDescription := fmt.Sprintf("%s -> %s ", originalSrc, originalDst) - logger := log.New(os.Stdout, "[CONN] "+flowDescription, golog.Ldate|golog.Lmicroseconds) - - remoteIP := getRemoteAsIP(clientConn) - if remoteIP == nil { - // Socket returned non-IP Remote Address - we can't really use that. If testing w/ pipe try - // wrapping with struct to provide mock RemoteAddr which return a real IP address. - return - } - - var asn uint = 0 - var cc string - var err error - cc, err = regManager.GeoIP.CC(remoteIP) - if err != nil { - logger.Errorln("Failed to get CC:", err) - return - } - if cc != "unk" { - // logger.Infoln("CC not unk:", cc, "ASN:", asn) // TESTING - asn, err = regManager.GeoIP.ASN(remoteIP) - if err != nil { - logger.Errorln("Failed to get ASN:", err) - return - } - } - // logger.Infoln("CC:", cc, "ASN:", asn) // TESTING - - count := regManager.CountRegistrations(originalDstIP) - logger.Debugf("new connection (%d potential registrations)\n", count) - cj.Stat().AddConn() - cm.addCreated(asn, cc, isIPv4) - - // Pick random timeout between 5 and 10 seconds, down to millisecond precision - ms := rand.Int63n(5000) + 5000 - timeout := time.Duration(ms) * time.Millisecond - - // Give the client a deadline to send enough data to identify a transport. - // This can be reset by transports to give more time for handshakes - // after a transport is identified. - deadline := time.Now().Add(timeout) - err = clientConn.SetDeadline(deadline) - if err != nil { - logger.Errorln("error occurred while setting deadline:", err) - } - - if count < 1 { - // Here, reading from the connection would be pointless, but - // since the kernel already ACK'd this connection, we gain no - // benefit from instantly dropping the connection; the jig is - // already up. We should keep reading in line with other code paths - // so the initiator of the connection gains no information - // about the correctness of their connection. - // - // Possible TODO: use NFQUEUE to be able to drop the connection - // in userspace before the SYN-ACK is sent, increasing probe - // resistance. - logger.Debugf("no possible registrations, reading for %v then dropping connection\n", timeout) - cj.Stat().AddMissedReg() - cj.Stat().CloseConn() - cm.createdToDiscard(asn, cc, isIPv4) - - // Copy into io.Discard to keep ACKing until the deadline. - // This should help prevent fingerprinting; if we let the read - // buffer fill up and stopped ACKing after 8192 + (buffer size) - // bytes for obfs4, as an example, that would be quite clear. - _, err = io.Copy(io.Discard, clientConn) - err = generalizeErr(err) - if errors.Is(err, errConnReset) { - // log reset error without client ip - logger.Errorln("error occurred discarding data (read 0 B): rst") - cm.discardToReset(asn, cc, isIPv4) - } else if errors.Is(err, errConnTimeout) { - logger.Errorln("error occurred discarding data (read 0 B): timeout") - cm.discardToTimeout(asn, cc, isIPv4) - } else if errors.Is(err, errConnClosed) { - cm.discardToClose(asn, cc, isIPv4) - } else if err != nil { - //Log any other error - logger.Errorln("error occurred discarding data (read 0 B):", err) - cm.discardToError(asn, cc, isIPv4) - } else { - cm.discardToClose(asn, cc, isIPv4) - } - return - } - - var buf [4096]byte - received := bytes.Buffer{} - possibleTransports := regManager.GetWrappingTransports() - - var reg *cj.DecoyRegistration - var wrapped net.Conn - -readLoop: - for { - if len(possibleTransports) < 1 { - logger.Warnf("ran out of possible transports, reading for %v then giving up\n", time.Until(deadline)) - cj.Stat().ConnErr() - - _, err = io.Copy(io.Discard, clientConn) - err = generalizeErr(err) - if errors.Is(err, errConnReset) { - // log reset error without client ip - logger.Errorf("error occurred discarding data (read %d B): rst\n", received.Len()) - cm.discardToReset(asn, cc, isIPv4) - } else if errors.Is(err, errConnTimeout) { - logger.Errorf("error occurred discarding data (read %d B): timeout\n", received.Len()) - cm.discardToTimeout(asn, cc, isIPv4) - } else if errors.Is(err, errConnClosed) { - cm.discardToClose(asn, cc, isIPv4) - } else if err != nil { - //Log any other error - logger.Errorf("error occurred discarding data (read %d B): %v\n", received.Len(), err) - cm.discardToError(asn, cc, isIPv4) - } else { - cm.discardToClose(asn, cc, isIPv4) - } - - return - } - - n, err := clientConn.Read(buf[:]) - err = generalizeErr(err) - if err != nil { - if errors.Is(err, errConnReset) { - logger.Errorf("got error while reading from connection, giving up after %d bytes: rst\n", received.Len()+n) - if received.Len() == 0 { - cm.createdToReset(asn, cc, isIPv4) - } else { - cm.readToReset(asn, cc, isIPv4) - } - } else if errors.Is(err, errConnTimeout) { - logger.Errorf("got error while reading from connection, giving up after %d bytes: timeout\n", received.Len()+n) - if received.Len() == 0 { - cm.createdToTimeout(asn, cc, isIPv4) - } else { - cm.readToTimeout(asn, cc, isIPv4) - } - } else if errors.Is(err, errConnClosed) { - logger.Errorf("got error while reading from connection, giving up after %d bytes: closed\n", received.Len()+n) - if received.Len() == 0 { - cm.createdToClose(asn, cc, isIPv4) - } else { - cm.readToError(asn, cc, isIPv4) - } - } else { - logger.Errorf("got error while reading from connection, giving up after %d bytes: %v\n", received.Len()+n, err) - if received.Len() == 0 { - cm.createdToError(asn, cc, isIPv4) - } else { - cm.readToError(asn, cc, isIPv4) - } - } - cj.Stat().ConnErr() - return - } - - if received.Len() == 0 { - cm.createdToCheck(asn, cc, isIPv4) - } else { - cm.readToCheck(asn, cc, isIPv4) - } - - received.Write(buf[:n]) - logger.Tracef("read %d bytes so far", received.Len()) - - transports: - for i, t := range possibleTransports { - wrappedReg, wrappedConn, err := t.WrapConnection(&received, clientConn, originalDstIP, regManager) - - err = generalizeErr(err) - if errors.Is(err, transports.ErrTryAgain) { - continue transports - } else if errors.Is(err, transports.ErrNotTransport) { - logger.Tracef("not transport %s, removing from checks\n", t.Name()) - delete(possibleTransports, i) - continue transports - } else if err != nil { - // If we got here, the error might have been produced while attempting - // to wrap the connection, which means received and the connection - // may no longer be valid. We should just give up on this connection. - d := time.Until(deadline) - logger.Warnf("got unexpected error from transport %s, sleeping %v then giving up: %v\n", t.Name(), d, err) - cj.Stat().ConnErr() - cm.checkToError(asn, cc, isIPv4) - time.Sleep(d) - return - } - - ok := false - reg, ok = wrappedReg.(*cj.DecoyRegistration) - if !ok { - logger.Errorf("unexpected returned reg type from transport: %T, expected: %T", wrapped, reg) - delete(possibleTransports, i) - continue transports - } - // set outer wrapped var - wrapped = wrappedConn - - // We found our transport! First order of business: disable deadline - err = wrapped.SetDeadline(time.Time{}) - if err != nil { - logger.Errorln("error occurred while setting deadline:", err) - } - - logger.SetPrefix(fmt.Sprintf("[%s] %s ", t.LogPrefix(), reg.IDString())) - logger.Debugf("registration found {reg_id: %s, phantom: %s, transport: %s}\n", reg.IDString(), originalDstIP, t.Name()) - - regManager.MarkActive(reg) - - cm.checkToFound(asn, cc, isIPv4) - break readLoop - } - - if len(possibleTransports) < 1 { - cm.checkToDiscard(asn, cc, isIPv4) - } else if received.Len() == 0 { - cm.checkToCreated(asn, cc, isIPv4) - } else { - cm.checkToRead(asn, cc, isIPv4) - } - } - - cj.Proxy(reg, wrapped, logger) - cj.Stat().CloseConn() -} - type statCounts struct { // States numCreated int64 // Number of connections that have read 0 bytes so far @@ -1590,51 +1225,3 @@ func (c *connStats) discardToClose(asn uint, cc string, isIPv4 bool) { func isValidCC(cc string) bool { return cc != "" } - -var ( - // errConnReset replaces the reset error in the halfpipe to remove ips and extra bytes - errConnReset = errors.New("rst") - - // errConnTimeout replaces the ip.timeout error in the halfpipe to remove ips and extra bytes - errConnTimeout = errors.New("timeout") - - // replaces refused error to prevent client IP logging - errConnRefused = errors.New("refused") - - // errUnreachable replaces unreachable error to prevent client IP logging - errUnreachable = errors.New("unreachable") - - // errConnAborted replaces aborted error to prevent client IP logging - errConnAborted = errors.New("aborted") - - // errConnClosed replaces closed errors to prevent client IP logging - errConnClosed = errors.New("closed") -) - -func generalizeErr(err error) error { - switch { - case err == nil: - return nil - case - errors.Is(err, net.ErrClosed), // Errors indicating operation on something already closed. - errors.Is(err, io.EOF), - errors.Is(err, syscall.EPIPE), - errors.Is(err, os.ErrClosed): - return errConnClosed - case errors.Is(err, syscall.ECONNRESET): - return errConnReset - case errors.Is(err, syscall.ECONNREFUSED): - return errConnRefused - case errors.Is(err, syscall.ECONNABORTED): - return errConnAborted - case errors.Is(err, syscall.EHOSTUNREACH): - return errUnreachable - default: - if errN, ok := err.(net.Error); ok && errN.Timeout() { - return errConnTimeout - } - } - - // if it is not a well known error, return it - return err -} 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 e2d819c3..7c17a08f 100644 --- a/pkg/station/lib/registration.go +++ b/pkg/station/lib/registration.go @@ -16,10 +16,11 @@ 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 +30,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 @@ -45,7 +42,7 @@ type RegistrationManager struct { GeoIP geoip.Database // ConnectingStats records stats related to connecting transports - connectingStats ConnectingTpStats + connectingStats interfaces.ConnectingTpStats // ingestChan is included here so that the capacity and use is available to // stats @@ -54,6 +51,9 @@ type RegistrationManager struct { // NewRegistrationManager returns a newly initialized registration Manager func NewRegistrationManager(conf *RegConfig) *RegistrationManager { + if conf == nil { + return nil + } logger := log.New(os.Stdout, "[REG] ", golog.Ldate|golog.Lmicroseconds) @@ -136,7 +136,7 @@ func (regManager *RegistrationManager) OnReload(conf *RegConfig) { // clients register. func (regManager *RegistrationManager) AddTransport(index pb.TransportType, t Transport) error { if regManager == nil { - regManager = NewRegistrationManager(regManager.RegConfig) + return fmt.Errorf("registration manager cannot be nil") } if regManager.registeredDecoys == nil { regManager.registeredDecoys = NewRegisteredDecoys() @@ -223,10 +223,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 } @@ -272,6 +272,12 @@ func (regManager *RegistrationManager) Cleanup() { clearDetector() } +// Shutdown closes any actively tracked threads, allowing a clean close of the station. +func (regManager *RegistrationManager) Shutdown() { + // TODO: more cleanup here + regManager.Cleanup() +} + // DecoyRegistration is a struct for tracking individual sessions that are expecting or tracking connections. type DecoyRegistration struct { PhantomIp net.IP @@ -293,7 +299,6 @@ type DecoyRegistration struct { DecoyListVersion uint32 regCount int32 clientLibVer uint32 - clientPort uint16 tunnelCount int64 @@ -425,7 +430,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)) } @@ -480,9 +485,11 @@ func (reg *DecoyRegistration) GetDstPort() uint16 { return reg.PhantomPort } -// GetSrcPort returns a source port if one was registered. +// GetSrcPort returns a source port if one was registered. Currently this is not +// supported -- for now this is intended as plumbing for potentially supporting +// seeded source port selection for the client. func (reg *DecoyRegistration) GetSrcPort() uint16 { - return reg.clientPort + return 0 } type regStatus int @@ -846,13 +853,11 @@ func sendToDetector(reg *DecoyRegistration, duration uint64, op pb.StationOperat src := reg.registrationAddr.String() phantom := reg.PhantomIp.String() // protocol := reg.GetProto() - srcPort := uint32(reg.GetSrcPort()) dstPort := uint32(reg.GetDstPort()) msg := &pb.StationToDetector{ PhantomIp: &phantom, ClientIp: &src, DstPort: &dstPort, - SrcPort: &srcPort, Proto: ®.PhantomProto, TimeoutNs: &duration, Operation: &op, diff --git a/pkg/station/lib/registration_config.go b/pkg/station/lib/registration_config.go index 4eb76816..e2840721 100644 --- a/pkg/station/lib/registration_config.go +++ b/pkg/station/lib/registration_config.go @@ -5,6 +5,7 @@ import ( "regexp" "strconv" + "github.com/refraction-networking/conjure/pkg/core/interfaces" "github.com/refraction-networking/conjure/pkg/station/geoip" "github.com/refraction-networking/conjure/pkg/station/liveness" ) @@ -47,7 +48,7 @@ type RegConfig struct { phantomBlocklist []*net.IPNet // ConnectingStats records stats related to connecting transports - ConnectingStats ConnectingTpStats + ConnectingStats interfaces.ConnectingTpStats } // ParseBlocklists converts string arrays of blocklisted domains, addresses and diff --git a/pkg/station/lib/registration_ingest.go b/pkg/station/lib/registration_ingest.go index 9d9bc7fc..aefc7e17 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" ) @@ -370,11 +371,6 @@ func (rm *RegistrationManager) NewRegistration(c2s *pb.ClientToStation, conjureK return nil, fmt.Errorf("error determining phantom connection proto: %s", err) } - srcPort, err := rm.getClientSrcPort(c2s.GetTransport(), transportParams, conjureKeys.ConjureSeed, clientLibVer) - if err != nil { - return nil, fmt.Errorf("error determining client source port: %s", err) - } - reg := DecoyRegistration{ DecoyListVersion: c2s.GetDecoyListGeneration(), Keys: conjureKeys, @@ -383,7 +379,6 @@ func (rm *RegistrationManager) NewRegistration(c2s *pb.ClientToStation, conjureK TransportPtr: &transport, transportParams: transportParams, Flags: c2s.Flags, - clientPort: srcPort, PhantomIp: *phantomAddr.IP, PhantomPort: phantomPort, @@ -501,22 +496,6 @@ func (rm *RegistrationManager) getPhantomDstPort(t pb.TransportType, params any, return transport.GetDstPort(libVer, seed, params) } -// getPhantomDstPort returns the proper phantom port based on registration type, transport -// parameters provided by the client and session details (also provided by the client). -func (rm *RegistrationManager) getClientSrcPort(t pb.TransportType, params any, seed []byte, libVer uint) (uint16, error) { - var transport, ok = rm.registeredDecoys.transports[t].(ConnectingTransport) - if !ok { - // non-connecting transports do not have a set source port - return 0, nil - } - - // GetDstPort Given the library version, a seed, and a generic object containing parameters the - // transport should be able to return the destination port that a clients phantom connection - // will attempt to reach. The libVersion is provided incase of version dependent changes in the - // transport selection algorithms themselves. - return transport.GetSrcPort(libVer, seed, params) -} - // Handle new registration from client for UDP Transports // NOTE: this is called within a goroutine in get_zmq_updates func handleConnectingTpReg(regManager *RegistrationManager, reg *DecoyRegistration, logger *log.Logger) { @@ -524,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) @@ -567,10 +546,3 @@ func handleConnectingTpReg(regManager *RegistrationManager, reg *DecoyRegistrati } } -type ConnectingTpStats interface { - AddCreatedConnecting(asn uint, cc string, tp string) - AddCreatedToSuccessfulConnecting(asn uint, cc string, tp string) - AddCreatedToTimeoutConnecting(asn uint, cc string, tp string) - AddSuccessfulToDiscardedConnecting(asn uint, cc string, tp string) - AddOtherFailConnecting(asn uint, cc string, tp string) -} 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..3e27931d 100644 --- a/pkg/station/lib/stats.go +++ b/pkg/station/lib/stats.go @@ -8,19 +8,11 @@ import ( "sync/atomic" "time" - "github.com/refraction-networking/conjure/pkg/station/log" + "github.com/refraction-networking/conjure/pkg/core/interfaces" + "github.com/refraction-networking/conjure/pkg/log" pb "github.com/refraction-networking/conjure/proto" ) -type stats interface { - // PrintAndReset is intended to allow each stats module to summarize metrics - // from the current epoch out through the logger and then reset any stats - // that need reset as the start of a new epoch. - PrintAndReset(logger *log.Logger) - - Reset() -} - // Stats contains counts of many things we want to keep track of in any given epoch // as well as reference to modular metrics interfaces from related modules. These // are used to print usage in a regulated and consumable way. @@ -30,8 +22,8 @@ type stats interface { type Stats struct { logger *log.Logger - moduleStats []stats - verboseStats []stats + moduleStats []interfaces.Stats + verboseStats []interfaces.Stats // TODO JMWAMPLE REMOVE activeConns int64 // incremented on add, decremented on remove, not reset @@ -70,7 +62,7 @@ func Stat() *Stats { return &statInstance } -func (s *Stats) AddStatsModule(sm stats, isVerbose bool) { +func (s *Stats) AddStatsModule(sm interfaces.Stats, isVerbose bool) { if sm == nil { return } 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..9a71d537 100644 --- a/pkg/station/lib/zmq_proxy.go +++ b/pkg/station/lib/zmq_proxy.go @@ -13,11 +13,13 @@ 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 type ZMQConfig struct { + LocalZmqAddress string `toml:"local_zmq_address"` + SocketName string `toml:"socket_name"` ConnectSockets []socketConfig `toml:"connect_sockets"` HeartbeatInterval int `toml:"heartbeat_interval"` 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/station/station.go b/pkg/station/station.go new file mode 100644 index 00000000..ccda9ccd --- /dev/null +++ b/pkg/station/station.go @@ -0,0 +1,230 @@ +package station + +import ( + "context" + "fmt" + "net" + "os" + "strconv" + "sync" + "time" + + "github.com/refraction-networking/conjure/pkg/core/interfaces" + "github.com/refraction-networking/conjure/pkg/dtls/dnat" + "github.com/refraction-networking/conjure/pkg/log" + "github.com/refraction-networking/conjure/pkg/station/connection" + "github.com/refraction-networking/conjure/pkg/station/lib" + "github.com/refraction-networking/conjure/pkg/station/liveness" + "github.com/refraction-networking/conjure/pkg/transports/wrapping/prefix" + pb "github.com/refraction-networking/conjure/proto" +) + +// PrivateKeyLength is the expected length of the station (ed25519) private key in bytes. +const PrivateKeyLength = 32 + +var ( + // ErrNotImplemented is returned when a method is not implemented. + ErrNotImplemented = liveness.ErrNotImplemented + + // ErrNonConjureConn is returned when a non-conjure connection is passed to a conjure method. + errNonConjureConn = "cannot use %s on non-conjure connection" +) + +var ( + // sharedLogger is the default logger for the station package. + sharedLogger *log.Logger +) + +// Station is a Conjure station. Running all required routines based on the provided configuration. +type Station struct { + regManager *lib.RegistrationManager + connManager *connection.ConnHandler + stats []*lib.Stats + + enabledTransports map[pb.TransportType]interfaces.TransportSS + + wg *sync.WaitGroup +} + +type listener struct { + initialized bool + listener net.Listener +} + +func New(ctx context.Context, conf *Config) (*Station, error) { + + connManager := connection.NewConnManager(conf.ConnManagerConfig) + enabledTransports := make(map[pb.TransportType]interfaces.TransportSS) + + conf.RegConfig.ConnectingStats = connManager + + regManager := lib.NewRegistrationManager(conf.RegConfig) + + logIPDTLS := func(logger func(asn uint, cc, tp string)) func(*net.IP) { + return func(ip *net.IP) { + cc, err := regManager.GeoIP.CC(*ip) + if err != nil { + return + } + + var asn uint = 0 + if cc != "unk" { + asn, err = regManager.GeoIP.ASN(*ip) + if err != nil { + return + } + } + + logger(asn, cc, "dtls") + } + } + + dtlsbuilder := dnat.NewDNAT + dtlsTransport, err := connManager.BuildDTLSTransport(dtlsbuilder, logIPDTLS) + + if err != nil { + log.Fatalf("failed to setup dtls: %v", err) + } + enabledTransports[pb.TransportType_DTLS] = dtlsTransport + + sharedLogger = regManager.Logger + logger := sharedLogger + defer regManager.Cleanup() + + // Should we log client IP addresses + logClientIP, err := strconv.ParseBool(os.Getenv("LOG_CLIENT_IP")) + if err != nil { + logger.Errorf("failed parse client ip logging setting: %v\n", err) + logClientIP = false + } else { + conf.LogClientIP = logClientIP + } + + privkey, err := conf.ParsePrivateKey() + if err != nil { + logger.Fatalf("error parseing private key: %s", err) + } + + var prefixTransport lib.Transport + if conf.DisableDefaultPrefixes { + prefixTransport, err = prefix.New(privkey, conf.PrefixFilePath) + } else { + prefixTransport, err = prefix.Default(privkey, conf.PrefixFilePath) + } + if err != nil { + logger.Errorf("Failed to parse provided custom prefix transport file: %s", err) + } else { + enabledTransports[pb.TransportType_Prefix] = prefixTransport + } + + // Add supported transport options for registration validation + for transportType, transport := range enabledTransports { + err = regManager.AddTransport(transportType, transport) + if err != nil { + logger.Errorf("failed to add transport: %v", err) + } + } + + wg := new(sync.WaitGroup) + regChan := make(chan interface{}, 10000) + zmqIngester, err := lib.NewZMQIngest(conf.ZMQConfig.LocalZmqAddress, regChan, privkey, conf.ZMQConfig) + if err != nil { + logger.Fatal("error creating ZMQ Ingest: %w", err) + } + + lib.Stat().AddStatsModule(zmqIngester, false) + lib.Stat().AddStatsModule(regManager.LivenessTester, false) + lib.Stat().AddStatsModule(lib.GetProxyStats(), false) + lib.Stat().AddStatsModule(regManager, false) + lib.Stat().AddStatsModule(connManager, true) + + // Periodically clean old registrations + wg.Add(1) + go func(ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() + + ticker := time.NewTicker(3 * time.Minute) + for { + select { + case <-ticker.C: + regManager.RemoveOldRegistrations() + case <-ctx.Done(): + return + } + } + }(ctx, wg) + + // Receive registration updates from ZMQ Proxy as subscriber + go zmqIngester.RunZMQ(ctx) + wg.Add(1) + go regManager.HandleRegUpdates(ctx, regChan, wg) + + return &Station{ + regManager: regManager, + connManager: &connManager, + stats: []*lib.Stats{lib.Stat()}, + enabledTransports: enabledTransports, + wg: wg, + }, nil +} + +// Listen creates a new listener for the station which gives back a listener that can be used to +// accept connections in the pattern of the net package. +func Listen(network, address string) (net.Listener, error) { + conf, err := ConfigFromEnv() + if err != nil { + return nil, err + } + + ctx := context.Background() + + station, err := New(ctx, conf) + if err != nil { + return nil, err + } + + return station.Listen(ctx, network, address) +} + +// Listen creates a new listener for the station which gives back a listener that can be used to +// accept connections in the pattern of the net package. Building a listener in this way allows the +// caller to specify the context. +func (s *Station) Listen(ctx context.Context, network, addr string) (net.Listener, error) { + return s, nil +} + +// Accept accepts a new connection from the listener. +func (s *Station) Accept() (net.Conn, error) { + return nil, ErrNotImplemented +} + +// Close closes the listener +// Any blocked Accept operations will be unblocked and return errors. +func (s *Station) Close() error { + return ErrNotImplemented +} + +// Addr returns the listener's network address. +func (s *Station) Addr() net.Addr { + return net.Addr(nil) +} + +// Shutdown shuts down the station. +func (s *Station) Shutdown() { + s.Close() + s.regManager.Shutdown() + s.wg.Wait() +} + +// ForwardProxy provides a Conjure specific transparent forward proxy which gives the ability to +// track statistics based on metadata associated with the registration such as transport type / +// parameters, phantom addr / subnet / port, client ASN / CC, etc. +func (s *Station) ForwardProxy(conn net.Conn) error { + cjConn, ok := conn.(*connection.Conn) + if !ok { + return fmt.Errorf(errNonConjureConn, "Station.ForwardProxy") + } + + lib.Proxy(&cjConn.DecoyRegistration, cjConn, s.regManager.Logger) + return nil +} 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/client.go b/pkg/transports/connecting/dtls/client.go index becde453..a1014ee3 100644 --- a/pkg/transports/connecting/dtls/client.go +++ b/pkg/transports/connecting/dtls/client.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "net" + "sync" "time" "github.com/refraction-networking/conjure/pkg/dtls" @@ -21,7 +22,8 @@ const ( portRangeMin = 1024 portRangeMax = 65535 defaultPort = 443 - defaultSTUNServer = "stun.voip.blackberry.com:3478" + defaultSTUNServer = "stun.l.google.com:19302" + defaultListenTime = 5 * time.Second ) // ClientTransport implements the client side transport interface for the DTLS transport. The @@ -31,14 +33,14 @@ type ClientTransport struct { // Parameters are fields that will be shared with the station in the registration Parameters *pb.DTLSTransportParams - // // state tracks fields internal to the registrar that survive for the lifetime - // // of the transport session without being shared - i.e. local derived keys. - // state any - privPort int - pubPort int + privAddr4 *net.UDPAddr + pubAddr4 *net.UDPAddr + privAddr6 *net.UDPAddr + pubAddr6 *net.UDPAddr psk []byte stunServer string disableIRWorkaround bool + listenTimeout *time.Duration } type ClientConfig struct { @@ -47,9 +49,14 @@ type ClientConfig struct { // DisableIRWorkaround disables sending an empty packet to workaround DTLS blocking in IR // - // In Iran, blocking seems to happen by matching the first packet in a "flow" against DTLS packet format and blocking if it matches. + // In Iran, blocking seems to happen by matching the first packet in a "flow" against DTLS packet format and blocking if it matches. // If the first packet is anything else packets are permitted. UDP dst port does not seem to change this. DisableIRWorkaround bool + + // ListenTimeout is the duration to listen for the DTLS handshake sent by station. After this duration, the + // client will initiate the handshake instead in case there are NAT issues preventing the station from reaching + // the client. + ListenTimeout *time.Duration } // Name returns a string identifier for the Transport for logging @@ -87,6 +94,7 @@ func (t *ClientTransport) SetParams(p any, unchecked ...bool) error { case *ClientConfig: t.stunServer = params.STUNServer t.disableIRWorkaround = params.DisableIRWorkaround + t.listenTimeout = params.ListenTimeout } return nil @@ -94,19 +102,51 @@ func (t *ClientTransport) SetParams(p any, unchecked ...bool) error { // Prepare lets the transport use the dialer to prepare. This is called before GetParams to let the // transport prepare stuff such as nat traversal. -func (t *ClientTransport) Prepare(dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) error { +func (t *ClientTransport) Prepare(ctx context.Context, dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) error { if t.stunServer == "" { t.stunServer = defaultSTUNServer } - privePort, pubPort, err := publicAddr(defaultSTUNServer, dialer) - if err != nil { - return fmt.Errorf("error finding public port: %v", err) + var privAddr4 *net.UDPAddr + var pubAddr4 *net.UDPAddr + var privAddr6 *net.UDPAddr + var pubAddr6 *net.UDPAddr + var err4 error + var err6 error + + wg := sync.WaitGroup{} + wg.Add(2) + + go func() { + privAddr4, pubAddr4, err4 = publicAddr(ctx, "udp4", t.stunServer, dialer) + wg.Done() + }() + + go func() { + privAddr6, pubAddr6, err6 = publicAddr(ctx, "udp6", t.stunServer, dialer) + wg.Done() + }() + + wg.Wait() + + if err4 != nil && err6 != nil { + return fmt.Errorf("error getting v4 public address: %v; error getting v6 public address: %v", err4, err6) } - t.privPort = privePort - t.pubPort = pubPort - t.Parameters = &pb.DTLSTransportParams{SrcPort: proto.Uint32(uint32(pubPort))} + if t.Parameters == nil { + t.Parameters = &pb.DTLSTransportParams{} + } + + if err4 == nil { + t.privAddr4 = privAddr4 + t.pubAddr4 = pubAddr4 + t.Parameters.SrcAddr4 = &pb.Addr{IP: pubAddr4.IP.To4(), Port: proto.Uint32(uint32(pubAddr4.Port))} + } + if err6 == nil { + t.privAddr6 = privAddr6 + t.pubAddr6 = pubAddr6 + t.Parameters.SrcAddr6 = &pb.Addr{IP: pubAddr6.IP.To16(), Port: proto.Uint32(uint32(pubAddr6.Port))} + } return nil } @@ -123,15 +163,18 @@ func (t *ClientTransport) GetDstPort(seed []byte) (uint16, error) { func (t *ClientTransport) WrapDial(dialer dialFunc) (dialFunc, error) { dtlsDialer := func(ctx context.Context, network, localAddr, address string) (net.Conn, error) { // Create a context that will automatically cancel after 5 seconds or when the existing context is cancelled, whichever comes first. - parentctx, parentcancel := context.WithTimeout(context.Background(), 10*time.Second) - defer parentcancel() - ctxtimeout, cancel := context.WithTimeout(parentctx, 5*time.Second) + timeout := t.listenTimeout + if timeout == nil { + time := defaultListenTime + timeout = &time + } + ctxtimeout, cancel := context.WithTimeout(ctx, *timeout) defer cancel() conn, errListen := t.listen(ctxtimeout, dialer, address) if errListen != nil { // fallback to dial - conn, errDial := t.dial(parentctx, dialer, address) + conn, errDial := t.dial(ctx, dialer, address) if errDial != nil { return nil, fmt.Errorf("error listening: %v, error dialing: %v", errListen, errDial) } @@ -146,7 +189,28 @@ func (t *ClientTransport) WrapDial(dialer dialFunc) (dialFunc, error) { } func (t *ClientTransport) listen(ctx context.Context, dialer dialFunc, address string) (net.Conn, error) { - laddr := &net.UDPAddr{IP: net.ParseIP("0.0.0.0"), Port: t.privPort} + is4, err := addrIsV4(address) + if err != nil { + return nil, fmt.Errorf("error checking remote address ip version: %v", err) + } + + if is4 { + return t.listenWithLaddr(ctx, dialer, t.privAddr4, address) + } + + return t.listenWithLaddr(ctx, dialer, t.privAddr6, address) +} + +func addrIsV4(address string) (bool, error) { + addr, err := net.ResolveUDPAddr("", address) + if err != nil { + return false, err + } + + return addr.IP.To4() != nil, nil +} + +func (t *ClientTransport) listenWithLaddr(ctx context.Context, dialer dialFunc, laddr *net.UDPAddr, address string) (net.Conn, error) { if t.disableIRWorkaround { err := openUDPLimitTTL(ctx, laddr.String(), address, dialer) @@ -179,6 +243,13 @@ func (t *ClientTransport) dial(ctx context.Context, dialer dialFunc, address str return nil, fmt.Errorf("error dialing udp: %v", err) } + if !t.disableIRWorkaround { + err := sendPacket(ctx, udpConn) + if err != nil { + return nil, err + } + } + conn, err := dtls.ClientWithContext(ctx, udpConn, &dtls.Config{PSK: t.psk, SCTP: dtls.ClientOpen}) if err != nil { return nil, fmt.Errorf("error dialing as client: %v", err) diff --git a/pkg/transports/connecting/dtls/dtls.go b/pkg/transports/connecting/dtls/dtls.go index d9a8e579..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,25 +62,46 @@ 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 } - clientAddr := net.UDPAddr{IP: net.ParseIP(reg.GetRegistrationAddress()), Port: int(reg.GetSrcPort())} - - err := t.DNAT.AddEntry(&clientAddr.IP, uint16(clientAddr.Port), reg.PhantomIP(), reg.GetDstPort()) - if err != nil { - return nil, fmt.Errorf("error adding DNAT entry: %v", err) + params, ok := reg.TransportParams().(*pb.DTLSTransportParams) + if !ok { + return nil, fmt.Errorf("transport params is not *pb.DTLSTransportParams") } - laddr := net.UDPAddr{IP: net.ParseIP("0.0.0.0"), Port: listenPort} - connCh := make(chan net.Conn, 2) errCh := make(chan error, 2) go func() { + + is4 := reg.PhantomIP().To4() != nil + + clientAddr := &net.UDPAddr{} + + if is4 { + clientAddr = &net.UDPAddr{IP: params.SrcAddr4.GetIP(), Port: int(params.SrcAddr4.GetPort())} + } else { + clientAddr = &net.UDPAddr{IP: params.SrcAddr6.GetIP(), Port: int(params.SrcAddr6.GetPort())} + } + + err := t.DNAT.AddEntry(&clientAddr.IP, uint16(clientAddr.Port), reg.PhantomIP(), reg.GetDstPort()) + if err != nil { + errCh <- fmt.Errorf("error adding DNAT entry: %v", err) + return + } + + // reuseport checks for local address and distinguishes between v4 and v6 + laddr := &net.UDPAddr{} + if is4 { + laddr = &net.UDPAddr{IP: net.ParseIP("0.0.0.0"), Port: listenPort} + } else { + laddr = &net.UDPAddr{IP: net.ParseIP("[::]"), Port: listenPort} + } + udpConn, err := reuseport.Dial("udp", laddr.String(), clientAddr.String()) if err != nil { errCh <- fmt.Errorf("error connecting to dtls client: %v", err) @@ -103,7 +124,8 @@ func (t *Transport) Connect(ctx context.Context, reg transports.Registration) (n errCh <- fmt.Errorf("error accepting dtls connection from secret: %v", err) return } - t.logListenSuccess(&clientAddr.IP) + logip := net.ParseIP(reg.GetRegistrationAddress()) + t.logListenSuccess(&logip) connCh <- conn }() @@ -135,15 +157,6 @@ func (t *Transport) Connect(ctx context.Context, reg transports.Registration) (n return nil, combinedErr // if we reached here, both attempts failed } -func (Transport) GetSrcPort(libVersion uint, seed []byte, params any) (uint16, error) { - parameters, ok := params.(*pb.DTLSTransportParams) - if !ok { - return 0, fmt.Errorf("bad parameters provided") - } - - return uint16(parameters.GetSrcPort()), nil -} - func (Transport) GetDstPort(libVersion uint, seed []byte, params any) (uint16, error) { return transports.PortSelectorRange(portRangeMin, portRangeMax, seed) } diff --git a/pkg/transports/connecting/dtls/nat.go b/pkg/transports/connecting/dtls/nat.go index d4290e39..4a34f693 100644 --- a/pkg/transports/connecting/dtls/nat.go +++ b/pkg/transports/connecting/dtls/nat.go @@ -6,6 +6,7 @@ import ( "net" "os" "syscall" + "time" "github.com/pion/stun" ) @@ -24,8 +25,11 @@ func openUDP(ctx context.Context, laddr, addr string, dialer dialFunc) error { } defer conn.Close() - // Write data to the connection - _, err = conn.Write([]byte("")) + return sendPacket(ctx, conn) +} + +func sendPacket(ctx context.Context, conn net.Conn) error { + _, err := conn.Write([]byte("")) if err != nil { return err } @@ -75,55 +79,57 @@ func openUDPLimitTTL(ctx context.Context, laddr, addr string, dialer dialFunc) e return nil } -var ( - privPortSingle int - pubPortSingle int -) +func publicAddr(ctx context.Context, network string, stunServer string, dialer dialFunc) (privateAddr *net.UDPAddr, publicAddr *net.UDPAddr, err error) { -func publicAddr(stunServer string, dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) (privatePort int, publicPort int, err error) { - - if privPortSingle != 0 && pubPortSingle != 0 { - return privPortSingle, pubPortSingle, nil - } - - udpConn, err := dialer(context.Background(), "udp", "", stunServer) + udpConn, err := dialer(ctx, network, "", stunServer) if err != nil { - return 0, 0, fmt.Errorf("error connecting to STUN server: %v", err) + return nil, nil, fmt.Errorf("error connecting to STUN server: %v", err) } defer udpConn.Close() localAddr, err := net.ResolveUDPAddr(udpConn.LocalAddr().Network(), udpConn.LocalAddr().String()) if err != nil { - return 0, 0, fmt.Errorf("error resolving local address: %v", err) + return nil, nil, fmt.Errorf("error resolving local address: %v", err) } client, err := stun.NewClient(udpConn) if err != nil { - return 0, 0, fmt.Errorf("error creating STUN client: %v", err) + return nil, nil, fmt.Errorf("error creating STUN client: %v", err) } message := stun.MustBuild(stun.TransactionID, stun.BindingRequest) var xorAddr stun.XORMappedAddress - err = client.Do(message, func(res stun.Event) { + doneCh := make(chan error, 1) + + err = client.Start(message, func(res stun.Event) { if res.Error != nil { - err = res.Error + doneCh <- err return } err = xorAddr.GetFrom(res.Message) - if err != nil { - return - } + doneCh <- err }) - if err != nil { - return 0, 0, fmt.Errorf("error getting address from STUN: %v", err) + return nil, nil, fmt.Errorf("error getting address from STUN: %v", err) } - privPortSingle = localAddr.Port - pubPortSingle = xorAddr.Port + defer client.Close() + if deadline, ok := ctx.Deadline(); ok { + timer := time.AfterFunc(time.Until(deadline), func() { client.Close() }) + defer timer.Stop() + } + + select { + case err := <-doneCh: + if err != nil { + return nil, nil, fmt.Errorf("error during client: %v", err) + } + case <-ctx.Done(): + return nil, nil, fmt.Errorf("timeout: %v", ctx.Err()) + } - return localAddr.Port, xorAddr.Port, nil + return localAddr, &net.UDPAddr{IP: xorAddr.IP, Port: xorAddr.Port}, nil } diff --git a/pkg/transports/registration.go b/pkg/transports/registration.go deleted file mode 100644 index 20680ca1..00000000 --- a/pkg/transports/registration.go +++ /dev/null @@ -1,29 +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 - 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]Registration -} diff --git a/pkg/transports/wrapping/min/client.go b/pkg/transports/wrapping/min/client.go index e3474a37..2cd42d22 100644 --- a/pkg/transports/wrapping/min/client.go +++ b/pkg/transports/wrapping/min/client.go @@ -39,7 +39,7 @@ func (*ClientTransport) ID() pb.TransportType { return pb.TransportType_Min } -func (*ClientTransport) Prepare(dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) error { +func (*ClientTransport) Prepare(ctx context.Context, dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) error { return nil } @@ -64,12 +64,16 @@ func (t ClientTransport) ParseParams(data *anypb.Any) (any, error) { // SetParams allows the caller to set parameters associated with the transport, returning an // error if the provided generic message is not compatible. func (t *ClientTransport) SetParams(p any, unchecked ...bool) error { - params, ok := p.(*pb.GenericTransportParams) - if !ok { + var parsedParams *pb.GenericTransportParams + if params, ok := p.(*pb.GenericTransportParams); ok { + parsedParams = params + } else if p == nil { + parsedParams = &pb.GenericTransportParams{} + parsedParams.RandomizeDstPort = proto.Bool(true) + } else { return fmt.Errorf("unable to parse params") } - t.Parameters = params - + t.Parameters = parsedParams return nil } 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/min/min_test.go b/pkg/transports/wrapping/min/min_test.go index d92e4b52..fcffe5d1 100644 --- a/pkg/transports/wrapping/min/min_test.go +++ b/pkg/transports/wrapping/min/min_test.go @@ -12,15 +12,15 @@ import ( "google.golang.org/protobuf/types/known/anypb" "github.com/refraction-networking/conjure/internal/conjurepath" + tests "github.com/refraction-networking/conjure/internal/testutils" core "github.com/refraction-networking/conjure/pkg/core" "github.com/refraction-networking/conjure/pkg/transports" - "github.com/refraction-networking/conjure/pkg/transports/wrapping/internal/tests" pb "github.com/refraction-networking/conjure/proto" ) func TestSuccessfulWrap(t *testing.T) { root := conjurepath.Root - os.Setenv("PHANTOM_SUBNET_LOCATION", root+"/pkg/transports/wrapping/internal/tests/phantom_subnets.toml") + os.Setenv("PHANTOM_SUBNET_LOCATION", root+"/internal/test_assets/phantom_subnets.toml") var transport Transport manager := tests.SetupRegistrationManager(tests.Transport{Index: pb.TransportType_Min, Transport: transport}) diff --git a/pkg/transports/wrapping/obfs4/client.go b/pkg/transports/wrapping/obfs4/client.go index 2cafabe0..b1b0709d 100644 --- a/pkg/transports/wrapping/obfs4/client.go +++ b/pkg/transports/wrapping/obfs4/client.go @@ -39,7 +39,7 @@ func (*ClientTransport) ID() pb.TransportType { return pb.TransportType_Obfs4 } -func (*ClientTransport) Prepare(dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) error { +func (*ClientTransport) Prepare(ctx context.Context, dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) error { return nil } @@ -52,12 +52,16 @@ func (t *ClientTransport) GetParams() (proto.Message, error) { // SetParams allows the caller to set parameters associated with the transport, returning an // error if the provided generic message is not compatible. func (t *ClientTransport) SetParams(p any, unchecked ...bool) error { - params, ok := p.(*pb.GenericTransportParams) - if !ok { + var parsedParams *pb.GenericTransportParams + if params, ok := p.(*pb.GenericTransportParams); ok { + parsedParams = params + } else if p == nil { + parsedParams = &pb.GenericTransportParams{} + parsedParams.RandomizeDstPort = proto.Bool(true) + } else { return fmt.Errorf("unable to parse params") } - t.Parameters = params - + t.Parameters = parsedParams return nil } 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/obfs4/obfs4_test.go b/pkg/transports/wrapping/obfs4/obfs4_test.go index ce356be4..84aab1f3 100644 --- a/pkg/transports/wrapping/obfs4/obfs4_test.go +++ b/pkg/transports/wrapping/obfs4/obfs4_test.go @@ -14,9 +14,9 @@ import ( "time" "github.com/refraction-networking/conjure/internal/conjurepath" + tests "github.com/refraction-networking/conjure/internal/testutils" dd "github.com/refraction-networking/conjure/pkg/station/lib" "github.com/refraction-networking/conjure/pkg/transports" - "github.com/refraction-networking/conjure/pkg/transports/wrapping/internal/tests" pb "github.com/refraction-networking/conjure/proto" "google.golang.org/protobuf/types/known/anypb" @@ -55,7 +55,7 @@ func wrapConnection(conn net.Conn, nodeID, publicKey string, wrapped chan (net.C func TestSuccessfulWrap(t *testing.T) { var err error - testSubnetPath := conjurepath.Root + "/pkg/transports/wrapping/internal/tests/phantom_subnets.toml" + testSubnetPath := conjurepath.Root + "/internal/test_assets/phantom_subnets.toml" os.Setenv("PHANTOM_SUBNET_LOCATION", testSubnetPath) var transport Transport @@ -116,10 +116,7 @@ func TestSuccessfulWrap(t *testing.T) { // last connection. func TestSuccessfulWrapMulti(t *testing.T) { var err error - - cwd, err := os.Getwd() - require.Nil(t, err) - testSubnetPath := cwd + "/../internal/tests/phantom_subnets_min.toml" + testSubnetPath := conjurepath.Root + "/internal/test_assets/phantom_subnets_min.toml" os.Setenv("PHANTOM_SUBNET_LOCATION", testSubnetPath) sharedSecrets := [][]byte{ diff --git a/pkg/transports/wrapping/prefix/client.go b/pkg/transports/wrapping/prefix/client.go index bc909b58..0c1091d3 100644 --- a/pkg/transports/wrapping/prefix/client.go +++ b/pkg/transports/wrapping/prefix/client.go @@ -43,22 +43,24 @@ const ( // FlushAfterPrefix flush after the prefix before the tag (if possible), but not after tag // before client data is sent over the connection FlushAfterPrefix - // FlushAfterTag do not flush after the prefix before the tag, but do flush after tag before - // client data is sent over the connection - FlushAfterTag - // FlushAfterPrefixAndTag flush after both the prefix before the tag (if possible), as well as - // after the tag before client data is sent over the connection - FlushAfterPrefixAndTag ) // ClientParams are parameters available to a calling library to configure the Prefix transport // outside of the specific Prefix type ClientParams struct { RandomizeDstPort bool - FlushAfterPrefix int32 + FlushPolicy int32 PrefixID int32 } +func (c *ClientParams) String() string { + return fmt.Sprintf("RandomizeDstPort: %t, FlushPolicy: %d, Prefix: %d", c.RandomizeDstPort, c.FlushPolicy, c.PrefixID) +} + +func (c *ClientParams) GetParams() any { + return c +} + // Prefix struct used by, selected by, or given to the client. This interface allows for non-uniform // behavior like a rand prefix for example. type Prefix interface { @@ -92,7 +94,7 @@ func (*ClientTransport) ID() pb.TransportType { // Prepare lets the transport use the dialer to prepare. This is called before GetParams to let the // transport prepare stuff such as nat traversal. -func (*ClientTransport) Prepare(dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) error { +func (*ClientTransport) Prepare(ctx context.Context, dialer func(ctx context.Context, network, laddr, raddr string) (net.Conn, error)) error { return nil } @@ -108,12 +110,7 @@ func (t *ClientTransport) GetParams() (proto.Message, error) { } if t.parameters == nil { - id := int32(t.Prefix.ID()) - F := false - t.parameters = &pb.PrefixTransportParams{ - PrefixId: &id, - RandomizeDstPort: &F, - } + t.parameters = defaultParams() } return t.parameters, nil @@ -131,10 +128,31 @@ func (t ClientTransport) ParseParams(data *anypb.Any) (any, error) { return m, err } +// DefaultParams returns the default parameters for the transport +func DefaultParams() *ClientParams { + return &ClientParams{ + RandomizeDstPort: false, + FlushPolicy: DefaultFlush, + PrefixID: int32(Rand), + } +} + +// defaultParams returns the internal default parameters for the transport +func defaultParams() *pb.PrefixTransportParams { + return &pb.PrefixTransportParams{ + PrefixId: proto.Int32(int32(Rand)), + RandomizeDstPort: proto.Bool(false), + CustomFlushPolicy: proto.Int32(DefaultFlush), + } +} + // SetParams allows the caller to set parameters associated with the transport, returning an // error if the provided generic message is not compatible or the parameters are otherwise invalid func (t *ClientTransport) SetParams(p any, unchecked ...bool) error { if genericParams, ok := p.(*pb.GenericTransportParams); ok { + if t.parameters == nil { + t.parameters = defaultParams() + } t.parameters.RandomizeDstPort = proto.Bool(genericParams.GetRandomizeDstPort()) return nil } @@ -145,15 +163,17 @@ func (t *ClientTransport) SetParams(p any, unchecked ...bool) error { } else if clientParams, ok := p.(*ClientParams); ok { prefixParams = &pb.PrefixTransportParams{ PrefixId: &clientParams.PrefixID, - CustomFlushPolicy: &clientParams.FlushAfterPrefix, + CustomFlushPolicy: &clientParams.FlushPolicy, RandomizeDstPort: &clientParams.RandomizeDstPort, } } else if clientParams, ok := p.(ClientParams); ok { prefixParams = &pb.PrefixTransportParams{ PrefixId: &clientParams.PrefixID, - CustomFlushPolicy: &clientParams.FlushAfterPrefix, + CustomFlushPolicy: &clientParams.FlushPolicy, RandomizeDstPort: &clientParams.RandomizeDstPort, } + } else if p == nil { + prefixParams = defaultParams() } else { return fmt.Errorf("%w, incorrect param type", ErrBadParams) } @@ -256,6 +276,10 @@ func (t *ClientTransport) WrapConn(conn net.Conn) (net.Conn, error) { t.TagObfuscator = transports.CTRObfuscator{} } + if t.parameters == nil { + t.parameters = defaultParams() + } + obfuscatedID, err := t.TagObfuscator.Obfuscate(t.connectTag, t.stationPublicKey[:]) if err != nil { return nil, err @@ -270,13 +294,11 @@ func (t *ClientTransport) WrapConn(conn net.Conn) (net.Conn, error) { } // Maybe flush based on prefix spec and client param override - switch *t.parameters.CustomFlushPolicy { + switch t.parameters.GetCustomFlushPolicy() { case NoAddedFlush: break case FlushAfterPrefix: w.Flush() - case FlushAfterPrefixAndTag: - w.Flush() case DefaultFlush: fallthrough default: @@ -285,37 +307,22 @@ func (t *ClientTransport) WrapConn(conn net.Conn) (net.Conn, error) { break case FlushAfterPrefix: w.Flush() - case FlushAfterPrefixAndTag: - w.Flush() case DefaultFlush: fallthrough default: - break } } - if _, err := w.Write(obfuscatedID); err != nil { + n, err := w.Write(obfuscatedID) + if err != nil { return nil, err + } else if n != len(obfuscatedID) { + return nil, fmt.Errorf("failed to write all bytes of obfuscated ID") } - // Maybe flush based on prefix spec and client param override - switch *t.parameters.CustomFlushPolicy { - case NoAddedFlush: - break - case FlushAfterTag: - w.Flush() - case FlushAfterPrefixAndTag: - w.Flush() - case DefaultFlush: - fallthrough - default: - switch t.Prefix.FlushPolicy() { - case NoAddedFlush: - break - default: - w.Flush() - } - } + // We are **REQUIRED** to flush here otherwise the prefix and tag will not be written into + // the wrapped net.Conn So FlushAfterTag does not make much sense. + w.Flush() return conn, nil } diff --git a/pkg/transports/wrapping/prefix/prefix.go b/pkg/transports/wrapping/prefix/prefix.go index 20793576..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 } @@ -341,7 +342,7 @@ func (t Transport) tryFindReg(data *bytes.Buffer, originalDst net.IP, regManager // If the registration we found has no params specified (invalid and shouldn't have // been ingested) or if the prefix ID does not match the expected prefix, set the // err to return if we can't match any other prefixes. - eWrongPrefix = ErrIncorrectPrefix + eWrongPrefix = fmt.Errorf("%w: e %d != %d", ErrIncorrectPrefix, params.GetPrefixId(), id) continue } } @@ -353,7 +354,7 @@ func (t Transport) tryFindReg(data *bytes.Buffer, originalDst net.IP, regManager return reg, nil } - if err == transports.ErrNotTransport && eWrongPrefix == ErrIncorrectPrefix { + if errors.Is(err, transports.ErrNotTransport) && errors.Is(eWrongPrefix, ErrIncorrectPrefix) { // If we found a match and it was the only one that matched (i.e. none of the other prefixes // could possibly match even if we read more bytes). Then something went wrong and the // client is attempting to connect with the wrong prefix. diff --git a/pkg/transports/wrapping/prefix/prefix_test.go b/pkg/transports/wrapping/prefix/prefix_test.go index 6b7a3910..8016c5c2 100644 --- a/pkg/transports/wrapping/prefix/prefix_test.go +++ b/pkg/transports/wrapping/prefix/prefix_test.go @@ -6,23 +6,26 @@ import ( "encoding/hex" "errors" "io" + "net" "os" "testing" + "time" "github.com/stretchr/testify/require" "golang.org/x/crypto/curve25519" "github.com/refraction-networking/conjure/internal/conjurepath" + tests "github.com/refraction-networking/conjure/internal/testutils" "github.com/refraction-networking/conjure/pkg/core" "github.com/refraction-networking/conjure/pkg/transports" - "github.com/refraction-networking/conjure/pkg/transports/wrapping/internal/tests" + pb "github.com/refraction-networking/conjure/proto" "github.com/refraction-networking/ed25519" "github.com/refraction-networking/ed25519/extra25519" ) func TestSuccessfulWrap(t *testing.T) { - testSubnetPath := conjurepath.Root + "/pkg/station/lib/test/phantom_subnets.toml" + testSubnetPath := conjurepath.Root + "/internal/test_assets/phantom_subnets.toml" os.Setenv("PHANTOM_SUBNET_LOCATION", testSubnetPath) _, private, _ := ed25519.GenerateKey(rand.Reader) @@ -64,11 +67,10 @@ func TestSuccessfulWrap(t *testing.T) { require.Nil(t, err) var buf [4096]byte - var buffer bytes.Buffer n, _ := sfp.Read(buf[:]) - buffer.Write(buf[:n]) + buffer := bytes.NewBuffer(buf[:n]) - _, wrapped, err := transport.WrapConnection(&buffer, sfp, reg.PhantomIp, manager) + _, wrapped, err := transport.WrapConnection(buffer, sfp, reg.PhantomIp, manager) if id != idx { require.ErrorIs(t, err, ErrIncorrectPrefix) continue @@ -399,3 +401,90 @@ func TestSuccessfulWrapBase64(t *testing.T) { } */ + +// Test End to End client WrapConn to Server WrapConnection +func TestPrefixEndToEnd(t *testing.T) { + testSubnetPath := conjurepath.Root + "/internal/test_assets/phantom_subnets.toml" + os.Setenv("PHANTOM_SUBNET_LOCATION", testSubnetPath) + + _, private, _ := ed25519.GenerateKey(rand.Reader) + + var curve25519Public, curve25519Private [32]byte + extra25519.PrivateKeyToCurve25519(&curve25519Private, private) + curve25519.ScalarBaseMult(&curve25519Public, &curve25519Private) + + var transport = Transport{ + TagObfuscator: transports.CTRObfuscator{}, + Privkey: curve25519Private, + SupportedPrefixes: defaultPrefixes, + } + message := []byte(`test message!`) + + for _, flushPolicy := range []int32{DefaultFlush, NoAddedFlush, FlushAfterPrefix} { + for idx := range defaultPrefixes { + + t.Logf("testing prefix %d, %s", idx, idx.Name()) + + var p int32 = int32(idx) + params := &pb.PrefixTransportParams{PrefixId: &p, CustomFlushPolicy: &flushPolicy} + manager := tests.SetupRegistrationManager(tests.Transport{Index: pb.TransportType_Prefix, Transport: transport}) + c2p, sfp, reg := tests.SetupPhantomConnections(manager, pb.TransportType_Prefix, params, uint(core.CurrentClientLibraryVersion())) + defer c2p.Close() + defer sfp.Close() + require.NotNil(t, reg) + sch := make(chan struct{}, 1) + + go func() { + var c net.Conn + var err error + var buf [4096]byte + received := bytes.Buffer{} + + sch <- struct{}{} + for { + n, err := sfp.Read(buf[:]) + if err != nil { + t.Errorf("error reading from server connection after %d bytes %s", n, err) + t.Fail() + return + } + + received.Write(buf[:n]) + _, c, err = transport.WrapConnection(&received, sfp, reg.PhantomIp, manager) + if err == nil { + break + } else if !errors.Is(err, transports.ErrTryAgain) { + t.Errorf("error getting wrapped connection %s - expected %s, %d", err, idx.Name(), flushPolicy) + t.Fail() + return + } + } + + recvBuf := make([]byte, len(message)) + _, err = io.ReadFull(c, recvBuf) + require.Nil(t, err, "failed reading from server connection") + _, err = c.Write(recvBuf) + require.Nil(t, err, "failed writing to server connection") + }() + + <-sch + clientPrefix, err := TryFromID(PrefixID(p)) + require.Nil(t, err) + ClientTransport := &ClientTransport{Prefix: clientPrefix, parameters: params} + err = ClientTransport.PrepareKeys(curve25519Public, reg.Keys.SharedSecret, reg.Keys.TransportReader) + require.Nil(t, err) + clientConn, err := ClientTransport.WrapConn(c2p) + require.Nil(t, err, "error getting wrapped connection") + + err = clientConn.SetDeadline(time.Now().Add(3 * time.Second)) + require.Nil(t, err, "error setting deadline") + + _, err = clientConn.Write(message) + require.Nil(t, err, "failed writing to client connection") + cbuf := make([]byte, len(message)) + _, err = io.ReadFull(clientConn, cbuf) + require.Nil(t, err, "failed reading from client connection") + require.True(t, bytes.Equal(message, cbuf), "%s\n%s", string(message), string(cbuf)) + } + } +} diff --git a/proto/signalling.pb.go b/proto/signalling.pb.go index 2455fc3d..02784c36 100644 --- a/proto/signalling.pb.go +++ b/proto/signalling.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.27.1 -// protoc v3.12.4 +// protoc-gen-go v1.30.0 +// protoc v4.24.2 // source: signalling.proto // TODO: We're using proto2 because it's the default on Ubuntu 16.04. @@ -11,9 +11,9 @@ package proto import ( - any "github.com/golang/protobuf/ptypes/any" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + anypb "google.golang.org/protobuf/types/known/anypb" reflect "reflect" sync "sync" ) @@ -1317,19 +1317,75 @@ func (x *WebRTCSignal) GetSdp() *WebRTCSDP { return nil } +type Addr struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IP []byte `protobuf:"bytes,1,opt,name=IP" json:"IP,omitempty"` + Port *uint32 `protobuf:"varint,2,opt,name=Port" json:"Port,omitempty"` +} + +func (x *Addr) Reset() { + *x = Addr{} + if protoimpl.UnsafeEnabled { + mi := &file_signalling_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Addr) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Addr) ProtoMessage() {} + +func (x *Addr) ProtoReflect() protoreflect.Message { + mi := &file_signalling_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Addr.ProtoReflect.Descriptor instead. +func (*Addr) Descriptor() ([]byte, []int) { + return file_signalling_proto_rawDescGZIP(), []int{10} +} + +func (x *Addr) GetIP() []byte { + if x != nil { + return x.IP + } + return nil +} + +func (x *Addr) GetPort() uint32 { + if x != nil && x.Port != nil { + return *x.Port + } + return 0 +} + type DTLSTransportParams struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SrcPort *uint32 `protobuf:"varint,1,opt,name=src_port,json=srcPort" json:"src_port,omitempty"` - RandomizeDstPort *bool `protobuf:"varint,2,opt,name=randomize_dst_port,json=randomizeDstPort" json:"randomize_dst_port,omitempty"` + SrcAddr4 *Addr `protobuf:"bytes,1,opt,name=src_addr4,json=srcAddr4" json:"src_addr4,omitempty"` + SrcAddr6 *Addr `protobuf:"bytes,2,opt,name=src_addr6,json=srcAddr6" json:"src_addr6,omitempty"` + RandomizeDstPort *bool `protobuf:"varint,3,opt,name=randomize_dst_port,json=randomizeDstPort" json:"randomize_dst_port,omitempty"` } func (x *DTLSTransportParams) Reset() { *x = DTLSTransportParams{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[10] + mi := &file_signalling_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1342,7 +1398,7 @@ func (x *DTLSTransportParams) String() string { func (*DTLSTransportParams) ProtoMessage() {} func (x *DTLSTransportParams) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[10] + mi := &file_signalling_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1355,14 +1411,21 @@ func (x *DTLSTransportParams) ProtoReflect() protoreflect.Message { // Deprecated: Use DTLSTransportParams.ProtoReflect.Descriptor instead. func (*DTLSTransportParams) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{10} + return file_signalling_proto_rawDescGZIP(), []int{11} } -func (x *DTLSTransportParams) GetSrcPort() uint32 { - if x != nil && x.SrcPort != nil { - return *x.SrcPort +func (x *DTLSTransportParams) GetSrcAddr4() *Addr { + if x != nil { + return x.SrcAddr4 } - return 0 + return nil +} + +func (x *DTLSTransportParams) GetSrcAddr6() *Addr { + if x != nil { + return x.SrcAddr6 + } + return nil } func (x *DTLSTransportParams) GetRandomizeDstPort() bool { @@ -1398,7 +1461,7 @@ type StationToClient struct { func (x *StationToClient) Reset() { *x = StationToClient{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[11] + mi := &file_signalling_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1411,7 +1474,7 @@ func (x *StationToClient) String() string { func (*StationToClient) ProtoMessage() {} func (x *StationToClient) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[11] + mi := &file_signalling_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1424,7 +1487,7 @@ func (x *StationToClient) ProtoReflect() protoreflect.Message { // Deprecated: Use StationToClient.ProtoReflect.Descriptor instead. func (*StationToClient) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{11} + return file_signalling_proto_rawDescGZIP(), []int{12} } func (x *StationToClient) GetProtocolVersion() uint32 { @@ -1491,7 +1554,7 @@ type RegistrationFlags struct { func (x *RegistrationFlags) Reset() { *x = RegistrationFlags{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[12] + mi := &file_signalling_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1504,7 +1567,7 @@ func (x *RegistrationFlags) String() string { func (*RegistrationFlags) ProtoMessage() {} func (x *RegistrationFlags) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[12] + mi := &file_signalling_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1517,7 +1580,7 @@ func (x *RegistrationFlags) ProtoReflect() protoreflect.Message { // Deprecated: Use RegistrationFlags.ProtoReflect.Descriptor instead. func (*RegistrationFlags) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{12} + return file_signalling_proto_rawDescGZIP(), []int{13} } func (x *RegistrationFlags) GetUploadOnly() bool { @@ -1582,7 +1645,7 @@ type ClientToStation struct { Stats *SessionStats `protobuf:"bytes,11,opt,name=stats" json:"stats,omitempty"` // NullTransport, MinTransport, Obfs4Transport, etc. Transport type we want from phantom proxy Transport *TransportType `protobuf:"varint,12,opt,name=transport,enum=proto.TransportType" json:"transport,omitempty"` - TransportParams *any.Any `protobuf:"bytes,13,opt,name=transport_params,json=transportParams" json:"transport_params,omitempty"` + TransportParams *anypb.Any `protobuf:"bytes,13,opt,name=transport_params,json=transportParams" json:"transport_params,omitempty"` // Station is only required to check this variable during session initialization. // If set, station must facilitate connection to said target by itself, i.e. write into squid // socket an HTTP/SOCKS/any other connection request. @@ -1607,7 +1670,7 @@ type ClientToStation struct { func (x *ClientToStation) Reset() { *x = ClientToStation{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[13] + mi := &file_signalling_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1620,7 +1683,7 @@ func (x *ClientToStation) String() string { func (*ClientToStation) ProtoMessage() {} func (x *ClientToStation) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[13] + mi := &file_signalling_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1633,7 +1696,7 @@ func (x *ClientToStation) ProtoReflect() protoreflect.Message { // Deprecated: Use ClientToStation.ProtoReflect.Descriptor instead. func (*ClientToStation) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{13} + return file_signalling_proto_rawDescGZIP(), []int{14} } func (x *ClientToStation) GetProtocolVersion() uint32 { @@ -1699,7 +1762,7 @@ func (x *ClientToStation) GetTransport() TransportType { return TransportType_Null } -func (x *ClientToStation) GetTransportParams() *any.Any { +func (x *ClientToStation) GetTransportParams() *anypb.Any { if x != nil { return x.TransportParams } @@ -1775,7 +1838,7 @@ type PrefixTransportParams struct { func (x *PrefixTransportParams) Reset() { *x = PrefixTransportParams{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[14] + mi := &file_signalling_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1788,7 +1851,7 @@ func (x *PrefixTransportParams) String() string { func (*PrefixTransportParams) ProtoMessage() {} func (x *PrefixTransportParams) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[14] + mi := &file_signalling_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1801,7 +1864,7 @@ func (x *PrefixTransportParams) ProtoReflect() protoreflect.Message { // Deprecated: Use PrefixTransportParams.ProtoReflect.Descriptor instead. func (*PrefixTransportParams) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{14} + return file_signalling_proto_rawDescGZIP(), []int{15} } func (x *PrefixTransportParams) GetPrefixId() int32 { @@ -1846,7 +1909,7 @@ type GenericTransportParams struct { func (x *GenericTransportParams) Reset() { *x = GenericTransportParams{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[15] + mi := &file_signalling_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1859,7 +1922,7 @@ func (x *GenericTransportParams) String() string { func (*GenericTransportParams) ProtoMessage() {} func (x *GenericTransportParams) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[15] + mi := &file_signalling_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1872,7 +1935,7 @@ func (x *GenericTransportParams) ProtoReflect() protoreflect.Message { // Deprecated: Use GenericTransportParams.ProtoReflect.Descriptor instead. func (*GenericTransportParams) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{15} + return file_signalling_proto_rawDescGZIP(), []int{16} } func (x *GenericTransportParams) GetRandomizeDstPort() bool { @@ -1912,7 +1975,7 @@ type C2SWrapper struct { func (x *C2SWrapper) Reset() { *x = C2SWrapper{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[16] + mi := &file_signalling_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1925,7 +1988,7 @@ func (x *C2SWrapper) String() string { func (*C2SWrapper) ProtoMessage() {} func (x *C2SWrapper) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[16] + mi := &file_signalling_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1938,7 +2001,7 @@ func (x *C2SWrapper) ProtoReflect() protoreflect.Message { // Deprecated: Use C2SWrapper.ProtoReflect.Descriptor instead. func (*C2SWrapper) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{16} + return file_signalling_proto_rawDescGZIP(), []int{17} } func (x *C2SWrapper) GetSharedSecret() []byte { @@ -2014,7 +2077,7 @@ type SessionStats struct { func (x *SessionStats) Reset() { *x = SessionStats{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[17] + mi := &file_signalling_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2027,7 +2090,7 @@ func (x *SessionStats) String() string { func (*SessionStats) ProtoMessage() {} func (x *SessionStats) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[17] + mi := &file_signalling_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2040,7 +2103,7 @@ func (x *SessionStats) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionStats.ProtoReflect.Descriptor instead. func (*SessionStats) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{17} + return file_signalling_proto_rawDescGZIP(), []int{18} } func (x *SessionStats) GetFailedDecoysAmount() uint32 { @@ -2095,7 +2158,7 @@ type StationToDetector struct { func (x *StationToDetector) Reset() { *x = StationToDetector{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[18] + mi := &file_signalling_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2108,7 +2171,7 @@ func (x *StationToDetector) String() string { func (*StationToDetector) ProtoMessage() {} func (x *StationToDetector) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[18] + mi := &file_signalling_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2121,7 +2184,7 @@ func (x *StationToDetector) ProtoReflect() protoreflect.Message { // Deprecated: Use StationToDetector.ProtoReflect.Descriptor instead. func (*StationToDetector) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{18} + return file_signalling_proto_rawDescGZIP(), []int{19} } func (x *StationToDetector) GetPhantomIp() string { @@ -2192,13 +2255,13 @@ type RegistrationResponse struct { // ClientConf field (optional) ClientConf *ClientConf `protobuf:"bytes,6,opt,name=clientConf" json:"clientConf,omitempty"` // Transport Params to if `allow_registrar_overrides` is set. - TransportParams *any.Any `protobuf:"bytes,10,opt,name=transport_params,json=transportParams" json:"transport_params,omitempty"` + TransportParams *anypb.Any `protobuf:"bytes,10,opt,name=transport_params,json=transportParams" json:"transport_params,omitempty"` } func (x *RegistrationResponse) Reset() { *x = RegistrationResponse{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[19] + mi := &file_signalling_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2211,7 +2274,7 @@ func (x *RegistrationResponse) String() string { func (*RegistrationResponse) ProtoMessage() {} func (x *RegistrationResponse) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[19] + mi := &file_signalling_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2224,7 +2287,7 @@ func (x *RegistrationResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegistrationResponse.ProtoReflect.Descriptor instead. func (*RegistrationResponse) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{19} + return file_signalling_proto_rawDescGZIP(), []int{20} } func (x *RegistrationResponse) GetIpv4Addr() uint32 { @@ -2269,7 +2332,7 @@ func (x *RegistrationResponse) GetClientConf() *ClientConf { return nil } -func (x *RegistrationResponse) GetTransportParams() *any.Any { +func (x *RegistrationResponse) GetTransportParams() *anypb.Any { if x != nil { return x.TransportParams } @@ -2290,7 +2353,7 @@ type DnsResponse struct { func (x *DnsResponse) Reset() { *x = DnsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_signalling_proto_msgTypes[20] + mi := &file_signalling_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2303,7 +2366,7 @@ func (x *DnsResponse) String() string { func (*DnsResponse) ProtoMessage() {} func (x *DnsResponse) ProtoReflect() protoreflect.Message { - mi := &file_signalling_proto_msgTypes[20] + mi := &file_signalling_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2316,7 +2379,7 @@ func (x *DnsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DnsResponse.ProtoReflect.Descriptor instead. func (*DnsResponse) Descriptor() ([]byte, []int) { - return file_signalling_proto_rawDescGZIP(), []int{20} + return file_signalling_proto_rawDescGZIP(), []int{21} } func (x *DnsResponse) GetSuccess() bool { @@ -2431,261 +2494,268 @@ var file_signalling_proto_rawDesc = []byte{ 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x73, 0x65, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x03, 0x73, 0x64, 0x70, 0x18, 0x02, 0x20, 0x02, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x57, 0x65, 0x62, 0x52, 0x54, 0x43, 0x53, 0x44, 0x50, 0x52, 0x03, 0x73, 0x64, 0x70, - 0x22, 0x5e, 0x0a, 0x13, 0x44, 0x54, 0x4c, 0x53, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, - 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x70, - 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x72, 0x63, 0x50, 0x6f, - 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x5f, - 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, - 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x44, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, - 0x22, 0xc2, 0x02, 0x0a, 0x0f, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, - 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x40, 0x0a, 0x10, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x53, 0x32, 0x43, 0x5f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x0f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x32, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x6e, 0x66, 0x6f, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x34, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x5f, 0x72, 0x65, 0x61, - 0x73, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x53, 0x32, 0x43, - 0x52, 0x09, 0x65, 0x72, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x74, - 0x6d, 0x70, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0a, 0x74, 0x6d, 0x70, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x12, 0x1d, 0x0a, 0x0a, - 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, - 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, - 0x64, 0x64, 0x69, 0x6e, 0x67, 0x22, 0xaf, 0x01, 0x0a, 0x11, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x75, - 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0a, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, - 0x64, 0x61, 0x72, 0x6b, 0x5f, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x09, 0x64, 0x61, 0x72, 0x6b, 0x44, 0x65, 0x63, 0x6f, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x70, - 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x17, - 0x0a, 0x07, 0x75, 0x73, 0x65, 0x5f, 0x54, 0x49, 0x4c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x06, 0x75, 0x73, 0x65, 0x54, 0x49, 0x4c, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x65, 0x73, 0x63, - 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x70, 0x72, 0x65, - 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x22, 0xa8, 0x06, 0x0a, 0x0f, 0x43, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x54, 0x6f, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x15, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x5f, - 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x4c, 0x69, 0x73, 0x74, - 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x10, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x32, 0x53, - 0x5f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, - 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0a, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x2c, 0x0a, - 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x69, 0x62, 0x5f, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x4c, 0x69, 0x62, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x1b, 0x64, - 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x72, - 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x19, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x61, 0x72, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x66, - 0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x73, 0x18, 0x0a, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x0c, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x44, 0x65, 0x63, 0x6f, 0x79, 0x73, - 0x12, 0x29, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, - 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x12, 0x32, 0x0a, 0x09, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, - 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, - 0x3f, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, 0x61, 0x72, - 0x61, 0x6d, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, - 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, - 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x74, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x37, 0x0a, 0x18, 0x6d, 0x61, 0x73, 0x6b, 0x65, - 0x64, 0x5f, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x6d, 0x61, 0x73, 0x6b, 0x65, - 0x64, 0x44, 0x65, 0x63, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x1d, 0x0a, 0x0a, 0x76, 0x36, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x16, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x76, 0x36, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x12, - 0x1d, 0x0a, 0x0a, 0x76, 0x34, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x17, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x09, 0x76, 0x34, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x2e, - 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x38, - 0x0a, 0x0d, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x18, - 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x57, 0x65, - 0x62, 0x52, 0x54, 0x43, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x0c, 0x77, 0x65, 0x62, 0x72, - 0x74, 0x63, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, - 0x69, 0x6e, 0x67, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, - 0x6e, 0x67, 0x22, 0xaa, 0x01, 0x0a, 0x15, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1b, 0x0a, 0x09, - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x08, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, - 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, - 0x78, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x66, 0x6c, 0x75, 0x73, - 0x68, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, - 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x5f, 0x64, - 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, - 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x44, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x22, - 0x46, 0x0a, 0x16, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, - 0x6f, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x61, 0x6e, - 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x5f, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, - 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, - 0x44, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x22, 0xc2, 0x03, 0x0a, 0x0a, 0x43, 0x32, 0x53, 0x57, - 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, - 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, - 0x68, 0x61, 0x72, 0x65, 0x64, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x49, 0x0a, 0x14, 0x72, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x79, 0x6c, - 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x13, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, - 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x4a, 0x0a, 0x13, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x12, - 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x12, 0x31, 0x0a, 0x14, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x13, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x5f, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x64, 0x65, - 0x63, 0x6f, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x50, 0x0a, 0x15, 0x72, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x14, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x0c, - 0x52, 0x65, 0x67, 0x52, 0x65, 0x73, 0x70, 0x42, 0x79, 0x74, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0c, 0x52, 0x65, 0x67, 0x52, 0x65, 0x73, 0x70, 0x42, 0x79, 0x74, 0x65, 0x73, - 0x12, 0x2a, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x52, 0x65, 0x73, 0x70, 0x53, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x52, 0x65, 0x67, 0x52, - 0x65, 0x73, 0x70, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xdd, 0x01, 0x0a, - 0x0c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x30, 0x0a, - 0x14, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x73, 0x5f, 0x61, - 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x66, 0x61, 0x69, - 0x6c, 0x65, 0x64, 0x44, 0x65, 0x63, 0x6f, 0x79, 0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x31, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, - 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x72, 0x74, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x72, 0x74, 0x74, 0x54, - 0x6f, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6c, 0x73, 0x5f, - 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x18, 0x26, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, - 0x74, 0x6c, 0x73, 0x54, 0x6f, 0x44, 0x65, 0x63, 0x6f, 0x79, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x63, - 0x70, 0x5f, 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x18, 0x27, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0a, 0x74, 0x63, 0x70, 0x54, 0x6f, 0x44, 0x65, 0x63, 0x6f, 0x79, 0x22, 0x82, 0x02, 0x0a, - 0x11, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x68, 0x61, 0x6e, 0x74, 0x6f, 0x6d, 0x5f, 0x69, 0x70, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x68, 0x61, 0x6e, 0x74, 0x6f, 0x6d, 0x49, - 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x70, 0x12, 0x1d, - 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4e, 0x73, 0x12, 0x36, 0x0a, - 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, - 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, - 0x12, 0x19, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0b, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x07, 0x73, 0x72, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x24, 0x0a, 0x05, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x49, 0x50, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0x97, 0x02, 0x0a, 0x14, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x70, - 0x76, 0x34, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x07, 0x52, 0x08, 0x69, 0x70, - 0x76, 0x34, 0x61, 0x64, 0x64, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x70, 0x76, 0x36, 0x61, 0x64, - 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x69, 0x70, 0x76, 0x36, 0x61, 0x64, - 0x64, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x22, 0x0a, - 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x61, 0x6e, 0x64, 0x6f, - 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x31, 0x0a, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x52, 0x0a, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x3f, 0x0a, 0x10, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, - 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0xac, 0x01, 0x0a, 0x0b, - 0x44, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, - 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x63, - 0x6f, 0x6e, 0x66, 0x5f, 0x6f, 0x75, 0x74, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x63, 0x6f, 0x6e, 0x66, 0x4f, 0x75, - 0x74, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x52, 0x0a, 0x16, 0x62, 0x69, 0x64, 0x69, 0x72, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x52, 0x15, 0x62, 0x69, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x2b, 0x0a, 0x07, 0x4b, 0x65, - 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x47, 0x43, 0x4d, - 0x5f, 0x31, 0x32, 0x38, 0x10, 0x5a, 0x12, 0x0f, 0x0a, 0x0b, 0x41, 0x45, 0x53, 0x5f, 0x47, 0x43, - 0x4d, 0x5f, 0x32, 0x35, 0x36, 0x10, 0x5b, 0x2a, 0x29, 0x0a, 0x0c, 0x44, 0x6e, 0x73, 0x52, 0x65, - 0x67, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, 0x01, - 0x12, 0x07, 0x0a, 0x03, 0x44, 0x4f, 0x54, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x44, 0x4f, 0x48, - 0x10, 0x03, 0x2a, 0xe7, 0x01, 0x0a, 0x0e, 0x43, 0x32, 0x53, 0x5f, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x32, 0x53, 0x5f, 0x4e, 0x4f, 0x5f, - 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x43, 0x32, 0x53, 0x5f, + 0x22, 0x2a, 0x0a, 0x04, 0x41, 0x64, 0x64, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x50, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x49, 0x50, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x6f, 0x72, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x22, 0x97, 0x01, 0x0a, + 0x13, 0x44, 0x54, 0x4c, 0x53, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x12, 0x28, 0x0a, 0x09, 0x73, 0x72, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x41, 0x64, 0x64, 0x72, 0x52, 0x08, 0x73, 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, 0x34, 0x12, 0x28, + 0x0a, 0x09, 0x73, 0x72, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x36, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x52, 0x08, + 0x73, 0x72, 0x63, 0x41, 0x64, 0x64, 0x72, 0x36, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x61, 0x6e, 0x64, + 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x5f, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x44, + 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x22, 0xc2, 0x02, 0x0a, 0x0f, 0x53, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x54, 0x6f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x10, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x32, 0x43, 0x5f, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x52, + 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x34, 0x0a, 0x0a, 0x65, + 0x72, 0x72, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, + 0x73, 0x6f, 0x6e, 0x53, 0x32, 0x43, 0x52, 0x09, 0x65, 0x72, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, + 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6d, 0x70, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x6d, 0x70, 0x42, 0x61, 0x63, 0x6b, 0x6f, + 0x66, 0x66, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x64, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x22, 0xaf, 0x01, 0x0a, 0x11, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x61, 0x67, + 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4f, 0x6e, + 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x72, 0x6b, 0x5f, 0x64, 0x65, 0x63, 0x6f, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x64, 0x61, 0x72, 0x6b, 0x44, 0x65, 0x63, 0x6f, + 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x48, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x5f, 0x54, 0x49, 0x4c, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x75, 0x73, 0x65, 0x54, 0x49, 0x4c, 0x12, 0x1e, 0x0a, + 0x0a, 0x70, 0x72, 0x65, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0a, 0x70, 0x72, 0x65, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x22, 0xa8, 0x06, + 0x0a, 0x0f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x15, + 0x64, 0x65, 0x63, 0x6f, 0x79, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x64, 0x65, 0x63, + 0x6f, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x40, 0x0a, 0x10, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x43, 0x32, 0x53, 0x5f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x0f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x73, 0x79, 0x6e, + 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, + 0x79, 0x6e, 0x63, 0x12, 0x2c, 0x0a, 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x69, + 0x62, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x10, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x62, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x3e, 0x0a, 0x1b, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x61, 0x72, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x72, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, + 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x64, 0x65, 0x63, 0x6f, + 0x79, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, + 0x44, 0x65, 0x63, 0x6f, 0x79, 0x73, 0x12, 0x29, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18, + 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, + 0x73, 0x12, 0x32, 0x0a, 0x09, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0c, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x3f, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, + 0x72, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x74, + 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x37, 0x0a, + 0x18, 0x6d, 0x61, 0x73, 0x6b, 0x65, 0x64, 0x5f, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x5f, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x15, 0x6d, 0x61, 0x73, 0x6b, 0x65, 0x64, 0x44, 0x65, 0x63, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x76, 0x36, 0x5f, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x76, 0x36, 0x53, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x76, 0x34, 0x5f, 0x73, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x76, 0x34, 0x53, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x12, 0x2e, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x18, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x52, 0x05, 0x66, + 0x6c, 0x61, 0x67, 0x73, 0x12, 0x38, 0x0a, 0x0d, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x5f, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x57, 0x65, 0x62, 0x52, 0x54, 0x43, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, + 0x52, 0x0c, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x12, 0x18, + 0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x64, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x22, 0xaa, 0x01, 0x0a, 0x15, 0x50, 0x72, 0x65, + 0x66, 0x69, 0x78, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, + 0x6d, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x49, 0x64, 0x12, + 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x75, 0x73, 0x74, 0x6f, + 0x6d, 0x5f, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x46, 0x6c, 0x75, 0x73, + 0x68, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x61, 0x6e, 0x64, 0x6f, + 0x6d, 0x69, 0x7a, 0x65, 0x5f, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0d, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x44, 0x73, + 0x74, 0x50, 0x6f, 0x72, 0x74, 0x22, 0x46, 0x0a, 0x16, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, + 0x2c, 0x0a, 0x12, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x5f, 0x64, 0x73, 0x74, + 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, 0x61, 0x6e, + 0x64, 0x6f, 0x6d, 0x69, 0x7a, 0x65, 0x44, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x22, 0xc2, 0x03, + 0x0a, 0x0a, 0x43, 0x32, 0x53, 0x57, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, + 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x53, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x12, 0x49, 0x0a, 0x14, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x6f, + 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x4a, 0x0a, 0x13, + 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x12, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x31, 0x0a, 0x14, 0x72, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x64, + 0x65, 0x63, 0x6f, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0c, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x50, 0x0a, 0x15, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x14, 0x72, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x52, 0x65, 0x73, 0x70, 0x42, 0x79, 0x74, + 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x52, 0x65, 0x67, 0x52, 0x65, 0x73, + 0x70, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x52, 0x65, 0x73, + 0x70, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x10, 0x52, 0x65, 0x67, 0x52, 0x65, 0x73, 0x70, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x22, 0xdd, 0x01, 0x0a, 0x0c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x64, 0x65, + 0x63, 0x6f, 0x79, 0x73, 0x5f, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x12, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x44, 0x65, 0x63, 0x6f, 0x79, 0x73, 0x41, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x31, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x18, 0x1f, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x54, + 0x6f, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x72, 0x74, 0x74, 0x5f, + 0x74, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x0c, 0x72, 0x74, 0x74, 0x54, 0x6f, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, + 0x0a, 0x0c, 0x74, 0x6c, 0x73, 0x5f, 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x63, 0x6f, 0x79, 0x18, 0x26, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x6c, 0x73, 0x54, 0x6f, 0x44, 0x65, 0x63, 0x6f, 0x79, + 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x63, 0x70, 0x5f, 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x63, 0x6f, 0x79, + 0x18, 0x27, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x63, 0x70, 0x54, 0x6f, 0x44, 0x65, 0x63, + 0x6f, 0x79, 0x22, 0x82, 0x02, 0x0a, 0x11, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, + 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x68, 0x61, 0x6e, + 0x74, 0x6f, 0x6d, 0x5f, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x68, + 0x61, 0x6e, 0x74, 0x6f, 0x6d, 0x49, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x5f, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x49, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, + 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, + 0x74, 0x4e, 0x73, 0x12, 0x36, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x64, + 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, + 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x73, 0x72, 0x63, 0x50, 0x6f, 0x72, + 0x74, 0x12, 0x24, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x50, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x52, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x97, 0x02, 0x0a, 0x14, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x70, 0x76, 0x34, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x07, 0x52, 0x08, 0x69, 0x70, 0x76, 0x34, 0x61, 0x64, 0x64, 0x72, 0x12, 0x1a, 0x0a, 0x08, + 0x69, 0x70, 0x76, 0x36, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, + 0x69, 0x70, 0x76, 0x36, 0x61, 0x64, 0x64, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, + 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x64, 0x73, 0x74, 0x50, + 0x6f, 0x72, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x52, 0x61, 0x6e, + 0x64, 0x6f, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x31, 0x0a, + 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x43, 0x6f, 0x6e, 0x66, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, + 0x12, 0x3f, 0x0a, 0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x70, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, + 0x52, 0x0f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x73, 0x22, 0xac, 0x01, 0x0a, 0x0b, 0x44, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x6f, 0x75, 0x74, 0x64, 0x61, 0x74, + 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x63, 0x6f, 0x6e, 0x66, 0x4f, 0x75, 0x74, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x52, 0x0a, 0x16, + 0x62, 0x69, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x15, 0x62, 0x69, 0x64, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x2a, 0x2b, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x41, + 0x45, 0x53, 0x5f, 0x47, 0x43, 0x4d, 0x5f, 0x31, 0x32, 0x38, 0x10, 0x5a, 0x12, 0x0f, 0x0a, 0x0b, + 0x41, 0x45, 0x53, 0x5f, 0x47, 0x43, 0x4d, 0x5f, 0x32, 0x35, 0x36, 0x10, 0x5b, 0x2a, 0x29, 0x0a, + 0x0c, 0x44, 0x6e, 0x73, 0x52, 0x65, 0x67, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x07, 0x0a, + 0x03, 0x55, 0x44, 0x50, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x44, 0x4f, 0x54, 0x10, 0x02, 0x12, + 0x07, 0x0a, 0x03, 0x44, 0x4f, 0x48, 0x10, 0x03, 0x2a, 0xe7, 0x01, 0x0a, 0x0e, 0x43, 0x32, 0x53, + 0x5f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x11, 0x0a, 0x0d, 0x43, + 0x32, 0x53, 0x5f, 0x4e, 0x4f, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x00, 0x12, 0x14, + 0x0a, 0x10, 0x43, 0x32, 0x53, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, + 0x49, 0x54, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x32, 0x53, 0x5f, 0x53, 0x45, 0x53, 0x53, + 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x56, 0x45, 0x52, 0x54, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x10, + 0x0b, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x32, 0x53, 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x5f, + 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x43, + 0x32, 0x53, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, + 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x43, 0x32, 0x53, 0x5f, 0x59, 0x49, 0x45, 0x4c, 0x44, 0x5f, + 0x55, 0x50, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x32, 0x53, 0x5f, + 0x41, 0x43, 0x51, 0x55, 0x49, 0x52, 0x45, 0x5f, 0x55, 0x50, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x05, + 0x12, 0x20, 0x0a, 0x1c, 0x43, 0x32, 0x53, 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x5f, 0x55, + 0x50, 0x4c, 0x4f, 0x41, 0x44, 0x4f, 0x4e, 0x4c, 0x59, 0x5f, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x4e, + 0x10, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x32, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, + 0xff, 0x01, 0x2a, 0x98, 0x01, 0x0a, 0x0e, 0x53, 0x32, 0x43, 0x5f, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x32, 0x43, 0x5f, 0x4e, 0x4f, 0x5f, + 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x32, 0x43, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x10, 0x01, 0x12, 0x1b, - 0x0a, 0x17, 0x43, 0x32, 0x53, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, - 0x56, 0x45, 0x52, 0x54, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x10, 0x0b, 0x12, 0x18, 0x0a, 0x14, 0x43, - 0x32, 0x53, 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x5f, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x4e, - 0x45, 0x43, 0x54, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x32, 0x53, 0x5f, 0x53, 0x45, 0x53, - 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, - 0x43, 0x32, 0x53, 0x5f, 0x59, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x55, 0x50, 0x4c, 0x4f, 0x41, 0x44, - 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x32, 0x53, 0x5f, 0x41, 0x43, 0x51, 0x55, 0x49, 0x52, - 0x45, 0x5f, 0x55, 0x50, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x05, 0x12, 0x20, 0x0a, 0x1c, 0x43, 0x32, - 0x53, 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x5f, 0x55, 0x50, 0x4c, 0x4f, 0x41, 0x44, 0x4f, - 0x4e, 0x4c, 0x59, 0x5f, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x4e, 0x10, 0x06, 0x12, 0x0e, 0x0a, 0x09, - 0x43, 0x32, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0xff, 0x01, 0x2a, 0x98, 0x01, 0x0a, - 0x0e, 0x53, 0x32, 0x43, 0x5f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x11, 0x0a, 0x0d, 0x53, 0x32, 0x43, 0x5f, 0x4e, 0x4f, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, - 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x32, 0x43, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, - 0x4e, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x32, 0x43, 0x5f, - 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x56, 0x45, 0x52, 0x54, 0x5f, 0x49, - 0x4e, 0x49, 0x54, 0x10, 0x0b, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x32, 0x43, 0x5f, 0x43, 0x4f, 0x4e, - 0x46, 0x49, 0x52, 0x4d, 0x5f, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x10, 0x02, - 0x12, 0x15, 0x0a, 0x11, 0x53, 0x32, 0x43, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, - 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x32, 0x43, 0x5f, 0x45, - 0x52, 0x52, 0x4f, 0x52, 0x10, 0xff, 0x01, 0x2a, 0xac, 0x01, 0x0a, 0x0e, 0x45, 0x72, 0x72, 0x6f, - 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x53, 0x32, 0x43, 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x4f, - 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x4f, 0x56, 0x45, - 0x52, 0x54, 0x5f, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x43, - 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x02, - 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, - 0x43, 0x4f, 0x4c, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x54, 0x41, 0x54, 0x49, 0x4f, 0x4e, - 0x5f, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x44, - 0x45, 0x43, 0x4f, 0x59, 0x5f, 0x4f, 0x56, 0x45, 0x52, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x05, 0x12, - 0x11, 0x0a, 0x0d, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, - 0x10, 0x64, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x49, 0x4d, - 0x45, 0x4f, 0x55, 0x54, 0x10, 0x65, 0x2a, 0x82, 0x01, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x70, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x75, 0x6c, 0x6c, - 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x69, 0x6e, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4f, - 0x62, 0x66, 0x73, 0x34, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x54, 0x4c, 0x53, 0x10, 0x03, - 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, - 0x75, 0x54, 0x4c, 0x53, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, - 0x10, 0x06, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x53, 0x4d, 0x10, 0x07, 0x12, 0x07, 0x0a, 0x03, - 0x46, 0x54, 0x45, 0x10, 0x08, 0x12, 0x08, 0x0a, 0x04, 0x51, 0x75, 0x69, 0x63, 0x10, 0x09, 0x12, - 0x0a, 0x0a, 0x06, 0x57, 0x65, 0x62, 0x72, 0x74, 0x63, 0x10, 0x63, 0x2a, 0x86, 0x01, 0x0a, 0x12, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, - 0x64, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x10, - 0x01, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x65, - 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x65, 0x73, 0x63, 0x61, 0x6e, 0x10, 0x03, 0x12, - 0x14, 0x0a, 0x10, 0x42, 0x69, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, - 0x41, 0x50, 0x49, 0x10, 0x04, 0x12, 0x07, 0x0a, 0x03, 0x44, 0x4e, 0x53, 0x10, 0x05, 0x12, 0x14, - 0x0a, 0x10, 0x42, 0x69, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x44, - 0x4e, 0x53, 0x10, 0x06, 0x2a, 0x40, 0x0a, 0x11, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, - 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, - 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4e, 0x65, 0x77, 0x10, 0x01, 0x12, - 0x0a, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x43, - 0x6c, 0x65, 0x61, 0x72, 0x10, 0x03, 0x2a, 0x24, 0x0a, 0x07, 0x49, 0x50, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x6e, 0x6b, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x63, - 0x70, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x64, 0x70, 0x10, 0x02, + 0x0a, 0x17, 0x53, 0x32, 0x43, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, + 0x56, 0x45, 0x52, 0x54, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x10, 0x0b, 0x12, 0x19, 0x0a, 0x15, 0x53, + 0x32, 0x43, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x5f, 0x52, 0x45, 0x43, 0x4f, 0x4e, + 0x4e, 0x45, 0x43, 0x54, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x32, 0x43, 0x5f, 0x53, 0x45, + 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x10, 0x03, 0x12, 0x0e, 0x0a, + 0x09, 0x53, 0x32, 0x43, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0xff, 0x01, 0x2a, 0xac, 0x01, + 0x0a, 0x0e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x53, 0x32, 0x43, + 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x4f, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x11, + 0x0a, 0x0d, 0x43, 0x4f, 0x56, 0x45, 0x52, 0x54, 0x5f, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x10, + 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x50, 0x4f, + 0x52, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, + 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x53, + 0x54, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, + 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x43, 0x4f, 0x59, 0x5f, 0x4f, 0x56, 0x45, 0x52, 0x4c, + 0x4f, 0x41, 0x44, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, + 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x10, 0x64, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4c, 0x49, 0x45, + 0x4e, 0x54, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x10, 0x65, 0x2a, 0x82, 0x01, 0x0a, + 0x0d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, + 0x0a, 0x04, 0x4e, 0x75, 0x6c, 0x6c, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x69, 0x6e, 0x10, + 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x62, 0x66, 0x73, 0x34, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, + 0x44, 0x54, 0x4c, 0x53, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, + 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x75, 0x54, 0x4c, 0x53, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, + 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x10, 0x06, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x53, 0x4d, + 0x10, 0x07, 0x12, 0x07, 0x0a, 0x03, 0x46, 0x54, 0x45, 0x10, 0x08, 0x12, 0x08, 0x0a, 0x04, 0x51, + 0x75, 0x69, 0x63, 0x10, 0x09, 0x12, 0x0a, 0x0a, 0x06, 0x57, 0x65, 0x62, 0x72, 0x74, 0x63, 0x10, + 0x63, 0x2a, 0x86, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x6e, 0x73, 0x70, + 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x65, 0x74, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x10, 0x02, + 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x65, 0x73, + 0x63, 0x61, 0x6e, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x69, 0x64, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x50, 0x49, 0x10, 0x04, 0x12, 0x07, 0x0a, 0x03, 0x44, + 0x4e, 0x53, 0x10, 0x05, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x69, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x44, 0x4e, 0x53, 0x10, 0x06, 0x2a, 0x40, 0x0a, 0x11, 0x53, 0x74, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, + 0x4e, 0x65, 0x77, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x10, + 0x02, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x10, 0x03, 0x2a, 0x24, 0x0a, 0x07, + 0x49, 0x50, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x6e, 0x6b, 0x10, 0x00, + 0x12, 0x07, 0x0a, 0x03, 0x54, 0x63, 0x70, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x64, 0x70, + 0x10, 0x02, } var ( @@ -2701,7 +2771,7 @@ func file_signalling_proto_rawDescGZIP() []byte { } var file_signalling_proto_enumTypes = make([]protoimpl.EnumInfo, 9) -var file_signalling_proto_msgTypes = make([]protoimpl.MessageInfo, 21) +var file_signalling_proto_msgTypes = make([]protoimpl.MessageInfo, 22) var file_signalling_proto_goTypes = []interface{}{ (KeyType)(0), // 0: proto.KeyType (DnsRegMethod)(0), // 1: proto.DnsRegMethod @@ -2722,18 +2792,19 @@ var file_signalling_proto_goTypes = []interface{}{ (*WebRTCICECandidate)(nil), // 16: proto.WebRTCICECandidate (*WebRTCSDP)(nil), // 17: proto.WebRTCSDP (*WebRTCSignal)(nil), // 18: proto.WebRTCSignal - (*DTLSTransportParams)(nil), // 19: proto.DTLSTransportParams - (*StationToClient)(nil), // 20: proto.StationToClient - (*RegistrationFlags)(nil), // 21: proto.RegistrationFlags - (*ClientToStation)(nil), // 22: proto.ClientToStation - (*PrefixTransportParams)(nil), // 23: proto.PrefixTransportParams - (*GenericTransportParams)(nil), // 24: proto.GenericTransportParams - (*C2SWrapper)(nil), // 25: proto.C2SWrapper - (*SessionStats)(nil), // 26: proto.SessionStats - (*StationToDetector)(nil), // 27: proto.StationToDetector - (*RegistrationResponse)(nil), // 28: proto.RegistrationResponse - (*DnsResponse)(nil), // 29: proto.DnsResponse - (*any.Any)(nil), // 30: google.protobuf.Any + (*Addr)(nil), // 19: proto.Addr + (*DTLSTransportParams)(nil), // 20: proto.DTLSTransportParams + (*StationToClient)(nil), // 21: proto.StationToClient + (*RegistrationFlags)(nil), // 22: proto.RegistrationFlags + (*ClientToStation)(nil), // 23: proto.ClientToStation + (*PrefixTransportParams)(nil), // 24: proto.PrefixTransportParams + (*GenericTransportParams)(nil), // 25: proto.GenericTransportParams + (*C2SWrapper)(nil), // 26: proto.C2SWrapper + (*SessionStats)(nil), // 27: proto.SessionStats + (*StationToDetector)(nil), // 28: proto.StationToDetector + (*RegistrationResponse)(nil), // 29: proto.RegistrationResponse + (*DnsResponse)(nil), // 30: proto.DnsResponse + (*anypb.Any)(nil), // 31: google.protobuf.Any } var file_signalling_proto_depIdxs = []int32{ 0, // 0: proto.PubKey.type:type_name -> proto.KeyType @@ -2748,28 +2819,30 @@ var file_signalling_proto_depIdxs = []int32{ 15, // 9: proto.PhantomSubnetsList.weighted_subnets:type_name -> proto.PhantomSubnets 16, // 10: proto.WebRTCSDP.candidates:type_name -> proto.WebRTCICECandidate 17, // 11: proto.WebRTCSignal.sdp:type_name -> proto.WebRTCSDP - 3, // 12: proto.StationToClient.state_transition:type_name -> proto.S2C_Transition - 11, // 13: proto.StationToClient.config_info:type_name -> proto.ClientConf - 4, // 14: proto.StationToClient.err_reason:type_name -> proto.ErrorReasonS2C - 2, // 15: proto.ClientToStation.state_transition:type_name -> proto.C2S_Transition - 26, // 16: proto.ClientToStation.stats:type_name -> proto.SessionStats - 5, // 17: proto.ClientToStation.transport:type_name -> proto.TransportType - 30, // 18: proto.ClientToStation.transport_params:type_name -> google.protobuf.Any - 21, // 19: proto.ClientToStation.flags:type_name -> proto.RegistrationFlags - 18, // 20: proto.ClientToStation.webrtc_signal:type_name -> proto.WebRTCSignal - 22, // 21: proto.C2SWrapper.registration_payload:type_name -> proto.ClientToStation - 6, // 22: proto.C2SWrapper.registration_source:type_name -> proto.RegistrationSource - 28, // 23: proto.C2SWrapper.registration_response:type_name -> proto.RegistrationResponse - 7, // 24: proto.StationToDetector.operation:type_name -> proto.StationOperations - 8, // 25: proto.StationToDetector.proto:type_name -> proto.IPProto - 11, // 26: proto.RegistrationResponse.clientConf:type_name -> proto.ClientConf - 30, // 27: proto.RegistrationResponse.transport_params:type_name -> google.protobuf.Any - 28, // 28: proto.DnsResponse.bidirectional_response:type_name -> proto.RegistrationResponse - 29, // [29:29] is the sub-list for method output_type - 29, // [29:29] is the sub-list for method input_type - 29, // [29:29] is the sub-list for extension type_name - 29, // [29:29] is the sub-list for extension extendee - 0, // [0:29] is the sub-list for field type_name + 19, // 12: proto.DTLSTransportParams.src_addr4:type_name -> proto.Addr + 19, // 13: proto.DTLSTransportParams.src_addr6:type_name -> proto.Addr + 3, // 14: proto.StationToClient.state_transition:type_name -> proto.S2C_Transition + 11, // 15: proto.StationToClient.config_info:type_name -> proto.ClientConf + 4, // 16: proto.StationToClient.err_reason:type_name -> proto.ErrorReasonS2C + 2, // 17: proto.ClientToStation.state_transition:type_name -> proto.C2S_Transition + 27, // 18: proto.ClientToStation.stats:type_name -> proto.SessionStats + 5, // 19: proto.ClientToStation.transport:type_name -> proto.TransportType + 31, // 20: proto.ClientToStation.transport_params:type_name -> google.protobuf.Any + 22, // 21: proto.ClientToStation.flags:type_name -> proto.RegistrationFlags + 18, // 22: proto.ClientToStation.webrtc_signal:type_name -> proto.WebRTCSignal + 23, // 23: proto.C2SWrapper.registration_payload:type_name -> proto.ClientToStation + 6, // 24: proto.C2SWrapper.registration_source:type_name -> proto.RegistrationSource + 29, // 25: proto.C2SWrapper.registration_response:type_name -> proto.RegistrationResponse + 7, // 26: proto.StationToDetector.operation:type_name -> proto.StationOperations + 8, // 27: proto.StationToDetector.proto:type_name -> proto.IPProto + 11, // 28: proto.RegistrationResponse.clientConf:type_name -> proto.ClientConf + 31, // 29: proto.RegistrationResponse.transport_params:type_name -> google.protobuf.Any + 29, // 30: proto.DnsResponse.bidirectional_response:type_name -> proto.RegistrationResponse + 31, // [31:31] is the sub-list for method output_type + 31, // [31:31] is the sub-list for method input_type + 31, // [31:31] is the sub-list for extension type_name + 31, // [31:31] is the sub-list for extension extendee + 0, // [0:31] is the sub-list for field type_name } func init() { file_signalling_proto_init() } @@ -2899,7 +2972,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DTLSTransportParams); i { + switch v := v.(*Addr); i { case 0: return &v.state case 1: @@ -2911,7 +2984,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StationToClient); i { + switch v := v.(*DTLSTransportParams); i { case 0: return &v.state case 1: @@ -2923,7 +2996,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegistrationFlags); i { + switch v := v.(*StationToClient); i { case 0: return &v.state case 1: @@ -2935,7 +3008,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ClientToStation); i { + switch v := v.(*RegistrationFlags); i { case 0: return &v.state case 1: @@ -2947,7 +3020,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PrefixTransportParams); i { + switch v := v.(*ClientToStation); i { case 0: return &v.state case 1: @@ -2959,7 +3032,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GenericTransportParams); i { + switch v := v.(*PrefixTransportParams); i { case 0: return &v.state case 1: @@ -2971,7 +3044,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*C2SWrapper); i { + switch v := v.(*GenericTransportParams); i { case 0: return &v.state case 1: @@ -2983,7 +3056,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SessionStats); i { + switch v := v.(*C2SWrapper); i { case 0: return &v.state case 1: @@ -2995,7 +3068,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StationToDetector); i { + switch v := v.(*SessionStats); i { case 0: return &v.state case 1: @@ -3007,7 +3080,7 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegistrationResponse); i { + switch v := v.(*StationToDetector); i { case 0: return &v.state case 1: @@ -3019,6 +3092,18 @@ func file_signalling_proto_init() { } } file_signalling_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegistrationResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_signalling_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DnsResponse); i { case 0: return &v.state @@ -3037,7 +3122,7 @@ func file_signalling_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_signalling_proto_rawDesc, NumEnums: 9, - NumMessages: 21, + NumMessages: 22, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/signalling.proto b/proto/signalling.proto index 2caab1e1..bc5e47a1 100644 --- a/proto/signalling.proto +++ b/proto/signalling.proto @@ -192,9 +192,15 @@ message WebRTCSignal { required WebRTCSDP sdp = 2; } +message Addr { + optional bytes IP = 1; + optional uint32 Port = 2; +} + message DTLSTransportParams { - optional uint32 src_port = 1; - optional bool randomize_dst_port = 2; + optional Addr src_addr4 = 1; + optional Addr src_addr6 = 2; + optional bool randomize_dst_port = 3; } message StationToClient {