Skip to content

Commit

Permalink
feat(http): add remote_addr to logs
Browse files Browse the repository at this point in the history
With this change, the remote address will be logged. This enables other
software, such as fail2ban, to monitor the logs and make actions if
required.

Closes #944
  • Loading branch information
NefixEstrada committed Feb 3, 2024
1 parent 79bfa3c commit 8e2b767
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 23 deletions.
11 changes: 8 additions & 3 deletions warpgate-protocol-http/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use async_trait::async_trait;
use common::page_admin_auth;
pub use common::PROTOCOL_NAME;
use http::HeaderValue;
use logging::{log_request_result, span_for_request};
use logging::{get_client_ip, log_request_result, span_for_request};
use poem::endpoint::{EmbeddedFileEndpoint, EmbeddedFilesEndpoint};
use poem::listener::{Listener, RustlsConfig, TcpListener};
use poem::middleware::SetHeader;
Expand Down Expand Up @@ -122,8 +122,11 @@ impl ProtocolServer for HTTPProtocolServer {
.around(move |ep, req| async move {
let method = req.method().clone();
let url = req.original_uri().clone();
let client_ip = get_client_ip(&req).await?;

let response = ep.call(req).await?;
log_request_result(&method, &url, &response.status());

log_request_result(&method, &url, client_ip, &response.status());
Ok(response)
}),
)
Expand Down Expand Up @@ -206,7 +209,9 @@ impl ProtocolServer for HTTPProtocolServer {

async fn test_target(&self, target: Target) -> Result<(), TargetTestError> {
let TargetOptions::Http(options) = target.options else {
return Err(TargetTestError::Misconfigured("Not an HTTP target".to_owned()));
return Err(TargetTestError::Misconfigured(
"Not an HTTP target".to_owned(),
));
};
let request = poem::Request::builder().uri_str("http://host/").finish();
crate::proxy::proxy_normal_request(&request, poem::Body::empty(), &options)
Expand Down
41 changes: 23 additions & 18 deletions warpgate-protocol-http/src/logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,8 @@ use crate::session_handle::WarpgateServerHandleFromRequest;

pub async fn span_for_request(req: &Request) -> poem::Result<Span> {
let handle = WarpgateServerHandleFromRequest::from_request_without_body(req).await;
let services: Data<&Services> = <_>::from_request_without_body(req).await?;
let config = services.config.lock().await;

let remote_ip = req
.remote_addr()
.as_socket_addr()
.map(|x| x.ip().to_string())
.unwrap_or("<unknown>".into());

let client_ip = match config.store.http.trust_x_forwarded_headers {
true => req
.header("x-forwarded-for")
.map(|x| x.to_string())
.unwrap_or(remote_ip),
false => remote_ip,
};
let client_ip = get_client_ip(req).await?;

Ok(match handle {
Ok(ref handle) => {
Expand All @@ -40,10 +26,29 @@ pub async fn span_for_request(req: &Request) -> poem::Result<Span> {
})
}

pub fn log_request_result(method: &Method, url: &Uri, status: &StatusCode) {
pub fn log_request_result(method: &Method, url: &Uri, client_ip: String, status: &StatusCode) {
if status.is_server_error() || status.is_client_error() {
warn!(%method, %url, %status, "Request failed");
warn!(%method, %url, %status, %client_ip, "Request failed");
} else {
info!(%method, %url, %status, "Request");
info!(%method, %url, %status, %client_ip, "Request");
}
}

pub async fn get_client_ip(req: &Request) -> poem::Result<String> {
let services: Data<&Services> = <_>::from_request_without_body(&req).await?;
let config = services.config.lock().await;

let remote_ip = req
.remote_addr()
.as_socket_addr()
.map(|x| x.ip().to_string())
.unwrap_or("<unknown>".into());

match config.store.http.trust_x_forwarded_headers {
true => Ok(req
.header("x-forwarded-for")
.map(|x| x.to_string())
.unwrap_or(remote_ip)),
false => Ok(remote_ip),
}
}
9 changes: 7 additions & 2 deletions warpgate-protocol-http/src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use url::Url;
use warpgate_common::{try_block, TargetHTTPOptions, TlsMode, WarpgateError};
use warpgate_web::lookup_built_file;

use crate::logging::log_request_result;
use crate::logging::{get_client_ip, log_request_result};

trait SomeResponse {
fn status(&self) -> http::StatusCode;
Expand Down Expand Up @@ -291,7 +291,12 @@ pub async fn proxy_normal_request(
copy_client_response(&client_response, &mut response);
copy_client_body(client_response, &mut response).await?;

log_request_result(req.method(), req.original_uri(), &status);
log_request_result(
req.method(),
req.original_uri(),
get_client_ip(req).await?,
&status,
);

rewrite_response(&mut response, options, &uri)?;
Ok(response)
Expand Down

0 comments on commit 8e2b767

Please sign in to comment.