From 8ccb44e6f543eb355b04c0d08eb45598f3fe1fd1 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Mon, 1 Dec 2014 23:58:05 +0000 Subject: Remove instances in libssl of the constant 28 (for size of IPv4 header + UDP) and instead use the value provided by the underlying BIO. Also provide some new DTLS_CTRLs so that the library user can set the mtu without needing to know this constant. These new DTLS_CTRLs provide the capability to set the link level mtu to be used (i.e. including this IP/UDP overhead). The previous DTLS_CTRLs required the library user to subtract this overhead first. Reviewed-by: Tim Hudson (cherry picked from commit 59669b6abf620d1ed2ef4d1e2df25c998b89b64d) Conflicts: ssl/d1_both.c ssl/ssl.h ssl/ssl_lib.c --- ssl/d1_both.c | 54 +++++++++++++++++++++++++++++++++++++----------------- ssl/d1_lib.c | 25 +++++++++++++++++++++++++ ssl/dtls1.h | 4 ++++ ssl/ssl.h | 6 ++++++ ssl/ssl_lib.c | 13 ------------- ssl/ssl_locl.h | 3 ++- 6 files changed, 74 insertions(+), 31 deletions(-) diff --git a/ssl/d1_both.c b/ssl/d1_both.c index c7e85ff284..3f33d1a279 100644 --- a/ssl/d1_both.c +++ b/ssl/d1_both.c @@ -156,9 +156,9 @@ static unsigned char bitmask_start_values[] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe static unsigned char bitmask_end_values[] = {0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f}; /* XDTLS: figure out the right values */ -static unsigned int g_probable_mtu[] = {1500 - 28, 512 - 28, 256 - 28}; +static const unsigned int g_probable_mtu[] = {1500, 512, 256}; -static unsigned int dtls1_guess_mtu(unsigned int curr_mtu); +static void dtls1_guess_mtu(SSL *s); static void dtls1_fix_message_header(SSL *s, unsigned long frag_off, unsigned long frag_len); static unsigned char *dtls1_write_message_header(SSL *s, @@ -226,18 +226,24 @@ void dtls1_hm_fragment_free(hm_fragment *frag) static void dtls1_query_mtu(SSL *s) { + if(s->d1->link_mtu) + { + s->d1->mtu = s->d1->link_mtu-BIO_dgram_get_mtu_overhead(SSL_get_wbio(s)); + s->d1->link_mtu = 0; + } + /* AHA! Figure out the MTU, and stick to the right size */ - if (s->d1->mtu < dtls1_min_mtu() && !(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) + if (s->d1->mtu < dtls1_min_mtu(s) && !(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) { s->d1->mtu = BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); /* I've seen the kernel return bogus numbers when it doesn't know * (initial write), so just make sure we have a reasonable number */ - if (s->d1->mtu < dtls1_min_mtu()) + if (s->d1->mtu < dtls1_min_mtu(s)) { s->d1->mtu = 0; - s->d1->mtu = dtls1_guess_mtu(s->d1->mtu); + dtls1_guess_mtu(s); BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU, s->d1->mtu, NULL); } @@ -275,7 +281,7 @@ int dtls1_do_write(SSL *s, int type) } #endif - OPENSSL_assert(s->d1->mtu >= dtls1_min_mtu()); /* should have something reasonable now */ + OPENSSL_assert(s->d1->mtu >= dtls1_min_mtu(s)); /* should have something reasonable now */ if ( s->init_off == 0 && type == SSL3_RT_HANDSHAKE) OPENSSL_assert(s->init_num == @@ -1424,26 +1430,40 @@ dtls1_write_message_header(SSL *s, unsigned char *p) return p; } -unsigned int -dtls1_min_mtu(void) +unsigned int +dtls1_link_min_mtu(void) { return (g_probable_mtu[(sizeof(g_probable_mtu) / sizeof(g_probable_mtu[0])) - 1]); } -static unsigned int -dtls1_guess_mtu(unsigned int curr_mtu) +unsigned int +dtls1_min_mtu(SSL *s) { - unsigned int i; + return dtls1_link_min_mtu()-BIO_dgram_get_mtu_overhead(SSL_get_wbio(s)); + } - if ( curr_mtu == 0 ) - return g_probable_mtu[0] ; +static void +dtls1_guess_mtu(SSL *s) + { + unsigned int curr_mtu; + unsigned int i; + unsigned int mtu_ovr; - for ( i = 0; i < sizeof(g_probable_mtu)/sizeof(g_probable_mtu[0]); i++) - if ( curr_mtu > g_probable_mtu[i]) - return g_probable_mtu[i]; + curr_mtu = s->d1->mtu; + mtu_ovr = BIO_dgram_get_mtu_overhead(SSL_get_wbio(s)); - return curr_mtu; + if ( curr_mtu == 0 ) + { + curr_mtu = g_probable_mtu[0] - mtu_ovr; + } + else + { + for ( i = 0; i < sizeof(g_probable_mtu)/sizeof(g_probable_mtu[0]); i++) + if ( curr_mtu > g_probable_mtu[i] - mtu_ovr) + return g_probable_mtu[i] - mtu_ovr; + } + s->d1->mtu = curr_mtu; } void diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index 2f696c52d8..00417c61ad 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -112,6 +112,9 @@ int dtls1_new(SSL *s) d1->cookie_len = sizeof(s->d1->cookie); } + d1->link_mtu = 0; + d1->mtu = 0; + if( ! d1->unprocessed_rcds.q || ! d1->processed_rcds.q || ! d1->buffered_messages || ! d1->sent_messages || ! d1->buffered_app_data.q) { @@ -207,6 +210,7 @@ void dtls1_clear(SSL *s) pqueue sent_messages; pqueue buffered_app_data; unsigned int mtu; + unsigned int link_mtu; if (s->d1) { @@ -216,6 +220,7 @@ void dtls1_clear(SSL *s) sent_messages = s->d1->sent_messages; buffered_app_data = s->d1->buffered_app_data.q; mtu = s->d1->mtu; + link_mtu = s->d1->link_mtu; dtls1_clear_queues(s); @@ -229,6 +234,7 @@ void dtls1_clear(SSL *s) if (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU) { s->d1->mtu = mtu; + s->d1->link_mtu = link_mtu; } s->d1->unprocessed_rcds.q = unprocessed_rcds; @@ -274,6 +280,25 @@ long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg) * fail closed if the version is not as expected. */ return s->version == DTLS_MAX_VERSION; + /* Just one protocol version is supported so far; + * fail closed if the version is not as expected. */ + return s->version == DTLS_MAX_VERSION; + case DTLS_CTRL_SET_LINK_MTU: + if (larg < (long)dtls1_link_min_mtu()) + return 0; + s->d1->link_mtu = larg; + return 1; + case DTLS_CTRL_GET_LINK_MIN_MTU: + return (long)dtls1_link_min_mtu(); + case SSL_CTRL_SET_MTU: + /* + * We may not have a BIO set yet so can't call dtls1_min_mtu() + * We'll have to make do with dtls1_link_min_mtu() and max overhead + */ + if (larg < (long)dtls1_link_min_mtu() - DTLS1_MAX_MTU_OVERHEAD) + return 0; + s->d1->mtu = larg; + return larg; default: ret = ssl3_ctrl(s, cmd, larg, parg); break; diff --git a/ssl/dtls1.h b/ssl/dtls1.h index 3e5578dd0e..d4a865772e 100644 --- a/ssl/dtls1.h +++ b/ssl/dtls1.h @@ -108,6 +108,9 @@ extern "C" { #endif +/* Max MTU overhead we know about so far is 40 for IPv6 + 8 for UDP */ +#define DTLS1_MAX_MTU_OVERHEAD 48 + typedef struct dtls1_bitmap_st { unsigned long map; /* track 32 packets on 32-bit systems @@ -222,6 +225,7 @@ typedef struct dtls1_state_st /* Is set when listening for new connections with dtls1_listen() */ unsigned int listen; + unsigned int link_mtu; /* max on-the-wire DTLS packet size */ unsigned int mtu; /* max DTLS packet size */ struct hm_header_st w_msg_hdr; diff --git a/ssl/ssl.h b/ssl/ssl.h index 63ba59381f..4f4fc821fa 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -645,6 +645,10 @@ typedef struct ssl_session_st SSL_ctrl((ssl),SSL_CTRL_MODE,0,NULL) #define SSL_set_mtu(ssl, mtu) \ SSL_ctrl((ssl),SSL_CTRL_SET_MTU,(mtu),NULL) +#define DTLS_set_link_mtu(ssl, mtu) \ + SSL_ctrl((ssl),DTLS_CTRL_SET_LINK_MTU,(mtu),NULL) +#define DTLS_get_link_min_mtu(ssl) \ + SSL_ctrl((ssl),DTLS_CTRL_GET_LINK_MIN_MTU,0,NULL) #define SSL_get_secure_renegotiation_support(ssl) \ SSL_ctrl((ssl), SSL_CTRL_GET_RI_SUPPORT, 0, NULL) @@ -1430,6 +1434,8 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) #define SSL_CTRL_GET_RI_SUPPORT 76 #define SSL_CTRL_CLEAR_OPTIONS 77 #define SSL_CTRL_CLEAR_MODE 78 +#define DTLS_CTRL_SET_LINK_MTU 120 +#define DTLS_CTRL_GET_LINK_MIN_MTU 121 #define SSL_CTRL_CHECK_PROTO_VERSION 119 diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index f9c7c3555f..ac40c6ac44 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1053,19 +1053,6 @@ long SSL_ctrl(SSL *s,int cmd,long larg,void *parg) l=s->max_cert_list; s->max_cert_list=larg; return(l); - case SSL_CTRL_SET_MTU: -#ifndef OPENSSL_NO_DTLS1 - if (larg < (long)dtls1_min_mtu()) - return 0; -#endif - - if (SSL_version(s) == DTLS1_VERSION || - SSL_version(s) == DTLS1_BAD_VER) - { - s->d1->mtu = larg; - return larg; - } - return 0; case SSL_CTRL_SET_MAX_SEND_FRAGMENT: if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH) return 0; diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index a12b08faba..d038a938b5 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -963,7 +963,8 @@ void dtls1_stop_timer(SSL *s); int dtls1_is_timer_expired(SSL *s); void dtls1_double_timeout(SSL *s); int dtls1_send_newsession_ticket(SSL *s); -unsigned int dtls1_min_mtu(void); +unsigned int dtls1_min_mtu(SSL *s); +unsigned int dtls1_link_min_mtu(void); void dtls1_hm_fragment_free(hm_fragment *frag); /* some client-only functions */ -- cgit v1.2.3