From be250f1e00d30df262fbf1d809e28dd5ecf80dfe Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 4 Oct 2024 00:47:58 +1000 Subject: [PATCH] refactor(connlib): repurpose `connlib-shared` as `connlib-model` (#6919) The `connlib-shared` crate has become a bit of a dependency magnet without a clear purpose. It hosts utilities like `get_user_agent`, messages for the client and gateway to communicate with the portal and domain types like `ResourceId`. To create a better dependency structure in our workspace, we repurpose `connlib-shared` as a `connlib-model` crate. Its purpose is to host domain-specific model types that multiple crates may want to use. For that purpose, we rename the `callbacks::ResourceDescription` type to `ResourceView`, designating that this is a _view_ onto a resource as seen by `connlib`. The message types which currently double up as connlib-internal model thus become an implementation detail of `firezone-tunnel` and shouldn't be used for anything else. --------- Signed-off-by: Reactor Scram Co-authored-by: Reactor Scram --- rust/Cargo.lock | 38 +-- rust/Cargo.toml | 6 +- rust/connlib/clients/android/Cargo.toml | 2 +- rust/connlib/clients/android/src/lib.rs | 9 +- rust/connlib/clients/apple/Cargo.toml | 2 +- rust/connlib/clients/apple/src/lib.rs | 8 +- rust/connlib/clients/shared/Cargo.toml | 4 +- rust/connlib/clients/shared/src/callbacks.rs | 4 +- rust/connlib/clients/shared/src/eventloop.rs | 15 +- rust/connlib/clients/shared/src/lib.rs | 12 +- rust/connlib/model/Cargo.toml | 21 ++ rust/connlib/model/src/lib.rs | 186 ++++++++++++ .../src/callbacks.rs => model/src/view.rs} | 87 +++--- rust/connlib/shared/Cargo.toml | 40 --- rust/connlib/shared/src/messages/client.rs | 286 ------------------ rust/connlib/shared/src/messages/gateway.rs | 195 ------------ rust/connlib/tunnel/Cargo.toml | 10 +- rust/connlib/tunnel/src/client.rs | 109 +++---- rust/connlib/tunnel/src/dns.rs | 4 +- rust/connlib/tunnel/src/gateway.rs | 8 +- rust/connlib/tunnel/src/lib.rs | 10 +- .../{shared => tunnel}/src/messages.rs | 124 +------- .../src/messages/client.rs} | 238 ++++++++++++++- .../tunnel/src/messages/gateway.rs} | 205 ++++++++++++- .../{shared => tunnel}/src/messages/key.rs | 2 +- rust/connlib/tunnel/src/peer.rs | 22 +- rust/connlib/tunnel/src/peer_store.rs | 2 +- rust/connlib/tunnel/src/proptest.rs | 10 +- rust/connlib/tunnel/src/tests/assertions.rs | 2 +- rust/connlib/tunnel/src/tests/reference.rs | 8 +- rust/connlib/tunnel/src/tests/sim_client.rs | 9 +- rust/connlib/tunnel/src/tests/sim_dns.rs | 2 +- rust/connlib/tunnel/src/tests/sim_gateway.rs | 6 +- rust/connlib/tunnel/src/tests/sim_net.rs | 2 +- rust/connlib/tunnel/src/tests/sim_relay.rs | 2 +- rust/connlib/tunnel/src/tests/strategies.rs | 9 +- rust/connlib/tunnel/src/tests/stub_portal.rs | 14 +- rust/connlib/tunnel/src/tests/sut.rs | 9 +- rust/connlib/tunnel/src/tests/transition.rs | 7 +- rust/connlib/tunnel/src/utils.rs | 6 +- rust/gateway/Cargo.toml | 2 +- rust/gateway/src/eventloop.rs | 17 +- rust/gateway/src/main.rs | 6 +- rust/gui-client/src-common/Cargo.toml | 8 +- rust/gui-client/src-common/src/controller.rs | 6 +- rust/gui-client/src-common/src/settings.rs | 2 +- rust/gui-client/src-common/src/system_tray.rs | 19 +- .../src-common/src/system_tray/builder.rs | 8 +- rust/gui-client/src-tauri/Cargo.toml | 6 +- rust/headless-client/Cargo.toml | 24 +- rust/headless-client/src/ipc_service.rs | 11 +- rust/headless-client/src/lib.rs | 6 +- rust/headless-client/src/main.rs | 5 +- rust/phoenix-channel/Cargo.toml | 1 + .../src/get_user_agent.rs} | 18 +- rust/phoenix-channel/src/lib.rs | 2 + 56 files changed, 902 insertions(+), 974 deletions(-) create mode 100644 rust/connlib/model/Cargo.toml create mode 100644 rust/connlib/model/src/lib.rs rename rust/connlib/{shared/src/callbacks.rs => model/src/view.rs} (72%) delete mode 100644 rust/connlib/shared/Cargo.toml delete mode 100644 rust/connlib/shared/src/messages/client.rs delete mode 100644 rust/connlib/shared/src/messages/gateway.rs rename rust/connlib/{shared => tunnel}/src/messages.rs (70%) rename rust/connlib/{clients/shared/src/messages.rs => tunnel/src/messages/client.rs} (76%) rename rust/{gateway/src/messages.rs => connlib/tunnel/src/messages/gateway.rs} (78%) rename rust/connlib/{shared => tunnel}/src/messages/key.rs (99%) rename rust/{connlib/shared/src/lib.rs => phoenix-channel/src/get_user_agent.rs} (82%) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 013896650..c9dae4a6f 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1232,7 +1232,7 @@ dependencies = [ "android_log-sys", "backoff", "connlib-client-shared", - "connlib-shared", + "connlib-model", "firezone-logging", "ip_network", "jni 0.21.1", @@ -1259,7 +1259,7 @@ dependencies = [ "anyhow", "backoff", "connlib-client-shared", - "connlib-shared", + "connlib-model", "firezone-logging", "ip_network", "libc", @@ -1287,7 +1287,7 @@ dependencies = [ "backoff", "bimap", "chrono", - "connlib-shared", + "connlib-model", "firezone-telemetry", "firezone-tunnel", "ip_network", @@ -1305,30 +1305,14 @@ dependencies = [ ] [[package]] -name = "connlib-shared" +name = "connlib-model" version = "0.1.0" dependencies = [ - "base64 0.22.1", "boringtun", - "chrono", "domain", - "futures", - "futures-util", "ip_network", "itertools 0.13.0", - "libc", - "os_info", - "phoenix-channel", - "rand 0.8.5", - "rand_core 0.6.4", - "secrecy", "serde", - "serde_json", - "swift-bridge", - "thiserror", - "tokio", - "tracing", - "url", "uuid", ] @@ -2235,7 +2219,7 @@ dependencies = [ "boringtun", "chrono", "clap", - "connlib-shared", + "connlib-model", "dns-lookup", "domain", "either", @@ -2271,7 +2255,7 @@ dependencies = [ "chrono", "clap", "connlib-client-shared", - "connlib-shared", + "connlib-model", "dirs", "firezone-bin-shared", "firezone-gui-client-common", @@ -2309,7 +2293,7 @@ dependencies = [ "anyhow", "arboard", "atomicwrites", - "connlib-shared", + "connlib-model", "dirs", "firezone-bin-shared", "firezone-headless-client", @@ -2350,7 +2334,7 @@ dependencies = [ "backoff", "clap", "connlib-client-shared", - "connlib-shared", + "connlib-model", "dirs", "firezone-bin-shared", "firezone-logging", @@ -2467,11 +2451,12 @@ name = "firezone-tunnel" version = "0.1.0" dependencies = [ "anyhow", + "base64 0.22.1", "bimap", "boringtun", "bytes", "chrono", - "connlib-shared", + "connlib-model", "derivative", "divan", "domain", @@ -2485,6 +2470,7 @@ dependencies = [ "ip_network_table", "itertools 0.13.0", "lru", + "phoenix-channel", "proptest", "proptest-state-machine", "rand 0.8.5", @@ -5557,6 +5543,7 @@ dependencies = [ "hex", "hostname", "libc", + "os_info", "rand_core 0.6.4", "secrecy", "serde", @@ -6474,7 +6461,6 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" dependencies = [ - "bytes", "serde", "zeroize", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index ab659e3a5..f2ff941e5 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -4,7 +4,7 @@ members = [ "connlib/clients/android", "connlib/clients/apple", "connlib/clients/shared", - "connlib/shared", + "connlib/model", "connlib/snownet", "connlib/tunnel", "gateway", @@ -20,7 +20,7 @@ members = [ "telemetry", "tests/gui-smoke-test", "tests/http-test-server", - "tun" + "tun", ] resolver = "2" @@ -52,7 +52,7 @@ firezone-logging = { path = "logging" } firezone-telemetry = { path = "telemetry" } snownet = { path = "connlib/snownet" } firezone-relay = { path = "relay" } -connlib-shared = { path = "connlib/shared" } +connlib-model = { path = "connlib/model" } firezone-tunnel = { path = "connlib/tunnel" } phoenix-channel = { path = "phoenix-channel" } ip-packet = { path = "ip-packet" } diff --git a/rust/connlib/clients/android/Cargo.toml b/rust/connlib/clients/android/Cargo.toml index 4075dc6de..86b242416 100644 --- a/rust/connlib/clients/android/Cargo.toml +++ b/rust/connlib/clients/android/Cargo.toml @@ -15,7 +15,7 @@ mock = ["connlib-client-shared/mock"] [dependencies] backoff = "0.4.0" connlib-client-shared = { workspace = true } -connlib-shared = { workspace = true } +connlib-model = { workspace = true } firezone-logging = { workspace = true } ip_network = "0.4" jni = { version = "0.21.1", features = ["invocation"] } diff --git a/rust/connlib/clients/android/src/lib.rs b/rust/connlib/clients/android/src/lib.rs index 77280ef4a..7ec6b734e 100644 --- a/rust/connlib/clients/android/src/lib.rs +++ b/rust/connlib/clients/android/src/lib.rs @@ -6,10 +6,9 @@ use crate::tun::Tun; use backoff::ExponentialBackoffBuilder; use connlib_client_shared::{ - keypair, Callbacks, ConnectArgs, DisconnectError, LoginUrl, LoginUrlError, Session, - V4RouteList, V6RouteList, + keypair, Callbacks, ConnectArgs, DisconnectError, Session, V4RouteList, V6RouteList, }; -use connlib_shared::{callbacks::ResourceDescription, get_user_agent, messages::ResourceId}; +use connlib_model::{ResourceId, ResourceView}; use ip_network::{Ipv4Network, Ipv6Network}; use jni::{ objects::{GlobalRef, JClass, JObject, JString, JValue}, @@ -17,7 +16,9 @@ use jni::{ sys::jlong, JNIEnv, JavaVM, }; +use phoenix_channel::get_user_agent; use phoenix_channel::PhoenixChannel; +use phoenix_channel::{LoginUrl, LoginUrlError}; use secrecy::{Secret, SecretString}; use socket_factory::{SocketFactory, TcpSocket, UdpSocket}; use std::{collections::BTreeSet, io, net::IpAddr, os::fd::AsRawFd, path::Path, sync::Arc}; @@ -225,7 +226,7 @@ impl Callbacks for CallbackHandler { .expect("onUpdateRoutes callback failed"); } - fn on_update_resources(&self, resource_list: Vec) { + fn on_update_resources(&self, resource_list: Vec) { self.env(|mut env| { let resource_list = env .new_string(serde_json::to_string(&resource_list)?) diff --git a/rust/connlib/clients/apple/Cargo.toml b/rust/connlib/clients/apple/Cargo.toml index d34dcd908..47d54f02d 100644 --- a/rust/connlib/clients/apple/Cargo.toml +++ b/rust/connlib/clients/apple/Cargo.toml @@ -14,7 +14,7 @@ swift-bridge-build = "0.1.57" anyhow = "1.0.86" backoff = "0.4.0" connlib-client-shared = { workspace = true } -connlib-shared = { workspace = true } +connlib-model = { workspace = true } firezone-logging = { workspace = true } ip_network = "0.4" libc = "0.2" diff --git a/rust/connlib/clients/apple/src/lib.rs b/rust/connlib/clients/apple/src/lib.rs index b16f62bbb..4e1bcc0b5 100644 --- a/rust/connlib/clients/apple/src/lib.rs +++ b/rust/connlib/clients/apple/src/lib.rs @@ -7,10 +7,12 @@ mod tun; use anyhow::Result; use backoff::ExponentialBackoffBuilder; use connlib_client_shared::{ - keypair, Callbacks, ConnectArgs, DisconnectError, LoginUrl, Session, V4RouteList, V6RouteList, + keypair, Callbacks, ConnectArgs, DisconnectError, Session, V4RouteList, V6RouteList, }; -use connlib_shared::{callbacks::ResourceDescription, get_user_agent}; +use connlib_model::ResourceView; use ip_network::{Ipv4Network, Ipv6Network}; +use phoenix_channel::get_user_agent; +use phoenix_channel::LoginUrl; use phoenix_channel::PhoenixChannel; use secrecy::{Secret, SecretString}; use std::{ @@ -139,7 +141,7 @@ impl Callbacks for CallbackHandler { ); } - fn on_update_resources(&self, resource_list: Vec) { + fn on_update_resources(&self, resource_list: Vec) { self.inner.on_update_resources( serde_json::to_string(&resource_list) .expect("developer error: failed to serialize resource list"), diff --git a/rust/connlib/clients/shared/Cargo.toml b/rust/connlib/clients/shared/Cargo.toml index 7def15aed..b870dd632 100644 --- a/rust/connlib/clients/shared/Cargo.toml +++ b/rust/connlib/clients/shared/Cargo.toml @@ -4,13 +4,13 @@ version = "0.1.0" edition = "2021" [features] -mock = ["connlib-shared/mock"] +mock = ["connlib-model/mock"] [dependencies] anyhow = "1.0.82" backoff = { workspace = true } bimap = "0.6" -connlib-shared = { workspace = true } +connlib-model = { workspace = true } firezone-telemetry = { workspace = true } firezone-tunnel = { workspace = true } ip_network = { version = "0.4", default-features = false } diff --git a/rust/connlib/clients/shared/src/callbacks.rs b/rust/connlib/clients/shared/src/callbacks.rs index 8d2d1f1b6..ac9bb16a0 100644 --- a/rust/connlib/clients/shared/src/callbacks.rs +++ b/rust/connlib/clients/shared/src/callbacks.rs @@ -1,4 +1,4 @@ -use connlib_shared::callbacks::ResourceDescription; +use connlib_model::ResourceView; use ip_network::{Ipv4Network, Ipv6Network}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; @@ -19,7 +19,7 @@ pub trait Callbacks: Clone + Send + Sync { /// This may not be called if a Client has no Resources, which can /// happen to new accounts, or when removing and re-adding Resources, /// or if all Resources for a user are disabled by policy. - fn on_update_resources(&self, _: Vec) {} + fn on_update_resources(&self, _: Vec) {} /// Called when the tunnel is disconnected. /// diff --git a/rust/connlib/clients/shared/src/eventloop.rs b/rust/connlib/clients/shared/src/eventloop.rs index 46454f138..7ce627312 100644 --- a/rust/connlib/clients/shared/src/eventloop.rs +++ b/rust/connlib/clients/shared/src/eventloop.rs @@ -1,16 +1,7 @@ -use crate::{ - callbacks::Callbacks, - messages::{ - Connect, ConnectionDetails, EgressMessages, GatewayIceCandidates, GatewaysIceCandidates, - IngressMessages, InitClient, ReplyMessages, - }, - PHOENIX_TOPIC, -}; +use crate::{callbacks::Callbacks, PHOENIX_TOPIC}; use anyhow::Result; -use connlib_shared::messages::{ - ClientPayload, ConnectionAccepted, GatewayResponse, RelaysPresence, RequestConnection, - ResourceAccepted, ResourceId, ReuseConnection, -}; +use connlib_model::ResourceId; +use firezone_tunnel::messages::{client::*, *}; use firezone_tunnel::ClientTunnel; use phoenix_channel::{ErrorReply, OutboundRequestId, PhoenixChannel}; use std::{ diff --git a/rust/connlib/clients/shared/src/lib.rs b/rust/connlib/clients/shared/src/lib.rs index 27aeb648d..892adcd70 100644 --- a/rust/connlib/clients/shared/src/lib.rs +++ b/rust/connlib/clients/shared/src/lib.rs @@ -1,16 +1,17 @@ //! Main connlib library for clients. pub use crate::serde_routelist::{V4RouteList, V6RouteList}; pub use callbacks::{Callbacks, DisconnectError}; -pub use connlib_shared::messages::client::ResourceDescription; -pub use connlib_shared::{LoginUrl, LoginUrlError, StaticSecret}; +pub use connlib_model::StaticSecret; pub use eventloop::Eventloop; pub use firezone_tunnel::keypair; +pub use firezone_tunnel::messages::client::{ + ResourceDescription, {IngressMessages, ReplyMessages}, +}; -use connlib_shared::messages::ResourceId; +use connlib_model::ResourceId; use eventloop::Command; use firezone_telemetry as telemetry; use firezone_tunnel::ClientTunnel; -use messages::{IngressMessages, ReplyMessages}; use phoenix_channel::PhoenixChannel; use socket_factory::{SocketFactory, TcpSocket, UdpSocket}; use std::collections::{BTreeMap, BTreeSet}; @@ -22,7 +23,6 @@ use tun::Tun; mod callbacks; mod eventloop; -mod messages; mod serde_routelist; const PHOENIX_TOPIC: &str = "client"; @@ -46,7 +46,7 @@ pub struct ConnectArgs { impl Session { /// Creates a new [`Session`]. /// - /// This connects to the portal a specified using [`LoginUrl`] and creates a wireguard tunnel using the provided private key. + /// This connects to the portal using the given [`LoginUrl`](phoenix_channel::LoginUrl) and creates a wireguard tunnel using the provided private key. pub fn connect( args: ConnectArgs, portal: PhoenixChannel<(), IngressMessages, ReplyMessages>, diff --git a/rust/connlib/model/Cargo.toml b/rust/connlib/model/Cargo.toml new file mode 100644 index 000000000..552e6f700 --- /dev/null +++ b/rust/connlib/model/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "connlib-model" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +mock = [] + +[dependencies] +boringtun = { workspace = true } +domain = { workspace = true } +ip_network = { version = "0.4", default-features = false, features = ["serde"] } +serde = { version = "1.0", default-features = false, features = ["derive", "std"] } +uuid = { version = "1.10", default-features = false, features = ["std", "v4", "serde"] } + +[dev-dependencies] +itertools = "0.13" + +[lints] +workspace = true diff --git a/rust/connlib/model/src/lib.rs b/rust/connlib/model/src/lib.rs new file mode 100644 index 000000000..cfe49eeb3 --- /dev/null +++ b/rust/connlib/model/src/lib.rs @@ -0,0 +1,186 @@ +//! This crates contains shared types and behavior between all the other libraries. +//! +//! This includes types provided by external crates, i.e. [boringtun] to make sure that +//! we are using the same version across our own crates. + +mod view; + +pub use boringtun::x25519::PublicKey; +pub use boringtun::x25519::StaticSecret; +pub use view::{ + CidrResourceView, DnsResourceView, InternetResourceView, ResourceStatus, ResourceView, +}; + +pub type DomainName = domain::base::Name>; + +use serde::{Deserialize, Serialize}; +use std::fmt; +use std::str::FromStr; +use uuid::Uuid; + +#[derive(Hash, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct GatewayId(Uuid); + +#[derive(Hash, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct ResourceId(Uuid); + +#[derive(Hash, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct RelayId(Uuid); + +impl RelayId { + pub fn from_u128(v: u128) -> Self { + Self(Uuid::from_u128(v)) + } +} + +impl FromStr for RelayId { + type Err = uuid::Error; + + fn from_str(s: &str) -> Result { + Ok(RelayId(Uuid::parse_str(s)?)) + } +} + +impl ResourceId { + pub fn random() -> ResourceId { + ResourceId(Uuid::new_v4()) + } + + pub fn from_u128(v: u128) -> Self { + Self(Uuid::from_u128(v)) + } +} + +impl GatewayId { + pub fn from_u128(v: u128) -> Self { + Self(Uuid::from_u128(v)) + } +} + +#[derive(Hash, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct ClientId(Uuid); + +impl FromStr for ClientId { + type Err = uuid::Error; + + fn from_str(s: &str) -> Result { + Ok(ClientId(Uuid::parse_str(s)?)) + } +} + +impl ClientId { + pub fn from_u128(v: u128) -> Self { + Self(Uuid::from_u128(v)) + } +} + +impl FromStr for ResourceId { + type Err = uuid::Error; + + fn from_str(s: &str) -> Result { + Ok(ResourceId(Uuid::parse_str(s)?)) + } +} + +impl FromStr for GatewayId { + type Err = uuid::Error; + + fn from_str(s: &str) -> Result { + Ok(GatewayId(Uuid::parse_str(s)?)) + } +} + +impl fmt::Display for ResourceId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl fmt::Display for ClientId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl fmt::Display for GatewayId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl fmt::Display for RelayId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl fmt::Debug for ResourceId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self, f) + } +} + +impl fmt::Debug for ClientId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self, f) + } +} + +impl fmt::Debug for GatewayId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self, f) + } +} + +impl fmt::Debug for RelayId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self, f) + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialOrd, Ord)] +pub struct Site { + pub id: SiteId, + pub name: String, +} + +impl std::hash::Hash for Site { + fn hash(&self, state: &mut H) { + self.id.hash(state); + } +} + +impl PartialEq for Site { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +#[derive(Deserialize, Serialize, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct SiteId(Uuid); + +impl FromStr for SiteId { + type Err = uuid::Error; + + fn from_str(s: &str) -> Result { + Ok(SiteId(Uuid::parse_str(s)?)) + } +} + +impl SiteId { + pub fn from_u128(v: u128) -> Self { + Self(Uuid::from_u128(v)) + } +} + +impl fmt::Display for SiteId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl fmt::Debug for SiteId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self, f) + } +} diff --git a/rust/connlib/shared/src/callbacks.rs b/rust/connlib/model/src/view.rs similarity index 72% rename from rust/connlib/shared/src/callbacks.rs rename to rust/connlib/model/src/view.rs index 5c0b917fd..fb628e29a 100644 --- a/rust/connlib/shared/src/callbacks.rs +++ b/rust/connlib/model/src/view.rs @@ -3,11 +3,11 @@ use serde::{Deserialize, Serialize}; use std::borrow::Cow; use std::fmt::Debug; -use crate::messages::client::Site; -use crate::messages::ResourceId; +use crate::ResourceId; +use crate::Site; #[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum Status { +pub enum ResourceStatus { Unknown, Online, Offline, @@ -15,69 +15,69 @@ pub enum Status { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] #[serde(tag = "type", rename_all = "snake_case")] -pub enum ResourceDescription { - Dns(ResourceDescriptionDns), - Cidr(ResourceDescriptionCidr), - Internet(ResourceDescriptionInternet), +pub enum ResourceView { + Dns(DnsResourceView), + Cidr(CidrResourceView), + Internet(InternetResourceView), } -impl ResourceDescription { +impl ResourceView { pub fn address_description(&self) -> Option<&str> { match self { - ResourceDescription::Dns(r) => r.address_description.as_deref(), - ResourceDescription::Cidr(r) => r.address_description.as_deref(), - ResourceDescription::Internet(_) => None, + ResourceView::Dns(r) => r.address_description.as_deref(), + ResourceView::Cidr(r) => r.address_description.as_deref(), + ResourceView::Internet(_) => None, } } pub fn name(&self) -> &str { match self { - ResourceDescription::Dns(r) => &r.name, - ResourceDescription::Cidr(r) => &r.name, - ResourceDescription::Internet(r) => &r.name, + ResourceView::Dns(r) => &r.name, + ResourceView::Cidr(r) => &r.name, + ResourceView::Internet(r) => &r.name, } } - pub fn status(&self) -> Status { + pub fn status(&self) -> ResourceStatus { match self { - ResourceDescription::Dns(r) => r.status, - ResourceDescription::Cidr(r) => r.status, - ResourceDescription::Internet(r) => r.status, + ResourceView::Dns(r) => r.status, + ResourceView::Cidr(r) => r.status, + ResourceView::Internet(r) => r.status, } } pub fn id(&self) -> ResourceId { match self { - ResourceDescription::Dns(r) => r.id, - ResourceDescription::Cidr(r) => r.id, - ResourceDescription::Internet(r) => r.id, + ResourceView::Dns(r) => r.id, + ResourceView::Cidr(r) => r.id, + ResourceView::Internet(r) => r.id, } } /// What the GUI clients should paste to the clipboard, e.g. `https://github.com/firezone` pub fn pastable(&self) -> Cow<'_, str> { match self { - ResourceDescription::Dns(r) => Cow::from(&r.address), - ResourceDescription::Cidr(r) => Cow::from(r.address.to_string()), - ResourceDescription::Internet(_) => Cow::default(), + ResourceView::Dns(r) => Cow::from(&r.address), + ResourceView::Cidr(r) => Cow::from(r.address.to_string()), + ResourceView::Internet(_) => Cow::default(), } } pub fn sites(&self) -> &[Site] { match self { - ResourceDescription::Dns(r) => &r.sites, - ResourceDescription::Cidr(r) => &r.sites, - ResourceDescription::Internet(r) => &r.sites, + ResourceView::Dns(r) => &r.sites, + ResourceView::Cidr(r) => &r.sites, + ResourceView::Internet(r) => &r.sites, } } pub fn is_internet_resource(&self) -> bool { - matches!(self, ResourceDescription::Internet(_)) + matches!(self, ResourceView::Internet(_)) } } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] -pub struct ResourceDescriptionDns { +pub struct DnsResourceView { /// Resource's id. pub id: ResourceId, /// Internal resource's domain name. @@ -90,12 +90,12 @@ pub struct ResourceDescriptionDns { pub address_description: Option, pub sites: Vec, - pub status: Status, + pub status: ResourceStatus, } /// Description of a resource that maps to a CIDR. #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct ResourceDescriptionCidr { +pub struct CidrResourceView { /// Resource's id. pub id: ResourceId, /// CIDR that this resource points to. @@ -108,28 +108,28 @@ pub struct ResourceDescriptionCidr { pub address_description: Option, pub sites: Vec, - pub status: Status, + pub status: ResourceStatus, } /// Description of an Internet resource #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct ResourceDescriptionInternet { +pub struct InternetResourceView { /// Name for display always set to "Internet Resource" pub name: String, pub id: ResourceId, pub sites: Vec, - pub status: Status, + pub status: ResourceStatus, } -impl PartialOrd for ResourceDescription { +impl PartialOrd for ResourceView { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for ResourceDescription { +impl Ord for ResourceView { fn cmp(&self, other: &Self) -> std::cmp::Ordering { if self.is_internet_resource() { return std::cmp::Ordering::Less; @@ -150,12 +150,11 @@ mod tests { use itertools::Itertools; use super::{ - ResourceDescription, ResourceDescriptionDns, ResourceDescriptionInternet, ResourceId, Site, - Status, + DnsResourceView, InternetResourceView, ResourceId, ResourceStatus, ResourceView, Site, }; - fn fake_resource(name: &str, uuid: &str) -> ResourceDescription { - ResourceDescription::Dns(ResourceDescriptionDns { + fn fake_resource(name: &str, uuid: &str) -> ResourceView { + ResourceView::Dns(DnsResourceView { id: ResourceId::from_str(uuid).unwrap(), name: name.to_string(), address: "unused.example.com".to_string(), @@ -164,19 +163,19 @@ mod tests { name: "test".to_string(), id: "99ba0c1e-5189-4cfc-a4db-fd6cb1c937fd".parse().unwrap(), }], - status: Status::Online, + status: ResourceStatus::Online, }) } - fn internet_resource(uuid: &str) -> ResourceDescription { - ResourceDescription::Internet(ResourceDescriptionInternet { + fn internet_resource(uuid: &str) -> ResourceView { + ResourceView::Internet(InternetResourceView { name: "Internet Resource".to_string(), id: ResourceId::from_str(uuid).unwrap(), sites: vec![Site { name: "test".to_string(), id: "99ba0c1e-5189-4cfc-a4db-fd6cb1c937fd".parse().unwrap(), }], - status: Status::Offline, + status: ResourceStatus::Offline, }) } diff --git a/rust/connlib/shared/Cargo.toml b/rust/connlib/shared/Cargo.toml deleted file mode 100644 index 93b52cb11..000000000 --- a/rust/connlib/shared/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -[package] -name = "connlib-shared" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[features] -mock = [] - -[dependencies] -base64 = { version = "0.22", default-features = false, features = ["std"] } -boringtun = { workspace = true } -chrono = { workspace = true } -domain = { workspace = true } -futures = { version = "0.3", default-features = false, features = ["std", "async-await", "executor"] } -futures-util = { version = "0.3", default-features = false, features = ["std", "async-await", "async-await-macro"] } -ip_network = { version = "0.4", default-features = false, features = ["serde"] } -itertools = "0.13" -libc = "0.2" -os_info = { version = "3", default-features = false } -phoenix-channel = { workspace = true } -rand = { version = "0.8", default-features = false, features = ["std"] } -rand_core = { version = "0.6.4", default-features = false, features = ["std"] } -secrecy = { workspace = true, features = ["serde", "bytes"] } -serde = { version = "1.0", default-features = false, features = ["derive", "std"] } -serde_json = { version = "1.0", default-features = false, features = ["std"] } -thiserror = { version = "1.0", default-features = false } -tokio = { workspace = true, features = ["fs"] } -tracing = { workspace = true } -url = { version = "2.5.2", default-features = false } -uuid = { version = "1.10", default-features = false, features = ["std", "v4", "serde"] } - -[dev-dependencies] -tokio = { version = "1.39", features = ["macros", "rt"] } - -[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] -swift-bridge = { workspace = true } - -[lints] -workspace = true diff --git a/rust/connlib/shared/src/messages/client.rs b/rust/connlib/shared/src/messages/client.rs deleted file mode 100644 index 3c7c29623..000000000 --- a/rust/connlib/shared/src/messages/client.rs +++ /dev/null @@ -1,286 +0,0 @@ -//! Client related messages that are needed within connlib - -use std::{collections::BTreeSet, fmt, str::FromStr}; - -use ip_network::IpNetwork; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -use crate::callbacks::Status; - -use super::ResourceId; -use itertools::Itertools; - -/// Description of a resource that maps to a DNS record. -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct ResourceDescriptionDns { - /// Resource's id. - pub id: ResourceId, - /// Internal resource's domain name. - pub address: String, - /// Name of the resource. - /// - /// Used only for display. - pub name: String, - - pub address_description: Option, - #[serde(rename = "gateway_groups")] - pub sites: Vec, -} - -impl ResourceDescriptionDns { - pub fn with_status(self, status: Status) -> crate::callbacks::ResourceDescriptionDns { - crate::callbacks::ResourceDescriptionDns { - id: self.id, - address: self.address, - name: self.name, - address_description: self.address_description, - sites: self.sites, - status, - } - } -} - -/// Description of a resource that maps to a CIDR. -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct ResourceDescriptionCidr { - /// Resource's id. - pub id: ResourceId, - /// CIDR that this resource points to. - pub address: IpNetwork, - /// Name of the resource. - /// - /// Used only for display. - pub name: String, - - pub address_description: Option, - #[serde(rename = "gateway_groups")] - pub sites: Vec, -} - -impl ResourceDescriptionCidr { - pub fn with_status(self, status: Status) -> crate::callbacks::ResourceDescriptionCidr { - crate::callbacks::ResourceDescriptionCidr { - id: self.id, - address: self.address, - name: self.name, - address_description: self.address_description, - sites: self.sites, - status, - } - } -} - -fn internet_resource_name() -> String { - "Internet Resource".to_string() -} - -/// Description of an internet resource. -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct ResourceDescriptionInternet { - /// Name of the resource. - /// - /// Used only for display. - #[serde(default = "internet_resource_name")] - pub name: String, - /// Resource's id. - pub id: ResourceId, - /// Sites for the internet resource - #[serde(rename = "gateway_groups")] - pub sites: Vec, -} - -impl ResourceDescriptionInternet { - pub fn with_status(self, status: Status) -> crate::callbacks::ResourceDescriptionInternet { - crate::callbacks::ResourceDescriptionInternet { - name: self.name, - id: self.id, - sites: self.sites, - status, - } - } -} - -#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialOrd, Ord)] -pub struct Site { - pub id: SiteId, - pub name: String, -} - -impl std::hash::Hash for Site { - fn hash(&self, state: &mut H) { - self.id.hash(state); - } -} - -impl PartialEq for Site { - fn eq(&self, other: &Self) -> bool { - self.id == other.id - } -} - -#[derive(Deserialize, Serialize, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct SiteId(Uuid); - -impl FromStr for SiteId { - type Err = uuid::Error; - - fn from_str(s: &str) -> Result { - Ok(SiteId(Uuid::parse_str(s)?)) - } -} - -impl SiteId { - pub fn from_u128(v: u128) -> Self { - Self(Uuid::from_u128(v)) - } -} - -impl fmt::Display for SiteId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl fmt::Debug for SiteId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self, f) - } -} - -impl ResourceDescription { - pub fn address_string(&self) -> Option { - match self { - ResourceDescription::Dns(d) => Some(d.address.clone()), - ResourceDescription::Cidr(c) => Some(c.address.to_string()), - ResourceDescription::Internet(_) => None, - } - } - - pub fn sites_string(&self) -> String { - self.sites().iter().map(|s| &s.name).join("|") - } - - pub fn id(&self) -> ResourceId { - match self { - ResourceDescription::Dns(r) => r.id, - ResourceDescription::Cidr(r) => r.id, - ResourceDescription::Internet(r) => r.id, - } - } - - pub fn sites(&self) -> BTreeSet<&Site> { - match self { - ResourceDescription::Dns(r) => BTreeSet::from_iter(r.sites.iter()), - ResourceDescription::Cidr(r) => BTreeSet::from_iter(r.sites.iter()), - ResourceDescription::Internet(r) => BTreeSet::from_iter(r.sites.iter()), - } - } - - pub fn sites_mut(&mut self) -> &mut Vec { - match self { - ResourceDescription::Dns(r) => &mut r.sites, - ResourceDescription::Cidr(r) => &mut r.sites, - ResourceDescription::Internet(r) => &mut r.sites, - } - } - - /// What the GUI clients should show as the user-friendly display name, e.g. `Firezone GitHub` - pub fn name(&self) -> &str { - match self { - ResourceDescription::Dns(r) => &r.name, - ResourceDescription::Cidr(r) => &r.name, - ResourceDescription::Internet(_) => "Internet", - } - } - - pub fn has_different_address(&self, other: &ResourceDescription) -> bool { - match (self, other) { - (ResourceDescription::Dns(dns_a), ResourceDescription::Dns(dns_b)) => { - dns_a.address != dns_b.address - } - (ResourceDescription::Cidr(cidr_a), ResourceDescription::Cidr(cidr_b)) => { - cidr_a.address != cidr_b.address - } - (ResourceDescription::Internet(_), ResourceDescription::Internet(_)) => false, - _ => true, - } - } - - pub fn with_status(self, status: Status) -> crate::callbacks::ResourceDescription { - match self { - ResourceDescription::Dns(r) => { - crate::callbacks::ResourceDescription::Dns(r.with_status(status)) - } - ResourceDescription::Cidr(r) => { - crate::callbacks::ResourceDescription::Cidr(r.with_status(status)) - } - ResourceDescription::Internet(r) => { - crate::callbacks::ResourceDescription::Internet(r.with_status(status)) - } - } - } -} - -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Hash)] -#[serde(tag = "type", rename_all = "snake_case")] -pub enum ResourceDescription { - Dns(ResourceDescriptionDns), - Cidr(ResourceDescriptionCidr), - Internet(ResourceDescriptionInternet), -} - -impl ResourceDescription { - pub fn into_dns(self) -> Option { - match self { - ResourceDescription::Dns(d) => Some(d), - ResourceDescription::Cidr(_) | ResourceDescription::Internet(_) => None, - } - } - - pub fn into_cidr(self) -> Option { - match self { - ResourceDescription::Cidr(c) => Some(c), - ResourceDescription::Dns(_) | ResourceDescription::Internet(_) => None, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn can_deserialize_internet_resource() { - let resources = r#"[ - { - "id": "73037362-715d-4a83-a749-f18eadd970e6", - "type": "cidr", - "name": "172.172.0.0/16", - "address": "172.172.0.0/16", - "address_description": "cidr resource", - "gateway_groups": [{"name": "test", "id": "bf56f32d-7b2c-4f5d-a784-788977d014a4"}] - }, - { - "id": "03000143-e25e-45c7-aafb-144990e57dcd", - "type": "dns", - "name": "gitlab.mycorp.com", - "address": "gitlab.mycorp.com", - "address_description": "dns resource", - "gateway_groups": [{"name": "test", "id": "bf56f32d-7b2c-4f5d-a784-788977d014a4"}] - }, - { - "id": "1106047c-cd5d-4151-b679-96b93da7383b", - "type": "internet", - "name": "Internet Resource", - "gateway_groups": [{"name": "test", "id": "eb94482a-94f4-47cb-8127-14fb3afa5516"}], - "not": "relevant", - "some_other": [ - "field" - ] - } - ]"#; - - serde_json::from_str::>(resources).unwrap(); - } -} diff --git a/rust/connlib/shared/src/messages/gateway.rs b/rust/connlib/shared/src/messages/gateway.rs deleted file mode 100644 index 56a49048f..000000000 --- a/rust/connlib/shared/src/messages/gateway.rs +++ /dev/null @@ -1,195 +0,0 @@ -//! Gateway related messages that are needed within connlib - -use ip_network::IpNetwork; -use serde::Deserialize; - -use super::ResourceId; - -pub type Filters = Vec; - -/// Description of a resource that maps to a DNS record. -#[derive(Debug, Deserialize, Clone, PartialEq, Eq)] -pub struct ResourceDescriptionDns { - /// Resource's id. - pub id: ResourceId, - /// Internal resource's domain name. - pub address: String, - /// Name of the resource. - /// - /// Used only for display. - pub name: String, - - pub filters: Filters, -} - -/// Description of a resource that maps to a CIDR. -#[derive(Debug, Deserialize, Clone, PartialEq, Eq)] -pub struct ResourceDescriptionCidr { - /// Resource's id. - pub id: ResourceId, - /// CIDR that this resource points to. - pub address: IpNetwork, - /// Name of the resource. - /// - /// Used only for display. - pub name: String, - - pub filters: Filters, -} - -/// Description of an Internet resource. -#[derive(Debug, Deserialize, Clone, PartialEq, Eq)] -pub struct ResourceDescriptionInternet { - pub id: ResourceId, -} - -#[derive(Debug, Deserialize, Clone, PartialEq, Eq)] -#[serde(tag = "type", rename_all = "snake_case")] -pub enum ResourceDescription { - Dns(ResourceDescriptionDns), - Cidr(ResourceDescriptionCidr), - Internet(ResourceDescriptionInternet), -} - -#[derive(Debug, Deserialize, Clone, Copy, PartialEq, Eq, Hash)] -#[serde(tag = "protocol", rename_all = "snake_case")] -pub enum Filter { - Udp(PortRange), - Tcp(PortRange), - Icmp, -} - -#[derive(Debug, Deserialize, Clone, Copy, PartialEq, Eq, Hash)] -pub struct PortRange { - // TODO: we can use a custom deserializer - // or maybe change the control plane to use start and end would suffice - #[serde(default = "max_port")] - pub port_range_end: u16, - #[serde(default = "min_port")] - pub port_range_start: u16, -} - -// Note: these 2 functions are needed since serde doesn't yet support default_value -// see serde-rs/serde#368 -fn min_port() -> u16 { - 0 -} - -fn max_port() -> u16 { - u16::MAX -} - -impl ResourceDescription { - pub fn id(&self) -> ResourceId { - match self { - ResourceDescription::Dns(r) => r.id, - ResourceDescription::Cidr(r) => r.id, - ResourceDescription::Internet(r) => r.id, - } - } - - pub fn filters(&self) -> Vec { - match self { - ResourceDescription::Dns(r) => r.filters.clone(), - ResourceDescription::Cidr(r) => r.filters.clone(), - ResourceDescription::Internet(_) => Vec::default(), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn can_deserialize_udp_filter() { - let msg = r#"{ "protocol": "udp", "port_range_start": 10, "port_range_end": 20 }"#; - let expected_filter = Filter::Udp(PortRange { - port_range_start: 10, - port_range_end: 20, - }); - - let actual_filter = serde_json::from_str(msg).unwrap(); - - assert_eq!(expected_filter, actual_filter); - } - - #[test] - fn can_deserialize_empty_udp_filter() { - let msg = r#"{ "protocol": "udp" }"#; - let expected_filter = Filter::Udp(PortRange { - port_range_start: 0, - port_range_end: u16::MAX, - }); - - let actual_filter = serde_json::from_str(msg).unwrap(); - - assert_eq!(expected_filter, actual_filter); - } - - #[test] - fn can_deserialize_tcp_filter() { - let msg = r#"{ "protocol": "tcp", "port_range_start": 10, "port_range_end": 20 }"#; - let expected_filter = Filter::Tcp(PortRange { - port_range_start: 10, - port_range_end: 20, - }); - - let actual_filter = serde_json::from_str(msg).unwrap(); - - assert_eq!(expected_filter, actual_filter); - } - - #[test] - fn can_deserialize_empty_tcp_filter() { - let msg = r#"{ "protocol": "tcp" }"#; - let expected_filter = Filter::Tcp(PortRange { - port_range_start: 0, - port_range_end: u16::MAX, - }); - - let actual_filter = serde_json::from_str(msg).unwrap(); - - assert_eq!(expected_filter, actual_filter); - } - - #[test] - fn can_deserialize_icmp_filter() { - let msg = r#"{ "protocol": "icmp" }"#; - let expected_filter = Filter::Icmp; - - let actual_filter = serde_json::from_str(msg).unwrap(); - - assert_eq!(expected_filter, actual_filter); - } - - #[test] - fn can_deserialize_internet_resource() { - let resources = r#"[ - { - "id": "73037362-715d-4a83-a749-f18eadd970e6", - "type": "cidr", - "address": "172.172.0.0/16", - "name": "172.172.0.0/16", - "filters": [] - }, - { - "id": "03000143-e25e-45c7-aafb-144990e57dcd", - "type": "dns", - "name": "gitlab.mycorp.com", - "address": "gitlab.mycorp.com", - "filters": [] - }, - { - "id": "1106047c-cd5d-4151-b679-96b93da7383b", - "type": "internet", - "not": "relevant", - "some_other": [ - "field" - ] - } - ]"#; - - serde_json::from_str::>(resources).unwrap(); - } -} diff --git a/rust/connlib/tunnel/Cargo.toml b/rust/connlib/tunnel/Cargo.toml index d737b66a1..650078c58 100644 --- a/rust/connlib/tunnel/Cargo.toml +++ b/rust/connlib/tunnel/Cargo.toml @@ -5,16 +5,17 @@ edition = "2021" [dependencies] anyhow = "1.0" +base64 = { version = "0.22", default-features = false, features = ["std"] } bimap = "0.6" boringtun = { workspace = true } bytes = { version = "1.7", default-features = false, features = ["std"] } chrono = { workspace = true } -connlib-shared = { workspace = true } +connlib-model = { workspace = true } derivative = "2.2.0" divan = { version = "0.1.14", optional = true } domain = { workspace = true } -futures = { version = "0.3", default-features = false, features = ["std", "async-await", "executor"] } -futures-util = { version = "0.3", default-features = false, features = ["std", "async-await", "async-await-macro"] } +futures = { version = "0.3", default-features = false, features = ["std", "async-await", "executor"] } +futures-util = { version = "0.3", default-features = false, features = ["std", "async-await", "async-await-macro"] } glob = "0.3.1" hex = "0.4.3" ip-packet = { workspace = true } @@ -25,7 +26,7 @@ lru = "0.12.4" proptest = { version = "1", optional = true } rand = "0.8.5" rangemap = "1.5.1" -secrecy = { workspace = true } +secrecy = { workspace = true, features = ["serde"] } serde = { version = "1.0", default-features = false, features = ["derive", "std"] } snownet = { workspace = true } socket-factory = { workspace = true } @@ -40,6 +41,7 @@ uuid = { version = "1.10", default-features = false, features = ["std", "v4"] } derivative = "2.2.0" firezone-relay = { workspace = true, features = ["proptest"] } ip-packet = { workspace = true, features = ["proptest"] } +phoenix-channel = { workspace = true } proptest-state-machine = "0.3" rand = "0.8" serde_json = "1.0" diff --git a/rust/connlib/tunnel/src/client.rs b/rust/connlib/tunnel/src/client.rs index 64bb7f8d0..b22161a70 100644 --- a/rust/connlib/tunnel/src/client.rs +++ b/rust/connlib/tunnel/src/client.rs @@ -1,16 +1,16 @@ use crate::dns::StubResolver; +use crate::messages::ResolveRequest; +use crate::messages::{ + client::ResourceDescription, client::ResourceDescriptionCidr, Answer, DnsServer, + Interface as InterfaceConfig, IpDnsServer, Key, Offer, Relay, +}; use crate::peer_store::PeerStore; use crate::{dns, TunConfig}; use anyhow::Context; use bimap::BiMap; -use connlib_shared::callbacks::Status; -use connlib_shared::messages::client::{Site, SiteId}; -use connlib_shared::messages::ResolveRequest; -use connlib_shared::messages::{ - client::ResourceDescription, client::ResourceDescriptionCidr, Answer, DnsServer, GatewayId, - Interface as InterfaceConfig, IpDnsServer, Key, Offer, Relay, RelayId, ResourceId, -}; -use connlib_shared::{callbacks, PublicKey, StaticSecret}; +use connlib_model::{GatewayId, RelayId, ResourceId, ResourceStatus, ResourceView}; +use connlib_model::{PublicKey, StaticSecret}; +use connlib_model::{Site, SiteId}; use ip_network::{IpNetwork, Ipv4Network, Ipv6Network}; use ip_network_table::IpNetworkTable; use ip_packet::IpPacket; @@ -204,7 +204,7 @@ pub struct ClientState { /// The site a gateway belongs to. gateways_site: HashMap, /// The online/offline status of a site. - sites_status: HashMap, + sites_status: HashMap, /// All CIDR resources we know about, indexed by the IP range they cover (like `1.1.0.0/8`). active_cidr_resources: IpNetworkTable, @@ -317,7 +317,7 @@ impl ClientState { self.node.num_connections() } - pub(crate) fn resources(&self) -> Vec { + pub(crate) fn resources(&self) -> Vec { self.resources_by_id .values() .cloned() @@ -329,24 +329,24 @@ impl ClientState { .collect_vec() } - fn resource_status(&self, resource: &ResourceDescription) -> Status { + fn resource_status(&self, resource: &ResourceDescription) -> ResourceStatus { if resource.sites().iter().any(|s| { self.sites_status .get(&s.id) - .is_some_and(|s| *s == Status::Online) + .is_some_and(|s| *s == ResourceStatus::Online) }) { - return Status::Online; + return ResourceStatus::Online; } if resource.sites().iter().all(|s| { self.sites_status .get(&s.id) - .is_some_and(|s| *s == Status::Offline) + .is_some_and(|s| *s == ResourceStatus::Offline) }) { - return Status::Offline; + return ResourceStatus::Offline; } - Status::Unknown + ResourceStatus::Unknown } fn set_resource_offline(&mut self, id: ResourceId) { @@ -355,7 +355,7 @@ impl ClientState { }; for Site { id, .. } in resource.sites() { - self.sites_status.insert(*id, Status::Offline); + self.sites_status.insert(*id, ResourceStatus::Offline); } } @@ -814,7 +814,7 @@ impl ClientState { #[tracing::instrument(level = "debug", skip_all, fields(gateway = %gateway_id))] pub fn cleanup_connected_gateway(&mut self, gateway_id: &GatewayId) { - self.update_site_status_by_gateway(gateway_id, Status::Unknown); + self.update_site_status_by_gateway(gateway_id, ResourceStatus::Unknown); self.peers.remove(gateway_id); self.resources_gateways.retain(|_, g| g != gateway_id); } @@ -1012,7 +1012,7 @@ impl ClientState { .insert(candidate); } snownet::Event::ConnectionEstablished(id) => { - self.update_site_status_by_gateway(&id, Status::Online); + self.update_site_status_by_gateway(&id, ResourceStatus::Online); resources_changed = true; } } @@ -1042,7 +1042,7 @@ impl ClientState { } } - fn update_site_status_by_gateway(&mut self, gateway_id: &GatewayId, status: Status) { + fn update_site_status_by_gateway(&mut self, gateway_id: &GatewayId, status: ResourceStatus) { // Note: we can do this because in theory we shouldn't have multiple gateways for the same site // connected at the same time. self.sites_status.insert( @@ -1201,7 +1201,7 @@ impl ClientState { // If there's no allowed ip left we remove the whole peer because there's no point on keeping it around if peer.allowed_ips.is_empty() { self.peers.remove(&gateway_id); - self.update_site_status_by_gateway(&gateway_id, Status::Unknown); + self.update_site_status_by_gateway(&gateway_id, ResourceStatus::Unknown); // TODO: should we have a Node::remove_connection? } @@ -1595,8 +1595,9 @@ mod tests { #[cfg(all(test, feature = "proptest"))] mod proptests { use super::*; + use crate::messages::client::ResourceDescriptionDns; use crate::proptest::*; - use connlib_shared::messages::client::ResourceDescriptionDns; + use connlib_model::ResourceView; use prop::collection; use proptest::prelude::*; @@ -1622,8 +1623,6 @@ mod proptests { #[strategy(dns_resource())] resource2: ResourceDescriptionDns, #[strategy(cidr_resource())] resource3: ResourceDescriptionCidr, ) { - use callbacks as cb; - let mut client_state = ClientState::for_test(); client_state.add_resource(ResourceDescription::Cidr(resource1.clone())); @@ -1632,8 +1631,8 @@ mod proptests { assert_eq!( hashset(client_state.resources()), hashset([ - cb::ResourceDescription::Cidr(resource1.clone().with_status(Status::Unknown)), - cb::ResourceDescription::Dns(resource2.clone().with_status(Status::Unknown)) + ResourceView::Cidr(resource1.clone().with_status(ResourceStatus::Unknown)), + ResourceView::Dns(resource2.clone().with_status(ResourceStatus::Unknown)) ]) ); @@ -1642,9 +1641,9 @@ mod proptests { assert_eq!( hashset(client_state.resources()), hashset([ - cb::ResourceDescription::Cidr(resource1.with_status(Status::Unknown)), - cb::ResourceDescription::Dns(resource2.with_status(Status::Unknown)), - cb::ResourceDescription::Cidr(resource3.with_status(Status::Unknown)), + ResourceView::Cidr(resource1.with_status(ResourceStatus::Unknown)), + ResourceView::Dns(resource2.with_status(ResourceStatus::Unknown)), + ResourceView::Cidr(resource3.with_status(ResourceStatus::Unknown)), ]) ); } @@ -1654,8 +1653,6 @@ mod proptests { #[strategy(cidr_resource())] resource: ResourceDescriptionCidr, #[strategy(any_ip_network(8))] new_address: IpNetwork, ) { - use callbacks as cb; - let mut client_state = ClientState::for_test(); client_state.add_resource(ResourceDescription::Cidr(resource.clone())); @@ -1668,8 +1665,8 @@ mod proptests { assert_eq!( hashset(client_state.resources()), - hashset([cb::ResourceDescription::Cidr( - updated_resource.with_status(Status::Unknown) + hashset([ResourceView::Cidr( + updated_resource.with_status(ResourceStatus::Unknown) )]) ); assert_eq!( @@ -1683,8 +1680,6 @@ mod proptests { #[strategy(dns_resource())] resource: ResourceDescriptionDns, #[strategy(any_ip_network(8))] address: IpNetwork, ) { - use callbacks as cb; - let mut client_state = ClientState::for_test(); client_state.add_resource(ResourceDescription::Dns(resource.clone())); @@ -1700,8 +1695,8 @@ mod proptests { assert_eq!( hashset(client_state.resources()), - hashset([cb::ResourceDescription::Cidr( - dns_as_cidr_resource.with_status(Status::Unknown) + hashset([ResourceView::Cidr( + dns_as_cidr_resource.with_status(ResourceStatus::Unknown) )]) ); assert_eq!( @@ -1715,8 +1710,6 @@ mod proptests { #[strategy(dns_resource())] dns_resource: ResourceDescriptionDns, #[strategy(cidr_resource())] cidr_resource: ResourceDescriptionCidr, ) { - use callbacks as cb; - let mut client_state = ClientState::for_test(); client_state.add_resource(ResourceDescription::Dns(dns_resource.clone())); client_state.add_resource(ResourceDescription::Cidr(cidr_resource.clone())); @@ -1725,8 +1718,8 @@ mod proptests { assert_eq!( hashset(client_state.resources()), - hashset([cb::ResourceDescription::Cidr( - cidr_resource.clone().with_status(Status::Unknown) + hashset([ResourceView::Cidr( + cidr_resource.clone().with_status(ResourceStatus::Unknown) )]) ); assert_eq!( @@ -1747,8 +1740,6 @@ mod proptests { #[strategy(cidr_resource())] cidr_resource1: ResourceDescriptionCidr, #[strategy(cidr_resource())] cidr_resource2: ResourceDescriptionCidr, ) { - use callbacks as cb; - let mut client_state = ClientState::for_test(); client_state.add_resource(ResourceDescription::Dns(dns_resource1)); client_state.add_resource(ResourceDescription::Cidr(cidr_resource1)); @@ -1761,8 +1752,8 @@ mod proptests { assert_eq!( hashset(client_state.resources()), hashset([ - cb::ResourceDescription::Dns(dns_resource2.with_status(Status::Unknown)), - cb::ResourceDescription::Cidr(cidr_resource2.clone().with_status(Status::Unknown)), + ResourceView::Dns(dns_resource2.with_status(ResourceStatus::Unknown)), + ResourceView::Cidr(cidr_resource2.clone().with_status(ResourceStatus::Unknown)), ]) ); assert_eq!( @@ -1791,14 +1782,20 @@ mod proptests { .gateways_site .insert(gateway, first_resource.sites().iter().next().unwrap().id); - client_state.update_site_status_by_gateway(&gateway, Status::Online); + client_state.update_site_status_by_gateway(&gateway, ResourceStatus::Online); for resource in resources_online { - assert_eq!(client_state.resource_status(&resource), Status::Online); + assert_eq!( + client_state.resource_status(&resource), + ResourceStatus::Online + ); } for resource in resources_unknown { - assert_eq!(client_state.resource_status(&resource), Status::Unknown); + assert_eq!( + client_state.resource_status(&resource), + ResourceStatus::Unknown + ); } } @@ -1819,11 +1816,14 @@ mod proptests { .gateways_site .insert(gateway, first_resources.sites().iter().next().unwrap().id); - client_state.update_site_status_by_gateway(&gateway, Status::Online); - client_state.update_site_status_by_gateway(&gateway, Status::Unknown); + client_state.update_site_status_by_gateway(&gateway, ResourceStatus::Online); + client_state.update_site_status_by_gateway(&gateway, ResourceStatus::Unknown); for resource in resources { - assert_eq!(client_state.resource_status(&resource), Status::Unknown); + assert_eq!( + client_state.resource_status(&resource), + ResourceStatus::Unknown + ); } } @@ -1842,10 +1842,13 @@ mod proptests { assert_eq!( client_state.resource_status(&single_site_resource), - Status::Offline + ResourceStatus::Offline ); for resource in multi_site_resources { - assert_eq!(client_state.resource_status(&resource), Status::Unknown); + assert_eq!( + client_state.resource_status(&resource), + ResourceStatus::Unknown + ); } } diff --git a/rust/connlib/tunnel/src/dns.rs b/rust/connlib/tunnel/src/dns.rs index 3a8cacd0d..3990746e2 100644 --- a/rust/connlib/tunnel/src/dns.rs +++ b/rust/connlib/tunnel/src/dns.rs @@ -1,7 +1,7 @@ use crate::client::IpProvider; +use crate::messages::DnsServer; use anyhow::{Context, Result}; -use connlib_shared::messages::{DnsServer, ResourceId}; -use connlib_shared::DomainName; +use connlib_model::{DomainName, ResourceId}; use domain::base::{ iana::{Class, Rcode, Rtype}, Message, MessageBuilder, ToName, diff --git a/rust/connlib/tunnel/src/gateway.rs b/rust/connlib/tunnel/src/gateway.rs index ca7589135..6dee955c3 100644 --- a/rust/connlib/tunnel/src/gateway.rs +++ b/rust/connlib/tunnel/src/gateway.rs @@ -1,3 +1,5 @@ +use crate::messages::ResolveRequest; +use crate::messages::{gateway::ResourceDescription, Answer, Key, Offer}; use crate::peer::ClientOnGateway; use crate::peer_store::PeerStore; use crate::utils::earliest; @@ -5,11 +7,7 @@ use crate::{GatewayEvent, GatewayTunnel}; use anyhow::Context; use boringtun::x25519::PublicKey; use chrono::{DateTime, Utc}; -use connlib_shared::messages::ResolveRequest; -use connlib_shared::messages::{ - gateway::ResourceDescription, Answer, ClientId, Key, Offer, RelayId, ResourceId, -}; -use connlib_shared::{DomainName, StaticSecret}; +use connlib_model::{ClientId, DomainName, RelayId, ResourceId, StaticSecret}; use ip_network::{Ipv4Network, Ipv6Network}; use ip_packet::IpPacket; use secrecy::{ExposeSecret as _, Secret}; diff --git a/rust/connlib/tunnel/src/lib.rs b/rust/connlib/tunnel/src/lib.rs index 98ed06be3..7004c6f00 100644 --- a/rust/connlib/tunnel/src/lib.rs +++ b/rust/connlib/tunnel/src/lib.rs @@ -3,13 +3,12 @@ //! This is both the wireguard and ICE implementation that should work in tandem. //! [Tunnel] is the main entry-point for this crate. +use crate::messages::{Offer, Relay, ResolveRequest, SecretKey}; use bimap::BiMap; use boringtun::x25519::StaticSecret; use chrono::Utc; -use connlib_shared::{ - callbacks, - messages::{ClientId, GatewayId, Offer, Relay, RelayId, ResolveRequest, ResourceId, SecretKey}, - DomainName, PublicKey, +use connlib_model::{ + ClientId, DomainName, GatewayId, PublicKey, RelayId, ResourceId, ResourceView, }; use io::Io; use ip_network::{Ipv4Network, Ipv6Network}; @@ -32,6 +31,7 @@ mod device_channel; mod dns; mod gateway; mod io; +pub mod messages; mod peer; mod peer_store; #[cfg(all(test, feature = "proptest"))] @@ -300,7 +300,7 @@ pub enum ClientEvent { }, /// The list of resources has changed and UI clients may have to be updated. ResourcesChanged { - resources: Vec, + resources: Vec, }, TunInterfaceUpdated(TunConfig), } diff --git a/rust/connlib/shared/src/messages.rs b/rust/connlib/tunnel/src/messages.rs similarity index 70% rename from rust/connlib/shared/src/messages.rs rename to rust/connlib/tunnel/src/messages.rs index b5bc26113..fde3af2ee 100644 --- a/rust/connlib/shared/src/messages.rs +++ b/rust/connlib/tunnel/src/messages.rs @@ -2,10 +2,10 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; use chrono::{serde::ts_seconds, DateTime, Utc}; +use connlib_model::{GatewayId, RelayId, ResourceId}; use ip_network::IpNetwork; use serde::{Deserialize, Serialize}; -use std::{fmt, str::FromStr}; -use uuid::Uuid; +use std::fmt; pub mod client; pub mod gateway; @@ -15,126 +15,6 @@ pub use key::{Key, SecretKey}; use crate::DomainName; -#[derive(Hash, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct GatewayId(Uuid); - -#[derive(Hash, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct ResourceId(Uuid); - -#[derive(Hash, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct RelayId(Uuid); - -impl RelayId { - pub fn from_u128(v: u128) -> Self { - Self(Uuid::from_u128(v)) - } -} - -impl FromStr for RelayId { - type Err = uuid::Error; - - fn from_str(s: &str) -> Result { - Ok(RelayId(Uuid::parse_str(s)?)) - } -} - -impl ResourceId { - pub fn random() -> ResourceId { - ResourceId(Uuid::new_v4()) - } - - pub fn from_u128(v: u128) -> Self { - Self(Uuid::from_u128(v)) - } -} - -impl GatewayId { - pub fn from_u128(v: u128) -> Self { - Self(Uuid::from_u128(v)) - } -} - -#[derive(Hash, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct ClientId(Uuid); - -impl FromStr for ClientId { - type Err = uuid::Error; - - fn from_str(s: &str) -> Result { - Ok(ClientId(Uuid::parse_str(s)?)) - } -} - -impl ClientId { - pub fn from_u128(v: u128) -> Self { - Self(Uuid::from_u128(v)) - } -} - -impl FromStr for ResourceId { - type Err = uuid::Error; - - fn from_str(s: &str) -> Result { - Ok(ResourceId(Uuid::parse_str(s)?)) - } -} - -impl FromStr for GatewayId { - type Err = uuid::Error; - - fn from_str(s: &str) -> Result { - Ok(GatewayId(Uuid::parse_str(s)?)) - } -} - -impl fmt::Display for ResourceId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl fmt::Display for ClientId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl fmt::Display for GatewayId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl fmt::Display for RelayId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl fmt::Debug for ResourceId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self, f) - } -} - -impl fmt::Debug for ClientId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self, f) - } -} - -impl fmt::Debug for GatewayId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self, f) - } -} - -impl fmt::Debug for RelayId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self, f) - } -} - /// Represents a wireguard peer. #[derive(Debug, Deserialize, Serialize, Clone)] pub struct Peer { diff --git a/rust/connlib/clients/shared/src/messages.rs b/rust/connlib/tunnel/src/messages/client.rs similarity index 76% rename from rust/connlib/clients/shared/src/messages.rs rename to rust/connlib/tunnel/src/messages/client.rs index ab816cc2c..978a0b151 100644 --- a/rust/connlib/clients/shared/src/messages.rs +++ b/rust/connlib/tunnel/src/messages/client.rs @@ -1,11 +1,199 @@ -use connlib_shared::messages::{ - client::{ResourceDescription, SiteId}, - GatewayId, GatewayResponse, Interface, Key, Relay, RelaysPresence, RequestConnection, - ResourceId, ReuseConnection, +//! Client related messages that are needed within connlib + +use crate::messages::{ + GatewayResponse, Interface, Key, Relay, RelaysPresence, RequestConnection, ReuseConnection, }; +use connlib_model::{ + CidrResourceView, DnsResourceView, GatewayId, InternetResourceView, ResourceId, ResourceStatus, + ResourceView, Site, SiteId, +}; +use ip_network::IpNetwork; +use itertools::Itertools; use serde::{Deserialize, Serialize}; use std::{collections::BTreeSet, net::IpAddr}; +/// Description of a resource that maps to a DNS record. +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct ResourceDescriptionDns { + /// Resource's id. + pub id: ResourceId, + /// Internal resource's domain name. + pub address: String, + /// Name of the resource. + /// + /// Used only for display. + pub name: String, + + pub address_description: Option, + #[serde(rename = "gateway_groups")] + pub sites: Vec, +} + +impl ResourceDescriptionDns { + pub fn with_status(self, status: ResourceStatus) -> DnsResourceView { + DnsResourceView { + id: self.id, + address: self.address, + name: self.name, + address_description: self.address_description, + sites: self.sites, + status, + } + } +} + +/// Description of a resource that maps to a CIDR. +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct ResourceDescriptionCidr { + /// Resource's id. + pub id: ResourceId, + /// CIDR that this resource points to. + pub address: IpNetwork, + /// Name of the resource. + /// + /// Used only for display. + pub name: String, + + pub address_description: Option, + #[serde(rename = "gateway_groups")] + pub sites: Vec, +} + +impl ResourceDescriptionCidr { + pub fn with_status(self, status: ResourceStatus) -> CidrResourceView { + CidrResourceView { + id: self.id, + address: self.address, + name: self.name, + address_description: self.address_description, + sites: self.sites, + status, + } + } +} + +fn internet_resource_name() -> String { + "Internet Resource".to_string() +} + +/// Description of an internet resource. +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct ResourceDescriptionInternet { + /// Name of the resource. + /// + /// Used only for display. + #[serde(default = "internet_resource_name")] + pub name: String, + /// Resource's id. + pub id: ResourceId, + /// Sites for the internet resource + #[serde(rename = "gateway_groups")] + pub sites: Vec, +} + +impl ResourceDescriptionInternet { + pub fn with_status(self, status: ResourceStatus) -> InternetResourceView { + InternetResourceView { + name: self.name, + id: self.id, + sites: self.sites, + status, + } + } +} + +impl ResourceDescription { + pub fn address_string(&self) -> Option { + match self { + ResourceDescription::Dns(d) => Some(d.address.clone()), + ResourceDescription::Cidr(c) => Some(c.address.to_string()), + ResourceDescription::Internet(_) => None, + } + } + + pub fn sites_string(&self) -> String { + self.sites().iter().map(|s| &s.name).join("|") + } + + pub fn id(&self) -> ResourceId { + match self { + ResourceDescription::Dns(r) => r.id, + ResourceDescription::Cidr(r) => r.id, + ResourceDescription::Internet(r) => r.id, + } + } + + pub fn sites(&self) -> BTreeSet<&Site> { + match self { + ResourceDescription::Dns(r) => BTreeSet::from_iter(r.sites.iter()), + ResourceDescription::Cidr(r) => BTreeSet::from_iter(r.sites.iter()), + ResourceDescription::Internet(r) => BTreeSet::from_iter(r.sites.iter()), + } + } + + pub fn sites_mut(&mut self) -> &mut Vec { + match self { + ResourceDescription::Dns(r) => &mut r.sites, + ResourceDescription::Cidr(r) => &mut r.sites, + ResourceDescription::Internet(r) => &mut r.sites, + } + } + + /// What the GUI clients should show as the user-friendly display name, e.g. `Firezone GitHub` + pub fn name(&self) -> &str { + match self { + ResourceDescription::Dns(r) => &r.name, + ResourceDescription::Cidr(r) => &r.name, + ResourceDescription::Internet(_) => "Internet", + } + } + + pub fn has_different_address(&self, other: &ResourceDescription) -> bool { + match (self, other) { + (ResourceDescription::Dns(dns_a), ResourceDescription::Dns(dns_b)) => { + dns_a.address != dns_b.address + } + (ResourceDescription::Cidr(cidr_a), ResourceDescription::Cidr(cidr_b)) => { + cidr_a.address != cidr_b.address + } + (ResourceDescription::Internet(_), ResourceDescription::Internet(_)) => false, + _ => true, + } + } + + pub fn with_status(self, status: ResourceStatus) -> ResourceView { + match self { + ResourceDescription::Dns(r) => ResourceView::Dns(r.with_status(status)), + ResourceDescription::Cidr(r) => ResourceView::Cidr(r.with_status(status)), + ResourceDescription::Internet(r) => ResourceView::Internet(r.with_status(status)), + } + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Hash)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum ResourceDescription { + Dns(ResourceDescriptionDns), + Cidr(ResourceDescriptionCidr), + Internet(ResourceDescriptionInternet), +} + +impl ResourceDescription { + pub fn into_dns(self) -> Option { + match self { + ResourceDescription::Dns(d) => Some(d), + ResourceDescription::Cidr(_) | ResourceDescription::Internet(_) => None, + } + } + + pub fn into_cidr(self) -> Option { + match self { + ResourceDescription::Cidr(c) => Some(c), + ResourceDescription::Dns(_) | ResourceDescription::Internet(_) => None, + } + } +} + #[derive(Debug, PartialEq, Eq, Deserialize, Clone)] pub struct InitClient { pub interface: Interface, @@ -98,16 +286,46 @@ pub enum EgressMessages { } #[cfg(test)] -mod test { +mod tests { use super::*; + use crate::messages::{DnsServer, IpDnsServer, Turn}; use chrono::DateTime; - use connlib_shared::messages::{ - client::{ResourceDescriptionCidr, ResourceDescriptionDns, Site}, - DnsServer, IpDnsServer, Turn, - }; + use connlib_model::Site; use phoenix_channel::{OutboundRequestId, PhoenixMessage}; - // TODO: request_connection tests + #[test] + fn can_deserialize_internet_resource() { + let resources = r#"[ + { + "id": "73037362-715d-4a83-a749-f18eadd970e6", + "type": "cidr", + "name": "172.172.0.0/16", + "address": "172.172.0.0/16", + "address_description": "cidr resource", + "gateway_groups": [{"name": "test", "id": "bf56f32d-7b2c-4f5d-a784-788977d014a4"}] + }, + { + "id": "03000143-e25e-45c7-aafb-144990e57dcd", + "type": "dns", + "name": "gitlab.mycorp.com", + "address": "gitlab.mycorp.com", + "address_description": "dns resource", + "gateway_groups": [{"name": "test", "id": "bf56f32d-7b2c-4f5d-a784-788977d014a4"}] + }, + { + "id": "1106047c-cd5d-4151-b679-96b93da7383b", + "type": "internet", + "name": "Internet Resource", + "gateway_groups": [{"name": "test", "id": "eb94482a-94f4-47cb-8127-14fb3afa5516"}], + "not": "relevant", + "some_other": [ + "field" + ] + } + ]"#; + + serde_json::from_str::>(resources).unwrap(); + } #[test] fn broadcast_ice_candidates() { diff --git a/rust/gateway/src/messages.rs b/rust/connlib/tunnel/src/messages/gateway.rs similarity index 78% rename from rust/gateway/src/messages.rs rename to rust/connlib/tunnel/src/messages/gateway.rs index 9a6bcf7ed..5db9b22b8 100644 --- a/rust/gateway/src/messages.rs +++ b/rust/connlib/tunnel/src/messages/gateway.rs @@ -1,14 +1,108 @@ +//! Gateway related messages that are needed within connlib + +use crate::messages::{ + GatewayResponse, Interface, Offer, Peer, Relay, RelaysPresence, ResolveRequest, +}; +use chrono::{serde::ts_seconds_option, DateTime, Utc}; +use connlib_model::{ClientId, ResourceId}; +use ip_network::IpNetwork; +use serde::{Deserialize, Serialize}; use std::{ collections::BTreeSet, net::{Ipv4Addr, Ipv6Addr}, }; -use chrono::{serde::ts_seconds_option, DateTime, Utc}; -use connlib_shared::messages::{ - gateway::ResourceDescription, ClientId, GatewayResponse, Interface, Offer, Peer, Relay, - RelaysPresence, ResolveRequest, ResourceId, -}; -use serde::{Deserialize, Serialize}; +pub type Filters = Vec; + +/// Description of a resource that maps to a DNS record. +#[derive(Debug, Deserialize, Clone, PartialEq, Eq)] +pub struct ResourceDescriptionDns { + /// Resource's id. + pub id: ResourceId, + /// Internal resource's domain name. + pub address: String, + /// Name of the resource. + /// + /// Used only for display. + pub name: String, + + pub filters: Filters, +} + +/// Description of a resource that maps to a CIDR. +#[derive(Debug, Deserialize, Clone, PartialEq, Eq)] +pub struct ResourceDescriptionCidr { + /// Resource's id. + pub id: ResourceId, + /// CIDR that this resource points to. + pub address: IpNetwork, + /// Name of the resource. + /// + /// Used only for display. + pub name: String, + + pub filters: Filters, +} + +/// Description of an Internet resource. +#[derive(Debug, Deserialize, Clone, PartialEq, Eq)] +pub struct ResourceDescriptionInternet { + pub id: ResourceId, +} + +#[derive(Debug, Deserialize, Clone, PartialEq, Eq)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum ResourceDescription { + Dns(ResourceDescriptionDns), + Cidr(ResourceDescriptionCidr), + Internet(ResourceDescriptionInternet), +} + +#[derive(Debug, Deserialize, Clone, Copy, PartialEq, Eq, Hash)] +#[serde(tag = "protocol", rename_all = "snake_case")] +pub enum Filter { + Udp(PortRange), + Tcp(PortRange), + Icmp, +} + +#[derive(Debug, Deserialize, Clone, Copy, PartialEq, Eq, Hash)] +pub struct PortRange { + // TODO: we can use a custom deserializer + // or maybe change the control plane to use start and end would suffice + #[serde(default = "max_port")] + pub port_range_end: u16, + #[serde(default = "min_port")] + pub port_range_start: u16, +} + +// Note: these 2 functions are needed since serde doesn't yet support default_value +// see serde-rs/serde#368 +fn min_port() -> u16 { + 0 +} + +fn max_port() -> u16 { + u16::MAX +} + +impl ResourceDescription { + pub fn id(&self) -> ResourceId { + match self { + ResourceDescription::Dns(r) => r.id, + ResourceDescription::Cidr(r) => r.id, + ResourceDescription::Internet(r) => r.id, + } + } + + pub fn filters(&self) -> Vec { + match self { + ResourceDescription::Dns(r) => r.filters.clone(), + ResourceDescription::Cidr(r) => r.filters.clone(), + ResourceDescription::Internet(_) => Vec::default(), + } + } +} #[derive(Debug, Deserialize, Clone, PartialEq)] pub struct ClientPayload { @@ -125,14 +219,103 @@ pub struct ConnectionReady { } #[cfg(test)] -mod test { +mod tests { use super::*; - use connlib_shared::messages::gateway::Filter; - use connlib_shared::messages::gateway::PortRange; - use connlib_shared::messages::gateway::ResourceDescriptionDns; - use connlib_shared::messages::Turn; + use crate::messages::Turn; use phoenix_channel::PhoenixMessage; + #[test] + fn can_deserialize_udp_filter() { + let msg = r#"{ "protocol": "udp", "port_range_start": 10, "port_range_end": 20 }"#; + let expected_filter = Filter::Udp(PortRange { + port_range_start: 10, + port_range_end: 20, + }); + + let actual_filter = serde_json::from_str(msg).unwrap(); + + assert_eq!(expected_filter, actual_filter); + } + + #[test] + fn can_deserialize_empty_udp_filter() { + let msg = r#"{ "protocol": "udp" }"#; + let expected_filter = Filter::Udp(PortRange { + port_range_start: 0, + port_range_end: u16::MAX, + }); + + let actual_filter = serde_json::from_str(msg).unwrap(); + + assert_eq!(expected_filter, actual_filter); + } + + #[test] + fn can_deserialize_tcp_filter() { + let msg = r#"{ "protocol": "tcp", "port_range_start": 10, "port_range_end": 20 }"#; + let expected_filter = Filter::Tcp(PortRange { + port_range_start: 10, + port_range_end: 20, + }); + + let actual_filter = serde_json::from_str(msg).unwrap(); + + assert_eq!(expected_filter, actual_filter); + } + + #[test] + fn can_deserialize_empty_tcp_filter() { + let msg = r#"{ "protocol": "tcp" }"#; + let expected_filter = Filter::Tcp(PortRange { + port_range_start: 0, + port_range_end: u16::MAX, + }); + + let actual_filter = serde_json::from_str(msg).unwrap(); + + assert_eq!(expected_filter, actual_filter); + } + + #[test] + fn can_deserialize_icmp_filter() { + let msg = r#"{ "protocol": "icmp" }"#; + let expected_filter = Filter::Icmp; + + let actual_filter = serde_json::from_str(msg).unwrap(); + + assert_eq!(expected_filter, actual_filter); + } + + #[test] + fn can_deserialize_internet_resource() { + let resources = r#"[ + { + "id": "73037362-715d-4a83-a749-f18eadd970e6", + "type": "cidr", + "address": "172.172.0.0/16", + "name": "172.172.0.0/16", + "filters": [] + }, + { + "id": "03000143-e25e-45c7-aafb-144990e57dcd", + "type": "dns", + "name": "gitlab.mycorp.com", + "address": "gitlab.mycorp.com", + "filters": [] + }, + { + "id": "1106047c-cd5d-4151-b679-96b93da7383b", + "type": "internet", + "not": "relevant", + "some_other": [ + "field" + ] + } + ]"#; + + serde_json::from_str::>(resources).unwrap(); + } + #[test] fn request_connection_message() { let message = r#"{ diff --git a/rust/connlib/shared/src/messages/key.rs b/rust/connlib/tunnel/src/messages/key.rs similarity index 99% rename from rust/connlib/shared/src/messages/key.rs rename to rust/connlib/tunnel/src/messages/key.rs index 628040a44..e354d0ebc 100644 --- a/rust/connlib/shared/src/messages/key.rs +++ b/rust/connlib/tunnel/src/messages/key.rs @@ -88,7 +88,7 @@ pub type SecretKey = Secret; #[cfg(test)] mod test { use boringtun::x25519::{PublicKey, StaticSecret}; - use rand_core::OsRng; + use rand::rngs::OsRng; use super::Key; diff --git a/rust/connlib/tunnel/src/peer.rs b/rust/connlib/tunnel/src/peer.rs index 43139dfd6..bf8751097 100644 --- a/rust/connlib/tunnel/src/peer.rs +++ b/rust/connlib/tunnel/src/peer.rs @@ -2,12 +2,10 @@ use std::collections::{hash_map, BTreeMap, HashMap, HashSet, VecDeque}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::time::{Duration, Instant}; +use crate::messages::gateway::ResourceDescription; +use crate::messages::{gateway::Filter, gateway::Filters}; use chrono::{DateTime, Utc}; -use connlib_shared::messages::gateway::ResourceDescription; -use connlib_shared::messages::{ - gateway::Filter, gateway::Filters, ClientId, GatewayId, ResourceId, -}; -use connlib_shared::DomainName; +use connlib_model::{ClientId, DomainName, GatewayId, ResourceId}; use ip_network::{IpNetwork, Ipv4Network, Ipv6Network}; use ip_network_table::IpNetworkTable; use ip_packet::IpPacket; @@ -327,7 +325,7 @@ impl ClientOnGateway { pub(crate) fn add_resource( &mut self, - resource: connlib_shared::messages::gateway::ResourceDescription, + resource: crate::messages::gateway::ResourceDescription, expires_at: Option>, ) { match self.resources.entry(resource.id()) { @@ -708,11 +706,11 @@ mod tests { time::{Duration, Instant}, }; - use chrono::Utc; - use connlib_shared::messages::{ - gateway::{Filter, PortRange, ResourceDescription, ResourceDescriptionCidr}, - ClientId, ResourceId, + use crate::messages::gateway::{ + Filter, PortRange, ResourceDescription, ResourceDescriptionCidr, }; + use chrono::Utc; + use connlib_model::{ClientId, ResourceId}; use ip_network::Ipv4Network; use super::{ClientOnGateway, TranslationState}; @@ -1077,10 +1075,8 @@ mod tests { #[cfg(all(test, feature = "proptest"))] mod proptests { use super::*; + use crate::messages::gateway::{PortRange, ResourceDescription, ResourceDescriptionCidr}; use crate::proptest::*; - use connlib_shared::messages::gateway::{ - PortRange, ResourceDescription, ResourceDescriptionCidr, - }; use ip_packet::make::{icmp_request_packet, tcp_packet, udp_packet}; use proptest::{ arbitrary::any, diff --git a/rust/connlib/tunnel/src/peer_store.rs b/rust/connlib/tunnel/src/peer_store.rs index 4afb27fc6..ee48bb214 100644 --- a/rust/connlib/tunnel/src/peer_store.rs +++ b/rust/connlib/tunnel/src/peer_store.rs @@ -3,7 +3,7 @@ use std::hash::Hash; use std::net::IpAddr; use crate::peer::{ClientOnGateway, GatewayOnClient}; -use connlib_shared::messages::{ClientId, GatewayId, ResourceId}; +use connlib_model::{ClientId, GatewayId, ResourceId}; use ip_network::IpNetwork; use ip_network_table::IpNetworkTable; diff --git a/rust/connlib/tunnel/src/proptest.rs b/rust/connlib/tunnel/src/proptest.rs index 9ee594caf..fbce6a11a 100644 --- a/rust/connlib/tunnel/src/proptest.rs +++ b/rust/connlib/tunnel/src/proptest.rs @@ -1,10 +1,8 @@ -use connlib_shared::messages::{ - client::{ - ResourceDescription, ResourceDescriptionCidr, ResourceDescriptionDns, - ResourceDescriptionInternet, Site, SiteId, - }, - ClientId, GatewayId, RelayId, ResourceId, +use crate::messages::client::{ + ResourceDescription, ResourceDescriptionCidr, ResourceDescriptionDns, + ResourceDescriptionInternet, }; +use connlib_model::{ClientId, GatewayId, RelayId, ResourceId, Site, SiteId}; use ip_network::{IpNetwork, Ipv4Network, Ipv6Network}; use proptest::{ arbitrary::{any, any_with}, diff --git a/rust/connlib/tunnel/src/tests/assertions.rs b/rust/connlib/tunnel/src/tests/assertions.rs index 24aad8af5..67ce33876 100644 --- a/rust/connlib/tunnel/src/tests/assertions.rs +++ b/rust/connlib/tunnel/src/tests/assertions.rs @@ -3,7 +3,7 @@ use super::{ sim_gateway::SimGateway, }; use crate::tests::reference::ResourceDst; -use connlib_shared::{messages::GatewayId, DomainName}; +use connlib_model::{DomainName, GatewayId}; use ip_packet::IpPacket; use itertools::Itertools; use std::{ diff --git a/rust/connlib/tunnel/src/tests/reference.rs b/rust/connlib/tunnel/src/tests/reference.rs index 83407e39e..ced847d8e 100644 --- a/rust/connlib/tunnel/src/tests/reference.rs +++ b/rust/connlib/tunnel/src/tests/reference.rs @@ -3,13 +3,11 @@ use super::{ strategies::*, stub_portal::StubPortal, transition::*, }; use crate::{dns::is_subdomain, proptest::relay_id}; -use connlib_shared::{ - messages::{ - client::{self, ResourceDescription}, - GatewayId, RelayId, ResourceId, - }, +use crate::{ + messages::client::{self, ResourceDescription}, DomainName, StaticSecret, }; +use connlib_model::{GatewayId, RelayId, ResourceId}; use domain::base::Rtype; use proptest::{prelude::*, sample}; use proptest_state_machine::ReferenceStateMachine; diff --git a/rust/connlib/tunnel/src/tests/sim_client.rs b/rust/connlib/tunnel/src/tests/sim_client.rs index b4ba2e462..88b918eef 100644 --- a/rust/connlib/tunnel/src/tests/sim_client.rs +++ b/rust/connlib/tunnel/src/tests/sim_client.rs @@ -6,18 +6,19 @@ use super::{ transition::DnsQuery, IcmpIdentifier, IcmpSeq, QueryId, }; -use crate::{proptest::*, ClientState}; -use bimap::BiMap; -use connlib_shared::{ +use crate::{ messages::{ client::{ ResourceDescription, ResourceDescriptionCidr, ResourceDescriptionDns, ResourceDescriptionInternet, }, - ClientId, DnsServer, GatewayId, Interface, RelayId, ResourceId, + DnsServer, Interface, }, DomainName, }; +use crate::{proptest::*, ClientState}; +use bimap::BiMap; +use connlib_model::{ClientId, GatewayId, RelayId, ResourceId}; use domain::{ base::{Message, Rtype, ToName}, rdata::AllRecordData, diff --git a/rust/connlib/tunnel/src/tests/sim_dns.rs b/rust/connlib/tunnel/src/tests/sim_dns.rs index f366b1be7..262936f2d 100644 --- a/rust/connlib/tunnel/src/tests/sim_dns.rs +++ b/rust/connlib/tunnel/src/tests/sim_dns.rs @@ -2,7 +2,7 @@ use super::{ sim_net::{host, Host}, strategies::latency, }; -use connlib_shared::DomainName; +use connlib_model::DomainName; use domain::{ base::{ iana::{Class, Rcode}, diff --git a/rust/connlib/tunnel/src/tests/sim_gateway.rs b/rust/connlib/tunnel/src/tests/sim_gateway.rs index 92ad6b741..fc6005ac9 100644 --- a/rust/connlib/tunnel/src/tests/sim_gateway.rs +++ b/rust/connlib/tunnel/src/tests/sim_gateway.rs @@ -4,11 +4,9 @@ use super::{ sim_relay::{map_explode, SimRelay}, strategies::latency, }; +use crate::DomainName; use crate::GatewayState; -use connlib_shared::{ - messages::{GatewayId, RelayId}, - DomainName, -}; +use connlib_model::{GatewayId, RelayId}; use ip_packet::{IcmpEchoHeader, Icmpv4Type, Icmpv6Type, IpPacket}; use proptest::prelude::*; use snownet::{EncryptBuffer, Transmit}; diff --git a/rust/connlib/tunnel/src/tests/sim_net.rs b/rust/connlib/tunnel/src/tests/sim_net.rs index ce6a1a81b..14ec071e9 100644 --- a/rust/connlib/tunnel/src/tests/sim_net.rs +++ b/rust/connlib/tunnel/src/tests/sim_net.rs @@ -1,7 +1,7 @@ use super::sim_dns::DnsServerId; use crate::tests::buffered_transmits::BufferedTransmits; use crate::tests::strategies::documentation_ip6s; -use connlib_shared::messages::{ClientId, GatewayId, RelayId}; +use connlib_model::{ClientId, GatewayId, RelayId}; use firezone_relay::{AddressFamily, IpStack}; use ip_network::{IpNetwork, Ipv4Network}; use ip_network_table::IpNetworkTable; diff --git a/rust/connlib/tunnel/src/tests/sim_relay.rs b/rust/connlib/tunnel/src/tests/sim_relay.rs index 99398ff54..3dbe725fb 100644 --- a/rust/connlib/tunnel/src/tests/sim_relay.rs +++ b/rust/connlib/tunnel/src/tests/sim_relay.rs @@ -2,7 +2,7 @@ use super::{ sim_net::{dual_ip_stack, host, Host}, strategies::latency, }; -use connlib_shared::messages::RelayId; +use connlib_model::RelayId; use firezone_relay::{AddressFamily, AllocationPort, ClientSocket, IpStack, PeerSocket}; use proptest::prelude::*; use rand::{rngs::StdRng, SeedableRng as _}; diff --git a/rust/connlib/tunnel/src/tests/strategies.rs b/rust/connlib/tunnel/src/tests/strategies.rs index 8fa6df72d..0bc8cd2a9 100644 --- a/rust/connlib/tunnel/src/tests/strategies.rs +++ b/rust/connlib/tunnel/src/tests/strategies.rs @@ -6,15 +6,14 @@ use super::{ }; use crate::client::{IPV4_RESOURCES, IPV6_RESOURCES}; use crate::proptest::*; -use connlib_shared::{ +use crate::{ messages::{ - client::{ - ResourceDescriptionCidr, ResourceDescriptionDns, ResourceDescriptionInternet, Site, - }, - DnsServer, RelayId, + client::{ResourceDescriptionCidr, ResourceDescriptionDns, ResourceDescriptionInternet}, + DnsServer, }, DomainName, }; +use connlib_model::{RelayId, Site}; use ip_network::{IpNetwork, Ipv4Network, Ipv6Network}; use itertools::Itertools; use prop::sample; diff --git a/rust/connlib/tunnel/src/tests/stub_portal.rs b/rust/connlib/tunnel/src/tests/stub_portal.rs index 3f8f97bf1..0fb409569 100644 --- a/rust/connlib/tunnel/src/tests/stub_portal.rs +++ b/rust/connlib/tunnel/src/tests/stub_portal.rs @@ -5,10 +5,12 @@ use super::{ strategies::{resolved_ips, subdomain_records}, }; use crate::proptest::*; -use connlib_shared::{ - messages::{client, gateway, DnsServer, GatewayId, ResourceId}, +use crate::{ + messages::{client, gateway, DnsServer}, DomainName, }; +use connlib_model::GatewayId; +use connlib_model::{ResourceId, SiteId}; use ip_network::{Ipv4Network, Ipv6Network}; use itertools::Itertools; use proptest::{ @@ -25,10 +27,10 @@ use std::{ #[derive(Clone, derivative::Derivative)] #[derivative(Debug)] pub(crate) struct StubPortal { - gateways_by_site: BTreeMap>, + gateways_by_site: BTreeMap>, #[derivative(Debug = "ignore")] - sites_by_resource: BTreeMap, + sites_by_resource: BTreeMap, cidr_resources: BTreeMap, dns_resources: BTreeMap, internet_resource: client::ResourceDescriptionInternet, @@ -39,7 +41,7 @@ pub(crate) struct StubPortal { impl StubPortal { pub(crate) fn new( - gateways_by_site: BTreeMap>, + gateways_by_site: BTreeMap>, gateway_selector: Selector, cidr_resources: BTreeSet, dns_resources: BTreeSet, @@ -118,7 +120,7 @@ impl StubPortal { &self, resource: ResourceId, _connected_gateway_ids: BTreeSet, - ) -> (GatewayId, client::SiteId) { + ) -> (GatewayId, SiteId) { let site_id = self .sites_by_resource .get(&resource) diff --git a/rust/connlib/tunnel/src/tests/sut.rs b/rust/connlib/tunnel/src/tests/sut.rs index 7bd995b9b..6bf6af280 100644 --- a/rust/connlib/tunnel/src/tests/sut.rs +++ b/rust/connlib/tunnel/src/tests/sut.rs @@ -9,16 +9,13 @@ use super::stub_portal::StubPortal; use super::transition::DnsQuery; use crate::dns::is_subdomain; use crate::gateway::DnsResourceNatEntry; +use crate::messages::client::ResourceDescription; use crate::tests::assertions::*; use crate::tests::flux_capacitor::FluxCapacitor; use crate::tests::transition::Transition; use crate::utils::earliest; -use crate::{ClientEvent, GatewayEvent}; -use connlib_shared::messages::client::ResourceDescription; -use connlib_shared::{ - messages::{ClientId, GatewayId, Interface, RelayId}, - DomainName, -}; +use crate::{messages::Interface, ClientEvent, GatewayEvent}; +use connlib_model::{ClientId, DomainName, GatewayId, RelayId}; use secrecy::ExposeSecret as _; use snownet::Transmit; use std::collections::BTreeSet; diff --git a/rust/connlib/tunnel/src/tests/transition.rs b/rust/connlib/tunnel/src/tests/transition.rs index 969fe059e..7d11c4a49 100644 --- a/rust/connlib/tunnel/src/tests/transition.rs +++ b/rust/connlib/tunnel/src/tests/transition.rs @@ -2,12 +2,11 @@ use crate::{ client::{IPV4_RESOURCES, IPV6_RESOURCES}, proptest::{host_v4, host_v6}, }; +use connlib_model::RelayId; use super::sim_net::{any_ip_stack, any_port, Host}; -use connlib_shared::{ - messages::{client::ResourceDescription, DnsServer, RelayId, ResourceId}, - DomainName, -}; +use crate::messages::{client::ResourceDescription, DnsServer}; +use connlib_model::{DomainName, ResourceId}; use domain::base::Rtype; use prop::collection; use proptest::{prelude::*, sample}; diff --git a/rust/connlib/tunnel/src/utils.rs b/rust/connlib/tunnel/src/utils.rs index 0b791c0f4..1d9f03de3 100644 --- a/rust/connlib/tunnel/src/utils.rs +++ b/rust/connlib/tunnel/src/utils.rs @@ -1,7 +1,7 @@ -use crate::REALM; -use connlib_shared::messages::{Relay, RelayId}; +use crate::{messages::Relay, REALM}; +use connlib_model::RelayId; use ip_network::{IpNetwork, Ipv4Network, Ipv6Network}; -use itertools::Itertools; +use itertools::Itertools as _; use snownet::RelaySocket; use std::{collections::BTreeSet, net::SocketAddr, time::Instant}; diff --git a/rust/gateway/Cargo.toml b/rust/gateway/Cargo.toml index 2b0ef05cb..4817c94b4 100644 --- a/rust/gateway/Cargo.toml +++ b/rust/gateway/Cargo.toml @@ -12,7 +12,7 @@ backoff = { workspace = true } boringtun = { workspace = true } chrono = { workspace = true } clap = "4.5.13" -connlib-shared = { workspace = true } +connlib-model = { workspace = true } dns-lookup = { workspace = true } domain = { workspace = true } either = "1" diff --git a/rust/gateway/src/eventloop.rs b/rust/gateway/src/eventloop.rs index 3ff09f174..7b281057b 100644 --- a/rust/gateway/src/eventloop.rs +++ b/rust/gateway/src/eventloop.rs @@ -1,15 +1,16 @@ -use crate::messages::{ - AllowAccess, ClientIceCandidates, ClientsIceCandidates, ConnectionReady, EgressMessages, - IngressMessages, RejectAccess, RequestConnection, -}; use anyhow::Result; use boringtun::x25519::PublicKey; -use connlib_shared::messages::{ - ClientId, ConnectionAccepted, Interface, RelaysPresence, ResourceId, -}; -use connlib_shared::{messages::GatewayResponse, DomainName}; +use connlib_model::DomainName; +use connlib_model::{ClientId, ResourceId}; #[cfg(not(target_os = "windows"))] use dns_lookup::{AddrInfoHints, AddrInfoIter, LookupError}; +use firezone_tunnel::messages::{ + gateway::{ + AllowAccess, ClientIceCandidates, ClientsIceCandidates, ConnectionReady, EgressMessages, + IngressMessages, RejectAccess, RequestConnection, + }, + ConnectionAccepted, GatewayResponse, Interface, RelaysPresence, +}; use firezone_tunnel::{DnsResourceNatEntry, GatewayTunnel}; use futures::channel::mpsc; use futures_bounded::Timeout; diff --git a/rust/gateway/src/main.rs b/rust/gateway/src/main.rs index 537221dd0..3ca4fff5d 100644 --- a/rust/gateway/src/main.rs +++ b/rust/gateway/src/main.rs @@ -2,13 +2,16 @@ use crate::eventloop::{Eventloop, PHOENIX_TOPIC}; use anyhow::{Context, Result}; use backoff::ExponentialBackoffBuilder; use clap::Parser; -use connlib_shared::{get_user_agent, messages::Interface, LoginUrl, StaticSecret}; +use connlib_model::StaticSecret; use firezone_bin_shared::{ http_health_check, linux::{tcp_socket_factory, udp_socket_factory}, TunDeviceManager, }; +use firezone_tunnel::messages::Interface; use firezone_tunnel::{keypair, GatewayTunnel, IPV4_PEERS, IPV6_PEERS}; +use phoenix_channel::get_user_agent; +use phoenix_channel::LoginUrl; use futures::channel::mpsc; use futures::{future, StreamExt, TryFutureExt}; @@ -25,7 +28,6 @@ use url::Url; use uuid::Uuid; mod eventloop; -mod messages; const ID_PATH: &str = "/var/lib/firezone/gateway_id"; diff --git a/rust/gui-client/src-common/Cargo.toml b/rust/gui-client/src-common/Cargo.toml index 30cc177f5..9b5c29ca0 100644 --- a/rust/gui-client/src-common/Cargo.toml +++ b/rust/gui-client/src-common/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" anyhow = { version = "1.0" } arboard = { version = "3.4.0", default-features = false } atomicwrites = { workspace = true } -connlib-shared = { workspace = true } +connlib-model = { workspace = true } firezone-bin-shared = { workspace = true } firezone-headless-client = { path = "../../headless-client" } firezone-logging = { workspace = true } @@ -39,9 +39,9 @@ zip = { version = "2", features = ["deflate", "time"], default-features = false [dependencies.keyring] version = "3.2.1" features = [ - "crypto-rust", # Don't rely on OpenSSL - "sync-secret-service", # Can't use Tokio because of - "windows-native", # Yes, really, we must actually explicitly ask for every platform. Otherwise it defaults to an in-memory mock store. Really. That's really how `keyring` 3.x is designed. + "crypto-rust", # Don't rely on OpenSSL + "sync-secret-service", # Can't use Tokio because of + "windows-native", # Yes, really, we must actually explicitly ask for every platform. Otherwise it defaults to an in-memory mock store. Really. That's really how `keyring` 3.x is designed. ] [target.'cfg(target_os = "linux")'.dependencies] diff --git a/rust/gui-client/src-common/src/controller.rs b/rust/gui-client/src-common/src/controller.rs index a312f7ec0..f7d913e9e 100644 --- a/rust/gui-client/src-common/src/controller.rs +++ b/rust/gui-client/src-common/src/controller.rs @@ -7,7 +7,7 @@ use crate::{ updates, }; use anyhow::{anyhow, Context, Result}; -use connlib_shared::callbacks::ResourceDescription; +use connlib_model::ResourceView; use firezone_bin_shared::{new_dns_notifier, new_network_notifier}; use firezone_headless_client::{ IpcClientMsg::{self, SetDisabledResources}, @@ -145,7 +145,7 @@ pub enum Status { Quitting, // The user asked to quit and we're waiting for the tunnel daemon to gracefully disconnect so we can flush telemetry. /// Firezone is ready to use. TunnelReady { - resources: Vec, + resources: Vec, }, /// Firezone is signing in to the Portal. WaitingForPortal { @@ -190,7 +190,7 @@ impl Status { } } - fn internet_resource(&self) -> Option { + fn internet_resource(&self) -> Option { #[expect(clippy::wildcard_enum_match_arm)] match self { Status::TunnelReady { resources } => { diff --git a/rust/gui-client/src-common/src/settings.rs b/rust/gui-client/src-common/src/settings.rs index 2a9b4d0ad..9172d3304 100644 --- a/rust/gui-client/src-common/src/settings.rs +++ b/rust/gui-client/src-common/src/settings.rs @@ -3,7 +3,7 @@ use anyhow::{Context as _, Result}; use atomicwrites::{AtomicFile, OverwriteBehavior}; -use connlib_shared::messages::ResourceId; +use connlib_model::ResourceId; use firezone_headless_client::known_dirs; use serde::{Deserialize, Serialize}; use std::{collections::HashSet, io::Write, path::PathBuf}; diff --git a/rust/gui-client/src-common/src/system_tray.rs b/rust/gui-client/src-common/src/system_tray.rs index aaf3789d8..fe45f38b3 100644 --- a/rust/gui-client/src-common/src/system_tray.rs +++ b/rust/gui-client/src-common/src/system_tray.rs @@ -1,8 +1,5 @@ use crate::updates::Release; -use connlib_shared::{ - callbacks::{ResourceDescription, Status}, - messages::ResourceId, -}; +use connlib_model::{ResourceId, ResourceStatus, ResourceView}; use std::collections::HashSet; use url::Url; @@ -75,7 +72,7 @@ pub enum ConnlibState { pub struct SignedIn { pub actor_name: String, pub favorite_resources: HashSet, - pub resources: Vec, + pub resources: Vec, pub internet_resource_enabled: Option, } @@ -94,7 +91,7 @@ impl SignedIn { /// Builds the submenu that has the resource address, name, desc, /// sites online, etc. - fn resource_submenu(&self, res: &ResourceDescription) -> Menu { + fn resource_submenu(&self, res: &ResourceView) -> Menu { let mut submenu = Menu::default().resource_description(res); if res.is_internet_resource() { @@ -113,9 +110,9 @@ impl SignedIn { if let Some(site) = res.sites().first() { // Emojis may be causing an issue on some Ubuntu desktop environments. let status = match res.status() { - Status::Unknown => NO_ACTIVITY, - Status::Online => GATEWAY_CONNECTED, - Status::Offline => ALL_GATEWAYS_OFFLINE, + ResourceStatus::Unknown => NO_ACTIVITY, + ResourceStatus::Online => GATEWAY_CONNECTED, + ResourceStatus::Offline => ALL_GATEWAYS_OFFLINE, }; submenu @@ -313,7 +310,7 @@ mod tests { } fn signed_in( - resources: Vec, + resources: Vec, favorite_resources: HashSet, internet_resource_enabled: Option, ) -> AppState { @@ -328,7 +325,7 @@ mod tests { } } - fn resources() -> Vec { + fn resources() -> Vec { let s = r#"[ { "id": "73037362-715d-4a83-a749-f18eadd970e6", diff --git a/rust/gui-client/src-common/src/system_tray/builder.rs b/rust/gui-client/src-common/src/system_tray/builder.rs index 32e1ab597..cd9884ea9 100644 --- a/rust/gui-client/src-common/src/system_tray/builder.rs +++ b/rust/gui-client/src-common/src/system_tray/builder.rs @@ -1,6 +1,6 @@ //! An abstraction over Tauri's system tray menu structs, that implements `PartialEq` for unit testing -use connlib_shared::{callbacks::ResourceDescription, messages::ResourceId}; +use connlib_model::{ResourceId, ResourceView}; use serde::{Deserialize, Serialize}; use url::Url; @@ -79,7 +79,7 @@ pub enum Window { Settings, } -fn resource_header(res: &ResourceDescription) -> Item { +fn resource_header(res: &ResourceView) -> Item { let Some(address_description) = res.address_description() else { return copyable(&res.pastable()); }; @@ -140,14 +140,14 @@ impl Menu { self.disabled(INTERNET_RESOURCE_DESCRIPTION) } - fn resource_body(self, resource: &ResourceDescription) -> Self { + fn resource_body(self, resource: &ResourceView) -> Self { self.separator() .disabled("Resource") .copyable(resource.name()) .copyable(resource.pastable().as_ref()) } - pub(crate) fn resource_description(mut self, resource: &ResourceDescription) -> Self { + pub(crate) fn resource_description(mut self, resource: &ResourceView) -> Self { if resource.is_internet_resource() { self.internet_resource() } else { diff --git a/rust/gui-client/src-tauri/Cargo.toml b/rust/gui-client/src-tauri/Cargo.toml index ec044f768..d35cbec10 100644 --- a/rust/gui-client/src-tauri/Cargo.toml +++ b/rust/gui-client/src-tauri/Cargo.toml @@ -15,9 +15,9 @@ tauri-build = { version = "1.5", features = [] } anyhow = { version = "1.0" } atomicwrites = { workspace = true } chrono = { workspace = true } -clap = { version = "4.5", features = ["derive", "env"] } +clap = { version = "4.5", features = ["derive", "env"] } connlib-client-shared = { workspace = true } -connlib-shared = { workspace = true } +connlib-model = { workspace = true } firezone-bin-shared = { workspace = true } firezone-gui-client-common = { path = "../src-common" } firezone-headless-client = { path = "../../headless-client" } @@ -32,7 +32,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" subtle = "2.5.0" # `notification` is not needed on Windows, but if we remove it, Tauri's bundler will just add it back. #6597 -tauri = { version = "1.7.1", features = [ "dialog", "icon-png", "notification", "shell-open-api", "system-tray" ] } +tauri = { version = "1.7.1", features = ["dialog", "icon-png", "notification", "shell-open-api", "system-tray"] } tauri-runtime = "0.14.5" tauri-utils = "1.6.0" thiserror = { version = "1.0", default-features = false } diff --git a/rust/headless-client/Cargo.toml b/rust/headless-client/Cargo.toml index cbf2dbca4..443a2720b 100644 --- a/rust/headless-client/Cargo.toml +++ b/rust/headless-client/Cargo.toml @@ -12,7 +12,7 @@ atomicwrites = { workspace = true } # Needed to safely backup `/etc/resolv.conf` backoff = "0.4.0" clap = { version = "4.5", features = ["derive", "env", "string"] } connlib-client-shared = { workspace = true } -connlib-shared = { workspace = true } +connlib-model = { workspace = true } firezone-bin-shared = { workspace = true } firezone-logging = { workspace = true } firezone-telemetry = { workspace = true } @@ -30,7 +30,7 @@ smbios-lib = "0.9.2" thiserror = { version = "1.0", default-features = false } # This actually relies on many other features in Tokio, so this will probably # fail to build outside the workspace. -tokio = { workspace = true, features = ["macros", "signal", "process", "time", "rt-multi-thread"] } +tokio = { workspace = true, features = ["macros", "signal", "process", "time", "rt-multi-thread", "fs"] } tokio-stream = "0.1.16" tokio-util = { version = "0.7.11", features = ["codec"] } tracing = { workspace = true } @@ -66,17 +66,17 @@ winreg = "0.52.0" [target.'cfg(windows)'.dependencies.windows] version = "0.58.0" features = [ - # For DNS control and route control - "Win32_Foundation", - "Win32_NetworkManagement_IpHelper", - "Win32_NetworkManagement_Ndis", - "Win32_Networking_WinSock", + # For DNS control and route control + "Win32_Foundation", + "Win32_NetworkManagement_IpHelper", + "Win32_NetworkManagement_Ndis", + "Win32_Networking_WinSock", - "Win32_Security", # For named pipe IPC - "Win32_System_GroupPolicy", # For NRPT when GPO is used - "Win32_System_SystemInformation", # For uptime - "Win32_System_SystemServices", - "Win32_System_Pipes", + "Win32_Security", # For named pipe IPC + "Win32_System_GroupPolicy", # For NRPT when GPO is used + "Win32_System_SystemInformation", # For uptime + "Win32_System_SystemServices", + "Win32_System_Pipes", ] [lints] diff --git a/rust/headless-client/src/ipc_service.rs b/rust/headless-client/src/ipc_service.rs index 3d96ab4e6..4ed921cfe 100644 --- a/rust/headless-client/src/ipc_service.rs +++ b/rust/headless-client/src/ipc_service.rs @@ -4,8 +4,8 @@ use crate::{ }; use anyhow::{bail, Context as _, Result}; use clap::Parser; -use connlib_client_shared::{keypair, ConnectArgs, LoginUrl}; -use connlib_shared::callbacks::ResourceDescription; +use connlib_client_shared::{keypair, ConnectArgs}; +use connlib_model::ResourceView; use firezone_bin_shared::{ platform::{tcp_socket_factory, udp_socket_factory, DnsControlMethod}, TunDeviceManager, TOKEN_ENV_KEY, @@ -16,6 +16,7 @@ use futures::{ task::{Context, Poll}, Future as _, SinkExt as _, Stream as _, }; +use phoenix_channel::LoginUrl; use secrecy::SecretString; use serde::{Deserialize, Serialize}; use std::{collections::BTreeSet, net::IpAddr, path::PathBuf, pin::pin, sync::Arc, time::Duration}; @@ -26,9 +27,9 @@ use url::Url; pub mod ipc; use backoff::ExponentialBackoffBuilder; -use connlib_shared::{get_user_agent, messages::ResourceId}; +use connlib_model::ResourceId; use ipc::{Server as IpcServer, ServiceId}; -use phoenix_channel::PhoenixChannel; +use phoenix_channel::{get_user_agent, PhoenixChannel}; use secrecy::Secret; #[cfg(target_os = "linux")] @@ -97,7 +98,7 @@ pub enum ServerMsg { error_msg: String, is_authentication_error: bool, }, - OnUpdateResources(Vec), + OnUpdateResources(Vec), /// The IPC service is terminating, maybe due to a software update /// /// This is a hint that the Client should exit with a message like, diff --git a/rust/headless-client/src/lib.rs b/rust/headless-client/src/lib.rs index 646b0196c..2ccfcb132 100644 --- a/rust/headless-client/src/lib.rs +++ b/rust/headless-client/src/lib.rs @@ -10,7 +10,7 @@ use anyhow::{Context as _, Result}; use connlib_client_shared::{Callbacks, DisconnectError}; -use connlib_shared::callbacks; +use connlib_model::ResourceView; use firezone_bin_shared::platform::DnsControlMethod; use std::{ net::{IpAddr, Ipv4Addr, Ipv6Addr}, @@ -82,7 +82,7 @@ pub enum ConnlibMsg { ipv6: Ipv6Addr, dns: Vec, }, - OnUpdateResources(Vec), + OnUpdateResources(Vec), OnUpdateRoutes { ipv4: Vec, ipv6: Vec, @@ -117,7 +117,7 @@ impl Callbacks for CallbackHandler { .expect("Should be able to send OnSetInterfaceConfig"); } - fn on_update_resources(&self, resources: Vec) { + fn on_update_resources(&self, resources: Vec) { tracing::debug!(len = resources.len(), "New resource list"); self.cb_tx .try_send(ConnlibMsg::OnUpdateResources(resources)) diff --git a/rust/headless-client/src/main.rs b/rust/headless-client/src/main.rs index d9f5f7c5f..f98dc9517 100644 --- a/rust/headless-client/src/main.rs +++ b/rust/headless-client/src/main.rs @@ -3,8 +3,7 @@ use anyhow::{anyhow, Context as _, Result}; use backoff::ExponentialBackoffBuilder; use clap::Parser; -use connlib_client_shared::{keypair, ConnectArgs, LoginUrl, Session}; -use connlib_shared::get_user_agent; +use connlib_client_shared::{keypair, ConnectArgs, Session}; use firezone_bin_shared::{ new_dns_notifier, new_network_notifier, platform::{tcp_socket_factory, udp_socket_factory}, @@ -15,6 +14,8 @@ use firezone_headless_client::{ }; use firezone_telemetry::Telemetry; use futures::{FutureExt as _, StreamExt as _}; +use phoenix_channel::get_user_agent; +use phoenix_channel::LoginUrl; use phoenix_channel::PhoenixChannel; use secrecy::{Secret, SecretString}; use std::{ diff --git a/rust/phoenix-channel/Cargo.toml b/rust/phoenix-channel/Cargo.toml index c5503af1a..89b1ded4e 100644 --- a/rust/phoenix-channel/Cargo.toml +++ b/rust/phoenix-channel/Cargo.toml @@ -10,6 +10,7 @@ base64 = "0.22.1" futures = "0.3.29" hex = "0.4" libc = "0.2" +os_info = { version = "3", default-features = false } rand_core = "0.6.4" secrecy = { workspace = true } serde = { version = "1.0.210", features = ["derive"] } diff --git a/rust/connlib/shared/src/lib.rs b/rust/phoenix-channel/src/get_user_agent.rs similarity index 82% rename from rust/connlib/shared/src/lib.rs rename to rust/phoenix-channel/src/get_user_agent.rs index 25f51e6fa..c21f10996 100644 --- a/rust/connlib/shared/src/lib.rs +++ b/rust/phoenix-channel/src/get_user_agent.rs @@ -1,20 +1,6 @@ -//! This crates contains shared types and behavior between all the other libraries. -//! -//! This includes types provided by external crates, i.e. [boringtun] to make sure that -//! we are using the same version across our own crates. - -pub mod callbacks; -pub mod messages; - -pub use boringtun::x25519::PublicKey; -pub use boringtun::x25519::StaticSecret; -pub use phoenix_channel::{LoginUrl, LoginUrlError}; - -pub type DomainName = domain::base::Name>; - -const LIB_NAME: &str = "connlib"; - pub fn get_user_agent(os_version_override: Option, app_version: &str) -> String { + const LIB_NAME: &str = "connlib"; + // Note: we could switch to sys-info and get the hostname // but we lose the arch // and neither of the libraries provide the kernel version. diff --git a/rust/phoenix-channel/src/lib.rs b/rust/phoenix-channel/src/lib.rs index 9517aaab4..3f531b926 100644 --- a/rust/phoenix-channel/src/lib.rs +++ b/rust/phoenix-channel/src/lib.rs @@ -1,3 +1,4 @@ +mod get_user_agent; mod heartbeat; mod login_url; @@ -27,6 +28,7 @@ use tokio_tungstenite::{ }; use url::{Host, Url}; +pub use get_user_agent::get_user_agent; pub use login_url::{DeviceInfo, LoginUrl, LoginUrlError}; pub struct PhoenixChannel {