"""Network trust helpers. ``is_trusted_proxy`` answers "may this TCP peer set X-Real-IP / X-Forwarded-For?" against ``settings.TRUSTED_PROXY_IPS``, accepting both single addresses (``127.0.0.1``) and CIDR networks (``172.16.0.0/12``). Why CIDR support exists (security review 2026-06-11): in the production Docker Compose topology nginx reaches the backend over the compose ``helix`` network, so the backend's TCP peer is the *nginx container IP* — assigned from the (now pinned) ``172.28.0.0/16`` subnet, which an exact-match list can't spell. With the old loopback-only list the peer never matched, ``get_real_ip`` ignored the forwarded headers, and every per-IP rate limiter / audit ``ip_address`` collapsed onto the nginx container IP. Trusting a docker subnet is only safe because the backend port is bound to loopback (``127.0.0.1:8000`` in docker-compose.prod.yml) — nothing outside the compose network can reach ``:8000``, so the only peers that ever present a ``172.28/16`` source are the compose containers themselves. If the backend port is ever republished to ``0.0.0.0``, docker-proxy would make external connections appear to originate from the bridge gateway (inside the trusted CIDR) and could spoof X-Forwarded-For — keep the bind on loopback, and keep the trusted CIDR no wider than the pinned compose subnet. """ from __future__ import annotations import ipaddress from functools import lru_cache from app.core.config import settings from app.core.safe_logging import get_safe_logger logger = get_safe_logger(__name__) @lru_cache(maxsize=1) def _trusted_networks() -> tuple[ipaddress._BaseNetwork, ...]: """Parse TRUSTED_PROXY_IPS once; bad entries are skipped loudly.""" networks: list[ipaddress._BaseNetwork] = [] for raw in settings.TRUSTED_PROXY_IPS: entry = str(raw).strip() if not entry: continue try: # ip_network accepts both bare addresses (/32 implied) and # CIDR strings; strict=False tolerates host bits set. networks.append(ipaddress.ip_network(entry, strict=False)) except ValueError: logger.warning( "TRUSTED_PROXY_IPS entry %r is not a valid IP/CIDR — ignored", entry, ) return tuple(networks) @lru_cache(maxsize=1024) def is_trusted_proxy(peer: str) -> bool: """True iff ``peer`` is allowed to set proxy forwarding headers.""" try: addr = ipaddress.ip_address(peer) except ValueError: return False return any(addr in net for net in _trusted_networks()) def reset_trust_cache() -> None: """Test hook — settings mutation must invalidate the parse cache.""" _trusted_networks.cache_clear() is_trusted_proxy.cache_clear() __all__ = ["is_trusted_proxy", "reset_trust_cache"]