Resolve real client IP behind trusted proxies (closes #94) #127

Open
clawbot wants to merge 6 commits from issue-94-trusted-proxies into next
6 Commits
Author SHA1 Message Date
sneak 518e84ce67 docs: document trusted_proxies and record in TODO.md
check / check (push) Failing after 1s
Describe the trusted_proxies key in README.md and config.example.yml,
including the rightmost-non-proxy selection rule and the safe default of
trusting no one. Record the unit in TODO.md.

Model: opus-4-8
2026-09-21 23:23:56 +00:00
sneak 20a18c7345 feat: use resolved client IP in request and auth logs
Add a ClientIP middleware that resolves the client address once per
request and stores it in the context, placed ahead of logging in the
route chain. The request-logging middleware and both login-attempt logs
now read the resolved address instead of the raw peer. Behind a trusted
proxy these records show the real client; a direct, untrusted client
still shows its own address and cannot forge one. Removes the local
host:port helper now that the clientip package owns that parsing.

Model: opus-4-8
2026-09-21 23:23:56 +00:00
sneak a280fd2c34 test: cover resolved client IP in request and auth logs
Assert the ClientIP middleware stores the resolved address in the
request context for trusted and untrusted peers, that the request log
records the forwarded client rather than the proxy peer, and that a
failed-login record carries the resolved address.

Model: opus-4-8
2026-09-21 23:23:55 +00:00
sneak 4f14cd86c3 feat: add trusted-proxy-aware client IP resolver
New internal/clientip package. Resolve honors X-Forwarded-For only when
the direct peer falls inside a configured trusted-proxy range; otherwise
it returns the peer address and ignores the header, so a client
connecting directly cannot spoof its address. When the peer is trusted,
the chain is walked right to left and the first entry that is not itself
a trusted proxy is returned. Also provides request-context helpers so the
resolved address can be shared across middleware and handlers.

Tests cover the honored, ignored, and spoofed-chain cases, rightmost
selection across a mixed chain, multi-line headers, IPv6 and
IPv4-mapped peers, and the context round-trip.

Model: opus-4-8
2026-09-21 23:23:47 +00:00
sneak c5f4682b0b feat: add trusted_proxies config key
Add a trusted_proxies CIDR-list config key alongside blocked_networks.
Generalize the blocked_networks parser into parseCIDRList and
cidrListEntries, which take the key name as a parameter, so both keys
share one parser rather than a second copy. An invalid entry aborts
startup naming the key and value; an omitted or empty key leaves the
list empty.

Model: opus-4-8
2026-09-21 23:23:47 +00:00
sneak 7697822c53 test: add failing config tests for trusted_proxies
Check that a valid CIDR list lands in TrustedProxies in order, an omitted
key trusts no one, and an invalid or null value aborts startup naming the
key and value. The list parser is shared with blocked_networks, whose
tests exercise the remaining shapes.

Model: opus-4-8
2026-09-21 23:23:47 +00:00