From dd7e56d1f65015172e0885a3fb6af2b66d231612 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Thu, 26 Sep 2024 11:59:43 -0400 Subject: [PATCH] MT#55283 switch to BIO_set_callback_arg Use a BIO WRITE callback instead of BIO_read'ing from the BIO after each operation. This is a more direct way to intercept data that needs to be sent out. Implement MTU-related BIO callbacks. Deduct the assumed IP MTU overhead from the configured MTU during startup. Unlike the previous code, this does not necessarily send DTLS from the same socket that received a message, nor to the same address that sent one, and instead always uses the selected_sfd and ->endpoint. This may or may not be a regression. Closes #1806 Change-Id: I4d4456df3f378d00782cbfa64afdb2a038217e6c (cherry picked from commit 08332161cfd2ccd1065f8837f4f5cc7c9551d140) --- daemon/dtls.c | 90 +++++++++++++++++++++++++++++--------------------- daemon/main.c | 2 ++ include/dtls.h | 1 + 3 files changed, 56 insertions(+), 37 deletions(-) diff --git a/daemon/dtls.c b/daemon/dtls.c index 04669a29f1..c231487c35 100644 --- a/daemon/dtls.c +++ b/daemon/dtls.c @@ -604,6 +604,51 @@ static int try_connect(struct dtls_connection *d) { return ret; } +static long dtls_bio_callback(BIO *bio, int oper, const char *argp, size_t len, int argi, long argl, + int ret, size_t *proc) +{ + if (oper == (BIO_CB_CTRL | BIO_CB_RETURN)) { + if (argi == BIO_CTRL_DGRAM_QUERY_MTU) + return rtpe_config.dtls_mtu; // this is with overhead already subtracted + if (argi == BIO_CTRL_DGRAM_GET_MTU_OVERHEAD) + return DTLS_MTU_OVERHEAD; + return ret; + } + + if (oper != BIO_CB_WRITE) + return ret; + if (!argp || len <= 0) + return ret; + + struct packet_stream *ps = (struct packet_stream *) BIO_get_callback_arg(bio); + if (!ps) + return ret; + struct stream_fd *sfd = ps->selected_sfd; + if (!sfd) + return ret; + struct dtls_connection *d = dtls_ptr(sfd); + if (!d) + return ret; + + __DBG("dtls packet output: len %zu %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + len, + argp[0], argp[1], argp[2], argp[3], + argp[4], argp[5], argp[6], argp[7], + argp[8], argp[9], argp[10], argp[11], + argp[12], argp[13], argp[14], argp[15]); + + const endpoint_t *fsin = &ps->endpoint; + if (fsin->port == 9 || fsin->address.family == NULL) + return ret; + + ilogs(srtp, LOG_DEBUG, "Sending DTLS packet"); + socket_sendto(&sfd->socket, argp, len, fsin); + atomic64_inc_na(&ps->stats_out->packets); + atomic64_add_na(&ps->stats_out->bytes, len); + + return ret; +} + int dtls_connection_init(struct dtls_connection *d, struct packet_stream *ps, int active, struct dtls_cert *cert) { @@ -656,6 +701,14 @@ int dtls_connection_init(struct dtls_connection *d, struct packet_stream *ps, in if (!d->r_bio || !d->w_bio) goto error; + BIO_set_callback_ex(d->w_bio, dtls_bio_callback); + BIO_set_callback_arg(d->w_bio, (char *) ps); + +#if defined(BIO_CTRL_DGRAM_SET_MTU) + BIO_ctrl(d->w_bio, BIO_CTRL_DGRAM_SET_MTU, rtpe_config.dtls_mtu, NULL); + BIO_ctrl(d->r_bio, BIO_CTRL_DGRAM_SET_MTU, rtpe_config.dtls_mtu, NULL); +#endif + SSL_set_app_data(d->ssl, d); SSL_set_bio(d->ssl, d->r_bio, d->w_bio); d->init = 1; @@ -792,7 +845,6 @@ static int dtls_setup_crypto(struct packet_stream *ps, struct dtls_connection *d int dtls(stream_fd *sfd, const str *s, const endpoint_t *fsin) { struct packet_stream *ps = sfd->stream; int ret; - unsigned char buf[0x10000]; if (!ps) return 0; @@ -856,42 +908,6 @@ int dtls(stream_fd *sfd, const str *s, const endpoint_t *fsin) { } } - while (1) { - ret = BIO_ctrl_pending(d->w_bio); - if (ret <= 0) - break; - - if (ret > sizeof(buf)) { - ilogs(srtp, LOG_ERROR, "BIO buffer overflow"); - (void) BIO_reset(d->w_bio); - break; - } - - ret = BIO_read(d->w_bio, buf, ret); - if (ret <= 0) - break; - - __DBG("dtls packet output: len %u %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - ret, - buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7], - buf[8], buf[9], buf[10], buf[11], - buf[12], buf[13], buf[14], buf[15]); - - if (!fsin) { - fsin = &ps->endpoint; - if (fsin->port == 9 || fsin->address.family == NULL) - fsin = NULL; - } - - if (fsin) { - ilogs(srtp, LOG_DEBUG, "Sending DTLS packet"); - socket_sendto(&sfd->socket, buf, ret, fsin); - atomic64_inc_na(&ps->stats_out->packets); - atomic64_add_na(&ps->stats_out->bytes, ret); - } - } - return dret; } diff --git a/daemon/main.c b/daemon/main.c index 55f1ec24a2..d034f11024 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -955,6 +955,8 @@ static void options(int *argc, char ***argv) { However, this does not preclude link layers with an MTU smaller than this minimum MTU from conveying IP data. Internet IPv4 path MTU is 68 bytes.*/ die("Invalid --dtls-mtu (%i)", rtpe_config.dtls_mtu); + rtpe_config.dtls_mtu -= DTLS_MTU_OVERHEAD; + if (rtpe_config.jb_length < 0) die("Invalid negative jitter buffer size"); diff --git a/include/dtls.h b/include/dtls.h index b9b836b48c..80238658e4 100644 --- a/include/dtls.h +++ b/include/dtls.h @@ -13,6 +13,7 @@ #include "types.h" #define DTLS_MAX_DIGEST_LEN 64 +#define DTLS_MTU_OVERHEAD 48 // 40 bytes IPv6 + 8 bytes UDP struct packet_stream; struct sockaddr_in6;