From: Frederic Lecaille Date: Wed, 21 Oct 2026 12:43:57 +0000 (+0200) Subject: BUG/MEDIUM: stick-tables: compute the shard of string keys on the stored key X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=94736c9e2ffa2228fc10d447b2f778898214a0cf;p=haproxy.git BUG/MEDIUM: stick-tables: compute the shard of string keys on the stored key stksess_setkey_shard() computes the peers shard from the raw sample length, while the key is stored truncated to the table's key size and to the first NUL, and the peers receiver computes the shard from the received key. For a key longer than the table's "len" (e.g. a User-Agent in a len-32 table) or containing a NUL, the creator and the receivers assign different shards to the same entry, so entries may be sent to the wrong peers. Compute the shard from the stored key, as the receiver does. The key argument is then unused, remove it. Introduced in 2.7 by 36d156564 ("MINOR: peers: Support for peer shards"), to be backported to 2.8 and above. --- diff --git a/include/haproxy/stick_table.h b/include/haproxy/stick_table.h index 72bdc9558..497dbce2e 100644 --- a/include/haproxy/stick_table.h +++ b/include/haproxy/stick_table.h @@ -43,7 +43,7 @@ extern struct stktable_type stktable_types[]; void stktable_store_name(struct stktable *t); struct stktable *stktable_find_by_name(const char *name); struct stksess *stksess_new(struct stktable *t, struct stktable_key *key); -void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key); +size_t stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key); void stksess_free(struct stktable *t, struct stksess *ts); int stksess_kill(struct stktable *t, struct stksess *ts); int stktable_get_key_shard(struct stktable *t, const void *key, size_t len); diff --git a/src/stick_table.c b/src/stick_table.c index 9c447bb99..9cf5d8d16 100644 --- a/src/stick_table.c +++ b/src/stick_table.c @@ -184,10 +184,14 @@ int stksess_kill(struct stktable *t, struct stksess *ts) /* * Initialize or update the key in the sticky session present in table - * from the value present in . + * from the value present in . The length of the key as it is stored is + * returned, which is the entry's identity in the table and over the peers + * protocol. */ -void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key) +size_t stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key *key) { + size_t keylen = t->key_size; + if (t->type != SMP_T_STR) memcpy(ts->key.key, key->key, t->key_size); else { @@ -204,7 +208,10 @@ void stksess_setkey(struct stktable *t, struct stksess *ts, struct stktable_key memcpy(ts->key.key, key->key, key_len); ts->key.key[key_len] = 0; + keylen = key_len; } + + return keylen; } /* @@ -242,20 +249,13 @@ int stktable_get_key_shard(struct stktable *t, const void *key, size_t len) } /* - * Set the shard for key of sticky session attached to stick table. + * Set the shard from the already initialized stored key of and its length + * as computed by stksess_setkey(). * Use zero for stick-table without peers synchronisation. */ -static void stksess_setkey_shard(struct stktable *t, struct stksess *ts, - struct stktable_key *key) +static void stksess_setkey_shard(struct stktable *t, struct stksess *ts, size_t keylen) { - size_t keylen; - - if (t->type == SMP_T_STR) - keylen = key->key_len; - else - keylen = t->key_size; - - ts->shard = stktable_get_key_shard(t, key->key, keylen); + ts->shard = stktable_get_key_shard(t, ts->key.key, keylen); } /* @@ -474,8 +474,10 @@ struct stksess *stksess_new(struct stktable *t, struct stktable_key *key) ts = (void *)ts + round_ptr_size(t->data_size); __stksess_init(t, ts); if (key) { - stksess_setkey(t, ts, key); - stksess_setkey_shard(t, ts, key); + size_t keylen; + + keylen = stksess_setkey(t, ts, key); + stksess_setkey_shard(t, ts, keylen); } } else HA_ATOMIC_DEC(&t->current);