From: Frédéric Lécaille Date: Mon, 17 Apr 2023 11:42:42 +0000 (+0200) Subject: BUG/MINOR: quic: Stop removing ACK ranges when building packets X-Git-Tag: v2.8-dev8~82 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4b2627beae586678be9964959af189d7310f66ca;p=thirdparty%2Fhaproxy.git BUG/MINOR: quic: Stop removing ACK ranges when building packets Since this commit: BUG/MINOR: quic: Possible wrapped values used as ACK tree purging limit. There are more chances that ack ranges may be removed from their trees when building a packet. It is preferable to impose a limit to these trees. This will be the subject of the a next commit to come. For now on, it is sufficient to stop deleting ack range from their trees. Remove quic_ack_frm_reduce_sz() and quic_rm_last_ack_ranges() which were there to do that. Make qc_frm_len() support ACK frames and calls it to ensure an ACK frame may be added to a packet before building it. Must be backported to 2.6 and 2.7. --- diff --git a/include/haproxy/quic_frame.h b/include/haproxy/quic_frame.h index aae45c9c7e..fd6bad7cb0 100644 --- a/include/haproxy/quic_frame.h +++ b/include/haproxy/quic_frame.h @@ -48,6 +48,27 @@ static inline size_t qc_frm_len(struct quic_frame *frm) size_t len = 0; switch (frm->type) { + case QUIC_FT_ACK: { + struct quic_tx_ack *tx_ack = &frm->tx_ack; + struct eb64_node *ar, *prev_ar; + struct quic_arng_node *ar_node, *prev_ar_node; + + ar = eb64_last(&tx_ack->arngs->root); + ar_node = eb64_entry(ar, struct quic_arng_node, first); + len += 1 + quic_int_getsize(ar_node->last); + len += quic_int_getsize(tx_ack->ack_delay); + len += quic_int_getsize(tx_ack->arngs->sz - 1); + len += quic_int_getsize(ar_node->last - ar_node->first.key); + + while ((prev_ar = eb64_prev(ar))) { + prev_ar_node = eb64_entry(prev_ar, struct quic_arng_node, first); + len += quic_int_getsize(ar_node->first.key - prev_ar_node->last - 2); + len += quic_int_getsize(prev_ar_node->last - prev_ar_node->first.key); + ar = prev_ar; + ar_node = eb64_entry(ar, struct quic_arng_node, first); + } + break; + } case QUIC_FT_RESET_STREAM: { struct quic_reset_stream *f = &frm->reset_stream; len += 1 + quic_int_getsize(f->id) + diff --git a/src/quic_conn.c b/src/quic_conn.c index 02e4044a49..2992ba0a96 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -4206,46 +4206,6 @@ static inline size_t sack_gap(struct quic_arng_node *p, return p->first.key - q->last - 2; } - -/* Remove the last elements of list of ack range updating its - * encoded size until it goes below . - * Returns 1 if succeeded, 0 if not (no more element to remove). - */ -static int quic_rm_last_ack_ranges(struct quic_conn *qc, - struct quic_arngs *arngs, size_t limit) -{ - int ret = 0; - struct eb64_node *last, *prev; - - TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc); - - last = eb64_last(&arngs->root); - while (last && arngs->enc_sz > limit) { - struct quic_arng_node *last_node, *prev_node; - - prev = eb64_prev(last); - if (!prev) { - TRACE_DEVEL(" not found", QUIC_EV_CONN_TXPKT, qc); - goto out; - } - - last_node = eb64_entry(last, struct quic_arng_node, first); - prev_node = eb64_entry(prev, struct quic_arng_node, first); - arngs->enc_sz -= quic_int_getsize(last_node->last - last_node->first.key); - arngs->enc_sz -= quic_int_getsize(sack_gap(prev_node, last_node)); - arngs->enc_sz -= quic_decint_size_diff(arngs->sz); - --arngs->sz; - eb64_delete(last); - pool_free(pool_head_quic_arng, last); - last = prev; - } - - ret = 1; - out: - TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc); - return ret; -} - /* Set the encoded size of QUIC ack ranges. */ static void quic_arngs_set_enc_sz(struct quic_conn *qc, struct quic_arngs *arngs) { @@ -7407,33 +7367,6 @@ static int quic_apply_header_protection(struct quic_conn *qc, unsigned char *buf return ret; } -/* Reduce the encoded size of ACK frame removing the last - * ACK ranges if needed to a value below in bytes. - * Return 1 if succeeded, 0 if not. - */ -static int quic_ack_frm_reduce_sz(struct quic_conn *qc, - struct quic_frame *ack_frm, size_t limit) -{ - size_t room, ack_delay_sz; - int ret = 0; - - TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc); - - ack_delay_sz = quic_int_getsize(ack_frm->tx_ack.ack_delay); - if (limit <= ack_delay_sz - 1) - goto leave; - - /* A frame is made of 1 byte for the frame type. */ - room = limit - ack_delay_sz - 1; - if (!quic_rm_last_ack_ranges(qc, ack_frm->tx_ack.arngs, room)) - goto leave; - - ret = 1 + ack_delay_sz + ack_frm->tx_ack.arngs->enc_sz; - leave: - TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc); - return ret; -} - /* Prepare into as most as possible ack-eliciting frame from their * prebuilt frames for encryption level to be encoded in a buffer * with as available room, and <*len> the packet Length field initialized @@ -7853,8 +7786,8 @@ static int qc_do_build_pkt(unsigned char *pos, const unsigned char *end, if (end - pos <= 1 + *pn_len) goto no_room; - ack_frm_len = quic_ack_frm_reduce_sz(qc, &ack_frm, end - 1 - *pn_len - pos); - if (!ack_frm_len) + ack_frm_len = qc_frm_len(&ack_frm); + if (ack_frm_len > end - 1 - *pn_len - pos) goto no_room; }