Sending Proxy protocol to Server that doesn't support Proxy Protocol

3.6k Views Asked by At

I have a HTTP Acceleration solution that use reverse proxy. In order the provide the client IP to the server I'm trying to add proxy protocol support in my HTTP Acceleration solution. Although as the HTTP Acceleration solution endpoint itself can not be the gateway for my servers, I need to add Proxy Protocol support in the server or add HA Proxy in front of them.

Currently for Proxy protocol states:

A receiver may be configured to support both version 1 and version 2 of the protocol. Identifying the protocol version is easy :

- if the incoming byte count is 16 or above and the 13 first bytes match
  the protocol signature block followed by the protocol version 2 :

       \x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x02

- otherwise, if the incoming byte count is 8 or above, and the 5 first
  characters match the US-ASCII representation of "PROXY" then the protocol
  must be parsed as version 1 :

       \x50\x52\x4F\x58\x59

- otherwise the protocol is not covered by this specification and the
  connection must be dropped.

My server are mainly nginx which have proxy protocol support. Although few of my http server doesn't support proxy protocol

My question is if server doesn’t support the protocol, whether they can parse the TCP/HTTP payload properly which includes the Proxy Protocol header ?

On the same note I would like to know why not the proxy-protocol specification have it as TCP/Ip header options : In that way the Server that doesn't understand the option will just ignore making it completely transparent to the server who doesn't support it. And those server who supports the protocol will drop packets that doesn't have the proxy-protocol option

2

There are 2 best solutions below

0
TimWolla On

My question is if server doesn’t support the protocol, whether they can parse the TCP/HTTP payload properly which includes the Proxy Protocol header?

No, servers that don't support the proxy protocol will fail to parse the request as HTTP, because it does not begin with a valid HTTP method.

Simply leave out the send-proxy directive for the backend servers that do not support the proxy protocol. Keep in mind that you will lose information about the client, unless you pass them in a header such as X-Forwarded-For.

0
Gautam On

Here's an example of a proxy protocol info :

enter image description here

If server doesn’t support the protocol, whether they can parse the TCP/HTTP payload properly which includes the Proxy Protocol header?

It depends on the Server Implementation.

For instance I tried sending proxy protocol information to python's HTTPServer, it threw a 400 error code. Here is the implementation of the server where it parses the header :

def parse_request(self):
    """Parse a request (internal).

    The request should be stored in self.raw_requestline; the results
    are in self.command, self.path, self.request_version and
    self.headers.

    Return True for success, False for failure; on failure, an
    error is sent back.

    """
    self.command = None  # set in case of error on the first line
    self.request_version = version = self.default_request_version
    self.close_connection = 1
    requestline = self.raw_requestline
    requestline = requestline.rstrip('\r\n')
    self.requestline = requestline
    words = requestline.split()
    if len(words) == 3:
        command, path, version = words
        if version[:5] != 'HTTP/':
            self.send_error(400, "Bad request version (%r)" % version)
            return False
        try:
            base_version_number = version.split('/', 1)[1]
            version_number = base_version_number.split(".")
            # RFC 2145 section 3.1 says there can be only one "." and
            #   - major and minor numbers MUST be treated as
            #      separate integers;
            #   - HTTP/2.4 is a lower version than HTTP/2.13, which in
            #      turn is lower than HTTP/12.3;
            #   - Leading zeros MUST be ignored by recipients.
            if len(version_number) != 2:
                raise ValueError
            version_number = int(version_number[0]), int(version_number[1])
        except (ValueError, IndexError):
            self.send_error(400, "Bad request version (%r)" % version)
            return False
        if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
            self.close_connection = 0
        if version_number >= (2, 0):
            self.send_error(505,
                      "Invalid HTTP Version (%s)" % base_version_number)
            return False
    elif len(words) == 2:
        command, path = words
        self.close_connection = 1
        if command != 'GET':
            self.send_error(400,
                            "Bad HTTP/0.9 request type (%r)" % command)
            return False
    elif not words:
        return False
    else:
        self.send_error(400, "Bad request syntax (%r)" % requestline)
        return False
    self.command, self.path, self.request_version = command, path, version

    # Examine the headers and look for a Connection directive
    self.headers = self.MessageClass(self.rfile, 0)

    conntype = self.headers.get('Connection', "")
    if conntype.lower() == 'close':
        self.close_connection = 1
    elif (conntype.lower() == 'keep-alive' and
          self.protocol_version >= "HTTP/1.1"):
        self.close_connection = 0
    return True

Note that a proxy protocol payload for example :

PROXY TCP4 192.168.73.178 192.168.73.185 52406 80

contains 6 words. This particular server implementation handles reqeust if the header has 3,2 or no words. Otherwise it throws a 400 error code.

else:
    self.send_error(400, "Bad request syntax (%r)" % requestline)
    return False

Whereas when I tried sending the same info to a tomcat server with the same HAProxy configuration, it simply ignored the payload.

In general, I would play safe and not send the proxy info unless I know it will be explicitly able to handle it.