From 8967b53170b2a9407278fa0323eaa066e49ca11c Mon Sep 17 00:00:00 2001 From: Gabi Date: Mon, 3 Jul 2023 16:25:37 -0300 Subject: [PATCH] Feat/connlib full flow (#1722) With this PR the full control-plane message flow is working. Meaning that if you do: ``` docker compose up -d docker compose exec -it client "ping 172.20.0.2" # will fix this IP later ``` Messages start flowing to gateway. The gateway still not correctly forwards the messages to the resource since masquerading is still not working, although I suspect there might be an additional problem. Will fix this in my next PR along with a README on how to test this whole flow. This PR also fixes how we sent the stamp secret to the gateway from the relay, but I still see some warnings in the webrtc that I'm sure that are due to a mismatch between how webrtc-rs and the relay handle messages (The most important being `bind() failed: unexpected response type`), I will take a look at that and a way to test that the flow works when: 1. hole-punching is available 2. through relay when it's not Since the flow right now works without hole-punching or relay since the gateway is in the same network in the docker compose. --- docker-compose.yml | 2 + rust/Cargo.lock | 311 +++++++++++-------- rust/Cargo.toml | 2 +- rust/Dockerfile.dev | 4 + rust/connlib/libs/client/src/control.rs | 46 +-- rust/connlib/libs/client/src/messages.rs | 33 +- rust/connlib/libs/common/src/control.rs | 84 ++++- rust/connlib/libs/common/src/messages/key.rs | 47 ++- rust/connlib/libs/common/src/session.rs | 46 ++- rust/connlib/libs/gateway/src/control.rs | 40 +-- rust/connlib/libs/gateway/src/messages.rs | 60 +++- rust/connlib/libs/tunnel/src/lib.rs | 2 + rust/relay/src/main.rs | 4 +- 13 files changed, 459 insertions(+), 222 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 5a4b79eb0..56d93b854 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -119,6 +119,7 @@ services: environment: FZ_URL: "ws://api:8081/" FZ_SECRET: "SFMyNTY.g2gDaANkAAhpZGVudGl0eW0AAAAkN2RhN2QxY2QtMTExYy00NGE3LWI1YWMtNDAyN2I5ZDIzMGU1bQAAACAZ_F7tY7RZcWcaeGbwM9H9EBDdj2U4QPu2sBzD8Z_7R24GAMH8mfqIAWIB4TOA.2IZ089fjvNLoCsirq2PwNTfMHXf3285F6YcNquk6niU" + RUST_LOG: headless=trace,firezone_client_connlib=trace,firezone_tunnel=trace,libs_common=trace,warn build: context: rust dockerfile: Dockerfile.dev @@ -142,6 +143,7 @@ services: environment: FZ_URL: "ws://api:8081/" FZ_SECRET: "SFMyNTY.g2gDaAJtAAAAJDNjZWYwNTY2LWFkZmQtNDhmZS1hMGYxLTU4MDY3OTYwOGY2Zm0AAABAamp0enhSRkpQWkdCYy1vQ1o5RHkyRndqd2FIWE1BVWRwenVScjJzUnJvcHg3NS16bmhfeHBfNWJUNU9uby1yYm4GAFvAb_mIAWIAAVGA.1DaY3H3fKzW5sqcciJqlHyG0uFctzOewofsVRGS7NrQ" + RUST_LOG: gateway=trace,firezone_gateway_connlib=trace,firezone_tunnel=trace,libs_common=trace,warn build: context: rust dockerfile: Dockerfile.dev diff --git a/rust/Cargo.lock b/rust/Cargo.lock index ec252bdc2..06f70d2b2 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aead" version = "0.3.2" @@ -256,13 +271,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "7b2d0f03b3640e3a630367e40c468cb7f309529c708ed1d88597047b0e7c6ef7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -288,6 +303,21 @@ dependencies = [ "rand", ] +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +dependencies = [ + "addr2line", + "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base16ct" version = "0.1.1" @@ -342,6 +372,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + [[package]] name = "blake2" version = "0.10.6" @@ -379,7 +415,7 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "boringtun" version = "0.5.2" -source = "git+https://github.com/cloudflare/boringtun?rev=878385f#878385f171d60effac4ad1a9d4dee41e777528b8" +source = "git+https://github.com/firezone/boringtun?branch=master#9e45acd768d88ce0eb74219641fbc2463d1f7b66" dependencies = [ "aead 0.5.2", "base64 0.13.1", @@ -524,9 +560,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.5" +version = "4.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2686c4115cb0810d9a984776e197823d08ec94f176549a89a9efded477c456dc" +checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a" dependencies = [ "clap_builder", "clap_derive", @@ -535,13 +571,12 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.5" +version = "4.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e53afce1efce6ed1f633cf0e57612fe51db54a1ee4fd8f8503d078fe02d69ae" +checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d" dependencies = [ "anstream", "anstyle", - "bitflags", "clap_lex", "strsim", ] @@ -555,7 +590,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -609,9 +644,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" +checksum = "6340df57935414636969091153f35f68d9f00bbc8fb4a9c6054706c213e6c6bc" [[package]] name = "convert_case" @@ -715,18 +750,31 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-rc.2" +version = "4.0.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d928d978dbec61a1167414f5ec534f24bea0d7a0d24dd9b6233d3d8223e585" +checksum = "436ace70fc06e06f7f689d2624dc4e2f0ea666efb5aa704215f7249ae6e047a7" dependencies = [ "cfg-if 1.0.0", + "cpufeatures", + "curve25519-dalek-derive", "fiat-crypto", - "packed_simd_2", "platforms", + "rustc_version", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] + [[package]] name = "darling" version = "0.14.4" @@ -885,7 +933,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -1126,7 +1174,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -1212,6 +1260,12 @@ dependencies = [ "polyval", ] +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + [[package]] name = "glob" version = "0.3.1" @@ -1247,15 +1301,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.1" @@ -1383,7 +1428,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi", "libc", "windows-sys 0.48.0", ] @@ -1415,19 +1460,18 @@ checksum = "8e537132deb99c0eb4b752f0346b6a836200eaaa3516dd7e5514b63930a09e5d" [[package]] name = "ipnet" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "is-terminal" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb" dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", + "hermit-abi", + "rustix 0.38.2", "windows-sys 0.48.0", ] @@ -1442,9 +1486,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" [[package]] name = "java-locator" @@ -1511,9 +1555,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.146" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libloading" @@ -1525,12 +1569,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "libm" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" - [[package]] name = "libm" version = "0.2.7" @@ -1570,6 +1608,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "linux-raw-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" + [[package]] name = "lock_api" version = "0.4.10" @@ -1631,6 +1675,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "mio" version = "0.8.8" @@ -1661,7 +1714,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea993e32c77d87f01236c38f572ecb6c311d592e56a06262a007fd2a6e31253c" dependencies = [ "anyhow", - "bitflags", + "bitflags 1.3.2", "byteorder", "libc", "netlink-packet-core", @@ -1714,7 +1767,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "libc", "memoffset", @@ -1727,7 +1780,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" dependencies = [ "autocfg", - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "libc", ] @@ -1738,7 +1791,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if 1.0.0", "libc", "static_assertions", @@ -1792,19 +1845,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", - "libm 0.2.7", + "libm", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ + "memchr", +] + [[package]] name = "oid-registry" version = "0.4.0" @@ -1879,16 +1941,6 @@ dependencies = [ "sha2", ] -[[package]] -name = "packed_simd_2" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" -dependencies = [ - "cfg-if 1.0.0", - "libm 0.1.4", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -1909,7 +1961,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.0", + "windows-targets 0.48.1", ] [[package]] @@ -1960,9 +2012,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" [[package]] name = "pin-utils" @@ -2017,9 +2069,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] @@ -2031,7 +2083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65" dependencies = [ "bit-set", - "bitflags", + "bitflags 1.3.2", "byteorder", "lazy_static", "num-traits", @@ -2052,9 +2104,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.28" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -2145,7 +2197,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -2279,6 +2331,12 @@ dependencies = [ "webrtc-util", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc_version" version = "0.4.0" @@ -2299,15 +2357,28 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.20" +version = "0.37.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" +checksum = "8818fa822adcc98b18fedbb3632a6a33213c070556b5aa7c4c8cc21cff565c4c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aabcb0461ebd01d6b79945797c27f8529082226cb630a9865a71870ff63532a4" +dependencies = [ + "bitflags 2.3.3", + "errno", + "libc", + "linux-raw-sys 0.4.3", "windows-sys 0.48.0", ] @@ -2350,9 +2421,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ "base64 0.21.2", ] @@ -2381,9 +2452,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" [[package]] name = "same-file" @@ -2396,11 +2467,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] @@ -2461,7 +2532,7 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -2486,29 +2557,29 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.165" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "c939f902bb7d0ccc5bce4f03297e161543c2dcb30914faf032c2bd0b7a0d48fc" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.165" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "6eaae920e25fffe4019b75ff65e7660e72091e59dd204cb5849bbd6a3fd343d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] name = "serde_json" -version = "1.0.97" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a" +checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" dependencies = [ "itoa", "ryu", @@ -2779,9 +2850,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" dependencies = [ "proc-macro2", "quote", @@ -2810,7 +2881,7 @@ dependencies = [ "cfg-if 1.0.0", "fastrand", "redox_syscall", - "rustix", + "rustix 0.37.22", "windows-sys 0.48.0", ] @@ -2852,7 +2923,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -2909,11 +2980,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -2934,7 +3006,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -3003,13 +3075,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8803eee176538f94ae9a14b55b2804eb7e1441f8210b1c31290b3bccdccff73b" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -3225,9 +3297,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.3.4" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa2982af2eec27de306107c027578ff7f423d65f7250e40ce0fea8f45248b81" +checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" dependencies = [ "getrandom 0.2.10", "serde", @@ -3306,7 +3378,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", "wasm-bindgen-shared", ] @@ -3328,7 +3400,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3564,7 +3636,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f1db1727772c05cf7a2cfece52c3aca8045ca1e176cd517d323489aa3c6d87" dependencies = [ "async-trait", - "bitflags", + "bitflags 1.3.2", "bytes", "cc 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)", "ipnet", @@ -3615,21 +3687,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-sys" version = "0.45.0" @@ -3645,7 +3702,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.1", ] [[package]] @@ -3665,9 +3722,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm 0.48.0", "windows_aarch64_msvc 0.48.0", @@ -3779,11 +3836,11 @@ dependencies = [ [[package]] name = "x25519-dalek" -version = "2.0.0-rc.2" +version = "2.0.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabd6e16dd08033932fc3265ad4510cc2eab24656058a6dcb107ffe274abcc95" +checksum = "ec7fae07da688e17059d5886712c933bb0520f15eff2e09cfa18e30968f4e63a" dependencies = [ - "curve25519-dalek 4.0.0-rc.2", + "curve25519-dalek 4.0.0-rc.3", "rand_core 0.6.4", "serde", "zeroize", @@ -3852,5 +3909,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 6c2705637..05f0b653c 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -13,7 +13,7 @@ members = [ ] [workspace.dependencies] -boringtun = { git = "https://github.com/cloudflare/boringtun", rev = "878385f", default-features = false } +boringtun = { git = "https://github.com/firezone/boringtun", branch = "master", default-features = false } swift-bridge = { git = "https://github.com/chinedufn/swift-bridge.git", rev = "4fbd30f" } # Patched to use https://github.com/rust-lang/cc-rs/pull/708 diff --git a/rust/Dockerfile.dev b/rust/Dockerfile.dev index 50e5db5cb..40b903be2 100644 --- a/rust/Dockerfile.dev +++ b/rust/Dockerfile.dev @@ -17,6 +17,10 @@ COPY --from=BUILDER /usr/local/bin/$PACKAGE . ENV RUST_BACKTRACE=1 ENV PATH "/app:$PATH" ENV PACKAGE_NAME ${PACKAGE} +RUN apt-get update -y \ + && apt-get install -y iputils-ping \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* # Some black magics here: # we need to use `/bin/sh -c` so that the env variable is correctly replaced # but then everything in `CMD` is placed after the executed string, so we need diff --git a/rust/connlib/libs/client/src/control.rs b/rust/connlib/libs/client/src/control.rs index 04edd0651..3e19bb610 100644 --- a/rust/connlib/libs/client/src/control.rs +++ b/rust/connlib/libs/client/src/control.rs @@ -3,6 +3,7 @@ use std::{sync::Arc, time::Duration}; use crate::messages::{Connect, EgressMessages, InitClient, Messages, Relays}; use boringtun::x25519::StaticSecret; use libs_common::{ + control::PhoenixSenderWithTopic, error_type::ErrorType::{Fatal, Recoverable}, messages::{Id, ResourceDescription}, Callbacks, ControlSession, Result, @@ -10,14 +11,14 @@ use libs_common::{ use async_trait::async_trait; use firezone_tunnel::{ControlSignal, Tunnel}; -use tokio::sync::mpsc::{channel, Receiver, Sender}; - -const INTERNAL_CHANNEL_SIZE: usize = 256; +use tokio::sync::mpsc::Receiver; #[async_trait] impl ControlSignal for ControlSignaler { async fn signal_connection_to(&self, resource: &ResourceDescription) -> Result<()> { - self.internal_sender + self.control_signal + // It's easier if self is not mut + .clone() .send(EgressMessages::ListRelays { resource_id: resource.id(), }) @@ -34,7 +35,7 @@ pub struct ControlPlane { #[derive(Clone)] struct ControlSignaler { - internal_sender: Arc>, + control_signal: PhoenixSenderWithTopic, } impl ControlPlane { @@ -75,14 +76,19 @@ impl ControlPlane { async fn connect( &mut self, Connect { - rtc_sdp, + gateway_rtc_session_description, resource_id, gateway_public_key, + .. }: Connect, ) { if let Err(e) = self .tunnel - .recieved_offer_response(resource_id, rtc_sdp, gateway_public_key.0.into()) + .recieved_offer_response( + resource_id, + gateway_rtc_session_description, + gateway_public_key.0.into(), + ) .await { self.tunnel.callbacks().on_error(&e, Recoverable); @@ -113,17 +119,18 @@ impl ControlPlane { }: Relays, ) { let tunnel = Arc::clone(&self.tunnel); - let control_signaler = self.control_signaler.clone(); + let mut control_signaler = self.control_signaler.clone(); tokio::spawn(async move { match tunnel.request_connection(resource_id, relays).await { Ok(connection_request) => { if let Err(err) = control_signaler - .internal_sender - .send(EgressMessages::RequestConnection(connection_request)) + .control_signal + // TODO: create a reference number and keep track for the response + .send_with_ref(EgressMessages::RequestConnection(connection_request), 0) .await { tunnel.cleanup_connection(resource_id); - tunnel.callbacks().on_error(&err.into(), Recoverable); + tunnel.callbacks().on_error(&err, Recoverable); } } Err(err) => { @@ -153,20 +160,15 @@ impl ControlPlane { } #[async_trait] -impl ControlSession for ControlPlane { +impl ControlSession for ControlPlane { #[tracing::instrument(level = "trace", skip(private_key, callbacks))] async fn start( private_key: StaticSecret, + receiver: Receiver, + control_signal: PhoenixSenderWithTopic, callbacks: CB, - ) -> Result<(Sender, Receiver)> { - // This is kinda hacky, the buffer size is 1 so that we make sure that we - // process one message at a time, blocking if a previous message haven't been processed - // to force queue ordering. - let (sender, receiver) = channel::(1); - - let (internal_sender, internal_receiver) = channel(INTERNAL_CHANNEL_SIZE); - let internal_sender = Arc::new(internal_sender); - let control_signaler = ControlSignaler { internal_sender }; + ) -> Result<()> { + let control_signaler = ControlSignaler { control_signal }; let tunnel = Arc::new(Tunnel::new(private_key, control_signaler.clone(), callbacks).await?); let control_plane = ControlPlane { @@ -176,7 +178,7 @@ impl ControlSession for C tokio::spawn(async move { control_plane.start(receiver).await }); - Ok((sender, internal_receiver)) + Ok(()) } fn socket_path() -> &'static str { diff --git a/rust/connlib/libs/client/src/messages.rs b/rust/connlib/libs/client/src/messages.rs index d2731e764..29f454e8b 100644 --- a/rust/connlib/libs/client/src/messages.rs +++ b/rust/connlib/libs/client/src/messages.rs @@ -17,9 +17,10 @@ pub struct RemoveResource { #[derive(Debug, Deserialize, Serialize, Clone)] pub struct Connect { - pub rtc_sdp: RTCSessionDescription, + pub gateway_rtc_session_description: RTCSessionDescription, pub resource_id: Id, pub gateway_public_key: Key, + pub persistent_keepalive: u64, } // Just because RTCSessionDescription doesn't implement partialeq @@ -48,7 +49,6 @@ pub struct Relays { #[allow(clippy::large_enum_variant)] pub enum IngressMessages { Init(InitClient), - Connect(Connect), // Resources: arrive in an orderly fashion ResourceAdded(ResourceDescription), @@ -59,8 +59,10 @@ pub enum IngressMessages { /// The replies that can arrive from the channel by a client #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] #[serde(untagged)] +#[allow(clippy::large_enum_variant)] pub enum ReplyMessages { Relays(Relays), + Connect(Connect), } /// The totality of all messages (might have a macro in the future to derive the other types) @@ -81,7 +83,6 @@ impl From for Messages { fn from(value: IngressMessages) -> Self { match value { IngressMessages::Init(m) => Self::Init(m), - IngressMessages::Connect(m) => Self::Connect(m), IngressMessages::ResourceAdded(m) => Self::ResourceAdded(m), IngressMessages::ResourceRemoved(m) => Self::ResourceRemoved(m), IngressMessages::ResourceUpdated(m) => Self::ResourceUpdated(m), @@ -93,6 +94,7 @@ impl From for Messages { fn from(value: ReplyMessages) -> Self { match value { ReplyMessages::Relays(m) => Self::Relays(m), + ReplyMessages::Connect(m) => Self::Connect(m), } } } @@ -123,6 +125,28 @@ mod test { // TODO: request_connection tests + #[test] + fn connection_ready_deserialization() { + let message = r#"{ + "ref": 0, + "topic": "device", + "event": "phx_reply", + "payload": { + "status": "ok", + "response": { + "resource_id": "ea6570d1-47c7-49d2-9dc3-efff1c0c9e0b", + "gateway_public_key": "dvy0IwyxAi+txSbAdT7WKgf7K4TekhKzrnYwt5WfbSM=", + "gateway_rtc_session_description": { + "sdp": "v=0\\r\\no=- 6423047867593421607 871431568 IN IP4 0.0.0.0\\r\\ns=-\\r\\nt=0 0\\r\\na=fingerprint:sha-256 65:8C:0B:EC:C5:B8:AB:2C:C7:47:F6:1A:6F:C3:4F:70:C7:06:34:84:FE:4E:FD:E5:C4:D2:4F:7C:ED:AF:0D:17\\r\\na=group:BUNDLE 0\\r\\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\\r\\nc=IN IP4 0.0.0.0\\r\\na=setup:active\\r\\na=mid:0\\r\\na=sendrecv\\r\\na=sctp-port:5000\\r\\na=ice-ufrag:zDSijpzITpzCfjbw\\r\\na=ice-pwd:QGufrJIKwqRjhDsNTdddVLFXmvGQJxke\\r\\na=candidate:167090039 1 udp 2130706431 :: 33628 typ host\\r\\na=candidate:167090039 2 udp 2130706431 :: 33628 typ host\\r\\na=candidate:1081386133 1 udp 2130706431 100.102.249.43 51575 typ host\\r\\na=candidate:1081386133 2 udp 2130706431 100.102.249.43 51575 typ host\\r\\na=candidate:1290078212 1 udp 2130706431 172.28.0.7 58698 typ host\\r\\na=candidate:1290078212 2 udp 2130706431 172.28.0.7 58698 typ host\\r\\na=candidate:349389859 1 udp 2130706431 172.20.0.3 51567 typ host\\r\\na=candidate:349389859 2 udp 2130706431 172.20.0.3 51567 typ host\\r\\na=candidate:936829106 1 udp 1694498815 172.28.0.7 35458 typ srflx raddr 0.0.0.0 rport 35458\\r\\na=candidate:936829106 2 udp 1694498815 172.28.0.7 35458 typ srflx raddr 0.0.0.0 rport 35458\\r\\na=candidate:936829106 1 udp 1694498815 172.28.0.7 46603 typ srflx raddr 0.0.0.0 rport 46603\\r\\na=candidate:936829106 2 udp 1694498815 172.28.0.7 46603 typ srflx raddr 0.0.0.0 rport 46603\\r\\na=end-of-candidates\\r\\n", + "type": "answer" + }, + "persistent_keepalive": 25 + } + } + }"#; + let _: PhoenixMessage = + serde_json::from_str(message).unwrap(); + } #[test] fn init_phoenix_message() { let m = PhoenixMessage::new( @@ -148,8 +172,8 @@ mod test { }), ], }), + None, ); - println!("{}", serde_json::to_string(&m).unwrap()); let message = r#"{ "event": "init", "payload": { @@ -190,6 +214,7 @@ mod test { EgressMessages::ListRelays { resource_id: "f16ecfa0-a94f-4bfd-a2ef-1cc1f2ef3da3".parse().unwrap(), }, + None, ); let message = r#" { diff --git a/rust/connlib/libs/common/src/control.rs b/rust/connlib/libs/common/src/control.rs index 5a72cfbf1..bdb68fd0a 100644 --- a/rust/connlib/libs/common/src/control.rs +++ b/rust/connlib/libs/common/src/control.rs @@ -89,11 +89,15 @@ where /// Additionally, you can add a list of topic to join after connection ASAP. /// /// See [struct-level docs][PhoenixChannel] for more info. - #[tracing::instrument(level = "trace", skip(self))] - pub async fn start(&mut self, topics: Vec) -> Result<()> { + /// + // TODO: this is not very elegant but it was the easiest way to do reset the exponential backoff for now + /// Furthermore, it calls the given callback once it connects to the portal. + #[tracing::instrument(level = "trace", skip(self, cb))] + pub async fn start(&mut self, topics: Vec, cb: impl FnOnce()) -> Result<()> { tracing::trace!("Trying to connect to the portal..."); let (ws_stream, _) = connect_async(make_request(&self.uri)?).await?; + cb(); tracing::trace!("Successfully connected to portal"); @@ -120,6 +124,7 @@ where serde_json::to_string(&PhoenixMessage::<_, ()>::new( topic, EgressControlMessage::PhxJoin(Empty {}), + None, )) .expect("we should always be able to serialize a join topic message"), )) @@ -197,6 +202,16 @@ where } } + /// Obtains a new sender that can be used to send message with this [PhoenixChannel] to the portal for a fixed topic. + /// + /// For more info see [PhoenixChannel::sender]. + pub fn sender_with_topic(&self, topic: String) -> PhoenixSenderWithTopic { + PhoenixSenderWithTopic { + topic, + phoenix_sender: self.sender(), + } + } + /// Creates a new [PhoenixChannel] not started yet. /// /// # Parameters: @@ -237,11 +252,11 @@ pub struct PhoenixMessage { } impl PhoenixMessage { - pub fn new(topic: impl Into, payload: T) -> Self { + pub fn new(topic: impl Into, payload: T, reference: Option) -> Self { Self { topic: topic.into(), payload: Payload::Message(payload), - reference: None, + reference, } } @@ -301,21 +316,74 @@ enum PhxReply { /// /// Messages won't be sent unless [PhoenixChannel::start] is running, internally /// this sends messages through a future channel that are forwrarded then in [PhoenixChannel] event loop +#[derive(Clone, Debug)] pub struct PhoenixSender { sender: Sender, } +/// Like a [PhoenixSender] with a fixed topic for simplicity +/// +/// You can obtain it through [PhoenixChannel::sender_with_topic] +/// See [PhoenixSender] docs and use that if you need more control. +#[derive(Clone, Debug)] +pub struct PhoenixSenderWithTopic { + phoenix_sender: PhoenixSender, + topic: String, +} + +impl PhoenixSenderWithTopic { + /// Sends a message to the associated topic using a [PhoenixSender] + /// + /// See [PhoenixSender::send] + pub async fn send(&mut self, payload: impl Serialize) -> Result<()> { + self.phoenix_sender.send(&self.topic, payload).await + } + + /// Sends a message to the associated topic using a [PhoenixSender] also setting the ref + /// + /// See [PhoenixSender::send] + pub async fn send_with_ref(&mut self, payload: impl Serialize, reference: i32) -> Result<()> { + self.phoenix_sender + .send_with_ref(&self.topic, payload, reference) + .await + } +} + impl PhoenixSender { + async fn send_internal( + &mut self, + topic: impl Into, + payload: impl Serialize, + reference: Option, + ) -> Result<()> { + // We don't care about the reply type when serializing + let str = serde_json::to_string(&PhoenixMessage::<_, ()>::new(topic, payload, reference))?; + self.sender.send(Message::text(str)).await?; + Ok(()) + } + /// Sends a message upstream to a connected [PhoenixChannel]. /// /// # Parameters /// - topic: Phoenix topic /// - payload: Message's payload pub async fn send(&mut self, topic: impl Into, payload: impl Serialize) -> Result<()> { - // We don't care about the reply type when serializing - let str = serde_json::to_string(&PhoenixMessage::<_, ()>::new(topic, payload))?; - self.sender.send(Message::text(str)).await?; - Ok(()) + self.send_internal(topic, payload, None).await + } + + /// Sends a message upstream to a connected [PhoenixChannel] using the given ref number. + /// + /// # Parameters + /// - topic: Phoenix topic + /// - payload: Message's payload + /// - reference: Reference number used in the message, if the message has a response that same number will be used + pub async fn send_with_ref( + &mut self, + topic: impl Into, + payload: impl Serialize, + reference: i32, + ) -> Result<()> { + self.send_internal(topic, payload, Some(reference)).await } /// Join a phoenix topic, meaning that after this method is invoked [PhoenixChannel] will diff --git a/rust/connlib/libs/common/src/messages/key.rs b/rust/connlib/libs/common/src/messages/key.rs index 9499ce814..93275c8f9 100644 --- a/rust/connlib/libs/common/src/messages/key.rs +++ b/rust/connlib/libs/common/src/messages/key.rs @@ -18,13 +18,22 @@ impl FromStr for Key { fn from_str(s: &str) -> Result { let mut key_bytes = [0u8; KEY_SIZE]; - let bytes_decoded = STANDARD.decode_slice(s, &mut key_bytes)?; - - if bytes_decoded != KEY_SIZE { - Err(base64::DecodeError::InvalidLength)?; + // decode_slice tries to estimate the size the decoded string before decoding + // if the passed buffer is smaller, it return an error. + // the problem is... the estimator is very bad! Meaning, decode_slice doesn't work + // we could use `decode_slice_unchecked`... or we could if we could trust the input, of course we can't + // (unless the portal sanitized the key beforehand which it doesn't) since someone could abuse this somehow + // to DoS a gateway by provinding a wrongly size public_key. + //:( + // so... we decode into a vec, check the length and convert to an array :) + // TODO: https://github.com/marshallpierce/rust-base64/issues/210 + let bytes_decoded = STANDARD.decode(s)?; + if bytes_decoded.len() != KEY_SIZE { + Err(Error::Base64DecodeError(base64::DecodeError::InvalidLength)) + } else { + key_bytes.copy_from_slice(&bytes_decoded); + Ok(Key(key_bytes)) } - - Ok(Self(key_bytes)) } } @@ -52,3 +61,29 @@ impl Serialize for Key { serializer.collect_str(&self) } } + +#[cfg(test)] +mod test { + use boringtun::x25519::{PublicKey, StaticSecret}; + use rand_core::OsRng; + + use super::Key; + + #[test] + fn can_deserialize_public_key() { + let public_key_string = r#""S6REkbStSNMfn8hpLkVxibjR+zz3RO/Gq40TprHJE2U=""#; + let actual_key: Key = serde_json::from_str(public_key_string).unwrap(); + assert_eq!(actual_key.to_string(), public_key_string.trim_matches('"')); + } + + #[test] + fn can_serialize_from_private_key_and_back() { + let private_key = StaticSecret::random_from_rng(OsRng); + let expected_public_key = PublicKey::from(&private_key); + let public_key = Key(expected_public_key.to_bytes()); + let public_key_string = serde_json::to_string(&public_key).unwrap(); + let actual_key: Key = serde_json::from_str(&public_key_string).unwrap(); + let actual_public_key = PublicKey::from(actual_key.0); + assert_eq!(actual_public_key, expected_public_key); + } +} diff --git a/rust/connlib/libs/common/src/session.rs b/rust/connlib/libs/common/src/session.rs index 4ec7d54de..5d4af8c5e 100644 --- a/rust/connlib/libs/common/src/session.rs +++ b/rust/connlib/libs/common/src/session.rs @@ -8,15 +8,12 @@ use std::{ net::{Ipv4Addr, Ipv6Addr}, time::Duration, }; -use tokio::{ - runtime::Runtime, - sync::mpsc::{Receiver, Sender}, -}; +use tokio::{runtime::Runtime, sync::mpsc::Receiver}; use url::Url; use uuid::Uuid; use crate::{ - control::PhoenixChannel, + control::{PhoenixChannel, PhoenixSenderWithTopic}, error_type::ErrorType, messages::{Key, ResourceDescription, ResourceDescriptionCidr}, Error, Result, @@ -25,9 +22,14 @@ use crate::{ // TODO: Not the most tidy trait for a control-plane. /// Trait that represents a control-plane. #[async_trait] -pub trait ControlSession { +pub trait ControlSession { /// Start control-plane with the given private-key in the background. - async fn start(private_key: StaticSecret, callbacks: CB) -> Result<(Sender, Receiver)>; + async fn start( + private_key: StaticSecret, + receiver: Receiver, + control_signal: PhoenixSenderWithTopic, + callbacks: CB, + ) -> Result<()>; /// Either "gateway" or "client" used to get the control-plane URL. fn socket_path() -> &'static str; @@ -88,7 +90,7 @@ macro_rules! fatal_error { impl Session where - T: ControlSession, + T: ControlSession, U: for<'de> serde::Deserialize<'de> + std::fmt::Debug + Send + 'static, R: for<'de> serde::Deserialize<'de> + std::fmt::Debug + Send + 'static, V: serde::Serialize + Send + 'static, @@ -146,32 +148,37 @@ where fn connect_inner(runtime: &Runtime, portal_url: Url, token: String, callbacks: CB) { runtime.spawn(async move { let private_key = StaticSecret::random_from_rng(OsRng); - let self_id = Uuid::new_v4(); + let self_id = uuid::Uuid::new_v4(); let name_suffix: String = thread_rng().sample_iter(&Alphanumeric).take(8).map(char::from).collect(); let connect_url = fatal_error!(get_websocket_path(portal_url, token, T::socket_path(), &Key(PublicKey::from(&private_key).to_bytes()), &self_id.to_string(), &name_suffix), callbacks); - let (sender, mut receiver) = fatal_error!(T::start(private_key, callbacks.clone()).await, callbacks); + + // This is kinda hacky, the buffer size is 1 so that we make sure that we + // process one message at a time, blocking if a previous message haven't been processed + // to force queue ordering. + let (control_plane_sender, control_plane_receiver) = tokio::sync::mpsc::channel(1); let mut connection = PhoenixChannel::<_, U, R, M>::new(connect_url, move |msg| { - let sender = sender.clone(); + let control_plane_sender = control_plane_sender.clone(); async move { tracing::trace!("Received message: {msg:?}"); - if let Err(e) = sender.send(msg).await { + if let Err(e) = control_plane_sender.send(msg).await { tracing::warn!("Received a message after handler already closed: {e}. Probably message received during session clean up."); } } }); // Used to send internal messages - let mut internal_sender = connection.sender(); let topic = T::socket_path().to_string(); - let topic_send = topic.clone(); + let internal_sender = connection.sender_with_topic(topic.clone()); + fatal_error!(T::start(private_key, control_plane_receiver, internal_sender, callbacks.clone()).await, callbacks); tokio::spawn(async move { let mut exponential_backoff = ExponentialBackoffBuilder::default().build(); loop { - let result = connection.start(vec![topic.clone()]).await; + // `connection.start` calls the callback only after connecting + let result = connection.start(vec![topic.clone()], || exponential_backoff.reset()).await; if let Some(t) = exponential_backoff.next_backoff() { tracing::warn!("Error during connection to the portal, retrying in {} seconds", t.as_secs()); match result { @@ -191,15 +198,6 @@ where }); - // TODO: Implement Sink for PhoenixEvent (created from a PhoenixSender event + topic) - // that way we can simply do receiver.forward(sender) - tokio::spawn(async move { - while let Some(message) = receiver.recv().await { - if let Err(err) = internal_sender.send(&topic_send, message).await { - tracing::error!("Channel already closed when trying to send message: {err}. Probably trying to send a message during session clean up."); - } - } - }); }); } diff --git a/rust/connlib/libs/gateway/src/control.rs b/rust/connlib/libs/gateway/src/control.rs index ec08a6e3e..12099d077 100644 --- a/rust/connlib/libs/gateway/src/control.rs +++ b/rust/connlib/libs/gateway/src/control.rs @@ -3,11 +3,12 @@ use std::{sync::Arc, time::Duration}; use boringtun::x25519::StaticSecret; use firezone_tunnel::{ControlSignal, Tunnel}; use libs_common::{ + control::PhoenixSenderWithTopic, error_type::ErrorType::{Fatal, Recoverable}, messages::ResourceDescription, Callbacks, ControlSession, Result, }; -use tokio::sync::mpsc::{channel, Receiver, Sender}; +use tokio::sync::mpsc::Receiver; use super::messages::{ ConnectionReady, EgressMessages, IngressMessages, InitGateway, RequestConnection, @@ -15,8 +16,6 @@ use super::messages::{ use async_trait::async_trait; -const INTERNAL_CHANNEL_SIZE: usize = 256; - pub struct ControlPlane { tunnel: Arc>, control_signaler: ControlSignaler, @@ -24,7 +23,7 @@ pub struct ControlPlane { #[derive(Clone)] struct ControlSignaler { - internal_sender: Arc>, + control_signal: PhoenixSenderWithTopic, } #[async_trait] @@ -63,7 +62,7 @@ impl ControlPlane { #[tracing::instrument(level = "trace", skip(self))] fn connection_request(&self, connection_request: RequestConnection) { let tunnel = Arc::clone(&self.tunnel); - let control_signaler = self.control_signaler.clone(); + let mut control_signaler = self.control_signaler.clone(); tokio::spawn(async move { match tunnel .set_peer_connection_request( @@ -74,17 +73,17 @@ impl ControlPlane { ) .await { - Ok(gateway_rtc_sdp) => { + Ok(gateway_rtc_session_description) => { if let Err(err) = control_signaler - .internal_sender + .control_signal .send(EgressMessages::ConnectionReady(ConnectionReady { - client_id: connection_request.device.id, - gateway_rtc_sdp, + reference: connection_request.reference, + gateway_rtc_session_description, })) .await { tunnel.cleanup_peer_connection(connection_request.device.id); - tunnel.callbacks().on_error(&err.into(), Recoverable); + tunnel.callbacks().on_error(&err, Recoverable); } } Err(err) => { @@ -120,23 +119,15 @@ impl ControlPlane { } #[async_trait] -impl ControlSession - for ControlPlane -{ +impl ControlSession for ControlPlane { #[tracing::instrument(level = "trace", skip(private_key, callbacks))] async fn start( private_key: StaticSecret, + receiver: Receiver, + control_signal: PhoenixSenderWithTopic, callbacks: CB, - ) -> Result<(Sender, Receiver)> { - // This is kinda hacky, the buffer size is 1 so that we make sure that we - // process one message at a time, blocking if a previous message haven't been processed - // to force queue ordering. - // (couldn't find any other guarantee of the ordering of message) - let (sender, receiver) = channel::(1); - - let (internal_sender, internal_receiver) = channel(INTERNAL_CHANNEL_SIZE); - let internal_sender = Arc::new(internal_sender); - let control_signaler = ControlSignaler { internal_sender }; + ) -> Result<()> { + let control_signaler = ControlSignaler { control_signal }; let tunnel = Arc::new(Tunnel::new(private_key, control_signaler.clone(), callbacks).await?); let control_plane = ControlPlane { @@ -144,10 +135,9 @@ impl ControlSession &'static str { diff --git a/rust/connlib/libs/gateway/src/messages.rs b/rust/connlib/libs/gateway/src/messages.rs index 5ce40cf0b..bae847b29 100644 --- a/rust/connlib/libs/gateway/src/messages.rs +++ b/rust/connlib/libs/gateway/src/messages.rs @@ -40,6 +40,10 @@ pub struct RequestConnection { pub relays: Vec, pub resource: ResourceDescription, pub device: Device, + #[serde(rename = "ref")] + pub reference: String, + // TODO: this should be a DateTime or similar + pub expires_at: u64, } #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] @@ -93,8 +97,9 @@ pub enum EgressMessages { #[derive(Debug, Deserialize, Serialize, Clone)] pub struct ConnectionReady { - pub client_id: Id, - pub gateway_rtc_sdp: RTCSessionDescription, + #[serde(rename = "ref")] + pub reference: String, + pub gateway_rtc_session_description: RTCSessionDescription, } #[cfg(test)] @@ -103,6 +108,56 @@ mod test { use super::{IngressMessages, InitGateway}; + #[test] + fn request_connection_message() { + let message = r#"{ + "ref": null, + "topic": "gateway", + "event": "request_connection", + "payload": { + "device": { + "id": "3a25ff38-f8d7-47de-9b30-c7c40c206083", + "peer": { + "ipv6": "fd00:2011:1111::3a:ab1b", + "public_key": "OR2dYCLwMEtwqtjOxSm4SU7BbHJDfM8ZCqK7HKXXxDw=", + "ipv4": "100.114.114.30", + "persistent_keepalive": 25, + "preshared_key": "sMeTuiJ3mezfpVdan948CmisIWbwBZ1z7jBNnbVtfVg=" + }, + "rtc_session_description": { + "sdp": "v=0\r\no=- 8696424395893049643 650344226 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=fingerprint:sha-256 AF:57:6F:03:CA:BD:0E:6E:F0:26:BA:B4:36:FE:2E:48:2D:FA:B7:39:84:BA:9E:FB:3F:DC:1F:46:ED:18:01:40\r\na=group:BUNDLE 0\r\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 0.0.0.0\r\na=setup:actpass\r\na=mid:0\r\na=sendrecv\r\na=sctp-port:5000\r\na=ice-ufrag:KOLSoUEJdNfpgLoM\r\na=ice-pwd:WvOTEYbBZwpRgERbKVjkPGsGwZsUoyKQ\r\na=candidate:312688668 1 udp 2130706431 172.28.0.100 46924 typ host\r\na=candidate:312688668 2 udp 2130706431 172.28.0.100 46924 typ host\r\na=candidate:1090862588 1 udp 2130706431 100.114.114.30 32969 typ host\r\na=candidate:1090862588 2 udp 2130706431 100.114.114.30 32969 typ host\r\na=candidate:2835903154 1 udp 1694498815 172.28.0.100 59817 typ srflx raddr 0.0.0.0 rport 59817\r\na=candidate:2835903154 2 udp 1694498815 172.28.0.100 59817 typ srflx raddr 0.0.0.0 rport 59817\r\na=candidate:2835903154 1 udp 1694498815 172.28.0.100 45350 typ srflx raddr 0.0.0.0 rport 45350\r\na=candidate:2835903154 2 udp 1694498815 172.28.0.100 45350 typ srflx raddr 0.0.0.0 rport 45350\r\na=candidate:167090039 1 udp 2130706431 :: 55852 typ host\r\na=candidate:167090039 2 udp 2130706431 :: 55852 typ host\r\na=end-of-candidates\r\n", + "type": "offer" + } + }, + "resource": { + "id": "ea6570d1-47c7-49d2-9dc3-efff1c0c9e0b", + "name": "172.20.0.1/16", + "type": "cidr", + "address": "172.20.0.0/16" + }, + "ref": "78e1159d-9dc6-480d-b2ef-1fcec2cd5730", + "expires_at": 1719367575, + "actor": { + "id": "3b1d86a0-4737-4814-8add-cfec42669511" + }, + "relays": [ + { + "type": "stun", + "uri": "stun:172.28.0.101:3478" + }, + { + "type": "turn", + "username": "1719367575:ZQHcVGkdnfgGmcP1", + "password": "ZWYiBeFHOJyYq0mcwAXjRpcuXIJJpzWlOXVdxwttrWg", + "uri": "turn:172.28.0.101:3478", + "expires_at": 1719367575 + } + ] + } + }"#; + // TODO: We are just testing we can deserialize for now. + let _: PhoenixMessage = serde_json::from_str(message).unwrap(); + } #[test] fn init_phoenix_message() { let m = PhoenixMessage::new( @@ -116,6 +171,7 @@ mod test { ipv4_masquerade_enabled: true, ipv6_masquerade_enabled: true, }), + None, ); let message = r#"{ diff --git a/rust/connlib/libs/tunnel/src/lib.rs b/rust/connlib/libs/tunnel/src/lib.rs index a2d98a7bb..3865b4ba5 100644 --- a/rust/connlib/libs/tunnel/src/lib.rs +++ b/rust/connlib/libs/tunnel/src/lib.rs @@ -369,11 +369,13 @@ where } TunnResult::WriteToTunnelV4(packet, addr) => { if peer.is_allowed(addr) { + tracing::trace!("Writing received peer packet to iface"); tunnel.write4_device_infallible(packet).await; } } TunnResult::WriteToTunnelV6(packet, addr) => { if peer.is_allowed(addr) { + tracing::trace!("Writing received peer packet to iface"); tunnel.write6_device_infallible(packet).await; } } diff --git a/rust/relay/src/main.rs b/rust/relay/src/main.rs index f59e64f57..4139c7aed 100644 --- a/rust/relay/src/main.rs +++ b/rust/relay/src/main.rs @@ -83,8 +83,6 @@ async fn main() -> Result<()> { let server = Server::new(args.public_ip4_addr, make_rng(args.rng_seed)); - tracing::info!("Relay auth secret: {}", server.auth_secret()); - let channel = if let Some(mut portal_url) = args.portal_ws_url { if portal_url.scheme() == "ws" && !args.allow_insecure_ws { bail!("Refusing to connect to portal over insecure connection, pass --allow-insecure-ws to override") @@ -113,7 +111,7 @@ async fn main() -> Result<()> { channel.join( "relay", JoinMessage { - stamp_secret: hex::encode(server.auth_secret()), + stamp_secret: server.auth_secret().to_string(), }, );