diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index 9ee00819b..7acbc2d77 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 d8413fb6e..852b0db22 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 (!sockaddr_alloc(&srv_conn->dst, 0, 0)) { + conn_free(srv_conn); + return SF_ERR_RESOURCE; + } } - } - - 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; + 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 6126dd180..5e7a4c5d6 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; }