From: Amaury Denoyelle Date: Fri, 2 Dec 2022 08:57:32 +0000 (+0100) Subject: MINOR: quic: detect connection migration X-Git-Tag: v2.8-dev1~195 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=eec0b3c1bdba757f427c5924ebd383633597300f;p=thirdparty%2Fhaproxy.git MINOR: quic: detect connection migration Detect connection migration attempted by the client. This is done by comparing addresses stored in quic-conn with src/dest addresses of the UDP datagram. A new function qc_handle_conn_migration() has been added. For the moment, no operation is conducted and the function will be completed during connection migration implementation. The only notable things is the increment of a new counter "quic_conn_migration_done". This should be backported up to 2.7. --- diff --git a/include/haproxy/quic_stats-t.h b/include/haproxy/quic_stats-t.h index 95d0af9e61..56961e0476 100644 --- a/include/haproxy/quic_stats-t.h +++ b/include/haproxy/quic_stats-t.h @@ -24,6 +24,8 @@ enum { QUIC_ST_HALF_OPEN_CONN, QUIC_ST_HDSHK_FAIL, QUIC_ST_STATELESS_RESET_SENT, + /* Special events of interest */ + QUIC_ST_CONN_MIGRATION_DONE, /* Transport errors */ QUIC_ST_TRANSP_ERR_NO_ERROR, QUIC_ST_TRANSP_ERR_INTERNAL_ERROR, @@ -68,6 +70,8 @@ struct quic_counters { long long half_open_conn; /* total number of half open connections */ long long hdshk_fail; /* total number of handshake failures */ long long stateless_reset_sent; /* total number of handshake failures */ + /* Special events of interest */ + long long conn_migration_done; /* total number of connection migration handled */ /* Transport errors */ long long quic_transp_err_no_error; /* total number of NO_ERROR connection errors */ long long quic_transp_err_internal_error; /* total number of INTERNAL_ERROR connection errors */ diff --git a/src/quic_conn.c b/src/quic_conn.c index 2dd21b9fd2..17f31ebc7a 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -6312,6 +6312,37 @@ static int qc_rx_check_closing(struct quic_conn *qc, return 1; } +/* React to a connection migration initiated on by a client with the new + * path addresses /. + * + * Returns 0 on success else non-zero. + */ +static int qc_handle_conn_migration(struct quic_conn *qc, + const struct sockaddr_storage *peer_addr, + const struct sockaddr_storage *local_addr) +{ + TRACE_ENTER(QUIC_EV_CONN_LPKT, qc); + + /* RFC 9000 9. Connection Migration + * + * TODO + * An endpoint MUST + * perform path validation (Section 8.2) if it detects any change to a + * peer's address, unless it has previously validated that address. + */ + + qc->local_addr = *local_addr; + qc->peer_addr = *peer_addr; + HA_ATOMIC_INC(&qc->prx_counters->conn_migration_done); + + TRACE_LEAVE(QUIC_EV_CONN_LPKT, qc); + return 0; + + err: + TRACE_LEAVE(QUIC_EV_CONN_LPKT, qc); + return 1; +} + /* Handle a parsed packet by the connection . Data will be copied * into receive buffer after header protection removal procedure. * @@ -7315,6 +7346,17 @@ int quic_dgram_parse(struct quic_dgram *dgram, struct quic_conn *from_qc, goto next; } + /* Detect QUIC connection migration. */ + if (ipcmp(&qc->peer_addr, &dgram->saddr, 1) || + ipcmp(&qc->local_addr, &dgram->daddr, 1)) { + if (qc_handle_conn_migration(qc, &dgram->saddr, &dgram->daddr)) { + /* Skip the entire datagram. */ + TRACE_ERROR("error during connection migration, datagram dropped", QUIC_EV_CONN_LPKT, qc); + pkt->len = end - pos; + goto next; + } + } + qc_rx_pkt_handle(qc, pkt, dgram, pos, &tasklist_head); next: diff --git a/src/quic_stats.c b/src/quic_stats.c index 71820d228e..7f1f2cd6cd 100644 --- a/src/quic_stats.c +++ b/src/quic_stats.c @@ -33,6 +33,9 @@ static struct name_desc quic_stats[] = { .desc = "Total number of handshake failures" }, [QUIC_ST_STATELESS_RESET_SENT] = { .name = "quic_stless_rst_sent", .desc = "Total number of stateless reset packet sent" }, + /* Special events of interest */ + [QUIC_ST_CONN_MIGRATION_DONE] = { .name = "quic_conn_migration_done", + .desc = "Total number of connection migration proceeded" }, /* Transport errors */ [QUIC_ST_TRANSP_ERR_NO_ERROR] = { .name = "quic_transp_err_no_error", .desc = "Total number of NO_ERROR errors received" }, @@ -104,6 +107,8 @@ static void quic_fill_stats(void *data, struct field *stats) stats[QUIC_ST_HALF_OPEN_CONN] = mkf_u64(FN_GAUGE, counters->half_open_conn); stats[QUIC_ST_HDSHK_FAIL] = mkf_u64(FN_COUNTER, counters->hdshk_fail); stats[QUIC_ST_STATELESS_RESET_SENT] = mkf_u64(FN_COUNTER, counters->stateless_reset_sent); + /* Special events of interest */ + stats[QUIC_ST_CONN_MIGRATION_DONE] = mkf_u64(FN_COUNTER, counters->conn_migration_done); /* Transport errors */ stats[QUIC_ST_TRANSP_ERR_NO_ERROR] = mkf_u64(FN_COUNTER, counters->quic_transp_err_no_error); stats[QUIC_ST_TRANSP_ERR_INTERNAL_ERROR] = mkf_u64(FN_COUNTER, counters->quic_transp_err_internal_error);