rocket_client_addr/
resolve.rs1use std::net::IpAddr;
2
3use rocket::http::HeaderMap;
4
5use crate::{
6 ChainHeader, ClientIp, ClientIpConfig, ClientIpSource, TrustAllChainIpSelection,
7 TrustAllProxyMode,
8 canonical::canonical_ip,
9 config::{ChainHeaderKind, TrustModel},
10 headers::{
11 ChainEntry, configured_client_ip_header, forwarded_entries, header_lines,
12 list_header_entries,
13 },
14};
15
16impl ClientIpConfig {
17 pub fn resolve_client_ip(&self, headers: &HeaderMap<'_>, peer_ip: IpAddr) -> ClientIp {
21 let peer_ip = canonical_ip(peer_ip);
22
23 match &self.trust {
24 TrustModel::NoProxy => ClientIp::new(peer_ip, ClientIpSource::Socket),
25 TrustModel::TrustedProxies {
26 chain_header_order, ..
27 } => resolve_client_ip_from_trusted_proxies(headers, peer_ip, self, chain_header_order),
28 TrustModel::TrustAllProxies(mode) => {
29 resolve_client_ip_trusting_all_proxies(headers, peer_ip, mode)
30 },
31 }
32 }
33}
34
35fn resolve_client_ip_from_trusted_proxies(
37 headers: &HeaderMap<'_>,
38 socket_ip: IpAddr,
39 config: &ClientIpConfig,
40 chain_header_order: &[ChainHeader],
41) -> ClientIp {
42 let Some(socket_proxy_rule) = config.rule_for(socket_ip) else {
44 return ClientIp::new(socket_ip, ClientIpSource::Socket);
45 };
46
47 if let Some(header) = socket_proxy_rule.client_ip_header()
48 && let Some(ip) = configured_client_ip_header(headers, header)
49 {
50 return ClientIp::new(ip, ClientIpSource::ConfiguredHeader(header.clone()));
51 }
52
53 if let Some((ip, source)) =
55 client_ip_from_chain_headers(headers, chain_header_order, |entries| {
56 first_non_trusted_from_right(entries, config)
57 })
58 {
59 return ClientIp::new(ip, source);
60 }
61
62 ClientIp::new(socket_ip, ClientIpSource::Socket)
63}
64
65fn resolve_client_ip_trusting_all_proxies(
67 headers: &HeaderMap<'_>,
68 socket_ip: IpAddr,
69 mode: &TrustAllProxyMode,
70) -> ClientIp {
71 if let Some(header) = mode.client_ip_header()
72 && let Some(ip) = configured_client_ip_header(headers, header)
73 {
74 return ClientIp::new(ip, ClientIpSource::ConfiguredHeader(header.clone()));
75 }
76
77 if let Some((ip, source)) =
78 client_ip_from_chain_headers(headers, mode.chain_header_order(), |entries| {
79 select_trust_all_chain_ip(entries, mode.chain_ip_selection())
80 })
81 {
82 return ClientIp::new(ip, source);
83 }
84
85 ClientIp::new(socket_ip, ClientIpSource::Socket)
86}
87
88fn client_ip_from_chain_headers(
94 headers: &HeaderMap<'_>,
95 chain_header_order: &[ChainHeader],
96 mut pick: impl FnMut(&mut dyn DoubleEndedIterator<Item = ChainEntry>) -> Option<IpAddr>,
97) -> Option<(IpAddr, ClientIpSource)> {
98 for chain_header in chain_header_order {
99 let header = chain_header.as_header_name();
100 let lines = header_lines(headers, header);
101
102 if lines.is_empty() {
103 continue;
104 }
105
106 let ip = match chain_header.kind() {
107 ChainHeaderKind::Forwarded => {
108 let entries = forwarded_entries(lines)?;
109
110 pick(&mut entries.into_iter())
111 },
112 ChainHeaderKind::XForwardedFor => {
113 let mut entries = list_header_entries(lines)?;
114
115 pick(&mut entries)
116 },
117 };
118
119 return Some((ip?, ClientIpSource::ChainHeader(header.clone())));
121 }
122
123 None
124}
125
126fn select_trust_all_chain_ip(
128 entries: &mut dyn DoubleEndedIterator<Item = ChainEntry>,
129 selection: TrustAllChainIpSelection,
130) -> Option<IpAddr> {
131 let entry = match selection {
132 TrustAllChainIpSelection::Leftmost => entries.next(),
133 TrustAllChainIpSelection::Rightmost => entries.next_back(),
134 TrustAllChainIpSelection::SkipRightmostHops(hops) => entries.nth_back(hops),
136 }?;
137
138 match entry {
139 ChainEntry::Ip(ip) => Some(ip),
140 ChainEntry::Opaque => None,
141 }
142}
143
144fn first_non_trusted_from_right(
146 entries: &mut dyn DoubleEndedIterator<Item = ChainEntry>,
147 config: &ClientIpConfig,
148) -> Option<IpAddr> {
149 while let Some(entry) = entries.next_back() {
150 match entry {
151 ChainEntry::Ip(ip) if config.is_trusted_proxy(ip) => continue,
153 ChainEntry::Ip(ip) => return Some(ip),
154 ChainEntry::Opaque => return None,
156 }
157 }
158
159 None
160}