2023-09-14 17:59:47 +08:00
|
|
|
/*
|
|
|
|
* 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"
|
2023-09-14 19:24:12 +08:00
|
|
|
#include "../testutil.h"
|
|
|
|
|
|
|
|
struct noisy_dgram_st {
|
|
|
|
size_t this_dgram;
|
|
|
|
};
|
2023-09-14 17:59:47 +08:00
|
|
|
|
|
|
|
static int noisy_dgram_read(BIO *bio, char *out, int outl)
|
|
|
|
{
|
|
|
|
/* We don't support this - not needed anyway */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int noisy_dgram_write(BIO *bio, const char *in, int inl)
|
|
|
|
{
|
|
|
|
/* We don't support this - not needed anyway */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static long noisy_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 noisy_dgram_gets(BIO *bio, char *buf, int size)
|
|
|
|
{
|
|
|
|
/* We don't support this - not needed anyway */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int noisy_dgram_puts(BIO *bio, const char *str)
|
|
|
|
{
|
|
|
|
/* We don't support this - not needed anyway */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int noisy_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);
|
|
|
|
}
|
|
|
|
|
2023-09-14 19:24:12 +08:00
|
|
|
static int should_drop(BIO *bio)
|
|
|
|
{
|
|
|
|
struct noisy_dgram_st *data = BIO_get_data(bio);
|
|
|
|
|
|
|
|
if (data == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Drop datagram 1 for now.
|
|
|
|
* TODO(QUIC): Provide more control over this behaviour.
|
|
|
|
*/
|
|
|
|
if (data->this_dgram == 1)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2023-09-14 17:59:47 +08:00
|
|
|
static int noisy_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);
|
2023-09-14 19:24:12 +08:00
|
|
|
size_t i, data_len = 0, drop_cnt = 0;
|
|
|
|
BIO_MSG *src, *dst;
|
|
|
|
struct noisy_dgram_st *data;
|
2023-09-14 17:59:47 +08:00
|
|
|
|
2023-09-14 19:24:12 +08:00
|
|
|
if (!TEST_ptr(next))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
data = BIO_get_data(bio);
|
|
|
|
if (!TEST_ptr(data))
|
2023-09-14 17:59:47 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
2023-09-14 19:24:12 +08:00
|
|
|
* 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.
|
2023-09-14 17:59:47 +08:00
|
|
|
*/
|
2023-09-14 19:24:12 +08:00
|
|
|
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;
|
|
|
|
|
|
|
|
/* Drop any messages */
|
|
|
|
for (i = 0, src = msg, dst = msg;
|
|
|
|
i < *msgs_processed;
|
|
|
|
i++, src++, data->this_dgram++) {
|
|
|
|
if (should_drop(bio)) {
|
|
|
|
drop_cnt++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (src != dst) {
|
|
|
|
/* Copy the src BIO_MSG to the dst BIO_MSG */
|
|
|
|
memcpy(dst->data, src->data, src->data_len);
|
|
|
|
dst->data_len = src->data_len;
|
|
|
|
dst->flags = src->flags;
|
|
|
|
if (src->local != NULL
|
|
|
|
&& !TEST_true(bio_addr_copy(dst->local, src->local)))
|
|
|
|
return 0;
|
|
|
|
if (!TEST_true(bio_addr_copy(dst->peer, src->peer)))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
dst++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*msgs_processed -= drop_cnt;
|
|
|
|
|
|
|
|
if (*msgs_processed == 0) {
|
|
|
|
ERR_raise(ERR_LIB_BIO, BIO_R_NON_FATAL);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
2023-09-14 17:59:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int noisy_dgram_new(BIO *bio)
|
|
|
|
{
|
2023-09-14 19:24:12 +08:00
|
|
|
struct noisy_dgram_st *data = OPENSSL_zalloc(sizeof(*data));
|
|
|
|
|
|
|
|
if (!TEST_ptr(data))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
BIO_set_data(bio, data);
|
2023-09-14 17:59:47 +08:00
|
|
|
BIO_set_init(bio, 1);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int noisy_dgram_free(BIO *bio)
|
|
|
|
{
|
2023-09-14 19:24:12 +08:00
|
|
|
OPENSSL_free(BIO_get_data(bio));
|
|
|
|
BIO_set_data(bio, NULL);
|
2023-09-14 17:59:47 +08:00
|
|
|
BIO_set_init(bio, 0);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Choose a sufficiently large type likely to be unused for this custom BIO */
|
|
|
|
#define BIO_TYPE_NOISY_DGRAM_FILTER (0x80 | BIO_TYPE_FILTER)
|
|
|
|
|
|
|
|
static BIO_METHOD *method_noisy_dgram = NULL;
|
|
|
|
|
|
|
|
/* Note: Not thread safe! */
|
|
|
|
const BIO_METHOD *bio_f_noisy_dgram_filter(void)
|
|
|
|
{
|
|
|
|
if (method_noisy_dgram == NULL) {
|
|
|
|
method_noisy_dgram = BIO_meth_new(BIO_TYPE_NOISY_DGRAM_FILTER,
|
|
|
|
"Nosiy datagram filter");
|
|
|
|
if (method_noisy_dgram == NULL
|
|
|
|
|| !BIO_meth_set_write(method_noisy_dgram, noisy_dgram_write)
|
|
|
|
|| !BIO_meth_set_read(method_noisy_dgram, noisy_dgram_read)
|
|
|
|
|| !BIO_meth_set_puts(method_noisy_dgram, noisy_dgram_puts)
|
|
|
|
|| !BIO_meth_set_gets(method_noisy_dgram, noisy_dgram_gets)
|
|
|
|
|| !BIO_meth_set_ctrl(method_noisy_dgram, noisy_dgram_ctrl)
|
|
|
|
|| !BIO_meth_set_sendmmsg(method_noisy_dgram, noisy_dgram_sendmmsg)
|
|
|
|
|| !BIO_meth_set_recvmmsg(method_noisy_dgram, noisy_dgram_recvmmsg)
|
|
|
|
|| !BIO_meth_set_create(method_noisy_dgram, noisy_dgram_new)
|
|
|
|
|| !BIO_meth_set_destroy(method_noisy_dgram, noisy_dgram_free))
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return method_noisy_dgram;
|
|
|
|
}
|
|
|
|
|
|
|
|
void bio_f_noisy_dgram_filter_free(void)
|
|
|
|
{
|
|
|
|
BIO_meth_free(method_noisy_dgram);
|
|
|
|
}
|