Skip to main content

parse_client_ip

Function parse_client_ip 

Source
pub fn parse_client_ip(
    headers: &HeaderMap,
    max_hops: usize,
    header: ForwardedHeader,
) -> Option<String>
Expand description

Extract the client IP max_hops entries in from the right end of whichever single header header selects — never both. Falls back to None if that header is absent, empty, or the walk runs off the end of the chain.

Only one header is ever consulted (#415 remediation). RFC 7239 Forwarded and the legacy X-Forwarded-For are alternatives, not complements — a real proxy emits one or the other, never both meaningfully. Consulting Forwarded whenever it happens to be present, ahead of X-Forwarded-For, let an attacker who knows a deployment trusts X-Forwarded-For bypass every hop-count/allowlist check just by sending an entirely unvalidated Forwarded header instead. header (from crate::trusted_proxy::TrustedProxyConfig::forwarded_header) names the one header this deployment’s proxy actually writes; the other is never even inspected.

Callers must only invoke this with a max_hops/header they have independently established is trustworthy (i.e. after confirming the request’s socket peer is a configured trusted proxy) — this function has no notion of trust itself, it only walks the chain. See crate::trusted_proxy::TrustedProxyConfig and crate::headers::enrich_context_from_headers for the trust check, and crate::headers::enrich_context_from_headers for the IP-shape validation applied to whatever this function selects.

Right-to-left, not left-to-right. The left end of the chain is exactly the part an untrusted client controls (it can prepend arbitrary entries), so walking in from the left re-opens the identical spoofing gap for any chain longer than one hop. max_hops counts inward from the right: max_hops = 1 takes the rightmost entry (the immediate trusted proxy’s own contribution); max_hops = 2 takes the second-from-right entry (what the next hop in reported seeing), and so on. max_hops = 0 trusts nothing and always returns None. See decision 5 in docs/design/trusted-proxy-client-ip.md.

Duplicate header occurrences are merged, not dropped (#415 remediation). RFC 7230 §3.2.2: repeated list-type header fields are semantically equivalent to a single comma-joined value. A proxy that appends its hop as a second X-Forwarded-For line (rather than extending the first) must not have that value silently lost to whichever line an attacker sent first — every occurrence is concatenated, in wire order, before the chain is walked.