mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-23 14:51:27 +02: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) {
|
switch (c->err_code) {
|
||||||
case CO_ER_NONE: return "Success";
|
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_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";
|
case CO_ER_SSL_TIMEOUT: return "Timeout during SSL handshake";
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -146,7 +146,14 @@ enum {
|
|||||||
/* possible connection error codes */
|
/* possible connection error codes */
|
||||||
enum {
|
enum {
|
||||||
CO_ER_NONE, /* no error */
|
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_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 */
|
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);
|
conn_sock_poll_recv(conn);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
goto fail;
|
goto recv_abort;
|
||||||
}
|
}
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
|
if (!trash.len) {
|
||||||
|
/* client shutdown */
|
||||||
|
conn->err_code = CO_ER_PRX_EMPTY;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (trash.len < 6)
|
if (trash.len < 6)
|
||||||
goto missing;
|
goto missing;
|
||||||
|
|
||||||
@ -291,8 +297,10 @@ int conn_recv_proxy(struct connection *conn, int flag)
|
|||||||
end = trash.str + trash.len;
|
end = trash.str + trash.len;
|
||||||
|
|
||||||
/* Decode a possible proxy request, fail early if it does not match */
|
/* 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;
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
line += 6;
|
line += 6;
|
||||||
if (trash.len < 18) /* shortest possible line */
|
if (trash.len < 18) /* shortest possible line */
|
||||||
@ -307,27 +315,27 @@ int conn_recv_proxy(struct connection *conn, int flag)
|
|||||||
if (line == end)
|
if (line == end)
|
||||||
goto missing;
|
goto missing;
|
||||||
if (*line++ != ' ')
|
if (*line++ != ' ')
|
||||||
goto fail;
|
goto bad_header;
|
||||||
|
|
||||||
dst3 = inetaddr_host_lim_ret(line, end, &line);
|
dst3 = inetaddr_host_lim_ret(line, end, &line);
|
||||||
if (line == end)
|
if (line == end)
|
||||||
goto missing;
|
goto missing;
|
||||||
if (*line++ != ' ')
|
if (*line++ != ' ')
|
||||||
goto fail;
|
goto bad_header;
|
||||||
|
|
||||||
sport = read_uint((const char **)&line, end);
|
sport = read_uint((const char **)&line, end);
|
||||||
if (line == end)
|
if (line == end)
|
||||||
goto missing;
|
goto missing;
|
||||||
if (*line++ != ' ')
|
if (*line++ != ' ')
|
||||||
goto fail;
|
goto bad_header;
|
||||||
|
|
||||||
dport = read_uint((const char **)&line, end);
|
dport = read_uint((const char **)&line, end);
|
||||||
if (line > end - 2)
|
if (line > end - 2)
|
||||||
goto missing;
|
goto missing;
|
||||||
if (*line++ != '\r')
|
if (*line++ != '\r')
|
||||||
goto fail;
|
goto bad_header;
|
||||||
if (*line++ != '\n')
|
if (*line++ != '\n')
|
||||||
goto fail;
|
goto bad_header;
|
||||||
|
|
||||||
/* update the session's addresses and mark them set */
|
/* update the session's addresses and mark them set */
|
||||||
((struct sockaddr_in *)&conn->addr.from)->sin_family = AF_INET;
|
((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 = 0;
|
||||||
line++;
|
line++;
|
||||||
if (*line++ != '\n')
|
if (*line++ != '\n')
|
||||||
goto fail;
|
goto bad_header;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,21 +382,21 @@ int conn_recv_proxy(struct connection *conn, int flag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!dst_s || !sport_s || !dport_s)
|
if (!dst_s || !sport_s || !dport_s)
|
||||||
goto fail;
|
goto bad_header;
|
||||||
|
|
||||||
sport = read_uint((const char **)&sport_s,dport_s - 1);
|
sport = read_uint((const char **)&sport_s,dport_s - 1);
|
||||||
if (*sport_s != 0)
|
if (*sport_s != 0)
|
||||||
goto fail;
|
goto bad_header;
|
||||||
|
|
||||||
dport = read_uint((const char **)&dport_s,line - 2);
|
dport = read_uint((const char **)&dport_s,line - 2);
|
||||||
if (*dport_s != 0)
|
if (*dport_s != 0)
|
||||||
goto fail;
|
goto bad_header;
|
||||||
|
|
||||||
if (inet_pton(AF_INET6, src_s, (void *)&src3) != 1)
|
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)
|
if (inet_pton(AF_INET6, dst_s, (void *)&dst3) != 1)
|
||||||
goto fail;
|
goto bad_header;
|
||||||
|
|
||||||
/* update the session's addresses and mark them set */
|
/* update the session's addresses and mark them set */
|
||||||
((struct sockaddr_in6 *)&conn->addr.from)->sin6_family = AF_INET6;
|
((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;
|
conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
/* The protocol does not match something known (TCP4/TCP6) */
|
||||||
|
conn->err_code = CO_ER_PRX_BAD_PROTO;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,7 +424,7 @@ int conn_recv_proxy(struct connection *conn, int flag)
|
|||||||
if (len2 < 0 && errno == EINTR)
|
if (len2 < 0 && errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
if (len2 != trash.len)
|
if (len2 != trash.len)
|
||||||
goto fail;
|
goto recv_abort;
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
conn->flags &= ~flag;
|
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
|
* we have not read anything. Otherwise we need to fail because we won't
|
||||||
* be able to poll anymore.
|
* 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:
|
fail:
|
||||||
conn_sock_stop_both(conn);
|
conn_sock_stop_both(conn);
|
||||||
conn->flags |= CO_FL_ERROR;
|
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)) {
|
if (log && (s->fe->options & PR_O_NULLNOLOG)) {
|
||||||
/* with "option dontlognull", we don't log connections with no transfer */
|
/* 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;
|
log = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user