Module proxy_proto

Module proxy_proto 

Source
Expand description

PROXY protocol acceptance, v1 and v2 (DW-030, feature analysis 4.20).

A listener configured with proxy_protocol: true expects a PROXY protocol header (HAProxy specification; v1 text or v2 binary) as the FIRST bytes of every connection — BEFORE the TLS handshake when the listener terminates TLS, because the L4 load balancer in front wraps the whole stream. The header’s source address then REPLACES the accepted socket peer for everything downstream that consumes the peer address: the authz IP ACL’s effective-client-IP base, rate-limit keying, and the X-Forwarded-For / X-Real-IP values stamped on the forwarded request (the one peer argument of crate::dataplane::proxy::handle).

Security posture (frozen):

  • Opt-in per listener. A listener without the flag never interprets first bytes as a PROXY line; there is no sniffing. The spoofing boundary is exactly the config: an address claim is honored only on listeners explicitly declared to sit behind a PROXY-protocol-speaking LB (the same trust model as gateway.trusted_proxies for XFF).
  • Fail closed. A malformed header (bad signature, bad lengths, Unix address family, datagram protocol on this stream listener, trailing garbage) is answered with a 400 JSON error envelope and the connection is closed — the bytes are NEVER handed to HTTP parsing (a desynced half-header must not become half a request line). A connection that stalls mid-header or drops is closed without a response (nothing parseable to answer, same as a TLS handshake timeout).
  • Bounded. The whole header must arrive within the caller’s deadline (the DW-023 slowloris header timeout — the same attack, one layer earlier) and within the protocol’s own size ceiling (107 bytes for v1, 16 + 65535 for v2). A trickle that never completes is cut by the deadline, not buffered forever.
  • Spec fallbacks honored. A v2 LOCAL command (the LB’s own health check, not a proxied client) and a v1 UNKNOWN line keep the REAL peer address — the specification’s fallback for connections whose origin the LB declines to assert.

Parsing is delegated to the ppp crate (v2 TLV/bounds safety); this module owns the async framing read, the deadline, the caps, and the fail-closed policy. Passthrough listeners cannot combine with PROXY acceptance (validation rejects it): a passthrough listener splices raw bytes and never runs the HTTP pipeline that would consume the address.

Structs§

ProxyHeader
What the listener learned from one accepted connection’s header.

Enums§

ProxyProtoError
Why a connection was not admitted with a PROXY-protocol-derived address. Malformed is answerable (the gateway was given bytes that claimed to be a header and were not); the IO variants are silent closes.

Functions§

read_client_addr
Read one PROXY protocol header (v1 or v2) from the stream and decide the connection’s EFFECTIVE client address.
reject_malformed
Answer a malformed-header connection with the 400 error envelope and close it (the fail-closed half of the policy: never fall through to HTTP parsing). The envelope is the gateway’s uniform error shape, with a freshly generated correlation ID (no request exists yet to inherit one from).