From: Amaury Denoyelle Date: Thu, 11 Feb 2021 15:46:53 +0000 (+0100) Subject: MINOR: connection: use dst addr as parameter for srv conn hash X-Git-Tag: v2.4-dev8~67 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=01a287f1e546c5acb87226f22266adc4276d5e81;p=thirdparty%2Fhaproxy.git MINOR: connection: use dst addr as parameter for srv conn hash The destination address is used as an input to the server connection hash. The address and port are used as separated hash inputs. Note that they are not used when statically specified on the server line. This is only useful for dynamic destination address. This is typically used when the server address is dynamically set via the set-dst action. The address and port are separated hash parameters. Most notably, it should fixed set-dst use case (cf github issue #947). --- diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index 9ee00819bf..7acbc2d77e 100644 --- a/include/haproxy/connection-t.h +++ b/include/haproxy/connection-t.h @@ -472,9 +472,11 @@ struct conn_stream { * CAUTION! Always update CONN_HASH_PARAMS_TYPE_COUNT when adding a new entry. */ enum conn_hash_params_t { - CONN_HASH_PARAMS_TYPE_SNI = 0x1, + CONN_HASH_PARAMS_TYPE_SNI = 0x1, + CONN_HASH_PARAMS_TYPE_DST_ADDR = 0x2, + CONN_HASH_PARAMS_TYPE_DST_PORT = 0x4, }; -#define CONN_HASH_PARAMS_TYPE_COUNT 1 +#define CONN_HASH_PARAMS_TYPE_COUNT 3 #define CONN_HASH_PAYLOAD_LEN \ (((sizeof(((struct connection *)0)->hash)) * 8) - CONN_HASH_PARAMS_TYPE_COUNT) @@ -489,6 +491,7 @@ enum conn_hash_params_t { struct conn_hash_params { struct server *srv; XXH64_hash_t *sni_prehash; + struct sockaddr_storage *dst_addr; }; /* This structure describes a connection with its methods and data. diff --git a/src/backend.c b/src/backend.c index d8413fb6ef..852b0db229 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1274,6 +1274,18 @@ int connect_server(struct stream *s) } #endif /* USE_OPENSSL */ + /* 2. destination address */ + if (!(s->flags & SF_ADDR_SET)) { + err = alloc_dst_address(&s->target_addr, srv, s); + if (err != SRV_STATUS_OK) + return SF_ERR_INTERNAL; + + s->flags |= SF_ADDR_SET; + } + + if (srv && (!is_addr(&srv->addr) || srv->flags & SRV_F_MAPPORTS)) + hash_params.dst_addr = s->target_addr; + if (srv) hash = conn_calculate_hash(&hash_params); @@ -1460,23 +1472,15 @@ skip_reuse: srv_conn->owner = s->sess; if (reuse_mode == PR_O_REUSE_NEVR) conn_set_private(srv_conn); - } - } - - if (!srv_conn || !sockaddr_alloc(&srv_conn->dst, 0, 0)) { - if (srv_conn) - conn_free(srv_conn); - return SF_ERR_RESOURCE; - } - if (!(s->flags & SF_ADDR_SET)) { - err = alloc_dst_address(&s->target_addr, srv, s); - if (err != SRV_STATUS_OK) { - conn_free(srv_conn); - return SF_ERR_INTERNAL; + if (!sockaddr_alloc(&srv_conn->dst, 0, 0)) { + conn_free(srv_conn); + return SF_ERR_RESOURCE; + } + } + else { + return SF_ERR_RESOURCE; } - - s->flags |= SF_ADDR_SET; } /* copy the target address into the connection */ diff --git a/src/connection.c b/src/connection.c index 6126dd1803..5e7a4c5d65 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1412,6 +1412,49 @@ static struct cfg_kw_list cfg_kws = {ILH, { INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws); +/* private function to handle sockaddr as input for connection hash */ +static void conn_calculate_hash_sockaddr(const struct sockaddr_storage *ss, + char *buf, size_t *idx, + enum conn_hash_params_t *hash_flags, + enum conn_hash_params_t param_type_addr, + enum conn_hash_params_t param_type_port) +{ + struct sockaddr_in *addr; + struct sockaddr_in6 *addr6; + + switch (ss->ss_family) { + case AF_INET: + addr = (struct sockaddr_in *)ss; + + conn_hash_update(buf, idx, + &addr->sin_addr, sizeof(addr->sin_addr), + hash_flags, param_type_addr); + + if (addr->sin_port) { + conn_hash_update(buf, idx, + &addr->sin_port, sizeof(addr->sin_port), + hash_flags, param_type_port); + } + + break; + + case AF_INET6: + addr6 = (struct sockaddr_in6 *)ss; + + conn_hash_update(buf, idx, + &addr6->sin6_addr, sizeof(addr6->sin6_addr), + hash_flags, param_type_addr); + + if (addr6->sin6_port) { + conn_hash_update(buf, idx, + &addr6->sin6_port, sizeof(addr6->sin6_port), + hash_flags, param_type_port); + } + + break; + } +} + XXH64_hash_t conn_calculate_hash(const struct conn_hash_params *params) { char *buf; @@ -1429,6 +1472,14 @@ XXH64_hash_t conn_calculate_hash(const struct conn_hash_params *params) &hash_flags, CONN_HASH_PARAMS_TYPE_SNI); } + if (params->dst_addr) { + conn_calculate_hash_sockaddr(params->dst_addr, + buf, &idx, &hash_flags, + CONN_HASH_PARAMS_TYPE_DST_ADDR, + CONN_HASH_PARAMS_TYPE_DST_PORT); + } + hash = conn_hash_digest(buf, idx, hash_flags); + return hash; }