diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | doc/src/manual/ranch.asciidoc | 1 | ||||
-rw-r--r-- | doc/src/manual/ranch.handshake.asciidoc | 1 | ||||
-rw-r--r-- | doc/src/manual/ranch.recv_proxy_header.asciidoc | 71 | ||||
-rw-r--r-- | doc/src/manual/ranch_app.asciidoc | 1 | ||||
-rw-r--r-- | doc/src/manual/ranch_proxy_header.asciidoc | 164 | ||||
-rw-r--r-- | doc/src/manual/ranch_proxy_header.header.asciidoc | 75 | ||||
-rw-r--r-- | doc/src/manual/ranch_proxy_header.parse.asciidoc | 49 | ||||
-rw-r--r-- | ebin/ranch.app | 2 | ||||
-rw-r--r-- | src/ranch.erl | 4 |
10 files changed, 368 insertions, 2 deletions
@@ -2,7 +2,7 @@ PROJECT = ranch PROJECT_DESCRIPTION = Socket acceptor pool for TCP protocols. -PROJECT_VERSION = 1.6.2 +PROJECT_VERSION = 1.7.0 PROJECT_REGISTERED = ranch_server # Options. diff --git a/doc/src/manual/ranch.asciidoc b/doc/src/manual/ranch.asciidoc index 21a117e..61b4021 100644 --- a/doc/src/manual/ranch.asciidoc +++ b/doc/src/manual/ranch.asciidoc @@ -27,6 +27,7 @@ Connections: * ranch:accept_ack(3) - Deprecated in favor of link:man:ranch:handshake(3)[ranch:handshake(3)] * link:man:ranch:handshake(3)[ranch:handshake(3)] - Perform the transport handshake +* link:man:ranch:recv_proxy_header(3)[ranch:recv_proxy_header(3)] - Receive the PROXY protocol header * link:man:ranch:remove_connection(3)[ranch:remove_connection(3)] - Remove connection from the count Options: diff --git a/doc/src/manual/ranch.handshake.asciidoc b/doc/src/manual/ranch.handshake.asciidoc index e2c7da9..c8a6ee9 100644 --- a/doc/src/manual/ranch.handshake.asciidoc +++ b/doc/src/manual/ranch.handshake.asciidoc @@ -70,5 +70,6 @@ init(Ref, Transport, Opts) -> == See also link:man:ranch:start_listener(3)[ranch:start_listener(3)], +link:man:ranch:recv_proxy_header(3)[ranch:recv_proxy_header(3)], link:man:ranch:remove_connection(3)[ranch:remove_connection(3)], link:man:ranch(3)[ranch(3)] diff --git a/doc/src/manual/ranch.recv_proxy_header.asciidoc b/doc/src/manual/ranch.recv_proxy_header.asciidoc new file mode 100644 index 0000000..9f23bde --- /dev/null +++ b/doc/src/manual/ranch.recv_proxy_header.asciidoc @@ -0,0 +1,71 @@ += ranch:recv_proxy_header(3) + +== Name + +ranch:recv_proxy_header - Receive the PROXY protocol header + +== Description + +[source,erlang] +---- +recv_proxy_header(ranch:ref(), timeout()) + -> {ok, ranch_proxy_header:proxy_info()} + | {error, Reason :: atom()} + | {error, protocol_error, HumanReadable :: atom()} +---- + +Receive the PROXY protocol header. + +This function must be called before `ranch:handshake/1,2` +on newly accepted connections to read and parse the PROXY +protocol header, if any. + +== Arguments + +Ref:: + +The listener name. + +Timeout:: + +Receive timeout in milliseconds. + +== Return value + +An `ok` tuple is returned containing PROXY header information +on success. + +An `error` 2-tuple is returned when a socket error occurs. + +An `error` 3-tuple is returned when a protocol error occurs +and Ranch was not able to parse the PROXY header information. +The third element contains a human-readable description of +the error. + +== Changelog + +* *1.7*: Function introduced. + +== Examples + +.Receive the PROXY protocol header +[source,erlang] +---- +start_link(Ref, _, Transport, Opts) -> + Pid = proc_lib:spawn_link(?MODULE, init, + [Ref, Transport, Opts]), + {ok, Pid}. + +init(Ref, Transport, Opts) -> + {ok, ProxyInfo} = ranch:recv_proxy_header(Ref, 1000), + {ok, Socket} = ranch:handshake(Ref), + loop(#state{ref=Ref, socket=Socket, transport=Transport, + proxy_info=ProxyInfo, opts=Opts}). +---- + +== See also + +link:man:ranch:start_listener(3)[ranch:start_listener(3)], +link:man:ranch:handshake(3)[ranch:handshake(3)], +link:man:ranch:remove_connection(3)[ranch:remove_connection(3)], +link:man:ranch(3)[ranch(3)] diff --git a/doc/src/manual/ranch_app.asciidoc b/doc/src/manual/ranch_app.asciidoc index c1cb0f9..3186e6c 100644 --- a/doc/src/manual/ranch_app.asciidoc +++ b/doc/src/manual/ranch_app.asciidoc @@ -19,6 +19,7 @@ service. Functions: * link:man:ranch(3)[ranch(3)] - Socket acceptor pool +* link:man:ranch_proxy_header(3)[ranch_proxy_header(3)] - PROXY protocol Transports: diff --git a/doc/src/manual/ranch_proxy_header.asciidoc b/doc/src/manual/ranch_proxy_header.asciidoc new file mode 100644 index 0000000..7155c5e --- /dev/null +++ b/doc/src/manual/ranch_proxy_header.asciidoc @@ -0,0 +1,164 @@ += ranch_proxy_header(3) + +== Name + +ranch_proxy_header - PROXY protocol + +== Description + +The module `ranch_proxy_header` provides functions +for parsing and building the PROXY protocol header. + +== Exports + +* link:man:ranch_proxy_header:parse(3)[ranch_proxy_header:parse(3)] - Parse a PROXY protocol header +* link:man:ranch_proxy_header:header(3)[ranch_proxy_header:header(3)] - Build a PROXY protocol header + +== Types + +=== proxy_info() + +[source,erlang] +---- +proxy_info() = #{ + %% Mandatory part. + version := 1 | 2, + command := local | proxy, + transport_family => undefined | ipv4 | ipv6 | unix, + transport_protocol => undefined | stream | dgram, + + %% Addresses. + src_address => inet:ip_address() | binary(), + src_port => inet:port_number(), + dest_address => inet:ip_address() | binary(), + dest_port => inet:port_number(), + + %% Extra TLV-encoded data. + alpn => binary(), %% US-ASCII. + authority => binary(), %% UTF-8. + netns => binary(), %% US-ASCII. + ssl => #{ + client := [ssl | cert_conn | cert_sess], + verified := boolean(), + version => binary(), %% US-ASCII. + cipher => binary(), %% US-ASCII. + sig_alg => binary(), %% US-ASCII. + key_alg => binary(), %% US-ASCII. + cn => binary() %% UTF-8. + }, + + %% Unknown TLVs can't be parsed so the raw data is given. + raw_tlvs => [{0..255, binary()}] +}. +---- + +The PROXY protocol information. + +The following fields may be found, although most of them are +optional: + +version:: + +The PROXY protocol version used. + +command:: + +`proxy` is used for proxied connections. `local` for non-proxied +connections. Those do not have any additional information. + +transport_family:: + +The transport family of the original connection. + +transport_protocol:: + +The transport protocol of the original connection. + +src_address:: + +The source address of the original connection. This is the +original address of the client. + +src_port:: + +The source port of the original connection. This is the +port the client opened on its end for the connection. It +is not defined for UNIX domain sockets. + +dest_address:: + +The destination address of the original connection. + +dest_port:: + +The destination port of the original connection. It +is not defined for UNIX domain sockets. + +alpn:: + +The upper layer protocol in use over the connection. This +is typically negotiated via the ALPN extension for TLS. + +authority:: + +The host name serving as authority for the connection. +This is typically passed using the SNI extension for TLS. + +netns:: + +The namespace's name for the original connection. + +ssl:: + +Various informations pertaining to the original SSL/TLS +connection. + +client::: + +A list containing a number of flags. `ssl` indicates +that the client connected over SSL/TLS. `cert_conn` +indicates that the client provided a certificate over +the original connection. `cert_sess` indicates that +the client provided a certificate at least once over +the TLS session this connection belongs to. + +verified::: + +Whether the client presented a certificate and it was +successfully verified. + +version::: + +The US-ASCII string containing the SSL/TLS version +used for the original connection. + +cipher::: + +The US-ASCII string name of the cipher used. + +sig_alg::: + +The US-ASCII string name of the algorithm used to sign +the certificate provided by the client. + +key_alg::: + +The US-ASCII string name of the algorithm used to generate +the key of the certificate provided by the client. + +cn::: + +The UTF-8 string representation of the Common Name field +of the client certificate's Distinguished Name. + +raw_tlvs:: + +The non-standard TLVs that Ranch was not able to parse. + +== Changelog + +* *1.7*: Module introduced. + +== See also + +link:man:ranch(7)[ranch(7)] diff --git a/doc/src/manual/ranch_proxy_header.header.asciidoc b/doc/src/manual/ranch_proxy_header.header.asciidoc new file mode 100644 index 0000000..4dc5044 --- /dev/null +++ b/doc/src/manual/ranch_proxy_header.header.asciidoc @@ -0,0 +1,75 @@ += ranch_proxy_header:header(3) + +== Name + +ranch_proxy_header:header - Build a PROXY protocol header + +== Description + +[source,erlang] +---- +header(ProxyInfo) -> header(ProxyInfo, #{}) +header(ProxyInfo, BuildOpts) -> iodata() + +ProxyInfo :: ranch_proxy_header:proxy_info() +BuildOpts :: #{ + checksum => crc32, + padding => pos_integer() %% >= 3 +} +---- + +Build a PROXY protocol header. + +== Arguments + +ProxyInfo:: + +The proxy information to encode. + +BuildOpts:: + +Options to control whether to add a checksum or padding +should be included in the encoded PROXY protocol header. + +== Return value + +The PROXY protocol header is returned. + +== Changelog + +* *1.7*: Function introduced. + +== Examples + +.Build a PROXY protocol header +[source,erlang] +---- +ProxyInfo = #{ + version => 2, + command => proxy, + + transport_family => ipv4, + transport_protocol => stream, + + src_address => {192, 168, 1, 11}, + src_port => 54321, + dest_address => {192, 168, 1, 42}, + dest_port => 443 +}, +Data = ranch_proxy_header:parse(ProxyInfo). +---- + +.Build a PROXY protocol header with checksum and padding +[source,erlang] +---- +Data = ranch_proxy_header:parse(ProxyInfo, #{ + checksum => crc32, + padding => 7 +}). +---- + +== See also + +link:man:ranch_proxy_header:header(3)[ranch_proxy_header:header(3)], +link:man:ranch_proxy_header(3)[ranch_proxy_header(3)] + diff --git a/doc/src/manual/ranch_proxy_header.parse.asciidoc b/doc/src/manual/ranch_proxy_header.parse.asciidoc new file mode 100644 index 0000000..6c22672 --- /dev/null +++ b/doc/src/manual/ranch_proxy_header.parse.asciidoc @@ -0,0 +1,49 @@ += ranch_proxy_header:parse(3) + +== Name + +ranch_proxy_header:parse - Parse a PROXY protocol header + +== Description + +[source,erlang] +---- +parse(Data :: binary()) + -> {ok, ranch_proxy_header:proxy_info(), Rest :: binary()} + | {error, HumanReadable :: atom()} +---- + +Parse a PROXY protocol header. + +== Arguments + +Data:: + +The PROXY protocol header optionally followed by more data. + +== Return value + +An `ok` tuple is returned on success, containing the proxy +information found in the header and the rest of the data +if more was provided. + +An `error` tuple is returned when a protocol error is +detected. It contains a human readable message about the +error. + +== Changelog + +* *1.7*: Function introduced. + +== Examples + +.Parse the PROXY protocol header +[source,erlang] +---- +{ok ProxyInfo, Rest} = ranch_proxy_header:parse(Data). +---- + +== See also + +link:man:ranch_proxy_header:header(3)[ranch_proxy_header:header(3)], +link:man:ranch_proxy_header(3)[ranch_proxy_header(3)] diff --git a/ebin/ranch.app b/ebin/ranch.app index 0c5bf36..82a4bbc 100644 --- a/ebin/ranch.app +++ b/ebin/ranch.app @@ -1,6 +1,6 @@ {application, 'ranch', [ {description, "Socket acceptor pool for TCP protocols."}, - {vsn, "1.6.2"}, + {vsn, "1.7.0"}, {modules, ['ranch','ranch_acceptor','ranch_acceptors_sup','ranch_app','ranch_conns_sup','ranch_listener_sup','ranch_protocol','ranch_proxy_header','ranch_server','ranch_ssl','ranch_sup','ranch_tcp','ranch_transport']}, {registered, [ranch_sup,ranch_server]}, {applications, [kernel,stdlib,ssl]}, diff --git a/src/ranch.erl b/src/ranch.erl index 894f78b..814e928 100644 --- a/src/ranch.erl +++ b/src/ranch.erl @@ -257,6 +257,10 @@ handshake(Ref, Opts) -> end end. +%% Unlike handshake/2 this function always return errors because +%% the communication between the proxy and the server are expected +%% to be reliable. If there is a problem while receiving the proxy +%% header, we probably want to know about it. -spec recv_proxy_header(ref(), timeout()) -> {ok, ranch_proxy_header:proxy_info()} | {error, closed | atom()} |