Refactoring BIO: Adapt BIO_s_datagram and all that depends on it

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>
This commit is contained in:
Richard Levitte 2016-02-03 00:27:44 +01:00
parent 75d5bd4e7d
commit d858c87653
4 changed files with 79 additions and 182 deletions

View 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;
}

View 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);
}

View File

@ -58,10 +58,8 @@
#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));

View 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 */