From 0fe7e8b8a2138e64e0d59bff1d846d768d16532a Mon Sep 17 00:00:00 2001 From: Friedel Ziegelmayer Date: Tue, 10 Dec 2024 12:30:44 +0100 Subject: [PATCH] refactor(iroh)!: make iroh::tls private (#3018) ## Description - makes `iroh::tls` private - match quinns tls setup for benchmarking ## Breaking Changes - `iroh::tls` is removed from the public API ## Notes & open questions The goal is to reduce the API surface of `iroh`, to what is really needed. I couldn't find any critical usage of this in our dependencies. ## Change checklist - [x] Self-review. - [x] Documentation updates following the [style guide](https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html#appendix-a-full-conventions-text), if relevant. - [ ] Tests if relevant. - [x] All breaking changes documented. --- .github/workflows/ci.yml | 2 +- .github/workflows/tests.yaml | 2 +- Cargo.lock | 40 +++++----- iroh-net-report/src/defaults.rs | 2 +- iroh/bench/Cargo.toml | 2 +- iroh/bench/src/bin/bulk.rs | 15 +++- iroh/bench/src/iroh.rs | 2 +- iroh/bench/src/lib.rs | 2 +- iroh/bench/src/quinn.rs | 136 +++++++++++++------------------- iroh/src/lib.rs | 2 +- 10 files changed, 91 insertions(+), 114 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dfb4c4e006..57bd5ad3f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -189,7 +189,7 @@ jobs: # uses: obi1kenobi/cargo-semver-checks-action@v2 uses: n0-computer/cargo-semver-checks-action@feat-baseline with: - package: iroh, iroh-base, iroh-dns-server, iroh-net-bench, iroh-relay, iroh-net-report + package: iroh, iroh-base, iroh-dns-server, iroh-bench, iroh-relay, iroh-net-report baseline-rev: ${{ env.HEAD_COMMIT_SHA }} use-cache: false diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 1bacb65108..e159b99a28 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -23,7 +23,7 @@ env: RUSTFLAGS: -Dwarnings RUSTDOCFLAGS: -Dwarnings SCCACHE_CACHE_SIZE: "10G" - CRATES_LIST: "iroh,iroh-net-bench,iroh-test,iroh-dns-server,iroh-relay,iroh-net-report" + CRATES_LIST: "iroh,iroh-bench,iroh-test,iroh-dns-server,iroh-relay,iroh-net-report" IROH_FORCE_STAGING_RELAYS: "1" jobs: diff --git a/Cargo.lock b/Cargo.lock index cc1c930818..57adb256c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2261,6 +2261,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "iroh-bench" +version = "0.29.0" +dependencies = [ + "anyhow", + "bytes", + "clap", + "futures-lite 2.5.0", + "hdrhistogram", + "iroh", + "iroh-metrics", + "iroh-quinn", + "rcgen", + "rustls", + "socket2", + "tokio", + "tracing", + "tracing-subscriber", +] + [[package]] name = "iroh-blake3" version = "1.4.5" @@ -2345,26 +2365,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "iroh-net-bench" -version = "0.29.0" -dependencies = [ - "anyhow", - "bytes", - "clap", - "futures-lite 2.5.0", - "hdrhistogram", - "iroh", - "iroh-metrics", - "iroh-quinn", - "rcgen", - "rustls", - "socket2", - "tokio", - "tracing", - "tracing-subscriber", -] - [[package]] name = "iroh-net-report" version = "0.29.0" diff --git a/iroh-net-report/src/defaults.rs b/iroh-net-report/src/defaults.rs index e40ae1e72a..094697386d 100644 --- a/iroh-net-report/src/defaults.rs +++ b/iroh-net-report/src/defaults.rs @@ -5,7 +5,7 @@ /// The STUN port as defined by [RFC 8489]() pub const DEFAULT_STUN_PORT: u16 = 3478; -/// Contains all timeouts that we use in `iroh-net_report`. +/// Contains all timeouts that we use in `iroh-net-report`. pub(crate) mod timeouts { use std::time::Duration; diff --git a/iroh/bench/Cargo.toml b/iroh/bench/Cargo.toml index afe9a67cf7..b5472b7710 100644 --- a/iroh/bench/Cargo.toml +++ b/iroh/bench/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "iroh-net-bench" +name = "iroh-bench" version = "0.29.0" edition = "2021" license = "MIT OR Apache-2.0" diff --git a/iroh/bench/src/bin/bulk.rs b/iroh/bench/src/bin/bulk.rs index d28215ba93..0380066ff1 100644 --- a/iroh/bench/src/bin/bulk.rs +++ b/iroh/bench/src/bin/bulk.rs @@ -3,8 +3,8 @@ use std::collections::BTreeMap; use anyhow::Result; use clap::Parser; #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] -use iroh_net_bench::quinn; -use iroh_net_bench::{configure_tracing_subscriber, iroh, rt, s2n, Commands, Opt}; +use iroh_bench::quinn; +use iroh_bench::{configure_tracing_subscriber, iroh, rt, s2n, Commands, Opt}; fn main() { let cmd = Commands::parse(); @@ -135,11 +135,17 @@ pub fn run_iroh(opt: Opt) -> Result<()> { #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] pub fn run_quinn(opt: Opt) -> Result<()> { + use rustls::pki_types::{CertificateDer, PrivatePkcs8KeyDer}; + let server_span = tracing::error_span!("server"); let runtime = rt(); + let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap(); + let key = PrivatePkcs8KeyDer::from(cert.key_pair.serialize_der()); + let cert = CertificateDer::from(cert.cert); + let (server_addr, endpoint) = { let _guard = server_span.enter(); - quinn::server_endpoint(&runtime, &opt) + quinn::server_endpoint(&runtime, cert.clone(), key.into(), &opt) }; let server_thread = std::thread::spawn(move || { @@ -151,10 +157,11 @@ pub fn run_quinn(opt: Opt) -> Result<()> { let mut handles = Vec::new(); for id in 0..opt.clients { + let cert = cert.clone(); handles.push(std::thread::spawn(move || { let _guard = tracing::error_span!("client", id).entered(); let runtime = rt(); - match runtime.block_on(quinn::client(server_addr, opt)) { + match runtime.block_on(quinn::client(server_addr, cert, opt)) { Ok(stats) => Ok(stats), Err(e) => { eprintln!("client failed: {e:#}"); diff --git a/iroh/bench/src/iroh.rs b/iroh/bench/src/iroh.rs index 063a59bd63..1a533e73a2 100644 --- a/iroh/bench/src/iroh.rs +++ b/iroh/bench/src/iroh.rs @@ -16,7 +16,7 @@ use crate::{ client_handler, stats::TransferResult, ClientStats, ConnectionSelector, EndpointSelector, Opt, }; -pub const ALPN: &[u8] = b"n0/iroh-net-bench/0"; +pub const ALPN: &[u8] = b"n0/iroh-bench/0"; /// Creates a server endpoint which runs on the given runtime pub fn server_endpoint( diff --git a/iroh/bench/src/lib.rs b/iroh/bench/src/lib.rs index 9de2f0ac72..0a1e7b66b5 100644 --- a/iroh/bench/src/lib.rs +++ b/iroh/bench/src/lib.rs @@ -21,7 +21,7 @@ pub mod s2n; pub mod stats; #[derive(Parser, Debug, Clone, Copy)] -#[clap(name = "iroh-net-bench")] +#[clap(name = "iroh-bench")] pub enum Commands { Iroh(Opt), #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd")))] diff --git a/iroh/bench/src/quinn.rs b/iroh/bench/src/quinn.rs index 8fdca46069..21028c44c8 100644 --- a/iroh/bench/src/quinn.rs +++ b/iroh/bench/src/quinn.rs @@ -1,55 +1,57 @@ use std::{ - net::SocketAddr, + net::{IpAddr, Ipv4Addr, SocketAddr}, sync::Arc, time::{Duration, Instant}, }; use anyhow::{Context, Result}; use bytes::Bytes; -use quinn::{Connection, Endpoint, RecvStream, SendStream, TokioRuntime, TransportConfig}; -use socket2::{Domain, Protocol, Socket, Type}; +use quinn::{ + crypto::rustls::QuicClientConfig, Connection, Endpoint, RecvStream, SendStream, TransportConfig, +}; +use rustls::{ + pki_types::{CertificateDer, PrivateKeyDer}, + RootCertStore, +}; use tracing::{trace, warn}; use crate::{ client_handler, stats::TransferResult, ClientStats, ConnectionSelector, EndpointSelector, Opt, }; -/// Derived from the iroh udp SOCKET_BUFFER_SIZE -const SOCKET_BUFFER_SIZE: usize = 7 << 20; pub const ALPN: &[u8] = b"n0/quinn-bench/0"; /// Creates a server endpoint which runs on the given runtime -pub fn server_endpoint(rt: &tokio::runtime::Runtime, opt: &Opt) -> (SocketAddr, quinn::Endpoint) { - let secret_key = iroh::key::SecretKey::generate(); - let crypto = iroh::tls::make_server_config(&secret_key, vec![ALPN.to_vec()], false).unwrap(); - - let transport = transport_config(opt.max_streams, opt.initial_mtu); - - let mut server_config = quinn::ServerConfig::with_crypto(Arc::new(crypto)); - server_config.transport_config(Arc::new(transport)); - - let addr = SocketAddr::new("127.0.0.1".parse().unwrap(), 0); - - let socket = bind_socket(addr).unwrap(); - - let _guard = rt.enter(); - rt.block_on(async move { - let ep = quinn::Endpoint::new( - Default::default(), - Some(server_config), - socket, - Arc::new(TokioRuntime), +pub fn server_endpoint( + rt: &tokio::runtime::Runtime, + cert: CertificateDer<'static>, + key: PrivateKeyDer<'static>, + opt: &Opt, +) -> (SocketAddr, quinn::Endpoint) { + let cert_chain = vec![cert]; + let mut server_config = quinn::ServerConfig::with_single_cert(cert_chain, key).unwrap(); + server_config.transport = Arc::new(transport_config(opt.max_streams, opt.initial_mtu)); + + let endpoint = { + let _guard = rt.enter(); + quinn::Endpoint::server( + server_config, + SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0), ) - .unwrap(); - let addr = ep.local_addr().unwrap(); - (addr, ep) - }) + .unwrap() + }; + let server_addr = endpoint.local_addr().unwrap(); + (server_addr, endpoint) } /// Create and run a client -pub async fn client(server_addr: SocketAddr, opt: Opt) -> Result { +pub async fn client( + server_addr: SocketAddr, + server_cert: CertificateDer<'static>, + opt: Opt, +) -> Result { let client_start = std::time::Instant::now(); - let (endpoint, connection) = connect_client(server_addr, opt).await?; + let (endpoint, connection) = connect_client(server_addr, server_cert, opt).await?; let client_connect_time = client_start.elapsed(); let mut res = client_handler( EndpointSelector::Quinn(endpoint), @@ -64,29 +66,34 @@ pub async fn client(server_addr: SocketAddr, opt: Opt) -> Result { /// Create a client endpoint and client connection pub async fn connect_client( server_addr: SocketAddr, + server_cert: CertificateDer<'_>, opt: Opt, ) -> Result<(::quinn::Endpoint, Connection)> { - let secret_key = iroh::key::SecretKey::generate(); - let quic_client_config = - iroh::tls::make_client_config(&secret_key, None, vec![ALPN.to_vec()], false)?; - let mut config = quinn::ClientConfig::new(Arc::new(quic_client_config)); + let endpoint = + quinn::Endpoint::client(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0)).unwrap(); - let transport = transport_config(opt.max_streams, opt.initial_mtu); + let mut roots = RootCertStore::empty(); + roots.add(server_cert)?; - // let mut config = quinn::ClientConfig::new(Arc::new(crypto)); - config.transport_config(Arc::new(transport)); + let provider = rustls::crypto::ring::default_provider(); - let addr = SocketAddr::new("127.0.0.1".parse().unwrap(), 0); + let crypto = rustls::ClientConfig::builder_with_provider(provider.into()) + .with_protocol_versions(&[&rustls::version::TLS13]) + .unwrap() + .with_root_certificates(roots) + .with_no_client_auth(); - let socket = bind_socket(addr).unwrap(); + let mut client_config = quinn::ClientConfig::new(Arc::new(QuicClientConfig::try_from(crypto)?)); + client_config.transport_config(Arc::new(transport_config(opt.max_streams, opt.initial_mtu))); - let ep = - quinn::Endpoint::new(Default::default(), None, socket, Arc::new(TokioRuntime)).unwrap(); - let connection = ep - .connect_with(config, server_addr, "local")? + let connection = endpoint + .connect_with(client_config, server_addr, "localhost") + .unwrap() .await - .context("connecting")?; - Ok((ep, connection)) + .context("unable to connect")?; + trace!("connected"); + + Ok((endpoint, connection)) } pub fn transport_config(max_streams: usize, initial_mtu: u16) -> TransportConfig { @@ -104,43 +111,6 @@ pub fn transport_config(max_streams: usize, initial_mtu: u16) -> TransportConfig config } -fn bind_socket(addr: SocketAddr) -> Result { - let socket = Socket::new(Domain::for_address(addr), Type::DGRAM, Some(Protocol::UDP)) - .context("create socket")?; - - if addr.is_ipv6() { - socket.set_only_v6(false).context("set_only_v6")?; - } - - socket - .bind(&socket2::SockAddr::from(addr)) - .context("binding endpoint")?; - socket - .set_send_buffer_size(SOCKET_BUFFER_SIZE) - .context("send buffer size")?; - socket - .set_recv_buffer_size(SOCKET_BUFFER_SIZE) - .context("recv buffer size")?; - - let buf_size = socket.send_buffer_size().context("send buffer size")?; - if buf_size < SOCKET_BUFFER_SIZE { - warn!( - "Unable to set desired send buffer size. Desired: {}, Actual: {}", - SOCKET_BUFFER_SIZE, buf_size - ); - } - - let buf_size = socket.recv_buffer_size().context("recv buffer size")?; - if buf_size < SOCKET_BUFFER_SIZE { - warn!( - "Unable to set desired recv buffer size. Desired: {}, Actual: {}", - SOCKET_BUFFER_SIZE, buf_size - ); - } - - Ok(socket.into()) -} - async fn drain_stream( stream: &mut RecvStream, read_unordered: bool, diff --git a/iroh/src/lib.rs b/iroh/src/lib.rs index f99f4db99f..c76e4e82ac 100644 --- a/iroh/src/lib.rs +++ b/iroh/src/lib.rs @@ -241,7 +241,7 @@ pub mod endpoint; mod magicsock; pub mod metrics; pub mod protocol; -pub mod tls; +mod tls; pub(crate) mod util;