-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(http): [#184] Axum extractor for peer IP
It uses a wrapper for another extractor becuase that extractor cannot be optional. We need to get the rigth most IP in the X-Forwarded-For header only when the tracker is runnin gon reverse proxy. More info: imbolc/axum-client-ip#9 (comment)
- Loading branch information
1 parent
74ed592
commit 02e2516
Showing
11 changed files
with
156 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pub mod peer_ip; | ||
pub mod remote_client_ip; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
use std::net::IpAddr; | ||
use std::panic::Location; | ||
|
||
use axum::response::{IntoResponse, Response}; | ||
use thiserror::Error; | ||
|
||
use super::remote_client_ip::RemoteClientIp; | ||
use crate::http::axum_implementation::responses; | ||
|
||
#[derive(Error, Debug)] | ||
pub enum ResolutionError { | ||
#[error("missing the right most X-Forwarded-For IP (mandatory on reverse proxy tracker configuration) in {location}")] | ||
MissingRightMostXForwardedForIp { location: &'static Location<'static> }, | ||
#[error("cannot get the client IP from the connection info in {location}")] | ||
MissingClientIp { location: &'static Location<'static> }, | ||
} | ||
|
||
impl From<ResolutionError> for responses::error::Error { | ||
fn from(err: ResolutionError) -> Self { | ||
responses::error::Error { | ||
failure_reason: format!("{err}"), | ||
} | ||
} | ||
} | ||
|
||
/// It resolves the peer IP. | ||
/// | ||
/// # Errors | ||
/// | ||
/// Will return an error if the peer IP cannot be obtained according to the configuration. | ||
/// For example, if the IP is extracted from an HTTP header which is missing in the request. | ||
pub fn peer_ip(on_reverse_proxy: bool, remote_client_ip: &RemoteClientIp) -> Result<IpAddr, Response> { | ||
if on_reverse_proxy { | ||
if let Some(ip) = remote_client_ip.right_most_x_forwarded_for { | ||
Ok(ip) | ||
} else { | ||
Err( | ||
responses::error::Error::from(ResolutionError::MissingRightMostXForwardedForIp { | ||
location: Location::caller(), | ||
}) | ||
.into_response(), | ||
) | ||
} | ||
} else if let Some(ip) = remote_client_ip.connection_info_ip { | ||
Ok(ip) | ||
} else { | ||
Err(responses::error::Error::from(ResolutionError::MissingClientIp { | ||
location: Location::caller(), | ||
}) | ||
.into_response()) | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
src/http/axum_implementation/extractors/remote_client_ip.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
use std::net::{IpAddr, SocketAddr}; | ||
|
||
use axum::async_trait; | ||
use axum::extract::{ConnectInfo, FromRequestParts}; | ||
use axum::http::request::Parts; | ||
use axum::response::Response; | ||
use axum_client_ip::RightmostXForwardedFor; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
/// Given this request chain: | ||
/// | ||
/// client <-> http proxy 1 <-> http proxy 2 <-> server | ||
/// ip: 126.0.0.1 ip: 126.0.0.2 ip: 126.0.0.3 ip: 126.0.0.4 | ||
/// X-Forwarded-For: 126.0.0.1 X-Forwarded-For: 126.0.0.1,126.0.0.2 | ||
/// | ||
/// This extractor extracts these values from the HTTP headers and connection info. | ||
/// | ||
/// `right_most_x_forwarded_for` = 126.0.0.2 | ||
/// `connection_info_ip` = 126.0.0.1 | ||
/// | ||
/// More info about inner extractors :<https://github.com/imbolc/axum-client-ip> | ||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] | ||
pub struct RemoteClientIp { | ||
pub right_most_x_forwarded_for: Option<IpAddr>, | ||
pub connection_info_ip: Option<IpAddr>, | ||
} | ||
|
||
#[async_trait] | ||
impl<S> FromRequestParts<S> for RemoteClientIp | ||
where | ||
S: Send + Sync, | ||
{ | ||
type Rejection = Response; | ||
|
||
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> { | ||
let right_most_x_forwarded_for = match RightmostXForwardedFor::from_request_parts(parts, state).await { | ||
Ok(right_most_x_forwarded_for) => Some(right_most_x_forwarded_for.0), | ||
Err(_) => None, | ||
}; | ||
|
||
let connection_info_ip = match ConnectInfo::<SocketAddr>::from_request_parts(parts, state).await { | ||
Ok(connection_info_socket_addr) => Some(connection_info_socket_addr.0.ip()), | ||
Err(_) => None, | ||
}; | ||
|
||
Ok(RemoteClientIp { | ||
right_most_x_forwarded_for, | ||
connection_info_ip, | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,12 @@ | ||
/// Temporary handler for testing and debugging the new Axum implementation | ||
/// It should be removed once the migration to Axum is finished. | ||
use axum::response::Json; | ||
use axum_client_ip::{InsecureClientIp, SecureClientIp}; | ||
|
||
use crate::http::axum_implementation::extractors::remote_client_ip::RemoteClientIp; | ||
use crate::http::axum_implementation::resources::ok::Ok; | ||
use crate::http::axum_implementation::responses::ok; | ||
|
||
#[allow(clippy::unused_async)] | ||
pub async fn get_status_handler(insecure_ip: InsecureClientIp, secure_ip: SecureClientIp) -> Json<Ok> { | ||
ok::response(&insecure_ip.0, &secure_ip.0) | ||
pub async fn get_status_handler(remote_client_ip: RemoteClientIp) -> Json<Ok> { | ||
ok::response(&remote_client_ip) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
pub mod extractors; | ||
pub mod handlers; | ||
pub mod query; | ||
pub mod requests; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,8 @@ | ||
use std::net::IpAddr; | ||
|
||
use serde::{Deserialize, Serialize}; | ||
|
||
use crate::http::axum_implementation::extractors::remote_client_ip::RemoteClientIp; | ||
|
||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] | ||
pub struct Ok { | ||
pub remote_client_insecure_ip: IpAddr, | ||
pub remote_client_secure_ip: IpAddr, | ||
pub remote_client_ip: RemoteClientIp, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,11 @@ | ||
use std::net::IpAddr; | ||
|
||
use axum::Json; | ||
|
||
use crate::http::axum_implementation::extractors::remote_client_ip::RemoteClientIp; | ||
use crate::http::axum_implementation::resources::ok::Ok; | ||
|
||
#[must_use] | ||
pub fn response(remote_client_insecure_ip: &IpAddr, remote_client_secure_ip: &IpAddr) -> Json<Ok> { | ||
pub fn response(remote_client_ip: &RemoteClientIp) -> Json<Ok> { | ||
Json(Ok { | ||
remote_client_insecure_ip: *remote_client_insecure_ip, | ||
remote_client_secure_ip: *remote_client_secure_ip, | ||
remote_client_ip: remote_client_ip.clone(), | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters