mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
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:
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user