Skip to content

Add staged ClientHello acceptor for ServerConfig selection#2671

Open
iadev09 wants to merge 11 commits into
quinn-rs:mainfrom
iadev09:server-config-acceptor
Open

Add staged ClientHello acceptor for ServerConfig selection#2671
iadev09 wants to merge 11 commits into
quinn-rs:mainfrom
iadev09:server-config-acceptor

Conversation

@iadev09

@iadev09 iadev09 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Closes #2024.

Adds a staged ClientHello accept path so a server can inspect the rustls ClientHello before finalizing the Quinn ServerConfig.

Commit Structure

1. rustls 0.24 upgrade path

Kept as one compatibility commit. This is where the temporary rustls git dependencies live, including the rustls-platform-verifier 0.8 branch.

Related rustls 0.24 PR outside Quinn: rustls/rustls-platform-verifier#233.

2. staged ClientHello acceptor primitive

3. selector helper

Adds a ServerConfigSelector helper trait on top of the staged acceptor API.

pub trait ServerConfigSelector {
    /// Error returned by the selector.
    type Error;

    /// Select a server config for the provided ClientHello.
    fn select_server_config<'a>(
        &'a self,
        client_hello: rustls::server::ClientHello<'a>,
    ) -> impl Future<Output = Result<Option<Arc<ServerConfig>>, Self::Error>> + 'a;
}

Tests

cargo test -p quinn incoming_acceptor \
  --features runtime-tokio,rustls-aws-lc-rs \
  --no-default-features \
  --locked \
  -- --nocapture

cargo test -p quinn incoming_acceptor \
  --features runtime-tokio,rustls-ring \
  --no-default-features \
  --locked \
  -- --nocapture

Bench

https://github.com/iadev09/quinn-acceptor-bench

In local 1000-sample smoke runs, the selected path stayed in the same range as continuing with the default ServerConfig.

Comparison

Compared with the TCP/rustls shape, this exposes the staged primitive directly.

For TCP, config selection usually needs an intermediate acceptor/future shape:

let acceptor =
    LazyConfigAcceptor::new(rustls::server::Acceptor::default(), tcp_stream);
tokio::pin!(acceptor);
let start = acceptor.as_mut().await?;

For Quinn, the proposed primitive lets the caller inspect the ClientHello and choose the quinn::ServerConfig directly.

Because the Endpoint already owns the Initial/CRYPTO handling, it does not need a LazyConfigAcceptor-style stream wrapper.

let accepted = incoming.acceptor()?.await?;
let hello = accepted.client_hello();
let config = app_state.select_server_config(hello).await?;
let connection = accepted.accept_with(config)?.await?;

Same scenario on TCP/rustls LazyConfigAcceptor:

https://github.com/iadev09/lazy-config-acceptor-bench

This only measures the selector/no-selector difference; TCP connect and kernel transport work are not included.

@iadev09
iadev09 force-pushed the server-config-acceptor branch from 190980e to 738f9f7 Compare June 5, 2026 18:51
@iadev09
iadev09 marked this pull request as draft June 5, 2026 19:20
@iadev09
iadev09 force-pushed the server-config-acceptor branch from 738f9f7 to 7dbd839 Compare June 5, 2026 19:32
@iadev09
iadev09 marked this pull request as ready for review June 5, 2026 19:50
Comment thread quinn/Cargo.toml
Comment thread quinn/Cargo.toml
# Enable rustls with the `aws-lc-rs` crypto provider
rustls-aws-lc-rs = ["dep:rustls", "aws-lc-rs", "proto/rustls-aws-lc-rs", "proto/aws-lc-rs"]
rustls-aws-lc-rs-fips = ["dep:rustls", "aws-lc-rs-fips", "proto/rustls-aws-lc-rs-fips", "proto/aws-lc-rs-fips"]
rustls-aws-lc-rs = ["__rustls", "dep:rustls-aws-lc-rs", "aws-lc-rs", "proto/rustls-aws-lc-rs", "proto/aws-lc-rs"]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this feature refactoring can be done separately, earlier (suggest in a separate PR). rustls 0.24 requires that callers provide a crypto provider explicitly. Since rustls is a public dependency for Quinn anyway, I suggest that we drop the provider-specific features in favor of requiring an explicit provider, too.

@Ralith do you agree?

If so, I'd suggest that the explicit provider passing can also become a separate commit that can be merged ahead of this one. (May obviate the need for a __rustls feature?)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest that we drop the provider-specific features in favor of requiring an explicit provider, too.

Yep, that should be much more composable. We may still want to spend some effort having a reasonable default, but we should try to avoid needing to know about other providers.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the challenge here is that we still have the raw primitives in use for packet protection. Maybe the first objective is finishing main...ctz:quinn:jbp-retry-calculation-uses-rustls...

Comment thread .github/workflows/codecov.yml Outdated
@djc djc mentioned this pull request Jun 10, 2026
@iadev09
iadev09 force-pushed the server-config-acceptor branch 3 times, most recently from e67f0ff to 6f479c7 Compare June 11, 2026 10:51
@djc

djc commented Jun 17, 2026

Copy link
Copy Markdown
Member

So I think if you want to make progress on getting this merged, this needs to be done as a separate PR:

I guess the challenge here is that we still have the raw primitives in use for packet protection. Maybe the first objective is finishing main...ctz:quinn:jbp-retry-calculation-uses-rustls...

I think the upgrade to 0.24 should also be a separate PR -- not sure which of these two makes sense to merge first.

@iadev09

iadev09 commented Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

I split the rustls 0.24 upgrade out into a separate branch first. #2701

After that, I can look at the retry packet protection cleanup as another small PR before rebasing the staged ClientHello acceptor work on top.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Access Client Hello before accepting connection

3 participants