Skip to content
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
5 changes: 2 additions & 3 deletions .github/workflows/cve.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ on: [pull_request]

jobs:
scan:
#runs-on: ubuntu-latest
#runs-on: [self-hosted, linux, X64]
runs-on: blacksmith-4vcpu-ubuntu-2404
strategy:
matrix:
Expand All @@ -14,5 +12,6 @@ jobs:
release_built: ${{ steps.set-output.outputs.release_built }}
steps:
- uses: actions/checkout@v5
- run: rustup update stable
- run: cargo install --force cargo-audit
- run: cargo audit --ignore "RUSTSEC-2023-0071"
- run: cargo audit --ignore "RUSTSEC-2023-0071"
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Added

- Support for the [PROXY protocol] (v1 and v2) behind the new `proxy-proto`
crate feature. Setting the `proxy_protocol` configuration option (env
`ROCKET_PROXY_PROTOCOL`) to `true` requires every connection to begin with a
PROXY protocol preamble, as sent by proxies and load balancers like HAProxy
and AWS NLB. The forwarded client address becomes the connection's peer
endpoint, so `Request::remote()` and `Request::client_ip()` report the
original client address. Only enable this when all connections arrive
through a trusted proxy that always sends the preamble; connections without
a valid preamble are rejected, as the protocol specification requires.

[PROXY protocol]: https://www.haproxy.org/download/2.9/doc/proxy-protocol.txt

## 1.1.0 - 2026-07-07

### Added
Expand Down
1 change: 1 addition & 0 deletions core/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ msgpack = ["rmp-serde"]
uuid = ["uuid_", "rkt_http/uuid"]
tls = ["rustls", "tokio-rustls", "rustls-pki-types"]
mtls = ["tls", "x509-parser"]
proxy-proto = []
tokio-macros = ["tokio/macros"]
trace = ["tracing-subscriber", "tinyvec", "thread_local", "rustls?/logging", "tokio-rustls?/logging", "multer/log", "s2n-quic-h3?/tracing"]

Expand Down
2 changes: 2 additions & 0 deletions core/lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
//! | `uuid` | No | Support for [UUID value parsing and (de)serialization]. |
//! | `tokio-macros` | No | Enables the `macros` feature in the exported `tokio` |
//! | `http3-preview` | No | Experimental preview support for [HTTP/3]. |
//! | `proxy-proto` | No | Support for the [PROXY protocol] (v1 and v2). |
//!
//! Disabled features can be selectively enabled in `Cargo.toml`:
//!
Expand All @@ -87,6 +88,7 @@
//! [TLS]: https://rkt.rs/guide/configuration/#tls
//! [mutual TLS]: crate::mtls
//! [HTTP/3]: crate::listener::quic
//! [PROXY protocol]: crate::listener::proxy
//!
//! ## Configuration
//!
Expand Down
47 changes: 36 additions & 11 deletions core/lib/src/listener/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ mod private {
type UnixListener = TcpListener;

pub type Listener = Either<
Either<TlsListener<TcpListener>, TlsListener<UnixListener>>,
Either<TcpListener, UnixListener>,
Either<TlsListener<Base<TcpListener>>, TlsListener<Base<UnixListener>>>,
Either<Base<TcpListener>, Base<UnixListener>>,
>;

/// The default connection listener.
Expand All @@ -36,11 +36,20 @@ mod private {
///
/// Reads the following optional configuration parameters:
///
/// | parameter | type | default |
/// | ----------- | ----------------- | --------------------- |
/// | `address` | [`Endpoint`] | `tcp:127.0.0.1:8000` |
/// | `tls` | [`TlsConfig`] | None |
/// | `reuse` | boolean | `true` |
/// | parameter | type | default |
/// | ---------------- | ----------------- | --------------------- |
/// | `address` | [`Endpoint`] | `tcp:127.0.0.1:8000` |
/// | `tls` | [`TlsConfig`] | None |
/// | `reuse` | boolean | `true` |
/// | `proxy_protocol` | boolean | `false` |
///
/// The `proxy_protocol` parameter is read only when the `proxy-proto`
/// crate feature is enabled. When set to `true`, every connection must
/// begin with a [PROXY protocol] v1 or v2 preamble, and the forwarded
/// address becomes the connection's peer [`Endpoint`]. See
/// [`listener::proxy`](crate::listener::proxy) for details.
///
/// [PROXY protocol]: https://www.haproxy.org/download/2.9/doc/proxy-protocol.txt
///
/// # Listener
///
Expand All @@ -65,6 +74,15 @@ mod private {
pub struct DefaultListener(());
}

/// The transport listener `T`, wrapped in a
/// [`ProxyProtocolListener`](crate::listener::proxy::ProxyProtocolListener)
/// when PROXY protocol support is compiled in. The wrapper passes connections
/// through unmodified unless `proxy_protocol` is configured.
#[cfg(feature = "proxy-proto")]
type Base<T> = crate::listener::proxy::ProxyProtocolListener<T>;
#[cfg(not(feature = "proxy-proto"))]
type Base<T> = T;

#[derive(Deserialize)]
struct Config {
#[serde(default)]
Expand Down Expand Up @@ -122,21 +140,21 @@ impl Bind for DefaultListener {
match config.address {
#[cfg(feature = "tls")]
Endpoint::Tcp(_) if config.tls.is_some() => {
let listener = <TlsListener<TcpListener> as Bind>::bind(rocket).await?;
let listener = <TlsListener<Base<TcpListener>> as Bind>::bind(rocket).await?;
Ok(Left(Left(listener)))
}
Endpoint::Tcp(_) => {
let listener = <TcpListener as Bind>::bind(rocket).await?;
let listener = <Base<TcpListener> as Bind>::bind(rocket).await?;
Ok(Right(Left(listener)))
}
#[cfg(all(unix, feature = "tls"))]
Endpoint::Unix(_) if config.tls.is_some() => {
let listener = <TlsListener<UnixListener> as Bind>::bind(rocket).await?;
let listener = <TlsListener<Base<UnixListener>> as Bind>::bind(rocket).await?;
Ok(Left(Right(listener)))
}
#[cfg(unix)]
Endpoint::Unix(_) => {
let listener = <UnixListener as Bind>::bind(rocket).await?;
let listener = <Base<UnixListener> as Bind>::bind(rocket).await?;
Ok(Right(Right(listener)))
}
endpoint => Err(Error::Unsupported(endpoint)),
Expand Down Expand Up @@ -183,6 +201,13 @@ impl From<Either<figment::Error, std::io::Error>> for Error {
}
}

#[cfg(feature = "proxy-proto")]
impl From<Either<figment::Error, Either<figment::Error, std::io::Error>>> for Error {
fn from(value: Either<figment::Error, Either<figment::Error, std::io::Error>>) -> Self {
value.either(Error::Config, Error::from)
}
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Expand Down
3 changes: 3 additions & 0 deletions core/lib/src/listener/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ mod default;
mod endpoint;
mod listener;

#[cfg(feature = "proxy-proto")]
#[cfg_attr(nightly, doc(cfg(feature = "proxy-proto")))]
pub mod proxy;
#[cfg(feature = "http3-preview")]
pub mod quic;
pub mod tcp;
Expand Down
Loading
Loading