Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions quic/s2n-quic-platform/src/io/tokio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ impl Io {
gro_enabled,
reuse_address,
reuse_port,
only_v6,
} = self.builder;

let clock = Clock::default();
Expand Down Expand Up @@ -91,7 +92,7 @@ impl Io {
let rx_socket = if let Some(rx_socket) = rx_socket {
rx_socket
} else if let Some(recv_addr) = recv_addr {
syscall::bind_udp(recv_addr, reuse_address, reuse_port)?
syscall::bind_udp(recv_addr, reuse_address, reuse_port, only_v6)?
} else {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
Expand All @@ -104,7 +105,7 @@ impl Io {
let tx_socket = if let Some(tx_socket) = tx_socket {
tx_socket
} else if let Some(send_addr) = send_addr {
syscall::bind_udp(send_addr, reuse_address, reuse_port)?
syscall::bind_udp(send_addr, reuse_address, reuse_port, only_v6)?
} else {
// No tx_socket or send address was specified, so the tx socket
// will be a handle to the rx socket.
Expand Down
14 changes: 14 additions & 0 deletions quic/s2n-quic-platform/src/io/tokio/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub struct Builder {
pub(super) gro_enabled: Option<bool>,
pub(super) reuse_address: bool,
pub(super) reuse_port: bool,
pub(super) only_v6: bool,
}

impl Builder {
Expand Down Expand Up @@ -236,6 +237,19 @@ impl Builder {
Ok(self)
}

/// Set the value for the IPV6_V6ONLY socket option.
///
/// If this is set to `true` then the socket is restricted to sending and
/// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications
/// can bind the same port at the same time.
///
/// If this is set to `false` then the socket can be used to send and
/// receive packets from an IPv4-mapped IPv6 address.
pub fn with_only_v6(mut self, only_v6: bool) -> io::Result<Self> {
self.only_v6 = only_v6;
Ok(self)
}

pub fn build(self) -> io::Result<Io> {
Ok(Io { builder: self })
}
Expand Down
28 changes: 25 additions & 3 deletions quic/s2n-quic-platform/src/io/tokio/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,17 @@ async fn runtime<A: ToSocketAddrs>(
receive_addr: A,
send_addr: Option<A>,
) -> io::Result<(super::Io, SocketAddress)> {
let rx_socket = syscall::bind_udp(receive_addr, false, false)?;
let mut io_builder = Io::builder();

let rx_socket = syscall::bind_udp(receive_addr, false, false, false)?;
rx_socket.set_nonblocking(true)?;
let rx_socket: std::net::UdpSocket = rx_socket.into();
let rx_addr = rx_socket.local_addr()?;

let mut io_builder = Io::builder().with_rx_socket(rx_socket)?;
io_builder = io_builder.with_rx_socket(rx_socket)?;

if let Some(tx_addr) = send_addr {
let tx_socket = syscall::bind_udp(tx_addr, false, false)?;
let tx_socket = syscall::bind_udp(tx_addr, false, false, false)?;
tx_socket.set_nonblocking(true)?;
let tx_socket: std::net::UdpSocket = tx_socket.into();
io_builder = io_builder.with_tx_socket(tx_socket)?
Expand Down Expand Up @@ -260,3 +262,23 @@ async fn ipv6_two_socket_test() -> io::Result<()> {
other => other,
}
}

#[cfg(unix)]
#[tokio::test]
#[cfg_attr(miri, ignore)]
async fn only_v6_test() -> io::Result<()> {
// Socket always set only_v6 to true if it binds
// to a specific IPV6 address. We use ANY address
// to test for only_v6.
static IPV6_ANY_ADDRESS: &str = "[::]:0";

let mut only_v6 = false;
let socket = syscall::bind_udp(IPV6_ANY_ADDRESS, false, false, only_v6)?;
assert!(!socket.only_v6()?);

only_v6 = true;
let socket = syscall::bind_udp(IPV6_ANY_ADDRESS, false, false, only_v6)?;
assert!(socket.only_v6()?);

Ok(())
}
3 changes: 2 additions & 1 deletion quic/s2n-quic-platform/src/io/xdp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ pub mod socket {
interface: &::std::ffi::CStr,
addr: ::std::net::SocketAddr,
) -> ::std::io::Result<::std::net::UdpSocket> {
let socket = crate::syscall::udp_socket(addr)?;
let only_v6 = false;
let socket = crate::syscall::udp_socket(addr, only_v6)?;

// associate the socket with a single interface
crate::syscall::bind_to_interface(&socket, interface)?;
Expand Down
4 changes: 3 additions & 1 deletion quic/s2n-quic-platform/src/socket/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub struct Options {
pub send_buffer: Option<usize>,
pub recv_buffer: Option<usize>,
pub backlog: usize,
pub only_v6: bool,
}

impl Default for Options {
Expand All @@ -47,6 +48,7 @@ impl Default for Options {
recv_buffer: None,
delay: false,
backlog: 4096,
only_v6: false,
}
}
}
Expand All @@ -62,7 +64,7 @@ impl Options {

#[inline]
pub fn build_udp(&self) -> io::Result<UdpSocket> {
let socket = syscall::udp_socket(self.addr)?;
let socket = syscall::udp_socket(self.addr, self.only_v6)?;

if self.gro {
let _ = syscall::configure_gro(&socket);
Expand Down
8 changes: 4 additions & 4 deletions quic/s2n-quic-platform/src/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,14 @@ pub trait UnixMessage: crate::message::Message {
);
}

pub fn udp_socket(addr: std::net::SocketAddr) -> io::Result<Socket> {
pub fn udp_socket(addr: std::net::SocketAddr, only_v6: bool) -> io::Result<Socket> {
let domain = Domain::for_address(addr);
let socket_type = Type::DGRAM;
let protocol = Some(Protocol::UDP);

let socket = Socket::new(domain, socket_type, protocol)?;

// allow ipv4 to also connect - ignore the error if it fails
let _ = socket.set_only_v6(false);
let _ = socket.set_only_v6(only_v6);

Ok(socket)
}
Expand All @@ -84,14 +83,15 @@ pub fn bind_udp<A: std::net::ToSocketAddrs>(
addr: A,
reuse_address: bool,
reuse_port: bool,
only_v6: bool,
) -> io::Result<Socket> {
let addr = addr.to_socket_addrs()?.next().ok_or_else(|| {
std::io::Error::new(
io::ErrorKind::InvalidInput,
"the provided bind address was empty",
)
})?;
let socket = udp_socket(addr)?;
let socket = udp_socket(addr, only_v6)?;

socket.set_reuse_address(reuse_address)?;

Expand Down
Loading