mirror of
https://github.com/openssl/openssl.git
synced 2025-01-24 13:55:42 +08:00
Add a packet splitting BIO
Provide a BIO filter that can split QUIC datagrams containing multiple packets, such that each packet is in its own datagram. Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Paul Dale <pauli@openssl.org> (Merged from https://github.com/openssl/openssl/pull/22157)
This commit is contained in:
parent
5d3933eef0
commit
35bd8a6004
@ -339,7 +339,9 @@ IF[{- !$disabled{tests} -}]
|
||||
INCLUDE[quic_client_test]=../include ../apps/include
|
||||
DEPEND[quic_client_test]=../libcrypto.a ../libssl.a libtestutil.a
|
||||
|
||||
SOURCE[quic_multistream_test]=quic_multistream_test.c helpers/ssltestlib.c helpers/quictestlib.c helpers/noisydgrambio.c
|
||||
$QUICTESTHELPERS=helpers/quictestlib.c helpers/noisydgrambio.c helpers/pktsplitbio.c
|
||||
|
||||
SOURCE[quic_multistream_test]=quic_multistream_test.c helpers/ssltestlib.c $QUICTESTHELPERS
|
||||
INCLUDE[quic_multistream_test]=../include ../apps/include
|
||||
DEPEND[quic_multistream_test]=../libcrypto.a ../libssl.a libtestutil.a
|
||||
|
||||
@ -818,15 +820,15 @@ IF[{- !$disabled{tests} -}]
|
||||
INCLUDE[event_queue_test]=../include ../apps/include
|
||||
DEPEND[event_queue_test]=../libcrypto ../libssl.a libtestutil.a
|
||||
|
||||
SOURCE[quicfaultstest]=quicfaultstest.c helpers/ssltestlib.c helpers/quictestlib.c helpers/noisydgrambio.c
|
||||
SOURCE[quicfaultstest]=quicfaultstest.c helpers/ssltestlib.c $QUICTESTHELPERS
|
||||
INCLUDE[quicfaultstest]=../include ../apps/include ..
|
||||
DEPEND[quicfaultstest]=../libcrypto.a ../libssl.a libtestutil.a
|
||||
|
||||
SOURCE[quicapitest]=quicapitest.c helpers/ssltestlib.c helpers/quictestlib.c helpers/noisydgrambio.c
|
||||
SOURCE[quicapitest]=quicapitest.c helpers/ssltestlib.c $QUICTESTHELPERS
|
||||
INCLUDE[quicapitest]=../include ../apps/include
|
||||
DEPEND[quicapitest]=../libcrypto.a ../libssl.a libtestutil.a
|
||||
|
||||
SOURCE[quic_newcid_test]=quic_newcid_test.c helpers/ssltestlib.c helpers/quictestlib.c helpers/noisydgrambio.c
|
||||
SOURCE[quic_newcid_test]=quic_newcid_test.c helpers/ssltestlib.c $QUICTESTHELPERS
|
||||
INCLUDE[quic_newcid_test]=../include ../apps/include ..
|
||||
DEPEND[quic_newcid_test]=../libcrypto.a ../libssl.a libtestutil.a
|
||||
ENDIF
|
||||
|
@ -105,67 +105,6 @@ static void get_noise(uint64_t *delay, int *should_drop)
|
||||
*delay += (uint64_t)(*should_drop);
|
||||
}
|
||||
|
||||
/* There isn't a public function to do BIO_ADDR_copy() so we create one */
|
||||
static int bio_addr_copy(BIO_ADDR *dst, BIO_ADDR *src)
|
||||
{
|
||||
size_t len;
|
||||
void *data = NULL;
|
||||
int res = 0;
|
||||
int family;
|
||||
|
||||
if (src == NULL || dst == NULL)
|
||||
return 0;
|
||||
|
||||
family = BIO_ADDR_family(src);
|
||||
if (family == AF_UNSPEC) {
|
||||
BIO_ADDR_clear(dst);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!BIO_ADDR_rawaddress(src, NULL, &len))
|
||||
return 0;
|
||||
|
||||
if (len > 0) {
|
||||
data = OPENSSL_malloc(len);
|
||||
if (!TEST_ptr(data))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!BIO_ADDR_rawaddress(src, data, &len))
|
||||
goto err;
|
||||
|
||||
if (!BIO_ADDR_rawmake(src, family, data, len, BIO_ADDR_rawport(src)))
|
||||
goto err;
|
||||
|
||||
res = 1;
|
||||
err:
|
||||
OPENSSL_free(data);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int bio_msg_copy(BIO_MSG *dst, BIO_MSG *src)
|
||||
{
|
||||
/*
|
||||
* Note it is assumed that the originally allocated data sizes for dst and
|
||||
* src are the same
|
||||
*/
|
||||
memcpy(dst->data, src->data, src->data_len);
|
||||
dst->data_len = src->data_len;
|
||||
dst->flags = src->flags;
|
||||
if (dst->local != NULL) {
|
||||
if (src->local != NULL) {
|
||||
if (!TEST_true(bio_addr_copy(dst->local, src->local)))
|
||||
return 0;
|
||||
} else {
|
||||
BIO_ADDR_clear(dst->local);
|
||||
}
|
||||
}
|
||||
if (!TEST_true(bio_addr_copy(dst->peer, src->peer)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int noisy_dgram_recvmmsg(BIO *bio, BIO_MSG *msg, size_t stride,
|
||||
size_t num_msg, uint64_t flags,
|
||||
size_t *msgs_processed)
|
||||
|
169
test/helpers/pktsplitbio.c
Normal file
169
test/helpers/pktsplitbio.c
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include "quictestlib.h"
|
||||
#include "../testutil.h"
|
||||
|
||||
static int pkt_split_dgram_read(BIO *bio, char *out, int outl)
|
||||
{
|
||||
/* We don't support this - not needed anyway */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int pkt_split_dgram_write(BIO *bio, const char *in, int inl)
|
||||
{
|
||||
/* We don't support this - not needed anyway */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static long pkt_split_dgram_ctrl(BIO *bio, int cmd, long num, void *ptr)
|
||||
{
|
||||
long ret;
|
||||
BIO *next = BIO_next(bio);
|
||||
|
||||
if (next == NULL)
|
||||
return 0;
|
||||
|
||||
switch (cmd) {
|
||||
case BIO_CTRL_DUP:
|
||||
ret = 0L;
|
||||
break;
|
||||
default:
|
||||
ret = BIO_ctrl(next, cmd, num, ptr);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pkt_split_dgram_gets(BIO *bio, char *buf, int size)
|
||||
{
|
||||
/* We don't support this - not needed anyway */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int pkt_split_dgram_puts(BIO *bio, const char *str)
|
||||
{
|
||||
/* We don't support this - not needed anyway */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int pkt_split_dgram_sendmmsg(BIO *bio, BIO_MSG *msg, size_t stride,
|
||||
size_t num_msg, uint64_t flags,
|
||||
size_t *msgs_processed)
|
||||
{
|
||||
BIO *next = BIO_next(bio);
|
||||
|
||||
if (next == NULL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* We only introduce noise when receiving messages. We just pass this on
|
||||
* to the underlying BIO.
|
||||
*/
|
||||
return BIO_sendmmsg(next, msg, stride, num_msg, flags, msgs_processed);
|
||||
}
|
||||
|
||||
static int pkt_split_dgram_recvmmsg(BIO *bio, BIO_MSG *msg, size_t stride,
|
||||
size_t num_msg, uint64_t flags,
|
||||
size_t *msgs_processed)
|
||||
{
|
||||
BIO *next = BIO_next(bio);
|
||||
size_t i, j, data_len = 0, msg_cnt = 0;
|
||||
BIO_MSG *thismsg;
|
||||
|
||||
if (!TEST_ptr(next))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* For simplicity we assume that all elements in the msg array have the
|
||||
* same data_len. They are not required to by the API, but it would be quite
|
||||
* strange for that not to be the case - and our code that calls
|
||||
* BIO_recvmmsg does do this (which is all that is important for this test
|
||||
* code). We test the invariant here.
|
||||
*/
|
||||
for (i = 0; i < num_msg; i++) {
|
||||
if (i == 0)
|
||||
data_len = msg[i].data_len;
|
||||
else if (!TEST_size_t_eq(msg[i].data_len, data_len))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!BIO_recvmmsg(next, msg, stride, num_msg, flags, msgs_processed))
|
||||
return 0;
|
||||
|
||||
msg_cnt = *msgs_processed;
|
||||
if (msg_cnt == num_msg)
|
||||
return 1; /* We've used all our slots and can't split any more */
|
||||
assert(msg_cnt < num_msg);
|
||||
|
||||
for (i = 0, thismsg = msg; i < msg_cnt; i++, thismsg++) {
|
||||
QUIC_PKT_HDR hdr;
|
||||
PACKET pkt;
|
||||
size_t remain;
|
||||
|
||||
if (!PACKET_buf_init(&pkt, thismsg->data, thismsg->data_len))
|
||||
return 0;
|
||||
|
||||
/* Decode the packet header */
|
||||
/*
|
||||
* TODO(QUIC SERVER): We need to query the short connection id len
|
||||
* here, e.g. via some API SSL_get_short_conn_id_len()
|
||||
*/
|
||||
if (ossl_quic_wire_decode_pkt_hdr(&pkt, 0, 0, 0, &hdr, NULL) != 1)
|
||||
return 0;
|
||||
remain = PACKET_remaining(&pkt);
|
||||
if (remain > 0) {
|
||||
for (j = msg_cnt; j > i; j--) {
|
||||
if (!bio_msg_copy(&msg[j], &msg[j - 1]))
|
||||
return 0;
|
||||
}
|
||||
thismsg->data_len -= remain;
|
||||
msg[i + 1].data_len = remain;
|
||||
memmove(msg[i + 1].data,
|
||||
(unsigned char *)msg[i + 1].data + thismsg->data_len,
|
||||
remain);
|
||||
msg_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
*msgs_processed = msg_cnt;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Choose a sufficiently large type likely to be unused for this custom BIO */
|
||||
#define BIO_TYPE_PKT_SPLIT_DGRAM_FILTER (0x81 | BIO_TYPE_FILTER)
|
||||
|
||||
static BIO_METHOD *method_pkt_split_dgram = NULL;
|
||||
|
||||
/* Note: Not thread safe! */
|
||||
const BIO_METHOD *bio_f_pkt_split_dgram_filter(void)
|
||||
{
|
||||
if (method_pkt_split_dgram == NULL) {
|
||||
method_pkt_split_dgram = BIO_meth_new(BIO_TYPE_PKT_SPLIT_DGRAM_FILTER,
|
||||
"Packet splitting datagram filter");
|
||||
if (method_pkt_split_dgram == NULL
|
||||
|| !BIO_meth_set_write(method_pkt_split_dgram, pkt_split_dgram_write)
|
||||
|| !BIO_meth_set_read(method_pkt_split_dgram, pkt_split_dgram_read)
|
||||
|| !BIO_meth_set_puts(method_pkt_split_dgram, pkt_split_dgram_puts)
|
||||
|| !BIO_meth_set_gets(method_pkt_split_dgram, pkt_split_dgram_gets)
|
||||
|| !BIO_meth_set_ctrl(method_pkt_split_dgram, pkt_split_dgram_ctrl)
|
||||
|| !BIO_meth_set_sendmmsg(method_pkt_split_dgram,
|
||||
pkt_split_dgram_sendmmsg)
|
||||
|| !BIO_meth_set_recvmmsg(method_pkt_split_dgram,
|
||||
pkt_split_dgram_recvmmsg))
|
||||
return NULL;
|
||||
}
|
||||
return method_pkt_split_dgram;
|
||||
}
|
||||
|
||||
void bio_f_pkt_split_dgram_filter_free(void)
|
||||
{
|
||||
BIO_meth_free(method_pkt_split_dgram);
|
||||
}
|
@ -1044,3 +1044,64 @@ int qtest_fault_resize_datagram(QTEST_FAULT *fault, size_t newlen)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* There isn't a public function to do BIO_ADDR_copy() so we create one */
|
||||
int bio_addr_copy(BIO_ADDR *dst, BIO_ADDR *src)
|
||||
{
|
||||
size_t len;
|
||||
void *data = NULL;
|
||||
int res = 0;
|
||||
int family;
|
||||
|
||||
if (src == NULL || dst == NULL)
|
||||
return 0;
|
||||
|
||||
family = BIO_ADDR_family(src);
|
||||
if (family == AF_UNSPEC) {
|
||||
BIO_ADDR_clear(dst);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!BIO_ADDR_rawaddress(src, NULL, &len))
|
||||
return 0;
|
||||
|
||||
if (len > 0) {
|
||||
data = OPENSSL_malloc(len);
|
||||
if (!TEST_ptr(data))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!BIO_ADDR_rawaddress(src, data, &len))
|
||||
goto err;
|
||||
|
||||
if (!BIO_ADDR_rawmake(src, family, data, len, BIO_ADDR_rawport(src)))
|
||||
goto err;
|
||||
|
||||
res = 1;
|
||||
err:
|
||||
OPENSSL_free(data);
|
||||
return res;
|
||||
}
|
||||
|
||||
int bio_msg_copy(BIO_MSG *dst, BIO_MSG *src)
|
||||
{
|
||||
/*
|
||||
* Note it is assumed that the originally allocated data sizes for dst and
|
||||
* src are the same
|
||||
*/
|
||||
memcpy(dst->data, src->data, src->data_len);
|
||||
dst->data_len = src->data_len;
|
||||
dst->flags = src->flags;
|
||||
if (dst->local != NULL) {
|
||||
if (src->local != NULL) {
|
||||
if (!TEST_true(bio_addr_copy(dst->local, src->local)))
|
||||
return 0;
|
||||
} else {
|
||||
BIO_ADDR_clear(dst->local);
|
||||
}
|
||||
}
|
||||
if (!TEST_true(bio_addr_copy(dst->peer, src->peer)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -233,8 +233,23 @@ int qtest_fault_set_datagram_listener(QTEST_FAULT *fault,
|
||||
*/
|
||||
int qtest_fault_resize_datagram(QTEST_FAULT *fault, size_t newlen);
|
||||
|
||||
/* Copy a BIO_ADDR */
|
||||
int bio_addr_copy(BIO_ADDR *dst, BIO_ADDR *src);
|
||||
|
||||
/* Copy a BIO_MSG */
|
||||
int bio_msg_copy(BIO_MSG *dst, BIO_MSG *src);
|
||||
|
||||
/* BIO filter for simulating a noisy UDP socket */
|
||||
const BIO_METHOD *bio_f_noisy_dgram_filter(void);
|
||||
|
||||
/* Free the BIO filter method object */
|
||||
void bio_f_noisy_dgram_filter_free(void);
|
||||
void bio_f_noisy_dgram_filter_free(void);
|
||||
|
||||
/*
|
||||
* BIO filter for splitting QUIC datagrams containing multiple packets into
|
||||
* individual datagrams.
|
||||
*/
|
||||
const BIO_METHOD *bio_f_pkt_split_dgram_filter(void);
|
||||
|
||||
/* Free the BIO filter method object */
|
||||
void bio_f_pkt_split_dgram_filter_free(void);
|
||||
|
Loading…
Reference in New Issue
Block a user