diff --git a/test/helpers/noisydgrambio.c b/test/helpers/noisydgrambio.c index 8b68726dd2..33cf84c3c6 100644 --- a/test/helpers/noisydgrambio.c +++ b/test/helpers/noisydgrambio.c @@ -17,6 +17,7 @@ struct noisy_dgram_st { uint64_t this_dgram; BIO_MSG msg; uint64_t reinject_dgram; + int backoff; }; static long noisy_dgram_ctrl(BIO *bio, int cmd, long num, void *ptr) @@ -31,6 +32,16 @@ static long noisy_dgram_ctrl(BIO *bio, int cmd, long num, void *ptr) case BIO_CTRL_DUP: ret = 0L; break; + case BIO_CTRL_NOISE_BACK_OFF: { + struct noisy_dgram_st *data; + + data = BIO_get_data(bio); + if (!TEST_ptr(data)) + return 0; + data->backoff = 1; + ret = 1; + break; + } default: ret = BIO_ctrl(next, cmd, num, ptr); break; @@ -195,6 +206,17 @@ static int noisy_dgram_recvmmsg(BIO *bio, BIO_MSG *msg, size_t stride, } get_noise(&reinject, &should_drop); + if (data->backoff) { + /* + * We might be asked to back off on introducing too much noise if + * there is a danger that the connection will fail. In that case + * we always ensure that the next datagram does not get dropped so + * that the connection always survives. After that we can resume + * with normal noise + */ + should_drop = 0; + data->backoff = 0; + } /* * We ignore reinjection if a message is already waiting to be diff --git a/test/helpers/quictestlib.c b/test/helpers/quictestlib.c index 514bb6422a..0ae05e5701 100644 --- a/test/helpers/quictestlib.c +++ b/test/helpers/quictestlib.c @@ -26,6 +26,13 @@ #define GROWTH_ALLOWANCE 1024 +struct noise_args_data_st { + BIO *cbio; + BIO *sbio; + BIO *tracebio; + int flags; +}; + struct qtest_fault { QUIC_TSERVER *qtserv; @@ -62,6 +69,7 @@ struct qtest_fault { BIO_MSG msg; /* Allocated size of msg data buffer */ size_t msgalloc; + struct noise_args_data_st noiseargs; }; static void packet_plain_finish(void *arg); @@ -75,6 +83,41 @@ static OSSL_TIME fake_now_cb(void *arg) return fake_now; } +static void noise_msg_callback(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, + void *arg) +{ + struct noise_args_data_st *noiseargs = (struct noise_args_data_st *)arg; + + if (content_type == SSL3_RT_QUIC_FRAME_FULL) { + PACKET pkt; + uint64_t frame_type; + + if (!PACKET_buf_init(&pkt, buf, len)) + return; + + if (!ossl_quic_wire_peek_frame_header(&pkt, &frame_type, NULL)) + return; + + if (frame_type == OSSL_QUIC_FRAME_TYPE_PING) { + /* + * If either endpoint issues a ping frame then we are in danger + * of our noise being too much such that the connection itself + * fails. We back off on the noise for a bit to avoid that. + */ + BIO_ctrl(noiseargs->cbio, BIO_CTRL_NOISE_BACK_OFF, 0, NULL); + BIO_ctrl(noiseargs->sbio, BIO_CTRL_NOISE_BACK_OFF, 0, NULL); + } + } + +#ifndef OPENSSL_NO_SSL_TRACE + if ((noiseargs->flags & QTEST_FLAG_CLIENT_TRACE) != 0 + && !SSL_is_server(ssl)) + SSL_trace(write_p, version, content_type, buf, len, ssl, + noiseargs->tracebio); +#endif +} + int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx, SSL_CTX *serverctx, char *certfile, char *keyfile, int flags, QUIC_TSERVER **qtserv, SSL **cssl, @@ -89,15 +132,18 @@ int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx, BIO *tmpbio = NULL; *qtserv = NULL; - if (fault != NULL) - *fault = NULL; - if (*cssl == NULL) { *cssl = SSL_new(clientctx); if (!TEST_ptr(*cssl)) return 0; } + if (fault != NULL) { + *fault = OPENSSL_zalloc(sizeof(**fault)); + if (*fault == NULL) + goto err; + } + #ifndef OPENSSL_NO_SSL_TRACE if ((flags & QTEST_FLAG_CLIENT_TRACE) != 0) { tmpbio = BIO_new_fp(stdout, BIO_NOCLOSE); @@ -170,7 +216,15 @@ int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx, } if ((flags & QTEST_FLAG_NOISE) != 0) { - BIO *noisebio = BIO_new(bio_f_noisy_dgram_filter()); + BIO *noisebio; + + /* + * It is an error to not have a QTEST_FAULT object when introducing noise + */ + if (!TEST_ptr(fault)) + goto err; + + noisebio = BIO_new(bio_f_noisy_dgram_filter()); if (!TEST_ptr(noisebio)) goto err; @@ -181,6 +235,14 @@ int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx, if (!TEST_ptr(noisebio)) goto err; sbio = BIO_push(noisebio, sbio); + + (*fault)->noiseargs.cbio = cbio; + (*fault)->noiseargs.sbio = sbio; + (*fault)->noiseargs.tracebio = tmpbio; + (*fault)->noiseargs.flags = flags; + + SSL_set_msg_callback(*cssl, noise_msg_callback); + SSL_set_msg_callback_arg(*cssl, &(*fault)->noiseargs); } SSL_set_bio(*cssl, cbio, cbio); @@ -192,12 +254,6 @@ int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx, if (!TEST_true(SSL_set1_initial_peer_addr(*cssl, peeraddr))) goto err; - if (fault != NULL) { - *fault = OPENSSL_zalloc(sizeof(**fault)); - if (*fault == NULL) - goto err; - } - fisbio = BIO_new(qtest_get_bio_method()); if (!TEST_ptr(fisbio)) goto err; @@ -237,6 +293,10 @@ int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx, sbio = NULL; fisbio = NULL; + if ((flags & QTEST_FLAG_NOISE) != 0) + ossl_quic_tserver_set_msg_callback(*qtserv, noise_msg_callback, + &(*fault)->noiseargs); + if (fault != NULL) (*fault)->qtserv = *qtserv; diff --git a/test/helpers/quictestlib.h b/test/helpers/quictestlib.h index f090299b22..d1ac350c24 100644 --- a/test/helpers/quictestlib.h +++ b/test/helpers/quictestlib.h @@ -245,6 +245,8 @@ int qtest_fault_resize_datagram(QTEST_FAULT *fault, size_t newlen); /* Copy a BIO_MSG */ int bio_msg_copy(BIO_MSG *dst, BIO_MSG *src); +#define BIO_CTRL_NOISE_BACK_OFF 1001 + /* BIO filter for simulating a noisy UDP socket */ const BIO_METHOD *bio_f_noisy_dgram_filter(void); diff --git a/test/quicapitest.c b/test/quicapitest.c index 273f1421e7..7739cbcb24 100644 --- a/test/quicapitest.c +++ b/test/quicapitest.c @@ -1410,6 +1410,7 @@ static int test_noisy_dgram(int idx) size_t msglen = strlen(msg), written, readbytes, i, j; unsigned char buf[80]; int flags = QTEST_FLAG_NOISE | QTEST_FLAG_FAKE_TIME; + QTEST_FAULT *fault = NULL; if (idx == 1) flags |= QTEST_FLAG_PACKET_SPLIT; @@ -1418,7 +1419,7 @@ static int test_noisy_dgram(int idx) || !TEST_true(qtest_create_quic_objects(libctx, cctx, NULL, cert, privkey, flags, &qtserv, - &clientquic, NULL, NULL))) + &clientquic, &fault, NULL))) goto err; if (!TEST_true(qtest_create_quic_connection(qtserv, clientquic))) @@ -1492,6 +1493,7 @@ static int test_noisy_dgram(int idx) SSL_free(stream[1]); SSL_free(clientquic); SSL_CTX_free(cctx); + qtest_fault_free(fault); return testresult; }