From 828d2300c0c02710c9064a7f465940cb503ed088 Mon Sep 17 00:00:00 2001 From: Jun Kurihara Date: Sat, 9 Jul 2022 12:37:50 +0900 Subject: [PATCH] add x-forwarded-proto --- docker-compose.yml | 4 +- src/proxy/proxy_handler.rs | 172 +++++++++++++++++++------------------ src/proxy/utils_headers.rs | 6 ++ 3 files changed, 96 insertions(+), 86 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4d90965..f6d9220 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,8 +10,8 @@ services: build: context: ./ environment: - - LOG_LEVEL=info - - LOG_TO_FILE + - LOG_LEVEL=debug + - LOG_TO_FILE=false tty: false privileged: true volumes: diff --git a/src/proxy/proxy_handler.rs b/src/proxy/proxy_handler.rs index 02b0bf9..6d3c8f4 100644 --- a/src/proxy/proxy_handler.rs +++ b/src/proxy/proxy_handler.rs @@ -70,7 +70,7 @@ where let request_upgraded = req.extensions_mut().remove::(); // Build request from destination information - let req_forwarded = if let Ok(req) = generate_request_forwarded( + let req_forwarded = if let Ok(req) = self.generate_request_forwarded( client_addr, req, upstream_scheme_host, @@ -149,7 +149,7 @@ where } } else { // Generate response to client - if generate_response_forwarded(&mut res_backend).is_ok() { + if self.generate_response_forwarded(&mut res_backend).is_ok() { info!("{} => {}", request_log, response_log); Ok(res_backend) } else { @@ -158,95 +158,99 @@ where } } } -} -//////////////////////////////////////////////////// -// Functions to generate messages + //////////////////////////////////////////////////// + // Functions to generate messages -fn generate_response_forwarded(response: &mut Response) -> Result<()> { - let headers = response.headers_mut(); - remove_hop_header(headers); - remove_connection_header(headers); - append_header_entry( - headers, - "server", - &format!("{}/{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")), - )?; + fn generate_response_forwarded( + &self, + response: &mut Response, + ) -> Result<()> { + let headers = response.headers_mut(); + remove_hop_header(headers); + remove_connection_header(headers); + append_header_entry( + headers, + "server", + &format!("{}/{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")), + )?; - Ok(()) -} + Ok(()) + } -fn generate_request_forwarded( - client_addr: SocketAddr, - mut req: Request, - upstream_scheme_host: &Uri, - upgrade: &Option, - upstream: &Upstream, -) -> Result> { - debug!("Generate request to be forwarded"); + fn generate_request_forwarded( + &self, + client_addr: SocketAddr, + mut req: Request, + upstream_scheme_host: &Uri, + upgrade: &Option, + upstream: &Upstream, + ) -> Result> { + debug!("Generate request to be forwarded"); - // Add te: trailer if contained in original request - let te_trailers = { - if let Some(te) = req.headers().get(header::TE) { - te.to_str()?.split(',').any(|x| x.trim() == "trailers") - } else { - false + // Add te: trailer if contained in original request + let te_trailers = { + if let Some(te) = req.headers().get(header::TE) { + te.to_str()?.split(',').any(|x| x.trim() == "trailers") + } else { + false + } + }; + + let headers = req.headers_mut(); + // delete headers specified in header.connection + remove_connection_header(headers); + // delete hop headers including header.connection + remove_hop_header(headers); + // X-Forwarded-For + add_forwarding_header(headers, client_addr, self.tls_enabled)?; + // println!("{:?}", headers); + + // Add te: trailer if te_trailer + if te_trailers { + headers.insert(header::TE, "trailer".parse()?); } - }; - let headers = req.headers_mut(); - // delete headers specified in header.connection - remove_connection_header(headers); - // delete hop headers including header.connection - remove_hop_header(headers); - // X-Forwarded-For - add_forwarding_header(headers, client_addr)?; - // println!("{:?}", headers); + // add "host" header of original server_name if not exist (default) + if req.headers().get(header::HOST).is_none() { + let org_host = req.uri().host().unwrap_or("none").to_owned(); + req + .headers_mut() + .insert(header::HOST, HeaderValue::from_str(org_host.as_str())?); + }; - // Add te: trailer if te_trailer - if te_trailers { - headers.insert(header::TE, "trailer".parse()?); + // apply upstream-specific headers given in upstream_option + let headers = req.headers_mut(); + apply_upstream_options_to_header(headers, client_addr, upstream_scheme_host, upstream)?; + + // update uri in request + ensure!(upstream_scheme_host.authority().is_some() && upstream_scheme_host.scheme().is_some()); + let new_uri = Uri::builder() + .scheme(upstream_scheme_host.scheme().unwrap().as_str()) + .authority(upstream_scheme_host.authority().unwrap().as_str()); + let pq = req.uri().path_and_query(); + *req.uri_mut() = match pq { + None => new_uri, + Some(x) => new_uri.path_and_query(x.to_owned()), + } + .build()?; + + // upgrade + if let Some(v) = upgrade { + req.headers_mut().insert("upgrade", v.parse()?); + req + .headers_mut() + .insert(header::CONNECTION, HeaderValue::from_str("upgrade")?); + } + + // Change version to http/1.1 when destination scheme is http + if req.version() != Version::HTTP_11 && upstream_scheme_host.scheme() == Some(&Scheme::HTTP) { + *req.version_mut() = Version::HTTP_11; + } else if req.version() == Version::HTTP_3 { + debug!("HTTP/3 is currently unsupported for request to upstream. Use HTTP/2."); + *req.version_mut() = Version::HTTP_2; + } + + Ok(req) } - - // add "host" header of original server_name if not exist (default) - if req.headers().get(header::HOST).is_none() { - let org_host = req.uri().host().unwrap_or("none").to_owned(); - req - .headers_mut() - .insert(header::HOST, HeaderValue::from_str(org_host.as_str())?); - }; - - // apply upstream-specific headers given in upstream_option - let headers = req.headers_mut(); - apply_upstream_options_to_header(headers, client_addr, upstream_scheme_host, upstream)?; - - // update uri in request - ensure!(upstream_scheme_host.authority().is_some() && upstream_scheme_host.scheme().is_some()); - let new_uri = Uri::builder() - .scheme(upstream_scheme_host.scheme().unwrap().as_str()) - .authority(upstream_scheme_host.authority().unwrap().as_str()); - let pq = req.uri().path_and_query(); - *req.uri_mut() = match pq { - None => new_uri, - Some(x) => new_uri.path_and_query(x.to_owned()), - } - .build()?; - - // upgrade - if let Some(v) = upgrade { - req.headers_mut().insert("upgrade", v.parse()?); - req - .headers_mut() - .insert(header::CONNECTION, HeaderValue::from_str("upgrade")?); - } - - // Change version to http/1.1 when destination scheme is http - if req.version() != Version::HTTP_11 && upstream_scheme_host.scheme() == Some(&Scheme::HTTP) { - *req.version_mut() = Version::HTTP_11; - } else if req.version() == Version::HTTP_3 { - debug!("HTTP/3 is currently unsupported for request to upstream. Use HTTP/2."); - *req.version_mut() = Version::HTTP_2; - } - - Ok(req) } diff --git a/src/proxy/utils_headers.rs b/src/proxy/utils_headers.rs index f751ca4..1790332 100644 --- a/src/proxy/utils_headers.rs +++ b/src/proxy/utils_headers.rs @@ -49,6 +49,7 @@ pub(super) fn append_header_entry( pub(super) fn add_forwarding_header( headers: &mut HeaderMap, client_addr: SocketAddr, + tls: bool, ) -> Result<()> { // default process // optional process defined by upstream_option is applied in fn apply_upstream_options @@ -57,6 +58,11 @@ pub(super) fn add_forwarding_header( "x-forwarded-for", &client_addr.to_canonical().ip().to_string(), )?; + append_header_entry( + headers, + "x-forwarded-proto", + if tls { "https" } else { "http" }, + )?; Ok(()) }