From 533150630308b8182c157d3dc774421197555437 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 ffb47cc33d..d2babfe6ff 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(&ps->stats_out.packets); + atomic64_add(&ps->stats_out.bytes, ret); + + 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(struct 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(struct 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(&ps->stats_out.packets); - atomic64_add(&ps->stats_out.bytes, ret); - } - } - return dret; } diff --git a/daemon/main.c b/daemon/main.c index 88393fe45c..c47d50a18c 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -842,6 +842,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 1dbaa0695e..93a2b25075 100644 --- a/include/dtls.h +++ b/include/dtls.h @@ -17,6 +17,7 @@ #define DTLS_MAX_DIGEST_LEN 64 +#define DTLS_MTU_OVERHEAD 48 // 40 bytes IPv6 + 8 bytes UDP