]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: quic: fix retry token check inconsistency
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 9 Nov 2023 15:44:50 +0000 (16:44 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 9 Nov 2023 15:57:37 +0000 (16:57 +0100)
A client may send multiple INITIAL packets if ClientHello is too big for
only one. In case a Retry token is used, the client must reuse it for
every INITIAL packets.

On the haproxy server side, there was an inconsistency to handle these
packets depending on the socket mode :
* when using listener socket, token is always revalidated.
* when using connection socket, token check is bypassed. This is because
  quic_conn instance is known through its socket and thus
  quic_rx_pkt_retrieve_conn() is not necessary.

RFC 9000 does not seems to mandate retry token validation after the
first INITIAL packet per connection. Thus, this patch chooses to bypass
the check every time the connection instance is known, as this indicates
that a previous token was already validated.

This should be backported up to 2.7.

src/quic_rx.c

index 9f11a3e16879562fb126c05653d621bb117fb514..d25f7ccfedfe00a05e6d406b9b66483e4565af5e 100644 (file)
@@ -1947,11 +1947,6 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt,
        if (pkt->type == QUIC_PACKET_TYPE_INITIAL) {
                BUG_ON(!pkt->version); /* This must not happen. */
 
-               if (pkt->token_len) {
-                       if (!quic_retry_token_check(pkt, dgram, l, qc, &token_odcid))
-                               goto err;
-               }
-
                if (!qc) {
                        struct quic_cid_tree *tree;
                        struct ebmb_node *node;
@@ -1973,8 +1968,13 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt,
                                goto out;
                        }
 
-                       if (!pkt->token_len && !(l->bind_conf->options & BC_O_QUIC_FORCE_RETRY) &&
-                           HA_ATOMIC_LOAD(&prx_counters->half_open_conn) >= global.tune.quic_retry_threshold) {
+                       if (pkt->token_len) {
+                               /* Validate the token only when connection is unknown. */
+                               if (!quic_retry_token_check(pkt, dgram, l, qc, &token_odcid))
+                                       goto err;
+                       }
+                       else if (!(l->bind_conf->options & BC_O_QUIC_FORCE_RETRY) &&
+                                HA_ATOMIC_LOAD(&prx_counters->half_open_conn) >= global.tune.quic_retry_threshold) {
                                TRACE_PROTO("Initial without token, sending retry",
                                            QUIC_EV_CONN_LPKT, NULL, NULL, NULL, pkt->version);
                                if (send_retry(l->rx.fd, &dgram->saddr, pkt, pkt->version)) {