]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: connection: add error reporting for the PROXY protocol header
authorWilly Tarreau <w@1wt.eu>
Mon, 3 Dec 2012 14:41:18 +0000 (15:41 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 3 Dec 2012 16:21:51 +0000 (17:21 +0100)
When the PROXY protocol header is expected and fails, leading to an
abort of the incoming connection, we now emit a log message. If option
dontlognull is set and it was just a port probe, then nothing is logged.

include/proto/connection.h
include/types/connection.h
src/connection.c
src/session.c

index 741e88ec644cac8b2b68f36b9f46cda18ec50e2a..8a40575a7f57474408d33f9613f5eaae68104eaa 100644 (file)
@@ -469,7 +469,13 @@ static inline const char *conn_err_code_str(struct connection *c)
 {
        switch (c->err_code) {
        case CO_ER_NONE:          return "Success";
+       case CO_ER_PRX_EMPTY:     return "Connection closed while waiting for PROXY protocol header";
+       case CO_ER_PRX_ABORT:     return "Connection error while waiting for PROXY protocol header";
        case CO_ER_PRX_TIMEOUT:   return "Timeout while waiting for PROXY protocol header";
+       case CO_ER_PRX_TRUNCATED: return "Truncated PROXY protocol header received";
+       case CO_ER_PRX_NOT_HDR:   return "Received something which does not look like a PROXY protocol header";
+       case CO_ER_PRX_BAD_HDR:   return "Received an invalid PROXY protocol header";
+       case CO_ER_PRX_BAD_PROTO: return "Received an unhandled protocol in the PROXY protocol header";
        case CO_ER_SSL_TIMEOUT:   return "Timeout during SSL handshake";
        }
        return NULL;
index 6b6ddab2449d013470a857cdd678fef51ba7a547..f9bedcdcc232bb52b961d93d6d1a53b1c79c931e 100644 (file)
@@ -146,7 +146,14 @@ enum {
 /* possible connection error codes */
 enum {
        CO_ER_NONE,             /* no error */
+       CO_ER_PRX_EMPTY,        /* nothing received in PROXY protocol header */
+       CO_ER_PRX_ABORT,        /* client abort during PROXY protocol header */
        CO_ER_PRX_TIMEOUT,      /* timeout while waiting for a PROXY header */
+       CO_ER_PRX_TRUNCATED,    /* truncated PROXY protocol header */
+       CO_ER_PRX_NOT_HDR,      /* not a PROXY protocol header */
+       CO_ER_PRX_BAD_HDR,      /* bad PROXY protocol header */
+       CO_ER_PRX_BAD_PROTO,    /* unsupported protocol in PROXY header */
+
        CO_ER_SSL_TIMEOUT,      /* timeout during SSL handshake */
 };
 
index a527bd77445acdb465c9f4fe7a8da7746e199c8c..e2d75ba7a51e7dbc92029fd344825ea3c4f4dc6c 100644 (file)
@@ -280,10 +280,16 @@ int conn_recv_proxy(struct connection *conn, int flag)
                                conn_sock_poll_recv(conn);
                                return 0;
                        }
-                       goto fail;
+                       goto recv_abort;
                }
        } while (0);
 
+       if (!trash.len) {
+               /* client shutdown */
+               conn->err_code = CO_ER_PRX_EMPTY;
+               goto fail;
+       }
+
        if (trash.len < 6)
                goto missing;
 
@@ -291,8 +297,10 @@ int conn_recv_proxy(struct connection *conn, int flag)
        end = trash.str + trash.len;
 
        /* Decode a possible proxy request, fail early if it does not match */
-       if (strncmp(line, "PROXY ", 6) != 0)
+       if (strncmp(line, "PROXY ", 6) != 0) {
+               conn->err_code = CO_ER_PRX_NOT_HDR;
                goto fail;
+       }
 
        line += 6;
        if (trash.len < 18) /* shortest possible line */
@@ -307,27 +315,27 @@ int conn_recv_proxy(struct connection *conn, int flag)
                if (line == end)
                        goto missing;
                if (*line++ != ' ')
-                       goto fail;
+                       goto bad_header;
 
                dst3 = inetaddr_host_lim_ret(line, end, &line);
                if (line == end)
                        goto missing;
                if (*line++ != ' ')
-                       goto fail;
+                       goto bad_header;
 
                sport = read_uint((const char **)&line, end);
                if (line == end)
                        goto missing;
                if (*line++ != ' ')
-                       goto fail;
+                       goto bad_header;
 
                dport = read_uint((const char **)&line, end);
                if (line > end - 2)
                        goto missing;
                if (*line++ != '\r')
-                       goto fail;
+                       goto bad_header;
                if (*line++ != '\n')
-                       goto fail;
+                       goto bad_header;
 
                /* update the session's addresses and mark them set */
                ((struct sockaddr_in *)&conn->addr.from)->sin_family      = AF_INET;
@@ -357,7 +365,7 @@ int conn_recv_proxy(struct connection *conn, int flag)
                                *line = 0;
                                line++;
                                if (*line++ != '\n')
-                                       goto fail;
+                                       goto bad_header;
                                break;
                        }
 
@@ -374,21 +382,21 @@ int conn_recv_proxy(struct connection *conn, int flag)
                }
 
                if (!dst_s || !sport_s || !dport_s)
-                       goto fail;
+                       goto bad_header;
 
                sport = read_uint((const char **)&sport_s,dport_s - 1);
                if (*sport_s != 0)
-                       goto fail;
+                       goto bad_header;
 
                dport = read_uint((const char **)&dport_s,line - 2);
                if (*dport_s != 0)
-                       goto fail;
+                       goto bad_header;
 
                if (inet_pton(AF_INET6, src_s, (void *)&src3) != 1)
-                       goto fail;
+                       goto bad_header;
 
                if (inet_pton(AF_INET6, dst_s, (void *)&dst3) != 1)
-                       goto fail;
+                       goto bad_header;
 
                /* update the session's addresses and mark them set */
                ((struct sockaddr_in6 *)&conn->addr.from)->sin6_family      = AF_INET6;
@@ -401,6 +409,8 @@ int conn_recv_proxy(struct connection *conn, int flag)
                conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
        }
        else {
+               /* The protocol does not match something known (TCP4/TCP6) */
+               conn->err_code = CO_ER_PRX_BAD_PROTO;
                goto fail;
        }
 
@@ -414,7 +424,7 @@ int conn_recv_proxy(struct connection *conn, int flag)
                if (len2 < 0 && errno == EINTR)
                        continue;
                if (len2 != trash.len)
-                       goto fail;
+                       goto recv_abort;
        } while (0);
 
        conn->flags &= ~flag;
@@ -425,6 +435,18 @@ int conn_recv_proxy(struct connection *conn, int flag)
         * we have not read anything. Otherwise we need to fail because we won't
         * be able to poll anymore.
         */
+       conn->err_code = CO_ER_PRX_TRUNCATED;
+       goto fail;
+
+ bad_header:
+       /* This is not a valid proxy protocol header */
+       conn->err_code = CO_ER_PRX_BAD_HDR;
+       goto fail;
+
+ recv_abort:
+       conn->err_code = CO_ER_PRX_ABORT;
+       goto fail;
+
  fail:
        conn_sock_stop_both(conn);
        conn->flags |= CO_FL_ERROR;
index 12f7f581e5c0844cdd953ff93417d8fa6ec23f93..c22459ba719446ce0d78f98e3bf84f87d61a03a7 100644 (file)
@@ -285,7 +285,8 @@ static void kill_mini_session(struct session *s)
 
        if (log && (s->fe->options & PR_O_NULLNOLOG)) {
                /* with "option dontlognull", we don't log connections with no transfer */
-               if (!conn->err_code)
+               if (!conn->err_code ||
+                   conn->err_code == CO_ER_PRX_EMPTY || conn->err_code == CO_ER_PRX_ABORT)
                        log = 0;
        }