diff --git a/include/haproxy/quic_conn-t.h b/include/haproxy/quic_conn-t.h index f5fc207ba..d85dc6fd3 100644 --- a/include/haproxy/quic_conn-t.h +++ b/include/haproxy/quic_conn-t.h @@ -398,6 +398,8 @@ struct quic_dgram { #define QUIC_FL_RX_PACKET_ACK_ELICITING (1UL << 0) /* Packet is the first one in the containing datagram. */ #define QUIC_FL_RX_PACKET_DGRAM_FIRST (1UL << 1) +/* Spin bit set */ +#define QUIC_FL_RX_PACKET_SPIN_BIT (1UL << 2) struct quic_rx_packet { struct list list; @@ -608,6 +610,7 @@ enum qc_mux_state { /* Flags at connection level */ #define QUIC_FL_CONN_ANTI_AMPLIFICATION_REACHED (1U << 0) +#define QUIC_FL_CONN_SPIN_BIT (1U << 1) /* Spin bit set by remote peer */ #define QUIC_FL_CONN_POST_HANDSHAKE_FRAMES_BUILT (1U << 2) #define QUIC_FL_CONN_LISTENER (1U << 3) #define QUIC_FL_CONN_ACCEPT_REGISTERED (1U << 4) diff --git a/src/quic_conn.c b/src/quic_conn.c index b6344db2b..2cae51cc3 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -4190,6 +4190,31 @@ int quic_update_ack_ranges_list(struct quic_conn *qc, TRACE_LEAVE(QUIC_EV_CONN_RXPKT, qc); return ret; } + +/* Detect the value of the spin bit to be used. */ +static inline void qc_handle_spin_bit(struct quic_conn *qc, struct quic_rx_packet *pkt, + struct quic_enc_level *qel) +{ + uint64_t largest_pn = qel->pktns->rx.largest_pn; + + if (qel != &qc->els[QUIC_TLS_ENC_LEVEL_APP] || largest_pn == -1 || + pkt->pn <= largest_pn) + return; + + if (qc_is_listener(qc)) { + if (pkt->flags & QUIC_FL_RX_PACKET_SPIN_BIT) + qc->flags |= QUIC_FL_CONN_SPIN_BIT; + else + qc->flags &= ~QUIC_FL_CONN_SPIN_BIT; + } + else { + if (pkt->flags & QUIC_FL_RX_PACKET_SPIN_BIT) + qc->flags &= ~QUIC_FL_CONN_SPIN_BIT; + else + qc->flags |= QUIC_FL_CONN_SPIN_BIT; + } +} + /* Remove the header protection of packets at encryption level. * Always succeeds. */ @@ -4216,6 +4241,7 @@ static inline void qc_rm_hp_pkts(struct quic_conn *qc, struct quic_enc_level *el TRACE_ERROR("hp removing error", QUIC_EV_CONN_ELRMHP, qc); } else { + qc_handle_spin_bit(qc, pqpkt, el); /* The AAD includes the packet number field */ pqpkt->aad_len = pqpkt->pn_offset + pqpkt->pnl; /* Store the packet into the tree of packets to decrypt. */ @@ -5763,6 +5789,7 @@ static inline int qc_try_rm_hp(struct quic_conn *qc, goto out; } + qc_handle_spin_bit(qc, pkt, qel); /* The AAD includes the packet number field. */ pkt->aad_len = pkt->pn_offset + pkt->pnl; if (pkt->len - pkt->aad_len < QUIC_TLS_TAG_LEN) { @@ -5845,6 +5872,8 @@ static inline int qc_parse_hd_form(struct quic_rx_packet *pkt, } } else { + if (byte0 & QUIC_PACKET_SPIN_BIT) + pkt->flags |= QUIC_FL_RX_PACKET_SPIN_BIT; pkt->type = QUIC_PACKET_TYPE_SHORT; *long_header = 0; } @@ -7023,6 +7052,8 @@ static int quic_build_packet_short_header(unsigned char **buf, const unsigned ch unsigned char tls_flags) { int ret = 0; + unsigned char spin_bit = + (qc->flags & QUIC_FL_CONN_SPIN_BIT) ? QUIC_PACKET_SPIN_BIT : 0; TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc); @@ -7032,7 +7063,7 @@ static int quic_build_packet_short_header(unsigned char **buf, const unsigned ch } /* #0 byte flags */ - *(*buf)++ = QUIC_PACKET_FIXED_BIT | + *(*buf)++ = QUIC_PACKET_FIXED_BIT | spin_bit | ((tls_flags & QUIC_FL_TLS_KP_BIT_SET) ? QUIC_PACKET_KEY_PHASE_BIT : 0) | (pn_len - 1); /* Destination connection ID */ if (qc->dcid.len) {