]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: refactor frame parsing
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 19 Feb 2025 13:53:14 +0000 (14:53 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 2 Apr 2026 12:02:04 +0000 (14:02 +0200)
This patch refactors parsing in QUIC frame module. Function
qc_parse_frm() has been splitted in three :
* qc_parse_frm_type()
* qc_parse_frm_pkt()
* qc_parse_frm_payload()

No functional change. The main objective of this patch is to facilitate
a QMux implementation. One of the gain is the ability to manipulate QUIC
frames without any reference to a QUIC packet as it is irrelevant for
QMux. Also, quic_set_connection_close() calls are extracted as this
relies on qc type. The caller is now responsible to set the required
error code.

include/haproxy/quic_frame.h
src/quic_frame.c
src/quic_rx.c

index 3994e8f53a3669d3d42af9fbb336419e467b0f2e..0c5fe70ca99661c81b3b2b84dee0e57c3dcf6252 100644 (file)
@@ -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);
 
index d92e1d661a2a127ee9af722fe535be7d40f31699..cbff5277ad08d239a6e3366cf90bb18052a2bdfa 100644 (file)
@@ -1150,17 +1150,19 @@ const struct quic_frame_builder *qf_builder(uint64_t type)
        return NULL;
 }
 
-/* Decode a QUIC frame at <pos> buffer position into <frm> frame.
- * Returns 1 if succeeded (enough data at <pos> buffer position to parse the frame), 0 if not.
+/* Parse frame type in buffer starting at <pos> and ending at <end> and store
+ * it in <frm> 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;
        }
 
-       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;
-       }
+       ret = 1;
+ leave:
+       TRACE_LEAVE(QUIC_EV_CONN_PRSFRM, qc);
+       return ret;
+}
+
+/* Checks that <frm> frame is authorized in <pkt> packet. Output parameter <flags>
+ * 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 <pos> and ending at <end>.
+ *
+ * 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->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);
index 0e2deb021dc28ed2ca487c063a8f877d9cff740b..abd9e9fef7d6f8ec8c1643a8d097de7a58cc6653 100644 (file)
@@ -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();
                }
        }