summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Landau <hlandau@openssl.org>2022-11-22 13:25:41 +0000
committerHugo Landau <hlandau@openssl.org>2023-01-19 13:17:39 +0000
commit93e9b6cc4e2b47a5fb32f093c38b7963e9c270aa (patch)
tree771df6c58ebd79ad8554ce7f46870061b69cc1ad
parent53b5d6c30f3b8eaf7a582da2265c0d1cfe14d54f (diff)
downloadopenssl-new-93e9b6cc4e2b47a5fb32f093c38b7963e9c270aa.tar.gz
QUIC DEMUX: (Server support) Add support for default handler
Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/19734)
-rw-r--r--include/internal/quic_demux.h33
-rw-r--r--ssl/quic/quic_demux.c51
2 files changed, 72 insertions, 12 deletions
diff --git a/include/internal/quic_demux.h b/include/internal/quic_demux.h
index dba669645b..1e5a85f9d7 100644
--- a/include/internal/quic_demux.h
+++ b/include/internal/quic_demux.h
@@ -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.
@@ -256,6 +257,20 @@ void ossl_quic_demux_unregister_by_cb(QUIC_DEMUX *demux,
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;
* that is, its prev and next pointers must be NULL.
@@ -264,6 +279,20 @@ 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.
*
diff --git a/ssl/quic/quic_demux.c b/ssl/quic/quic_demux.c
index 6d30c1c2b9..b2afe73062 100644
--- a/ssl/quic/quic_demux.c
+++ b/ssl/quic/quic_demux.c
@@ -25,10 +25,10 @@
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;
+}