mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-27 23:22:09 +00:00
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:
parent
0af2912fd1
commit
8e3bf699db
@ -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;
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user