Skip to main content

Module proxy

Module proxy 

Source
Expand description

Trusted reverse proxies and the real client address

Behind a load balancer every connection comes from the proxy, and the client’s address travels in X-Forwarded-For / Forwarded. Those headers are written by clients too: a naive “take the first entry” lets anyone choose their own address, which defeats rate limits, allow-lists and audit logs. The rule that works: only believe the header when the connection comes from a proxy you run, and read it from the right, skipping hops that are your own proxies.

use ullun::prelude::*;
use ullun::proxy::TrustedProxies;

App::new()
    // the load balancers in front of this service
    .trusted_proxies(TrustedProxies::new().trust("10.0.0.0/8").unwrap())
    .get("/ip", |req: Request| async move {
        Ok(Response::text(req.client_ip().map(|ip| ip.to_string()).unwrap_or_default()))
    })
    .run("0.0.0.0:3000")
    .await
    .unwrap();

With trusted proxies configured:

  • Request::client_ip is the first address from the right that is not one of your proxies (Forwarded wins over X-Forwarded-For); from any other peer it is the peer address itself, whatever the headers say
  • Request::is_secure also accepts X-Forwarded-Proto: https / Forwarded: proto=https from a trusted peer
  • the default RateLimiter key and the AccessLog use the client address

Without them nothing changes: client_ip() is the peer address.

Structs§

Cidr
A network such as 10.0.0.0/8 or fd00::/8 (a bare address is a single host)
TrustedProxies
The proxies whose forwarding headers are believed