Home | History | Annotate | Line # | Download | only in internal
      1 /*
      2  * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #ifndef OSSL_QUIC_DEMUX_H
     11 #define OSSL_QUIC_DEMUX_H
     12 
     13 #include <openssl/ssl.h>
     14 #include "internal/quic_types.h"
     15 #include "internal/quic_predef.h"
     16 #include "internal/bio_addr.h"
     17 #include "internal/time.h"
     18 #include "internal/list.h"
     19 
     20 #ifndef OPENSSL_NO_QUIC
     21 
     22 /*
     23  * QUIC Demuxer
     24  * ============
     25  *
     26  * The QUIC connection demuxer is the entity responsible for receiving datagrams
     27  * from the network via a datagram BIO. It parses the headers of the first
     28  * packet in the datagram to determine that packet's DCID and hands off
     29  * processing of the entire datagram to a single callback function which can
     30  * decide how to handle and route the datagram, for example by looking up
     31  * a QRX instance and injecting the URXE into that QRX.
     32  *
     33  * A QRX will typically be instantiated per QUIC connection and contains the
     34  * cryptographic resources needed to decrypt QUIC packets for that connection.
     35  * However, it is up to the callback function to handle routing, for example by
     36  * consulting a LCIDM instance. Thus the demuxer has no specific knowledge of
     37  * any QRX and is not coupled to it. All CID knowledge is also externalised into
     38  * a LCIDM or other CID state tracking object, without the DEMUX being coupled
     39  * to any particular DCID resolution mechanism.
     40  *
     41  * URX Queue
     42  * ---------
     43  *
     44  * Since the demuxer must handle the initial reception of datagrams from the OS,
     45  * RX queue management for new, unprocessed datagrams is also handled by the
     46  * demuxer.
     47  *
     48  * The demuxer maintains a queue of Unprocessed RX Entries (URXEs), which store
     49  * unprocessed (i.e., encrypted, unvalidated) data received from the network.
     50  * The URXE queue is designed to allow multiple datagrams to be received in a
     51  * single call to BIO_recvmmsg, where supported.
     52  *
     53  * One URXE is used per received datagram. Each datagram may contain multiple
     54  * packets, however, this is not the demuxer's concern. QUIC prohibits different
     55  * packets in the same datagram from containing different DCIDs; the demuxer
     56  * only considers the DCID of the first packet in a datagram when deciding how
     57  * to route a received datagram, and it is the responsibility of the QRX to
     58  * enforce this rule. Packets other than the first packet in a datagram are not
     59  * examined by the demuxer, and the demuxer does not perform validation of
     60  * packet headers other than to the minimum extent necessary to extract the
     61  * DCID; further parsing and validation of packet headers is the responsibility
     62  * of the QRX.
     63  *
     64  * Rather than defining an opaque interface, the URXE structure internals
     65  * are exposed. Since the demuxer is only exposed to other parts of the QUIC
     66  * implementation internals, this poses no problem, and has a number of
     67  * advantages:
     68  *
     69  *   - Fields in the URXE can be allocated to support requirements in other
     70  *     components, like the QRX, which would otherwise have to allocate extra
     71  *     memory corresponding to each URXE.
     72  *
     73  *   - Other components, like the QRX, can keep the URXE in queues of its own
     74  *     when it is not being managed by the demuxer.
     75  *
     76  * URX Queue Structure
     77  * -------------------
     78  *
     79  * The URXE queue is maintained as a simple doubly-linked list. URXE entries are
     80  * moved between different lists in their lifecycle (for example, from a free
     81  * list to a pending list and vice versa). The buffer into which datagrams are
     82  * received immediately follows this URXE header structure and is part of the
     83  * same allocation.
     84  */
     85 
     86 /* Maximum number of packets we allow to exist in one datagram. */
     87 #define QUIC_MAX_PKT_PER_URXE (sizeof(uint64_t) * 8)
     88 
     89 struct quic_urxe_st {
     90     OSSL_LIST_MEMBER(urxe, QUIC_URXE);
     91 
     92     /*
     93      * The URXE data starts after this structure so we don't need a pointer.
     94      * data_len stores the current length (i.e., the length of the received
     95      * datagram) and alloc_len stores the allocation length. The URXE will be
     96      * reallocated if we need a larger allocation than is available, though this
     97      * should not be common as we will have a good idea of worst-case MTUs up
     98      * front.
     99      */
    100     size_t data_len, alloc_len;
    101 
    102     /*
    103      * Bitfields per packet. processed indicates the packet has been processed
    104      * and must not be processed again, hpr_removed indicates header protection
    105      * has already been removed. Used by QRX only; not used by the demuxer.
    106      */
    107     uint64_t processed, hpr_removed;
    108 
    109     /*
    110      * This monotonically increases with each datagram received. It is used for
    111      * diagnostic purposes only.
    112      */
    113     uint64_t datagram_id;
    114 
    115     /*
    116      * Address of peer we received the datagram from, and the local interface
    117      * address we received it on. If local address support is not enabled, local
    118      * is zeroed.
    119      */
    120     BIO_ADDR peer, local;
    121 
    122     /*
    123      * Time at which datagram was received (or ossl_time_zero()) if a now
    124      * function was not provided).
    125      */
    126     OSSL_TIME time;
    127 
    128     /*
    129      * Used by the QRX to mark whether a datagram has been deferred. Used by the
    130      * QRX only; not used by the demuxer.
    131      */
    132     char deferred;
    133 
    134     /*
    135      * Used by the DEMUX to track if a URXE has been handed out. Used primarily
    136      * for debugging purposes.
    137      */
    138     char demux_state;
    139 };
    140 
    141 /* Accessors for URXE buffer. */
    142 static ossl_unused ossl_inline unsigned char *
    143 ossl_quic_urxe_data(const QUIC_URXE *e)
    144 {
    145     return (unsigned char *)&e[1];
    146 }
    147 
    148 static ossl_unused ossl_inline unsigned char *
    149 ossl_quic_urxe_data_end(const QUIC_URXE *e)
    150 {
    151     return ossl_quic_urxe_data(e) + e->data_len;
    152 }
    153 
    154 /* List structure tracking a queue of URXEs. */
    155 DEFINE_LIST_OF(urxe, QUIC_URXE);
    156 typedef OSSL_LIST(urxe) QUIC_URXE_LIST;
    157 
    158 /*
    159  * List management helpers. These are used by the demuxer but can also be used
    160  * by users of the demuxer to manage URXEs.
    161  */
    162 void ossl_quic_urxe_remove(QUIC_URXE_LIST *l, QUIC_URXE *e);
    163 void ossl_quic_urxe_insert_head(QUIC_URXE_LIST *l, QUIC_URXE *e);
    164 void ossl_quic_urxe_insert_tail(QUIC_URXE_LIST *l, QUIC_URXE *e);
    165 
    166 /*
    167  * Called when a datagram is received for a given connection ID.
    168  *
    169  * e is a URXE containing the datagram payload. It is permissible for the callee
    170  * to mutate this buffer; once the demuxer calls this callback, it will never
    171  * read the buffer again.
    172  *
    173  * If a DCID was identified for the datagram, dcid is non-NULL; otherwise
    174  * it is NULL.
    175  *
    176  * The callee must arrange for ossl_quic_demux_release_urxe or
    177  * ossl_quic_demux_reinject_urxe to be called on the URXE at some point in the
    178  * future (this need not be before the callback returns).
    179  *
    180  * At the time the callback is made, the URXE will not be in any queue,
    181  * therefore the callee can use the prev and next fields as it wishes.
    182  */
    183 typedef void(ossl_quic_demux_cb_fn)(QUIC_URXE *e, void *arg,
    184     const QUIC_CONN_ID *dcid);
    185 
    186 /*
    187  * Creates a new demuxer. The given BIO is used to receive datagrams from the
    188  * network using BIO_recvmmsg. short_conn_id_len is the length of destination
    189  * connection IDs used in RX'd packets; it must have the same value for all
    190  * connections used on a socket. default_urxe_alloc_len is the buffer size to
    191  * receive datagrams into; it should be a value large enough to contain any
    192  * received datagram according to local MTUs, etc.
    193  *
    194  * now is an optional function used to determine the time a datagram was
    195  * received. now_arg is an opaque argument passed to the function. If now is
    196  * NULL, ossl_time_zero() is used as the datagram reception time.
    197  */
    198 QUIC_DEMUX *ossl_quic_demux_new(BIO *net_bio,
    199     size_t short_conn_id_len,
    200     OSSL_TIME (*now)(void *arg),
    201     void *now_arg);
    202 
    203 /*
    204  * Destroy a demuxer. All URXEs must have been released back to the demuxer
    205  * before calling this. No-op if demux is NULL.
    206  */
    207 void ossl_quic_demux_free(QUIC_DEMUX *demux);
    208 
    209 /*
    210  * Changes the BIO which the demuxer reads from. This also sets the MTU if the
    211  * BIO supports querying the MTU.
    212  */
    213 void ossl_quic_demux_set_bio(QUIC_DEMUX *demux, BIO *net_bio);
    214 
    215 /*
    216  * Changes the MTU in bytes we use to receive datagrams.
    217  */
    218 int ossl_quic_demux_set_mtu(QUIC_DEMUX *demux, unsigned int mtu);
    219 
    220 /*
    221  * Set the default packet handler. This is used for incoming packets which don't
    222  * match a registered DCID. This is only needed for servers. If a default packet
    223  * handler is not set, a packet which doesn't match a registered DCID is
    224  * silently dropped. A default packet handler may be unset by passing NULL.
    225  *
    226  * The handler is responsible for ensuring that ossl_quic_demux_reinject_urxe or
    227  * ossl_quic_demux_release_urxe is called on the passed packet at some point in
    228  * the future, which may or may not be before the handler returns.
    229  */
    230 void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux,
    231     ossl_quic_demux_cb_fn *cb,
    232     void *cb_arg);
    233 
    234 /*
    235  * Releases a URXE back to the demuxer. No reference must be made to the URXE or
    236  * its buffer after calling this function. The URXE must not be in any queue;
    237  * that is, its prev and next pointers must be NULL.
    238  */
    239 void ossl_quic_demux_release_urxe(QUIC_DEMUX *demux,
    240     QUIC_URXE *e);
    241 
    242 /*
    243  * Reinjects a URXE which was issued to a registered DCID callback or the
    244  * default packet handler callback back into the pending queue. This is useful
    245  * when a packet has been handled by the default packet handler callback such
    246  * that a DCID has now been registered and can be dispatched normally by DCID.
    247  * Once this has been called, the caller must not touch the URXE anymore and
    248  * must not also call ossl_quic_demux_release_urxe().
    249  *
    250  * The URXE is reinjected at the head of the queue, so it will be reprocessed
    251  * immediately.
    252  */
    253 void ossl_quic_demux_reinject_urxe(QUIC_DEMUX *demux,
    254     QUIC_URXE *e);
    255 
    256 /*
    257  * Process any unprocessed RX'd datagrams, by calling registered callbacks by
    258  * connection ID, reading more datagrams from the BIO if necessary.
    259  *
    260  * Returns one of the following values:
    261  *
    262  *     QUIC_DEMUX_PUMP_RES_OK
    263  *         At least one incoming datagram was processed.
    264  *
    265  *     QUIC_DEMUX_PUMP_RES_TRANSIENT_FAIL
    266  *         No more incoming datagrams are currently available.
    267  *         Call again later.
    268  *
    269  *     QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL
    270  *         Either the network read BIO has failed in a non-transient fashion, or
    271  *         the QUIC implementation has encountered an internal state, assertion
    272  *         or allocation error. The caller should tear down the connection
    273  *         similarly to in the case of a protocol violation.
    274  *
    275  */
    276 #define QUIC_DEMUX_PUMP_RES_OK 1
    277 #define QUIC_DEMUX_PUMP_RES_TRANSIENT_FAIL (-1)
    278 #define QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL (-2)
    279 
    280 int ossl_quic_demux_pump(QUIC_DEMUX *demux);
    281 
    282 /*
    283  * Artificially inject a packet into the demuxer for testing purposes. The
    284  * buffer must not exceed the URXE size being used by the demuxer.
    285  *
    286  * If peer or local are NULL, their respective fields are zeroed in the injected
    287  * URXE.
    288  *
    289  * Returns 1 on success or 0 on failure.
    290  */
    291 int ossl_quic_demux_inject(QUIC_DEMUX *demux,
    292     const unsigned char *buf,
    293     size_t buf_len,
    294     const BIO_ADDR *peer,
    295     const BIO_ADDR *local);
    296 
    297 /*
    298  * Returns 1 if there are any pending URXEs.
    299  */
    300 int ossl_quic_demux_has_pending(const QUIC_DEMUX *demux);
    301 
    302 #endif
    303 
    304 #endif
    305