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}