From: Amaury Denoyelle Date: Mon, 6 Nov 2023 09:32:17 +0000 (+0100) Subject: MEDIUM: quic: adjust address validation X-Git-Tag: v2.9-dev10~112 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d38bb7f8a7170c8c89d9c02ebd472a2a69e864aa;p=thirdparty%2Fhaproxy.git MEDIUM: quic: adjust address validation 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. --- diff --git a/include/haproxy/quic_conn-t.h b/include/haproxy/quic_conn-t.h index 05b48f8905..ae2e7685e8 100644 --- a/include/haproxy/quic_conn-t.h +++ b/include/haproxy/quic_conn-t.h @@ -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) */ diff --git a/src/quic_conn.c b/src/quic_conn.c index 69fa996ca8..03d8076df2 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -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; diff --git a/src/quic_rx.c b/src/quic_rx.c index 37ab52176b..3ec02f22c3 100644 --- a/src/quic_rx.c +++ b/src/quic_rx.c @@ -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) {