From d27a7a30833b7a690c34d935ea2978a31d226738 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Wed, 5 Jun 2024 14:04:17 +1000 Subject: [PATCH] feat(relay): support custom turn port (#5208) Original PR: #5130. Co-authored-by: Antoine --- elixir/apps/api/lib/api/relay/socket.ex | 2 +- rust/connlib/snownet/tests/lib.rs | 2 +- rust/connlib/tunnel/src/tests.rs | 1 + rust/phoenix-channel/src/login_url.rs | 12 ++++++-- rust/relay/README.md | 4 +-- rust/relay/src/main.rs | 38 ++++++++++++++++--------- rust/relay/src/server.rs | 7 +++++ rust/relay/tests/regression.rs | 2 +- 8 files changed, 47 insertions(+), 21 deletions(-) diff --git a/elixir/apps/api/lib/api/relay/socket.ex b/elixir/apps/api/lib/api/relay/socket.ex index 2f076cd05..5eb75e421 100644 --- a/elixir/apps/api/lib/api/relay/socket.ex +++ b/elixir/apps/api/lib/api/relay/socket.ex @@ -16,7 +16,7 @@ defmodule API.Relay.Socket do OpenTelemetry.Tracer.with_span "relay.connect" do context = API.Sockets.auth_context(connect_info, :relay_group) - attrs = Map.take(attrs, ~w[ipv4 ipv6 name]) + attrs = Map.take(attrs, ~w[ipv4 ipv6 name port]) with {:ok, group, token} <- Relays.authenticate(encoded_token, context), {:ok, relay} <- Relays.upsert_relay(group, token, attrs, context) do diff --git a/rust/connlib/snownet/tests/lib.rs b/rust/connlib/snownet/tests/lib.rs index 330b5fd7c..b2834a944 100644 --- a/rust/connlib/snownet/tests/lib.rs +++ b/rust/connlib/snownet/tests/lib.rs @@ -462,7 +462,7 @@ impl Firewall { impl TestRelay { fn new(local: impl Into, span: Span) -> Self { let local = local.into(); - let inner = firezone_relay::Server::new(to_ip_stack(local), OsRng, 49152, 65535); + let inner = firezone_relay::Server::new(to_ip_stack(local), OsRng, 3478, 49152, 65535); Self { inner, diff --git a/rust/connlib/tunnel/src/tests.rs b/rust/connlib/tunnel/src/tests.rs index c5ef12b3b..0f6472b55 100644 --- a/rust/connlib/tunnel/src/tests.rs +++ b/rust/connlib/tunnel/src/tests.rs @@ -226,6 +226,7 @@ impl StateMachineTest for TunnelTest { state: firezone_relay::Server::new( ref_state.relay.ip_stack, rand::rngs::StdRng::seed_from_u64(ref_state.relay.state), + 3478, 49152, 65535, ), diff --git a/rust/phoenix-channel/src/login_url.rs b/rust/phoenix-channel/src/login_url.rs index 1e1b5d6e8..fed2188b9 100644 --- a/rust/phoenix-channel/src/login_url.rs +++ b/rust/phoenix-channel/src/login_url.rs @@ -59,6 +59,7 @@ impl LoginUrl { Some(device_name), None, None, + None, )?; Ok(LoginUrl { @@ -88,6 +89,7 @@ impl LoginUrl { Some(device_name), None, None, + None, )?; Ok(LoginUrl { @@ -100,6 +102,7 @@ impl LoginUrl { url: impl TryInto, firezone_token: &SecretString, device_name: Option, + listen_port: u16, ipv4_address: Option, ipv6_address: Option, ) -> std::result::Result> { @@ -110,6 +113,7 @@ impl LoginUrl { None, None, device_name, + Some(listen_port), ipv4_address, ipv6_address, )?; @@ -176,6 +180,7 @@ fn get_websocket_path( public_key: Option<[u8; 32]>, external_id: Option, name: Option, + port: Option, ipv4_address: Option, ipv6_address: Option, ) -> std::result::Result> { @@ -208,8 +213,11 @@ fn get_websocket_path( if let Some(ipv4_address) = ipv4_address { query_pairs.append_pair("ipv4", &ipv4_address.to_string()); } - if let Some(ipv4_address) = ipv6_address { - query_pairs.append_pair("ipv6", &ipv4_address.to_string()); + if let Some(ipv6_address) = ipv6_address { + query_pairs.append_pair("ipv6", &ipv6_address.to_string()); + } + if let Some(port) = port { + query_pairs.append_pair("port", &port.to_string()); } } diff --git a/rust/relay/README.md b/rust/relay/README.md index 5435cd2f0..7a79b2e87 100644 --- a/rust/relay/README.md +++ b/rust/relay/README.md @@ -44,8 +44,8 @@ firezone-relay --help ### Ports -The relay listens on port `3478`. This is the standard port for STUN/TURN and -not configurable. Additionally, the relay needs to have access to the port range +By default, the relay listens on port `3478`. This is the standard port for +STUN/TURN. Additionally, the relay needs to have access to the port range `49152` - `65535` for the allocations. ### Portal Connection diff --git a/rust/relay/src/main.rs b/rust/relay/src/main.rs index 377e8e251..7c7545f71 100644 --- a/rust/relay/src/main.rs +++ b/rust/relay/src/main.rs @@ -27,8 +27,6 @@ use url::Url; const STATS_LOG_INTERVAL: Duration = Duration::from_secs(10); -const TURN_PORT: u16 = 3478; - const MAX_PARTITION_TIME: Duration = Duration::from_secs(60 * 15); #[derive(Parser, Debug)] @@ -39,6 +37,9 @@ struct Args { /// The public (i.e. internet-reachable) IPv6 address of the relay server. #[arg(long, env)] public_ip6_addr: Option, + /// The port to listen on for STUN messages. + #[arg(long, env, hide = true, default_value = "3478")] + listen_port: u16, // See https://www.rfc-editor.org/rfc/rfc8656.html#name-allocations /// The lowest port used for TURN allocations. #[arg(long, env, hide = true, default_value = "49152")] @@ -112,6 +113,7 @@ async fn main() -> Result<()> { let server = Server::new( public_addr, make_rng(args.rng_seed), + args.listen_port, args.lowest_port, args.highest_port, ); @@ -130,6 +132,7 @@ async fn main() -> Result<()> { args.api_url.clone(), token, args.name.clone(), + args.listen_port, args.public_ip4_addr, args.public_ip6_addr, )?; @@ -153,7 +156,7 @@ async fn main() -> Result<()> { let mut eventloop = Eventloop::new(server, channel, public_addr, last_heartbeat_sent)?; - tracing::info!(target: "relay", "Listening for incoming traffic on UDP port {TURN_PORT}"); + tracing::info!(target: "relay", "Listening for incoming traffic on UDP port {0}", args.listen_port); future::poll_fn(|cx| eventloop.poll(cx)) .await @@ -323,16 +326,22 @@ where if public_address.as_v4().is_some() { sockets - .bind(TURN_PORT, AddressFamily::V4) + .bind(server.listen_port(), AddressFamily::V4) .with_context(|| { - format!("Failed to bind to port {TURN_PORT} on IPv4 interfaces") + format!( + "Failed to bind to port {0} on IPv4 interfaces", + server.listen_port() + ) })?; } if public_address.as_v6().is_some() { sockets - .bind(TURN_PORT, AddressFamily::V6) + .bind(server.listen_port(), AddressFamily::V6) .with_context(|| { - format!("Failed to bind to port {TURN_PORT} on IPv6 interfaces") + format!( + "Failed to bind to port {0} on IPv6 interfaces", + server.listen_port() + ) })?; } @@ -360,10 +369,11 @@ where if let Some(next_command) = self.server.next_command() { match next_command { Command::SendMessage { payload, recipient } => { - if let Err(e) = - self.sockets - .try_send(TURN_PORT, recipient.into_socket(), &payload) - { + if let Err(e) = self.sockets.try_send( + self.server.listen_port(), + recipient.into_socket(), + &payload, + ) { tracing::warn!(target: "relay", %recipient, "Failed to send message: {e}"); } } @@ -416,10 +426,10 @@ where match self.sockets.poll_recv_from(payload, cx) { Poll::Ready(Ok(sockets::Received { - port: TURN_PORT, // Packets coming in on the TURN port are from clients. + port, // Packets coming in on the TURN port are from clients. from, packet, - })) => { + })) if port == self.server.listen_port() => { if let Some((port, peer)) = self.server.handle_client_input( packet, ClientSocket::new(from), @@ -456,7 +466,7 @@ where ); if let Err(e) = self.sockets.try_send( - TURN_PORT, // Packets coming in from peers always go out on the TURN port + self.server.listen_port(), // Packets coming in from peers always go out on the TURN port client.into_socket(), &self.buffer[..total_length], ) { diff --git a/rust/relay/src/server.rs b/rust/relay/src/server.rs index 8c571c73f..2f8c10b2e 100644 --- a/rust/relay/src/server.rs +++ b/rust/relay/src/server.rs @@ -60,6 +60,7 @@ pub struct Server { channel_and_client_by_port_and_peer: HashMap<(AllocationPort, PeerSocket), (ClientSocket, ChannelNumber)>, + listen_port: u16, lowest_port: u16, highest_port: u16, @@ -154,6 +155,7 @@ where pub fn new( public_address: impl Into, mut rng: R, + listen_port: u16, lowest_port: u16, highest_port: u16, ) -> Self { @@ -181,6 +183,7 @@ where public_address: public_address.into(), allocations: Default::default(), clients_by_allocation: Default::default(), + listen_port, lowest_port, highest_port, channels_by_client_and_number: Default::default(), @@ -201,6 +204,10 @@ where &self.auth_secret } + pub fn listen_port(&self) -> u16 { + self.listen_port + } + /// Registers a new, valid nonce. /// /// Each nonce is valid for 10 requests. diff --git a/rust/relay/tests/regression.rs b/rust/relay/tests/regression.rs index 44948d377..8ef8d8dbd 100644 --- a/rust/relay/tests/regression.rs +++ b/rust/relay/tests/regression.rs @@ -696,7 +696,7 @@ struct TestServer { impl TestServer { fn new(relay_public_addr: impl Into) -> Self { Self { - server: Server::new(relay_public_addr, StepRng::new(0, 0), 49152, 65535), + server: Server::new(relay_public_addr, StepRng::new(0, 0), 3478, 49152, 65535), } }