summaryrefslogtreecommitdiffstats
path: root/test/helpers
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2023-09-19 11:52:42 +0100
committerMatt Caswell <matt@openssl.org>2023-09-22 13:56:43 +0100
commit35bd8a60043bde500f777e465530076524d2534a (patch)
treebd31d264091952f4e37f3ba8527712c12b713f2a /test/helpers
parent5d3933eef0d937a4845a439d5fbfa76738592fc0 (diff)
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)
Diffstat (limited to 'test/helpers')
-rw-r--r--test/helpers/noisydgrambio.c61
-rw-r--r--test/helpers/pktsplitbio.c169
-rw-r--r--test/helpers/quictestlib.c61
-rw-r--r--test/helpers/quictestlib.h17
4 files changed, 246 insertions, 62 deletions
diff --git a/test/helpers/noisydgrambio.c b/test/helpers/noisydgrambio.c
index b42dbe6f4b..7dc6a9cf35 100644
--- a/test/helpers/noisydgrambio.c
+++ b/test/helpers/noisydgrambio.c
@@ -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)
diff --git a/test/helpers/pktsplitbio.c b/test/helpers/pktsplitbio.c
new file mode 100644
index 0000000000..a3c01b9506
--- /dev/null
+++ b/test/helpers/pktsplitbio.c
@@ -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);
+}
diff --git a/test/helpers/quictestlib.c b/test/helpers/quictestlib.c
index 28791267ed..6381d720ff 100644
--- a/test/helpers/quictestlib.c
+++ b/test/helpers/quictestlib.c
@@ -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;
+}
diff --git a/test/helpers/quictestlib.h b/test/helpers/quictestlib.h
index 7a72e352d9..f18cd29481 100644
--- a/test/helpers/quictestlib.h
+++ b/test/helpers/quictestlib.h
@@ -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); \ No newline at end of file
+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);