Browse Source

Add support for the UNIQUE_ID proxy protocol header TLV

Loïc Hoguin 1 year ago
parent
commit
cb75e10c99
2 changed files with 16 additions and 0 deletions
  1. 6 0
      doc/src/manual/ranch_proxy_header.asciidoc
  2. 10 0
      src/ranch_proxy_header.erl

+ 6 - 0
doc/src/manual/ranch_proxy_header.asciidoc

@@ -37,6 +37,7 @@ proxy_info() = #{
     %% Extra TLV-encoded data.
     %% Extra TLV-encoded data.
     alpn      => binary(), %% US-ASCII.
     alpn      => binary(), %% US-ASCII.
     authority => binary(), %% UTF-8.
     authority => binary(), %% UTF-8.
+    unique_id => binary(), %% Opaque byte sequence of up to 128 bytes.
     netns     => binary(), %% US-ASCII.
     netns     => binary(), %% US-ASCII.
     ssl       => #{
     ssl       => #{
         client   := [ssl | cert_conn | cert_sess],
         client   := [ssl | cert_conn | cert_sess],
@@ -105,6 +106,10 @@ authority::
 The host name serving as authority for the connection.
 The host name serving as authority for the connection.
 This is typically passed using the SNI extension for TLS.
 This is typically passed using the SNI extension for TLS.
 
 
+unique_id::
+An opaque byte sequence of up to 128 bytes generated
+by the upstream proxy that uniquely identifies the connection.
+
 netns::
 netns::
 
 
 The namespace's name for the original connection.
 The namespace's name for the original connection.
@@ -158,6 +163,7 @@ The non-standard TLVs that Ranch was not able to parse.
 
 
 == Changelog
 == Changelog
 
 
+* *2.2*: The `unique_id` TLV was added.
 * *1.7*: Module introduced.
 * *1.7*: Module introduced.
 
 
 == See also
 == See also

+ 10 - 0
src/ranch_proxy_header.erl

@@ -33,6 +33,7 @@
 	%% Extra TLV-encoded data.
 	%% Extra TLV-encoded data.
 	alpn => binary(), %% US-ASCII.
 	alpn => binary(), %% US-ASCII.
 	authority => binary(), %% UTF-8.
 	authority => binary(), %% UTF-8.
+	unique_id => binary(), %% Opaque byte sequence of up to 128 bytes.
 	ssl => #{
 	ssl => #{
 		client := [ssl | cert_conn | cert_sess],
 		client := [ssl | cert_conn | cert_sess],
 		verified := boolean(),
 		verified := boolean(),
@@ -520,6 +521,12 @@ parse_tlv(<<16#3, TLVLen:16, CRC32C:32, Rest/bits>>, Len0, Info, Header) when TL
 %% PP2_TYPE_NOOP.
 %% PP2_TYPE_NOOP.
 parse_tlv(<<16#4, TLVLen:16, _:TLVLen/binary, Rest/bits>>, Len, Info, Header) ->
 parse_tlv(<<16#4, TLVLen:16, _:TLVLen/binary, Rest/bits>>, Len, Info, Header) ->
 	parse_tlv(Rest, Len - TLVLen - 3, Info, Header);
 	parse_tlv(Rest, Len - TLVLen - 3, Info, Header);
+%% PP2_TYPE_UNIQUE_ID.
+parse_tlv(<<16#5, TLVLen:16, UniqueID:TLVLen/binary, Rest/bits>>, Len, Info, Header)
+		when TLVLen =< 128 ->
+	parse_tlv(Rest, Len - TLVLen - 3, Info#{unique_id => UniqueID}, Header);
+parse_tlv(<<16#5, _/bits>>, _, _, _) ->
+	{error, 'Invalid TLV length in the PROXY protocol binary header. (PP 2.2, PP 2.2.5)'};
 %% PP2_TYPE_SSL.
 %% PP2_TYPE_SSL.
 parse_tlv(<<16#20, TLVLen:16, Client, Verify:32, Rest0/bits>>, Len, Info, Header) ->
 parse_tlv(<<16#20, TLVLen:16, Client, Verify:32, Rest0/bits>>, Len, Info, Header) ->
 	SubsLen = TLVLen - 5,
 	SubsLen = TLVLen - 5,
@@ -682,6 +689,7 @@ tlvs(ProxyInfo, Opts) ->
 	[
 	[
 		binary_tlv(ProxyInfo, alpn, 16#1),
 		binary_tlv(ProxyInfo, alpn, 16#1),
 		binary_tlv(ProxyInfo, authority, 16#2),
 		binary_tlv(ProxyInfo, authority, 16#2),
+		binary_tlv(ProxyInfo, unique_id, 16#5),
 		ssl_tlv(ProxyInfo),
 		ssl_tlv(ProxyInfo),
 		binary_tlv(ProxyInfo, netns, 16#30),
 		binary_tlv(ProxyInfo, netns, 16#30),
 		raw_tlvs(ProxyInfo),
 		raw_tlvs(ProxyInfo),
@@ -849,6 +857,8 @@ v2_tlvs_test() ->
 	]},
 	]},
 	Test5Out = Test5In#{raw_tlvs => lists:reverse(RawTLVs)},
 	Test5Out = Test5In#{raw_tlvs => lists:reverse(RawTLVs)},
 	{ok, Test5Out, <<>>} = parse(iolist_to_binary(header(Test5In))),
 	{ok, Test5Out, <<>>} = parse(iolist_to_binary(header(Test5In))),
+	Test6 = Common#{unique_id => rand:bytes(rand:uniform(128))},
+	{ok, Test6, <<>>} = parse(iolist_to_binary(header(Test6))),
 	ok.
 	ok.
 
 
 v2_checksum_test() ->
 v2_checksum_test() ->