/src/openssl/include/internal/quic_demux.h
Line | Count | Source (jump to first uncovered line) |
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 | 1.18M | #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 | 421M | { |
145 | 421M | return (unsigned char *)&e[1]; |
146 | 421M | } Unexecuted instantiation: quic-client.c:ossl_quic_urxe_data Unexecuted instantiation: ssl_cert.c:ossl_quic_urxe_data Unexecuted instantiation: ssl_ciph.c:ossl_quic_urxe_data Unexecuted instantiation: ssl_init.c:ossl_quic_urxe_data Unexecuted instantiation: ssl_lib.c:ossl_quic_urxe_data Unexecuted instantiation: ssl_mcnf.c:ossl_quic_urxe_data Unexecuted instantiation: ssl_sess.c:ossl_quic_urxe_data Unexecuted instantiation: t1_lib.c:ossl_quic_urxe_data Unexecuted instantiation: tls13_enc.c:ossl_quic_urxe_data Unexecuted instantiation: tls_depr.c:ossl_quic_urxe_data Unexecuted instantiation: tls_srp.c:ossl_quic_urxe_data Unexecuted instantiation: quic_impl.c:ossl_quic_urxe_data Unexecuted instantiation: quic_method.c:ossl_quic_urxe_data quic_port.c:ossl_quic_urxe_data Line | Count | Source | 144 | 2.47M | { | 145 | 2.47M | return (unsigned char *)&e[1]; | 146 | 2.47M | } |
quic_record_rx.c:ossl_quic_urxe_data Line | Count | Source | 144 | 1.10M | { | 145 | 1.10M | return (unsigned char *)&e[1]; | 146 | 1.10M | } |
Unexecuted instantiation: quic_record_shared.c:ossl_quic_urxe_data Unexecuted instantiation: quic_record_tx.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: rec_layer_s3.c:ossl_quic_urxe_data Unexecuted instantiation: dtls_meth.c:ossl_quic_urxe_data Unexecuted instantiation: tls1_meth.c:ossl_quic_urxe_data Unexecuted instantiation: tls_common.c:ossl_quic_urxe_data Unexecuted instantiation: tls_multib.c:ossl_quic_urxe_data Unexecuted instantiation: tlsany_meth.c:ossl_quic_urxe_data Unexecuted instantiation: extensions.c:ossl_quic_urxe_data Unexecuted instantiation: extensions_clnt.c:ossl_quic_urxe_data Unexecuted instantiation: extensions_cust.c:ossl_quic_urxe_data Unexecuted instantiation: extensions_srvr.c:ossl_quic_urxe_data Unexecuted instantiation: statem.c:ossl_quic_urxe_data Unexecuted instantiation: statem_clnt.c:ossl_quic_urxe_data Unexecuted instantiation: statem_dtls.c:ossl_quic_urxe_data Unexecuted instantiation: statem_lib.c:ossl_quic_urxe_data Unexecuted instantiation: statem_srvr.c:ossl_quic_urxe_data Unexecuted instantiation: d1_lib.c:ossl_quic_urxe_data Unexecuted instantiation: d1_srtp.c:ossl_quic_urxe_data Unexecuted instantiation: methods.c:ossl_quic_urxe_data Unexecuted instantiation: pqueue.c:ossl_quic_urxe_data Unexecuted instantiation: s3_enc.c:ossl_quic_urxe_data Unexecuted instantiation: s3_lib.c:ossl_quic_urxe_data Unexecuted instantiation: s3_msg.c:ossl_quic_urxe_data Unexecuted instantiation: ssl_asn1.c:ossl_quic_urxe_data Unexecuted instantiation: ssl_conf.c:ossl_quic_urxe_data Unexecuted instantiation: ssl_rsa.c:ossl_quic_urxe_data Unexecuted instantiation: t1_enc.c:ossl_quic_urxe_data Unexecuted instantiation: quic_channel.c:ossl_quic_urxe_data quic_demux.c:ossl_quic_urxe_data Line | Count | Source | 144 | 417M | { | 145 | 417M | return (unsigned char *)&e[1]; | 146 | 417M | } |
Unexecuted instantiation: quic_engine.c:ossl_quic_urxe_data Unexecuted instantiation: quic_rx_depack.c:ossl_quic_urxe_data Unexecuted instantiation: quic_tls.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_d1.c:ossl_quic_urxe_data Unexecuted instantiation: ssl3_meth.c:ossl_quic_urxe_data Unexecuted instantiation: tls13_meth.c:ossl_quic_urxe_data Unexecuted instantiation: d1_msg.c:ossl_quic_urxe_data Unexecuted instantiation: quic_fifd.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: quic-client.c:ossl_quic_urxe_data_end Unexecuted instantiation: ssl_cert.c:ossl_quic_urxe_data_end Unexecuted instantiation: ssl_ciph.c:ossl_quic_urxe_data_end Unexecuted instantiation: ssl_init.c:ossl_quic_urxe_data_end Unexecuted instantiation: ssl_lib.c:ossl_quic_urxe_data_end Unexecuted instantiation: ssl_mcnf.c:ossl_quic_urxe_data_end Unexecuted instantiation: ssl_sess.c:ossl_quic_urxe_data_end Unexecuted instantiation: t1_lib.c:ossl_quic_urxe_data_end Unexecuted instantiation: tls13_enc.c:ossl_quic_urxe_data_end Unexecuted instantiation: tls_depr.c:ossl_quic_urxe_data_end Unexecuted instantiation: tls_srp.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_port.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_record_rx.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_record_shared.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_record_tx.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: rec_layer_s3.c:ossl_quic_urxe_data_end Unexecuted instantiation: dtls_meth.c:ossl_quic_urxe_data_end Unexecuted instantiation: tls1_meth.c:ossl_quic_urxe_data_end Unexecuted instantiation: tls_common.c:ossl_quic_urxe_data_end Unexecuted instantiation: tls_multib.c:ossl_quic_urxe_data_end Unexecuted instantiation: tlsany_meth.c:ossl_quic_urxe_data_end Unexecuted instantiation: extensions.c:ossl_quic_urxe_data_end Unexecuted instantiation: extensions_clnt.c:ossl_quic_urxe_data_end Unexecuted instantiation: extensions_cust.c:ossl_quic_urxe_data_end Unexecuted instantiation: extensions_srvr.c:ossl_quic_urxe_data_end Unexecuted instantiation: statem.c:ossl_quic_urxe_data_end Unexecuted instantiation: statem_clnt.c:ossl_quic_urxe_data_end Unexecuted instantiation: statem_dtls.c:ossl_quic_urxe_data_end Unexecuted instantiation: statem_lib.c:ossl_quic_urxe_data_end Unexecuted instantiation: statem_srvr.c:ossl_quic_urxe_data_end Unexecuted instantiation: d1_lib.c:ossl_quic_urxe_data_end Unexecuted instantiation: d1_srtp.c:ossl_quic_urxe_data_end Unexecuted instantiation: methods.c:ossl_quic_urxe_data_end Unexecuted instantiation: pqueue.c:ossl_quic_urxe_data_end Unexecuted instantiation: s3_enc.c:ossl_quic_urxe_data_end Unexecuted instantiation: s3_lib.c:ossl_quic_urxe_data_end Unexecuted instantiation: s3_msg.c:ossl_quic_urxe_data_end Unexecuted instantiation: ssl_asn1.c:ossl_quic_urxe_data_end Unexecuted instantiation: ssl_conf.c:ossl_quic_urxe_data_end Unexecuted instantiation: ssl_rsa.c:ossl_quic_urxe_data_end Unexecuted instantiation: t1_enc.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_rx_depack.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_tls.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_d1.c:ossl_quic_urxe_data_end Unexecuted instantiation: ssl3_meth.c:ossl_quic_urxe_data_end Unexecuted instantiation: tls13_meth.c:ossl_quic_urxe_data_end Unexecuted instantiation: d1_msg.c:ossl_quic_urxe_data_end Unexecuted instantiation: quic_fifd.c:ossl_quic_urxe_data_end |
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 | 17.1M | #define QUIC_DEMUX_PUMP_RES_OK 1 |
277 | 10.8M | #define QUIC_DEMUX_PUMP_RES_TRANSIENT_FAIL (-1) |
278 | 12.9M | #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 |