aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--doc/src/manual/ranch.asciidoc1
-rw-r--r--doc/src/manual/ranch.handshake.asciidoc1
-rw-r--r--doc/src/manual/ranch.recv_proxy_header.asciidoc71
-rw-r--r--doc/src/manual/ranch_app.asciidoc1
-rw-r--r--doc/src/manual/ranch_proxy_header.asciidoc164
-rw-r--r--doc/src/manual/ranch_proxy_header.header.asciidoc75
-rw-r--r--doc/src/manual/ranch_proxy_header.parse.asciidoc49
-rw-r--r--ebin/ranch.app2
-rw-r--r--src/ranch.erl4
10 files changed, 368 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index f40691a..df20a5d 100644
--- a/Makefile
+++ b/Makefile
@@ -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()}