Hi David,

On Mon, Apr 14, 2014 at 09:54:19PM -0400, David S wrote:
> Hello--
>     Part of my solution uses a non-HTTP protocol.  My backend server need
> L3/L4 information, so the PROXY protocol is a perfect fit.  In addition to
> TCP and IP addresses, my backend server needs information from the client
> SSL connection.  So, I would like to extend the PROXY protocol.
>     I want to keep the protocol header small, extensible, and backwards
> compatible.
> 
>     The current version 1 header looks like:
> PROXY TCP4 1.2.3.4 2.3.4.5 51111 443\r\n
>      It is sent when the server keyword "send-proxy" is configured.
> 
>      I propose a Version 1-SSL that can be sent when a new server keyword
> "send-proxy-ssl" is configured.
>      It would look like:
> PROXY SSL4 1.2.3.4 2.3.4.5 51111 443 1 0 CN="certificate common name"\r\n
> 
>      The rules to follow would be:
> 1) If the connection is not SSL, then the original TCP4 format is used
> 2) The first integer after the destination port is:
>        0 if not client certifcate was sent
>        1 if a client certificate was sent
> 3) The second integer after destination port is:
>        0 if the certificate verified
>        X the return code from the SSL verify() function if the certificate
> did not verify
> 4) Delimited by quotation marks, following CN=, is the Common Name from the
> client certificate.
> 
> My hope is these values will solve most people's needs, and if not, this
> format can be easily extended.
> 
> I intend this email to start a discussion, but I am also attaching a code
> patch implementing the above.
> 
> My To Do List:
> 1) remove printf() in src/stream_interface.c left in for ease of testing
> 2) update doc/configuration.txt
> 3) update doc/proxy-protocol.txt
> 
> Please let me know your feedback.

I have nothing against the patch itself but don't completely agree with
the change for a few reasons that were discussed at the beginning of the
year when you started that thread :
  - other fields will have to be exchanged as well (SNI, ALPN, TLS version,
    ciphers immediately come to mind)

  - replacing the L4 protocol with a new name will only ask server-side to
    support the two versions.

Thus I'd suggest *not* to change the L4 keyword and keep TCP4 or TCP6 there.

I think that one way of extending the protocol would be by adding fields at
the end of the line before the CRLF. That way, existing implementations can
easily be upgraded (eg: check for CRLF or space and ignore the rest). And
we keep the leftmost part of the protocol for the lower layers and the
rightmost part for the upper layers as it is right now.

Thus the following string :
    PROXY SSL4 1.2.3.4 2.3.4.5 51111 443 1 0 CN="certificate common name"\r\n

Could become something more or less like this :
    PROXY TCP4 1.2.3.4 2.3.4.5 51111 443 SSL 1 0 CN="certificate common 
name"\r\n

After the next protocol name (SSL here), we absolutely need to specify the
version (eg: 3.1). I agree with passing some information about the result
of the cert check and the cert name when available. Most people will definitely
want ALPN/SNI over CN. So that's something we must pass as well when known.
I also agree with using FIELD="quoted value" for any field there.

I'm wondering whether we should "register" a certain number of field names or
also support some hex-encoded opaque extensions. Maybe that would become harder
to standarize in the long run however.

Another thing to keep in mind is that other people want to see the incoming
interface name, which would conflict with this format.

Thus I'm thinking that we could proceed with a stricter format after the TCP
ports :

    (PROTONAME (FIELD=value|quoted_value)*)*

That means that "SSL" would indicate that whatever follows is still related
to SSL as long as there are equal signs after the words, and that each new
name without an equal sign indicates a different layer.

Thus it could lead to something like this for someone who would like to add more
fields :

    PROXY TCP4 1.2.3.4 2.3.4.5 51111 443 DEV IF=eth0 MAC SRC=00:01:02:03:04:05 
DST=02:03:04:05:06:07 IP ASN=12345 SSL VER=3.1 SNI="www.example.com" 
ALPN="spdy/3.1" CRT=1 RES=0 CN="certificate common name"\r\n

The parser just has to focus on the relevant parts. And even with something
that large, it remains easy for any existing parser to ignore the extra parts
or to only pick the one it needs.

I really think that we should design with such possibilities in mind, and it
will allow for easier later enhancements even in your use case to support extra
fields.

I'm pretty sure that some fields could easily be added within the same
"context" (eg: IF, SRC, ...). That's something to think about when naming
or grouping fields. Some container-based systems might want to see a context
number for example. Unix-based sockets will like to pass an UID. Some
virtualized systems might want to indicate the UUID of the originating VM
sometimes. Thus maybe we'll finally configure the send-proxy parameter to
specify what fields we want to report, and the recipient will simply ignore
those it's not interestd in.

Note that this probably marks the death of protocol v2 that nobody implemented
yet, but that was supposed to be easier to parse...

Willy


Reply via email to