ferron/modules/
x_forwarded_for.rs

1use std::error::Error;
2use std::net::{IpAddr, SocketAddr};
3
4use crate::ferron_common::{
5  ErrorLogger, HyperResponse, RequestData, ResponseData, ServerConfig, ServerModule,
6  ServerModuleHandlers, SocketData,
7};
8use crate::ferron_common::{HyperUpgraded, WithRuntime};
9use async_trait::async_trait;
10use hyper::header::HeaderName;
11use hyper::StatusCode;
12use hyper_tungstenite::HyperWebsocket;
13use tokio::runtime::Handle;
14
15struct XForwardedForModule;
16
17pub fn server_module_init(
18) -> Result<Box<dyn ServerModule + Send + Sync>, Box<dyn Error + Send + Sync>> {
19  Ok(Box::new(XForwardedForModule::new()))
20}
21
22impl XForwardedForModule {
23  fn new() -> Self {
24    Self
25  }
26}
27
28impl ServerModule for XForwardedForModule {
29  fn get_handlers(&self, handle: Handle) -> Box<dyn ServerModuleHandlers + Send> {
30    Box::new(XForwardedForModuleHandlers { handle })
31  }
32}
33struct XForwardedForModuleHandlers {
34  handle: Handle,
35}
36
37#[async_trait]
38impl ServerModuleHandlers for XForwardedForModuleHandlers {
39  async fn request_handler(
40    &mut self,
41    request: RequestData,
42    config: &ServerConfig,
43    socket_data: &SocketData,
44    _error_logger: &ErrorLogger,
45  ) -> Result<ResponseData, Box<dyn Error + Send + Sync>> {
46    WithRuntime::new(self.handle.clone(), async move {
47      if config["enableIPSpoofing"].as_bool() == Some(true) {
48        let hyper_request = request.get_hyper_request();
49
50        if let Some(x_forwarded_for_value) = hyper_request
51          .headers()
52          .get(HeaderName::from_static("x-forwarded-for"))
53        {
54          let x_forwarded_for = x_forwarded_for_value.to_str()?;
55
56          let prepared_remote_ip_str = match x_forwarded_for.split(",").nth(0) {
57            Some(ip_address_str) => ip_address_str.replace(" ", ""),
58            None => {
59              return Ok(
60                ResponseData::builder(request)
61                  .status(StatusCode::BAD_REQUEST)
62                  .build(),
63              );
64            }
65          };
66
67          let prepared_remote_ip: IpAddr = match prepared_remote_ip_str.parse() {
68            Ok(ip_address) => ip_address,
69            Err(_) => {
70              return Ok(
71                ResponseData::builder(request)
72                  .status(StatusCode::BAD_REQUEST)
73                  .build(),
74              );
75            }
76          };
77
78          let new_socket_addr = SocketAddr::new(prepared_remote_ip, socket_data.remote_addr.port());
79
80          return Ok(
81            ResponseData::builder(request)
82              .new_remote_address(new_socket_addr)
83              .build(),
84          );
85        }
86
87        return Ok(ResponseData::builder(request).build());
88      }
89
90      Ok(ResponseData::builder(request).build())
91    })
92    .await
93  }
94
95  async fn proxy_request_handler(
96    &mut self,
97    request: RequestData,
98    _config: &ServerConfig,
99    _socket_data: &SocketData,
100    _error_logger: &ErrorLogger,
101  ) -> Result<ResponseData, Box<dyn Error + Send + Sync>> {
102    Ok(ResponseData::builder(request).build())
103  }
104
105  async fn response_modifying_handler(
106    &mut self,
107    response: HyperResponse,
108  ) -> Result<HyperResponse, Box<dyn Error + Send + Sync>> {
109    Ok(response)
110  }
111
112  async fn proxy_response_modifying_handler(
113    &mut self,
114    response: HyperResponse,
115  ) -> Result<HyperResponse, Box<dyn Error + Send + Sync>> {
116    Ok(response)
117  }
118
119  async fn connect_proxy_request_handler(
120    &mut self,
121    _upgraded_request: HyperUpgraded,
122    _connect_address: &str,
123    _config: &ServerConfig,
124    _socket_data: &SocketData,
125    _error_logger: &ErrorLogger,
126  ) -> Result<(), Box<dyn Error + Send + Sync>> {
127    Ok(())
128  }
129
130  fn does_connect_proxy_requests(&mut self) -> bool {
131    false
132  }
133
134  async fn websocket_request_handler(
135    &mut self,
136    _websocket: HyperWebsocket,
137    _uri: &hyper::Uri,
138    _headers: &hyper::HeaderMap,
139    _config: &ServerConfig,
140    _socket_data: &SocketData,
141    _error_logger: &ErrorLogger,
142  ) -> Result<(), Box<dyn Error + Send + Sync>> {
143    Ok(())
144  }
145
146  fn does_websocket_requests(&mut self, _config: &ServerConfig, _socket_data: &SocketData) -> bool {
147    false
148  }
149}