Remove instances in libssl of the constant 28 (for size of IPv4 header + UDP)
authorMatt Caswell <matt@openssl.org>
Mon, 1 Dec 2014 23:58:05 +0000 (23:58 +0000)
committerMatt Caswell <matt@openssl.org>
Wed, 3 Dec 2014 09:43:47 +0000 (09:43 +0000)
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 <tjh@openssl.org>
(cherry picked from commit 59669b6abf620d1ed2ef4d1e2df25c998b89b64d)

Conflicts:
ssl/d1_both.c
ssl/ssl.h
ssl/ssl_lib.c

ssl/d1_both.c
ssl/d1_lib.c
ssl/dtls1.h
ssl/ssl.h
ssl/ssl_lib.c
ssl/ssl_locl.h

index c7e85ff284dfa744b53e5e593ce739ad0c3193d6..3f33d1a2799dc5b47dcdefacc73689973d5436f9 100644 (file)
@@ -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
index 2f696c52d810e9384d2ad76c00e025f5278c2440..00417c61ad7f33601260154a6429ed1f5ff515c5 100644 (file)
@@ -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;
index 3e5578dd0e7a150beb01c2d2540bfc6cc36e2cc8..d4a865772e4aa8c41399c77b96bd4d4eaecfa051 100644 (file)
@@ -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;
index 63ba59381feaeec3eb16712cdd0fabb506e036bd..4f4fc821fa119cdf3adaef309dfd2cdeb3efb363 100644 (file)
--- 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
 
index f9c7c3555f33e26f275c988d28ac26938e78f6ea..ac40c6ac44ebc7f59f86c765100b825e108408bd 100644 (file)
@@ -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;
index a12b08faba373bec955eff512b0f8cad6b418ff8..d038a938b5b194d0735acf47453d5ff9263b7eed 100644 (file)
@@ -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 */