aster_forge_actix_middleware/
client_ip.rs1use std::net::IpAddr;
8
9use actix_web::http::header::HeaderMap;
10use ipnet::IpNet;
11
12pub fn real_ip_from_headers(
17 headers: &HeaderMap,
18 peer: IpAddr,
19 trusted_proxies: &[String],
20) -> IpAddr {
21 let trusted = aster_forge_utils::net::parse_trusted_proxies(trusted_proxies);
22 real_ip_from_trusted_headers(headers, peer, &trusted)
23}
24
25pub fn real_ip_from_trusted_headers(
27 headers: &HeaderMap,
28 peer: IpAddr,
29 trusted: &[IpNet],
30) -> IpAddr {
31 let x_forwarded_for = headers
32 .get("x-forwarded-for")
33 .and_then(|value| value.to_str().ok());
34 aster_forge_utils::net::real_ip_from_forwarded_for(x_forwarded_for, peer, trusted)
35}
36
37#[cfg(test)]
38mod tests {
39 use std::net::IpAddr;
40
41 use actix_web::test as actix_test;
42 use aster_forge_utils::net::{is_trusted_proxy, parse_trusted_proxies};
43
44 use super::{real_ip_from_headers, real_ip_from_trusted_headers};
45
46 #[test]
47 fn parses_trusted_proxies_as_cidr_and_single_ip() {
48 let trusted = parse_trusted_proxies(&["10.0.0.0/8".to_string(), "192.168.1.1".to_string()]);
49
50 assert!(is_trusted_proxy("10.0.0.5".parse().unwrap(), &trusted));
51 assert!(is_trusted_proxy("192.168.1.1".parse().unwrap(), &trusted));
52 assert!(!is_trusted_proxy("203.0.113.1".parse().unwrap(), &trusted));
53 }
54
55 #[test]
56 fn real_ip_uses_leftmost_forwarded_value_only_for_trusted_peer() {
57 let trusted = parse_trusted_proxies(&["10.0.0.0/8".to_string()]);
58 let req = actix_test::TestRequest::default()
59 .insert_header(("X-Forwarded-For", "203.0.113.10, 198.51.100.2"))
60 .to_srv_request();
61
62 assert_eq!(
63 real_ip_from_trusted_headers(
64 req.headers(),
65 "10.0.0.5".parse::<IpAddr>().unwrap(),
66 &trusted,
67 ),
68 "203.0.113.10".parse::<IpAddr>().unwrap()
69 );
70 assert_eq!(
71 real_ip_from_trusted_headers(
72 req.headers(),
73 "198.51.100.2".parse::<IpAddr>().unwrap(),
74 &trusted,
75 ),
76 "198.51.100.2".parse::<IpAddr>().unwrap()
77 );
78 }
79
80 #[test]
81 fn real_ip_falls_back_to_peer_for_invalid_header() {
82 let req = actix_test::TestRequest::default()
83 .insert_header(("X-Forwarded-For", "not-an-ip"))
84 .to_srv_request();
85
86 assert_eq!(
87 real_ip_from_headers(
88 req.headers(),
89 "10.0.0.5".parse::<IpAddr>().unwrap(),
90 &["10.0.0.0/8".to_string()],
91 ),
92 "10.0.0.5".parse::<IpAddr>().unwrap()
93 );
94 }
95
96 #[test]
97 fn real_ip_accepts_forwarded_values_with_ports() {
98 let trusted = parse_trusted_proxies(&["10.0.0.0/8".to_string()]);
99
100 for (forwarded, expected) in [
101 ("203.0.113.10:54321, 10.0.0.5", "203.0.113.10"),
102 ("[2001:db8::1]:443, 10.0.0.5", "2001:db8::1"),
103 ] {
104 let req = actix_test::TestRequest::default()
105 .insert_header(("X-Forwarded-For", forwarded))
106 .to_srv_request();
107
108 assert_eq!(
109 real_ip_from_trusted_headers(
110 req.headers(),
111 "10.0.0.5".parse::<IpAddr>().unwrap(),
112 &trusted,
113 ),
114 expected.parse::<IpAddr>().unwrap()
115 );
116 }
117 }
118}