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

Add interface binding to QUIC link #1652

Merged
merged 4 commits into from
Dec 11, 2024
Merged
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
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
Loading