QUIC DEMUX: Remove legacy routing code
authorHugo Landau <hlandau@openssl.org>
Thu, 9 Nov 2023 10:27:14 +0000 (10:27 +0000)
committerHugo Landau <hlandau@openssl.org>
Thu, 21 Dec 2023 08:12:00 +0000 (08:12 +0000)
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/22674)

include/internal/quic_demux.h
ssl/quic/quic_demux.c

index 0749fe90b757cd07564af3b69e3b5ed3861d64ca..bca483a9a92dcc5f370ad5a9db04b64af3ea885d 100644 (file)
  * ============
  *
  * The QUIC connection demuxer is the entity responsible for receiving datagrams
- * from the network via a datagram BIO. It parses packet headers to determine
- * each packet's destination connection ID (DCID) and hands off processing of
- * the packet to the correct QUIC Record Layer (QRL)'s RX side (known as the
- * QRX).
- *
- * A QRX is instantiated per QUIC connection and contains the cryptographic
- * resources needed to decrypt QUIC packets for that connection. Received
- * datagrams are passed from the demuxer to the QRX via a callback registered
- * for a specific DCID by the QRX; thus the demuxer has no specific knowledge of
- * the QRX and is not coupled to it.
- *
- * A connection may have multiple connection IDs associated with it; a QRX
- * handles this simply by registering multiple connection IDs with the demuxer
- * via multiple register calls.
+ * from the network via a datagram BIO. It parses the headers of the first
+ * packet in the datagram to determine that packet's DCID and hands off
+ * processing of the entire datagram to a single callback function which can
+ * decide how to handle and route the datagram, for example by looking up
+ * a QRX instance and injecting the URXE into that QRX.
+ *
+ * A QRX will typically be instantiated per QUIC connection and contains the
+ * cryptographic resources needed to decrypt QUIC packets for that connection.
+ * However, it is up to the callback function to handle routing, for example by
+ * consulting a LCIDM instance. Thus the demuxer has no specific knowledge of
+ * any QRX and is not coupled to it. All CID knowledge is also externalised into
+ * a LCIDM or other CID state tracking object, without the DEMUX being coupled
+ * to any particular DCID resolution mechanism.
  *
  * URX Queue
  * ---------
@@ -224,59 +223,6 @@ void ossl_quic_demux_set_bio(QUIC_DEMUX *demux, BIO *net_bio);
  */
 int ossl_quic_demux_set_mtu(QUIC_DEMUX *demux, unsigned int mtu);
 
-/*
- * Register a datagram handler callback for a connection ID.
- *
- * ossl_quic_demux_pump will call the specified function if it receives a datagram
- * the first packet of which has the specified destination connection ID.
- *
- * It is assumed all packets in a datagram have the same destination connection
- * ID (as QUIC mandates this), but it is the user's responsibility to check for
- * this and reject subsequent packets in a datagram that violate this rule.
- *
- * dst_conn_id is a destination connection ID; it is copied and need not remain
- * valid after this function returns.
- *
- * cb_arg is passed to cb when it is called. For information on the callback,
- * see its typedef above.
- *
- * Only one handler can be set for a given connection ID. If a handler is
- * already set for the given connection ID, returns 0.
- *
- * TODO(QUIC SERVER): DEPRECATED in favour of explicit routing by QUIC_PORT with
- * reference to QUIC_LCIDM. To be removed.
- *
- * Returns 1 on success or 0 on failure.
- */
-int ossl_quic_demux_register(QUIC_DEMUX *demux,
-                             const QUIC_CONN_ID *dst_conn_id,
-                             ossl_quic_demux_cb_fn *cb,
-                             void *cb_arg);
-
-/*
- * Unregisters any datagram handler callback set for the given connection ID.
- * Fails if no handler is registered for the given connection ID.
- *
- * TODO(QUIC SERVER): DEPRECATED in favour of explicit routing by QUIC_PORT with
- * reference to QUIC_LCIDM. To be removed.
- *
- * Returns 1 on success or 0 on failure.
- */
-int ossl_quic_demux_unregister(QUIC_DEMUX *demux,
-                               const QUIC_CONN_ID *dst_conn_id);
-
-/*
- * Unregisters any datagram handler callback from all connection IDs it is used
- * for. cb and cb_arg must both match the values passed to
- * ossl_quic_demux_register.
- *
- * TODO(QUIC SERVER): DEPRECATED in favour of explicit routing by QUIC_PORT with
- * reference to QUIC_LCIDM. To be removed.
- */
-void ossl_quic_demux_unregister_by_cb(QUIC_DEMUX *demux,
-                                      ossl_quic_demux_cb_fn *cb,
-                                      void *cb_arg);
-
 /*
  * Set the default packet handler. This is used for incoming packets which don't
  * match a registered DCID. This is only needed for servers. If a default packet
@@ -286,11 +232,6 @@ void ossl_quic_demux_unregister_by_cb(QUIC_DEMUX *demux,
  * The handler is responsible for ensuring that ossl_quic_demux_reinject_urxe or
  * ossl_quic_demux_release_urxe is called on the passed packet at some point in
  * the future, which may or may not be before the handler returns.
- *
- * TODO(QUIC SERVER): In the future all RX handling will go via this function
- * and the QUIC_PORT will be responsible for routing. DEMUX will then handle
- * URXE memory management and datagram DCID parsing only. The MVP LCID routing
- * functionality of the DEMUX will be removed in favour of LCIDM.
  */
 void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux,
                                          ossl_quic_demux_cb_fn *cb,
index 376c0888114b9a13deffbb953b8eed0517318f6b..34d53b9f5c69076b52cae025c90514c1be5a8390 100644 (file)
 
 #define DEMUX_DEFAULT_MTU        1500
 
-/* Structure used to track a given connection ID. */
-typedef struct quic_demux_conn_st QUIC_DEMUX_CONN;
-
-struct quic_demux_conn_st {
-    QUIC_DEMUX_CONN                 *next; /* used when unregistering only */
-    QUIC_CONN_ID                    dst_conn_id;
-    ossl_quic_demux_cb_fn           *cb;
-    void                            *cb_arg;
-};
-
-DEFINE_LHASH_OF_EX(QUIC_DEMUX_CONN);
-
-static unsigned long demux_conn_hash(const QUIC_DEMUX_CONN *conn)
-{
-    size_t i;
-    unsigned long v = 0;
-
-    assert(conn->dst_conn_id.id_len <= QUIC_MAX_CONN_ID_LEN);
-
-    for (i = 0; i < conn->dst_conn_id.id_len; ++i)
-        v ^= ((unsigned long)conn->dst_conn_id.id[i])
-             << ((i * 8) % (sizeof(unsigned long) * 8));
-
-    return v;
-}
-
-static int demux_conn_cmp(const QUIC_DEMUX_CONN *a, const QUIC_DEMUX_CONN *b)
-{
-    return !ossl_quic_conn_id_eq(&a->dst_conn_id, &b->dst_conn_id);
-}
-
 struct quic_demux_st {
     /* The underlying transport BIO with datagram semantics. */
     BIO                        *net_bio;
@@ -73,9 +42,6 @@ struct quic_demux_st {
     OSSL_TIME                 (*now)(void *arg);
     void                       *now_arg;
 
-    /* Hashtable mapping connection IDs to QUIC_DEMUX_CONN structures. */
-    LHASH_OF(QUIC_DEMUX_CONN)  *conns_by_id;
-
     /* The default packet handler, if any. */
     ossl_quic_demux_cb_fn      *default_cb;
     void                       *default_cb_arg;
@@ -121,13 +87,6 @@ QUIC_DEMUX *ossl_quic_demux_new(BIO *net_bio,
     demux->now                      = now;
     demux->now_arg                  = now_arg;
 
-    demux->conns_by_id
-        = lh_QUIC_DEMUX_CONN_new(demux_conn_hash, demux_conn_cmp);
-    if (demux->conns_by_id == NULL) {
-        OPENSSL_free(demux);
-        return NULL;
-    }
-
     if (net_bio != NULL
         && BIO_dgram_get_local_addr_cap(net_bio)
         && BIO_dgram_set_local_addr_enable(net_bio, 1))
@@ -136,11 +95,6 @@ QUIC_DEMUX *ossl_quic_demux_new(BIO *net_bio,
     return demux;
 }
 
-static void demux_free_conn_it(QUIC_DEMUX_CONN *conn, void *arg)
-{
-    OPENSSL_free(conn);
-}
-
 static void demux_free_urxl(QUIC_URXE_LIST *l)
 {
     QUIC_URXE *e, *enext;
@@ -157,10 +111,6 @@ void ossl_quic_demux_free(QUIC_DEMUX *demux)
     if (demux == NULL)
         return;
 
-    /* Free all connection structures. */
-    lh_QUIC_DEMUX_CONN_doall_arg(demux->conns_by_id, demux_free_conn_it, NULL);
-    lh_QUIC_DEMUX_CONN_free(demux->conns_by_id);
-
     /* Free all URXEs we are holding. */
     demux_free_urxl(&demux->urx_free);
     demux_free_urxl(&demux->urx_pending);
@@ -195,104 +145,6 @@ int ossl_quic_demux_set_mtu(QUIC_DEMUX *demux, unsigned int mtu)
     return 1;
 }
 
-static QUIC_DEMUX_CONN *demux_get_by_conn_id(QUIC_DEMUX *demux,
-                                             const QUIC_CONN_ID *dst_conn_id)
-{
-    QUIC_DEMUX_CONN key;
-
-    if (dst_conn_id->id_len > QUIC_MAX_CONN_ID_LEN)
-        return NULL;
-
-    key.dst_conn_id = *dst_conn_id;
-    return lh_QUIC_DEMUX_CONN_retrieve(demux->conns_by_id, &key);
-}
-
-int ossl_quic_demux_register(QUIC_DEMUX *demux,
-                             const QUIC_CONN_ID *dst_conn_id,
-                             ossl_quic_demux_cb_fn *cb, void *cb_arg)
-{
-    QUIC_DEMUX_CONN *conn;
-
-    if (dst_conn_id == NULL
-        || dst_conn_id->id_len > QUIC_MAX_CONN_ID_LEN
-        || cb == NULL)
-        return 0;
-
-    /* Ensure not already registered. */
-    if (demux_get_by_conn_id(demux, dst_conn_id) != NULL)
-        /* Handler already registered with this connection ID. */
-        return 0;
-
-    conn = OPENSSL_zalloc(sizeof(QUIC_DEMUX_CONN));
-    if (conn == NULL)
-        return 0;
-
-    conn->dst_conn_id   = *dst_conn_id;
-    conn->cb            = cb;
-    conn->cb_arg        = cb_arg;
-
-    lh_QUIC_DEMUX_CONN_insert(demux->conns_by_id, conn);
-    return 1;
-}
-
-static void demux_unregister(QUIC_DEMUX *demux,
-                             QUIC_DEMUX_CONN *conn)
-{
-    lh_QUIC_DEMUX_CONN_delete(demux->conns_by_id, conn);
-    OPENSSL_free(conn);
-}
-
-int ossl_quic_demux_unregister(QUIC_DEMUX *demux,
-                               const QUIC_CONN_ID *dst_conn_id)
-{
-    QUIC_DEMUX_CONN *conn;
-
-    if (dst_conn_id == NULL
-        || dst_conn_id->id_len > QUIC_MAX_CONN_ID_LEN)
-        return 0;
-
-    conn = demux_get_by_conn_id(demux, dst_conn_id);
-    if (conn == NULL)
-        return 0;
-
-    demux_unregister(demux, conn);
-    return 1;
-}
-
-struct unreg_arg {
-    ossl_quic_demux_cb_fn *cb;
-    void *cb_arg;
-    QUIC_DEMUX_CONN *head;
-};
-
-static void demux_unregister_by_cb(QUIC_DEMUX_CONN *conn, void *arg_)
-{
-    struct unreg_arg *arg = arg_;
-
-    if (conn->cb == arg->cb && conn->cb_arg == arg->cb_arg) {
-        conn->next = arg->head;
-        arg->head = conn;
-    }
-}
-
-void ossl_quic_demux_unregister_by_cb(QUIC_DEMUX *demux,
-                                      ossl_quic_demux_cb_fn *cb,
-                                      void *cb_arg)
-{
-    QUIC_DEMUX_CONN *conn, *cnext;
-    struct unreg_arg arg = {0};
-    arg.cb      = cb;
-    arg.cb_arg  = cb_arg;
-
-    lh_QUIC_DEMUX_CONN_doall_arg(demux->conns_by_id,
-                                 demux_unregister_by_cb, &arg);
-
-    for (conn = arg.head; conn != NULL; conn = cnext) {
-        cnext = conn->next;
-        demux_unregister(demux, conn);
-    }
-}
-
 void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux,
                                          ossl_quic_demux_cb_fn *cb,
                                          void *cb_arg)
@@ -480,29 +332,12 @@ static int demux_identify_conn_id(QUIC_DEMUX *demux,
                                                   dst_conn_id);
 }
 
-/* Identify the connection structure corresponding to a given URXE. */
-static QUIC_DEMUX_CONN *demux_identify_conn(QUIC_DEMUX *demux, QUIC_URXE *e,
-                                            QUIC_CONN_ID *dst_conn_id,
-                                            int *dst_conn_id_ok)
-{
-    if (!demux_identify_conn_id(demux, e, dst_conn_id))
-        /*
-         * Datagram is so badly malformed we can't get the DCID from the first
-         * packet in it, so just give up.
-         */
-        return NULL;
-
-    *dst_conn_id_ok = 1;
-    return demux_get_by_conn_id(demux, dst_conn_id);
-}
-
 /*
  * Process a single pending URXE.
  * Returning 1 on success, 0 on failure and -1 on stateless reset.
  */
 static int demux_process_pending_urxe(QUIC_DEMUX *demux, QUIC_URXE *e)
 {
-    QUIC_DEMUX_CONN *conn;
     QUIC_CONN_ID dst_conn_id;
     int r, dst_conn_id_ok = 0;
 
@@ -535,35 +370,25 @@ static int demux_process_pending_urxe(QUIC_DEMUX *demux, QUIC_URXE *e)
             return 0;
     }
 
-    conn = demux_identify_conn(demux, e, &dst_conn_id, &dst_conn_id_ok);
-    if (conn == NULL) {
+    /* Determine the DCID of the first packet in the datagram. */
+    dst_conn_id_ok = demux_identify_conn_id(demux, e, &dst_conn_id);
+
+    ossl_list_urxe_remove(&demux->urx_pending, e);
+    if (demux->default_cb != NULL) {
         /*
-         * We could not identify a connection. If we have a default packet
-         * handler, pass it to the handler. Otherwise, we will never be able to
-         * process this datagram, so get rid of it.
+         * Pass to default handler for routing. The URXE now belongs to the
+         * callback.
          */
-        ossl_list_urxe_remove(&demux->urx_pending, e);
-        if (demux->default_cb != NULL) {
-            /* Pass to default handler. */
-            e->demux_state = URXE_DEMUX_STATE_ISSUED;
-            demux->default_cb(e, demux->default_cb_arg,
-                              dst_conn_id_ok ? &dst_conn_id : NULL);
-        } else {
-            /* Discard. */
-            ossl_list_urxe_insert_tail(&demux->urx_free, e);
-            e->demux_state = URXE_DEMUX_STATE_FREE;
-        }
-        return 1; /* keep processing pending URXEs */
+        e->demux_state = URXE_DEMUX_STATE_ISSUED;
+        demux->default_cb(e, demux->default_cb_arg,
+                          dst_conn_id_ok ? &dst_conn_id : NULL);
+    } else {
+        /* Discard. */
+        ossl_list_urxe_insert_tail(&demux->urx_free, e);
+        e->demux_state = URXE_DEMUX_STATE_FREE;
     }
 
-    /*
-     * Remove from list and invoke callback. The URXE now belongs to the
-     * callback. (QUIC_DEMUX_CONN never has non-NULL cb.)
-     */
-    ossl_list_urxe_remove(&demux->urx_pending, e);
-    e->demux_state = URXE_DEMUX_STATE_ISSUED;
-    conn->cb(e, conn->cb_arg, dst_conn_id_ok ? &dst_conn_id : NULL);
-    return 1;
+    return 1; /* keep processing pending URXEs */
 }
 
 /* Process pending URXEs to generate callbacks. */