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

feat(quic): remove QUIC draft-29 version support #5759

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
16 changes: 1 addition & 15 deletions transports/quic/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,6 @@ pub struct Config {
/// of a connection.
pub max_connection_data: u32,

/// Support QUIC version draft-29 for dialing and listening.
///
/// Per default only QUIC Version 1 / [`libp2p_core::multiaddr::Protocol::QuicV1`]
/// is supported.
///
/// If support for draft-29 is enabled servers support draft-29 and version 1 on all
/// QUIC listening addresses.
/// As client the version is chosen based on the remote's address.
pub support_draft_29: bool,

/// TLS client config for the inner [`quinn::ClientConfig`].
client_tls_config: Arc<QuicClientConfig>,
/// TLS server config for the inner [`quinn::ServerConfig`].
Expand All @@ -85,7 +75,6 @@ impl Config {
Self {
client_tls_config,
server_tls_config,
support_draft_29: false,
handshake_timeout: Duration::from_secs(5),
max_idle_timeout: 10 * 1000,
max_concurrent_stream_limit: 256,
Expand Down Expand Up @@ -132,7 +121,6 @@ impl From<Config> for QuinnConfig {
keep_alive_interval,
max_connection_data,
max_stream_data,
support_draft_29,
handshake_timeout: _,
keypair,
mtu_discovery_config,
Expand Down Expand Up @@ -169,9 +157,7 @@ impl From<Config> for QuinnConfig {
})
.unwrap_or_default();

if !support_draft_29 {
endpoint_config.supported_versions(vec![1]);
}
endpoint_config.supported_versions(vec![1]);

QuinnConfig {
client_config,
Expand Down
126 changes: 36 additions & 90 deletions transports/quic/src/transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@
/// By default only QUIC Version 1 (RFC 9000) is supported. In the [`Multiaddr`] this maps to
/// [`libp2p_core::multiaddr::Protocol::QuicV1`].
/// The [`libp2p_core::multiaddr::Protocol::Quic`] codepoint is interpreted as QUIC version
/// draft-29 and only supported if [`Config::support_draft_29`] is set to `true`.
/// Note that in that case servers support both version an all QUIC listening addresses.
///
/// Version draft-29 should only be used to connect to nodes from other libp2p implementations
Expand All @@ -72,8 +71,6 @@
quinn_config: QuinnConfig,
/// Timeout for the [`Connecting`] future.
handshake_timeout: Duration,
/// Whether draft-29 is supported for dialing and listening.
support_draft_29: bool,
/// Streams of active [`Listener`]s.
listeners: SelectAll<Listener<P>>,
/// Dialer for each socket family if no matching listener exists.
Expand All @@ -88,15 +85,13 @@
/// Create a new [`GenTransport`] with the given [`Config`].
pub fn new(config: Config) -> Self {
let handshake_timeout = config.handshake_timeout;
let support_draft_29 = config.support_draft_29;
let quinn_config = config.into();
Self {
listeners: SelectAll::new(),
quinn_config,
handshake_timeout,
dialer: HashMap::new(),
waker: None,
support_draft_29,
hole_punch_attempts: Default::default(),
}
}
Expand Down Expand Up @@ -142,7 +137,7 @@
(SocketAddr, ProtocolVersion, Option<PeerId>),
TransportError<<Self as Transport>::Error>,
> {
let (socket_addr, version, peer_id) = multiaddr_to_socketaddr(&addr, self.support_draft_29)
let (socket_addr, version, peer_id) = multiaddr_to_socketaddr(&addr)
.ok_or_else(|| TransportError::MultiaddrNotSupported(addr.clone()))?;
if check_unspecified_addr && (socket_addr.port() == 0 || socket_addr.ip().is_unspecified())
{
Expand Down Expand Up @@ -228,20 +223,14 @@
listener_id: ListenerId,
addr: Multiaddr,
) -> Result<(), TransportError<Self::Error>> {
let (socket_addr, version, _peer_id) = self.remote_multiaddr_to_socketaddr(addr, false)?;
let (socket_addr, _, _peer_id) = self.remote_multiaddr_to_socketaddr(addr, false)?;
let endpoint_config = self.quinn_config.endpoint_config.clone();
let server_config = self.quinn_config.server_config.clone();
let socket = self.create_socket(socket_addr).map_err(Self::Error::from)?;

let socket_c = socket.try_clone().map_err(Self::Error::from)?;
let endpoint = Self::new_endpoint(endpoint_config, Some(server_config), socket)?;
let listener = Listener::new(
listener_id,
socket_c,
endpoint,
self.handshake_timeout,
version,
)?;
let listener = Listener::new(listener_id, socket_c, endpoint, self.handshake_timeout)?;
self.listeners.push(listener);

if let Some(waker) = self.waker.take() {
Expand Down Expand Up @@ -272,8 +261,7 @@
addr: Multiaddr,
dial_opts: DialOpts,
) -> Result<Self::Dial, TransportError<Self::Error>> {
let (socket_addr, version, peer_id) =
self.remote_multiaddr_to_socketaddr(addr.clone(), true)?;
let (socket_addr, _, peer_id) = self.remote_multiaddr_to_socketaddr(addr.clone(), true)?;

match (dial_opts.role, dial_opts.port_use) {
(Endpoint::Dialer, _) | (Endpoint::Listener, PortUse::Reuse) => {
Expand All @@ -300,10 +288,7 @@
dialer
};
let handshake_timeout = self.handshake_timeout;
let mut client_config = self.quinn_config.client_config.clone();
if version == ProtocolVersion::Draft29 {
client_config.version(0xff00_001d);
}
let client_config = self.quinn_config.client_config.clone();
Ok(Box::pin(async move {
// This `"l"` seems necessary because an empty string is an invalid domain
// name. While we don't use domain names, the underlying rustls library
Expand Down Expand Up @@ -385,10 +370,7 @@
local_addr,
send_back_addr,
} => {
let socket_addr =
multiaddr_to_socketaddr(&send_back_addr, self.support_draft_29)
.unwrap()
.0;
let socket_addr = multiaddr_to_socketaddr(&send_back_addr).unwrap().0;

if let Some(sender) = self.hole_punch_attempts.remove(&socket_addr) {
match sender.send(upgrade) {
Expand Down Expand Up @@ -426,9 +408,6 @@
/// Id of the listener.
listener_id: ListenerId,

/// Version of the supported quic protocol.
version: ProtocolVersion,

/// Endpoint
endpoint: quinn::Endpoint,

Expand Down Expand Up @@ -463,7 +442,6 @@
socket: UdpSocket,
endpoint: quinn::Endpoint,
handshake_timeout: Duration,
version: ProtocolVersion,
) -> Result<Self, Error> {
let if_watcher;
let pending_event;
Expand All @@ -475,7 +453,7 @@
} else {
if_watcher = None;
listening_addresses.insert(local_addr.ip());
let ma = socketaddr_to_multiaddr(&local_addr, version);
let ma = socketaddr_to_multiaddr(&local_addr);
pending_event = Some(TransportEvent::NewAddress {
listener_id,
listen_addr: ma,
Expand All @@ -490,7 +468,6 @@
socket,
accept,
listener_id,
version,
handshake_timeout,
if_watcher,
is_closed: false,
Expand Down Expand Up @@ -539,9 +516,7 @@
loop {
match ready!(P::poll_if_event(if_watcher, cx)) {
Ok(IfEvent::Up(inet)) => {
if let Some(listen_addr) =
ip_to_listenaddr(&endpoint_addr, inet.addr(), self.version)
{
if let Some(listen_addr) = ip_to_listenaddr(&endpoint_addr, inet.addr()) {
tracing::debug!(
address=%listen_addr,
"New listen address"
Expand All @@ -554,9 +529,7 @@
}
}
Ok(IfEvent::Down(inet)) => {
if let Some(listen_addr) =
ip_to_listenaddr(&endpoint_addr, inet.addr(), self.version)
{
if let Some(listen_addr) = ip_to_listenaddr(&endpoint_addr, inet.addr()) {
tracing::debug!(
address=%listen_addr,
"Expired listen address"
Expand Down Expand Up @@ -608,9 +581,9 @@
}
};

let local_addr = socketaddr_to_multiaddr(&self.socket_addr(), self.version);
let local_addr = socketaddr_to_multiaddr(&self.socket_addr());
let remote_addr = connecting.remote_address();
let send_back_addr = socketaddr_to_multiaddr(&remote_addr, self.version);
let send_back_addr = socketaddr_to_multiaddr(&remote_addr);

let event = TransportEvent::Incoming {
upgrade: Connecting::new(connecting, self.handshake_timeout),
Expand Down Expand Up @@ -648,7 +621,6 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ProtocolVersion {
V1, // i.e. RFC9000
Draft29,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -683,24 +655,19 @@
///
/// Returns `None` if the `ip` is not the same socket family as the
/// address that the endpoint is bound to.
fn ip_to_listenaddr(
endpoint_addr: &SocketAddr,
ip: IpAddr,
version: ProtocolVersion,
) -> Option<Multiaddr> {
fn ip_to_listenaddr(endpoint_addr: &SocketAddr, ip: IpAddr) -> Option<Multiaddr> {
// True if either both addresses are Ipv4 or both Ipv6.
if !SocketFamily::is_same(&endpoint_addr.ip(), &ip) {
return None;
}
let socket_addr = SocketAddr::new(ip, endpoint_addr.port());
Some(socketaddr_to_multiaddr(&socket_addr, version))
Some(socketaddr_to_multiaddr(&socket_addr))
}

/// Tries to turn a QUIC multiaddress into a UDP [`SocketAddr`]. Returns None if the format
/// of the multiaddr is wrong.
fn multiaddr_to_socketaddr(
addr: &Multiaddr,
support_draft_29: bool,
) -> Option<(SocketAddr, ProtocolVersion, Option<PeerId>)> {
let mut iter = addr.iter();
let proto1 = iter.next()?;
Expand All @@ -716,56 +683,52 @@
_ => return None,
}
}
let version = match proto3 {
Protocol::QuicV1 => ProtocolVersion::V1,
Protocol::Quic if support_draft_29 => ProtocolVersion::Draft29,

match proto3 {
Protocol::QuicV1 => (),
_ => return None,
};

match (proto1, proto2) {
(Protocol::Ip4(ip), Protocol::Udp(port)) => {
Some((SocketAddr::new(ip.into(), port), version, peer_id))
}
(Protocol::Ip6(ip), Protocol::Udp(port)) => {
Some((SocketAddr::new(ip.into(), port), version, peer_id))
}
(Protocol::Ip4(ip), Protocol::Udp(port)) => Some((
SocketAddr::new(ip.into(), port),
ProtocolVersion::V1,
peer_id,
)),
(Protocol::Ip6(ip), Protocol::Udp(port)) => Some((
SocketAddr::new(ip.into(), port),
ProtocolVersion::V1,
peer_id,
)),
_ => None,
}
}

/// Turns an IP address and port into the corresponding QUIC multiaddr.
fn socketaddr_to_multiaddr(socket_addr: &SocketAddr, version: ProtocolVersion) -> Multiaddr {
let quic_proto = match version {
ProtocolVersion::V1 => Protocol::QuicV1,
ProtocolVersion::Draft29 => Protocol::Quic,
};
fn socketaddr_to_multiaddr(socket_addr: &SocketAddr) -> Multiaddr {
Multiaddr::empty()
.with(socket_addr.ip().into())
.with(Protocol::Udp(socket_addr.port()))
.with(quic_proto)
.with(Protocol::QuicV1)
}

#[cfg(test)]
#[cfg(any(feature = "async-std", feature = "tokio"))]
mod tests {
use futures::future::poll_fn;

use super::*;

#[test]
fn multiaddr_to_udp_conversion() {
assert!(multiaddr_to_socketaddr(
&"/ip4/127.0.0.1/udp/1234".parse::<Multiaddr>().unwrap(),
true
)
.is_none());
assert!(
multiaddr_to_socketaddr(&"/ip4/127.0.0.1/udp/1234".parse::<Multiaddr>().unwrap())
.is_none()
);

assert_eq!(
multiaddr_to_socketaddr(
&"/ip4/127.0.0.1/udp/12345/quic-v1"
.parse::<Multiaddr>()
.unwrap(),
false
.unwrap()
),
Some((
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12345,),
Expand All @@ -778,7 +741,6 @@
&"/ip4/255.255.255.255/udp/8080/quic-v1"
.parse::<Multiaddr>()
.unwrap(),
false
),
Some((
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(255, 255, 255, 255)), 8080,),
Expand All @@ -790,18 +752,15 @@
multiaddr_to_socketaddr(
&"/ip4/127.0.0.1/udp/55148/quic-v1/p2p/12D3KooW9xk7Zp1gejwfwNpfm6L9zH5NL4Bx5rm94LRYJJHJuARZ"
.parse::<Multiaddr>()
.unwrap(), false
.unwrap()
),
Some((SocketAddr::new(
IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
55148,
), ProtocolVersion::V1, Some("12D3KooW9xk7Zp1gejwfwNpfm6L9zH5NL4Bx5rm94LRYJJHJuARZ".parse().unwrap())))
);
assert_eq!(
multiaddr_to_socketaddr(
&"/ip6/::1/udp/12345/quic-v1".parse::<Multiaddr>().unwrap(),
false
),
multiaddr_to_socketaddr(&"/ip6/::1/udp/12345/quic-v1".parse::<Multiaddr>().unwrap(),),
Some((
SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 12345,),
ProtocolVersion::V1,
Expand All @@ -813,7 +772,6 @@
&"/ip6/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/udp/8080/quic-v1"
.parse::<Multiaddr>()
.unwrap(),
false
),
Some((
SocketAddr::new(
Expand All @@ -828,21 +786,9 @@
);

assert!(multiaddr_to_socketaddr(
&"/ip4/127.0.0.1/udp/1234/quic".parse::<Multiaddr>().unwrap(),
false
&"/ip4/127.0.0.1/udp/1234/quic".parse::<Multiaddr>().unwrap()
)
.is_none());
assert_eq!(
multiaddr_to_socketaddr(
&"/ip4/127.0.0.1/udp/1234/quic".parse::<Multiaddr>().unwrap(),
true
),
Some((
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 1234,),
ProtocolVersion::Draft29,
None
))
);
}

#[cfg(feature = "async-std")]
Expand All @@ -851,7 +797,7 @@
let keypair = libp2p_identity::Keypair::generate_ed25519();
let config = Config::new(&keypair);
let mut transport = crate::async_std::Transport::new(config);
assert!(poll_fn(|cx| Pin::new(&mut transport).as_mut().poll(cx))

Check failure on line 800 in transports/quic/src/transport.rs

View workflow job for this annotation

GitHub Actions / clippy (1.83.0)

cannot find function `poll_fn` in this scope

Check failure on line 800 in transports/quic/src/transport.rs

View workflow job for this annotation

GitHub Actions / Test libp2p-quic

cannot find function `poll_fn` in this scope
.now_or_never()
.is_none());

Expand All @@ -863,7 +809,7 @@
.listen_on(id, "/ip4/0.0.0.0/udp/0/quic-v1".parse().unwrap())
.unwrap();

match poll_fn(|cx| Pin::new(&mut transport).as_mut().poll(cx)).await {

Check failure on line 812 in transports/quic/src/transport.rs

View workflow job for this annotation

GitHub Actions / clippy (1.83.0)

cannot find function `poll_fn` in this scope

Check failure on line 812 in transports/quic/src/transport.rs

View workflow job for this annotation

GitHub Actions / Test libp2p-quic

cannot find function `poll_fn` in this scope
TransportEvent::NewAddress {
listener_id,
listen_addr,
Expand All @@ -880,7 +826,7 @@
e => panic!("Unexpected event: {e:?}"),
}
assert!(transport.remove_listener(id), "Expect listener to exist.");
match poll_fn(|cx| Pin::new(&mut transport).as_mut().poll(cx)).await {

Check failure on line 829 in transports/quic/src/transport.rs

View workflow job for this annotation

GitHub Actions / clippy (1.83.0)

cannot find function `poll_fn` in this scope

Check failure on line 829 in transports/quic/src/transport.rs

View workflow job for this annotation

GitHub Actions / Test libp2p-quic

cannot find function `poll_fn` in this scope
TransportEvent::ListenerClosed {
listener_id,
reason: Ok(()),
Expand All @@ -891,7 +837,7 @@
}
// Poll once again so that the listener has the chance to return `Poll::Ready(None)` and
// be removed from the list of listeners.
assert!(poll_fn(|cx| Pin::new(&mut transport).as_mut().poll(cx))

Check failure on line 840 in transports/quic/src/transport.rs

View workflow job for this annotation

GitHub Actions / clippy (1.83.0)

cannot find function `poll_fn` in this scope

Check failure on line 840 in transports/quic/src/transport.rs

View workflow job for this annotation

GitHub Actions / Test libp2p-quic

cannot find function `poll_fn` in this scope
.now_or_never()
.is_none());
assert!(transport.listeners.is_empty());
Expand Down
Loading
Loading