MEDIUM: connection: add error reporting for the PROXY protocol header

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.
This commit is contained in:
Willy Tarreau 2012-12-03 15:41:18 +01:00
parent 0af2912fd1
commit 8e3bf699db
4 changed files with 51 additions and 15 deletions

View 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;

View 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 */
};

View 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;

View 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;
}