BUG/MINOR: quic: ignore AGAIN ncbuf err when parsing CRYPTO frames

This fix follows this previous one:

    BUG/MINOR: quic: reorder fragmented RX CRYPTO frames by their offsets

which is not sufficient when a client fragments and mixes its CRYPTO frames AND
leaveswith holes by packets. ngtcp2 (and perhaps chrome) splits theire CRYPTO
frames but without hole by packet. In such a case, the CRYPTO parsing leads to
QUIC_RX_RET_FRM_AGAIN errors which cannot be fixed when the peer resends its packets.
Indeed, even if the peer resends its frames in a different order, this does not
help because since the previous commit, the CRYPTO frames are ordered on haproxy side.

This issue was detected thanks to the interopt tests with quic-go as client. This
client fragments its CRYPTO frames, mixes them, and generate holes, and most of
the times with the retry test.

To fix this, when a QUIC_RX_RET_FRM_AGAIN error is encountered, the CRYPTO frames
parsing is not stop. This leaves chances to the next CRYPTO frames to be parsed.

Must be backported as far as 2.6 as the commit mentioned above.
This commit is contained in:
Frederic Lecaille 2025-09-01 14:35:14 +02:00
parent 26776c7b8f
commit fba80c7fe8

View File

@ -825,7 +825,7 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
struct quic_frame *frm = NULL; struct quic_frame *frm = NULL;
const unsigned char *pos, *end; const unsigned char *pos, *end;
enum quic_rx_ret_frm ret; enum quic_rx_ret_frm ret;
int fast_retrans = 0; int fast_retrans = 0, cf_err = 0;
TRACE_ENTER(QUIC_EV_CONN_PRSHPKT, qc); TRACE_ENTER(QUIC_EV_CONN_PRSHPKT, qc);
/* Skip the AAD */ /* Skip the AAD */
@ -1107,9 +1107,8 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
case QUIC_RX_RET_FRM_AGAIN: case QUIC_RX_RET_FRM_AGAIN:
TRACE_STATE("AGAIN encountered", QUIC_EV_CONN_PRSHPKT, qc); TRACE_STATE("AGAIN encountered", QUIC_EV_CONN_PRSHPKT, qc);
/* avoid freeing without eb_delete() */ cf_err = 1;
frm = NULL; break;
goto err;
case QUIC_RX_RET_FRM_DONE: case QUIC_RX_RET_FRM_DONE:
TRACE_PROTO("frame handled", QUIC_EV_CONN_PRSAFRM, qc, frm); TRACE_PROTO("frame handled", QUIC_EV_CONN_PRSAFRM, qc, frm);
@ -1127,6 +1126,9 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
qc_frm_free(qc, &frm); qc_frm_free(qc, &frm);
} }
if (cf_err)
goto err;
/* Error should be returned if some frames cannot be parsed. */ /* Error should be returned if some frames cannot be parsed. */
BUG_ON(!eb_is_empty(&cf_frms_tree)); BUG_ON(!eb_is_empty(&cf_frms_tree));