trusted_proxies/
config.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
use core::net::IpAddr;

use ipnet::{AddrParseError, IpNet};

/// Config for trusted proxies extractor
///
/// By default, it trusts the following:
///   - IPV4 Loopback
///   - IPV4 Private Networks
///   - IPV6 Loopback
///   - IPV6 Private Networks
///
/// It also trusts the `Forwarded` and `X-Forwarded-For` header by default.
///
/// # Example
/// ```
/// use trusted_proxies::Config;
///
/// let mut config = Config::new_local();
/// config.add_trusted_ip("168.10.0.0/16").unwrap();
/// config.trust_x_forwarded_host();
///
/// ```
#[derive(Debug, Clone)]
pub struct Config {
    trusted_ips: Vec<IpNet>,
    pub(crate) is_forwarded_trusted: bool,
    pub(crate) is_x_forwarded_for_trusted: bool,
    pub(crate) is_x_forwarded_host_trusted: bool,
    pub(crate) is_x_forwarded_proto_trusted: bool,
    pub(crate) is_x_forwarded_by_trusted: bool,
}

impl Default for Config {
    fn default() -> Self {
        Self::new_local()
    }
}

impl Config {
    /// Create a new TrustedProxies instance with no trusted proxies or headers
    pub fn new() -> Self {
        Self {
            trusted_ips: Vec::new(),
            is_forwarded_trusted: false,
            is_x_forwarded_for_trusted: false,
            is_x_forwarded_host_trusted: false,
            is_x_forwarded_proto_trusted: false,
            is_x_forwarded_by_trusted: false,
        }
    }

    /// Create a new TrustedProxies instance with local and private networks ip trusted and FORWARDED / X-Forwarded-For headers trusted
    pub fn new_local() -> Self {
        Self {
            trusted_ips: vec![
                // IPV4 Loopback
                "127.0.0.0/8".parse().unwrap(),
                // IPV4 Private Networks
                "10.0.0.0/8".parse().unwrap(),
                "172.16.0.0/12".parse().unwrap(),
                "192.168.0.0/16".parse().unwrap(),
                // IPV6 Loopback
                "::1/128".parse().unwrap(),
                // IPV6 Private network
                "fd00::/8".parse().unwrap(),
            ],
            is_forwarded_trusted: true,
            is_x_forwarded_for_trusted: true,
            is_x_forwarded_host_trusted: false,
            is_x_forwarded_proto_trusted: false,
            is_x_forwarded_by_trusted: false,
        }
    }

    /// Add a trusted proxy to the list of trusted proxies
    ///
    /// proxy can be an IP address or a CIDR
    pub fn add_trusted_ip(&mut self, proxy: &str) -> Result<(), AddrParseError> {
        match proxy.parse() {
            Ok(v) => {
                self.trusted_ips.push(v);

                Ok(())
            }
            Err(e) => match proxy.parse::<IpAddr>() {
                Ok(v) => {
                    self.trusted_ips.push(IpNet::from(v));

                    Ok(())
                }
                _ => Err(e),
            },
        }
    }

    /// Check if a remote address is trusted given the list of trusted proxies
    pub fn is_ip_trusted(&self, remote_addr: &IpAddr) -> bool {
        for proxy in &self.trusted_ips {
            if proxy.contains(remote_addr) {
                return true;
            }
        }

        false
    }

    /// Trust the `Forwarded` header
    pub fn trust_forwarded(&mut self) {
        self.is_forwarded_trusted = true;
    }

    /// Trust the `X-Forwarded-For` header
    pub fn trust_x_forwarded_for(&mut self) {
        self.is_x_forwarded_for_trusted = true;
    }

    /// Trust the `X-Forwarded-Host` header to fetch the host and optionally the port
    ///
    /// It is not recommended to trust this header as it can be easily spoofed, however you can trust
    /// it if you are behind a reverse proxy that **always** sets this header.
    ///
    /// If there is multiple values in the header, the last one is used, even if there is multiple
    /// proxies in the chain.
    ///
    /// If you need to get the original value with multiple proxies in the chain, you can use the
    /// `Forwarded` header that allows to do that in a secure way.
    /// See [RFC7239](https://tools.ietf.org/html/rfc7239) for more information.
    pub fn trust_x_forwarded_host(&mut self) {
        self.is_x_forwarded_host_trusted = true;
    }

    /// Trust the `X-Forwarded-Proto` header to fetch the scheme
    ///
    /// It is not recommended to trust this header as it can be easily spoofed, however you can trust
    /// it if you are behind a reverse proxy that **always** sets this header.
    ///
    /// If there is multiple values in the header, the last one is used, even if there is multiple
    /// proxies in the chain.
    ///
    /// If you need to get the original value with multiple proxies in the chain, you can use the
    /// `Forwarded` header that allows to do that in a secure way.
    /// See [RFC7239](https://tools.ietf.org/html/rfc7239) for more information.
    pub fn trust_x_forwarded_proto(&mut self) {
        self.is_x_forwarded_proto_trusted = true;
    }

    /// Trust the `X-Forwarded-By` header to identify the proxy that sent the request
    ///
    /// It is not recommended to trust this header as it can be easily spoofed, however you can trust
    /// it if you are behind a reverse proxy that **always** sets this header.
    ///
    /// If there is multiple values in the header, the last one is used, even if there is multiple
    /// proxies in the chain.
    ///
    /// If you need to get the original value with multiple proxies in the chain, you can use the
    /// `Forwarded` header that allows to do that in a secure way.
    /// See [RFC7239](https://tools.ietf.org/html/rfc7239) for more information.
    pub fn trust_x_forwarded_by(&mut self) {
        self.is_x_forwarded_by_trusted = true;
    }
}