Refactoring BIO: Adapt BIO_s_datagram and all that depends on it
authorRichard Levitte <levitte@openssl.org>
Tue, 2 Feb 2016 23:27:44 +0000 (00:27 +0100)
committerRichard Levitte <levitte@openssl.org>
Wed, 3 Feb 2016 18:40:32 +0000 (19:40 +0100)
The control commands that previously took a struct sockaddr * have
been changed to take a BIO_ADDR * instead.

Reviewed-by: Kurt Roeckx <kurt@openssl.org>
apps/s_cb.c
apps/s_server.c
crypto/bio/bss_dgram.c
ssl/d1_lib.c

index 5e36e7e..dd4aa92 100644 (file)
@@ -737,14 +737,9 @@ int generate_cookie_callback(SSL *ssl, unsigned char *cookie,
                              unsigned int *cookie_len)
 {
     unsigned char *buffer;
-    unsigned int length;
-    union {
-        struct sockaddr sa;
-        struct sockaddr_in s4;
-#if OPENSSL_USE_IPV6
-        struct sockaddr_in6 s6;
-#endif
-    } peer;
+    size_t length;
+    unsigned short port;
+    BIO_ADDR *peer = NULL;
 
     /* Initialize a random secret */
     if (!cookie_initialized) {
@@ -755,50 +750,31 @@ int generate_cookie_callback(SSL *ssl, unsigned char *cookie,
         cookie_initialized = 1;
     }
 
+    peer = BIO_ADDR_new();
+    if (peer == NULL) {
+        BIO_printf(bio_err, "memory full\n");
+        return 0;
+    }
+
     /* Read peer information */
-    (void)BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
+    (void)BIO_dgram_get_peer(SSL_get_rbio(ssl), peer);
 
     /* Create buffer with peer's address and port */
-    length = 0;
-    switch (peer.sa.sa_family) {
-    case AF_INET:
-        length += sizeof(struct in_addr);
-        length += sizeof(peer.s4.sin_port);
-        break;
-#if OPENSSL_USE_IPV6
-    case AF_INET6:
-        length += sizeof(struct in6_addr);
-        length += sizeof(peer.s6.sin6_port);
-        break;
-#endif
-    default:
-        OPENSSL_assert(0);
-        break;
-    }
+    BIO_ADDR_rawaddress(peer, NULL, &length);
+    OPENSSL_assert(length != 0);
+    port = BIO_ADDR_rawport(peer);
+    length += sizeof(port);
     buffer = app_malloc(length, "cookie generate buffer");
 
-    switch (peer.sa.sa_family) {
-    case AF_INET:
-        memcpy(buffer, &peer.s4.sin_port, sizeof(peer.s4.sin_port));
-        memcpy(buffer + sizeof(peer.s4.sin_port),
-               &peer.s4.sin_addr, sizeof(struct in_addr));
-        break;
-#if OPENSSL_USE_IPV6
-    case AF_INET6:
-        memcpy(buffer, &peer.s6.sin6_port, sizeof(peer.s6.sin6_port));
-        memcpy(buffer + sizeof(peer.s6.sin6_port),
-               &peer.s6.sin6_addr, sizeof(struct in6_addr));
-        break;
-#endif
-    default:
-        OPENSSL_assert(0);
-        break;
-    }
+    memcpy(buffer, &port, sizeof(port));
+    BIO_ADDR_rawaddress(peer, buffer + sizeof(port), NULL);
 
     /* Calculate HMAC of buffer using the secret */
     HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH,
          buffer, length, cookie, cookie_len);
+
     OPENSSL_free(buffer);
+    BIO_ADDR_free(peer);
 
     return 1;
 }
index 6467060..848ba1f 100644 (file)
@@ -2432,12 +2432,15 @@ static int init_ssl_connection(SSL *con)
     unsigned next_proto_neg_len;
 #endif
     unsigned char *exportedkeymat;
-#ifndef OPENSSL_NO_DTLS
-    struct sockaddr_storage client;
-#endif
 
 #ifndef OPENSSL_NO_DTLS
     if(dtlslisten) {
+        BIO_ADDR *client = NULL;
+
+        if ((client = BIO_ADDR_new()) == NULL) {
+            BIO_printf(bio_err, "ERROR - memory\n");
+            return 0;
+        }
         i = DTLSv1_listen(con, &client);
         if (i > 0) {
             BIO *wbio;
@@ -2448,11 +2451,12 @@ static int init_ssl_connection(SSL *con)
                 BIO_get_fd(wbio, &fd);
             }
 
-            if(!wbio || connect(fd, (struct sockaddr *)&client,
-                                sizeof(struct sockaddr_storage))) {
+            if(!wbio || BIO_connect(fd, client, 0) == 0) {
                 BIO_printf(bio_err, "ERROR - unable to connect\n");
+                BIO_ADDR_free(client);
                 return 0;
             }
+            BIO_ADDR_free(client);
             dtlslisten = 0;
             i = SSL_accept(con);
         }
index d8e1b94..a3d8a0c 100644 (file)
 
 #include <stdio.h>
 #include <errno.h>
-#define USE_SOCKETS
-#include "internal/cryptlib.h"
 
-#include <openssl/bio.h>
+#include "bio_lcl.h"
 #ifndef OPENSSL_NO_DGRAM
 
 # if !(defined(_WIN32) || defined(OPENSSL_SYS_VMS))
@@ -156,13 +154,7 @@ static BIO_METHOD methods_dgramp_sctp = {
 # endif
 
 typedef struct bio_dgram_data_st {
-    union {
-        struct sockaddr sa;
-        struct sockaddr_in sa_in;
-# if OPENSSL_USE_IPV6
-        struct sockaddr_in6 sa_in6;
-# endif
-    } peer;
+    BIO_ADDR peer;
     unsigned int connected;
     unsigned int _errno;
     unsigned int mtu;
@@ -179,13 +171,7 @@ typedef struct bio_dgram_sctp_save_message_st {
 } bio_dgram_sctp_save_message;
 
 typedef struct bio_dgram_sctp_data_st {
-    union {
-        struct sockaddr sa;
-        struct sockaddr_in sa_in;
-#  if OPENSSL_USE_IPV6
-        struct sockaddr_in6 sa_in6;
-#  endif
-    } peer;
+    BIO_ADDR peer;
     unsigned int connected;
     unsigned int _errno;
     unsigned int mtu;
@@ -369,40 +355,20 @@ static int dgram_read(BIO *b, char *out, int outl)
     bio_dgram_data *data = (bio_dgram_data *)b->ptr;
     int flags = 0;
 
-    struct {
-        /*
-         * See commentary in b_sock.c. <appro>
-         */
-        union {
-            size_t s;
-            int i;
-        } len;
-        union {
-            struct sockaddr sa;
-            struct sockaddr_in sa_in;
-# if OPENSSL_USE_IPV6
-            struct sockaddr_in6 sa_in6;
-# endif
-        } peer;
-    } sa;
-
-    sa.len.s = 0;
-    sa.len.i = sizeof(sa.peer);
+    BIO_ADDR peer;
+    socklen_t len = sizeof(peer);
 
     if (out != NULL) {
         clear_socket_error();
-        memset(&sa.peer, 0, sizeof(sa.peer));
+        memset(&peer, 0, sizeof(peer));
         dgram_adjust_rcv_timeout(b);
         if (data->peekmode)
             flags = MSG_PEEK;
-        ret = recvfrom(b->num, out, outl, flags, &sa.peer.sa, (void *)&sa.len);
-        if (sizeof(sa.len.i) != sizeof(sa.len.s) && sa.len.i == 0) {
-            OPENSSL_assert(sa.len.s <= sizeof(sa.peer));
-            sa.len.i = (int)sa.len.s;
-        }
+        ret = recvfrom(b->num, out, outl, flags,
+                       BIO_ADDR_sockaddr_noconst(&peer), &len);
 
         if (!data->connected && ret >= 0)
-            BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer);
+            BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &peer);
 
         BIO_clear_retry_flags(b);
         if (ret < 0) {
@@ -426,18 +392,14 @@ static int dgram_write(BIO *b, const char *in, int inl)
     if (data->connected)
         ret = writesocket(b->num, in, inl);
     else {
-        int peerlen = sizeof(data->peer);
+        int peerlen = BIO_ADDR_sockaddr_size(&data->peer);
 
-        if (data->peer.sa.sa_family == AF_INET)
-            peerlen = sizeof(data->peer.sa_in);
-# if OPENSSL_USE_IPV6
-        else if (data->peer.sa.sa_family == AF_INET6)
-            peerlen = sizeof(data->peer.sa_in6);
-# endif
 # if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK)
-        ret = sendto(b->num, (char *)in, inl, 0, &data->peer.sa, peerlen);
+        ret = sendto(b->num, (char *)in, inl, 0,
+                     BIO_ADDR_sockaddr(&data->peer), peerlen);
 # else
-        ret = sendto(b->num, in, inl, 0, &data->peer.sa, peerlen);
+        ret = sendto(b->num, in, inl, 0,
+                     BIO_ADDR_sockaddr(&data->peer), peerlen);
 # endif
     }
 
@@ -455,27 +417,31 @@ static long dgram_get_mtu_overhead(bio_dgram_data *data)
 {
     long ret;
 
-    switch (data->peer.sa.sa_family) {
+    switch (BIO_ADDR_family(&data->peer)) {
     case AF_INET:
         /*
          * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP
          */
         ret = 28;
         break;
-# if OPENSSL_USE_IPV6
+# ifdef AF_INET6
     case AF_INET6:
+        {
 #  ifdef IN6_IS_ADDR_V4MAPPED
-        if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr))
-            /*
-             * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP
-             */
-            ret = 28;
-        else
+            struct in6_addr tmp_addr;
+            if (BIO_ADDR_rawaddress(&data->peer, &tmp_addr, NULL)
+                && IN6_IS_ADDR_V4MAPPED(&tmp_addr))
+                /*
+                 * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP
+                 */
+                ret = 28;
+            else
 #  endif
             /*
              * Assume this is UDP - 40 bytes for IP, 8 bytes for UDP
              */
             ret = 48;
+        }
         break;
 # endif
     default:
@@ -490,20 +456,13 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
 {
     long ret = 1;
     int *ip;
-    struct sockaddr *to = NULL;
     bio_dgram_data *data = NULL;
     int sockopt_val = 0;
 # if defined(OPENSSL_SYS_LINUX) && (defined(IP_MTU_DISCOVER) || defined(IP_MTU))
     socklen_t sockopt_len;      /* assume that system supporting IP_MTU is
                                  * modern enough to define socklen_t */
     socklen_t addr_len;
-    union {
-        struct sockaddr sa;
-        struct sockaddr_in s4;
-#  if OPENSSL_USE_IPV6
-        struct sockaddr_in6 s6;
-#  endif
-    } addr;
+    BIO_ADDR addr;
 # endif
 
     data = (bio_dgram_data *)b->ptr;
@@ -546,20 +505,7 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
         ret = 1;
         break;
     case BIO_CTRL_DGRAM_CONNECT:
-        to = (struct sockaddr *)ptr;
-        switch (to->sa_family) {
-        case AF_INET:
-            memcpy(&data->peer, to, sizeof(data->peer.sa_in));
-            break;
-# if OPENSSL_USE_IPV6
-        case AF_INET6:
-            memcpy(&data->peer, to, sizeof(data->peer.sa_in6));
-            break;
-# endif
-        default:
-            memcpy(&data->peer, to, sizeof(data->peer.sa));
-            break;
-        }
+        BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr));
         break;
         /* (Linux)kernel sets DF bit on outgoing IP packets */
     case BIO_CTRL_DGRAM_MTU_DISCOVER:
@@ -644,18 +590,22 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
         break;
     case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
         ret = -dgram_get_mtu_overhead(data);
-        switch (data->peer.sa.sa_family) {
+        switch (BIO_ADDR_family(&data->peer)) {
         case AF_INET:
             ret += 576;
             break;
 # if OPENSSL_USE_IPV6
         case AF_INET6:
+            {
 #  ifdef IN6_IS_ADDR_V4MAPPED
-            if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr))
-                ret += 576;
-            else
+                struct in6_addr tmp_addr;
+                if (BIO_ADDR_rawaddress(&data->peer, &tmp_addr, NULL)
+                    && IN6_IS_ADDR_V4MAPPED(&tmp_addr))
+                    ret += 576;
+                else
 #  endif
-                ret += 1280;
+                    ret += 1280;
+            }
             break;
 # endif
         default:
@@ -670,61 +620,24 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
         ret = num;
         break;
     case BIO_CTRL_DGRAM_SET_CONNECTED:
-        to = (struct sockaddr *)ptr;
-
-        if (to != NULL) {
+        if (ptr != NULL) {
             data->connected = 1;
-            switch (to->sa_family) {
-            case AF_INET:
-                memcpy(&data->peer, to, sizeof(data->peer.sa_in));
-                break;
-# if OPENSSL_USE_IPV6
-            case AF_INET6:
-                memcpy(&data->peer, to, sizeof(data->peer.sa_in6));
-                break;
-# endif
-            default:
-                memcpy(&data->peer, to, sizeof(data->peer.sa));
-                break;
-            }
+            BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr));
         } else {
             data->connected = 0;
             memset(&data->peer, 0, sizeof(data->peer));
         }
         break;
     case BIO_CTRL_DGRAM_GET_PEER:
-        switch (data->peer.sa.sa_family) {
-        case AF_INET:
-            ret = sizeof(data->peer.sa_in);
-            break;
-# if OPENSSL_USE_IPV6
-        case AF_INET6:
-            ret = sizeof(data->peer.sa_in6);
-            break;
-# endif
-        default:
-            ret = sizeof(data->peer.sa);
-            break;
-        }
+        ret = BIO_ADDR_sockaddr_size(&data->peer);
+        /* FIXME: if num < ret, we will only return part of an address.
+           That should bee an error, no? */
         if (num == 0 || num > ret)
             num = ret;
         memcpy(ptr, &data->peer, (ret = num));
         break;
     case BIO_CTRL_DGRAM_SET_PEER:
-        to = (struct sockaddr *)ptr;
-        switch (to->sa_family) {
-        case AF_INET:
-            memcpy(&data->peer, to, sizeof(data->peer.sa_in));
-            break;
-# if OPENSSL_USE_IPV6
-        case AF_INET6:
-            memcpy(&data->peer, to, sizeof(data->peer.sa_in6));
-            break;
-# endif
-        default:
-            memcpy(&data->peer, to, sizeof(data->peer.sa));
-            break;
-        }
+        BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr));
         break;
     case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
         memcpy(&(data->next_timeout), ptr, sizeof(struct timeval));
index 65e30f7..3fde524 100644 (file)
@@ -75,7 +75,7 @@
 static void get_current_time(struct timeval *t);
 static int dtls1_set_handshake_header(SSL *s, int type, unsigned long len);
 static int dtls1_handshake_write(SSL *s);
-int dtls1_listen(SSL *s, struct sockaddr *client);
+int dtls1_listen(SSL *s, BIO_ADDR *client);
 static unsigned int dtls1_link_min_mtu(void);
 
 /* XDTLS:  figure out the right values */
@@ -484,7 +484,7 @@ static void get_current_time(struct timeval *t)
 #define LISTEN_SEND_VERIFY_REQUEST  1
 
 
-int dtls1_listen(SSL *s, struct sockaddr *client)
+int dtls1_listen(SSL *s, BIO_ADDR *client)
 {
     int next, n, ret = 0, clearpkt = 0;
     unsigned char cookie[DTLS1_COOKIE_LENGTH];
@@ -495,7 +495,7 @@ int dtls1_listen(SSL *s, struct sockaddr *client)
     unsigned int rectype, versmajor, msgseq, msgtype, clientvers, cookielen;
     BIO *rbio, *wbio;
     BUF_MEM *bufm;
-    struct sockaddr_storage tmpclient;
+    BIO_ADDR *tmpclient = NULL;
     PACKET pkt, msgpkt, msgpayload, session, cookiepkt;
 
     /* Ensure there is no state left over from a previous invocation */
@@ -805,11 +805,14 @@ int dtls1_listen(SSL *s, struct sockaddr *client)
              * This is unneccessary if rbio and wbio are one and the same - but
              * maybe they're not.
              */
-            if(BIO_dgram_get_peer(rbio, &tmpclient) <= 0
-               || BIO_dgram_set_peer(wbio, &tmpclient) <= 0) {
+            if ((tmpclient = BIO_ADDR_new()) == NULL
+                || BIO_dgram_get_peer(rbio, tmpclient) <= 0
+                || BIO_dgram_set_peer(wbio, tmpclient) <= 0) {
                 SSLerr(SSL_F_DTLS1_LISTEN, ERR_R_INTERNAL_ERROR);
                 goto end;
             }
+            BIO_ADDR_free(tmpclient);
+            tmpclient = NULL;
 
             if (BIO_write(wbio, buf, reclen) < (int)reclen) {
                 if(BIO_should_retry(wbio)) {
@@ -863,6 +866,7 @@ int dtls1_listen(SSL *s, struct sockaddr *client)
     ret = 1;
     clearpkt = 0;
 end:
+    BIO_ADDR_free(tmpclient);
     BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL);
     if (clearpkt) {
         /* Dump this packet. Ignore return value */