feat(relay): allow channel bindings to IPv6 addresses (#3434)

Previously, we still had a hard-coded rule in the relay that would not
allow us to relay to an IPv6 peer. We can remove that and properly check
this based on the allocated addresses.

Resolves: #3405.
This commit is contained in:
Thomas Eizinger
2024-01-30 16:36:54 -08:00
committed by GitHub
parent 6a33516460
commit 3f8c6cb6eb
2 changed files with 68 additions and 11 deletions

View File

@@ -1027,9 +1027,18 @@ impl Channel {
}
impl Allocation {
/// Checks whether this [`Allocation`] can relay to the given address.
///
/// This is called in the context of a channel binding with the requested peer address.
/// We can only relay to the address if the allocation supports the same version of the IP protocol.
fn can_relay_to(&self, addr: SocketAddr) -> bool {
// Currently, we only support IPv4, thus any IPv6 address is invalid.
addr.is_ipv4()
match addr {
SocketAddr::V4(_) => self.first_relay_addr.is_ipv4(), // If we have an IPv4 address, it is in `first_relay_addr`, no need to check `second_relay_addr`.
SocketAddr::V6(_) => {
self.first_relay_addr.is_ipv6()
|| self.second_relay_addr.is_some_and(|a| a.is_ipv6())
}
}
}
}

View File

@@ -7,7 +7,7 @@ use rand::rngs::mock::StepRng;
use secrecy::SecretString;
use std::collections::HashMap;
use std::iter;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::time::{Duration, SystemTime};
use stun_codec::rfc5389::attributes::{ErrorCode, Nonce, Realm, Username, XorMappedAddress};
use stun_codec::rfc5389::errors::Unauthorized;
@@ -377,28 +377,36 @@ fn ping_pong_relay(
}
#[proptest]
fn can_make_ipv6_allocation(
#[strategy(firezone_relay::proptest::transaction_id())] transaction_id: TransactionId,
fn ping_pong_ip6_relay(
#[strategy(firezone_relay::proptest::transaction_id())] allocate_transaction_id: TransactionId,
#[strategy(firezone_relay::proptest::transaction_id())]
channel_bind_transaction_id: TransactionId,
#[strategy(firezone_relay::proptest::allocation_lifetime())] lifetime: Lifetime,
#[strategy(firezone_relay::proptest::username_salt())] username_salt: String,
source: SocketAddrV4,
#[strategy(firezone_relay::proptest::channel_number())] channel: ChannelNumber,
source: SocketAddrV6,
peer: SocketAddrV6,
public_relay_ip4_addr: Ipv4Addr,
public_relay_ip6_addr: Ipv6Addr,
#[strategy(firezone_relay::proptest::now())] now: SystemTime,
peer_to_client_ping: [u8; 32],
client_to_peer_ping: [u8; 32],
#[strategy(firezone_relay::proptest::nonce())] nonce: Uuid,
) {
let _ = env_logger::try_init();
let mut server =
TestServer::new((public_relay_ip4_addr, public_relay_ip6_addr)).with_nonce(nonce);
let secret = server.auth_secret();
let secret = server.auth_secret().to_owned();
server.assert_commands(
from_client(
source,
Allocate::new_authenticated_udp_ip6(
transaction_id,
allocate_transaction_id,
Some(lifetime.clone()),
valid_username(now, &username_salt),
secret,
&secret,
nonce,
),
now,
@@ -409,7 +417,7 @@ fn can_make_ipv6_allocation(
send_message(
source,
allocate_response(
transaction_id,
allocate_transaction_id,
public_relay_ip6_addr,
49152,
source,
@@ -418,6 +426,46 @@ fn can_make_ipv6_allocation(
),
],
);
let now = now + Duration::from_secs(1);
server.assert_commands(
from_client(
source,
ChannelBind::new(
channel_bind_transaction_id,
channel,
XorPeerAddress::new(peer.into()),
valid_username(now, &username_salt),
&secret,
nonce,
),
now,
),
[send_message(
source,
channel_bind_response(channel_bind_transaction_id),
)],
);
let now = now + Duration::from_secs(1);
server.assert_commands(
from_client(
source,
ChannelData::new(channel.value(), client_to_peer_ping.as_ref()),
now,
),
[forward(peer, &client_to_peer_ping, 49152)],
);
server.assert_commands(
from_peer(peer, peer_to_client_ping.as_ref(), 49152),
[send_channel_data(
source,
ChannelData::new(channel.value(), peer_to_client_ping.as_ref()),
)],
);
}
struct TestServer {
@@ -590,7 +638,7 @@ fn allocate_response(
transaction_id: TransactionId,
public_relay_addr: impl Into<IpAddr>,
port: u16,
source: SocketAddrV4,
source: impl Into<SocketAddr>,
lifetime: &Lifetime,
) -> Message<Attribute> {
let mut message =