MEDIUM: stick-tables: add a new stored type for glitch_cnt and glitch_rate

This adds a new pair of stored types in the stick-tables:
  - glitch_cnt
  - glitch_rate

These keep count of the number of glitches reported on a front connection,
in order to decide how to act with a badly defective client or a potential
attacker. For now nothing updates these counters, but all the infrastructure
needed to configure, update and retrieve them was added, including the doc.

No regtest was added yet since they're not filled yet.
This commit is contained in:
Willy Tarreau 2024-01-19 17:23:07 +01:00
parent 668eb9aebf
commit c9c6b683fb
5 changed files with 276 additions and 1 deletions

View File

@ -20001,6 +20001,21 @@ table_expire(<table>[,<default_value>])
input sample in the designated table.
See also the table_idle sample fetch keyword.
table_glitch_cnt(<table>)
Uses the string representation of the input sample to perform a look up in
the specified table. If the key is not found in the table, integer value zero
is returned. Otherwise the converter returns the cumulative number of front
connection glitches associated with the input sample in the designated table.
See also the sc_glitch_cnt sample fetch keyword and fc_glitches for the value
measured on the current front connection.
table_glitch_rate(<table>)
Uses the string representation of the input sample to perform a look up in
the specified table. If the key is not found in the table, integer value zero
is returned. Otherwise the converter returns the average front connection
glitch rate associated with the input sample in the designated table. See
also the sc_glitch_rate sample fetch keyword.
table_gpc(<idx>,<table>)
Uses the string representation of the input sample to perform a lookup in
the specified table. If the key is not found in the table, integer value zero
@ -21122,6 +21137,14 @@ sc_get_gpt0(<ctr>[,<table>]) integer
sc0_get_gpt0([<table>]) integer
sc1_get_gpt0([<table>]) integer
sc2_get_gpt0([<table>]) integer
sc_glitch_cnt(<ctr>[,<table>]) integer
sc0_glitch_cnt([<table>]) integer
sc1_glitch_cnt([<table>]) integer
sc2_glitch_cnt([<table>]) integer
sc_glitch_rate(<ctr>[,<table>]) integer
sc0_glitch_rate([<table>]) integer
sc1_glitch_rate([<table>]) integer
sc2_glitch_rate([<table>]) integer
sc_gpc_rate(<idx>,<ctr>[,<table>]) integer
sc_gpc0_rate(<ctr>[,<table>]) integer
sc0_gpc0_rate([<table>]) integer
@ -21770,6 +21793,34 @@ sc2_get_gpt0([<table>]) : integer
Returns the value of the first General Purpose Tag associated to the
currently tracked counters. See also src_get_gpt0.
sc_glitch_cnt(<ctr>[,<table>]) : integer
sc0_glitch_cnt([<table>]) : integer
sc1_glitch_cnt([<table>]) : integer
sc2_glitch_cnt([<table>]) : integer
Returns the cumulative number of front connection glitches that were observed
on connections associated with the currently tracked counters. Usually these
result in requests or connections to be aborted so the returned value will
often correspond to past connections. There is no good nor bad value, but a
poor quality client may occasionally cause a few glitches per connection,
while a very bogus or malevolent client may quickly cause thousands of events
to be added on a connection. See also fc_glitches for the number affecting
the current connection, src_glitch_cnt to look them up per source, and
sc_glitch_rate for the event rate measurements.
sc_glitch_rate(<ctr>[,<table>]) : integer
sc0_glitch_rate([<table>]) : integer
sc1_glitch_rate([<table>]) : integer
sc2_glitch_rate([<table>]) : integer
Returns the average rate at which front connection glitches were observed for
the currently tracked counters, measured in amount of events over the period
configured in the table. Usually these glitches result in requests or
connections to be aborted so the returned value will often be related to past
connections. There is no good nor bad value, but a poor quality client may
occasionally cause a few glitches per connection, hence a low rate is
generally expected. However, a very bogus or malevolent client may quickly
cause thousands of events to be added per connection, and maintain a high
rate here. See also src_glitch_rate and sc_glitch_cnt.
sc_gpc_rate(<idx>,<ctr>[,<table>]) : integer
Returns the average increment rate of the General Purpose Counter at the
index <idx> of the array associated to the tracked counter of ID <ctr> from
@ -22084,6 +22135,29 @@ src_get_gpt0([<table>]) : integer
the designated stick-table. If the address is not found, zero is returned.
See also sc/sc0/sc1/sc2_get_gpt0.
src_glitch_cnt([<table>]) : integer
Returns the cumulative number of front connection glitches that were observed
on connections from the current connection's source address. Usually these
result in requests or connections to be aborted so the returned value will
often correspond to past connections. There is no good nor bad value, but a
poor quality client may occasionally cause a few glitches per connection,
while a very bogus or malevolent client may quickly cause thousands of events
to be added on a connection. See also fc_glitches for the number affecting
the current connection, sc_glitch_cnt to look them up in currently tracked
counters, and src_glitch_rate for the event rate measurements.
src_glitch_rate([<table>]) : integer
Returns the average rate at which front connection glitches were observed for
on connections from the current connection's source address, measured in
amount of events over the period configured in the table. Usually these
glitches result in requests or connections to be aborted so the returned
value will often be related to past connections. There is no good nor bad
value, but a poor quality client may occasionally cause a few glitches per
connection, hence a low rate is generally expected. However, a very bogus or
malevolent client may quickly cause thousands of events to be added per
connection, and maintain a high rate here. See also sc_glitch_rate and
src_glitch_cnt.
src_gpc_rate(<idx>[,<table>]) : integer
Returns the average increment rate of the General Purpose Counter at the
index <idx> of the array associated to the incoming connection's

View File

@ -227,6 +227,8 @@ bit
22: gpt array
23: gpc array
24: gpc rate array
25: glitch counter
26: glitch rate
d) Table Switch Message

View File

@ -58,7 +58,8 @@ enum {
STKTABLE_DT_GPT, /* array of gpt */
STKTABLE_DT_GPC, /* array of gpc */
STKTABLE_DT_GPC_RATE, /* array of gpc_rate */
STKTABLE_DT_GLITCH_CNT, /* cumulated number of front glitches */
STKTABLE_DT_GLITCH_RATE, /* rate of front glitches */
STKTABLE_STATIC_DATA_TYPES,/* number of types above */
/* up to STKTABLE_EXTRA_DATA_TYPES types may be registered here, always

View File

@ -401,4 +401,36 @@ static inline int stkctr_inc_bytes_out_ctr(struct stkctr *stkctr, unsigned long
return 1;
}
/* Add <inc> to the number of cumulated front glitches in the tracked counter
* <stkctr>. It returns 0 if the entry pointer does not exist and nothing is
* performed. Otherwise it returns 1.
*/
static inline int stkctr_add_glitch_ctr(struct stkctr *stkctr, uint inc)
{
struct stksess *ts;
void *ptr1, *ptr2;
ts = stkctr_entry(stkctr);
if (!ts)
return 0;
HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock);
ptr1 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GLITCH_CNT);
if (ptr1)
stktable_data_cast(ptr1, std_t_uint) += inc;
ptr2 = stktable_data_ptr(stkctr->table, ts, STKTABLE_DT_GLITCH_RATE);
if (ptr2)
update_freq_ctr_period(&stktable_data_cast(ptr2, std_t_frqp),
stkctr->table->data_arg[STKTABLE_DT_GLITCH_RATE].u, inc);
HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock);
/* If data was modified, we need to touch to re-schedule sync */
if (ptr1 || ptr2)
stktable_touch_local(stkctr->table, ts, 0);
return 1;
}
#endif /* _HAPROXY_STICK_TABLE_H */

View File

@ -1448,6 +1448,8 @@ struct stktable_data_type stktable_data_types[STKTABLE_DATA_TYPES] = {
[STKTABLE_DT_GPT] = { .name = "gpt", .std_type = STD_T_UINT, .is_array = 1, .as_is = 1 },
[STKTABLE_DT_GPC] = { .name = "gpc", .std_type = STD_T_UINT, .is_array = 1 },
[STKTABLE_DT_GPC_RATE] = { .name = "gpc_rate", .std_type = STD_T_FRQP, .is_array = 1, .arg_type = ARG_T_DELAY },
[STKTABLE_DT_GLITCH_CNT] = { .name = "glitch_cnt", .std_type = STD_T_UINT },
[STKTABLE_DT_GLITCH_RATE] = { .name = "glitch_rate", .std_type = STD_T_FRQP, .arg_type = ARG_T_DELAY },
};
/* Registers stick-table extra data type with index <idx>, name <name>, type
@ -1787,6 +1789,79 @@ static int sample_conv_table_bytes_out_rate(const struct arg *arg_p, struct samp
return !!ptr;
}
/* Casts sample <smp> to the type of the table specified in arg(0), and looks
* it up into this table. Returns the cumulated number of front glitches for the
* key if the key is present in the table, otherwise zero, so that comparisons
* can be easily performed. If the inspected parameter is not stored in the
* table, <not found> is returned.
*/
static int sample_conv_table_glitch_cnt(const struct arg *arg_p, struct sample *smp, void *private)
{
struct stktable *t;
struct stktable_key *key;
struct stksess *ts;
void *ptr;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
return 0;
ts = stktable_lookup_key(t, key);
smp->flags = SMP_F_VOL_TEST;
smp->data.type = SMP_T_SINT;
smp->data.u.sint = 0;
if (!ts) /* key not present */
return 1;
ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GLITCH_CNT);
if (ptr)
smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
stktable_release(t, ts);
return !!ptr;
}
/* Casts sample <smp> to the type of the table specified in arg(0), and looks
* it up into this table. Returns the front glitch rate the key if the key is
* present in the table, otherwise zero, so that comparisons can be easily
* performed. If the inspected parameter is not stored in the table, <not found>
* is returned.
*/
static int sample_conv_table_glitch_rate(const struct arg *arg_p, struct sample *smp, void *private)
{
struct stktable *t;
struct stktable_key *key;
struct stksess *ts;
void *ptr;
t = arg_p[0].data.t;
key = smp_to_stkey(smp, t);
if (!key)
return 0;
ts = stktable_lookup_key(t, key);
smp->flags = SMP_F_VOL_TEST;
smp->data.type = SMP_T_SINT;
smp->data.u.sint = 0;
if (!ts) /* key not present */
return 1;
ptr = stktable_data_ptr(t, ts, STKTABLE_DT_GLITCH_RATE);
if (ptr)
smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
t->data_arg[STKTABLE_DT_GLITCH_RATE].u);
stktable_release(t, ts);
return !!ptr;
}
/* Casts sample <smp> to the type of the table specified in arg_p(1), and looks
* it up into this table. Returns the value of the GPT[arg_p(0)] tag for the key
* if the key is present in the table, otherwise false, so that comparisons can
@ -4264,6 +4339,85 @@ smp_fetch_sc_conn_cur(const struct arg *args, struct sample *smp, const char *kw
return 1;
}
/* set <smp> to the cumulated number of glitches from the stream or session's
* tracked frontend counters. Supports being called as "sc[0-9]_glitch_cnt" or
* "src_glitch_cnt" only.
*/
static int
smp_fetch_sc_glitch_cnt(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
struct stkctr tmpstkctr;
struct stkctr *stkctr;
stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
if (!stkctr)
return 0;
smp->flags = SMP_F_VOL_TEST;
smp->data.type = SMP_T_SINT;
smp->data.u.sint = 0;
if (stkctr_entry(stkctr) != NULL) {
void *ptr;
ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GLITCH_CNT);
if (!ptr) {
if (stkctr == &tmpstkctr)
stktable_release(stkctr->table, stkctr_entry(stkctr));
return 0; /* parameter not stored */
}
HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
smp->data.u.sint = stktable_data_cast(ptr, std_t_uint);
HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
if (stkctr == &tmpstkctr)
stktable_release(stkctr->table, stkctr_entry(stkctr));
}
return 1;
}
/* set <smp> to the rate of glitches from the stream or session's tracked
* frontend counters. Supports being called as "sc[0-9]_glitch_rate" or
* "src_glitch_rate" only.
*/
static int
smp_fetch_sc_glitch_rate(const struct arg *args, struct sample *smp, const char *kw, void *private)
{
struct stkctr tmpstkctr;
struct stkctr *stkctr;
stkctr = smp_fetch_sc_stkctr(smp->sess, smp->strm, args, kw, &tmpstkctr);
if (!stkctr)
return 0;
smp->flags = SMP_F_VOL_TEST;
smp->data.type = SMP_T_SINT;
smp->data.u.sint = 0;
if (stkctr_entry(stkctr) != NULL) {
void *ptr;
ptr = stktable_data_ptr(stkctr->table, stkctr_entry(stkctr), STKTABLE_DT_GLITCH_RATE);
if (!ptr) {
if (stkctr == &tmpstkctr)
stktable_release(stkctr->table, stkctr_entry(stkctr));
return 0; /* parameter not stored */
}
HA_RWLOCK_RDLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
smp->data.u.sint = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
stkctr->table->data_arg[STKTABLE_DT_GLITCH_RATE].u);
HA_RWLOCK_RDUNLOCK(STK_SESS_LOCK, &stkctr_entry(stkctr)->lock);
if (stkctr == &tmpstkctr)
stktable_release(stkctr->table, stkctr_entry(stkctr));
}
return 1;
}
/* set <smp> to the cumulated number of streams from the stream's tracked
* frontend counters. Supports being called as "sc[0-9]_sess_cnt" or
* "src_sess_cnt" only.
@ -5573,6 +5727,8 @@ static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
{ "sc_get_gpc", smp_fetch_sc_get_gpc, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc_get_gpc0", smp_fetch_sc_get_gpc0, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc_get_gpc1", smp_fetch_sc_get_gpc1, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN },
{ "sc_glitch_cnt", smp_fetch_sc_glitch_cnt, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc_glitch_rate", smp_fetch_sc_glitch_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc_gpc_rate", smp_fetch_sc_gpc_rate, ARG3(2,SINT,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG2(1,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
@ -5601,6 +5757,8 @@ static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
{ "sc0_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc0_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc0_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc0_glitch_cnt", smp_fetch_sc_glitch_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc0_glitch_rate", smp_fetch_sc_glitch_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc0_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc0_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc0_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
@ -5628,6 +5786,8 @@ static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
{ "sc1_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc1_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc1_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc1_glitch_cnt", smp_fetch_sc_glitch_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc1_glitch_rate", smp_fetch_sc_glitch_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc1_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc1_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc1_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
@ -5654,6 +5814,8 @@ static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
{ "sc2_get_gpt0", smp_fetch_sc_get_gpt0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc2_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc2_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc2_glitch_cnt", smp_fetch_sc_glitch_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc2_glitch_rate", smp_fetch_sc_glitch_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc2_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc2_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
{ "sc2_http_err_cnt", smp_fetch_sc_http_err_cnt, ARG1(0,TAB), NULL, SMP_T_SINT, SMP_USE_INTRN, },
@ -5683,6 +5845,8 @@ static struct sample_fetch_kw_list smp_fetch_keywords = {ILH, {
{ "src_get_gpc", smp_fetch_sc_get_gpc, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
{ "src_get_gpc0", smp_fetch_sc_get_gpc0, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
{ "src_get_gpc1", smp_fetch_sc_get_gpc1, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
{ "src_glitch_cnt", smp_fetch_sc_glitch_cnt, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
{ "src_glitch_rate", smp_fetch_sc_glitch_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
{ "src_gpc_rate", smp_fetch_sc_gpc_rate, ARG2(2,SINT,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
{ "src_gpc0_rate", smp_fetch_sc_gpc0_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
{ "src_gpc1_rate", smp_fetch_sc_gpc1_rate, ARG1(1,TAB), NULL, SMP_T_SINT, SMP_USE_L4CLI, },
@ -5724,6 +5888,8 @@ static struct sample_conv_kw_list sample_conv_kws = {ILH, {
{ "table_gpc_rate", sample_conv_table_gpc_rate, ARG2(2,SINT,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
{ "table_gpc0_rate", sample_conv_table_gpc0_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
{ "table_gpc1_rate", sample_conv_table_gpc1_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
{ "table_glitch_cnt", sample_conv_table_glitch_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
{ "table_glitch_rate", sample_conv_table_glitch_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
{ "table_http_err_cnt", sample_conv_table_http_err_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
{ "table_http_err_rate", sample_conv_table_http_err_rate, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },
{ "table_http_fail_cnt", sample_conv_table_http_fail_cnt, ARG1(1,TAB), NULL, SMP_T_ANY, SMP_T_SINT },