diff --git a/include/haproxy/quic_conn-t.h b/include/haproxy/quic_conn-t.h index f2c7680e4..68362343d 100644 --- a/include/haproxy/quic_conn-t.h +++ b/include/haproxy/quic_conn-t.h @@ -618,6 +618,7 @@ enum qc_mux_state { /* gap here */ #define QUIC_FL_CONN_HALF_OPEN_CNT_DECREMENTED (1U << 11) /* The half-open connection counter was decremented */ #define QUIC_FL_CONN_HANDSHAKE_SPEED_UP (1U << 12) /* Handshake speeding up was done */ +#define QUIC_FL_CONN_TO_KILL (1U << 24) /* Unusable connection, to be killed */ #define QUIC_FL_CONN_TX_TP_RECEIVED (1U << 25) /* Peer transport parameters have been received (used for the transmitting part) */ #define QUIC_FL_CONN_FINALIZED (1U << 26) /* QUIC connection finalized (functional, ready to send/receive) */ #define QUIC_FL_CONN_NOTIFY_CLOSE (1U << 27) /* MUX notified about quic-conn imminent closure (idle-timeout or CONNECTION_CLOSE emission/reception) */ diff --git a/include/haproxy/quic_conn.h b/include/haproxy/quic_conn.h index 5e92afbee..dc8013762 100644 --- a/include/haproxy/quic_conn.h +++ b/include/haproxy/quic_conn.h @@ -752,6 +752,8 @@ void qc_check_close_on_released_mux(struct quic_conn *qc); void quic_conn_release(struct quic_conn *qc); +void qc_kill_conn(struct quic_conn *qc); + int quic_dgram_parse(struct quic_dgram *dgram, struct quic_conn *qc, struct listener *li); diff --git a/src/quic_conn.c b/src/quic_conn.c index 904e6699b..d515b6d28 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -272,7 +272,9 @@ static void quic_trace(enum trace_level level, uint64_t mask, const struct trace if (mask & QUIC_EV_TRANSP_PARAMS) { const struct quic_transport_params *p = a2; - quic_transport_params_dump(&trace_buf, qc, p); + + if (p) + quic_transport_params_dump(&trace_buf, qc, p); } if (mask & QUIC_EV_CONN_ADDDATA) { @@ -727,6 +729,13 @@ static inline int quic_peer_validated_addr(struct quic_conn *qc) return 0; } +/* To be called to kill a connection as soon as possible (without sending any packet). */ +void qc_kill_conn(struct quic_conn *qc) +{ + qc->flags |= QUIC_FL_CONN_TO_KILL; + task_wakeup(qc->idle_timer_task, TASK_WOKEN_OTHER); +} + /* Set the timer attached to the QUIC connection with as I/O handler and used for * both loss detection and PTO and schedule the task assiated to this timer if needed. */ @@ -926,6 +935,12 @@ int ha_quic_set_encryption_secrets(SSL *ssl, enum ssl_encryption_level_t level, TRACE_ENTER(QUIC_EV_CONN_RWSEC, qc); BUG_ON(secret_len > QUIC_TLS_SECRET_LEN); + + if (qc->flags & QUIC_FL_CONN_TO_KILL) { + TRACE_PROTO("connection to be killed", QUIC_EV_CONN_ADDDATA, qc); + goto out; + } + if (qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE) { TRACE_PROTO("CC required", QUIC_EV_CONN_RWSEC, qc); goto out; @@ -1220,6 +1235,11 @@ int ha_quic_add_handshake_data(SSL *ssl, enum ssl_encryption_level_t level, qc = SSL_get_ex_data(ssl, ssl_qc_app_data_index); TRACE_ENTER(QUIC_EV_CONN_ADDDATA, qc); + if (qc->flags & QUIC_FL_CONN_TO_KILL) { + TRACE_PROTO("connection to be killed", QUIC_EV_CONN_ADDDATA, qc); + goto out; + } + if (qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE) { TRACE_PROTO("CC required", QUIC_EV_CONN_ADDDATA, qc); goto out; @@ -2304,6 +2324,11 @@ static inline int qc_provide_cdata(struct quic_enc_level *el, if (state < QUIC_HS_ST_COMPLETE) { ssl_err = SSL_do_handshake(ctx->ssl); + if (qc->flags & QUIC_FL_CONN_TO_KILL) { + TRACE_DEVEL("connection to be killed", QUIC_EV_CONN_IO_CB, qc); + goto leave; + } + /* Finalize the connection as soon as possible if the peer transport parameters * have been received. This may be useful to send packets even if this * handshake fails. @@ -4380,6 +4405,11 @@ struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int sta goto out; } + if (qc->flags & QUIC_FL_CONN_TO_KILL) { + TRACE_DEVEL("connection to be killed", QUIC_EV_CONN_IO_CB, qc); + goto out; + } + if ((qc->flags & QUIC_FL_CONN_DRAINING) && !(qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE)) { TRACE_STATE("draining connection (must not send packets)", QUIC_EV_CONN_IO_CB, qc); @@ -4475,6 +4505,11 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state) if (!qc_treat_rx_pkts(qc, qel, next_qel, force_ack)) goto out; + if (qc->flags & QUIC_FL_CONN_TO_KILL) { + TRACE_DEVEL("connection to be killed", QUIC_EV_CONN_PHPKTS, qc); + goto out; + } + if ((qc->flags & QUIC_FL_CONN_DRAINING) && !(qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE)) goto out; diff --git a/src/quic_tp.c b/src/quic_tp.c index 85e2870ee..e76375727 100644 --- a/src/quic_tp.c +++ b/src/quic_tp.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include @@ -626,6 +626,8 @@ int quic_transport_params_store(struct quic_conn *qc, int server, { struct quic_transport_params *tx_params = &qc->tx.params; struct quic_transport_params *rx_params = &qc->rx.params; + /* Initial source connection ID */ + struct tp_cid *iscid; /* initialize peer TPs to RFC default value */ quic_dflt_transport_params_cpy(tx_params); @@ -650,6 +652,18 @@ int quic_transport_params_store(struct quic_conn *qc, int server, QUIC_MAX(tx_params->max_idle_timeout, rx_params->max_idle_timeout); TRACE_PROTO("\nTX(remote) transp. params.", QUIC_EV_TRANSP_PARAMS, qc, tx_params); + /* Check that the "initial_source_connection_id" transport parameter matches + * the SCID received which is also the DCID of the connection. + */ + iscid = &tx_params->initial_source_connection_id; + if (qc->dcid.len != iscid->len || + (qc->dcid.len && memcmp(qc->dcid.data, iscid->data, qc->dcid.len))) { + TRACE_PROTO("initial_source_connection_id transport parameter mismatch", + QUIC_EV_TRANSP_PARAMS, qc); + /* Kill the connection as soon as possible */ + qc_kill_conn(qc); + } + return 1; }