Coverage Report

Created: 2026-08-31 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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