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