Skip to content

feat(ip-extractor): fall back to the peer address when the proxy header is missing - #280

Open
dawiegriesel wants to merge 3 commits into
ixpantia:mainfrom
dawiegriesel:feat/peer-fallback
Open

dawiegriesel wants to merge 3 commits into
ixpantia:mainfrom
dawiegriesel:feat/peer-fallback

Conversation

@dawiegriesel

@dawiegriesel dawiegriesel commented Oct 13, 2026 •

Copy link
Copy Markdown

Stacks on #279 (its two commits are included here); the new change is the last commit.

Problem

With --ip-from x-forwarded-for (or x-real-ip), a request that carries no such header is rejected before any response is written, so the client sees a dropped connection. On Azure App Service the platform's own startup probe reaches the container from a link-local address (169.254.x.x) with no X-Forwarded-For:

DEBUG faucet] Accepted TCP connection from 169.254.137.1:17829
ERROR faucet] Error extracting IP, verify that proxy headers are set correctly: Missing header: X-Forwarded-For
ERROR faucet] Connection error: hyper::Error(User(Service), Missing header: X-Forwarded-For)

The container is therefore never marked ready and the site serves 503, even though every real user request does carry the header. Other platforms whose health checks bypass the edge proxy will behave the same way.

Change

When the configured header is absent, use the peer address (the same value --ip-from client would use) and log it at debug level. It is still a stable key for ip-hash. A header that is present but malformed is still an error, and a missing header with no peer address is still an error, so nothing becomes silently permissive.

Tests

Four new unit tests: missing X-Forwarded-For falls back to the peer, missing X-Real-IP falls back to the peer, missing header with no peer is an error, malformed header is still an error. cargo test passes (90 tests). The two clippy -D warnings findings on this branch are in websockets.rs and telemetry/mod.rs and are present on main.

Verified on a live App Service slot: with this build the probe is answered, the container is marked ready, and sessions are served by the workers.

🤖 Generated with Claude Code

Some reverse proxies forward the client address as `ip:port` rather than
a bare IP. Azure App Service does this in X-Forwarded-For, so with
FAUCET_IP_FROM=x-forwarded-for every request failed to parse and faucet
answered 400 Bad Request. Parse a bare IpAddr first and fall back to a
SocketAddr, keeping only its IP; SocketAddr parsing also covers the
bracketed IPv6 form. Garbage still fails as before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
dawiegriesel and others added 2 commits October 14, 2026 07:14
A proxy that normalises IPv6 into bracketed form sends `[2001:db8::1]`,
which fails both the `IpAddr` and the `SocketAddr` parse, so every
request was rejected with 400. Strip the brackets and parse the inside
as IPv6; brackets around an IPv4 address are still rejected.

Document the accepted forms under --ip-from, and the one limit: an
unbracketed IPv6 address cannot carry a port, because `2001:db8::1:443`
is itself a valid address. Add tests for that limit, for X-Real-IP with
bracketed IPv6 and padding whitespace, and for an out-of-range port.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er is missing

A request without the proxy header is, in practice, a platform health
probe arriving from inside the host rather than through the proxy.
Azure App Service's startup probe comes from a link-local address with
no X-Forwarded-For; faucet dropped that connection without an HTTP
response, so the container was never marked ready and the whole site
returned 503. Use the peer address instead, which is still a stable
key for the hash strategies. A header that is present but malformed is
still rejected, and a missing header with no peer address is still an
error.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant