From: Hugo Landau Date: Tue, 22 Nov 2022 13:25:41 +0000 (+0000) Subject: QUIC DEMUX: (Server support) Add support for default handler X-Git-Tag: openssl-3.2.0-alpha1~1442 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=93e9b6cc4e2b47a5fb32f093c38b7963e9c270aa;p=thirdparty%2Fopenssl.git QUIC DEMUX: (Server support) Add support for default handler Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/19734) --- diff --git a/include/internal/quic_demux.h b/include/internal/quic_demux.h index dba669645bd..1e5a85f9d74 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. @@ -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. diff --git a/ssl/quic/quic_demux.c b/ssl/quic/quic_demux.c index 6d30c1c2b99..b2afe73062f 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; +}