1use crate::ip_utils::{match_ip, parse_ip};
7use actix_web::dev::Payload;
8use actix_web::web::Data;
9use actix_web::{Error, FromRequest, HttpRequest};
10use futures_util::future::{ready, Ready};
11use std::fmt::Display;
12use std::net::IpAddr;
13
14mod ip_utils;
15
16#[derive(Debug, Clone, Eq, PartialEq, Default)]
20pub struct RemoteIPConfig {
21 pub proxy: Option<String>,
23}
24
25impl RemoteIPConfig {
26 pub fn with_proxy_ip<D: Display>(proxy: D) -> Self {
29 Self {
30 proxy: Some(proxy.to_string()),
31 }
32 }
33}
34
35pub fn get_remote_ip(req: &HttpRequest) -> IpAddr {
37 let proxy = req
38 .app_data::<Data<RemoteIPConfig>>()
39 .map(|c| c.proxy.as_ref())
40 .unwrap_or_default();
41 log::trace!("Proxy IP: {:?}", proxy);
42
43 let mut ip = req.peer_addr().unwrap().ip();
44
45 if let Some(proxy) = proxy.as_ref() {
47 if match_ip(proxy, &ip.to_string()) {
48 if let Some(header) = req.headers().get("X-Forwarded-For") {
49 let header = header.to_str().unwrap();
50
51 let remote_ip = if let Some((upstream_ip, _)) = header.split_once(',') {
52 upstream_ip
53 } else {
54 header
55 };
56
57 if let Some(upstream_ip) = parse_ip(remote_ip) {
58 ip = upstream_ip;
59 }
60 }
61 }
62 }
63
64 ip
65}
66
67#[derive(Copy, Clone, Debug, Eq, PartialEq)]
68pub struct RemoteIP(pub IpAddr);
69
70impl From<RemoteIP> for IpAddr {
71 fn from(i: RemoteIP) -> Self {
72 i.0
73 }
74}
75
76impl FromRequest for RemoteIP {
77 type Error = Error;
78 type Future = Ready<Result<Self, Error>>;
79
80 #[inline]
81 fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
82 ready(Ok(RemoteIP(get_remote_ip(req))))
83 }
84}
85
86#[cfg(test)]
87mod test {
88 use std::net::{IpAddr, SocketAddr};
89 use std::str::FromStr;
90
91 use crate::{get_remote_ip, RemoteIPConfig};
92 use actix_web::test::TestRequest;
93 use actix_web::web::Data;
94
95 #[test]
96 fn test_get_remote_ip() {
97 let req = TestRequest::default()
98 .peer_addr(SocketAddr::from_str("192.168.1.1:1000").unwrap())
99 .to_http_request();
100 assert_eq!(
101 get_remote_ip(&req),
102 "192.168.1.1".parse::<IpAddr>().unwrap()
103 );
104 }
105
106 #[test]
107 fn test_get_remote_ip_from_proxy() {
108 let req = TestRequest::default()
109 .peer_addr(SocketAddr::from_str("192.168.1.1:1000").unwrap())
110 .insert_header(("X-Forwarded-For", "1.1.1.1"))
111 .app_data(Data::new(RemoteIPConfig::with_proxy_ip("192.168.1.1")))
112 .to_http_request();
113
114 assert_eq!(get_remote_ip(&req), "1.1.1.1".parse::<IpAddr>().unwrap());
115 }
116
117 #[test]
118 fn test_get_remote_ip_from_proxy_2() {
119 let req = TestRequest::default()
120 .peer_addr(SocketAddr::from_str("192.168.1.1:1000").unwrap())
121 .insert_header(("X-Forwarded-For", "1.1.1.1, 1.2.2.2"))
122 .app_data(Data::new(RemoteIPConfig::with_proxy_ip("192.168.1.1")))
123 .to_http_request();
124 assert_eq!(get_remote_ip(&req), "1.1.1.1".parse::<IpAddr>().unwrap());
125 }
126
127 #[test]
128 fn test_get_remote_ip_from_proxy_ipv6() {
129 let req = TestRequest::default()
130 .peer_addr(SocketAddr::from_str("192.168.1.1:1000").unwrap())
131 .insert_header(("X-Forwarded-For", "10::1, 1.2.2.2"))
132 .app_data(Data::new(RemoteIPConfig::with_proxy_ip("192.168.1.1")))
133 .to_http_request();
134
135 assert_eq!(get_remote_ip(&req), "10::".parse::<IpAddr>().unwrap());
136 }
137
138 #[test]
139 fn test_get_remote_ip_from_no_proxy() {
140 let req = TestRequest::default()
141 .peer_addr(SocketAddr::from_str("192.168.1.1:1000").unwrap())
142 .insert_header(("X-Forwarded-For", "1.1.1.1, 1.2.2.2"))
143 .to_http_request();
144
145 assert_eq!(
146 get_remote_ip(&req),
147 "192.168.1.1".parse::<IpAddr>().unwrap()
148 );
149 }
150
151 #[test]
152 fn test_get_remote_ip_from_other_proxy() {
153 let req = TestRequest::default()
154 .peer_addr(SocketAddr::from_str("192.168.1.1:1000").unwrap())
155 .insert_header(("X-Forwarded-For", "1.1.1.1, 1.2.2.2"))
156 .app_data(Data::new(RemoteIPConfig::with_proxy_ip("192.168.1.2")))
157 .to_http_request();
158
159 assert_eq!(
160 get_remote_ip(&req),
161 "192.168.1.1".parse::<IpAddr>().unwrap()
162 );
163 }
164}