X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=apps%2Fs_socket.c;h=74cf8d28e2cc368ce53b98eb6ef75b1c820de9f5;hp=20c662664da4746ca5cf2a27fc11bd33db7f3e42;hb=48e5119a6b83fd5781174d3b524cb8d1dc411649;hpb=968d1a23726dbca82ac694a508efe8ea37d0a95e diff --git a/apps/s_socket.c b/apps/s_socket.c index 20c662664d..74cf8d28e2 100644 --- a/apps/s_socket.c +++ b/apps/s_socket.c @@ -1,106 +1,10 @@ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * 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 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 acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS 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 AUTHOR OR 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. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ -/* ==================================================================== - * Copyright (c) 199-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 - * licensing@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/)" +/* + * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. * - * 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. - * ==================================================================== + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html */ /* socket-related functions used by s_client and s_server */ @@ -109,6 +13,7 @@ #include #include #include +#include /* * With IPv6, it looks like Digital has mixed up the proper order of @@ -123,10 +28,9 @@ typedef unsigned int u_int; #ifndef OPENSSL_NO_SOCK -# define USE_SOCKETS # include "apps.h" -# undef USE_SOCKETS # include "s_apps.h" +# include "internal/sockets.h" # include # include @@ -139,6 +43,7 @@ typedef unsigned int u_int; * @family: desired socket family, may be AF_INET, AF_INET6, AF_UNIX or * AF_UNSPEC * @type: socket type, must be SOCK_STREAM or SOCK_DGRAM + * @protocol: socket protocol, e.g. IPPROTO_TCP or IPPROTO_UDP (or 0 for any) * * This will create a socket and use it to connect to a host:port, or if * family == AF_UNIX, to the path found in host. @@ -150,16 +55,17 @@ typedef unsigned int u_int; * Returns 1 on success, 0 on failure. */ int init_client(int *sock, const char *host, const char *port, - int family, int type) + int family, int type, int protocol) { BIO_ADDRINFO *res = NULL; const BIO_ADDRINFO *ai = NULL; int ret; - if (!BIO_sock_init()) + if (BIO_sock_init() != 1) return 0; - ret = BIO_lookup(host, port, BIO_LOOKUP_CLIENT, family, type, &res); + ret = BIO_lookup_ex(host, port, BIO_LOOKUP_CLIENT, family, type, protocol, + &res); if (ret == 0) { ERR_print_errors(bio_err); return 0; @@ -167,25 +73,42 @@ int init_client(int *sock, const char *host, const char *port, ret = 0; for (ai = res; ai != NULL; ai = BIO_ADDRINFO_next(ai)) { - int protocol = (type == SOCK_STREAM ? IPPROTO_TCP : IPPROTO_UDP); -# ifdef AF_UNIX - if (BIO_ADDRINFO_family(ai) == AF_UNIX) - protocol = 0; -# endif - /* Admitedly, these checks are quite paranoid, we should - not get anything in the BIO_ADDRINFO chain that we haven't - asked for */ - OPENSSL_assert((family == AF_UNSPEC || family == BIO_ADDRINFO_family(res)) - && (type == 0 || type == BIO_ADDRINFO_socktype(res))); + /* Admittedly, these checks are quite paranoid, we should not get + * anything in the BIO_ADDRINFO chain that we haven't + * asked for. */ + OPENSSL_assert((family == AF_UNSPEC + || family == BIO_ADDRINFO_family(ai)) + && (type == 0 || type == BIO_ADDRINFO_socktype(ai)) + && (protocol == 0 + || protocol == BIO_ADDRINFO_protocol(ai))); *sock = BIO_socket(BIO_ADDRINFO_family(ai), BIO_ADDRINFO_socktype(ai), - protocol, 0); + BIO_ADDRINFO_protocol(ai), 0); if (*sock == INVALID_SOCKET) { /* Maybe the kernel doesn't support the socket family, even if * BIO_lookup() added it in the returned result... */ continue; } + +#ifndef OPENSSL_NO_SCTP + if (protocol == IPPROTO_SCTP) { + /* + * For SCTP we have to set various options on the socket prior to + * connecting. This is done automatically by BIO_new_dgram_sctp(). + * We don't actually need the created BIO though so we free it again + * immediately. + */ + BIO *tmpbio = BIO_new_dgram_sctp(*sock, BIO_NOCLOSE); + + if (tmpbio == NULL) { + ERR_print_errors(bio_err); + return 0; + } + BIO_free(tmpbio); + } +#endif + if (!BIO_connect(*sock, BIO_ADDRINFO_address(ai), 0)) { BIO_closesocket(*sock); *sock = INVALID_SOCKET; @@ -199,6 +122,8 @@ int init_client(int *sock, const char *host, const char *port, if (*sock == INVALID_SOCKET) { ERR_print_errors(bio_err); } else { + /* Remove any stale errors from previous connection attempts */ + ERR_clear_error(); ret = 1; } BIO_ADDRINFO_free(res); @@ -226,38 +151,32 @@ int init_client(int *sock, const char *host, const char *port, * 0 on failure, something other on success. */ int do_server(int *accept_sock, const char *host, const char *port, - int family, int type, - int (*cb) (const char *hostname, int s, int stype, - unsigned char *context), unsigned char *context, - int naccept) + int family, int type, int protocol, do_server_cb cb, + unsigned char *context, int naccept) { int asock = 0; int sock; int i; BIO_ADDRINFO *res = NULL; int ret = 0; - int protocol = (type == SOCK_STREAM ? IPPROTO_TCP : IPPROTO_UDP); - if (!BIO_sock_init()) + if (BIO_sock_init() != 1) return 0; - if (!BIO_lookup(host, port, BIO_LOOKUP_SERVER, family, type, &res)) { + if (!BIO_lookup_ex(host, port, BIO_LOOKUP_SERVER, family, type, protocol, + &res)) { ERR_print_errors(bio_err); return 0; } -# ifdef AF_UNIX - if (BIO_ADDRINFO_family(res) == AF_UNIX) - protocol = 0; -# endif - /* Admitedly, these checks are quite paranoid, we should - not get anything in the BIO_ADDRINFO chain that we haven't - asked for */ + /* Admittedly, these checks are quite paranoid, we should not get + * anything in the BIO_ADDRINFO chain that we haven't asked for */ OPENSSL_assert((family == AF_UNSPEC || family == BIO_ADDRINFO_family(res)) - && (type == 0 || type == BIO_ADDRINFO_socktype(res))); + && (type == 0 || type == BIO_ADDRINFO_socktype(res)) + && (protocol == 0 || protocol == BIO_ADDRINFO_protocol(res))); asock = BIO_socket(BIO_ADDRINFO_family(res), BIO_ADDRINFO_socktype(res), - protocol, 0); + BIO_ADDRINFO_protocol(res), 0); if (asock == INVALID_SOCKET || !BIO_listen(asock, BIO_ADDRINFO_address(res), BIO_SOCK_REUSEADDR)) { BIO_ADDRINFO_free(res); @@ -267,55 +186,75 @@ int do_server(int *accept_sock, const char *host, const char *port, goto end; } +#ifndef OPENSSL_NO_SCTP + if (protocol == IPPROTO_SCTP) { + /* + * For SCTP we have to set various options on the socket prior to + * accepting. This is done automatically by BIO_new_dgram_sctp(). + * We don't actually need the created BIO though so we free it again + * immediately. + */ + BIO *tmpbio = BIO_new_dgram_sctp(asock, BIO_NOCLOSE); + + if (tmpbio == NULL) { + BIO_closesocket(asock); + ERR_print_errors(bio_err); + goto end; + } + BIO_free(tmpbio); + } +#endif + BIO_ADDRINFO_free(res); + res = NULL; - if (accept_sock != NULL) { + if (accept_sock != NULL) *accept_sock = asock; - } for (;;) { - BIO_ADDR *accepted_addr = NULL; - char *name = NULL; if (type == SOCK_STREAM) { - if ((accepted_addr = BIO_ADDR_new()) == NULL) { - BIO_closesocket(asock); - return 0; - } - redoit: - sock = BIO_accept_ex(asock, accepted_addr, 0); + do { + sock = BIO_accept_ex(asock, NULL, 0); + } while (sock < 0 && BIO_sock_should_retry(sock)); if (sock < 0) { - if (BIO_sock_should_retry(ret)) { - goto redoit; - } else { - ERR_print_errors(bio_err); - BIO_ADDR_free(accepted_addr); - SHUTDOWN(asock); - break; - } + ERR_print_errors(bio_err); + BIO_closesocket(asock); + break; } - } else { - sock = asock; - } + i = (*cb)(sock, type, protocol, context); - /* accepted_addr is NULL if we're dealing with SOCK_DGRAM - * this means that for SOCK_DGRAM, name will be NULL - */ - if (accepted_addr != NULL) { -#ifdef AF_UNIX - if (family == AF_UNIX) - name = BIO_ADDR_path_string(accepted_addr); - else + /* + * Give the socket time to send its last data before we close it. + * No amount of setting SO_LINGER etc on the socket seems to + * persuade Windows to send the data before closing the socket... + * but sleeping for a short time seems to do it (units in ms) + * TODO: Find a better way to do this + */ +#if defined(OPENSSL_SYS_WINDOWS) + Sleep(50); +#elif defined(OPENSSL_SYS_CYGWIN) + usleep(50000); #endif - name = BIO_ADDR_hostname_string(accepted_addr, 0); + + /* + * If we ended with an alert being sent, but still with data in the + * network buffer to be read, then calling BIO_closesocket() will + * result in a TCP-RST being sent. On some platforms (notably + * Windows) then this will result in the peer immediately abandoning + * the connection including any buffered alert data before it has + * had a chance to be read. Shutting down the sending side first, + * and then closing the socket sends TCP-FIN first followed by + * TCP-RST. This seems to allow the peer to read the alert data. + */ + shutdown(sock, 1); /* SHUT_WR */ + BIO_closesocket(sock); + } else { + i = (*cb)(asock, type, protocol, context); } - i = (*cb) (name, sock, type, context); - OPENSSL_free(name); - BIO_ADDR_free(accepted_addr); - if (type == SOCK_STREAM) - SHUTDOWN2(sock); + if (naccept != -1) naccept--; if (i < 0 || naccept == 0) { - SHUTDOWN2(asock); + BIO_closesocket(asock); ret = i; break; }