fix: validate the trusted X-Forwarded-For entry as client_ip
MA
9h ago+86+86+01234567890123456789-2-2-0123456789
Closes #7854
With trusted_proxy_hops set, the selected X-Forwarded-For entry became router.session.client_ip as is, so 203.0.113.7:51234, [2001:db8::1]:443 or text that isn't an address at all ended up there.
- New
_forwarded_client_ip()drops a numeric:portsuffix or IPv6 brackets and returnsstr(ipaddress.ip_address(...)), orNoneif the entry isn't an address. Malformed forms (an unclosed bracket, text after], a non-numeric or empty port) and IPv6 zone indexes (fe80::1%eth0, whichipaddresskeeps without validating) are rejected rather than trimmed. It's only used at theclient_ipsite;_trusted_forwarded_value()and theX-Forwarded-Host/X-Forwarded-Protohandling are unchanged. - An invalid entry falls back to the connection's peer address and is logged at debug level (through the existing
_clip), since the value is client-controlled when a deployment is misconfigured. - Valid IPv6 entries are now canonical (
2001:DB8:0:0:0:0:0:1becomes2001:db8::1), and leading-zero IPv4 such as010.0.0.1falls back to the peer address, whichipaddressrejects. - The
trusted_proxy_hopsdocs mention the normalisation, and the bugfix news fragment notes the change so otherclient_ipconsumers can follow.
Tests: new cases in test_static_router_data_resolves_client_ip_from_trusted_proxy_hops (port, bracketed IPv6 with and without port, expanded IPv6, a non-address entry, malformed brackets and ports, zone indexes) and test_static_router_data_logs_ignored_forwarded_client_ip; 13 of them fail on main. pytest tests/units/test_app.py tests/units/test_config.py: 500 passed; ruff check/format clean.
All Submissions:
- Have you followed the guidelines stated in CONTRIBUTING.md file?
- Have you checked to ensure there aren't any other open Pull Requests for the desired changed?
Type of change
- Bug fix (non-breaking change which fixes an issue)