Skip to content

Stream: PROXY protocol version 2 upstream write support#1204

Draft
VadimZhestikov wants to merge 4 commits intonginx:masterfrom
VadimZhestikov:proxy_protocol_v2
Draft

Stream: PROXY protocol version 2 upstream write support#1204
VadimZhestikov wants to merge 4 commits intonginx:masterfrom
VadimZhestikov:proxy_protocol_v2

Conversation

@VadimZhestikov
Copy link
Copy Markdown
Contributor

@VadimZhestikov VadimZhestikov commented Mar 22, 2026

Added ngx_proxy_protocol_v2_write() to write a binary PROXY protocol v2 header to an upstream connection. The new stream directive proxy_protocol_version (1|2) selects which version
to send; the default is 1, preserving backwards compatibility.

The transport nibble in the family_transport byte is derived from the downstream connection type: 0x01 (STREAM) for TCP, 0x02 (DGRAM) for UDP. This ensures that UDP stream proxy
sessions emit the correct AF_INET/DGRAM (0x12) or AF_INET6/DGRAM (0x22) header rather than incorrectly claiming STREAM.

Four test files are included:

  • stream_proxy_protocol_v2.t — TCP/IPv4, validates the full binary header structure and that v1 remains the default.
  • stream_proxy_protocol_v2_ssl.t — same over an SSL upstream.
  • stream_proxy_protocol_v2_udp.t — UDP upstream, verifies family_transport = 0x12 (AF_INET, DGRAM).
  • stream_proxy_protocol_v2_ipv6.t — IPv6 TCP upstream, verifies family_transport = 0x21 (AF_INET6, STREAM) and the 52-byte header structure.

Closes #970

Added ngx_proxy_protocol_v2_write() to write a binary PROXYv2
header.  The new stream directive proxy_protocol_version (1|2)
selects which version to send to upstream; the default is 1,
preserving backwards compatibility.

Closes nginx#970
Derive the transport nibble from the downstream connection type
instead of hardcoding STREAM.  For TCP (SOCK_STREAM) upstream the
nibble is 0x01 (STREAM); for UDP (SOCK_DGRAM) it is 0x02 (DGRAM).

Also fix both call sites in the stream proxy module to pass
NGX_PROXY_PROTOCOL_V2_MAX_HEADER as the buffer bound when calling
ngx_proxy_protocol_v2_write(), matching the size check inside the
function.
Two test files covering the new proxy_protocol_version directive:
stream_proxy_protocol_v2.t tests the non-SSL upstream path,
stream_proxy_protocol_v2_ssl.t tests the SSL upstream path.
Both verify the full binary header structure (signature, command,
family, address block length, addresses, ports) as well as that
payload is delivered intact after the header.
Move $sp = $s->sockport() before $s->io() in the TCP and SSL tests
for clarity — the local port is set at connect time.

In the SSL test, move the $PPV2_HDR declaration before run_daemon()
so the forked daemon child inherits the value, and replace the two
hardcoded 28 literals in the daemon's read loop with $PPV2_HDR.
Use a timeout drain loop in the TCP daemon to handle the case where
nginx sends the PPv2 header and payload in separate TCP segments.

Add stream_proxy_protocol_v2_udp.t: a UDP echo daemon with nginx
configured as a UDP stream proxy using proxy_protocol_version 2.
Verifies that the emitted family_transport byte is 0x12 (AF_INET,
DGRAM), covering the transport-nibble fix.

Add stream_proxy_protocol_v2_ipv6.t: an IPv6 TCP test that connects
to nginx via [::1] and verifies family_transport 0x21 (AF_INET6,
STREAM) and the full 52-byte binary header structure.
@VadimZhestikov VadimZhestikov changed the title Proxy protocol v2 Stream: PROXY protocol version 2 upstream write support Mar 22, 2026
@sindhushiv sindhushiv added this to the nginx-1.29.8 milestone Mar 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for writing PROXY protocol v2 to upstream

2 participants