- tune.pt.zero-copy-forwarding
- tune.quic.cc-hystart
- tune.quic.frontend.conn-tx-buffers.limit
+ - tune.quic.frontend.glitches-threshold
- tune.quic.frontend.max-idle-timeout
- tune.quic.frontend.max-streams-bidi
- tune.quic.max-frame-loss
and memory consumption and can be adjusted according to an estimated round
time-trip. Each buffer is tune.bufsize.
+tune.quic.frontend.glitches-threshold <number>
+ Sets the threshold for the number of glitches on a frontend connection, where
+ that connection will automatically be killed. This allows to automatically
+ kill misbehaving connections without having to write explicit rules for them.
+ The default value is zero, indicating that no threshold is set so that no
+ event will cause a connection to be closed. Beware that some QUIC clients may
+ occasionally cause a few glitches over long lasting connection, so any non-
+ zero value here should probably be in the hundreds or thousands to be
+ effective without affecting slightly bogus clients.
+
+ See also: fc_glitches
+
tune.quic.frontend.max-idle-timeout <timeout>
Sets the QUIC max_idle_timeout transport parameters in milliseconds for
frontends which determines the period of time after which a connection silently
#ifdef USE_QUIC
unsigned int quic_backend_max_idle_timeout;
unsigned int quic_frontend_max_idle_timeout;
+ unsigned int quic_frontend_glitches_threshold;
unsigned int quic_frontend_max_streams_bidi;
unsigned int quic_retry_threshold;
unsigned int quic_reorder_ratio;
uint64_t nb_sc; /* number of attached stream connectors */
uint64_t nb_hreq; /* number of in-progress http requests */
uint32_t flags; /* QC_CF_* */
+ int glitches; /* total number of glitches on this connection */
/* flow-control fields set by us enforced on our side. */
struct {
/* Increment app counters on CONNECTION_CLOSE_APP reception. */
void (*inc_err_cnt)(void *ctx, int err_code);
+ /* Set QCC error code as suspicious activity has been detected. */
+ void (*report_susp)(void *ctx);
};
#endif /* USE_QUIC */
#include <haproxy/stconn.h>
void qcc_set_error(struct qcc *qcc, int err, int app);
+int qcc_report_glitch(struct qcc *qcc, int inc);
struct qcs *qcc_init_stream_local(struct qcc *qcc, int bidi);
struct stconn *qcs_attach_sc(struct qcs *qcs, struct buffer *buf, char fin);
int qcs_is_close_local(struct qcs *qcs);
suffix = args[0] + prefix_len;
if (strcmp(suffix, "frontend.conn-tx-buffers.limit") == 0)
global.tune.quic_streams_buf = arg;
+ else if (strcmp(suffix, "frontend.glitches-threshold") == 0)
+ global.tune.quic_frontend_glitches_threshold = arg;
else if (strcmp(suffix, "frontend.max-streams-bidi") == 0)
global.tune.quic_frontend_max_streams_bidi = arg;
else if (strcmp(suffix, "max-frame-loss") == 0)
{ CFG_GLOBAL, "tune.quic.backend.max-idle-timeou", cfg_parse_quic_time },
{ CFG_GLOBAL, "tune.quic.cc-hystart", cfg_parse_quic_tune_on_off },
{ CFG_GLOBAL, "tune.quic.frontend.conn-tx-buffers.limit", cfg_parse_quic_tune_setting },
+ { CFG_GLOBAL, "tune.quic.frontend.glitches-threshold", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.frontend.max-streams-bidi", cfg_parse_quic_tune_setting },
{ CFG_GLOBAL, "tune.quic.frontend.max-idle-timeout", cfg_parse_quic_time },
{ CFG_GLOBAL, "tune.quic.max-frame-loss", cfg_parse_quic_tune_setting },
h3_inc_err_cnt(h3c->prx_counters, err_code);
}
+static void h3_report_susp(void *ctx)
+{
+ struct h3c *h3c = ctx;
+ h3c->qcc->err = quic_err_app(H3_ERR_EXCESSIVE_LOAD);
+}
+
static inline const char *h3_ft_str(uint64_t type)
{
switch (type) {
.detach = h3_detach,
.shutdown = h3_shutdown,
.inc_err_cnt = h3_stats_inc_err_cnt,
+ .report_susp = h3_report_susp,
.release = h3_release,
};
tasklet_wakeup(qcc->wait_event.tasklet);
}
+/* Increment glitch counter for <qcc> connection by <inc> steps. If configured
+ * threshold reached, close the connection with an error code.
+ */
+int qcc_report_glitch(struct qcc *qcc, int inc)
+{
+ const int max = global.tune.quic_frontend_glitches_threshold;
+
+ qcc->glitches += inc;
+ if (max && qcc->glitches >= max && !(qcc->flags & QC_CF_ERRL)) {
+ if (qcc->app_ops->report_susp) {
+ qcc->app_ops->report_susp(qcc->ctx);
+ qcc_set_error(qcc, qcc->err.code, 1);
+ }
+ else {
+ qcc_set_error(qcc, QC_ERR_INTERNAL_ERROR, 0);
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
/* Open a locally initiated stream for the connection <qcc>. Set <bidi> for a
* bidirectional stream, else an unidirectional stream is opened. The next
* available ID on the connection will be used according to the stream type.
conn->ctx = qcc;
qcc->nb_hreq = qcc->nb_sc = 0;
qcc->flags = 0;
+ qcc->glitches = 0;
qcc->err = quic_err_transport(QC_ERR_NO_ERROR);
/* Server parameters, params used for RX flow control. */
case MUX_CTL_EXIT_STATUS:
return MUX_ES_UNKNOWN;
+ case MUX_CTL_GET_GLITCHES:
+ return qcc->glitches;
+
case MUX_CTL_GET_NBSTRM: {
struct qcs *qcs;
unsigned int nb_strm = qcc->nb_sc;