net: Implement QUIC transport based on quinn

Also deduplicate some TLS code.
This commit is contained in:
x
2026-01-15 16:42:17 +00:00
parent bf47853e87
commit cb7f9e4d0c
6 changed files with 759 additions and 310 deletions

491
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -67,6 +67,7 @@ tor-hscrypto = {version = "0.37.0", optional = true}
tor-hsservice = {version = "0.37.0", optional = true}
tor-proto = {version = "0.37.0", optional = true}
tor-cell = {version = "0.37.0", optional = true}
quinn = {git="https://github.com/parazyd/quinn", branch="no-tokio", default-features = false, features = ["rustls-ring", "runtime-smol"], optional = true}
# TLS cert utilities
ed25519-compact = {version = "2.2.0", optional = true}
@@ -228,6 +229,7 @@ net-defaults = [
"p2p-i2p",
"p2p-socks5",
"p2p-unix",
"p2p-quic",
]
p2p-unix = []
@@ -238,6 +240,10 @@ p2p-i2p = [
"p2p-socks5"
]
p2p-quic = [
"quinn"
]
net = ["net-defaults"]
rpc = [

View File

@@ -48,6 +48,10 @@ pub(crate) mod nym;
#[cfg(feature = "p2p-unix")]
pub(crate) mod unix;
/// QUIC transport
#[cfg(feature = "p2p-quic")]
pub(crate) mod quic;
/// Dialer variants
#[derive(Debug, Clone)]
pub enum DialerVariant {
@@ -84,6 +88,9 @@ pub enum DialerVariant {
/// SOCKS5 proxy with TLS
#[cfg(feature = "p2p-socks5")]
Socks5Tls(socks5::Socks5Dialer),
/// QUIC (with built-in TLS)
Quic(quic::QuicDialer),
}
/// Listener variants
@@ -99,9 +106,13 @@ pub enum ListenerVariant {
/// Tor
Tor(tor::TorListener),
/// Unix socket
#[cfg(feature = "p2p-unix")]
/// Unix socket
Unix(unix::UnixListener),
#[cfg(feature = "p2p-quic")]
/// QUIC (with built-in TLS)
Quic(quic::QuicListener),
}
/// A dialer that is able to transparently operate over arbitrary transports.
@@ -243,6 +254,15 @@ impl Dialer {
Ok(Self { endpoint, variant })
}
#[cfg(feature = "p2p-quic")]
"quic" => {
// Build a QUIC dialer (TLS is built-in)
enforce_hostport!(endpoint);
let variant = quic::QuicDialer::new().await?;
let variant = DialerVariant::Quic(variant);
Ok(Self { endpoint, variant })
}
x => {
error!("[P2P] Requested unsupported transport: {x}");
Err(io::Error::from_raw_os_error(libc::ENETUNREACH))
@@ -323,6 +343,13 @@ impl Dialer {
let stream = tlsupgrade.upgrade_dialer_tls(stream).await?;
Ok(Box::new(stream))
}
#[cfg(feature = "p2p-quic")]
DialerVariant::Quic(dialer) => {
let sockaddr = self.endpoint.socket_addrs(|| None)?;
let stream = dialer.do_dial(sockaddr[0], timeout).await?;
Ok(Box::new(stream))
}
}
}
@@ -378,6 +405,14 @@ impl Listener {
Ok(Self { endpoint, variant })
}
#[cfg(feature = "p2p-quic")]
"quic" => {
enforce_hostport!(endpoint);
let variant = quic::QuicListener::new().await?;
let variant = ListenerVariant::Quic(variant);
Ok(Self { endpoint, variant })
}
x => {
error!("[P2P] Requested unsupported transport: {x}");
Err(io::Error::from_raw_os_error(libc::ENETUNREACH))
@@ -419,6 +454,13 @@ impl Listener {
let l = listener.do_listen(&path).await?;
Ok(Box::new(l))
}
#[cfg(feature = "p2p-quic")]
ListenerVariant::Quic(listener) => {
let sockaddr = self.endpoint.socket_addrs(|| None)?;
let l = listener.do_listen(sockaddr[0]).await?;
Ok(Box::new(l))
}
}
}
@@ -443,8 +485,24 @@ impl Listener {
endpoint
}
#[cfg(feature = "p2p-tor")]
ListenerVariant::Tor(listener) => listener.endpoint.get().unwrap().clone(),
#[cfg(feature = "p2p-quic")]
ListenerVariant::Quic(listener) => {
let mut endpoint = self.endpoint.clone();
let port = self.endpoint.port().unwrap();
if port == 0 {
if let Some(actual_port) = listener.port.get() {
endpoint.set_port(Some(*actual_port)).unwrap();
}
}
endpoint
}
#[allow(unreachable_patterns)]
_ => self.endpoint.clone(),
}
@@ -467,6 +525,9 @@ impl PtStream for futures_rustls::TlsStream<arti_client::DataStream> {}
#[cfg(feature = "p2p-unix")]
impl PtStream for smol::net::unix::UnixStream {}
#[cfg(feature = "p2p-quic")]
impl PtStream for quic::QuicStream {}
/// Wrapper trait for async listeners
#[async_trait]
pub trait PtListener: Send + Unpin {

286
src/net/transport/quic.rs Normal file
View File

@@ -0,0 +1,286 @@
/* This file is part of DarkFi (https://dark.fi)
*
* Copyright (C) 2020-2026 Dyne.org foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use std::{
io,
net::SocketAddr,
pin::Pin,
sync::Arc,
task::{Context, Poll},
time::Duration,
};
use async_trait::async_trait;
use futures::{
future::{select, Either},
pin_mut,
};
use futures_rustls::rustls::{self, version::TLS13};
use quinn::{
crypto::rustls::{QuicClientConfig, QuicServerConfig},
ClientConfig, Endpoint, RecvStream, SendStream, ServerConfig, TransportConfig, VarInt,
};
use smol::{
io::{AsyncRead, AsyncWrite},
lock::OnceCell,
Timer,
};
use tracing::debug;
use url::Url;
use super::{
tls::{
generate_certificate, ClientCertificateVerifier, ServerCertificateVerifier, TLS_DNS_NAME,
},
PtListener, PtStream,
};
/// Create QUIC client configuration with our TLS config
fn create_client_config() -> io::Result<ClientConfig> {
let (certificate, secret_key) = generate_certificate()?;
let server_cert_verifier = Arc::new(ServerCertificateVerifier {});
let tls_config = rustls::ClientConfig::builder_with_protocol_versions(&[&TLS13])
.dangerous()
.with_custom_certificate_verifier(server_cert_verifier)
.with_client_auth_cert(vec![certificate], secret_key)
.map_err(|e| io::Error::other(format!("Failed to create QUIC client TLS config: {e}")))?;
let quic_config: QuicClientConfig = tls_config
.try_into()
.map_err(|e| io::Error::other(format!("Failed to create QUIC client config: {e}")))?;
let mut config = ClientConfig::new(Arc::new(quic_config));
// Configure transport parameters
let mut transport = TransportConfig::default();
transport.keep_alive_interval(Some(Duration::from_secs(15)));
transport.max_idle_timeout(Some(VarInt::from_u32(30_000).into()));
config.transport_config(Arc::new(transport));
Ok(config)
}
/// Create QUIC server configuration with our TLS config
fn create_server_config() -> io::Result<ServerConfig> {
let (certificate, secret_key) = generate_certificate()?;
let client_cert_verifier = Arc::new(ClientCertificateVerifier {});
let tls_config = rustls::ServerConfig::builder_with_protocol_versions(&[&TLS13])
.with_client_cert_verifier(client_cert_verifier)
.with_single_cert(vec![certificate], secret_key)
.map_err(|e| io::Error::other(format!("Failed to create QUIC server TLS config: {e}")))?;
let quic_config: QuicServerConfig = tls_config
.try_into()
.map_err(|e| io::Error::other(format!("Failed to create QUIC server config: {e}")))?;
let mut config = ServerConfig::with_crypto(Arc::new(quic_config));
// Configure transport parameters
let mut transport = TransportConfig::default();
transport.keep_alive_interval(Some(Duration::from_secs(15)));
transport.max_idle_timeout(Some(VarInt::from_u32(30_000).into()));
config.transport_config(Arc::new(transport));
Ok(config)
}
/// Wrapper around quinn's bidirectional stream to implement PtStream
pub struct QuicStream {
send: SendStream,
recv: RecvStream,
}
impl QuicStream {
fn new(send: SendStream, recv: RecvStream) -> Self {
Self { send, recv }
}
}
impl AsyncRead for QuicStream {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut self.recv)
.poll_read(cx, buf)
.map_err(|e| io::Error::other(format!("QUIC read error: {e}")))
}
}
impl AsyncWrite for QuicStream {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Pin::new(&mut self.send)
.poll_write(cx, buf)
.map_err(|e| io::Error::other(format!("QUIC write error: {e}")))
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut self.send)
.poll_flush(cx)
.map_err(|e| io::Error::other(format!("QUIC flush error: {e}")))
}
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut self.send)
.poll_close(cx)
.map_err(|e| io::Error::other(format!("QUIC close error: {e}")))
}
}
/// QUIC Dialer implementation
#[derive(Clone, Debug)]
pub struct QuicDialer {
endpoint: Endpoint,
}
impl QuicDialer {
/// Instantiate a new [`QuicDialer`] object
pub(crate) async fn new() -> io::Result<Self> {
let client_config = create_client_config()?;
// Bind to any available port for outgoing connections
let endpoint = Endpoint::client("0.0.0.0:0".parse().unwrap())
.map_err(|e| io::Error::other(format!("Failed to create QUIC endpoint: {e}")))?;
endpoint.set_default_client_config(client_config);
Ok(Self { endpoint })
}
/// Internal dial function
pub(crate) async fn do_dial(
&self,
socket_addr: SocketAddr,
timeout: Option<Duration>,
) -> io::Result<QuicStream> {
debug!(target: "net::quic::do_dial", "Dialing {socket_addr} with QUIC...");
let connect = async {
// Connect to the remote endpoint
let connection = self
.endpoint
.connect(socket_addr, TLS_DNS_NAME)
.map_err(|e| io::Error::other(format!("QUIC connect error: {e}")))?
.await
.map_err(|e| io::Error::other(format!("QUIC connection error: {e}")))?;
// Open a bidirectional stream
let (send, recv) = connection
.open_bi()
.await
.map_err(|e| io::Error::other(format!("QUIC stream error: {e}")))?;
Ok(QuicStream::new(send, recv))
};
match timeout {
Some(t) => {
let timer = Timer::after(t);
pin_mut!(timer);
pin_mut!(connect);
match select(connect, timer).await {
Either::Left((Ok(stream), _)) => Ok(stream),
Either::Left((Err(e), _)) => Err(e),
Either::Right((_, _)) => Err(io::ErrorKind::TimedOut.into()),
}
}
None => connect.await,
}
}
}
/// QUIC Listener implementation
#[derive(Debug, Clone)]
pub struct QuicListener {
/// When the user puts a port of 0, the OS will assign a random port.
/// We get it from the listener so we know what the true endpoint is.
pub port: Arc<OnceCell<u16>>,
}
impl QuicListener {
/// Instantiate a new [`QuicListener`]
pub async fn new() -> io::Result<Self> {
Ok(Self { port: Arc::new(OnceCell::new()) })
}
/// Internal listen function
pub(crate) async fn do_listen(
&self,
socket_addr: SocketAddr,
) -> io::Result<QuicListenerIntern> {
let server_config = create_server_config()?;
let endpoint = Endpoint::server(server_config, socket_addr)
.map_err(|e| io::Error::other(format!("Failed to create QUIC server endpoint: {e}")))?;
let local_port = endpoint.local_addr()?.port();
debug!(
target: "net::quic::do_listen",
"Listening on QUIC endpoint: {}",
endpoint.local_addr()?,
);
self.port.set(local_port).await.expect("fatal port already set for QuicListener");
Ok(QuicListenerIntern { endpoint })
}
}
/// Internal QUIC Listener implementation, used with `PtListener`
pub struct QuicListenerIntern {
endpoint: Endpoint,
}
#[async_trait]
impl PtListener for QuicListenerIntern {
async fn next(&self) -> io::Result<(Box<dyn PtStream>, Url)> {
// Wait for an incoming connection
let incoming =
self.endpoint.accept().await.ok_or_else(|| {
io::Error::new(io::ErrorKind::ConnectionAborted, "Endpoint closed")
})?;
let peer_addr = incoming.remote_address();
let connection =
incoming.await.map_err(|e| io::Error::other(format!("QUIC accept error: {e}")))?;
// Accept a bidirectional stream from the client
let (send, recv) = connection
.accept_bi()
.await
.map_err(|e| io::Error::other(format!("QUIC stream accept error: {e}")))?;
let url = Url::parse(&format!("quic://{peer_addr}")).map_err(|e| {
io::Error::new(io::ErrorKind::InvalidData, format!("Invalid peer address: {e}"))
})?;
Ok((Box::new(QuicStream::new(send, recv)), url))
}
}

View File

@@ -36,10 +36,13 @@ use x509_parser::{
prelude::{GeneralName, ParsedExtension, X509Certificate},
};
/// The DNS name used for certificate validation across all transports
pub(crate) const TLS_DNS_NAME: &str = "dark.fi";
/// Validate certificate DNSName.
fn validate_dnsname(cert: &X509Certificate) -> std::result::Result<(), rustls::Error> {
#[rustfmt::skip]
let oid = x509_parser::oid_registry::asn1_rs::oid!(2.5.29.17);
let oid = x509_parser::oid_registry::asn1_rs::oid!(2.5.29.17);
let Ok(Some(extension)) = cert.get_extension_unique(&oid) else {
return Err(rustls::CertificateError::BadEncoding.into())
};
@@ -59,15 +62,52 @@ fn validate_dnsname(cert: &X509Certificate) -> std::result::Result<(), rustls::E
_ => return Err(rustls::CertificateError::BadEncoding.into()),
};
if dns_name != "dark.fi" {
if dns_name != TLS_DNS_NAME {
return Err(rustls::CertificateError::BadEncoding.into())
}
Ok(())
}
fn verify_ed25519_signature(
message: &[u8],
cert: &CertificateDer,
dss: &DigitallySignedStruct,
) -> std::result::Result<HandshakeSignatureValid, rustls::Error> {
if dss.scheme != SignatureScheme::ED25519 {
return Err(rustls::CertificateError::BadSignature.into())
}
// Read the DER-encoded certificate into a buffer
let buf: Vec<u8> = cert.iter().copied().collect();
// Parse the cert and extract the public key
let Ok((_, cert)) = parse_x509_certificate(&buf) else {
error!(target: "net::tls::verify_ed25519_signature", "[net::tls] Failed parsing TLS certificate");
return Err(rustls::CertificateError::BadEncoding.into())
};
let Ok(public_key) = ed25519_compact::PublicKey::from_der(cert.public_key().raw) else {
error!(target: "net::tls::verify_ed25519_signature", "[net::tls] Failed parsing public key");
return Err(rustls::CertificateError::BadEncoding.into())
};
let Ok(signature) = ed25519_compact::Signature::from_slice(dss.signature()) else {
error!(target: "net::tls::verify_ed25519_signature", "[net::tls] Failed verifying signature");
return Err(rustls::CertificateError::BadSignature.into())
};
if let Err(e) = public_key.verify(message, &signature) {
error!(target: "net::tls::verify_ed25519_signature", "[net::tls] Failed verifying signature: {e}");
return Err(rustls::CertificateError::BadSignature.into())
}
Ok(HandshakeSignatureValid::assertion())
}
#[derive(Debug)]
struct ServerCertificateVerifier;
pub(crate) struct ServerCertificateVerifier;
impl ServerCertVerifier for ServerCertificateVerifier {
fn verify_server_cert(
&self,
@@ -78,10 +118,7 @@ impl ServerCertVerifier for ServerCertificateVerifier {
_now: UnixTime,
) -> std::result::Result<ServerCertVerified, rustls::Error> {
// Read the DER-encoded certificate into a buffer
let mut buf = Vec::with_capacity(end_entity.len());
for byte in end_entity.iter() {
buf.push(*byte);
}
let buf: Vec<u8> = end_entity.iter().copied().collect();
// Parse the certificate
let Ok((_, cert)) = parse_x509_certificate(&buf) else {
@@ -110,40 +147,7 @@ impl ServerCertVerifier for ServerCertificateVerifier {
cert: &CertificateDer,
dss: &DigitallySignedStruct,
) -> std::result::Result<HandshakeSignatureValid, rustls::Error> {
// Verify we're using the correct signature scheme
if dss.scheme != SignatureScheme::ED25519 {
return Err(rustls::CertificateError::BadSignature.into())
}
// Read the DER-encoded certificate into a buffer
let mut buf = Vec::with_capacity(cert.len());
for byte in cert.iter() {
buf.push(*byte);
}
// Parse the certificate and extract the public key
let Ok((_, cert)) = parse_x509_certificate(&buf) else {
error!(target: "net::tls::verify_tls13_signature", "[net::tls] Failed parsing server TLS certificate");
return Err(rustls::CertificateError::BadEncoding.into())
};
let Ok(public_key) = ed25519_compact::PublicKey::from_der(cert.public_key().raw) else {
error!(target: "net::tls::verify_tls13_signature", "[net::tls] Failed parsing server public key");
return Err(rustls::CertificateError::BadEncoding.into())
};
// Verify the signature
let Ok(signature) = ed25519_compact::Signature::from_slice(dss.signature()) else {
error!(target: "net::tls::verify_tls13_signature", "[net::tls] Failed verifying server signature");
return Err(rustls::CertificateError::BadSignature.into())
};
if let Err(e) = public_key.verify(message, &signature) {
error!(target: "net::tls::verify_tls13_signature", "[net::tls] Failed verifying server signature: {e}");
return Err(rustls::CertificateError::BadSignature.into())
}
Ok(HandshakeSignatureValid::assertion())
verify_ed25519_signature(message, cert, dss)
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
@@ -152,7 +156,8 @@ impl ServerCertVerifier for ServerCertificateVerifier {
}
#[derive(Debug)]
struct ClientCertificateVerifier;
pub(crate) struct ClientCertificateVerifier;
impl ClientCertVerifier for ClientCertificateVerifier {
fn offer_client_auth(&self) -> bool {
true
@@ -173,13 +178,10 @@ impl ClientCertVerifier for ClientCertificateVerifier {
_now: UnixTime,
) -> std::result::Result<ClientCertVerified, rustls::Error> {
// Read the DER-encoded certificate into a buffer
let mut cert = Vec::with_capacity(end_entity.len());
for byte in end_entity.iter() {
cert.push(*byte);
}
let buf: Vec<u8> = end_entity.iter().copied().collect();
// Parse the certificate
let Ok((_, cert)) = parse_x509_certificate(&cert) else {
let Ok((_, cert)) = parse_x509_certificate(&buf) else {
error!(target: "net::tls::verify_server_cert", "[net::tls] Failed parsing server TLS certificate");
return Err(rustls::CertificateError::BadEncoding.into())
};
@@ -205,40 +207,7 @@ impl ClientCertVerifier for ClientCertificateVerifier {
cert: &CertificateDer,
dss: &DigitallySignedStruct,
) -> std::result::Result<HandshakeSignatureValid, rustls::Error> {
// Verify we're using the correct signature scheme
if dss.scheme != SignatureScheme::ED25519 {
return Err(rustls::CertificateError::BadSignature.into())
}
// Read the DER-encoded certificate into a buffer
let mut buf = Vec::with_capacity(cert.len());
for byte in cert.iter() {
buf.push(*byte);
}
// Parse the certificate and extract the public key
let Ok((_, cert)) = parse_x509_certificate(&buf) else {
error!(target: "net::tls::verify_tls13_signature", "[net::tls] Failed parsing server TLS certificate");
return Err(rustls::CertificateError::BadEncoding.into())
};
let Ok(public_key) = ed25519_compact::PublicKey::from_der(cert.public_key().raw) else {
error!(target: "net::tls::verify_tls13_signature", "[net::tls] Failed parsing server public key");
return Err(rustls::CertificateError::BadEncoding.into())
};
// Verify the signature
let Ok(signature) = ed25519_compact::Signature::from_slice(dss.signature()) else {
error!(target: "net::tls::verify_tls13_signature", "[net::tls] Failed verifying server signature");
return Err(rustls::CertificateError::BadSignature.into())
};
if let Err(e) = public_key.verify(message, &signature) {
error!(target: "net::tls::verify_tls13_signature", "[net::tls] Failed verifying server signature: {e}");
return Err(rustls::CertificateError::BadSignature.into())
}
Ok(HandshakeSignatureValid::assertion())
verify_ed25519_signature(message, cert, dss)
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
@@ -246,6 +215,39 @@ impl ClientCertVerifier for ClientCertificateVerifier {
}
}
/// Generate a self-signed Ed25519 certificate for TLS.
/// Returns the certificate and private key in DER format.
pub(crate) fn generate_certificate() -> io::Result<(CertificateDer<'static>, PrivateKeyDer<'static>)>
{
let Ok(keypair) = rcgen::KeyPair::generate_for(&rcgen::PKCS_ED25519) else {
return Err(io::Error::other("Failed to generate TLS keypair"))
};
let Ok(mut cert_params) = rcgen::CertificateParams::new(&[]) else {
return Err(io::Error::other("Failed to generate TLS params"))
};
cert_params.subject_alt_names =
vec![rcgen::SanType::DnsName(Ia5String::try_from(TLS_DNS_NAME).unwrap())];
cert_params.extended_key_usages = vec![
rcgen::ExtendedKeyUsagePurpose::ClientAuth,
rcgen::ExtendedKeyUsagePurpose::ServerAuth,
];
let Ok(certificate) = cert_params.self_signed(&keypair) else {
return Err(io::Error::other("Failed to sign TLS certificate"))
};
let certificate = certificate.der().clone();
let keypair_der = keypair.serialize_der();
let Ok(secret_key_der) = PrivateKeyDer::try_from(keypair_der) else {
return Err(io::Error::other("Failed to deserialize DER TLS secret"))
};
Ok((certificate, secret_key_der))
}
pub struct TlsUpgrade {
/// TLS server configuration
server_config: Arc<ServerConfig>,
@@ -256,30 +258,7 @@ pub struct TlsUpgrade {
impl TlsUpgrade {
pub async fn new() -> io::Result<Self> {
// On each instantiation, generate a new keypair and certificate
let Ok(keypair) = rcgen::KeyPair::generate_for(&rcgen::PKCS_ED25519) else {
return Err(io::Error::other("Failed to generate TLS keypair"))
};
let Ok(mut cert_params) = rcgen::CertificateParams::new(&[]) else {
return Err(io::Error::other("Failed to generate TLS params"))
};
cert_params.subject_alt_names =
vec![rcgen::SanType::DnsName(Ia5String::try_from("dark.fi").unwrap())];
cert_params.extended_key_usages = vec![
rcgen::ExtendedKeyUsagePurpose::ClientAuth,
rcgen::ExtendedKeyUsagePurpose::ServerAuth,
];
let Ok(certificate) = cert_params.self_signed(&keypair) else {
return Err(io::Error::other("Failed to sign TLS certificate"))
};
let certificate = certificate.der();
let keypair_der = keypair.serialize_der();
let Ok(secret_key_der) = PrivateKeyDer::try_from(keypair_der) else {
return Err(io::Error::other("Failed to deserialize DER TLS secret"))
};
let (certificate, secret_key_der) = generate_certificate()?;
// Server-side config
let client_cert_verifier = Arc::new(ClientCertificateVerifier {});
@@ -307,7 +286,7 @@ impl TlsUpgrade {
where
IO: super::PtStream,
{
let server_name = ServerName::try_from("dark.fi").unwrap();
let server_name = ServerName::try_from(TLS_DNS_NAME).unwrap();
let connector = TlsConnector::from(self.client_config);
let stream = connector.connect(server_name, stream).await?;
Ok(TlsStream::Client(stream))

View File

@@ -88,6 +88,38 @@ fn tcp_tls_transport() {
}));
}
#[test]
fn quic_transport() {
let executor = LocalExecutor::new();
smol::block_on(executor.run(async {
let listener = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
let port = listener.local_addr().unwrap().port();
drop(listener);
let url = Url::parse(&format!("quic://127.0.0.1:{port}")).unwrap();
let listener = Listener::new(url.clone(), None).await.unwrap().listen().await.unwrap();
executor
.spawn(async move {
let (stream, _) = listener.next().await.unwrap();
let (mut reader, mut writer) = smol::io::split(stream);
io::copy(&mut reader, &mut writer).await.unwrap();
})
.detach();
let payload = "ohai quic";
let dialer = Dialer::new(url, None, None).await.unwrap();
let mut client = dialer.dial(None).await.unwrap();
payload.encode_async(&mut client).await.unwrap();
let buf: String = AsyncDecodable::decode_async(&mut client).await.unwrap();
assert_eq!(buf, payload);
}));
}
#[test]
fn unix_transport() {
let executor = LocalExecutor::new();