diff options
author | Richard Levitte <levitte@openssl.org> | 2016-02-02 21:04:54 +0100 |
---|---|---|
committer | Richard Levitte <levitte@openssl.org> | 2016-02-03 19:38:07 +0100 |
commit | d33b215b331116e50947ca7e75d210e1db39b78d (patch) | |
tree | e6ff0dbddd1ad7a894aa69712f916b13991789d7 /crypto/bio | |
parent | 83be2778fe11ede4cd065a136c686fe664c212a2 (diff) | |
download | openssl-d33b215b331116e50947ca7e75d210e1db39b78d.zip openssl-d33b215b331116e50947ca7e75d210e1db39b78d.tar.gz openssl-d33b215b331116e50947ca7e75d210e1db39b78d.tar.bz2 |
Refactoring BIO: new socket-handling functions, deprecate older ones
Added functions:
BIO_socket
BIO_connect
BIO_listen
BIO_accept_ex
BIO_closesocket
BIO_sock_info
These get deprecated:
BIO_gethostbyname
BIO_get_port
BIO_get_host_ip
BIO_get_accept_socket
BIO_accept
Reviewed-by: Kurt Roeckx <kurt@openssl.org>
Diffstat (limited to 'crypto/bio')
-rw-r--r-- | crypto/bio/Makefile.in | 4 | ||||
-rw-r--r-- | crypto/bio/b_sock.c | 36 | ||||
-rw-r--r-- | crypto/bio/b_sock2.c | 307 |
3 files changed, 345 insertions, 2 deletions
diff --git a/crypto/bio/Makefile.in b/crypto/bio/Makefile.in index 9bcc17e..4ad411e 100644 --- a/crypto/bio/Makefile.in +++ b/crypto/bio/Makefile.in @@ -19,14 +19,14 @@ LIBSRC= bio_lib.c bio_cb.c bio_err.c \ bss_mem.c bss_null.c bss_fd.c \ bss_file.c bss_sock.c bss_conn.c \ bf_null.c bf_buff.c b_print.c b_dump.c b_addr.c \ - b_sock.c bss_acpt.c bf_nbio.c bss_log.c bss_bio.c \ + b_sock.c b_sock2.c bss_acpt.c bf_nbio.c bss_log.c bss_bio.c \ bss_dgram.c # bf_lbuf.c LIBOBJ= bio_lib.o bio_cb.o bio_err.o \ bss_mem.o bss_null.o bss_fd.o \ bss_file.o bss_sock.o bss_conn.o \ bf_null.o bf_buff.o b_print.o b_dump.o b_addr.o \ - b_sock.o bss_acpt.o bf_nbio.o bss_log.o bss_bio.o \ + b_sock.o b_sock2.o bss_acpt.o bf_nbio.o bss_log.o bss_bio.o \ bss_dgram.o # bf_lbuf.o diff --git a/crypto/bio/b_sock.c b/crypto/bio/b_sock.c index 5a50251..af40454 100644 --- a/crypto/bio/b_sock.c +++ b/crypto/bio/b_sock.c @@ -88,6 +88,7 @@ static int wsa_init_done = 0; # define WSAAPI # endif +# if OPENSSL_API_COMPAT < 0x10100000L static int get_ip(const char *str, unsigned char *ip); int BIO_get_host_ip(const char *str, unsigned char *ip) { @@ -194,6 +195,7 @@ int BIO_get_port(const char *str, unsigned short *port_ptr) } return (1); } +# endif int BIO_sock_error(int sock) { @@ -218,6 +220,7 @@ int BIO_sock_error(int sock) return (j); } +# if OPENSSL_API_COMPAT < 0x10100000L struct hostent *BIO_gethostbyname(const char *name) { /* @@ -230,6 +233,7 @@ struct hostent *BIO_gethostbyname(const char *name) return gethostbyname(name); # endif } +# endif int BIO_sock_init(void) { @@ -338,6 +342,7 @@ int BIO_socket_ioctl(int fd, long type, void *arg) } # endif /* __VMS_VER */ +# if OPENSSL_API_COMPAT < 0x10100000L /* * The reason I have implemented this instead of using sscanf is because * Visual C 1.52c gives an unresolved external when linking a DLL :-( @@ -697,6 +702,7 @@ int BIO_accept(int sock, char **addr) end: return (ret); } +# endif int BIO_set_tcp_ndelay(int s, int on) { @@ -728,4 +734,34 @@ int BIO_socket_nbio(int s, int mode) # endif return (ret == 0); } + +int BIO_sock_info(int sock, + enum BIO_sock_info_type type, union BIO_sock_info_u *info) +{ + switch (type) { + case BIO_SOCK_INFO_ADDRESS: + { + socklen_t addr_len; + int ret = 0; + addr_len = sizeof(*info->addr); + ret = getsockname(sock, BIO_ADDR_sockaddr_noconst(info->addr), + &addr_len); + if (ret == -1) { + SYSerr(SYS_F_GETSOCKNAME, get_last_socket_error()); + BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_GETSOCKNAME_ERROR); + return 0; + } + if (addr_len > sizeof(*info->addr)) { + BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS); + return 0; + } + } + break; + default: + BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_UNKNOWN_INFO_TYPE); + return 0; + } + return 1; +} + #endif diff --git a/crypto/bio/b_sock2.c b/crypto/bio/b_sock2.c new file mode 100644 index 0000000..4bf5cf3 --- /dev/null +++ b/crypto/bio/b_sock2.c @@ -0,0 +1,307 @@ +/* ==================================================================== + * Copyright (c) 2015 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#include "bio_lcl.h" + +#include <openssl/err.h> + +#ifndef OPENSSL_NO_SOCK +# ifdef SO_MAXCONN +# define MAX_LISTEN SO_MAXCONN +# elif defined(SOMAXCONN) +# define MAX_LISTEN SOMAXCONN +# else +# define MAX_LISTEN 32 +# endif + +/*- + * BIO_socket - create a socket + * @domain: the socket domain (AF_INET, AF_INET6, AF_UNIX, ...) + * @socktype: the socket type (SOCK_STEAM, SOCK_DGRAM) + * @protocol: the protocol to use (IPPROTO_TCP, IPPROTO_UDP) + * @options: BIO socket options (currently unused) + * + * Creates a socket. This should be called before calling any + * of BIO_connect and BIO_listen. + * + * Returns the file descriptor on success or INVALID_SOCKET on failure. On + * failure errno is set, and a status is added to the OpenSSL error stack. + */ +int BIO_socket(int domain, int socktype, int protocol, int options) +{ + int sock = -1; + + if (BIO_sock_init() != 1) + return INVALID_SOCKET; + + sock = socket(domain, socktype, protocol); + if (sock == -1) { + SYSerr(SYS_F_SOCKET, get_last_socket_error()); + BIOerr(BIO_F_BIO_SOCKET, BIO_R_UNABLE_TO_CREATE_SOCKET); + return INVALID_SOCKET; + } + + return sock; +} + +/*- + * BIO_connect - connect to an address + * @sock: the socket to connect with + * @addr: the address to connect to + * @options: BIO socket options + * + * Connects to the address using the given socket and options. + * + * Options can be a combination of the following: + * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages. + * - BIO_SOCK_NONBLOCK: Make the socket non-blocking. + * - BIO_SOCK_NODELAY: don't delay small messages. + * + * options holds BIO socket options that can be used + * You should call this for every address returned by BIO_lookup + * until the connection is succesful. + * + * Returns 1 on success or 0 on failure. On failure errno is set + * and an error status is added to the OpenSSL error stack. + */ +int BIO_connect(int sock, const BIO_ADDR *addr, int options) +{ + int on = 1; + + if (sock == -1) { + BIOerr(BIO_F_BIO_CONNECT, BIO_R_INVALID_SOCKET); + return 0; + } + + if (!BIO_socket_nbio(sock, (options & BIO_SOCK_NONBLOCK) != 0)) + return 0; + + if (options & BIO_SOCK_KEEPALIVE) { + if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_KEEPALIVE); + return 0; + } + } + + if (options & BIO_SOCK_NODELAY) { + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_NODELAY); + return 0; + } + } + + if (connect(sock, BIO_ADDR_sockaddr(addr), + BIO_ADDR_sockaddr_size(addr)) == -1) { + SYSerr(SYS_F_CONNECT, get_last_socket_error()); + BIOerr(BIO_F_BIO_CONNECT, BIO_R_CONNECT_ERROR); + return 0; + } + return 1; +} + +/*- + * BIO_listen - Creates a listen socket + * @sock: the socket to listen with + * @addr: local address to bind to + * @options: BIO socket options + * + * Binds to the address using the given socket and options, then + * starts listening for incoming connections. + * + * Options can be a combination of the following: + * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages. + * - BIO_SOCK_NONBLOCK: Make the socket non-blocking. + * - BIO_SOCK_NODELAY: don't delay small messages. + * - BIO_SOCK_REUSEADDR: Try to reuse the address and port combination + * for a recently closed port. + * - BIO_SOCK_V6_ONLY: When creating an IPv6 socket, make it listen only + * for IPv6 addresses and not IPv4 addresses mapped to IPv6. + * + * It's recommended that you set up both an IPv6 and IPv4 listen socket, and + * then check both for new clients that connect to it. You want to set up + * the socket as non-blocking in that case since else it could hang. + * + * Not all operating systems support IPv4 addresses on an IPv6 socket, and for + * others it's an option. If you pass the BIO_LISTEN_V6_ONLY it will try to + * create the IPv6 sockets to only listen for IPv6 connection. + * + * It could be that the first BIO_listen() call will listen to all the IPv6 + * and IPv4 addresses and that then trying to bind to the IPv4 address will + * fail. We can't tell the difference between already listening ourself to + * it and someone else listening to it when failing and errno is EADDRINUSE, so + * it's recommended to not give an error in that case if the first call was + * succesful. + * + * When restarting the program it could be that the port is still in use. If + * you set to BIO_SOCK_REUSEADDR option it will try to reuse the port anyway. + * It's recommended that you use this. + */ +int BIO_listen(int sock, const BIO_ADDR *addr, int options) +{ + int on = 1; + int socktype; + socklen_t socktype_len = sizeof(socktype); + + if (sock == -1) { + BIOerr(BIO_F_BIO_LISTEN, BIO_R_INVALID_SOCKET); + return 0; + } + + if (getsockopt(sock, SOL_SOCKET, SO_TYPE, &socktype, &socktype_len) != 0 + || socktype_len != sizeof(socktype)) { + SYSerr(SYS_F_GETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_GETTING_SOCKTYPE); + return 0; + } + + if (!BIO_socket_nbio(sock, (options & BIO_SOCK_NONBLOCK) != 0)) + return 0; + +# ifndef OPENSSL_SYS_WINDOWS + /* SO_REUSEADDR has different behavior on Windows than on + * other operating systems, don't set it there. */ + if (options & BIO_SOCK_REUSEADDR) { + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_REUSEADDR); + return 0; + } + } +# endif + + if (options & BIO_SOCK_KEEPALIVE) { + if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_KEEPALIVE); + return 0; + } + } + + if (options & BIO_SOCK_NODELAY) { + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_NODELAY); + return 0; + } + } + +# ifdef IPV6_V6ONLY + if ((options & BIO_SOCK_V6_ONLY) && BIO_ADDR_family(addr) == AF_INET6) { + if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_LISTEN_V6_ONLY); + return 0; + } + } +# endif + + if (bind(sock, BIO_ADDR_sockaddr(addr), BIO_ADDR_sockaddr_size(addr)) != 0) { + SYSerr(SYS_F_BIND, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_BIND_SOCKET); + return 0; + } + + if (socktype != SOCK_DGRAM && listen(sock, MAX_LISTEN) == -1) { + SYSerr(SYS_F_LISTEN, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_LISTEN_SOCKET); + return 0; + } + + return 1; +} + +/*- + * BIO_accept_ex - Accept new incoming connections + * @sock: the listening socket + * @addr: the BIO_ADDR to store the peer address in + * @options: BIO socket options, applied on the accepted socket. + * + */ +int BIO_accept_ex(int accept_sock, BIO_ADDR *addr, int options) +{ + socklen_t len; + int accepted_sock; + + len = sizeof(*addr); + accepted_sock = accept(accept_sock, + BIO_ADDR_sockaddr_noconst(addr), &len); + if (accepted_sock == -1) { + SYSerr(SYS_F_ACCEPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_ACCEPT_EX, BIO_R_ACCEPT_ERROR); + return INVALID_SOCKET; + } + + if (!BIO_socket_nbio(accepted_sock, (options & BIO_SOCK_NONBLOCK) != 0)) + return INVALID_SOCKET; + + return accepted_sock; +} + +/*- + * BIO_closesocket - Close a socket + * @sock: the socket to close + */ +int BIO_closesocket(int sock) +{ + if (closesocket(sock) < 0) + return 0; + return 1; +} +#endif |