]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: detect connection migration
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 2 Dec 2022 08:57:32 +0000 (09:57 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 2 Dec 2022 13:45:43 +0000 (14:45 +0100)
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.

include/haproxy/quic_stats-t.h
src/quic_conn.c
src/quic_stats.c

index 95d0af9e6170fa2ea1417b2ca910409dbeb06317..56961e0476638577698e7e9154929f2d55fb158e 100644 (file)
@@ -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 */
index 2dd21b9fd2e4adf582643b09896a89480e00db98..17f31ebc7a4befe58bb261412a0dfa104c71cbc0 100644 (file)
@@ -6312,6 +6312,37 @@ static int qc_rx_check_closing(struct quic_conn *qc,
        return 1;
 }
 
+/* React to a connection migration initiated on <qc> by a client with the new
+ * path addresses <peer_addr>/<local_addr>.
+ *
+ * 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 <pkt> by the connection <qc>. Data will be copied
  * into <qc> 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:
index 71820d228e5bc8039ac5902dd6e224ca9a97fbfc..7f1f2cd6cd495b103011b97e1531dc37a7b624e7 100644 (file)
@@ -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);