#header #request #real #ip #proxies #forwarded #incoming

real-ip

Get the "real ip" of an incoming request using the "forwarded", "x-forwarded-for" or "x-real-ip" headers set by reverse proxies

1 unstable release

new 0.1.0 Nov 29, 2024

#1691 in Network programming

Download history 109/week @ 2024-11-25

109 downloads per month

MIT/Apache

10KB
109 lines

real-ip

Get the "real-ip" of an incoming request using the "forwarded", "x-forwarded-for" or "x-real-ip" headers set by reverse proxies.

See the crate documentation for more details and examples.

Example

use http::Request;
use std::net::IpAddr;
use real_ip::{real_ip, IpNet};

// in a real program this info would of course come from the http server
let incoming_ip = IpAddr::from([10, 0, 0, 1]);
let request = Request::builder().header("x-forwarded-for", "192.0.2.1").body(()).unwrap();

// the reverse-proxies in our network that we trust
let trusted_proxies = [
    IpAddr::from([10, 0, 0, 1]).into(),
];
let client_ip = real_ip(request.headers(), incoming_ip, &trusted_proxies);
assert_eq!(Some(IpAddr::from([192, 0, 2, 1])), client_ip);

lib.rs:

Get the "real-ip" of an incoming request.

This uses the "forwarded", "x-forwarded-for" or "x-real-ip" headers set by reverse proxies.

Trusted proxies

To stop clients from being able to spoof the remote ip, you are required to configure the trusted proxies which are allowed to set the forwarded headers.

Trusted proxies are configured as a list of IpNets, which can be a single ip or an ip range.

Note that if multiple forwarded-for addresses are present, which can be the case when using nested reverse proxies, all proxies in the chain have to be within the list of trusted proxies.

Examples

A request originating from 192.0.2.1, being proxied through 10.10.10.10 and 10.0.0.1 before reaching our program

#
// in a real program this info would of course come from the http server
let incoming_ip = IpAddr::from([10, 0, 0, 1]);
let request = Request::builder().header("x-forwarded-for", "192.0.2.1, 10.10.10.10").body(()).unwrap();

// the reverse-proxies in our network that we trust
let trusted_proxies = [
    IpAddr::from([10, 0, 0, 1]).into(),
    IpNet::new_assert(IpAddr::from([10, 10, 10, 0]), 24), // 10.10.10.0/24
];
let client_ip = real_ip(request.headers(), incoming_ip, &trusted_proxies);
assert_eq!(Some(IpAddr::from([192, 0, 2, 1])), client_ip);

A request originating from 192.0.2.1, being proxied through 203.0.113.10 and 10.0.0.1 before reaching our program. But 203.0.113.10 is not a trusted proxy, so we don't accept anything it added to the forwarded headers

#
let incoming_ip = IpAddr::from([10, 0, 0, 1]);
let request = Request::builder().header("forwarded", "for=192.0.2.1, for=203.0.113.10;proto=https").body(()).unwrap();

let trusted_proxies = [
    IpAddr::from([10, 0, 0, 1]).into(),
    IpNet::new_assert(IpAddr::from([10, 10, 10, 0]), 24),
];
let client_ip = real_ip(request.headers(), incoming_ip, &trusted_proxies);
assert_eq!(Some(IpAddr::from([203, 0, 113, 10])), client_ip);

Dependencies

~1MB
~22K SLoC