From 3d2093af9bec2b73ed285b967f434f6bc3b7af9b Mon Sep 17 00:00:00 2001 From: Remi Tricot-Le Breton Date: Thu, 29 Jul 2021 09:45:49 +0200 Subject: [PATCH] MINOR: connection: Add a connection error code sample fetch The fc_conn_err and fc_conn_err_str sample fetches give information about the problem that made the connection fail. This information would previously only have been given by the error log messages meaning that thanks to these fetches, the error log can now be included in a custom log format. The log strings were all found in the conn_err_code_str function. --- doc/configuration.txt | 61 ++++++++++++++++++++++++++++++++++ include/haproxy/connection-t.h | 6 +++- src/connection.c | 51 ++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 1 deletion(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index 2e08367275..b3ac72be62 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -17753,6 +17753,67 @@ dst_port : integer a same server, or to pass the destination port information to a server using an HTTP header. +fc_conn_err : integer + Returns the ID of the error that might have occurred on the current + connection. Any strictly positive value of this fetch indicates that the + connection did not succeed and would result in an error log being output (as + decribed in section 8.2.5). See the "fc_conn_err_str" fetch for a full list of + error codes and their corresponding error message. + +fc_conn_err_str : string + Returns an error message decribing what problem happened on the current + connection, resulting in a connection failure. This string corresponds to the + "message" part of the error log format (see section 8.2.5). See below for a + full list of error codes and their corresponding error messages : + + +----+---------------------------------------------------------------------------+ + | ID | message | + +----+---------------------------------------------------------------------------+ + | 0 | "Success" | + | 1 | "Reached configured maxconn value" | + | 2 | "Too many sockets on the process" | + | 3 | "Too many sockets on the system" | + | 4 | "Out of system buffers" | + | 5 | "Protocol or address family not supported" | + | 6 | "General socket error" | + | 7 | "Source port range exhausted" | + | 8 | "Can't bind to source address" | + | 9 | "Out of local source ports on the system" | + | 10 | "Local source address already in use" | + | 11 | "Connection closed while waiting for PROXY protocol header" | + | 12 | "Connection error while waiting for PROXY protocol header" | + | 13 | "Timeout while waiting for PROXY protocol header" | + | 14 | "Truncated PROXY protocol header received" | + | 15 | "Received something which does not look like a PROXY protocol header" | + | 16 | "Received an invalid PROXY protocol header" | + | 17 | "Received an unhandled protocol in the PROXY protocol header" | + | 18 | "Connection closed while waiting for NetScaler Client IP header" | + | 19 | "Connection error while waiting for NetScaler Client IP header" | + | 20 | "Timeout while waiting for a NetScaler Client IP header" | + | 21 | "Truncated NetScaler Client IP header received" | + | 22 | "Received an invalid NetScaler Client IP magic number" | + | 23 | "Received an unhandled protocol in the NetScaler Client IP header" | + | 24 | "Connection closed during SSL handshake" | + | 25 | "Connection error during SSL handshake" | + | 26 | "Timeout during SSL handshake" | + | 27 | "Too many SSL connections" | + | 28 | "Out of memory when initializing an SSL connection" | + | 29 | "Rejected a client-initiated SSL renegotiation attempt" | + | 30 | "SSL client CA chain cannot be verified" | + | 31 | "SSL client certificate not trusted" | + | 32 | "Server presented an SSL certificate different from the configured one" | + | 33 | "Server presented an SSL certificate different from the expected one" | + | 34 | "SSL handshake failure" | + | 35 | "SSL handshake failure after heartbeat" | + | 36 | "Stopped a TLSv1 heartbeat attack (CVE-2014-0160)" | + | 37 | "Attempt to use SSL on an unknown target (internal error)" | + | 38 | "Server refused early data" | + | 39 | "SOCKS4 Proxy write error during handshake" | + | 40 | "SOCKS4 Proxy read error during handshake" | + | 41 | "SOCKS4 Proxy deny the request" | + | 42 | "SOCKS4 Proxy handshake aborted by server" | + +----+---------------------------------------------------------------------------+ + fc_http_major : integer Reports the front connection's HTTP major version encoding, which may be 1 for HTTP/0.9 to HTTP/1.1 or 2 for HTTP/2. Note, this is based on the on-wire diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index 9451585aec..ff8927dbad 100644 --- a/include/haproxy/connection-t.h +++ b/include/haproxy/connection-t.h @@ -194,7 +194,11 @@ enum { CO_FL_SOCKS4 = CO_FL_SOCKS4_SEND | CO_FL_SOCKS4_RECV, }; -/* possible connection error codes */ +/* Possible connection error codes. + * Warning: Do not reorder the codes, they are fetchable through the + * "fc_conn_err" sample fetch. If a new code is added, please add an error label + * in conn_err_code_str and in the "fc_conn_err_str" sample fetch documentation. + */ enum { CO_ER_NONE, /* no error */ diff --git a/src/connection.c b/src/connection.c index 0ba29ed662..09c91a5421 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1498,6 +1498,55 @@ int smp_fetch_fc_pp_unique_id(const struct arg *args, struct sample *smp, const return 1; } +/* fetch the error code of a connection */ +int smp_fetch_fc_conn_err(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct connection *conn; + + conn = objt_conn(smp->sess->origin); + if (!conn) + return 0; + + if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) { + smp->flags |= SMP_F_MAY_CHANGE; + return 0; + } + + smp->flags = 0; + smp->data.type = SMP_T_SINT; + smp->data.u.sint = (unsigned long long int)conn->err_code; + + return 1; +} + +/* fetch a string representation of the error code of a connection */ +int smp_fetch_fc_conn_err_str(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + struct connection *conn; + const char *err_code_str; + + conn = objt_conn(smp->sess->origin); + if (!conn) + return 0; + + if (conn->flags & CO_FL_WAIT_XPRT && !conn->err_code) { + smp->flags |= SMP_F_MAY_CHANGE; + return 0; + } + + err_code_str = conn_err_code_str(conn); + + if (!err_code_str) + return 0; + + smp->flags = 0; + smp->data.type = SMP_T_STR; + smp->data.u.str.area = (char*)err_code_str; + smp->data.u.str.data = strlen(err_code_str); + + return 1; +} + /* Note: must not be declared as its list will be overwritten. * Note: fetches that may return multiple types must be declared as the lowest * common denominator, the type that can be casted into all other ones. For @@ -1509,6 +1558,8 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, { { "fc_rcvd_proxy", smp_fetch_fc_rcvd_proxy, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI }, { "fc_pp_authority", smp_fetch_fc_pp_authority, 0, NULL, SMP_T_STR, SMP_USE_L4CLI }, { "fc_pp_unique_id", smp_fetch_fc_pp_unique_id, 0, NULL, SMP_T_STR, SMP_USE_L4CLI }, + { "fc_conn_err", smp_fetch_fc_conn_err, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI }, + { "fc_conn_err_str", smp_fetch_fc_conn_err_str, 0, NULL, SMP_T_STR, SMP_USE_L4CLI }, { /* END */ }, }};