From c4e608bd1440cd70bb00f1df534b9255e4fd7378 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Wed, 19 Jun 2024 08:08:49 +1000 Subject: [PATCH] fix(gateway): ensure DNS resolution times out before connection (#5419) When we attempt to establish a connection to a gateway for a DNS resource, the gateway must resolve the requested domain name before it can accept the connection. Currently, this timeout is set to 60s which is much longer than the client's connection timeout. DNS resolution is typically a very fast protocol so reducing this timeout to 5s should be safe. In addition, we add a compile-time assertion that this timeout must be less than the client's connection timeout. --------- Signed-off-by: Thomas Eizinger Co-authored-by: Jamil --- rust/Cargo.lock | 2 ++ rust/connlib/snownet/src/lib.rs | 2 +- rust/connlib/snownet/src/node.rs | 2 +- rust/gateway/Cargo.toml | 2 ++ rust/gateway/src/eventloop.rs | 11 ++++++++++- 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index fb22e3593..f508ac74a 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1916,6 +1916,8 @@ dependencies = [ "secrecy", "serde", "serde_json", + "snownet", + "static_assertions", "tokio", "tokio-tungstenite", "tracing", diff --git a/rust/connlib/snownet/src/lib.rs b/rust/connlib/snownet/src/lib.rs index dd06195d3..e34323b90 100644 --- a/rust/connlib/snownet/src/lib.rs +++ b/rust/connlib/snownet/src/lib.rs @@ -13,6 +13,6 @@ mod utils; pub use allocation::RelaySocket; pub use node::{ Answer, Client, ClientNode, Credentials, Error, Event, Node, Offer, Server, ServerNode, - Transmit, + Transmit, HANDSHAKE_TIMEOUT, }; pub use stats::{ConnectionStats, NodeStats}; diff --git a/rust/connlib/snownet/src/node.rs b/rust/connlib/snownet/src/node.rs index 6279c1ec3..d30a782cf 100644 --- a/rust/connlib/snownet/src/node.rs +++ b/rust/connlib/snownet/src/node.rs @@ -38,7 +38,7 @@ const HANDSHAKE_RATE_LIMIT: u64 = 100; const CANDIDATE_TIMEOUT: Duration = Duration::from_secs(10); /// How long we will at most wait for an [`Answer`] from the remote. -const HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(20); +pub const HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(20); const MAX_UDP_SIZE: usize = (1 << 16) - 1; diff --git a/rust/gateway/Cargo.toml b/rust/gateway/Cargo.toml index 5206b6d91..59e66c131 100644 --- a/rust/gateway/Cargo.toml +++ b/rust/gateway/Cargo.toml @@ -33,6 +33,8 @@ dns-lookup = { workspace = true } libc = { version = "0.2", default-features = false, features = ["std", "const-extern-fn", "extra_traits"] } either = "1" http-health-check = { workspace = true } +static_assertions = "1.1.0" +snownet = { workspace = true } [dev-dependencies] serde_json = { version = "1.0", default-features = false, features = ["std"] } diff --git a/rust/gateway/src/eventloop.rs b/rust/gateway/src/eventloop.rs index f6baf5d96..8f48f71d8 100644 --- a/rust/gateway/src/eventloop.rs +++ b/rust/gateway/src/eventloop.rs @@ -24,6 +24,15 @@ use std::time::Duration; pub const PHOENIX_TOPIC: &str = "gateway"; +/// How long we allow a DNS resolution via `libc::get_addr_info`. +const DNS_RESOLUTION_TIMEOUT: Duration = Duration::from_secs(10); + +// DNS resolution happens as part of every connection setup. +// For a connection to succeed, DNS resolution must be less than `snownet`'s handshake timeout. +static_assertions::const_assert!( + DNS_RESOLUTION_TIMEOUT.as_secs() < snownet::HANDSHAKE_TIMEOUT.as_secs() +); + pub struct Eventloop { tunnel: GatewayTunnel, portal: PhoenixChannel<(), IngressMessages, ()>, @@ -40,7 +49,7 @@ impl Eventloop { Self { tunnel, portal, - resolve_tasks: futures_bounded::FuturesTupleSet::new(Duration::from_secs(60), 100), + resolve_tasks: futures_bounded::FuturesTupleSet::new(DNS_RESOLUTION_TIMEOUT, 100), } } }