nhttp_proxy_protocol (nhttp_lib v1.0.0)

View Source

PROXY protocol v1 and v2 parser.

The PROXY protocol preserves the original client IP/port across a connection-terminating intermediary (load balancer, proxy). Both v1 (ASCII line) and v2 (binary frame) are supported.

The 12-byte v2 signature \\r\\n\\r\\n\\x00\\r\\nQUIT\\n is unambiguous and shares no prefix with "PROXY ", so callers wishing to accept both versions can probe each shape from the first byte without ambiguity.

Usage

case nhttp_proxy_protocol:parse(Buffer, #{version => both}) of
    {ok, Header, Consumed} ->
        Rest = binary:part(Buffer, Consumed, byte_size(Buffer) - Consumed),
        handle(Header, Rest);
    {more, _MinBytes} ->
        recv_more();
    {error, Reason} ->
        reject(Reason)
end.

The returned header/0 map carries the parsed source/destination addresses for the proxy command. The local command (v2 only) signals a health-check-style connection from the proxy itself; callers should keep the original L4 peer in that case.

Summary

Functions

Equivalent to parse(Bin, #{version => both}).

Parse a PROXY protocol header from Bin. Opts may carry version => v1 | v2 | both (default both) to restrict the accepted protocol versions. When restricted, a header that matches a disallowed version returns {error, unsupported_version}. Returns {ok, Header, Consumed} on success, where Consumed is the number of bytes occupied by the PROXY header (including any v1 CRLF or v2 length prefix). Use binary:part/3 on the original buffer to recover the bytes that follow.

Types

accepted()

-type accepted() :: v1 | v2 | both.

command()

-type command() :: proxy | local.

family()

-type family() :: inet | inet6 | unix | unspec.

header()

-type header() ::
          #{version := version(),
            command := command(),
            family := family(),
            transport := transport(),
            src_addr => inet:ip_address() | binary(),
            dst_addr => inet:ip_address() | binary(),
            src_port => inet:port_number(),
            dst_port => inet:port_number(),
            tlvs => [tlv()]}.

opts()

-type opts() :: #{version => accepted()}.

parse_error()

-type parse_error() ::
          bad_signature | bad_v1_header | bad_v1_proto | bad_v1_addr | bad_v1_port | bad_v1_too_long |
          bad_v2_version | bad_v2_command | bad_v2_family | bad_v2_transport | bad_v2_payload |
          unsupported_version.

parse_result()

-type parse_result() ::
          {ok, header(), Consumed :: pos_integer()} |
          {more, MinBytes :: pos_integer()} |
          {error, parse_error()}.

tlv()

-type tlv() :: {Type :: 0..255, Value :: binary()}.

transport()

-type transport() :: stream | dgram | unspec.

version()

-type version() :: v1 | v2.

Functions

parse/1

-spec parse(binary()) -> parse_result().

Equivalent to parse(Bin, #{version => both}).

parse/2

-spec parse(binary(), opts()) -> parse_result().

Parse a PROXY protocol header from Bin. Opts may carry version => v1 | v2 | both (default both) to restrict the accepted protocol versions. When restricted, a header that matches a disallowed version returns {error, unsupported_version}. Returns {ok, Header, Consumed} on success, where Consumed is the number of bytes occupied by the PROXY header (including any v1 CRLF or v2 length prefix). Use binary:part/3 on the original buffer to recover the bytes that follow.