trusted_proxies/
config.rs

1use core::net::IpAddr;
2
3use ipnet::{AddrParseError, IpNet};
4
5/// Config for trusted proxies extractor
6///
7/// By default, it trusts the following:
8///   - IPV4 Loopback
9///   - IPV4 Private Networks
10///   - IPV6 Loopback
11///   - IPV6 Private Networks
12///
13/// It also trusts the `Forwarded` and `X-Forwarded-For` header by default.
14///
15/// # Example
16/// ```
17/// use trusted_proxies::Config;
18///
19/// let mut config = Config::new_local();
20/// config.add_trusted_ip("168.10.0.0/16").unwrap();
21/// config.trust_x_forwarded_host();
22///
23/// ```
24#[derive(Debug, Clone)]
25pub struct Config {
26    trusted_ips: Vec<IpNet>,
27    pub(crate) is_forwarded_trusted: bool,
28    pub(crate) is_x_forwarded_for_trusted: bool,
29    pub(crate) is_x_forwarded_host_trusted: bool,
30    pub(crate) is_x_forwarded_proto_trusted: bool,
31    pub(crate) is_x_forwarded_by_trusted: bool,
32}
33
34impl Default for Config {
35    fn default() -> Self {
36        Self::new_local()
37    }
38}
39
40impl Config {
41    /// Create a new TrustedProxies instance with no trusted proxies or headers
42    pub fn new() -> Self {
43        Self {
44            trusted_ips: Vec::new(),
45            is_forwarded_trusted: false,
46            is_x_forwarded_for_trusted: false,
47            is_x_forwarded_host_trusted: false,
48            is_x_forwarded_proto_trusted: false,
49            is_x_forwarded_by_trusted: false,
50        }
51    }
52
53    /// Create a new TrustedProxies instance with local and private networks ip trusted and FORWARDED / X-Forwarded-For headers trusted
54    pub fn new_local() -> Self {
55        Self {
56            trusted_ips: vec![
57                // IPV4 Loopback
58                "127.0.0.0/8".parse().unwrap(),
59                // IPV4 Private Networks
60                "10.0.0.0/8".parse().unwrap(),
61                "172.16.0.0/12".parse().unwrap(),
62                "192.168.0.0/16".parse().unwrap(),
63                // IPV6 Loopback
64                "::1/128".parse().unwrap(),
65                // IPV6 Private network
66                "fd00::/8".parse().unwrap(),
67            ],
68            is_forwarded_trusted: true,
69            is_x_forwarded_for_trusted: true,
70            is_x_forwarded_host_trusted: false,
71            is_x_forwarded_proto_trusted: false,
72            is_x_forwarded_by_trusted: false,
73        }
74    }
75
76    /// Add a trusted proxy to the list of trusted proxies
77    ///
78    /// proxy can be an IP address or a CIDR
79    pub fn add_trusted_ip(&mut self, proxy: &str) -> Result<(), AddrParseError> {
80        match proxy.parse() {
81            Ok(v) => {
82                self.trusted_ips.push(v);
83
84                Ok(())
85            }
86            Err(e) => match proxy.parse::<IpAddr>() {
87                Ok(v) => {
88                    self.trusted_ips.push(IpNet::from(v));
89
90                    Ok(())
91                }
92                _ => Err(e),
93            },
94        }
95    }
96
97    /// Check if a remote address is trusted given the list of trusted proxies
98    pub fn is_ip_trusted(&self, remote_addr: &IpAddr) -> bool {
99        for proxy in &self.trusted_ips {
100            if proxy.contains(remote_addr) {
101                return true;
102            }
103        }
104
105        false
106    }
107
108    /// Trust the `Forwarded` header
109    pub fn trust_forwarded(&mut self) {
110        self.is_forwarded_trusted = true;
111    }
112
113    /// Trust the `X-Forwarded-For` header
114    pub fn trust_x_forwarded_for(&mut self) {
115        self.is_x_forwarded_for_trusted = true;
116    }
117
118    /// Trust the `X-Forwarded-Host` header to fetch the host and optionally the port
119    ///
120    /// It is not recommended to trust this header as it can be easily spoofed, however you can trust
121    /// it if you are behind a reverse proxy that **always** sets this header.
122    ///
123    /// If there is multiple values in the header, the last one is used, even if there is multiple
124    /// proxies in the chain.
125    ///
126    /// If you need to get the original value with multiple proxies in the chain, you can use the
127    /// `Forwarded` header that allows to do that in a secure way.
128    /// See [RFC7239](https://tools.ietf.org/html/rfc7239) for more information.
129    pub fn trust_x_forwarded_host(&mut self) {
130        self.is_x_forwarded_host_trusted = true;
131    }
132
133    /// Trust the `X-Forwarded-Proto` header to fetch the scheme
134    ///
135    /// It is not recommended to trust this header as it can be easily spoofed, however you can trust
136    /// it if you are behind a reverse proxy that **always** sets this header.
137    ///
138    /// If there is multiple values in the header, the last one is used, even if there is multiple
139    /// proxies in the chain.
140    ///
141    /// If you need to get the original value with multiple proxies in the chain, you can use the
142    /// `Forwarded` header that allows to do that in a secure way.
143    /// See [RFC7239](https://tools.ietf.org/html/rfc7239) for more information.
144    pub fn trust_x_forwarded_proto(&mut self) {
145        self.is_x_forwarded_proto_trusted = true;
146    }
147
148    /// Trust the `X-Forwarded-By` header to identify the proxy that sent the request
149    ///
150    /// It is not recommended to trust this header as it can be easily spoofed, however you can trust
151    /// it if you are behind a reverse proxy that **always** sets this header.
152    ///
153    /// If there is multiple values in the header, the last one is used, even if there is multiple
154    /// proxies in the chain.
155    ///
156    /// If you need to get the original value with multiple proxies in the chain, you can use the
157    /// `Forwarded` header that allows to do that in a secure way.
158    /// See [RFC7239](https://tools.ietf.org/html/rfc7239) for more information.
159    pub fn trust_x_forwarded_by(&mut self) {
160        self.is_x_forwarded_by_trusted = true;
161    }
162}