mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
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 <ReactorScram@users.noreply.github.com> Co-authored-by: Reactor Scram <ReactorScram@users.noreply.github.com>
This commit is contained in:
38
rust/Cargo.lock
generated
38
rust/Cargo.lock
generated
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
@@ -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<ResourceDescription>) {
|
||||
fn on_update_resources(&self, resource_list: Vec<ResourceView>) {
|
||||
self.env(|mut env| {
|
||||
let resource_list = env
|
||||
.new_string(serde_json::to_string(&resource_list)?)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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<ResourceDescription>) {
|
||||
fn on_update_resources(&self, resource_list: Vec<ResourceView>) {
|
||||
self.inner.on_update_resources(
|
||||
serde_json::to_string(&resource_list)
|
||||
.expect("developer error: failed to serialize resource list"),
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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<ResourceDescription>) {}
|
||||
fn on_update_resources(&self, _: Vec<ResourceView>) {}
|
||||
|
||||
/// Called when the tunnel is disconnected.
|
||||
///
|
||||
|
||||
@@ -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::{
|
||||
|
||||
@@ -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<CB> {
|
||||
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<CB: Callbacks + 'static>(
|
||||
args: ConnectArgs<CB>,
|
||||
portal: PhoenixChannel<(), IngressMessages, ReplyMessages>,
|
||||
|
||||
21
rust/connlib/model/Cargo.toml
Normal file
21
rust/connlib/model/Cargo.toml
Normal file
@@ -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
|
||||
186
rust/connlib/model/src/lib.rs
Normal file
186
rust/connlib/model/src/lib.rs
Normal file
@@ -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<Vec<u8>>;
|
||||
|
||||
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<Self, Self::Err> {
|
||||
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<Self, Self::Err> {
|
||||
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<Self, Self::Err> {
|
||||
Ok(ResourceId(Uuid::parse_str(s)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for GatewayId {
|
||||
type Err = uuid::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
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<H: std::hash::Hasher>(&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<Self, Self::Err> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -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<String>,
|
||||
pub sites: Vec<Site>,
|
||||
|
||||
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<String>,
|
||||
pub sites: Vec<Site>,
|
||||
|
||||
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<Site>,
|
||||
|
||||
pub status: Status,
|
||||
pub status: ResourceStatus,
|
||||
}
|
||||
|
||||
impl PartialOrd for ResourceDescription {
|
||||
impl PartialOrd for ResourceView {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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<String>,
|
||||
#[serde(rename = "gateway_groups")]
|
||||
pub sites: Vec<Site>,
|
||||
}
|
||||
|
||||
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<String>,
|
||||
#[serde(rename = "gateway_groups")]
|
||||
pub sites: Vec<Site>,
|
||||
}
|
||||
|
||||
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<Site>,
|
||||
}
|
||||
|
||||
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<H: std::hash::Hasher>(&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<Self, Self::Err> {
|
||||
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<String> {
|
||||
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<Site> {
|
||||
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<ResourceDescriptionDns> {
|
||||
match self {
|
||||
ResourceDescription::Dns(d) => Some(d),
|
||||
ResourceDescription::Cidr(_) | ResourceDescription::Internet(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_cidr(self) -> Option<ResourceDescriptionCidr> {
|
||||
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::<Vec<ResourceDescription>>(resources).unwrap();
|
||||
}
|
||||
}
|
||||
@@ -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<Filter>;
|
||||
|
||||
/// 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<Filter> {
|
||||
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::<Vec<ResourceDescription>>(resources).unwrap();
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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<GatewayId, SiteId>,
|
||||
/// The online/offline status of a site.
|
||||
sites_status: HashMap<SiteId, Status>,
|
||||
sites_status: HashMap<SiteId, ResourceStatus>,
|
||||
|
||||
/// All CIDR resources we know about, indexed by the IP range they cover (like `1.1.0.0/8`).
|
||||
active_cidr_resources: IpNetworkTable<ResourceDescriptionCidr>,
|
||||
@@ -317,7 +317,7 @@ impl ClientState {
|
||||
self.node.num_connections()
|
||||
}
|
||||
|
||||
pub(crate) fn resources(&self) -> Vec<callbacks::ResourceDescription> {
|
||||
pub(crate) fn resources(&self) -> Vec<ResourceView> {
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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<callbacks::ResourceDescription>,
|
||||
resources: Vec<ResourceView>,
|
||||
},
|
||||
TunInterfaceUpdated(TunConfig),
|
||||
}
|
||||
|
||||
@@ -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<Self, Self::Err> {
|
||||
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<Self, Self::Err> {
|
||||
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<Self, Self::Err> {
|
||||
Ok(ResourceId(Uuid::parse_str(s)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for GatewayId {
|
||||
type Err = uuid::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
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 {
|
||||
@@ -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<String>,
|
||||
#[serde(rename = "gateway_groups")]
|
||||
pub sites: Vec<Site>,
|
||||
}
|
||||
|
||||
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<String>,
|
||||
#[serde(rename = "gateway_groups")]
|
||||
pub sites: Vec<Site>,
|
||||
}
|
||||
|
||||
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<Site>,
|
||||
}
|
||||
|
||||
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<String> {
|
||||
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<Site> {
|
||||
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<ResourceDescriptionDns> {
|
||||
match self {
|
||||
ResourceDescription::Dns(d) => Some(d),
|
||||
ResourceDescription::Cidr(_) | ResourceDescription::Internet(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_cidr(self) -> Option<ResourceDescriptionCidr> {
|
||||
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::<Vec<ResourceDescription>>(resources).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn broadcast_ice_candidates() {
|
||||
@@ -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<Filter>;
|
||||
|
||||
/// 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<Filter> {
|
||||
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::<Vec<ResourceDescription>>(resources).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn request_connection_message() {
|
||||
let message = r#"{
|
||||
@@ -88,7 +88,7 @@ pub type SecretKey = Secret<Key>;
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use boringtun::x25519::{PublicKey, StaticSecret};
|
||||
use rand_core::OsRng;
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
use super::Key;
|
||||
|
||||
@@ -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<DateTime<Utc>>,
|
||||
) {
|
||||
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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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::{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 _};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<client::SiteId, BTreeSet<GatewayId>>,
|
||||
gateways_by_site: BTreeMap<SiteId, BTreeSet<GatewayId>>,
|
||||
|
||||
#[derivative(Debug = "ignore")]
|
||||
sites_by_resource: BTreeMap<ResourceId, client::SiteId>,
|
||||
sites_by_resource: BTreeMap<ResourceId, SiteId>,
|
||||
cidr_resources: BTreeMap<ResourceId, client::ResourceDescriptionCidr>,
|
||||
dns_resources: BTreeMap<ResourceId, client::ResourceDescriptionDns>,
|
||||
internet_resource: client::ResourceDescriptionInternet,
|
||||
@@ -39,7 +41,7 @@ pub(crate) struct StubPortal {
|
||||
|
||||
impl StubPortal {
|
||||
pub(crate) fn new(
|
||||
gateways_by_site: BTreeMap<client::SiteId, BTreeSet<GatewayId>>,
|
||||
gateways_by_site: BTreeMap<SiteId, BTreeSet<GatewayId>>,
|
||||
gateway_selector: Selector,
|
||||
cidr_resources: BTreeSet<client::ResourceDescriptionCidr>,
|
||||
dns_resources: BTreeSet<client::ResourceDescriptionDns>,
|
||||
@@ -118,7 +120,7 @@ impl StubPortal {
|
||||
&self,
|
||||
resource: ResourceId,
|
||||
_connected_gateway_ids: BTreeSet<GatewayId>,
|
||||
) -> (GatewayId, client::SiteId) {
|
||||
) -> (GatewayId, SiteId) {
|
||||
let site_id = self
|
||||
.sites_by_resource
|
||||
.get(&resource)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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 <https://github.com/hwchen/keyring-rs/issues/132>
|
||||
"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 <https://github.com/hwchen/keyring-rs/issues/132>
|
||||
"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]
|
||||
|
||||
@@ -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<ResourceDescription>,
|
||||
resources: Vec<ResourceView>,
|
||||
},
|
||||
/// Firezone is signing in to the Portal.
|
||||
WaitingForPortal {
|
||||
@@ -190,7 +190,7 @@ impl Status {
|
||||
}
|
||||
}
|
||||
|
||||
fn internet_resource(&self) -> Option<ResourceDescription> {
|
||||
fn internet_resource(&self) -> Option<ResourceView> {
|
||||
#[expect(clippy::wildcard_enum_match_arm)]
|
||||
match self {
|
||||
Status::TunnelReady { resources } => {
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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<ResourceId>,
|
||||
pub resources: Vec<ResourceDescription>,
|
||||
pub resources: Vec<ResourceView>,
|
||||
pub internet_resource_enabled: Option<bool>,
|
||||
}
|
||||
|
||||
@@ -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<ResourceDescription>,
|
||||
resources: Vec<ResourceView>,
|
||||
favorite_resources: HashSet<ResourceId>,
|
||||
internet_resource_enabled: Option<bool>,
|
||||
) -> AppState {
|
||||
@@ -328,7 +325,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn resources() -> Vec<ResourceDescription> {
|
||||
fn resources() -> Vec<ResourceView> {
|
||||
let s = r#"[
|
||||
{
|
||||
"id": "73037362-715d-4a83-a749-f18eadd970e6",
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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. <https://github.com/firezone/firezone/pull/4328#discussion_r1540342142>
|
||||
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]
|
||||
|
||||
@@ -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<ResourceDescription>),
|
||||
OnUpdateResources(Vec<ResourceView>),
|
||||
/// The IPC service is terminating, maybe due to a software update
|
||||
///
|
||||
/// This is a hint that the Client should exit with a message like,
|
||||
|
||||
@@ -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<IpAddr>,
|
||||
},
|
||||
OnUpdateResources(Vec<callbacks::ResourceDescription>),
|
||||
OnUpdateResources(Vec<ResourceView>),
|
||||
OnUpdateRoutes {
|
||||
ipv4: Vec<Ipv4Network>,
|
||||
ipv6: Vec<Ipv6Network>,
|
||||
@@ -117,7 +117,7 @@ impl Callbacks for CallbackHandler {
|
||||
.expect("Should be able to send OnSetInterfaceConfig");
|
||||
}
|
||||
|
||||
fn on_update_resources(&self, resources: Vec<callbacks::ResourceDescription>) {
|
||||
fn on_update_resources(&self, resources: Vec<ResourceView>) {
|
||||
tracing::debug!(len = resources.len(), "New resource list");
|
||||
self.cb_tx
|
||||
.try_send(ConnlibMsg::OnUpdateResources(resources))
|
||||
|
||||
@@ -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::{
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
@@ -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<Vec<u8>>;
|
||||
|
||||
const LIB_NAME: &str = "connlib";
|
||||
|
||||
pub fn get_user_agent(os_version_override: Option<String>, 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.
|
||||
@@ -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<TInitReq, TInboundMsg, TOutboundRes> {
|
||||
|
||||
Reference in New Issue
Block a user