]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: quic: adjust address validation
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 6 Nov 2023 09:32:17 +0000 (10:32 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 9 Nov 2023 15:23:52 +0000 (16:23 +0100)
When a new QUIC connection is created, server considers peer address as
not yet validated. The server must limit its sending up to 3 times the
content already received. This is a defensive measure to avoid flooding
a remote host victim of address spoofing.

This patch adjust the condition to consider the peer address as
validated. Two conditions are now considered :
* successful handling of a received HANDSHAKE packet. This was already
  done before although implemented in a different way.
* validation of a Retry token. This was not considered prior this patch
  despite RFC recommandation.

This patch also adjusts how a connection is internally labelled as using
a validated peer address. Before, above conditions were checked via
quic_peer_validated_addr(). Now, a flag QUIC_FL_CONN_PEER_VALIDATED_ADDR
is set to labelled this. It already existed prior this patch but was
only used for quic_cc_conn. This should now be more explicit.

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

index 05b48f8905c9c6dcf318c1d3c431506adde9d4e8..ae2e7685e8f558c57577fac4e04c7ef4dbaf73e7 100644 (file)
@@ -247,8 +247,7 @@ struct quic_connection_id {
        uint tid;              /* Attached Thread ID for the connection. */
 };
 
-/* Flag the packet number space as having received a packet */
-#define QUIC_FL_PKTNS_PKT_RECEIVED  (1UL << 0)
+/* unused: 0x01 */
 /* Flag the packet number space as requiring an ACK frame to be sent. */
 #define QUIC_FL_PKTNS_ACK_REQUIRED  (1UL << 1)
 /* Flag the packet number space as needing probing */
@@ -394,7 +393,7 @@ struct quic_conn_cntrs {
 #define QUIC_FL_CONN_IO_TO_REQUEUE               (1U << 14) /* IO handler must be requeued on new thread after connection migration */
 #define QUIC_FL_CONN_IPKTNS_DCD                  (1U << 15) /* Initial packet number space discarded  */
 #define QUIC_FL_CONN_HPKTNS_DCD                  (1U << 16) /* Handshake packet number space discarded  */
-#define QUIC_FL_CONN_PEER_VALIDATED_ADDR         (1U << 17) /* Connection with peer validated address */
+#define QUIC_FL_CONN_PEER_VALIDATED_ADDR         (1U << 17) /* Peer address is considered as validated for this connection. */
 #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) */
index 69fa996ca8ac2fe8e85c6b4d01460afb611aba2d..03d8076df2900417d7c40e2e059c9a0bacf152f4 100644 (file)
@@ -151,9 +151,7 @@ int quic_peer_validated_addr(struct quic_conn *qc)
        if (!qc_is_listener(qc))
                return 1;
 
-       if ((qc->hpktns && (qc->hpktns->flags & QUIC_FL_PKTNS_PKT_RECEIVED)) ||
-           (qc->apktns && (qc->apktns->flags & QUIC_FL_PKTNS_PKT_RECEIVED)) ||
-           qc->state >= QUIC_HS_ST_COMPLETE)
+       if (qc->flags & QUIC_FL_CONN_PEER_VALIDATED_ADDR)
                return 1;
 
        BUG_ON(qc->bytes.prep > 3 * qc->bytes.rx);
@@ -845,8 +843,6 @@ static struct quic_cc_conn *qc_new_cc_conn(struct quic_conn *qc)
        if (qc->fd >= 0)
                fdtab[cc_qc->fd].owner = cc_qc;
        cc_qc->flags = qc->flags;
-       if (quic_peer_validated_addr(qc))
-           cc_qc->flags |= QUIC_FL_CONN_PEER_VALIDATED_ADDR;
        cc_qc->err = qc->err;
 
        cc_qc->nb_pkt_for_cc = qc->nb_pkt_for_cc;
@@ -1383,6 +1379,15 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
        LIST_APPEND(&th_ctx->quic_conns, &qc->el_th_ctx);
        qc->qc_epoch = HA_ATOMIC_LOAD(&qc_epoch);
 
+       /* If connection is instantiated due to an INITIAL packet with an
+        * already checked token, consider the peer address as validated.
+        */
+       if (token_odcid->len) {
+               TRACE_STATE("validate peer address due to initial token",
+                           QUIC_EV_CONN_INIT, qc);
+               qc->flags |= QUIC_FL_CONN_PEER_VALIDATED_ADDR;
+       }
+
        TRACE_LEAVE(QUIC_EV_CONN_INIT, qc);
 
        return qc;
index 37ab52176bccc34ee8ed61248c135edc303cf58f..3ec02f22c39991d6b452019bd50d313070a0e5c6 100644 (file)
@@ -1158,9 +1158,6 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
                }
        }
 
-       /* Flag this packet number space as having received a packet. */
-       qel->pktns->flags |= QUIC_FL_PKTNS_PKT_RECEIVED;
-
        if (fast_retrans && qc->iel && qc->hel) {
                struct quic_enc_level *iqel = qc->iel;
                struct quic_enc_level *hqel = qc->hel;
@@ -1381,6 +1378,19 @@ int qc_treat_rx_pkts(struct quic_conn *qc)
                                else {
                                        struct quic_arng ar = { .first = pkt->pn, .last = pkt->pn };
 
+                                       /* RFC 9000 8.1. Address Validation during Connection Establishment
+                                        *
+                                        * Connection establishment implicitly provides address validation for
+                                        * both endpoints. In particular, receipt of a packet protected with
+                                        * Handshake keys confirms that the peer successfully processed an
+                                        * Initial packet.
+                                        */
+                                       if (qel == qc->hel) {
+                                               TRACE_STATE("validate peer address on handshake packet",
+                                                           QUIC_EV_CONN_RXPKT, qc, pkt);
+                                               qc->flags |= QUIC_FL_CONN_PEER_VALIDATED_ADDR;
+                                       }
+
                                        /* Update the list of ranges to acknowledge. */
                                        if (quic_update_ack_ranges_list(qc, &qel->pktns->rx.arngs, &ar)) {
                                                if (pkt->flags & QUIC_FL_RX_PACKET_ACK_ELICITING) {