From: Hugo Landau Date: Thu, 9 Nov 2023 10:27:14 +0000 (+0000) Subject: QUIC DEMUX: Remove legacy routing code X-Git-Tag: openssl-3.3.0-alpha1~419 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=da15093a31cc32cfffb2767fb51fce6f4212d913;p=thirdparty%2Fopenssl.git QUIC DEMUX: Remove legacy routing code Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22674) --- diff --git a/include/internal/quic_demux.h b/include/internal/quic_demux.h index 0749fe90b75..bca483a9a92 100644 --- a/include/internal/quic_demux.h +++ b/include/internal/quic_demux.h @@ -23,20 +23,19 @@ * ============ * * 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, diff --git a/ssl/quic/quic_demux.c b/ssl/quic/quic_demux.c index 376c0888114..34d53b9f5c6 100644 --- a/ssl/quic/quic_demux.c +++ b/ssl/quic/quic_demux.c @@ -21,37 +21,6 @@ #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. */