From 0454f2c4901218d749e4dac411e8b471fd749474 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Sun, 17 May 2009 16:04:21 +0000 Subject: [PATCH] PR: 1929 Submitted by: Michael Tuexen Approved by: steve@openssl.org Updated DTLS MTU bug fix. --- apps/s_client.c | 6 +-- apps/s_server.c | 6 +-- crypto/bio/bss_dgram.c | 93 ++++++++++++++++++++++++++++++++++++------ ssl/dtls1.h | 2 +- 4 files changed, 88 insertions(+), 19 deletions(-) diff --git a/apps/s_client.c b/apps/s_client.c index 5f09c31297..bd2a3b8633 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -320,7 +320,7 @@ static void sc_usage(void) BIO_printf(bio_err," -ssl3 - just use SSLv3\n"); BIO_printf(bio_err," -tls1 - just use TLSv1\n"); BIO_printf(bio_err," -dtls1 - just use DTLSv1\n"); - BIO_printf(bio_err," -mtu - set the MTU\n"); + BIO_printf(bio_err," -mtu - set the link layer MTU\n"); BIO_printf(bio_err," -no_tls1/-no_ssl3/-no_ssl2 - turn off that protocol\n"); BIO_printf(bio_err," -bugs - Switch on all SSL implementation bug workarounds\n"); BIO_printf(bio_err," -serverpref - Use server's cipher preferences (only SSLv2)\n"); @@ -999,10 +999,10 @@ re_start: BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); } - if (socket_mtu > 0) + if (socket_mtu > 28) { SSL_set_options(con, SSL_OP_NO_QUERY_MTU); - SSL_set_mtu(con, socket_mtu); + SSL_set_mtu(con, socket_mtu - 28); } else /* want to do MTU discovery */ diff --git a/apps/s_server.c b/apps/s_server.c index dffa5d3151..6bbbd7f732 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -459,7 +459,7 @@ static void sv_usage(void) BIO_printf(bio_err," -tls1 - Just talk TLSv1\n"); BIO_printf(bio_err," -dtls1 - Just talk DTLSv1\n"); BIO_printf(bio_err," -timeout - Enable timeouts\n"); - BIO_printf(bio_err," -mtu - Set MTU\n"); + BIO_printf(bio_err," -mtu - Set link layer MTU\n"); BIO_printf(bio_err," -chain - Read a certificate chain\n"); BIO_printf(bio_err," -no_ssl2 - Just disable SSLv2\n"); BIO_printf(bio_err," -no_ssl3 - Just disable SSLv3\n"); @@ -1823,10 +1823,10 @@ static int sv_body(char *hostname, int s, unsigned char *context) BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); } - if (socket_mtu > 0) + if (socket_mtu > 28) { SSL_set_options(con, SSL_OP_NO_QUERY_MTU); - SSL_set_mtu(con, socket_mtu); + SSL_set_mtu(con, socket_mtu - 28); } else /* want to do MTU discovery */ diff --git a/crypto/bio/bss_dgram.c b/crypto/bio/bss_dgram.c index d809a35857..3f568da142 100644 --- a/crypto/bio/bss_dgram.c +++ b/crypto/bio/bss_dgram.c @@ -70,7 +70,9 @@ #include #endif +#ifdef OPENSSL_SYS_LINUX #define IP_MTU 14 /* linux is lame */ +#endif #ifdef WATT32 #define sock_write SockWrite /* Watt-32 uses same names */ @@ -336,6 +338,10 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) bio_dgram_data *data = NULL; long sockopt_val = 0; unsigned int sockopt_len = 0; +#ifdef OPENSSL_SYS_LINUX + socklen_t addr_len; + struct sockaddr_storage addr; +#endif data = (bio_dgram_data *)b->ptr; @@ -394,24 +400,87 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) #endif break; /* (Linux)kernel sets DF bit on outgoing IP packets */ -#ifdef IP_MTU_DISCOVER case BIO_CTRL_DGRAM_MTU_DISCOVER: - sockopt_val = IP_PMTUDISC_DO; - if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, - &sockopt_val, sizeof(sockopt_val))) < 0) - perror("setsockopt"); +#ifdef OPENSSL_SYS_LINUX + addr_len = (socklen_t)sizeof(struct sockaddr_storage); + memset((void *)&addr, 0, sizeof(struct sockaddr_storage)); + if (getsockname(b->num, (void *)&addr, &addr_len) < 0) + { + ret = 0; + break; + } + sockopt_len = sizeof(sockopt_val); + switch (addr.ss_family) + { + case AF_INET: + sockopt_val = IP_PMTUDISC_DO; + if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, + &sockopt_val, sizeof(sockopt_val))) < 0) + perror("setsockopt"); + break; + case AF_INET6: + sockopt_val = IPV6_PMTUDISC_DO; + if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER, + &sockopt_val, sizeof(sockopt_val))) < 0) + perror("setsockopt"); + break; + default: + ret = -1; + break; + } + ret = -1; +#else break; #endif case BIO_CTRL_DGRAM_QUERY_MTU: - sockopt_len = sizeof(sockopt_val); - if ((ret = getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val, - &sockopt_len)) < 0 || sockopt_val < 0) - { ret = 0; } - else +#ifdef OPENSSL_SYS_LINUX + addr_len = (socklen_t)sizeof(struct sockaddr_storage); + memset((void *)&addr, 0, sizeof(struct sockaddr_storage)); + if (getsockname(b->num, (void *)&addr, &addr_len) < 0) { - data->mtu = sockopt_val; - ret = data->mtu; + ret = 0; + break; } + sockopt_len = sizeof(sockopt_val); + switch (addr.ss_family) + { + case AF_INET: + if ((ret = getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val, + &sockopt_len)) < 0 || sockopt_val < 0) + { + ret = 0; + } + else + { + /* we assume that the transport protocol is UDP and no + * IP options are used. + */ + data->mtu = sockopt_val - 8 - 20; + ret = data->mtu; + } + break; + case AF_INET6: + if ((ret = getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU, (void *)&sockopt_val, + &sockopt_len)) < 0 || sockopt_val < 0) + { + ret = 0; + } + else + { + /* we assume that the transport protocol is UDP and no + * IPV6 options are used. + */ + data->mtu = sockopt_val - 8 - 40; + ret = data->mtu; + } + break; + default: + ret = 0; + break; + } +#else + ret = 0; +#endif break; case BIO_CTRL_DGRAM_GET_MTU: return data->mtu; diff --git a/ssl/dtls1.h b/ssl/dtls1.h index 177e55cd9f..884bbd34f1 100644 --- a/ssl/dtls1.h +++ b/ssl/dtls1.h @@ -204,7 +204,7 @@ typedef struct dtls1_state_st */ record_pqueue buffered_app_data; - unsigned int mtu; /* max wire packet size */ + unsigned int mtu; /* max DTLS packet size */ struct hm_header_st w_msg_hdr; struct hm_header_st r_msg_hdr; -- 2.25.1