]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
QUIC DEMUX: (Server support) Add support for default handler
authorHugo Landau <hlandau@openssl.org>
Tue, 22 Nov 2022 13:25:41 +0000 (13:25 +0000)
committerHugo Landau <hlandau@openssl.org>
Thu, 19 Jan 2023 13:17:39 +0000 (13:17 +0000)
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19734)

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

index dba669645bd616fdb4ad1f6effe091c647eac43a..1e5a85f9d740bfe1a96b049518a44a3aa06fbc7a 100644 (file)
@@ -169,8 +169,9 @@ typedef struct quic_demux_st QUIC_DEMUX;
  * to mutate this buffer; once the demuxer calls this callback, it will never
  * read the buffer again.
  *
- * The callee must arrange for ossl_quic_demux_release_urxe to be called on the URXE
- * at some point in the future (this need not be before the callback returns).
+ * The callee must arrange for ossl_quic_demux_release_urxe or
+ * ossl_quic_demux_reinject_urxe to be called on the URXE at some point in the
+ * future (this need not be before the callback returns).
  *
  * At the time the callback is made, the URXE will not be in any queue,
  * therefore the callee can use the prev and next fields as it wishes.
@@ -255,6 +256,20 @@ 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
+ * handler is not set, a packet which doesn't match a registered DCID is
+ * silently dropped. A default packet handler may be unset by passing NULL.
+ *
+ * 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.
+ */
+void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux,
+                                         ossl_quic_demux_cb_fn *cb,
+                                         void *cb_arg);
+
 /*
  * Releases a URXE back to the demuxer. No reference must be made to the URXE or
  * its buffer after calling this function. The URXE must not be in any queue;
@@ -263,6 +278,20 @@ void ossl_quic_demux_unregister_by_cb(QUIC_DEMUX *demux,
 void ossl_quic_demux_release_urxe(QUIC_DEMUX *demux,
                                   QUIC_URXE *e);
 
+/*
+ * Reinjects a URXE which was issued to a registered DCID callback or the
+ * default packet handler callback back into the pending queue. This is useful
+ * when a packet has been handled by the default packet handler callback such
+ * that a DCID has now been registered and can be dispatched normally by DCID.
+ * Once this has been called, the caller must not touch the URXE anymore and
+ * must not also call ossl_quic_demux_release_urxe().
+ *
+ * The URXE is reinjected at the head of the queue, so it will be reprocessed
+ * immediately.
+ */
+void ossl_quic_demux_reinject_urxe(QUIC_DEMUX *demux,
+                                   QUIC_URXE *e);
+
 /*
  * Process any unprocessed RX'd datagrams, by calling registered callbacks by
  * connection ID, reading more datagrams from the BIO if necessary.
index 6d30c1c2b99794b5df382fb00994b9163bbafcfb..b2afe73062f391a39387d73aeca705373c508125 100644 (file)
 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;
+    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);
@@ -76,6 +76,10 @@ struct quic_demux_st {
     /* 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;
+
     /*
      * List of URXEs which are not currently in use (i.e., not filled with
      * unconsumed data). These are moved to the pending list as they are filled.
@@ -285,6 +289,14 @@ void ossl_quic_demux_unregister_by_cb(QUIC_DEMUX *demux,
     }
 }
 
+void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux,
+                                         ossl_quic_demux_cb_fn *cb,
+                                         void *cb_arg)
+{
+    demux->default_cb       = cb;
+    demux->default_cb_arg   = cb_arg;
+}
+
 static QUIC_URXE *demux_alloc_urxe(size_t alloc_len)
 {
     QUIC_URXE *e;
@@ -406,6 +418,7 @@ static int demux_recv(QUIC_DEMUX *demux)
         msg[i].data     = ossl_quic_urxe_data(urxe);
         msg[i].data_len = urxe->alloc_len;
         msg[i].peer     = &urxe->peer;
+        BIO_ADDR_clear(&urxe->peer);
         if (demux->use_local_addr)
             msg[i].local = &urxe->local;
         else
@@ -484,12 +497,21 @@ static int demux_process_pending_urxe(QUIC_DEMUX *demux, QUIC_URXE *e)
     conn = demux_identify_conn(demux, e);
     if (conn == NULL) {
         /*
-         * We could not identify a connection. We will never be able to process
-         * this datagram, so get rid of it.
+         * 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.
          */
-        ossl_list_urxe_remove(&demux->urx_pending, e);
-        ossl_list_urxe_insert_tail(&demux->urx_free, e);
-        e->demux_state = URXE_DEMUX_STATE_FREE;
+        if (demux->default_cb != NULL) {
+            /* Pass to default handler. */
+            ossl_list_urxe_remove(&demux->urx_pending, e);
+            e->demux_state = URXE_DEMUX_STATE_ISSUED;
+            demux->default_cb(e, demux->default_cb_arg);
+        } else {
+            /* Discard. */
+            ossl_list_urxe_remove(&demux->urx_pending, e);
+            ossl_list_urxe_insert_tail(&demux->urx_free, e);
+            e->demux_state = URXE_DEMUX_STATE_FREE;
+        }
         return 1; /* keep processing pending URXEs */
     }
 
@@ -572,7 +594,7 @@ int ossl_quic_demux_inject(QUIC_DEMUX *demux,
     if (peer != NULL)
         urxe->peer = *peer;
     else
-        BIO_ADDR_clear(&urxe->local);
+        BIO_ADDR_clear(&urxe->peer);
 
     if (local != NULL)
         urxe->local = *local;
@@ -596,3 +618,12 @@ void ossl_quic_demux_release_urxe(QUIC_DEMUX *demux,
     ossl_list_urxe_insert_tail(&demux->urx_free, e);
     e->demux_state = URXE_DEMUX_STATE_FREE;
 }
+
+void ossl_quic_demux_reinject_urxe(QUIC_DEMUX *demux,
+                                   QUIC_URXE *e)
+{
+    assert(ossl_list_urxe_prev(e) == NULL && ossl_list_urxe_next(e) == NULL);
+    assert(e->demux_state == URXE_DEMUX_STATE_ISSUED);
+    ossl_list_urxe_insert_head(&demux->urx_pending, e);
+    e->demux_state = URXE_DEMUX_STATE_PENDING;
+}