Skip to content

Commit

Permalink
Add interface binding to QUIC link (#1652)
Browse files Browse the repository at this point in the history
* Add interface binding for QUIC listener

* Add interface binding for QUIC link

* Add TLS and QUIC interface binding tests

* Fix incorrect port number in test
  • Loading branch information
oteffahi authored Dec 11, 2024
1 parent 83bc4ed commit 911382d
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 161 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions io/zenoh-links/zenoh-link-quic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ zenoh-core = { workspace = true }
zenoh-link-commons = { workspace = true, features = ["tls"] }
zenoh-protocol = { workspace = true }
zenoh-result = { workspace = true }
zenoh-util = { workspace = true }

[package.metadata.cargo-machete]
ignored = ["rustls-webpki"]
59 changes: 52 additions & 7 deletions io/zenoh-links/zenoh-link-quic/src/unicast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ use std::{
};

use async_trait::async_trait;
use quinn::crypto::rustls::{QuicClientConfig, QuicServerConfig};
use quinn::{
crypto::rustls::{QuicClientConfig, QuicServerConfig},
EndpointConfig,
};
use time::OffsetDateTime;
use tokio::sync::Mutex as AsyncMutex;
use tokio_util::sync::CancellationToken;
Expand Down Expand Up @@ -270,8 +273,30 @@ impl LinkManagerUnicastTrait for LinkManagerUnicastQuic {
} else {
Ipv6Addr::UNSPECIFIED.into()
};
let mut quic_endpoint = quinn::Endpoint::client(SocketAddr::new(ip_addr, 0))
.map_err(|e| zerror!("Can not create a new QUIC link bound to {}: {}", host, e))?;

// Initialize the Endpoint
let mut quic_endpoint = if let Some(iface) = client_crypto.bind_iface {
async {
// Bind the UDP socket
let socket = tokio::net::UdpSocket::bind(SocketAddr::new(ip_addr, 0)).await?;
zenoh_util::net::set_bind_to_device_udp_socket(&socket, iface)?;

// create the Endpoint with this socket
let runtime = quinn::default_runtime().ok_or_else(|| {
std::io::Error::new(std::io::ErrorKind::Other, "no async runtime found")
})?;
ZResult::Ok(quinn::Endpoint::new_with_abstract_socket(
EndpointConfig::default(),
None,
runtime.wrap_udp_socket(socket.into_std()?)?,
runtime,
)?)
}
.await
} else {
quinn::Endpoint::client(SocketAddr::new(ip_addr, 0)).map_err(Into::into)
}
.map_err(|e| zerror!("Can not create a new QUIC link bound to {host}: {e}"))?;

let quic_config: QuicClientConfig = client_crypto
.client_config
Expand Down Expand Up @@ -324,7 +349,7 @@ impl LinkManagerUnicastTrait for LinkManagerUnicastQuic {
Ok(LinkUnicast(link))
}

async fn new_listener(&self, mut endpoint: EndPoint) -> ZResult<Locator> {
async fn new_listener(&self, endpoint: EndPoint) -> ZResult<Locator> {
let epaddr = endpoint.address();
let epconf = endpoint.config();

Expand Down Expand Up @@ -367,15 +392,35 @@ impl LinkManagerUnicastTrait for LinkManagerUnicastQuic {
.max_concurrent_bidi_streams(1_u8.into());

// Initialize the Endpoint
let quic_endpoint = quinn::Endpoint::server(server_config, addr)
.map_err(|e| zerror!("Can not create a new QUIC listener on {}: {}", addr, e))?;
let quic_endpoint = if let Some(iface) = server_crypto.bind_iface {
async {
// Bind the UDP socket
let socket = tokio::net::UdpSocket::bind(addr).await?;
zenoh_util::net::set_bind_to_device_udp_socket(&socket, iface)?;

// create the Endpoint with this socket
let runtime = quinn::default_runtime().ok_or_else(|| {
std::io::Error::new(std::io::ErrorKind::Other, "no async runtime found")
})?;
ZResult::Ok(quinn::Endpoint::new_with_abstract_socket(
EndpointConfig::default(),
Some(server_config),
runtime.wrap_udp_socket(socket.into_std()?)?,
runtime,
)?)
}
.await
} else {
quinn::Endpoint::server(server_config, addr).map_err(Into::into)
}
.map_err(|e| zerror!("Can not create a new QUIC listener on {}: {}", addr, e))?;

let local_addr = quic_endpoint
.local_addr()
.map_err(|e| zerror!("Can not create a new QUIC listener on {}: {}", addr, e))?;

// Update the endpoint locator address
endpoint = EndPoint::new(
let endpoint = EndPoint::new(
endpoint.protocol(),
local_addr.to_string(),
endpoint.metadata(),
Expand Down
20 changes: 13 additions & 7 deletions io/zenoh-links/zenoh-link-quic/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ use rustls::{
use secrecy::ExposeSecret;
use webpki::anchor_from_trusted_cert;
use zenoh_config::Config as ZenohConfig;
use zenoh_link_commons::{tls::WebPkiVerifierAnyServerName, ConfigurationInspector};
use zenoh_link_commons::{
tls::WebPkiVerifierAnyServerName, ConfigurationInspector, BIND_INTERFACE,
};
use zenoh_protocol::core::{
endpoint::{Address, Config},
parameters,
Expand Down Expand Up @@ -151,13 +153,14 @@ impl ConfigurationInspector<ZenohConfig> for TlsConfigurator {
}
}

pub(crate) struct TlsServerConfig {
pub(crate) struct TlsServerConfig<'a> {
pub(crate) server_config: ServerConfig,
pub(crate) tls_close_link_on_expiration: bool,
pub(crate) bind_iface: Option<&'a str>,
}

impl TlsServerConfig {
pub async fn new(config: &Config<'_>) -> ZResult<TlsServerConfig> {
impl<'a> TlsServerConfig<'a> {
pub async fn new(config: &'a Config<'_>) -> ZResult<Self> {
let tls_server_client_auth: bool = match config.get(TLS_ENABLE_MTLS) {
Some(s) => s
.parse()
Expand Down Expand Up @@ -231,6 +234,7 @@ impl TlsServerConfig {
Ok(TlsServerConfig {
server_config: sc,
tls_close_link_on_expiration,
bind_iface: config.get(BIND_INTERFACE),
})
}

Expand All @@ -255,13 +259,14 @@ impl TlsServerConfig {
}
}

pub(crate) struct TlsClientConfig {
pub(crate) struct TlsClientConfig<'a> {
pub(crate) client_config: ClientConfig,
pub(crate) tls_close_link_on_expiration: bool,
pub(crate) bind_iface: Option<&'a str>,
}

impl TlsClientConfig {
pub async fn new(config: &Config<'_>) -> ZResult<TlsClientConfig> {
impl<'a> TlsClientConfig<'a> {
pub async fn new(config: &'a Config<'_>) -> ZResult<Self> {
let tls_client_server_auth: bool = match config.get(TLS_ENABLE_MTLS) {
Some(s) => s
.parse()
Expand Down Expand Up @@ -375,6 +380,7 @@ impl TlsClientConfig {
Ok(TlsClientConfig {
client_config: cc,
tls_close_link_on_expiration,
bind_iface: config.get(BIND_INTERFACE),
})
}

Expand Down
Loading

0 comments on commit 911382d

Please sign in to comment.