extract_client_ip misses TCP peer-addr fallback — IP auto-login broken from browser → proxy #31
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_proxy#31
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
extract_client_ip(incrates/hero_proxy_server/src/proxy.rs) reads onlyX-Real-IpandX-Forwarded-Forheaders. Both are upstream-proxy headers — neither is sent by a browser that connects to hero_proxy directly. Result: when hero_proxy is the edge (no nginx/caddy/Cloudflare in front, which is its designed deployment shape),client_ip = Nonefor every browser request.This breaks the IP-based auto-login path:
find_user_for_ip(None)always returnsNone, so the proxy never injectsX-Hero-Userfromuser_networksrows, even when the operator has explicitly configured127.0.0.1/32 → user Xvia the admin UI. The whole IP-auto-login feature is effectively dead from any browser → proxy path.Verification
After the fix, the same call returns the auto-resolved user — IP-auto-login works as configured.
Root cause
extract_client_ipis missing the standard third tier of every edge HTTP server's client-IP lookup chain:X-Real-Ip(single IP from a trusted upstream proxy)X-Forwarded-For(chain from CDN / multi-hop proxy)The whole point of hero_proxy is that it's the edge. Putting another reverse proxy in front of it would defeat its purpose (duplicate TLS termination, duplicate auth surface). So step 3 is what's needed for the actual deployment shape this service is designed for.
axum-extra's
ClientIp, tower-http'sRealIp, nginx'sreal_ip_module, actix-web'sConnectionInfo— all use this same three-tier pattern.Fix shape
Two surgical changes:
extract_client_ipsignature gains anOption<&SocketAddr>parameter and falls back topeer_addr.map(|a| a.ip().to_string())after the existing header lookups. Header precedence is unchanged so deployments behind a CDN keep working.proxy_handlerextractsaxum::extract::ConnectInfo<SocketAddr>and passes the peer addr through. Listener wiring inmain.rs(HTTP, HTTPS-ACME, HTTPS-self-signed) switches frominto_make_service()tointo_make_service_with_connect_info::<SocketAddr>()so the extractor has the data to extract.Pre-existing trust gap (separate issue)
This patch does NOT address:
extract_client_iphonorsX-Forwarded-Forfrom any peer. With IP auto-login now actually working, anyone who can reach the listener directly can spoofX-Forwarded-For: 127.0.0.1and impersonate the operator. Pre-existing in current code; the patch inherits it.Filing as a separate issue: add
trusted_proxies: Vec<IpNetwork>setting; only honorX-Real-Ip/X-Forwarded-Forwhen the immediate peer is in that list. Default empty (= edge mode).PR
Fix in
feat/peer-addr-fallback. ~30 LOC. No schema change.