From 56101231bef15dfa49efed07c514c5b3a7537cd2 Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 21 Jan 2026 12:19:57 +0100 Subject: [PATCH 1/6] Fix URI in request headers to match target service --- src/lib.rs | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index b88a2c5..b9e69c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -163,9 +163,20 @@ impl ProxyServer { // Setup a request handler let service = service_fn(move |mut req| { + // Change the request uri to match the target service + let new_uri = rewrite_uri_authority(req.uri(), &target); + *req.uri_mut() = new_uri; + let headers = req.headers_mut(); + + // Add or update the HOST header + if let Ok(host_header_value) = target.parse() { + headers.insert(http::header::HOST, host_header_value); + } else { + error!("Failed to encode host as header value: {target}"); + } + // If we have measurements, from the remote peer, add them to the request header let measurements = measurements.clone(); - let headers = req.headers_mut(); if let Some(measurements) = measurements { match measurements.to_header_format() { Ok(header_value) => { @@ -508,6 +519,29 @@ impl ProxyClient { } } +/// Given an http request, update the host in the URI when proxying +fn rewrite_uri_authority(old_uri: &http::Uri, new_authority: &str) -> http::Uri { + let path_and_query = old_uri + .path_and_query() + .map(|pq| pq.as_str()) + .unwrap_or("/"); + + let scheme = old_uri.scheme_str().unwrap_or("http"); + + match http::Uri::builder() + .scheme(scheme) + .authority(new_authority) + .path_and_query(path_and_query) + .build() + { + Ok(new_uri) => new_uri, + Err(err) => { + tracing::error!("Failed to build URI - falling back to old one: {err}"); + old_uri.clone() + } + } +} + /// An error when running a proxy client or server #[derive(Error, Debug)] pub enum ProxyError { From 55de9b4d7c591b7ea3ec4ef097fe952a179993c7 Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 21 Jan 2026 13:10:17 +0100 Subject: [PATCH 2/6] Add additional logging to debug issue with URI setting --- src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index b9e69c9..fe5355c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -165,7 +165,9 @@ impl ProxyServer { let service = service_fn(move |mut req| { // Change the request uri to match the target service let new_uri = rewrite_uri_authority(req.uri(), &target); + tracing::info!("Setting URI to: {new_uri}"); *req.uri_mut() = new_uri; + let headers = req.headers_mut(); // Add or update the HOST header @@ -521,11 +523,15 @@ impl ProxyClient { /// Given an http request, update the host in the URI when proxying fn rewrite_uri_authority(old_uri: &http::Uri, new_authority: &str) -> http::Uri { + tracing::info!("Updating URI in request - old URI: {old_uri} new_authority: {new_authority}"); + let path_and_query = old_uri .path_and_query() .map(|pq| pq.as_str()) .unwrap_or("/"); + tracing::info!("Path and query: {path_and_query}"); + let scheme = old_uri.scheme_str().unwrap_or("http"); match http::Uri::builder() From f6e7a63bb4f5c6735a9b5edec2ee7cfe9eae16d7 Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 21 Jan 2026 13:52:15 +0100 Subject: [PATCH 3/6] Dont set host in header as well as URI --- src/lib.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fe5355c..f66c796 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -170,13 +170,6 @@ impl ProxyServer { let headers = req.headers_mut(); - // Add or update the HOST header - if let Ok(host_header_value) = target.parse() { - headers.insert(http::header::HOST, host_header_value); - } else { - error!("Failed to encode host as header value: {target}"); - } - // If we have measurements, from the remote peer, add them to the request header let measurements = measurements.clone(); if let Some(measurements) = measurements { From f11ca8db6443055ff65a2f878f5d3920a51caf60 Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 21 Jan 2026 15:04:51 +0100 Subject: [PATCH 4/6] Set host only in the header - dont touch the URI --- src/lib.rs | 42 ++++++++++-------------------------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f66c796..06b16e4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -163,13 +163,18 @@ impl ProxyServer { // Setup a request handler let service = service_fn(move |mut req| { - // Change the request uri to match the target service - let new_uri = rewrite_uri_authority(req.uri(), &target); - tracing::info!("Setting URI to: {new_uri}"); - *req.uri_mut() = new_uri; - let headers = req.headers_mut(); + // Add or update the HOST header + if let Ok(host_header_value) = target.parse() { + let old_value = headers.insert(http::header::HOST, host_header_value); + tracing::info!( + "Updating Host header - old value: {old_value:?} new value: {target}", + ); + } else { + error!("Failed to encode host as header value: {target}"); + } + // If we have measurements, from the remote peer, add them to the request header let measurements = measurements.clone(); if let Some(measurements) = measurements { @@ -514,33 +519,6 @@ impl ProxyClient { } } -/// Given an http request, update the host in the URI when proxying -fn rewrite_uri_authority(old_uri: &http::Uri, new_authority: &str) -> http::Uri { - tracing::info!("Updating URI in request - old URI: {old_uri} new_authority: {new_authority}"); - - let path_and_query = old_uri - .path_and_query() - .map(|pq| pq.as_str()) - .unwrap_or("/"); - - tracing::info!("Path and query: {path_and_query}"); - - let scheme = old_uri.scheme_str().unwrap_or("http"); - - match http::Uri::builder() - .scheme(scheme) - .authority(new_authority) - .path_and_query(path_and_query) - .build() - { - Ok(new_uri) => new_uri, - Err(err) => { - tracing::error!("Failed to build URI - falling back to old one: {err}"); - old_uri.clone() - } - } -} - /// An error when running a proxy client or server #[derive(Error, Debug)] pub enum ProxyError { From a9422208198024712b7d262c0ce695005e378696 Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 21 Jan 2026 17:32:42 +0100 Subject: [PATCH 5/6] Set x-forwarded-for header --- src/lib.rs | 45 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 06b16e4..d48d884 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ pub mod websockets; pub use attestation::AttestationGenerator; use bytes::Bytes; -use http::HeaderValue; +use http::{HeaderName, HeaderValue}; use http_body_util::{combinators::BoxBody, BodyExt}; use hyper::{service::service_fn, Response}; use hyper_util::rt::TokioIo; @@ -45,6 +45,12 @@ const ATTESTATION_TYPE_HEADER: &str = "X-Flashbots-Attestation-Type"; /// The header name for giving measurements const MEASUREMENT_HEADER: &str = "X-Flashbots-Measurement"; +/// The header name for giving the forwarded for IP +static X_FORWARDED_FOR: HeaderName = HeaderName::from_static("x-forwarded-for"); + +/// The header name for giving the 'real IP' - in our case that of the client +static X_REAL_IP: HeaderName = HeaderName::from_static("x-real-ip"); + /// The longest time in seconds to wait between reconnection attempts const SERVER_RECONNECT_MAX_BACKOFF_SECS: u64 = 120; @@ -122,15 +128,20 @@ impl ProxyServer { /// Accept an incoming connection and handle it in a seperate task pub async fn accept(&self) -> Result<(), ProxyError> { let target = self.target.clone(); - let (inbound, _client_addr) = self.listener.accept().await?; + let (inbound, client_addr) = self.listener.accept().await?; let attested_tls_server = self.attested_tls_server.clone(); tokio::spawn(async move { match attested_tls_server.handle_connection(inbound).await { Ok((tls_stream, measurements, attestation_type)) => { - if let Err(err) = - Self::handle_connection(tls_stream, measurements, attestation_type, target) - .await + if let Err(err) = Self::handle_connection( + tls_stream, + measurements, + attestation_type, + target, + client_addr, + ) + .await { warn!("Failed to handle connection: {err}"); } @@ -155,6 +166,7 @@ impl ProxyServer { measurements: Option, remote_attestation_type: AttestationType, target: String, + client_addr: SocketAddr, ) -> Result<(), ProxyError> { tracing::debug!("proxy-server accepted connection"); @@ -175,6 +187,29 @@ impl ProxyServer { error!("Failed to encode host as header value: {target}"); } + // Add the x-real-ip header + let client_ip = client_addr.ip().to_string(); + if let Ok(real_ip_value) = HeaderValue::from_str(&client_ip) { + headers.insert(&X_REAL_IP, real_ip_value); + } else { + error!("Failed to encode x-real-ip header value: {client_ip}"); + } + + // Add or update the x-forwarded-for header + let new_x_forwarded_for = + match headers.get(&X_FORWARDED_FOR).and_then(|v| v.to_str().ok()) { + Some(existing) if !existing.trim().is_empty() => { + format!("{}, {}", existing.trim(), client_ip) + } + _ => client_ip.clone(), + }; + + if let Ok(forwarded_for_value) = HeaderValue::from_str(&new_x_forwarded_for) { + headers.insert(&X_FORWARDED_FOR, forwarded_for_value); + } else { + error!("Failed to encode x-forwarded-for header value: {new_x_forwarded_for}"); + } + // If we have measurements, from the remote peer, add them to the request header let measurements = measurements.clone(); if let Some(measurements) = measurements { From 47e4946eaa9612333ed464c54e7a4c45ffbb4dbd Mon Sep 17 00:00:00 2001 From: peg Date: Thu, 22 Jan 2026 11:38:17 +0100 Subject: [PATCH 6/6] Use helper fn for updating http headers --- src/lib.rs | 58 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d48d884..8d33f1e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ pub mod websockets; pub use attestation::AttestationGenerator; use bytes::Bytes; -use http::{HeaderName, HeaderValue}; +use http::{HeaderMap, HeaderName, HeaderValue}; use http_body_util::{combinators::BoxBody, BodyExt}; use hyper::{service::service_fn, Response}; use hyper_util::rt::TokioIo; @@ -178,22 +178,12 @@ impl ProxyServer { let headers = req.headers_mut(); // Add or update the HOST header - if let Ok(host_header_value) = target.parse() { - let old_value = headers.insert(http::header::HOST, host_header_value); - tracing::info!( - "Updating Host header - old value: {old_value:?} new value: {target}", - ); - } else { - error!("Failed to encode host as header value: {target}"); - } + let old_value = update_header(headers, &http::header::HOST, &target); + tracing::info!("Updating Host header - old value: {old_value:?} new value: {target}",); // Add the x-real-ip header let client_ip = client_addr.ip().to_string(); - if let Ok(real_ip_value) = HeaderValue::from_str(&client_ip) { - headers.insert(&X_REAL_IP, real_ip_value); - } else { - error!("Failed to encode x-real-ip header value: {client_ip}"); - } + update_header(headers, &X_REAL_IP, &client_ip); // Add or update the x-forwarded-for header let new_x_forwarded_for = @@ -204,11 +194,7 @@ impl ProxyServer { _ => client_ip.clone(), }; - if let Ok(forwarded_for_value) = HeaderValue::from_str(&new_x_forwarded_for) { - headers.insert(&X_FORWARDED_FOR, forwarded_for_value); - } else { - error!("Failed to encode x-forwarded-for header value: {new_x_forwarded_for}"); - } + update_header(headers, &X_FORWARDED_FOR, &new_x_forwarded_for); // If we have measurements, from the remote peer, add them to the request header let measurements = measurements.clone(); @@ -224,10 +210,11 @@ impl ProxyServer { } } } - headers.insert( + + update_header( + headers, ATTESTATION_TYPE_HEADER, - HeaderValue::from_str(remote_attestation_type.as_str()) - .expect("Attestation type should be able to be encoded as a header value"), + remote_attestation_type.as_str(), ); let target = target.clone(); @@ -392,11 +379,11 @@ impl ProxyClient { } } } - headers.insert( + + update_header( + headers, ATTESTATION_TYPE_HEADER, - HeaderValue::from_str(remote_attestation_type.as_str()).expect( - "Attestation type should be able to be encoded as a header value", - ), + remote_attestation_type.as_str(), ); (Ok(resp.map(|b| b.boxed())), false) } @@ -554,6 +541,25 @@ impl ProxyClient { } } +/// Update a request/response header if we are able to encode the header value +/// +/// This avoids bailing on bad header values - the headers are simply not updated +fn update_header( + headers: &mut HeaderMap, + header_name: K, + header_value: &str, +) -> Option +where + K: http::header::IntoHeaderName + std::fmt::Display, +{ + if let Ok(value) = HeaderValue::from_str(header_value) { + headers.insert(header_name, value) + } else { + error!("Failed to encode {header_name} header value: {header_value}"); + None + } +} + /// An error when running a proxy client or server #[derive(Error, Debug)] pub enum ProxyError {