Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net: add option to set and retrieve IPV6_V6ONLY option to TcpSocket #6171

Closed
wants to merge 1 commit into from

Conversation

fusion32
Copy link

Adding fine control over the IPV6_V6ONLY option allows for consistency across systems instead of relying on system defaults.

Motivation

Currently there is no way to access this option without resorting to the socket2 library and converting a socket to std::net::TcpListener and then to tokio::net::TcpListener. This process can be error prone as there are other options that the net runtime expects to be set like the nonblocking option.

This is an example of the function I'm using myself to "solve" this problem.

use std::net::{Ipv6Addr, SocketAddr};
use tokio::net::TcpListener;
fn tokio_tcp_listener_v6(port: u16, v6only: bool) -> io::Result<TcpListener> {
	let addr = SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), port);
	let socket = socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::STREAM, None)?;
	#[cfg(not(windows))]
	socket.set_reuse_address(true)?;
	socket.set_only_v6(v6only)?;
	socket.set_nonblocking(true)?;
	socket.bind(&addr.into())?;
	socket.listen(1024)?;

	let listener = std::net::TcpListener::from(socket);
	let listener = TcpListener::from_std(listener)?;
	Ok(listener)
}

Solution

The TcpSocket interface already uses the socket2 library underneath so adding a couple of functions to retrieve and set the IPV6_V6ONLY option is absolutely trivial and allows code to setup a listener to be straightforward and to have less direct dependencies:

use std::net::{Ipv6Addr, SocketAddr};
use tokio::net::{TcpListener, TcpSocket};
fn tokio_tcp_listener_v6(port: u16, v6only: bool) -> io::Result<TcpListener> {
	let socket = TcpSocket::new_v6()?;
	socket.set_only_v6(v6only)?;
	socket.bind((Ipv6Addr::UNSPECIFIED, port).into())?;
	let listener = socket.listen(1024)?;
	Ok(listener)
}

The reasoning for adding fine control over the IPV6_V6ONLY option is
to have consistency across systems instead of being stuck with system
defaults. For example: on Windows this option is ON by default while
on Linux, the default value is defined by the contents of the file
`/proc/sys/net/ipv6/bindv6only`.
@Darksonn
Copy link
Contributor

You don't have to create the entire socket with socket2 to use socket2. You can use SockRef on an existing Tokio socket to set the option, and let Tokio handle the rest of the options.

@Darksonn Darksonn added A-tokio Area: The main tokio crate M-net Module: tokio/net labels Nov 29, 2023
@fusion32
Copy link
Author

fusion32 commented Dec 1, 2023

Using socket2::SockRef does solve the problem of having to set tokio's socket options manually while also simplifying the process which is nice.

pub fn tokio_tcp_listener_v6(port: u16, v6only: bool) -> io::Result<tokio::net::TcpListener> {
	let socket = tokio::net::TcpSocket::new_v6()?;

	{
		let socket_ref = socket2::SockRef::from(&socket);
		socket_ref.set_only_v6(v6only)?;
	}

	socket.bind((Ipv6Addr::UNSPECIFIED, port).into())?;
	socket.listen(1024)
}

The thing is that it still adds the direct dependency of socket2 which may not be that bad but I'm wondering why aren't more common socket options exposed? When using IPv6, I feel like IPV6_V6ONLY is something you want to directly control or at least have consistent behavior across multiple systems.

Anyway, it's not my decision and I don't want to force any unwanted PR merge. If anything, the socket2::SockRef solution is already satisfactory.

@Darksonn
Copy link
Contributor

Darksonn commented Dec 1, 2023

On one hand, we could add this. On the other hand, we don't want to add every single option. I'm leaning towards not adding this particular option.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio Area: The main tokio crate M-net Module: tokio/net
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants