diff --git a/include/haproxy/quic_frame.h b/include/haproxy/quic_frame.h index 3994e8f53..0c5fe70ca 100644 --- a/include/haproxy/quic_frame.h +++ b/include/haproxy/quic_frame.h @@ -38,9 +38,16 @@ int qc_build_frm(unsigned char **pos, const unsigned char *end, struct quic_frame *frm, struct quic_tx_packet *pkt, struct quic_conn *conn); -int qc_parse_frm(struct quic_frame *frm, struct quic_rx_packet *pkt, - const unsigned char **pos, const unsigned char *end, - struct quic_conn *conn); +int qc_parse_frm_type(struct quic_frame *frm, + const unsigned char **pos, const unsigned char *end, + struct quic_conn *conn); + +int qc_parse_frm_pkt(const struct quic_frame *frm, + const struct quic_rx_packet *pkt, int *flags); + +int qc_parse_frm_payload(struct quic_frame *frm, + const unsigned char **pos, const unsigned char *end, + struct quic_conn *qc); void qc_release_frm(struct quic_conn *qc, struct quic_frame *frm); diff --git a/src/quic_frame.c b/src/quic_frame.c index d92e1d661..cbff5277a 100644 --- a/src/quic_frame.c +++ b/src/quic_frame.c @@ -1150,17 +1150,19 @@ const struct quic_frame_builder *qf_builder(uint64_t type) return NULL; } -/* Decode a QUIC frame at buffer position into frame. - * Returns 1 if succeeded (enough data at buffer position to parse the frame), 0 if not. +/* Parse frame type in buffer starting at and ending at and store + * it in object. + * + * Returns 1 on success else 0. */ -int qc_parse_frm(struct quic_frame *frm, struct quic_rx_packet *pkt, - const unsigned char **pos, const unsigned char *end, - struct quic_conn *qc) +int qc_parse_frm_type(struct quic_frame *frm, + const unsigned char **pos, const unsigned char *end, + struct quic_conn *qc) { int ret = 0; - const struct quic_frame_parser *parser; TRACE_ENTER(QUIC_EV_CONN_PRSFRM, qc); + if (end <= *pos) { TRACE_DEVEL("wrong frame", QUIC_EV_CONN_PRSFRM, qc); goto leave; @@ -1168,34 +1170,50 @@ int qc_parse_frm(struct quic_frame *frm, struct quic_rx_packet *pkt, if (!quic_dec_int(&frm->type, pos, end)) { TRACE_ERROR("malformed frame type", QUIC_EV_CONN_PRSFRM, qc); - quic_set_connection_close(qc, quic_err_transport(QC_ERR_FRAME_ENCODING_ERROR)); goto leave; } if (!quic_frame_type_is_known(frm->type)) { - /* RFC 9000 12.4. Frames and Frame Types - * - * An endpoint MUST treat the receipt of a frame of unknown type as a - * connection error of type FRAME_ENCODING_ERROR. - */ TRACE_DEVEL("wrong frame type", QUIC_EV_CONN_PRSFRM, qc, frm); - quic_set_connection_close(qc, quic_err_transport(QC_ERR_FRAME_ENCODING_ERROR)); goto leave; } + ret = 1; + leave: + TRACE_LEAVE(QUIC_EV_CONN_PRSFRM, qc); + return ret; +} + +/* Checks that frame is authorized in packet. Output parameter + * may be updated if the frame characteristics impacts the containing packet. + * + * Returns true for a valid frame else false. + */ +int qc_parse_frm_pkt(const struct quic_frame *frm, + const struct quic_rx_packet *pkt, int *flags) +{ + const struct quic_frame_parser *parser = qf_parser(frm->type); + if (!(parser->mask & (1U << pkt->type))) + return 0; + + *flags = parser->flags; + return 1; +} + +/* Parse frame content in buffer starting at and ending at . + * + * Returns 1 on success else 0. + */ +int qc_parse_frm_payload(struct quic_frame *frm, + const unsigned char **pos, const unsigned char *end, + struct quic_conn *qc) +{ + int ret = 0; + const struct quic_frame_parser *parser; + + TRACE_ENTER(QUIC_EV_CONN_PRSFRM, qc); + parser = qf_parser(frm->type); - if (!(parser->mask & (1U << pkt->type))) { - /* RFC 9000 12.4. Frames and Frame Types - * - * An endpoint MUST treat - * receipt of a frame in a packet type that is not permitted as a - * connection error of type PROTOCOL_VIOLATION. - */ - TRACE_DEVEL("unauthorized frame", QUIC_EV_CONN_PRSFRM, qc, frm); - quic_set_connection_close(qc, quic_err_transport(QC_ERR_PROTOCOL_VIOLATION)); - goto leave; - } - if (!parser->func(frm, qc, pos, end)) { TRACE_DEVEL("parsing error", QUIC_EV_CONN_PRSFRM, qc, frm); goto leave; @@ -1203,8 +1221,6 @@ int qc_parse_frm(struct quic_frame *frm, struct quic_rx_packet *pkt, TRACE_PROTO("RX frm", QUIC_EV_CONN_PSTRM, qc, frm); - pkt->flags |= parser->flags; - ret = 1; leave: TRACE_LEAVE(QUIC_EV_CONN_PRSFRM, qc); diff --git a/src/quic_rx.c b/src/quic_rx.c index 0e2deb021..abd9e9fef 100644 --- a/src/quic_rx.c +++ b/src/quic_rx.c @@ -840,7 +840,7 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt, { struct quic_frame *frm = NULL; const unsigned char *pos, *end; - int fast_retrans = 0, ret; + int fast_retrans = 0, pkt_flags = 0, ret; TRACE_ENTER(QUIC_EV_CONN_PRSHPKT, qc); /* Skip the AAD */ @@ -867,7 +867,32 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt, goto err; } - if (!qc_parse_frm(frm, pkt, &pos, end, qc)) { + if (!qc_parse_frm_type(frm, &pos, end, qc)) { + /* RFC 9000 12.4. Frames and Frame Types + * + * An endpoint MUST treat the receipt of a frame of unknown type as a + * connection error of type FRAME_ENCODING_ERROR. + */ + quic_set_connection_close(qc, quic_err_transport(QC_ERR_FRAME_ENCODING_ERROR)); + /* trace already emitted by above function */ + goto err; + } + + /* RFC 9000 12.4. Frames and Frame Types + * + * An endpoint MUST treat + * receipt of a frame in a packet type that is not permitted as a + * connection error of type PROTOCOL_VIOLATION. + */ + if (!qc_parse_frm_pkt(frm, pkt, &pkt_flags)) { + TRACE_ERROR("unauthorized frame", QUIC_EV_CONN_PRSFRM, qc, frm); + quic_set_connection_close(qc, quic_err_transport(QC_ERR_PROTOCOL_VIOLATION)); + goto err; + } + + pkt->flags |= pkt_flags; + + if (!qc_parse_frm_payload(frm, &pos, end, qc)) { // trace already emitted by function above goto err; } @@ -1147,7 +1172,7 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt, qc->state = QUIC_HS_ST_CONFIRMED; break; default: - /* Unknown frame type must be rejected by qc_parse_frm(). */ + /* Unknown frame type must be rejected by qc_parse_frm_type(). */ ABORT_NOW(); } }