/src/openssl/include/internal/quic_demux.h
Line  | Count  | Source  | 
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  | 0  | #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  | 0  | { | 
145  | 0  |     return (unsigned char *)&e[1];  | 
146  | 0  | } Unexecuted instantiation: ssl_lib.c:ossl_quic_urxe_data Unexecuted instantiation: t1_lib.c:ossl_quic_urxe_data Unexecuted instantiation: quic_impl.c:ossl_quic_urxe_data Unexecuted instantiation: quic_method.c:ossl_quic_urxe_data Unexecuted instantiation: quic_obj.c:ossl_quic_urxe_data Unexecuted instantiation: quic_port.c:ossl_quic_urxe_data Unexecuted instantiation: quic_record_rx.c:ossl_quic_urxe_data Unexecuted instantiation: quic_record_util.c:ossl_quic_urxe_data Unexecuted instantiation: quic_rstream.c:ossl_quic_urxe_data Unexecuted instantiation: quic_sf_list.c:ossl_quic_urxe_data Unexecuted instantiation: quic_sstream.c:ossl_quic_urxe_data Unexecuted instantiation: quic_stream_map.c:ossl_quic_urxe_data Unexecuted instantiation: quic_thread_assist.c:ossl_quic_urxe_data Unexecuted instantiation: quic_txp.c:ossl_quic_urxe_data Unexecuted instantiation: quic_wire.c:ossl_quic_urxe_data Unexecuted instantiation: rec_layer_s3.c:ossl_quic_urxe_data Unexecuted instantiation: quic_channel.c:ossl_quic_urxe_data Unexecuted instantiation: quic_demux.c:ossl_quic_urxe_data Unexecuted instantiation: quic_engine.c:ossl_quic_urxe_data Unexecuted instantiation: quic_fifd.c:ossl_quic_urxe_data Unexecuted instantiation: quic_rx_depack.c:ossl_quic_urxe_data  | 
147  |  |  | 
148  |  | static ossl_unused ossl_inline unsigned char *  | 
149  |  | ossl_quic_urxe_data_end(const QUIC_URXE *e)  | 
150  | 0  | { | 
151  | 0  |     return ossl_quic_urxe_data(e) + e->data_len;  | 
152  | 0  | } Unexecuted instantiation: ssl_lib.c:ossl_quic_urxe_data_end Unexecuted instantiation: t1_lib.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_impl.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_method.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_obj.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_port.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_record_rx.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_record_util.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_rstream.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_sf_list.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_sstream.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_stream_map.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_thread_assist.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_txp.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_wire.c:ossl_quic_urxe_data_end Unexecuted instantiation: rec_layer_s3.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_channel.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_demux.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_engine.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_fifd.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_rx_depack.c:ossl_quic_urxe_data_end  | 
153  |  |  | 
154  |  | /* List structure tracking a queue of URXEs. */  | 
155  | 0  | DEFINE_LIST_OF(urxe, QUIC_URXE); Unexecuted instantiation: quic_record_rx.c:ossl_list_urxe_head Unexecuted instantiation: quic_record_rx.c:ossl_list_urxe_next Unexecuted instantiation: quic_record_rx.c:ossl_list_urxe_remove Unexecuted instantiation: quic_record_rx.c:ossl_list_urxe_insert_tail Unexecuted instantiation: quic_demux.c:ossl_list_urxe_next Unexecuted instantiation: quic_demux.c:ossl_list_urxe_head Unexecuted instantiation: quic_demux.c:ossl_list_urxe_prev Unexecuted instantiation: quic_demux.c:ossl_list_urxe_insert_after Unexecuted instantiation: quic_demux.c:ossl_list_urxe_remove Unexecuted instantiation: quic_demux.c:ossl_list_urxe_insert_tail Unexecuted instantiation: quic_demux.c:ossl_list_urxe_insert_head  | 
156  | 0  | typedef OSSL_LIST(urxe) QUIC_URXE_LIST;  | 
157  | 0  | 
  | 
158  | 0  | /*  | 
159  | 0  |  * List management helpers. These are used by the demuxer but can also be used  | 
160  | 0  |  * by users of the demuxer to manage URXEs.  | 
161  | 0  |  */  | 
162  | 0  | void ossl_quic_urxe_remove(QUIC_URXE_LIST *l, QUIC_URXE *e);  | 
163  | 0  | void ossl_quic_urxe_insert_head(QUIC_URXE_LIST *l, QUIC_URXE *e);  | 
164  | 0  | void ossl_quic_urxe_insert_tail(QUIC_URXE_LIST *l, QUIC_URXE *e);  | 
165  | 0  | 
  | 
166  | 0  | /*  | 
167  | 0  |  * Called when a datagram is received for a given connection ID.  | 
168  | 0  |  *  | 
169  | 0  |  * e is a URXE containing the datagram payload. It is permissible for the callee  | 
170  | 0  |  * to mutate this buffer; once the demuxer calls this callback, it will never  | 
171  | 0  |  * read the buffer again.  | 
172  | 0  |  *  | 
173  | 0  |  * If a DCID was identified for the datagram, dcid is non-NULL; otherwise  | 
174  | 0  |  * it is NULL.  | 
175  | 0  |  *  | 
176  | 0  |  * The callee must arrange for ossl_quic_demux_release_urxe or  | 
177  | 0  |  * ossl_quic_demux_reinject_urxe to be called on the URXE at some point in the  | 
178  | 0  |  * future (this need not be before the callback returns).  | 
179  | 0  |  *  | 
180  | 0  |  * At the time the callback is made, the URXE will not be in any queue,  | 
181  | 0  |  * therefore the callee can use the prev and next fields as it wishes.  | 
182  | 0  |  */  | 
183  | 0  | typedef void (ossl_quic_demux_cb_fn)(QUIC_URXE *e, void *arg,  | 
184  | 0  |                                      const QUIC_CONN_ID *dcid);  | 
185  | 0  | 
  | 
186  | 0  | /*  | 
187  | 0  |  * Creates a new demuxer. The given BIO is used to receive datagrams from the  | 
188  | 0  |  * network using BIO_recvmmsg. short_conn_id_len is the length of destination  | 
189  | 0  |  * connection IDs used in RX'd packets; it must have the same value for all  | 
190  | 0  |  * connections used on a socket. default_urxe_alloc_len is the buffer size to  | 
191  | 0  |  * receive datagrams into; it should be a value large enough to contain any  | 
192  | 0  |  * received datagram according to local MTUs, etc.  | 
193  | 0  |  *  | 
194  | 0  |  * now is an optional function used to determine the time a datagram was  | 
195  | 0  |  * received. now_arg is an opaque argument passed to the function. If now is  | 
196  | 0  |  * NULL, ossl_time_zero() is used as the datagram reception time.  | 
197  | 0  |  */  | 
198  | 0  | QUIC_DEMUX *ossl_quic_demux_new(BIO *net_bio,  | 
199  | 0  |                                 size_t short_conn_id_len,  | 
200  | 0  |                                 OSSL_TIME (*now)(void *arg),  | 
201  | 0  |                                 void *now_arg);  | 
202  | 0  | 
  | 
203  | 0  | /*  | 
204  | 0  |  * Destroy a demuxer. All URXEs must have been released back to the demuxer  | 
205  | 0  |  * before calling this. No-op if demux is NULL.  | 
206  | 0  |  */  | 
207  | 0  | void ossl_quic_demux_free(QUIC_DEMUX *demux);  | 
208  | 0  | 
  | 
209  | 0  | /*  | 
210  | 0  |  * Changes the BIO which the demuxer reads from. This also sets the MTU if the  | 
211  | 0  |  * BIO supports querying the MTU.  | 
212  | 0  |  */  | 
213  | 0  | void ossl_quic_demux_set_bio(QUIC_DEMUX *demux, BIO *net_bio);  | 
214  | 0  | 
  | 
215  | 0  | /*  | 
216  | 0  |  * Changes the MTU in bytes we use to receive datagrams.  | 
217  | 0  |  */  | 
218  | 0  | int ossl_quic_demux_set_mtu(QUIC_DEMUX *demux, unsigned int mtu);  | 
219  | 0  | 
  | 
220  | 0  | /*  | 
221  | 0  |  * Set the default packet handler. This is used for incoming packets which don't  | 
222  | 0  |  * match a registered DCID. This is only needed for servers. If a default packet  | 
223  | 0  |  * handler is not set, a packet which doesn't match a registered DCID is  | 
224  | 0  |  * silently dropped. A default packet handler may be unset by passing NULL.  | 
225  | 0  |  *  | 
226  | 0  |  * The handler is responsible for ensuring that ossl_quic_demux_reinject_urxe or  | 
227  | 0  |  * ossl_quic_demux_release_urxe is called on the passed packet at some point in  | 
228  | 0  |  * the future, which may or may not be before the handler returns.  | 
229  | 0  |  */  | 
230  | 0  | void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux,  | 
231  | 0  |                                          ossl_quic_demux_cb_fn *cb,  | 
232  | 0  |                                          void *cb_arg);  | 
233  | 0  | 
  | 
234  | 0  | /*  | 
235  | 0  |  * Releases a URXE back to the demuxer. No reference must be made to the URXE or  | 
236  | 0  |  * its buffer after calling this function. The URXE must not be in any queue;  | 
237  | 0  |  * that is, its prev and next pointers must be NULL.  | 
238  | 0  |  */  | 
239  | 0  | void ossl_quic_demux_release_urxe(QUIC_DEMUX *demux,  | 
240  | 0  |                                   QUIC_URXE *e);  | 
241  | 0  | 
  | 
242  | 0  | /*  | 
243  | 0  |  * Reinjects a URXE which was issued to a registered DCID callback or the  | 
244  | 0  |  * default packet handler callback back into the pending queue. This is useful  | 
245  | 0  |  * when a packet has been handled by the default packet handler callback such  | 
246  | 0  |  * that a DCID has now been registered and can be dispatched normally by DCID.  | 
247  | 0  |  * Once this has been called, the caller must not touch the URXE anymore and  | 
248  | 0  |  * must not also call ossl_quic_demux_release_urxe().  | 
249  | 0  |  *  | 
250  | 0  |  * The URXE is reinjected at the head of the queue, so it will be reprocessed  | 
251  | 0  |  * immediately.  | 
252  | 0  |  */  | 
253  | 0  | void ossl_quic_demux_reinject_urxe(QUIC_DEMUX *demux,  | 
254  | 0  |                                    QUIC_URXE *e);  | 
255  | 0  | 
  | 
256  | 0  | /*  | 
257  | 0  |  * Process any unprocessed RX'd datagrams, by calling registered callbacks by  | 
258  | 0  |  * connection ID, reading more datagrams from the BIO if necessary.  | 
259  | 0  |  *  | 
260  | 0  |  * Returns one of the following values:  | 
261  | 0  |  *  | 
262  | 0  |  *     QUIC_DEMUX_PUMP_RES_OK  | 
263  | 0  |  *         At least one incoming datagram was processed.  | 
264  | 0  |  *  | 
265  | 0  |  *     QUIC_DEMUX_PUMP_RES_TRANSIENT_FAIL  | 
266  | 0  |  *         No more incoming datagrams are currently available.  | 
267  | 0  |  *         Call again later.  | 
268  | 0  |  *  | 
269  | 0  |  *     QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL  | 
270  | 0  |  *         Either the network read BIO has failed in a non-transient fashion, or  | 
271  | 0  |  *         the QUIC implementation has encountered an internal state, assertion  | 
272  | 0  |  *         or allocation error. The caller should tear down the connection  | 
273  | 0  |  *         similarly to in the case of a protocol violation.  | 
274  | 0  |  *  | 
275  | 0  |  */  | 
276  | 0  | #define QUIC_DEMUX_PUMP_RES_OK              1  | 
277  | 0  | #define QUIC_DEMUX_PUMP_RES_TRANSIENT_FAIL  (-1)  | 
278  | 0  | #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  |