From 84ec1e8973f29f49e98e416bb34929edc37928ff Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Thu, 17 Oct 2024 11:23:51 +0900 Subject: [PATCH 01/16] chore: deps --- rpxy-acme/Cargo.toml | 2 +- rpxy-certs/Cargo.toml | 2 +- rpxy-lib/Cargo.toml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rpxy-acme/Cargo.toml b/rpxy-acme/Cargo.toml index 5cb3dcf2..c2504d34 100644 --- a/rpxy-acme/Cargo.toml +++ b/rpxy-acme/Cargo.toml @@ -21,7 +21,7 @@ aws-lc-rs = { version = "1.10.0", default-features = false, features = [ "aws-lc-sys", ] } blocking = "1.6.1" -rustls = { version = "0.23.14", default-features = false, features = [ +rustls = { version = "0.23.15", default-features = false, features = [ "std", "aws_lc_rs", ] } diff --git a/rpxy-certs/Cargo.toml b/rpxy-certs/Cargo.toml index 94b191f1..a36a2f0e 100644 --- a/rpxy-certs/Cargo.toml +++ b/rpxy-certs/Cargo.toml @@ -21,7 +21,7 @@ derive_builder = { version = "0.20.2" } thiserror = { version = "1.0.64" } hot_reload = { version = "0.1.6" } async-trait = { version = "0.1.83" } -rustls = { version = "0.23.14", default-features = false, features = [ +rustls = { version = "0.23.15", default-features = false, features = [ "std", "aws_lc_rs", ] } diff --git a/rpxy-lib/Cargo.toml b/rpxy-lib/Cargo.toml index d3a9a266..40ceb34f 100644 --- a/rpxy-lib/Cargo.toml +++ b/rpxy-lib/Cargo.toml @@ -54,7 +54,7 @@ thiserror = "1.0.64" # http for both server and client http = "1.1.0" http-body-util = "0.1.2" -hyper = { version = "1.4.1", default-features = false } +hyper = { version = "1.5.0", default-features = false } hyper-util = { version = "0.1.9", features = ["full"] } futures-util = { version = "0.3.31", default-features = false } futures-channel = { version = "0.3.31", default-features = false } @@ -74,7 +74,7 @@ hyper-rustls = { version = "0.27.3", default-features = false, features = [ # tls and cert management for server rpxy-certs = { path = "../rpxy-certs/", default-features = false } hot_reload = "0.1.6" -rustls = { version = "0.23.14", default-features = false } +rustls = { version = "0.23.15", default-features = false } tokio-rustls = { version = "0.26.0", features = ["early-data"] } # acme From 851cd58231730baa1b36ca211880db0465c0a296 Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Thu, 24 Oct 2024 21:29:14 +0900 Subject: [PATCH 02/16] feat: check unsupported configuration entries with serde-ignored --- rpxy-bin/Cargo.toml | 1 + rpxy-bin/src/config/toml.rs | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/rpxy-bin/Cargo.toml b/rpxy-bin/Cargo.toml index 85e2f44e..a45fd592 100644 --- a/rpxy-bin/Cargo.toml +++ b/rpxy-bin/Cargo.toml @@ -47,6 +47,7 @@ futures-util = { version = "0.3.31", default-features = false } clap = { version = "4.5.20", features = ["std", "cargo", "wrap_help"] } toml = { version = "0.8.19", default-features = false, features = ["parse"] } hot_reload = "0.1.6" +serde_ignored = "0.1.10" # logging tracing = { version = "0.1.40" } diff --git a/rpxy-bin/src/config/toml.rs b/rpxy-bin/src/config/toml.rs index 9befc196..639f927e 100644 --- a/rpxy-bin/src/config/toml.rs +++ b/rpxy-bin/src/config/toml.rs @@ -1,6 +1,7 @@ use crate::{ constants::*, error::{anyhow, ensure}, + log::warn, }; use rpxy_lib::{reexports::Uri, AppConfig, ProxyConfig, ReverseProxyConfig, TlsConfig, UpstreamUri}; use rustc_hash::FxHashMap as HashMap; @@ -229,7 +230,21 @@ impl ConfigToml { pub fn new(config_file: &str) -> std::result::Result { let config_str = fs::read_to_string(config_file)?; - toml::from_str(&config_str).map_err(|e| anyhow!(e)) + // Check unused fields during deserialization + let t = toml::de::Deserializer::new(&config_str); + let mut unused = rustc_hash::FxHashSet::default(); + + let res = serde_ignored::deserialize(t, |path| { + unused.insert(path.to_string()); + }) + .map_err(|e| anyhow!(e)); + + if !unused.is_empty() { + let str = unused.iter().fold(String::new(), |acc, x| acc + x + "\n"); + warn!("Configuration file contains unsupported fields. Check typos:\n{}", str); + } + + res } } From ddfaad099c88dc682beb8b2d80fd24df2b0ef02b Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Thu, 24 Oct 2024 21:34:04 +0900 Subject: [PATCH 03/16] chore: deps chore: deps --- rpxy-acme/Cargo.toml | 4 ++-- rpxy-bin/Cargo.toml | 6 +++--- rpxy-certs/Cargo.toml | 4 ++-- rpxy-lib/Cargo.toml | 16 ++++++++-------- submodules/s2n-quic-h3/Cargo.toml | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/rpxy-acme/Cargo.toml b/rpxy-acme/Cargo.toml index c2504d34..ef46ffaf 100644 --- a/rpxy-acme/Cargo.toml +++ b/rpxy-acme/Cargo.toml @@ -13,7 +13,7 @@ publish.workspace = true [dependencies] url = { version = "2.5.2" } rustc-hash = "2.0.0" -thiserror = "1.0.64" +thiserror = "1.0.65" tracing = "0.1.40" async-trait = "0.1.83" base64 = "0.22.1" @@ -29,6 +29,6 @@ rustls-platform-verifier = { version = "0.3.4" } rustls-acme = { path = "../submodules/rustls-acme/", default-features = false, features = [ "aws-lc-rs", ] } -tokio = { version = "1.40.0", default-features = false } +tokio = { version = "1.41.0", default-features = false } tokio-util = { version = "0.7.12", default-features = false } tokio-stream = { version = "0.1.16", default-features = false } diff --git a/rpxy-bin/Cargo.toml b/rpxy-bin/Cargo.toml index a45fd592..96c552c0 100644 --- a/rpxy-bin/Cargo.toml +++ b/rpxy-bin/Cargo.toml @@ -29,10 +29,10 @@ rpxy-lib = { path = "../rpxy-lib/", default-features = false, features = [ ] } mimalloc = { version = "*", default-features = false } -anyhow = "1.0.89" +anyhow = "1.0.91" rustc-hash = "2.0.0" -serde = { version = "1.0.210", default-features = false, features = ["derive"] } -tokio = { version = "1.40.0", default-features = false, features = [ +serde = { version = "1.0.213", default-features = false, features = ["derive"] } +tokio = { version = "1.41.0", default-features = false, features = [ "net", "rt-multi-thread", "time", diff --git a/rpxy-certs/Cargo.toml b/rpxy-certs/Cargo.toml index a36a2f0e..b96e2512 100644 --- a/rpxy-certs/Cargo.toml +++ b/rpxy-certs/Cargo.toml @@ -18,7 +18,7 @@ http3 = [] rustc-hash = { version = "2.0.0" } tracing = { version = "0.1.40" } derive_builder = { version = "0.20.2" } -thiserror = { version = "1.0.64" } +thiserror = { version = "1.0.65" } hot_reload = { version = "0.1.6" } async-trait = { version = "0.1.83" } rustls = { version = "0.23.15", default-features = false, features = [ @@ -33,7 +33,7 @@ rustls-webpki = { version = "0.102.8", default-features = false, features = [ x509-parser = { version = "0.16.0" } [dev-dependencies] -tokio = { version = "1.40.0", default-features = false, features = [ +tokio = { version = "1.41.0", default-features = false, features = [ "rt-multi-thread", "macros", ] } diff --git a/rpxy-lib/Cargo.toml b/rpxy-lib/Cargo.toml index 40ceb34f..e50dc2a7 100644 --- a/rpxy-lib/Cargo.toml +++ b/rpxy-lib/Cargo.toml @@ -32,10 +32,10 @@ acme = ["dep:rpxy-acme"] [dependencies] rand = "0.8.5" rustc-hash = "2.0.0" -bytes = "1.7.2" +bytes = "1.8.0" derive_builder = "0.20.2" futures = { version = "0.3.31", features = ["alloc", "async-await"] } -tokio = { version = "1.40.0", default-features = false, features = [ +tokio = { version = "1.41.0", default-features = false, features = [ "net", "rt-multi-thread", "time", @@ -44,12 +44,12 @@ tokio = { version = "1.40.0", default-features = false, features = [ "fs", ] } tokio-util = { version = "0.7.12", default-features = false } -pin-project-lite = "0.2.14" +pin-project-lite = "0.2.15" async-trait = "0.1.83" # Error handling -anyhow = "1.0.89" -thiserror = "1.0.64" +anyhow = "1.0.91" +thiserror = "1.0.65" # http for both server and client http = "1.1.0" @@ -90,11 +90,11 @@ h3-quinn = { version = "0.0.7", optional = true } s2n-quic-h3 = { path = "../submodules/s2n-quic-h3/", features = [ "tracing", ], optional = true } -s2n-quic = { version = "1.47.0", default-features = false, features = [ +s2n-quic = { version = "1.48.0", default-features = false, features = [ "provider-tls-rustls", ], optional = true } -s2n-quic-core = { version = "0.47.0", default-features = false, optional = true } -s2n-quic-rustls = { version = "0.47.0", optional = true } +s2n-quic-core = { version = "0.48.0", default-features = false, optional = true } +s2n-quic-rustls = { version = "0.48.0", optional = true } ########## # for UDP socket wit SO_REUSEADDR when h3 with quinn socket2 = { version = "0.5.7", features = ["all"], optional = true } diff --git a/submodules/s2n-quic-h3/Cargo.toml b/submodules/s2n-quic-h3/Cargo.toml index a2e1a839..8d53fc10 100644 --- a/submodules/s2n-quic-h3/Cargo.toml +++ b/submodules/s2n-quic-h3/Cargo.toml @@ -16,7 +16,7 @@ h3 = { version = "0.0.6", features = ["tracing"] } # s2n-quic = { path = "../s2n-quic" } # s2n-quic-core = { path = "../s2n-quic-core" } s2n-quic = { version = "1.47.0" } -s2n-quic-core = { version = "0.47.0" } +s2n-quic-core = { version = "0.48.0" } tracing = { version = "0.1.40", optional = true } [features] From a50b8a4c2aed4bae2156ed18c597435637d5fbbf Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Thu, 24 Oct 2024 21:44:00 +0900 Subject: [PATCH 04/16] [skip ci] update changelog --- CHANGELOG.md | 10 +++++++++- Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02077ff0..74a82d0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # CHANGELOG -## 0.10.0 (Unreleased) +## 0.9.3 or 0.10.0 (Unreleased) + +### Improvement + +- Feat: emit WARN messages if there exist unused and unsupported options specified in configuration file. +- Docs: `rpxy.io` is now available for the official website of `rpxy`. +- Refactor: lots of minor improvements +- Deps + ## 0.9.2 diff --git a/Cargo.toml b/Cargo.toml index 522bd41d..ce788714 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace.package] -version = "0.9.2" +version = "0.9.3" authors = ["Jun Kurihara"] homepage = "https://github.com/junkurihara/rust-rpxy" repository = "https://github.com/junkurihara/rust-rpxy" From beedf5f10f3ac998c1cc590184707bcd70effdc8 Mon Sep 17 00:00:00 2001 From: Jonas Berlin Date: Sat, 26 Oct 2024 14:56:11 +0300 Subject: [PATCH 05/16] Update config-example.toml to explain Alt-SVC header #192 forgot to update the example configuration file --- config-example.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config-example.toml b/config-example.toml index b0a19458..a6a215e7 100644 --- a/config-example.toml +++ b/config-example.toml @@ -11,8 +11,8 @@ listen_port = 8080 listen_port_tls = 8443 # Optional. If you listen on a custom port like 8443 but redirect with firewall to 443 -# When you specify this, the server sends a redirection response 301 with specified port to the client for plaintext http request. -# Otherwise, the server sends 301 with the same port as `listen_port_tls`. +# When you specify this, the server uses this port in an "Alt-SVC" header for e.g. indicating support for HTTP/3 and also sends a redirection response 301 with specified port to the client for plaintext http request +# Otherwise, the server sends Alt-SVC and 301 with the same port as `listen_port_tls`. # https_redirection_port = 443 # Optional for h2 and http1.1 From 3eaa7041f2f1a542c469d178e2b086c62f17adc9 Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Mon, 28 Oct 2024 18:51:26 +0900 Subject: [PATCH 06/16] add rustfmt.toml --- .rustfmt.toml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .rustfmt.toml diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 00000000..ce003c85 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,4 @@ +edition = "2021" +newline_style = "Unix" +tab_spaces = 2 +max_width = 130 From a8877500758f4936ff8a90075b28ff1d9ed8d8e7 Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Thu, 31 Oct 2024 18:21:04 +0900 Subject: [PATCH 07/16] feat: initial support for X25519Kyber768Draft00 PQC --- rpxy-acme/Cargo.toml | 6 +++++- rpxy-acme/src/manager.rs | 3 +++ rpxy-bin/Cargo.toml | 7 +++++-- rpxy-certs/Cargo.toml | 4 +++- rpxy-certs/src/lib.rs | 7 +++++-- rpxy-certs/src/server_crypto.rs | 3 +++ rpxy-lib/Cargo.toml | 10 ++++++++-- rpxy-lib/src/lib.rs | 7 +++++-- 8 files changed, 37 insertions(+), 10 deletions(-) diff --git a/rpxy-acme/Cargo.toml b/rpxy-acme/Cargo.toml index ef46ffaf..80fe15c6 100644 --- a/rpxy-acme/Cargo.toml +++ b/rpxy-acme/Cargo.toml @@ -10,6 +10,9 @@ readme.workspace = true edition.workspace = true publish.workspace = true +[features] +post-quantum = ["rustls-post-quantum"] + [dependencies] url = { version = "2.5.2" } rustc-hash = "2.0.0" @@ -21,7 +24,7 @@ aws-lc-rs = { version = "1.10.0", default-features = false, features = [ "aws-lc-sys", ] } blocking = "1.6.1" -rustls = { version = "0.23.15", default-features = false, features = [ +rustls = { version = "0.23.16", default-features = false, features = [ "std", "aws_lc_rs", ] } @@ -29,6 +32,7 @@ rustls-platform-verifier = { version = "0.3.4" } rustls-acme = { path = "../submodules/rustls-acme/", default-features = false, features = [ "aws-lc-rs", ] } +rustls-post-quantum = { version = "0.1.0", optional = true } tokio = { version = "1.41.0", default-features = false } tokio-util = { version = "0.7.12", default-features = false } tokio-stream = { version = "0.1.16", default-features = false } diff --git a/rpxy-acme/src/manager.rs b/rpxy-acme/src/manager.rs index fe10c851..1fe6f9e3 100644 --- a/rpxy-acme/src/manager.rs +++ b/rpxy-acme/src/manager.rs @@ -37,8 +37,11 @@ impl AcmeManager { domains: &[String], runtime_handle: Handle, ) -> Result { + #[cfg(not(feature = "post-quantum"))] // Install aws_lc_rs as default crypto provider for rustls let _ = rustls::crypto::CryptoProvider::install_default(rustls::crypto::aws_lc_rs::default_provider()); + #[cfg(feature = "post-quantum")] + let _ = rustls::crypto::CryptoProvider::install_default(rustls_post_quantum::provider()); let acme_registry_dir = acme_registry_dir .map(|v| v.to_ascii_lowercase()) diff --git a/rpxy-bin/Cargo.toml b/rpxy-bin/Cargo.toml index 96c552c0..d83213d7 100644 --- a/rpxy-bin/Cargo.toml +++ b/rpxy-bin/Cargo.toml @@ -13,7 +13,9 @@ publish.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["http3-quinn", "cache", "rustls-backend", "acme"] +default = ["http3-quinn", "cache", "rustls-backend", "acme", "post-quantum"] +# default = ["http3-s2n", "cache", "rustls-backend", "acme", "post-quantum"] +# default = ["http3-quinn", "cache", "rustls-backend", "acme"] # default = ["http3-s2n", "cache", "rustls-backend", "acme"] http3-quinn = ["rpxy-lib/http3-quinn"] http3-s2n = ["rpxy-lib/http3-s2n"] @@ -22,6 +24,7 @@ rustls-backend = ["rpxy-lib/rustls-backend"] webpki-roots = ["rpxy-lib/webpki-roots"] cache = ["rpxy-lib/cache"] acme = ["rpxy-lib/acme", "rpxy-acme"] +post-quantum = ["rpxy-lib/post-quantum"] [dependencies] rpxy-lib = { path = "../rpxy-lib/", default-features = false, features = [ @@ -31,7 +34,7 @@ rpxy-lib = { path = "../rpxy-lib/", default-features = false, features = [ mimalloc = { version = "*", default-features = false } anyhow = "1.0.91" rustc-hash = "2.0.0" -serde = { version = "1.0.213", default-features = false, features = ["derive"] } +serde = { version = "1.0.214", default-features = false, features = ["derive"] } tokio = { version = "1.41.0", default-features = false, features = [ "net", "rt-multi-thread", diff --git a/rpxy-certs/Cargo.toml b/rpxy-certs/Cargo.toml index b96e2512..8d9560e6 100644 --- a/rpxy-certs/Cargo.toml +++ b/rpxy-certs/Cargo.toml @@ -12,6 +12,7 @@ publish.workspace = true [features] default = ["http3"] +post-quantum = ["rustls-post-quantum"] http3 = [] [dependencies] @@ -21,7 +22,7 @@ derive_builder = { version = "0.20.2" } thiserror = { version = "1.0.65" } hot_reload = { version = "0.1.6" } async-trait = { version = "0.1.83" } -rustls = { version = "0.23.15", default-features = false, features = [ +rustls = { version = "0.23.16", default-features = false, features = [ "std", "aws_lc_rs", ] } @@ -30,6 +31,7 @@ rustls-webpki = { version = "0.102.8", default-features = false, features = [ "std", "aws_lc_rs", ] } +rustls-post-quantum = { version = "0.1.0", optional = true } x509-parser = { version = "0.16.0" } [dev-dependencies] diff --git a/rpxy-certs/src/lib.rs b/rpxy-certs/src/lib.rs index 6a262f04..43994a11 100644 --- a/rpxy-certs/src/lib.rs +++ b/rpxy-certs/src/lib.rs @@ -12,7 +12,7 @@ mod log { use crate::{error::*, log::*, reloader_service::DynCryptoSource}; use hot_reload::{ReloaderReceiver, ReloaderService}; use rustc_hash::FxHashMap as HashMap; -use rustls::crypto::{aws_lc_rs, CryptoProvider}; +use rustls::crypto::CryptoProvider; use std::sync::Arc; /* ------------------------------------------------ */ @@ -44,8 +44,11 @@ where T: CryptoSource + Send + Sync + Clone + 'static, { info!("Building certificate reloader service"); + #[cfg(not(feature = "post-quantum"))] // Install aws_lc_rs as default crypto provider for rustls - let _ = CryptoProvider::install_default(aws_lc_rs::default_provider()); + let _ = CryptoProvider::install_default(rustls::crypto::aws_lc_rs::default_provider()); + #[cfg(feature = "post-quantum")] + let _ = CryptoProvider::install_default(rustls_post_quantum::provider()); let source = crypto_source_map .iter() diff --git a/rpxy-certs/src/server_crypto.rs b/rpxy-certs/src/server_crypto.rs index 60ffcba9..71426c8a 100644 --- a/rpxy-certs/src/server_crypto.rs +++ b/rpxy-certs/src/server_crypto.rs @@ -179,7 +179,10 @@ mod tests { #[tokio::test] async fn test_server_crypto_base_try_into() { + #[cfg(not(feature = "post-quantum"))] let _ = CryptoProvider::install_default(rustls::crypto::aws_lc_rs::default_provider()); + #[cfg(feature = "post-quantum")] + let _ = CryptoProvider::install_default(rustls_post_quantum::provider()); let mut server_crypto_base = ServerCryptoBase::default(); diff --git a/rpxy-lib/Cargo.toml b/rpxy-lib/Cargo.toml index e50dc2a7..33eb1354 100644 --- a/rpxy-lib/Cargo.toml +++ b/rpxy-lib/Cargo.toml @@ -28,6 +28,11 @@ native-tls-backend = ["hyper-tls"] rustls-backend = ["hyper-rustls"] webpki-roots = ["rustls-backend", "hyper-rustls/webpki-tokio"] acme = ["dep:rpxy-acme"] +post-quantum = [ + "rustls-post-quantum", + "rpxy-acme/post-quantum", + "rpxy-certs/post-quantum", +] [dependencies] rand = "0.8.5" @@ -55,7 +60,7 @@ thiserror = "1.0.65" http = "1.1.0" http-body-util = "0.1.2" hyper = { version = "1.5.0", default-features = false } -hyper-util = { version = "0.1.9", features = ["full"] } +hyper-util = { version = "0.1.10", features = ["full"] } futures-util = { version = "0.3.31", default-features = false } futures-channel = { version = "0.3.31", default-features = false } @@ -74,7 +79,8 @@ hyper-rustls = { version = "0.27.3", default-features = false, features = [ # tls and cert management for server rpxy-certs = { path = "../rpxy-certs/", default-features = false } hot_reload = "0.1.6" -rustls = { version = "0.23.15", default-features = false } +rustls = { version = "0.23.16", default-features = false } +rustls-post-quantum = { version = "0.1.0", optional = true } tokio-rustls = { version = "0.26.0", features = ["early-data"] } # acme diff --git a/rpxy-lib/src/lib.rs b/rpxy-lib/src/lib.rs index c1ee44fa..b12d5e07 100644 --- a/rpxy-lib/src/lib.rs +++ b/rpxy-lib/src/lib.rs @@ -22,7 +22,7 @@ use crate::{ use futures::future::join_all; use hot_reload::ReloaderReceiver; use rpxy_certs::ServerCryptoBase; -use rustls::crypto::{aws_lc_rs, CryptoProvider}; +use rustls::crypto::CryptoProvider; use std::sync::Arc; use tokio_util::sync::CancellationToken; @@ -101,8 +101,11 @@ pub async fn entrypoint( info!("Cache is disabled") } + #[cfg(not(feature = "post-quantum"))] // Install aws_lc_rs as default crypto provider for rustls - let _ = CryptoProvider::install_default(aws_lc_rs::default_provider()); + let _ = CryptoProvider::install_default(rustls::crypto::aws_lc_rs::default_provider()); + #[cfg(feature = "post-quantum")] + let _ = CryptoProvider::install_default(rustls_post_quantum::provider()); // 1. build backends, and make it contained in Arc let app_manager = Arc::new(backend::BackendAppManager::try_from(app_config_list)?); From 68b4a2afdd8bf0bac34418729d818d3cd30d0052 Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Fri, 1 Nov 2024 10:07:44 +0900 Subject: [PATCH 08/16] [skip ci] update changelog --- CHANGELOG.md | 6 ++++-- rpxy-acme/Cargo.toml | 2 +- rpxy-certs/Cargo.toml | 2 +- rpxy-lib/Cargo.toml | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74a82d0c..2bcf601c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,17 @@ # CHANGELOG -## 0.9.3 or 0.10.0 (Unreleased) +## 0.10.0 (Unreleased) + +## 0.9.3 ### Improvement +- Feat: Support post-quantum `X25519Kyber768Draft00` for incoming TLS initiation. This is non-default feature [feature: `post-quantum`]. Upstream connection to backend applications does not yet support PQC. - Feat: emit WARN messages if there exist unused and unsupported options specified in configuration file. - Docs: `rpxy.io` is now available for the official website of `rpxy`. - Refactor: lots of minor improvements - Deps - ## 0.9.2 ### Improvement diff --git a/rpxy-acme/Cargo.toml b/rpxy-acme/Cargo.toml index 80fe15c6..6b7b96e1 100644 --- a/rpxy-acme/Cargo.toml +++ b/rpxy-acme/Cargo.toml @@ -16,7 +16,7 @@ post-quantum = ["rustls-post-quantum"] [dependencies] url = { version = "2.5.2" } rustc-hash = "2.0.0" -thiserror = "1.0.65" +thiserror = "1.0.66" tracing = "0.1.40" async-trait = "0.1.83" base64 = "0.22.1" diff --git a/rpxy-certs/Cargo.toml b/rpxy-certs/Cargo.toml index 8d9560e6..ba39e6cb 100644 --- a/rpxy-certs/Cargo.toml +++ b/rpxy-certs/Cargo.toml @@ -19,7 +19,7 @@ http3 = [] rustc-hash = { version = "2.0.0" } tracing = { version = "0.1.40" } derive_builder = { version = "0.20.2" } -thiserror = { version = "1.0.65" } +thiserror = { version = "1.0.66" } hot_reload = { version = "0.1.6" } async-trait = { version = "0.1.83" } rustls = { version = "0.23.16", default-features = false, features = [ diff --git a/rpxy-lib/Cargo.toml b/rpxy-lib/Cargo.toml index 33eb1354..dc5d09a0 100644 --- a/rpxy-lib/Cargo.toml +++ b/rpxy-lib/Cargo.toml @@ -54,7 +54,7 @@ async-trait = "0.1.83" # Error handling anyhow = "1.0.91" -thiserror = "1.0.65" +thiserror = "1.0.66" # http for both server and client http = "1.1.0" From e3678446371ad1be8fe0bc7d5c96a2dbc5dd31cd Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Fri, 1 Nov 2024 10:43:17 +0900 Subject: [PATCH 09/16] update docker actions --- .github/workflows/release.yml | 28 +++++++++++++++++++++ .github/workflows/release_docker.yml | 37 ++++++++++++++++++++++++++++ docker/README.md | 2 ++ rpxy-bin/Cargo.toml | 4 +-- 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8c0dca69..3f2c594e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,6 +34,14 @@ jobs: platform: linux/arm64 tags-suffix: "-slim" + - target: "musl" + platform: linux/amd64 + tags-suffix: "-slim-pq" + + - target: "musl" + platform: linux/arm64 + tags-suffix: "-slim-pq" + - target: "gnu" build-feature: "-s2n" platform: linux/amd64 @@ -44,6 +52,26 @@ jobs: platform: linux/arm64 tags-suffix: "-s2n" + - target: "gnu" + build-feature: "-pq" + platform: linux/amd64 + tags-suffix: "-pq" + + - target: "gnu" + build-feature: "-pq" + platform: linux/arm64 + tags-suffix: "-pq" + + - target: "gnu" + build-feature: "-s2n-pq" + platform: linux/amd64 + tags-suffix: "-s2n-pq" + + - target: "gnu" + build-feature: "-s2n" + platform: linux/arm64 + tags-suffix: "-s2n-pq" + - target: "gnu" build-feature: "-webpki-roots" platform: linux/amd64 diff --git a/.github/workflows/release_docker.yml b/.github/workflows/release_docker.yml index c0182729..7a3105d7 100644 --- a/.github/workflows/release_docker.yml +++ b/.github/workflows/release_docker.yml @@ -30,6 +30,17 @@ jobs: jqtype/rpxy:latest ghcr.io/junkurihara/rust-rpxy:latest + - target: "default-pq" + dockerfile: ./docker/Dockerfile + platforms: linux/amd64,linux/arm64 + build-args: | + "CARGO_FEATURES=--no-default-features --features=http3-quinn,cache,rustls-backend,acme,post-quantum" + tags-suffix: "-pq" + # Aliases must be used only for release builds + aliases: | + jqtype/rpxy:pq + ghcr.io/junkurihara/rust-rpxy:pq + - target: "default-slim" dockerfile: ./docker/Dockerfile-slim build-contexts: | @@ -42,6 +53,20 @@ jobs: jqtype/rpxy:slim ghcr.io/junkurihara/rust-rpxy:slim + - target: "default-slim-pq" + dockerfile: ./docker/Dockerfile-slim + build-args: | + "CARGO_FEATURES=--no-default-features --features=http3-quinn,cache,rustls-backend,acme,post-quantum" + build-contexts: | + messense/rust-musl-cross:amd64-musl=docker-image://messense/rust-musl-cross:x86_64-musl + messense/rust-musl-cross:arm64-musl=docker-image://messense/rust-musl-cross:aarch64-musl + platforms: linux/amd64,linux/arm64 + tags-suffix: "-slim-pq" + # Aliases must be used only for release builds + aliases: | + jqtype/rpxy:slim-pq + ghcr.io/junkurihara/rust-rpxy:slim-pq + - target: "s2n" dockerfile: ./docker/Dockerfile build-args: | @@ -54,6 +79,18 @@ jobs: jqtype/rpxy:s2n ghcr.io/junkurihara/rust-rpxy:s2n + - target: "s2n-pq" + dockerfile: ./docker/Dockerfile + build-args: | + "CARGO_FEATURES=--no-default-features --features=http3-s2n,cache,rustls-backend,acme,post-quantum" + "ADDITIONAL_DEPS=pkg-config libssl-dev cmake libclang1 gcc g++" + platforms: linux/amd64,linux/arm64 + tags-suffix: "-s2n-pq" + # Aliases must be used only for release builds + aliases: | + jqtype/rpxy:s2n-pq + ghcr.io/junkurihara/rust-rpxy:s2n-pq + - target: "webpki-roots" dockerfile: ./docker/Dockerfile platforms: linux/amd64,linux/arm64 diff --git a/docker/README.md b/docker/README.md index 25f5b86f..ab373a42 100644 --- a/docker/README.md +++ b/docker/README.md @@ -32,12 +32,14 @@ Differences among tags are summarized as follows. - `latest`: Built from the `main` branch with default features, running on Ubuntu. - `latest-slim`, `slim`: Built by `musl` from the `main` branch with default features, running on Alpine. - `latest-s2n`, `s2n`: Built from the `main` branch with the `http3-s2n` feature, running on Ubuntu. +- `*-pq`: Built with the `post-quantum` feature. This feature supports the post-quantum key exchange using `rustls-post-quantum` crate. ### Nightly Builds - `nightly`: Built from the `develop` branch with default features, running on Ubuntu. - `nightly-slim`: Built by `musl` from the `develop` branch with default features, running on Alpine. - `nightly-s2n`: Built from the `develop` branch with the `http3-s2n` feature, running on Ubuntu. +- - `*-pq`: Built with the `post-quantum` feature. This feature supports the post-quantum key exchange using `rustls-post-quantum` crate. ## Caveats diff --git a/rpxy-bin/Cargo.toml b/rpxy-bin/Cargo.toml index d83213d7..50173fe9 100644 --- a/rpxy-bin/Cargo.toml +++ b/rpxy-bin/Cargo.toml @@ -13,9 +13,9 @@ publish.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["http3-quinn", "cache", "rustls-backend", "acme", "post-quantum"] +# default = ["http3-quinn", "cache", "rustls-backend", "acme", "post-quantum"] # default = ["http3-s2n", "cache", "rustls-backend", "acme", "post-quantum"] -# default = ["http3-quinn", "cache", "rustls-backend", "acme"] +default = ["http3-quinn", "cache", "rustls-backend", "acme"] # default = ["http3-s2n", "cache", "rustls-backend", "acme"] http3-quinn = ["rpxy-lib/http3-quinn"] http3-s2n = ["rpxy-lib/http3-s2n"] From ad8d02889af0afd5e58468cf4cd6e994be2cab89 Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Fri, 1 Nov 2024 10:55:12 +0900 Subject: [PATCH 10/16] [skip ci] update readme --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 504e07d5..28e4f62a 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,12 @@ [^pure_rust]: Doubtfully can be claimed to be written in pure Rust since current `rpxy` is based on `aws-lc-rs` for cryptographic operations. -By default, `rpxy` provides the *TLS connection sanitization* by correctly binding a certificate used to establish a secure channel with the backend application. Specifically, it always keeps the consistency between the given SNI (server name indication) in `ClientHello` of the underlying TLS and the domain name given by the overlaid HTTP HOST header (or URL in Request line) [^1]. Additionally, as a somewhat unstable feature, our `rpxy` can handle the brand-new HTTP/3 connection thanks to [`quinn`](https://github.com/quinn-rs/quinn), [`s2n-quic`](https://github.com/aws/s2n-quic) and [`hyperium/h3`](https://github.com/hyperium/h3).[^h3lib] Furthermore, `rpxy` supports the automatic issuance and renewal of certificates via [TLS-ALPN-01 (RFC8737)](https://www.rfc-editor.org/rfc/rfc8737) of [ACME protocol (RFC8555)](https://www.rfc-editor.org/rfc/rfc8555) thanks to [`rustls-acme`](https://github.com/FlorianUekermann/rustls-acme). +By default, `rpxy` provides the *TLS connection sanitization* by correctly binding a certificate used to establish a secure channel with the backend application. Specifically, it always keeps the consistency between the given SNI (server name indication) in `ClientHello` of the underlying TLS and the domain name given by the overlaid HTTP HOST header (or URL in Request line) [^1]. Additionally, as a somewhat unstable feature, our `rpxy` can handle the brand-new HTTP/3 connection thanks to [`quinn`](https://github.com/quinn-rs/quinn), [`s2n-quic`](https://github.com/aws/s2n-quic) and [`hyperium/h3`](https://github.com/hyperium/h3).[^h3lib] Furthermore, `rpxy` supports the automatic issuance and renewal of certificates via [TLS-ALPN-01 (RFC8737)](https://www.rfc-editor.org/rfc/rfc8737) of [ACME protocol (RFC8555)](https://www.rfc-editor.org/rfc/rfc8555) thanks to [`rustls-acme`](https://github.com/FlorianUekermann/rustls-acme), and the hybridized post-quantum key exchange [`X25519Kyber768Draft00`](https://datatracker.ietf.org/doc/draft-tls-westerbaan-xyber768d00/)[^kyber] for TLS initiation thanks to `rustls-post-quantum` crate. [^h3lib]: HTTP/3 libraries are mutually exclusive. You need to explicitly specify `s2n-quic` with `--no-default-features` flag. Also note that if you build `rpxy` with `s2n-quic`, then it requires `openssl` just for building the package. + [^kyber]: This is not yet a default feature. You need to specify `--features post-quantum` when building `rpxy`. Also note that `X25519Kyber768Draft00` is a draft version yet this is widely used on the Internet. We will update the feature when the newest version (`X25519MLKEM768` in [`ECDHE-MLKEM`](https://www.ietf.org/archive/id/draft-kwiatkowski-tls-ecdhe-mlkem-02.html)) is available. + This project is still *work-in-progress*. But it is already working in some production environments and serves a number of domain names. Furthermore it *significantly outperforms* NGINX and Caddy, e.g., *1.5x faster than NGINX*, in the setting of a very simple HTTP reverse-proxy scenario (See [`bench`](./bench/) directory). [^1]: We should note that NGINX doesn't guarantee such a consistency by default. To this end, you have to add `if` statement in the configuration file in NGINX. From 03175b23d94f2efdf917ba79397147b5c1feb383 Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Fri, 1 Nov 2024 11:03:55 +0900 Subject: [PATCH 11/16] docs: update docker/readme --- docker/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/README.md b/docker/README.md index ab373a42..f5a4c2b1 100644 --- a/docker/README.md +++ b/docker/README.md @@ -39,7 +39,7 @@ Differences among tags are summarized as follows. - `nightly`: Built from the `develop` branch with default features, running on Ubuntu. - `nightly-slim`: Built by `musl` from the `develop` branch with default features, running on Alpine. - `nightly-s2n`: Built from the `develop` branch with the `http3-s2n` feature, running on Ubuntu. -- - `*-pq`: Built with the `post-quantum` feature. This feature supports the post-quantum key exchange using `rustls-post-quantum` crate. +- `*-pq`: Built with the `post-quantum` feature. This feature supports the hybridized post-quantum key exchange using `rustls-post-quantum` crate. ## Caveats From 6235e1dd1b7847d546052e69770c0c37f6771bb8 Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Fri, 1 Nov 2024 11:39:35 +0900 Subject: [PATCH 12/16] docs: update readme --- CHANGELOG.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bcf601c..25c274a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ ### Improvement -- Feat: Support post-quantum `X25519Kyber768Draft00` for incoming TLS initiation. This is non-default feature [feature: `post-quantum`]. Upstream connection to backend applications does not yet support PQC. +- Feat: Support post-quantum `X25519Kyber768Draft00` for incoming and outgoing TLS initiation. This is non-default feature [feature: `post-quantum`]. - Feat: emit WARN messages if there exist unused and unsupported options specified in configuration file. - Docs: `rpxy.io` is now available for the official website of `rpxy`. - Refactor: lots of minor improvements diff --git a/README.md b/README.md index 28e4f62a..5f0467d4 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ [^pure_rust]: Doubtfully can be claimed to be written in pure Rust since current `rpxy` is based on `aws-lc-rs` for cryptographic operations. -By default, `rpxy` provides the *TLS connection sanitization* by correctly binding a certificate used to establish a secure channel with the backend application. Specifically, it always keeps the consistency between the given SNI (server name indication) in `ClientHello` of the underlying TLS and the domain name given by the overlaid HTTP HOST header (or URL in Request line) [^1]. Additionally, as a somewhat unstable feature, our `rpxy` can handle the brand-new HTTP/3 connection thanks to [`quinn`](https://github.com/quinn-rs/quinn), [`s2n-quic`](https://github.com/aws/s2n-quic) and [`hyperium/h3`](https://github.com/hyperium/h3).[^h3lib] Furthermore, `rpxy` supports the automatic issuance and renewal of certificates via [TLS-ALPN-01 (RFC8737)](https://www.rfc-editor.org/rfc/rfc8737) of [ACME protocol (RFC8555)](https://www.rfc-editor.org/rfc/rfc8555) thanks to [`rustls-acme`](https://github.com/FlorianUekermann/rustls-acme), and the hybridized post-quantum key exchange [`X25519Kyber768Draft00`](https://datatracker.ietf.org/doc/draft-tls-westerbaan-xyber768d00/)[^kyber] for TLS initiation thanks to `rustls-post-quantum` crate. +By default, `rpxy` provides the *TLS connection sanitization* by correctly binding a certificate used to establish a secure channel with the backend application. Specifically, it always keeps the consistency between the given SNI (server name indication) in `ClientHello` of the underlying TLS and the domain name given by the overlaid HTTP HOST header (or URL in Request line) [^1]. Additionally, as a somewhat unstable feature, our `rpxy` can handle the brand-new HTTP/3 connection thanks to [`quinn`](https://github.com/quinn-rs/quinn), [`s2n-quic`](https://github.com/aws/s2n-quic) and [`hyperium/h3`](https://github.com/hyperium/h3).[^h3lib] Furthermore, `rpxy` supports the automatic issuance and renewal of certificates via [TLS-ALPN-01 (RFC8737)](https://www.rfc-editor.org/rfc/rfc8737) of [ACME protocol (RFC8555)](https://www.rfc-editor.org/rfc/rfc8555) thanks to [`rustls-acme`](https://github.com/FlorianUekermann/rustls-acme), and the hybridized post-quantum key exchange [`X25519Kyber768Draft00`](https://datatracker.ietf.org/doc/draft-tls-westerbaan-xyber768d00/)[^kyber] for TLS incoming and outgoing initiation thanks to [`rustls-post-quantum`](https://docs.rs/rustls-post-quantum/latest/rustls_post_quantum/). [^h3lib]: HTTP/3 libraries are mutually exclusive. You need to explicitly specify `s2n-quic` with `--no-default-features` flag. Also note that if you build `rpxy` with `s2n-quic`, then it requires `openssl` just for building the package. From b93d42f35d3fea0a6a75ba272c0f1218fc3453aa Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Fri, 1 Nov 2024 12:43:47 +0900 Subject: [PATCH 13/16] fix: github actions release.yml --- .github/workflows/release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3f2c594e..8b056bb8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,10 +35,12 @@ jobs: tags-suffix: "-slim" - target: "musl" + build-feature: "-slim-pq" platform: linux/amd64 tags-suffix: "-slim-pq" - target: "musl" + build-feature: "-slim-pq" platform: linux/arm64 tags-suffix: "-slim-pq" @@ -68,7 +70,7 @@ jobs: tags-suffix: "-s2n-pq" - target: "gnu" - build-feature: "-s2n" + build-feature: "-s2n-pq" platform: linux/arm64 tags-suffix: "-s2n-pq" From 5dd236a80b9746443b847edfbab972cbe6ebaaef Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Fri, 1 Nov 2024 12:46:37 +0900 Subject: [PATCH 14/16] chore: add message for pqc --- rpxy-lib/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rpxy-lib/src/lib.rs b/rpxy-lib/src/lib.rs index b12d5e07..fa74d42d 100644 --- a/rpxy-lib/src/lib.rs +++ b/rpxy-lib/src/lib.rs @@ -106,6 +106,8 @@ pub async fn entrypoint( let _ = CryptoProvider::install_default(rustls::crypto::aws_lc_rs::default_provider()); #[cfg(feature = "post-quantum")] let _ = CryptoProvider::install_default(rustls_post_quantum::provider()); + #[cfg(feature = "post-quantum")] + info!("Post-quantum crypto provider is installed"); // 1. build backends, and make it contained in Arc let app_manager = Arc::new(backend::BackendAppManager::try_from(app_config_list)?); From 7aefc011c07f61dc07a8d90aae5e40ae8b134ac3 Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Fri, 1 Nov 2024 15:22:45 +0900 Subject: [PATCH 15/16] chore: follow the up-to-date s2n-quic-h3 --- rpxy-lib/Cargo.toml | 6 +++--- submodules/s2n-quic-h3/Cargo.toml | 2 -- submodules/s2n-quic-h3/src/s2n_quic.rs | 10 ++++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/rpxy-lib/Cargo.toml b/rpxy-lib/Cargo.toml index dc5d09a0..2d46293a 100644 --- a/rpxy-lib/Cargo.toml +++ b/rpxy-lib/Cargo.toml @@ -93,14 +93,14 @@ tracing = { version = "0.1.40" } quinn = { version = "0.11.5", optional = true } h3 = { version = "0.0.6", features = ["tracing"], optional = true } h3-quinn = { version = "0.0.7", optional = true } -s2n-quic-h3 = { path = "../submodules/s2n-quic-h3/", features = [ - "tracing", -], optional = true } s2n-quic = { version = "1.48.0", default-features = false, features = [ "provider-tls-rustls", ], optional = true } s2n-quic-core = { version = "0.48.0", default-features = false, optional = true } s2n-quic-rustls = { version = "0.48.0", optional = true } +s2n-quic-h3 = { path = "../submodules/s2n-quic-h3/", features = [ + "tracing", +], optional = true } ########## # for UDP socket wit SO_REUSEADDR when h3 with quinn socket2 = { version = "0.5.7", features = ["all"], optional = true } diff --git a/submodules/s2n-quic-h3/Cargo.toml b/submodules/s2n-quic-h3/Cargo.toml index 8d53fc10..0058e45e 100644 --- a/submodules/s2n-quic-h3/Cargo.toml +++ b/submodules/s2n-quic-h3/Cargo.toml @@ -14,9 +14,7 @@ bytes = { version = "1", default-features = false } futures = { version = "0.3", default-features = false } h3 = { version = "0.0.6", features = ["tracing"] } # s2n-quic = { path = "../s2n-quic" } -# s2n-quic-core = { path = "../s2n-quic-core" } s2n-quic = { version = "1.47.0" } -s2n-quic-core = { version = "0.48.0" } tracing = { version = "0.1.40", optional = true } [features] diff --git a/submodules/s2n-quic-h3/src/s2n_quic.rs b/submodules/s2n-quic-h3/src/s2n_quic.rs index abe0a332..622f9652 100644 --- a/submodules/s2n-quic-h3/src/s2n_quic.rs +++ b/submodules/s2n-quic-h3/src/s2n_quic.rs @@ -4,8 +4,10 @@ use bytes::{Buf, Bytes}; use core::task::ready; use h3::quic::{self, Error, StreamId, WriteBuf}; -use s2n_quic::stream::{BidirectionalStream, ReceiveStream}; -use s2n_quic_core::varint::VarInt; +use s2n_quic::{ + application, + stream::{BidirectionalStream, ReceiveStream}, +}; use std::{ convert::TryInto, fmt::{self, Display}, @@ -179,7 +181,7 @@ where self.conn.close( code.value() .try_into() - .unwrap_or_else(|_| VarInt::MAX.into()), + .unwrap_or(application::Error::UNKNOWN), ); } } @@ -462,7 +464,7 @@ where fn reset(&mut self, reset_code: u64) { let _ = self .stream - .reset(reset_code.try_into().unwrap_or_else(|_| VarInt::MAX.into())); + .reset(reset_code.try_into().unwrap_or(application::Error::UNKNOWN)); } #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] From cec781fcfc16639f447b805851042fa586a35c9d Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Fri, 1 Nov 2024 16:53:43 +0900 Subject: [PATCH 16/16] fix: s2n-quic-rustls post-quantum support --- .gitmodules | 4 + rpxy-lib/Cargo.toml | 9 +- submodules/s2n-quic | 1 + submodules/s2n-quic-h3/Cargo.toml | 21 - submodules/s2n-quic-h3/README.md | 10 - submodules/s2n-quic-h3/src/lib.rs | 7 - submodules/s2n-quic-h3/src/s2n_quic.rs | 534 ------------------------- 7 files changed, 10 insertions(+), 576 deletions(-) create mode 160000 submodules/s2n-quic delete mode 100644 submodules/s2n-quic-h3/Cargo.toml delete mode 100644 submodules/s2n-quic-h3/README.md delete mode 100644 submodules/s2n-quic-h3/src/lib.rs delete mode 100644 submodules/s2n-quic-h3/src/s2n_quic.rs diff --git a/.gitmodules b/.gitmodules index 7ff65fe1..a8c5d142 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,7 @@ [submodule "submodules/rustls-acme"] path = submodules/rustls-acme url = git@github.com:junkurihara/rustls-acme.git +[submodule "submodules/s2n-quic"] + path = submodules/s2n-quic + url = git@github.com:junkurihara/s2n-quic.git + branch = rustls-pq diff --git a/rpxy-lib/Cargo.toml b/rpxy-lib/Cargo.toml index 2d46293a..fb21a4fc 100644 --- a/rpxy-lib/Cargo.toml +++ b/rpxy-lib/Cargo.toml @@ -32,6 +32,7 @@ post-quantum = [ "rustls-post-quantum", "rpxy-acme/post-quantum", "rpxy-certs/post-quantum", + "s2n-quic-rustls/post-quantum", ] [dependencies] @@ -93,12 +94,12 @@ tracing = { version = "0.1.40" } quinn = { version = "0.11.5", optional = true } h3 = { version = "0.0.6", features = ["tracing"], optional = true } h3-quinn = { version = "0.0.7", optional = true } -s2n-quic = { version = "1.48.0", default-features = false, features = [ +s2n-quic = { version = "1.48.0", path = "../submodules/s2n-quic/quic/s2n-quic/", default-features = false, features = [ "provider-tls-rustls", ], optional = true } -s2n-quic-core = { version = "0.48.0", default-features = false, optional = true } -s2n-quic-rustls = { version = "0.48.0", optional = true } -s2n-quic-h3 = { path = "../submodules/s2n-quic-h3/", features = [ +s2n-quic-core = { version = "0.48.0", path = "../submodules/s2n-quic/quic/s2n-quic-core", default-features = false, optional = true } +s2n-quic-rustls = { version = "0.48.0", path = "../submodules/s2n-quic/quic/s2n-quic-rustls", optional = true } +s2n-quic-h3 = { path = "../submodules/s2n-quic/quic/s2n-quic-h3/", features = [ "tracing", ], optional = true } ########## diff --git a/submodules/s2n-quic b/submodules/s2n-quic new file mode 160000 index 00000000..ffeaac1e --- /dev/null +++ b/submodules/s2n-quic @@ -0,0 +1 @@ +Subproject commit ffeaac1eb32589599c9be357f2273a2824741c7d diff --git a/submodules/s2n-quic-h3/Cargo.toml b/submodules/s2n-quic-h3/Cargo.toml deleted file mode 100644 index 0058e45e..00000000 --- a/submodules/s2n-quic-h3/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "s2n-quic-h3" -# this in an unpublished internal crate so the version should not be changed -version = "0.1.0" -authors = ["AWS s2n"] -edition = "2021" -rust-version = "1.71" -license = "Apache-2.0" -# this contains an http3 implementation for testing purposes and should not be published -publish = false - -[dependencies] -bytes = { version = "1", default-features = false } -futures = { version = "0.3", default-features = false } -h3 = { version = "0.0.6", features = ["tracing"] } -# s2n-quic = { path = "../s2n-quic" } -s2n-quic = { version = "1.47.0" } -tracing = { version = "0.1.40", optional = true } - -[features] -tracing = ["dep:tracing"] diff --git a/submodules/s2n-quic-h3/README.md b/submodules/s2n-quic-h3/README.md deleted file mode 100644 index aed94754..00000000 --- a/submodules/s2n-quic-h3/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# s2n-quic-h3 - -This is an internal crate used by [s2n-quic](https://github.com/aws/s2n-quic) written as a proof of concept for implementing HTTP3 on top of s2n-quic. The API is not currently stable and should not be used directly. - -## License - -This project is licensed under the [Apache-2.0 License][license-url]. - -[license-badge]: https://img.shields.io/badge/license-apache-blue.svg -[license-url]: https://aws.amazon.com/apache-2-0/ diff --git a/submodules/s2n-quic-h3/src/lib.rs b/submodules/s2n-quic-h3/src/lib.rs deleted file mode 100644 index c85f197f..00000000 --- a/submodules/s2n-quic-h3/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -mod s2n_quic; - -pub use self::s2n_quic::*; -pub use h3; diff --git a/submodules/s2n-quic-h3/src/s2n_quic.rs b/submodules/s2n-quic-h3/src/s2n_quic.rs deleted file mode 100644 index 622f9652..00000000 --- a/submodules/s2n-quic-h3/src/s2n_quic.rs +++ /dev/null @@ -1,534 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -use bytes::{Buf, Bytes}; -use core::task::ready; -use h3::quic::{self, Error, StreamId, WriteBuf}; -use s2n_quic::{ - application, - stream::{BidirectionalStream, ReceiveStream}, -}; -use std::{ - convert::TryInto, - fmt::{self, Display}, - sync::Arc, - task::{self, Poll}, -}; - -#[cfg(feature = "tracing")] -use tracing::instrument; - -pub struct Connection { - conn: s2n_quic::connection::Handle, - bidi_acceptor: s2n_quic::connection::BidirectionalStreamAcceptor, - recv_acceptor: s2n_quic::connection::ReceiveStreamAcceptor, -} - -impl Connection { - pub fn new(new_conn: s2n_quic::Connection) -> Self { - let (handle, acceptor) = new_conn.split(); - let (bidi, recv) = acceptor.split(); - - Self { - conn: handle, - bidi_acceptor: bidi, - recv_acceptor: recv, - } - } -} - -#[derive(Debug)] -pub struct ConnectionError(s2n_quic::connection::Error); - -impl std::error::Error for ConnectionError {} - -impl fmt::Display for ConnectionError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl Error for ConnectionError { - fn is_timeout(&self) -> bool { - matches!(self.0, s2n_quic::connection::Error::IdleTimerExpired { .. }) - } - - fn err_code(&self) -> Option { - match self.0 { - s2n_quic::connection::Error::Application { error, .. } => Some(error.into()), - _ => None, - } - } -} - -impl From for ConnectionError { - fn from(e: s2n_quic::connection::Error) -> Self { - Self(e) - } -} - -impl quic::Connection for Connection -where - B: Buf, -{ - type RecvStream = RecvStream; - type OpenStreams = OpenStreams; - type AcceptError = ConnectionError; - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn poll_accept_recv( - &mut self, - cx: &mut task::Context<'_>, - ) -> Poll, Self::AcceptError>> { - let recv = match ready!(self.recv_acceptor.poll_accept_receive_stream(cx))? { - Some(x) => x, - None => return Poll::Ready(Ok(None)), - }; - Poll::Ready(Ok(Some(Self::RecvStream::new(recv)))) - } - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn poll_accept_bidi( - &mut self, - cx: &mut task::Context<'_>, - ) -> Poll, Self::AcceptError>> { - let (recv, send) = match ready!(self.bidi_acceptor.poll_accept_bidirectional_stream(cx))? { - Some(x) => x.split(), - None => return Poll::Ready(Ok(None)), - }; - Poll::Ready(Ok(Some(Self::BidiStream { - send: Self::SendStream::new(send), - recv: Self::RecvStream::new(recv), - }))) - } - - fn opener(&self) -> Self::OpenStreams { - OpenStreams { - conn: self.conn.clone(), - } - } -} - -impl quic::OpenStreams for Connection -where - B: Buf, -{ - type BidiStream = BidiStream; - type SendStream = SendStream; - type OpenError = ConnectionError; - - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn poll_open_bidi( - &mut self, - cx: &mut task::Context<'_>, - ) -> Poll> { - let stream = ready!(self.conn.poll_open_bidirectional_stream(cx))?; - Ok(stream.into()).into() - } - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn poll_open_send( - &mut self, - cx: &mut task::Context<'_>, - ) -> Poll> { - let stream = ready!(self.conn.poll_open_send_stream(cx))?; - Ok(stream.into()).into() - } - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn close(&mut self, code: h3::error::Code, _reason: &[u8]) { - self.conn.close( - code.value() - .try_into() - .expect("s2n-quic supports error codes up to 2^62-1"), - ); - } -} - -pub struct OpenStreams { - conn: s2n_quic::connection::Handle, -} - -impl quic::OpenStreams for OpenStreams -where - B: Buf, -{ - type BidiStream = BidiStream; - type SendStream = SendStream; - type OpenError = ConnectionError; - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn poll_open_bidi( - &mut self, - cx: &mut task::Context<'_>, - ) -> Poll> { - let stream = ready!(self.conn.poll_open_bidirectional_stream(cx))?; - Ok(stream.into()).into() - } - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn poll_open_send( - &mut self, - cx: &mut task::Context<'_>, - ) -> Poll> { - let stream = ready!(self.conn.poll_open_send_stream(cx))?; - Ok(stream.into()).into() - } - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn close(&mut self, code: h3::error::Code, _reason: &[u8]) { - self.conn.close( - code.value() - .try_into() - .unwrap_or(application::Error::UNKNOWN), - ); - } -} - -impl Clone for OpenStreams { - fn clone(&self) -> Self { - Self { - conn: self.conn.clone(), - } - } -} - -pub struct BidiStream -where - B: Buf, -{ - send: SendStream, - recv: RecvStream, -} - -impl quic::BidiStream for BidiStream -where - B: Buf, -{ - type SendStream = SendStream; - type RecvStream = RecvStream; - - fn split(self) -> (Self::SendStream, Self::RecvStream) { - (self.send, self.recv) - } -} - -impl quic::RecvStream for BidiStream -where - B: Buf, -{ - type Buf = Bytes; - type Error = ReadError; - - fn poll_data( - &mut self, - cx: &mut task::Context<'_>, - ) -> Poll, Self::Error>> { - self.recv.poll_data(cx) - } - - fn stop_sending(&mut self, error_code: u64) { - self.recv.stop_sending(error_code) - } - - fn recv_id(&self) -> StreamId { - self.recv.recv_id() - } -} - -impl quic::SendStream for BidiStream -where - B: Buf, -{ - type Error = SendStreamError; - - fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll> { - self.send.poll_ready(cx) - } - - fn poll_finish(&mut self, cx: &mut task::Context<'_>) -> Poll> { - self.send.poll_finish(cx) - } - - fn reset(&mut self, reset_code: u64) { - self.send.reset(reset_code) - } - - fn send_data>>(&mut self, data: D) -> Result<(), Self::Error> { - self.send.send_data(data) - } - - fn send_id(&self) -> StreamId { - self.send.send_id() - } -} - -impl From for BidiStream -where - B: Buf, -{ - fn from(bidi: BidirectionalStream) -> Self { - let (recv, send) = bidi.split(); - BidiStream { - send: send.into(), - recv: recv.into(), - } - } -} - -pub struct RecvStream { - stream: s2n_quic::stream::ReceiveStream, -} - -impl RecvStream { - fn new(stream: s2n_quic::stream::ReceiveStream) -> Self { - Self { stream } - } -} - -impl quic::RecvStream for RecvStream { - type Buf = Bytes; - type Error = ReadError; - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn poll_data( - &mut self, - cx: &mut task::Context<'_>, - ) -> Poll, Self::Error>> { - let buf = ready!(self.stream.poll_receive(cx))?; - Ok(buf).into() - } - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn stop_sending(&mut self, error_code: u64) { - let _ = self.stream.stop_sending( - s2n_quic::application::Error::new(error_code) - .expect("s2n-quic supports error codes up to 2^62-1"), - ); - } - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn recv_id(&self) -> StreamId { - self.stream.id().try_into().expect("invalid stream id") - } -} - -impl From for RecvStream { - fn from(recv: ReceiveStream) -> Self { - RecvStream::new(recv) - } -} - -#[derive(Debug)] -pub struct ReadError(s2n_quic::stream::Error); - -impl std::error::Error for ReadError {} - -impl fmt::Display for ReadError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl From for Arc { - fn from(e: ReadError) -> Self { - Arc::new(e) - } -} - -impl From for ReadError { - fn from(e: s2n_quic::stream::Error) -> Self { - Self(e) - } -} - -impl Error for ReadError { - fn is_timeout(&self) -> bool { - matches!( - self.0, - s2n_quic::stream::Error::ConnectionError { - error: s2n_quic::connection::Error::IdleTimerExpired { .. }, - .. - } - ) - } - - fn err_code(&self) -> Option { - match self.0 { - s2n_quic::stream::Error::ConnectionError { - error: s2n_quic::connection::Error::Application { error, .. }, - .. - } => Some(error.into()), - s2n_quic::stream::Error::StreamReset { error, .. } => Some(error.into()), - _ => None, - } - } -} - -pub struct SendStream { - stream: s2n_quic::stream::SendStream, - chunk: Option, - buf: Option>, // TODO: Replace with buf: PhantomData - // after https://github.com/hyperium/h3/issues/78 is resolved -} - -impl SendStream -where - B: Buf, -{ - fn new(stream: s2n_quic::stream::SendStream) -> SendStream { - Self { - stream, - chunk: None, - buf: Default::default(), - } - } -} - -impl quic::SendStream for SendStream -where - B: Buf, -{ - type Error = SendStreamError; - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll> { - loop { - // try to flush the current chunk if we have one - if let Some(chunk) = self.chunk.as_mut() { - ready!(self.stream.poll_send(chunk, cx))?; - - // s2n-quic will take the whole chunk on send, even if it exceeds the limits - debug_assert!(chunk.is_empty()); - self.chunk = None; - } - - // try to take the next chunk from the WriteBuf - if let Some(ref mut data) = self.buf { - let len = data.chunk().len(); - - // if the write buf is empty, then clear it and break - if len == 0 { - self.buf = None; - break; - } - - // copy the first chunk from WriteBuf and prepare it to flush - let chunk = data.copy_to_bytes(len); - self.chunk = Some(chunk); - - // loop back around to flush the chunk - continue; - } - - // if we didn't have either a chunk or WriteBuf, then we're ready - break; - } - - Poll::Ready(Ok(())) - - // TODO: Replace with following after https://github.com/hyperium/h3/issues/78 is resolved - // self.available_bytes = ready!(self.stream.poll_send_ready(cx))?; - // Poll::Ready(Ok(())) - } - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn send_data>>(&mut self, data: D) -> Result<(), Self::Error> { - if self.buf.is_some() { - return Err(Self::Error::NotReady); - } - self.buf = Some(data.into()); - Ok(()) - - // TODO: Replace with following after https://github.com/hyperium/h3/issues/78 is resolved - // let mut data = data.into(); - // while self.available_bytes > 0 && data.has_remaining() { - // let len = data.chunk().len(); - // let chunk = data.copy_to_bytes(len); - // self.stream.send_data(chunk)?; - // self.available_bytes = self.available_bytes.saturating_sub(len); - // } - // Ok(()) - } - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn poll_finish(&mut self, cx: &mut task::Context<'_>) -> Poll> { - // ensure all chunks are flushed to the QUIC stream before finishing - ready!(self.poll_ready(cx))?; - self.stream.finish()?; - Ok(()).into() - } - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn reset(&mut self, reset_code: u64) { - let _ = self - .stream - .reset(reset_code.try_into().unwrap_or(application::Error::UNKNOWN)); - } - - #[cfg_attr(feature = "tracing", instrument(skip_all, level = "trace"))] - fn send_id(&self) -> StreamId { - self.stream.id().try_into().expect("invalid stream id") - } -} - -impl From for SendStream -where - B: Buf, -{ - fn from(send: s2n_quic::stream::SendStream) -> Self { - SendStream::new(send) - } -} - -#[derive(Debug)] -pub enum SendStreamError { - Write(s2n_quic::stream::Error), - NotReady, -} - -impl std::error::Error for SendStreamError {} - -impl Display for SendStreamError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{self:?}") - } -} - -impl From for SendStreamError { - fn from(e: s2n_quic::stream::Error) -> Self { - Self::Write(e) - } -} - -impl Error for SendStreamError { - fn is_timeout(&self) -> bool { - matches!( - self, - Self::Write(s2n_quic::stream::Error::ConnectionError { - error: s2n_quic::connection::Error::IdleTimerExpired { .. }, - .. - }) - ) - } - - fn err_code(&self) -> Option { - match self { - Self::Write(s2n_quic::stream::Error::StreamReset { error, .. }) => { - Some((*error).into()) - } - Self::Write(s2n_quic::stream::Error::ConnectionError { - error: s2n_quic::connection::Error::Application { error, .. }, - .. - }) => Some((*error).into()), - _ => None, - } - } -} - -impl From for Arc { - fn from(e: SendStreamError) -> Self { - Arc::new(e) - } -}