Path: blob/main/crypto/openssl/apps/lib/s_socket.c
34869 views
/*1* Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89/* socket-related functions used by s_client and s_server */10#include <stdio.h>11#include <stdlib.h>12#include <string.h>13#include <errno.h>14#include <signal.h>15#include <openssl/opensslconf.h>1617/*18* With IPv6, it looks like Digital has mixed up the proper order of19* recursive header file inclusion, resulting in the compiler complaining20* that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which is21* needed to have fileno() declared correctly... So let's define u_int22*/23#if defined(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT)24# define __U_INT25typedef unsigned int u_int;26#endif2728#ifdef _WIN3229# include <process.h>3031/* MSVC renamed some POSIX functions to have an underscore prefix. */32# ifdef _MSC_VER33# define getpid _getpid34# endif35#endif3637#ifndef OPENSSL_NO_SOCK3839# include "internal/e_os.h"40# include "apps.h"41# include "s_apps.h"42# include "internal/sockets.h" /* for openssl_fdset() */4344# include <openssl/bio.h>45# include <openssl/err.h>4647/* Keep track of our peer's address for the cookie callback */48BIO_ADDR *ourpeer = NULL;4950/*51* init_client - helper routine to set up socket communication52* @sock: pointer to storage of resulting socket.53* @host: the hostname or path (for AF_UNIX) to connect to.54* @port: the port to connect to (ignored for AF_UNIX).55* @bindhost: source host or path (for AF_UNIX).56* @bindport: source port (ignored for AF_UNIX).57* @family: desired socket family, may be AF_INET, AF_INET6, AF_UNIX or58* AF_UNSPEC59* @type: socket type, must be SOCK_STREAM or SOCK_DGRAM60* @protocol: socket protocol, e.g. IPPROTO_TCP or IPPROTO_UDP (or 0 for any)61* @tfo: flag to enable TCP Fast Open62* @doconn: whether we should call BIO_connect() on the socket63* @ba_ret: BIO_ADDR for the remote peer, to be freed by caller64*65* This will create a socket and use it to connect to a host:port, or if66* family == AF_UNIX, to the path found in host.67*68* If the host has more than one address, it will try them one by one until69* a successful connection is established. The resulting socket will be70* found in *sock on success, it will be given INVALID_SOCKET otherwise.71*72* Returns 1 on success, 0 on failure.73*/74int init_client(int *sock, const char *host, const char *port,75const char *bindhost, const char *bindport,76int family, int type, int protocol, int tfo, int doconn,77BIO_ADDR **ba_ret)78{79BIO_ADDRINFO *res = NULL;80BIO_ADDRINFO *bindaddr = NULL;81const BIO_ADDRINFO *ai = NULL;82const BIO_ADDRINFO *bi = NULL;83int found = 0;84int ret;85int options = 0;8687if (BIO_sock_init() != 1)88return 0;8990ret = BIO_lookup_ex(host, port, BIO_LOOKUP_CLIENT, family, type, protocol,91&res);92if (ret == 0) {93ERR_print_errors(bio_err);94return 0;95}9697if (bindhost != NULL || bindport != NULL) {98ret = BIO_lookup_ex(bindhost, bindport, BIO_LOOKUP_CLIENT,99family, type, protocol, &bindaddr);100if (ret == 0) {101ERR_print_errors (bio_err);102goto out;103}104}105106ret = 0;107for (ai = res; ai != NULL; ai = BIO_ADDRINFO_next(ai)) {108/* Admittedly, these checks are quite paranoid, we should not get109* anything in the BIO_ADDRINFO chain that we haven't110* asked for. */111OPENSSL_assert((family == AF_UNSPEC112|| family == BIO_ADDRINFO_family(ai))113&& (type == 0 || type == BIO_ADDRINFO_socktype(ai))114&& (protocol == 0115|| protocol == BIO_ADDRINFO_protocol(ai)));116117if (bindaddr != NULL) {118for (bi = bindaddr; bi != NULL; bi = BIO_ADDRINFO_next(bi)) {119if (BIO_ADDRINFO_family(bi) == BIO_ADDRINFO_family(ai))120break;121}122if (bi == NULL)123continue;124++found;125}126127*sock = BIO_socket(BIO_ADDRINFO_family(ai), BIO_ADDRINFO_socktype(ai),128BIO_ADDRINFO_protocol(ai), 0);129if (*sock == INVALID_SOCKET) {130/* Maybe the kernel doesn't support the socket family, even if131* BIO_lookup() added it in the returned result...132*/133continue;134}135136if (bi != NULL) {137if (!BIO_bind(*sock, BIO_ADDRINFO_address(bi),138BIO_SOCK_REUSEADDR)) {139BIO_closesocket(*sock);140*sock = INVALID_SOCKET;141break;142}143}144145#ifndef OPENSSL_NO_SCTP146if (protocol == IPPROTO_SCTP) {147/*148* For SCTP we have to set various options on the socket prior to149* connecting. This is done automatically by BIO_new_dgram_sctp().150* We don't actually need the created BIO though so we free it again151* immediately.152*/153BIO *tmpbio = BIO_new_dgram_sctp(*sock, BIO_NOCLOSE);154155if (tmpbio == NULL) {156ERR_print_errors(bio_err);157return 0;158}159BIO_free(tmpbio);160}161#endif162if (BIO_ADDRINFO_protocol(ai) == IPPROTO_TCP) {163options |= BIO_SOCK_NODELAY;164if (tfo)165options |= BIO_SOCK_TFO;166}167168if (doconn && !BIO_connect(*sock, BIO_ADDRINFO_address(ai), options)) {169BIO_closesocket(*sock);170*sock = INVALID_SOCKET;171continue;172}173174/* Save the address */175if (tfo || !doconn) {176if (ba_ret == NULL) {177BIO_printf(bio_err, "Internal error\n");178BIO_closesocket(*sock);179*sock = INVALID_SOCKET;180goto out;181}182183*ba_ret = BIO_ADDR_dup(BIO_ADDRINFO_address(ai));184}185186/* Success, don't try any more addresses */187break;188}189190if (*sock == INVALID_SOCKET) {191if (bindaddr != NULL && !found) {192BIO_printf(bio_err, "Can't bind %saddress for %s%s%s\n",193#ifdef AF_INET6194BIO_ADDRINFO_family(res) == AF_INET6 ? "IPv6 " :195#endif196BIO_ADDRINFO_family(res) == AF_INET ? "IPv4 " :197BIO_ADDRINFO_family(res) == AF_UNIX ? "unix " : "",198bindhost != NULL ? bindhost : "",199bindport != NULL ? ":" : "",200bindport != NULL ? bindport : "");201ERR_clear_error();202ret = 0;203}204ERR_print_errors(bio_err);205} else {206char *hostname = NULL;207208hostname = BIO_ADDR_hostname_string(BIO_ADDRINFO_address(ai), 1);209if (hostname != NULL) {210BIO_printf(bio_err, "Connecting to %s\n", hostname);211OPENSSL_free(hostname);212}213/* Remove any stale errors from previous connection attempts */214ERR_clear_error();215ret = 1;216}217out:218if (bindaddr != NULL) {219BIO_ADDRINFO_free (bindaddr);220}221BIO_ADDRINFO_free(res);222return ret;223}224225void get_sock_info_address(int asock, char **hostname, char **service)226{227union BIO_sock_info_u info;228229if (hostname != NULL)230*hostname = NULL;231if (service != NULL)232*service = NULL;233234if ((info.addr = BIO_ADDR_new()) != NULL235&& BIO_sock_info(asock, BIO_SOCK_INFO_ADDRESS, &info)) {236if (hostname != NULL)237*hostname = BIO_ADDR_hostname_string(info.addr, 1);238if (service != NULL)239*service = BIO_ADDR_service_string(info.addr, 1);240}241BIO_ADDR_free(info.addr);242}243244int report_server_accept(BIO *out, int asock, int with_address, int with_pid)245{246int success = 1;247248if (BIO_printf(out, "ACCEPT") <= 0)249return 0;250if (with_address) {251char *hostname, *service;252253get_sock_info_address(asock, &hostname, &service);254success = hostname != NULL && service != NULL;255if (success)256success = BIO_printf(out,257strchr(hostname, ':') == NULL258? /* IPv4 */ " %s:%s"259: /* IPv6 */ " [%s]:%s",260hostname, service) > 0;261else262(void)BIO_printf(out, "unknown:error\n");263OPENSSL_free(hostname);264OPENSSL_free(service);265}266if (with_pid)267success *= BIO_printf(out, " PID=%d", getpid()) > 0;268success *= BIO_printf(out, "\n") > 0;269(void)BIO_flush(out);270271return success;272}273274/*275* do_server - helper routine to perform a server operation276* @accept_sock: pointer to storage of resulting socket.277* @host: the hostname or path (for AF_UNIX) to connect to.278* @port: the port to connect to (ignored for AF_UNIX).279* @family: desired socket family, may be AF_INET, AF_INET6, AF_UNIX or280* AF_UNSPEC281* @type: socket type, must be SOCK_STREAM or SOCK_DGRAM282* @cb: pointer to a function that receives the accepted socket and283* should perform the communication with the connecting client.284* @context: pointer to memory that's passed verbatim to the cb function.285* @naccept: number of times an incoming connect should be accepted. If -1,286* unlimited number.287*288* This will create a socket and use it to listen to a host:port, or if289* family == AF_UNIX, to the path found in host, then start accepting290* incoming connections and run cb on the resulting socket.291*292* 0 on failure, something other on success.293*/294int do_server(int *accept_sock, const char *host, const char *port,295int family, int type, int protocol, do_server_cb cb,296unsigned char *context, int naccept, BIO *bio_s_out,297int tfo)298{299int asock = 0;300int sock;301int i;302BIO_ADDRINFO *res = NULL;303const BIO_ADDRINFO *next;304int sock_family, sock_type, sock_protocol, sock_port;305const BIO_ADDR *sock_address;306int sock_family_fallback = AF_UNSPEC;307const BIO_ADDR *sock_address_fallback = NULL;308int sock_options = BIO_SOCK_REUSEADDR;309int ret = 0;310311if (BIO_sock_init() != 1)312return 0;313314if (!BIO_lookup_ex(host, port, BIO_LOOKUP_SERVER, family, type, protocol,315&res)) {316ERR_print_errors(bio_err);317return 0;318}319320/* Admittedly, these checks are quite paranoid, we should not get321* anything in the BIO_ADDRINFO chain that we haven't asked for */322OPENSSL_assert((family == AF_UNSPEC || family == BIO_ADDRINFO_family(res))323&& (type == 0 || type == BIO_ADDRINFO_socktype(res))324&& (protocol == 0 || protocol == BIO_ADDRINFO_protocol(res)));325326sock_family = BIO_ADDRINFO_family(res);327sock_type = BIO_ADDRINFO_socktype(res);328sock_protocol = BIO_ADDRINFO_protocol(res);329sock_address = BIO_ADDRINFO_address(res);330next = BIO_ADDRINFO_next(res);331if (tfo && sock_type == SOCK_STREAM)332sock_options |= BIO_SOCK_TFO;333#ifdef AF_INET6334if (sock_family == AF_INET6)335sock_options |= BIO_SOCK_V6_ONLY;336if (next != NULL337&& BIO_ADDRINFO_socktype(next) == sock_type338&& BIO_ADDRINFO_protocol(next) == sock_protocol) {339if (sock_family == AF_INET340&& BIO_ADDRINFO_family(next) == AF_INET6) {341/* In case AF_INET6 is returned but not supported by the342* kernel, retry with the first detected address family */343sock_family_fallback = sock_family;344sock_address_fallback = sock_address;345sock_family = AF_INET6;346sock_address = BIO_ADDRINFO_address(next);347} else if (sock_family == AF_INET6348&& BIO_ADDRINFO_family(next) == AF_INET) {349sock_options &= ~BIO_SOCK_V6_ONLY;350}351}352#endif353354asock = BIO_socket(sock_family, sock_type, sock_protocol, 0);355if (asock == INVALID_SOCKET && sock_family_fallback != AF_UNSPEC) {356asock = BIO_socket(sock_family_fallback, sock_type, sock_protocol, 0);357sock_address = sock_address_fallback;358}359if (asock == INVALID_SOCKET360|| !BIO_listen(asock, sock_address, sock_options)) {361BIO_ADDRINFO_free(res);362ERR_print_errors(bio_err);363if (asock != INVALID_SOCKET)364BIO_closesocket(asock);365goto end;366}367368#ifndef OPENSSL_NO_SCTP369if (protocol == IPPROTO_SCTP) {370/*371* For SCTP we have to set various options on the socket prior to372* accepting. This is done automatically by BIO_new_dgram_sctp().373* We don't actually need the created BIO though so we free it again374* immediately.375*/376BIO *tmpbio = BIO_new_dgram_sctp(asock, BIO_NOCLOSE);377378if (tmpbio == NULL) {379BIO_closesocket(asock);380ERR_print_errors(bio_err);381goto end;382}383BIO_free(tmpbio);384}385#endif386387sock_port = BIO_ADDR_rawport(sock_address);388389BIO_ADDRINFO_free(res);390res = NULL;391392if (!report_server_accept(bio_s_out, asock, sock_port == 0, 0)) {393BIO_closesocket(asock);394ERR_print_errors(bio_err);395goto end;396}397398if (accept_sock != NULL)399*accept_sock = asock;400for (;;) {401char sink[64];402struct timeval timeout;403fd_set readfds;404405if (type == SOCK_STREAM) {406BIO_ADDR_free(ourpeer);407ourpeer = BIO_ADDR_new();408if (ourpeer == NULL) {409BIO_closesocket(asock);410ERR_print_errors(bio_err);411goto end;412}413do {414sock = BIO_accept_ex(asock, ourpeer, 0);415} while (sock < 0 && BIO_sock_should_retry(sock));416if (sock < 0) {417ERR_print_errors(bio_err);418BIO_closesocket(asock);419break;420}421422if (naccept != -1)423naccept--;424if (naccept == 0)425BIO_closesocket(asock);426427BIO_set_tcp_ndelay(sock, 1);428i = (*cb)(sock, type, protocol, context);429430/*431* If we ended with an alert being sent, but still with data in the432* network buffer to be read, then calling BIO_closesocket() will433* result in a TCP-RST being sent. On some platforms (notably434* Windows) then this will result in the peer immediately abandoning435* the connection including any buffered alert data before it has436* had a chance to be read. Shutting down the sending side first,437* and then closing the socket sends TCP-FIN first followed by438* TCP-RST. This seems to allow the peer to read the alert data.439*/440shutdown(sock, 1); /* SHUT_WR */441/*442* We just said we have nothing else to say, but it doesn't mean443* that the other side has nothing. It's even recommended to444* consume incoming data. [In testing context this ensures that445* alerts are passed on...]446*/447timeout.tv_sec = 0;448timeout.tv_usec = 500000; /* some extreme round-trip */449do {450FD_ZERO(&readfds);451openssl_fdset(sock, &readfds);452} while (select(sock + 1, &readfds, NULL, NULL, &timeout) > 0453&& readsocket(sock, sink, sizeof(sink)) > 0);454455BIO_closesocket(sock);456} else {457if (naccept != -1)458naccept--;459460i = (*cb)(asock, type, protocol, context);461}462463if (i < 0 || naccept == 0) {464BIO_closesocket(asock);465ret = i;466break;467}468}469end:470# ifdef AF_UNIX471if (family == AF_UNIX)472unlink(host);473# endif474BIO_ADDR_free(ourpeer);475ourpeer = NULL;476return ret;477}478479void do_ssl_shutdown(SSL *ssl)480{481int ret;482483do {484/* We only do unidirectional shutdown */485ret = SSL_shutdown(ssl);486if (ret < 0) {487switch (SSL_get_error(ssl, ret)) {488case SSL_ERROR_WANT_READ:489case SSL_ERROR_WANT_WRITE:490case SSL_ERROR_WANT_ASYNC:491case SSL_ERROR_WANT_ASYNC_JOB:492/* We just do busy waiting. Nothing clever */493continue;494}495ret = 0;496}497} while (ret < 0);498}499500#endif /* OPENSSL_NO_SOCK */501502503