fix(quic): allow listening on ipv4 and ipv6 separately

Resolves #4165.

Pull-Request: #4289.
This commit is contained in:
João Oliveira 2023-08-08 17:48:08 +01:00 committed by GitHub
parent b5d993267f
commit 02dc432227
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 52 additions and 5 deletions

3
Cargo.lock generated
View File

@ -3058,7 +3058,7 @@ dependencies = [
[[package]] [[package]]
name = "libp2p-quic" name = "libp2p-quic"
version = "0.9.0-alpha" version = "0.9.1-alpha"
dependencies = [ dependencies = [
"async-std", "async-std",
"bytes", "bytes",
@ -3079,6 +3079,7 @@ dependencies = [
"quinn", "quinn",
"rand 0.8.5", "rand 0.8.5",
"rustls 0.21.5", "rustls 0.21.5",
"socket2 0.5.3",
"thiserror", "thiserror",
"tokio", "tokio",
] ]

View File

@ -85,7 +85,7 @@ libp2p-perf = { version = "0.2.0", path = "protocols/perf" }
libp2p-ping = { version = "0.43.0", path = "protocols/ping" } libp2p-ping = { version = "0.43.0", path = "protocols/ping" }
libp2p-plaintext = { version = "0.40.0", path = "transports/plaintext" } libp2p-plaintext = { version = "0.40.0", path = "transports/plaintext" }
libp2p-pnet = { version = "0.23.0", path = "transports/pnet" } libp2p-pnet = { version = "0.23.0", path = "transports/pnet" }
libp2p-quic = { version = "0.9.0-alpha", path = "transports/quic" } libp2p-quic = { version = "0.9.1-alpha", path = "transports/quic" }
libp2p-relay = { version = "0.16.1", path = "protocols/relay" } libp2p-relay = { version = "0.16.1", path = "protocols/relay" }
libp2p-rendezvous = { version = "0.13.0", path = "protocols/rendezvous" } libp2p-rendezvous = { version = "0.13.0", path = "protocols/rendezvous" }
libp2p-request-response = { version = "0.25.1", path = "protocols/request-response" } libp2p-request-response = { version = "0.25.1", path = "protocols/request-response" }

View File

@ -1,3 +1,10 @@
## 0.9.1-alpha - unreleased
- Allow listening on ipv4 and ipv6 separately.
See [PR 4289].
[PR 4289]: https://github.com/libp2p/rust-libp2p/pull/4289
## 0.9.0-alpha ## 0.9.0-alpha
- Use `quinn` instead of `quinn-proto`. - Use `quinn` instead of `quinn-proto`.

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libp2p-quic" name = "libp2p-quic"
version = "0.9.0-alpha" version = "0.9.1-alpha"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021" edition = "2021"
rust-version = { workspace = true } rust-version = { workspace = true }
@ -24,6 +24,7 @@ rand = "0.8.5"
rustls = { version = "0.21.2", default-features = false } rustls = { version = "0.21.2", default-features = false }
thiserror = "1.0.44" thiserror = "1.0.44"
tokio = { version = "1.29.1", default-features = false, features = ["net", "rt", "time"], optional = true } tokio = { version = "1.29.1", default-features = false, features = ["net", "rt", "time"], optional = true }
socket2 = "0.5.3"
[features] [features]
tokio = ["dep:tokio", "if-watch/tokio", "quinn/runtime-tokio"] tokio = ["dep:tokio", "if-watch/tokio", "quinn/runtime-tokio"]

View File

@ -37,12 +37,13 @@ use libp2p_core::{
Transport, Transport,
}; };
use libp2p_identity::PeerId; use libp2p_identity::PeerId;
use socket2::{Domain, Socket, Type};
use std::collections::hash_map::{DefaultHasher, Entry}; use std::collections::hash_map::{DefaultHasher, Entry};
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, UdpSocket}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, UdpSocket};
use std::time::Duration; use std::time::Duration;
use std::{fmt, io};
use std::{ use std::{
net::SocketAddr, net::SocketAddr,
pin::Pin, pin::Pin,
@ -172,6 +173,21 @@ impl<P: Provider> GenTransport<P> {
} }
} }
} }
fn create_socket(&self, socket_addr: SocketAddr) -> io::Result<UdpSocket> {
let socket = Socket::new(
Domain::for_address(socket_addr),
Type::DGRAM,
Some(socket2::Protocol::UDP),
)?;
if socket_addr.is_ipv6() {
socket.set_only_v6(true)?;
}
socket.bind(&socket_addr.into())?;
Ok(socket.into())
}
} }
impl<P: Provider> Transport for GenTransport<P> { impl<P: Provider> Transport for GenTransport<P> {
@ -188,7 +204,8 @@ impl<P: Provider> Transport for GenTransport<P> {
let (socket_addr, version, _peer_id) = self.remote_multiaddr_to_socketaddr(addr, false)?; let (socket_addr, version, _peer_id) = self.remote_multiaddr_to_socketaddr(addr, false)?;
let endpoint_config = self.quinn_config.endpoint_config.clone(); let endpoint_config = self.quinn_config.endpoint_config.clone();
let server_config = self.quinn_config.server_config.clone(); let server_config = self.quinn_config.server_config.clone();
let socket = UdpSocket::bind(socket_addr).map_err(Self::Error::from)?; let socket = self.create_socket(socket_addr).map_err(Self::Error::from)?;
let socket_c = socket.try_clone().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 endpoint = Self::new_endpoint(endpoint_config, Some(server_config), socket)?;
let listener = Listener::new( let listener = Listener::new(
@ -888,4 +905,25 @@ mod test {
.unwrap(); .unwrap();
assert!(!transport.dialer.contains_key(&SocketFamily::Ipv4)); assert!(!transport.dialer.contains_key(&SocketFamily::Ipv4));
} }
#[cfg(feature = "tokio")]
#[tokio::test]
async fn test_listens_ipv4_ipv6_separately() {
let keypair = libp2p_identity::Keypair::generate_ed25519();
let config = Config::new(&keypair);
let mut transport = crate::tokio::Transport::new(config);
transport
.listen_on(
ListenerId::next(),
"/ip4/0.0.0.0/udp/4001/quic-v1".parse().unwrap(),
)
.unwrap();
transport
.listen_on(
ListenerId::next(),
"/ip6/::/udp/4001/quic-v1".parse().unwrap(),
)
.unwrap();
}
} }