Skip to content

Commit 2566d6b

Browse files
authored
bug: Handle private networks as trusted proxies (#53)
* bug: Handle private networks as trusted proxies Local private networks should be automatically considered proxies and skipped for metadata lookup. Closes #51
1 parent f4beedc commit 2566d6b

File tree

2 files changed

+52
-36
lines changed

2 files changed

+52
-36
lines changed

channelserver/src/main.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,22 +165,39 @@ fn main() {
165165
};
166166
let msettings = settings.clone();
167167
let mut trusted_list: Vec<ipnet::IpNet> = Vec::new();
168+
// Add the known private networks to the trusted proxy list
169+
trusted_list.push("10.0.0.0/8".parse().unwrap());
170+
trusted_list.push("172.16.0.0/12".parse().unwrap());
171+
trusted_list.push("192.168.0.0/16".parse().unwrap());
172+
168173
// Add the list of trusted proxies.
169174
if settings.trusted_proxy_list.len() > 0 {
170175
for mut proxy in settings.trusted_proxy_list.split(",") {
171176
proxy = proxy.trim();
172177
if proxy.len() > 0 {
173-
let addr: ipnet::IpNet = proxy.parse().unwrap();
174-
trusted_list.push(addr);
178+
// ipnet::IpNet only wants CIDRs. Normally that's not a problem, but the
179+
// user may specify a single address. In that case, force the single
180+
// into a CIDR by giving it a single address scope.
181+
let mut fixed = proxy.to_owned();
182+
if !proxy.contains("/") {
183+
fixed = format!("{}/32", proxy);
184+
debug!(log.log, "Fixing single address {}", fixed);
185+
}
186+
match fixed.parse::<ipnet::IpNet>() {
187+
Ok(addr) => trusted_list.push(addr),
188+
Err(err) => {
189+
error!(logger.log, r#"Ignoring unparsable IP address "{}"#, proxy);
190+
}
191+
};
175192
}
176193
}
177194
}
195+
debug!(logger.log, "Trusted Proxies: {:?}", trusted_list);
178196
// check that the maxmind db is where it should be.
179197
if !Path::new(&settings.mmdb_loc).exists() {
180-
slog_error!(
198+
error!(
181199
logger.log,
182-
"Cannot find geoip database: {}",
183-
settings.mmdb_loc
200+
"Cannot find geoip database: {}", settings.mmdb_loc
184201
);
185202
return;
186203
};

channelserver/src/meta.rs

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -127,24 +127,16 @@ fn get_ua(
127127
None
128128
}
129129

130-
fn is_trusted_proxy(proxy_list: &[IpNet], host: &str) -> Result<bool, HandlerError> {
131-
// Return if an address is NOT part of the allow list
132-
let test_addr: IpAddr = match host.parse() {
133-
Ok(addr) => addr,
134-
Err(e) => return Err(HandlerErrorKind::BadRemoteAddrError(format!("{:?}", e)).into()),
135-
};
136-
for proxy_range in proxy_list {
137-
if proxy_range.contains(&test_addr) {
138-
return Ok(true);
139-
}
140-
}
141-
Ok(false)
130+
fn is_trusted_proxy(proxy_list: &[IpNet], host: &IpAddr) -> bool {
131+
// Return if an address is part of the allow list
132+
proxy_list.iter().any(|range| range.contains(host))
142133
}
143134

144135
fn get_remote(
145136
peer: &Option<SocketAddr>,
146137
headers: &http::HeaderMap,
147138
proxy_list: &[IpNet],
139+
log: &logging::MozLogger,
148140
) -> Result<String, HandlerError> {
149141
// Actix determines the connection_info.remote() from the first entry in the
150142
// Forwarded then X-Fowarded-For, Forwarded-For, then peer name. The problem is that any
@@ -156,31 +148,36 @@ fn get_remote(
156148
if peer.is_none() {
157149
return Err(HandlerErrorKind::BadRemoteAddrError("Peer is unspecified".to_owned()).into());
158150
}
159-
let peer_ip = peer.unwrap().ip().to_string();
151+
let peer_ip = peer.unwrap().ip();
160152
// if the peer is not a known proxy, ignore the X-Forwarded-For headers
161-
if !is_trusted_proxy(proxy_list, &peer_ip)? {
162-
return Ok(peer_ip);
153+
if !is_trusted_proxy(proxy_list, &peer_ip) {
154+
return Ok(peer_ip.to_string());
163155
}
164156

165157
// The peer is a known proxy, so take rightmost X-Forwarded-For that is not a trusted proxy.
166158
match headers.get(HeaderName::from_lowercase("x-forwarded-for".as_bytes()).unwrap()) {
167159
Some(header) => {
168160
match header.to_str() {
169161
Ok(hstr) => {
162+
info!(log.log, "Remote IP List: {:?}", hstr);
170163
// successive proxies are appeneded to this header.
171164
let mut host_list: Vec<&str> = hstr.split(',').collect();
172165
host_list.reverse();
173166
for host_str in host_list {
174-
let host = host_str.trim().to_owned();
175-
if !is_trusted_proxy(proxy_list, &host)? {
176-
return Ok(host.to_owned());
167+
match host_str.trim().parse::<IpAddr>() {
168+
Ok(addr) => {
169+
if !addr.is_loopback() &&
170+
!is_trusted_proxy(proxy_list, &addr) {
171+
return Ok(addr.to_string());
172+
}
173+
},
174+
Err(err) => {
175+
return Err(HandlerErrorKind::BadRemoteAddrError("Bad IP Specified".to_owned()).into());
176+
}
177177
}
178-
}
179-
Err(HandlerErrorKind::BadRemoteAddrError(format!(
180-
"Could not find remote IP in X-Forwarded-For"
181-
))
182-
.into())
183-
}
178+
};
179+
Err(HandlerErrorKind::BadRemoteAddrError("Only proxies specified".to_owned()).into())
180+
},
184181
Err(err) => Err(HandlerErrorKind::BadRemoteAddrError(format!(
185182
"Unknown address in X-Forwarded-For: {:?}",
186183
err
@@ -302,6 +299,7 @@ impl From<HttpRequest<WsChannelSessionState>> for SenderData {
302299
&req.peer_addr(),
303300
&req.headers(),
304301
&req.state().trusted_proxy_list,
302+
&log,
305303
) {
306304
Ok(addr) => Some(addr),
307305
Err(err) => {
@@ -485,30 +483,31 @@ mod test {
485483

486484
let true_remote: SocketAddr = "1.2.3.4:0".parse().unwrap();
487485
let proxy_server: SocketAddr = "192.168.0.4:0".parse().unwrap();
486+
let log = logging::MozLogger::new_human();
488487

489488
bad_headers.insert(
490489
http::header::HeaderName::from_lowercase("x-forwarded-for".as_bytes()).unwrap(),
491490
"".parse().unwrap(),
492491
);
493492

494493
// Proxy only, no XFF header
495-
let remote = get_remote(&Some(proxy_server), &empty_headers, &proxy_list);
494+
let remote = get_remote(&Some(proxy_server), &empty_headers, &proxy_list, &log);
496495
assert!(remote.is_err());
497496

498497
// Proxy only, bad XFF header
499-
let remote = get_remote(&Some(proxy_server), &bad_headers, &proxy_list);
498+
let remote = get_remote(&Some(proxy_server), &bad_headers, &proxy_list, &log);
500499
assert!(remote.is_err());
501500

502501
// Proxy only, crap XFF header
503502
bad_headers.insert(
504503
http::header::HeaderName::from_lowercase("x-forwarded-for".as_bytes()).unwrap(),
505504
"invalid".parse().unwrap(),
506505
);
507-
let remote = get_remote(&Some(proxy_server), &bad_headers, &proxy_list);
506+
let remote = get_remote(&Some(proxy_server), &bad_headers, &proxy_list, &log);
508507
assert!(remote.is_err());
509508

510509
// Peer only, no header
511-
let remote = get_remote(&Some(true_remote), &empty_headers, &proxy_list);
510+
let remote = get_remote(&Some(true_remote), &empty_headers, &proxy_list, &log);
512511
assert_eq!(remote.unwrap(), "1.2.3.4".to_owned());
513512

514513
headers.insert(
@@ -517,7 +516,7 @@ mod test {
517516
);
518517

519518
// Peer proxy, fetch from XFF header
520-
let remote = get_remote(&Some(proxy_server), &headers, &proxy_list);
519+
let remote = get_remote(&Some(proxy_server), &headers, &proxy_list, &log);
521520
assert_eq!(remote.unwrap(), "1.2.3.4".to_owned());
522521

523522
// Peer proxy, ensure right most XFF client fetched
@@ -526,7 +525,7 @@ mod test {
526525
"1.2.3.4, 2.3.4.5".parse().unwrap(),
527526
);
528527

529-
let remote = get_remote(&Some(proxy_server), &headers, &proxy_list);
528+
let remote = get_remote(&Some(proxy_server), &headers, &proxy_list, &log);
530529
assert_eq!(remote.unwrap(), "2.3.4.5".to_owned());
531530

532531
// Peer proxy, ensure right most non-proxy XFF client fetched
@@ -535,7 +534,7 @@ mod test {
535534
"1.2.3.4, 2.3.4.5, 192.168.0.10".parse().unwrap(),
536535
);
537536

538-
let remote = get_remote(&Some(proxy_server), &headers, &proxy_list);
537+
let remote = get_remote(&Some(proxy_server), &headers, &proxy_list, &log);
539538
assert_eq!(remote.unwrap(), "2.3.4.5".to_owned());
540539
}
541540
}

0 commit comments

Comments
 (0)