2016-05-17 18:18:30 +00:00
|
|
|
/*
|
2018-01-19 09:49:22 +00:00
|
|
|
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
|
1998-12-21 10:52:47 +00:00
|
|
|
*
|
2018-12-06 12:00:26 +00:00
|
|
|
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
2016-05-17 18:18:30 +00:00
|
|
|
* 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
|
Big apps cleanup (option-parsing, etc)
This is merges the old "rsalz-monolith" branch over to master. The biggest
change is that option parsing switch from cascasding 'else if strcmp("-foo")'
to a utility routine and somethin akin to getopt. Also, an error in the
command line no longer prints the full summary; use -help (or --help :)
for that. There have been many other changes and code-cleanup, see
bullet list below.
Special thanks to Matt for the long and detailed code review.
TEMPORARY:
For now, comment out CRYPTO_mem_leaks() at end of main
Tickets closed:
RT3515: Use 3DES in pkcs12 if built with no-rc2
RT1766: s_client -reconnect and -starttls broke
RT2932: Catch write errors
RT2604: port should be 'unsigned short'
RT2983: total_bytes undeclared #ifdef RENEG
RT1523: Add -nocert to fix output in x509 app
RT3508: Remove unused variable introduced by b09eb24
RT3511: doc fix; req default serial is random
RT1325,2973: Add more extensions to c_rehash
RT2119,3407: Updated to dgst.pod
RT2379: Additional typo fix
RT2693: Extra include of string.h
RT2880: HFS is case-insensitive filenames
RT3246: req command prints version number wrong
Other changes; incompatibilities marked with *:
Add SCSV support
Add -misalign to speed command
Make dhparam, dsaparam, ecparam, x509 output C in proper style
Make some internal ocsp.c functions void
Only display cert usages with -help in verify
Use global bio_err, remove "BIO*err" parameter from functions
For filenames, - always means stdin (or stdout as appropriate)
Add aliases for -des/aes "wrap" ciphers.
*Remove support for IISSGC (server gated crypto)
*The undocumented OCSP -header flag is now "-header name=value"
*Documented the OCSP -header flag
Reviewed-by: Matt Caswell <matt@openssl.org>
2015-04-24 19:26:15 +00:00
|
|
|
*/
|
1998-12-21 10:52:47 +00:00
|
|
|
|
Big apps cleanup (option-parsing, etc)
This is merges the old "rsalz-monolith" branch over to master. The biggest
change is that option parsing switch from cascasding 'else if strcmp("-foo")'
to a utility routine and somethin akin to getopt. Also, an error in the
command line no longer prints the full summary; use -help (or --help :)
for that. There have been many other changes and code-cleanup, see
bullet list below.
Special thanks to Matt for the long and detailed code review.
TEMPORARY:
For now, comment out CRYPTO_mem_leaks() at end of main
Tickets closed:
RT3515: Use 3DES in pkcs12 if built with no-rc2
RT1766: s_client -reconnect and -starttls broke
RT2932: Catch write errors
RT2604: port should be 'unsigned short'
RT2983: total_bytes undeclared #ifdef RENEG
RT1523: Add -nocert to fix output in x509 app
RT3508: Remove unused variable introduced by b09eb24
RT3511: doc fix; req default serial is random
RT1325,2973: Add more extensions to c_rehash
RT2119,3407: Updated to dgst.pod
RT2379: Additional typo fix
RT2693: Extra include of string.h
RT2880: HFS is case-insensitive filenames
RT3246: req command prints version number wrong
Other changes; incompatibilities marked with *:
Add SCSV support
Add -misalign to speed command
Make dhparam, dsaparam, ecparam, x509 output C in proper style
Make some internal ocsp.c functions void
Only display cert usages with -help in verify
Use global bio_err, remove "BIO*err" parameter from functions
For filenames, - always means stdin (or stdout as appropriate)
Add aliases for -des/aes "wrap" ciphers.
*Remove support for IISSGC (server gated crypto)
*The undocumented OCSP -header flag is now "-header name=value"
*Documented the OCSP -header flag
Reviewed-by: Matt Caswell <matt@openssl.org>
2015-04-24 19:26:15 +00:00
|
|
|
/* socket-related functions used by s_client and s_server */
|
1999-07-28 23:25:59 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <signal.h>
|
2016-03-21 15:32:40 +00:00
|
|
|
#include <openssl/opensslconf.h>
|
1999-07-28 23:25:59 +00:00
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
/*
|
|
|
|
* With IPv6, it looks like Digital has mixed up the proper order of
|
|
|
|
* recursive header file inclusion, resulting in the compiler complaining
|
|
|
|
* that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which is
|
|
|
|
* needed to have fileno() declared correctly... So let's define u_int
|
|
|
|
*/
|
2001-02-20 08:13:47 +00:00
|
|
|
#if defined(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT)
|
2015-01-22 03:40:55 +00:00
|
|
|
# define __U_INT
|
1999-05-13 11:37:32 +00:00
|
|
|
typedef unsigned int u_int;
|
|
|
|
#endif
|
|
|
|
|
2002-11-28 08:04:36 +00:00
|
|
|
#ifndef OPENSSL_NO_SOCK
|
|
|
|
|
2016-02-02 23:47:42 +00:00
|
|
|
# include "apps.h"
|
|
|
|
# include "s_apps.h"
|
2017-08-21 21:22:19 +00:00
|
|
|
# include "internal/sockets.h"
|
2005-06-13 03:23:50 +00:00
|
|
|
|
2016-02-02 23:47:42 +00:00
|
|
|
# include <openssl/bio.h>
|
|
|
|
# include <openssl/err.h>
|
2000-03-12 23:27:14 +00:00
|
|
|
|
2017-09-12 15:19:09 +00:00
|
|
|
/* Keep track of our peer's address for the cookie callback */
|
|
|
|
BIO_ADDR *ourpeer = NULL;
|
|
|
|
|
2016-02-02 23:47:42 +00:00
|
|
|
/*
|
|
|
|
* init_client - helper routine to set up socket communication
|
|
|
|
* @sock: pointer to storage of resulting socket.
|
|
|
|
* @host: the host name or path (for AF_UNIX) to connect to.
|
|
|
|
* @port: the port to connect to (ignored for AF_UNIX).
|
2018-02-08 09:49:02 +00:00
|
|
|
* @bindhost: source host or path (for AF_UNIX).
|
|
|
|
* @bindport: source port (ignored for AF_UNIX).
|
2016-02-02 23:47:42 +00:00
|
|
|
* @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
|
2017-04-20 08:57:12 +00:00
|
|
|
* @protocol: socket protocol, e.g. IPPROTO_TCP or IPPROTO_UDP (or 0 for any)
|
2016-02-02 23:47:42 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* If the host has more than one address, it will try them one by one until
|
|
|
|
* a successful connection is established. The resulting socket will be
|
|
|
|
* found in *sock on success, it will be given INVALID_SOCKET otherwise.
|
|
|
|
*
|
|
|
|
* Returns 1 on success, 0 on failure.
|
|
|
|
*/
|
|
|
|
int init_client(int *sock, const char *host, const char *port,
|
2018-02-08 09:49:02 +00:00
|
|
|
const char *bindhost, const char *bindport,
|
2017-04-20 08:57:12 +00:00
|
|
|
int family, int type, int protocol)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
2016-02-02 23:47:42 +00:00
|
|
|
BIO_ADDRINFO *res = NULL;
|
2018-02-08 09:49:02 +00:00
|
|
|
BIO_ADDRINFO *bindaddr = NULL;
|
2016-02-02 23:47:42 +00:00
|
|
|
const BIO_ADDRINFO *ai = NULL;
|
2018-02-08 09:49:02 +00:00
|
|
|
const BIO_ADDRINFO *bi = NULL;
|
|
|
|
int found = 0;
|
2016-02-02 23:47:42 +00:00
|
|
|
int ret;
|
2003-11-28 13:10:58 +00:00
|
|
|
|
2017-06-25 17:09:46 +00:00
|
|
|
if (BIO_sock_init() != 1)
|
2016-02-02 23:47:42 +00:00
|
|
|
return 0;
|
2015-01-22 03:40:55 +00:00
|
|
|
|
2017-04-20 08:57:12 +00:00
|
|
|
ret = BIO_lookup_ex(host, port, BIO_LOOKUP_CLIENT, family, type, protocol,
|
|
|
|
&res);
|
2016-02-02 23:47:42 +00:00
|
|
|
if (ret == 0) {
|
|
|
|
ERR_print_errors(bio_err);
|
|
|
|
return 0;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
|
|
|
|
2018-02-08 09:49:02 +00:00
|
|
|
if (bindhost != NULL || bindport != NULL) {
|
|
|
|
ret = BIO_lookup_ex(bindhost, bindport, BIO_LOOKUP_CLIENT,
|
|
|
|
family, type, protocol, &bindaddr);
|
|
|
|
if (ret == 0) {
|
|
|
|
ERR_print_errors (bio_err);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-02 23:47:42 +00:00
|
|
|
ret = 0;
|
|
|
|
for (ai = res; ai != NULL; ai = BIO_ADDRINFO_next(ai)) {
|
2016-02-24 15:59:14 +00:00
|
|
|
/* Admittedly, these checks are quite paranoid, we should not get
|
|
|
|
* anything in the BIO_ADDRINFO chain that we haven't
|
|
|
|
* asked for. */
|
2017-04-24 10:45:42 +00:00
|
|
|
OPENSSL_assert((family == AF_UNSPEC
|
|
|
|
|| family == BIO_ADDRINFO_family(ai))
|
|
|
|
&& (type == 0 || type == BIO_ADDRINFO_socktype(ai))
|
2017-04-20 08:57:12 +00:00
|
|
|
&& (protocol == 0
|
2017-04-24 10:45:42 +00:00
|
|
|
|| protocol == BIO_ADDRINFO_protocol(ai)));
|
2016-02-02 23:47:42 +00:00
|
|
|
|
2018-02-08 09:49:02 +00:00
|
|
|
if (bindaddr != NULL) {
|
|
|
|
for (bi = bindaddr; bi != NULL; bi = BIO_ADDRINFO_next(bi)) {
|
|
|
|
if (BIO_ADDRINFO_family(bi) == BIO_ADDRINFO_family(ai))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (bi == NULL)
|
|
|
|
continue;
|
|
|
|
++found;
|
|
|
|
}
|
|
|
|
|
2016-02-02 23:47:42 +00:00
|
|
|
*sock = BIO_socket(BIO_ADDRINFO_family(ai), BIO_ADDRINFO_socktype(ai),
|
2017-04-24 10:45:42 +00:00
|
|
|
BIO_ADDRINFO_protocol(ai), 0);
|
2016-02-02 23:47:42 +00:00
|
|
|
if (*sock == INVALID_SOCKET) {
|
|
|
|
/* Maybe the kernel doesn't support the socket family, even if
|
|
|
|
* BIO_lookup() added it in the returned result...
|
|
|
|
*/
|
|
|
|
continue;
|
|
|
|
}
|
2017-04-20 08:57:12 +00:00
|
|
|
|
2018-02-08 09:49:02 +00:00
|
|
|
if (bi != NULL) {
|
|
|
|
if (!BIO_bind(*sock, BIO_ADDRINFO_address(bi),
|
|
|
|
BIO_SOCK_REUSEADDR)) {
|
|
|
|
BIO_closesocket(*sock);
|
|
|
|
*sock = INVALID_SOCKET;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-20 08:57:12 +00:00
|
|
|
#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
|
|
|
|
|
2018-05-02 15:08:27 +00:00
|
|
|
if (!BIO_connect(*sock, BIO_ADDRINFO_address(ai),
|
2018-05-29 14:58:47 +00:00
|
|
|
protocol == IPPROTO_TCP ? BIO_SOCK_NODELAY : 0)) {
|
2016-02-02 23:47:42 +00:00
|
|
|
BIO_closesocket(*sock);
|
|
|
|
*sock = INVALID_SOCKET;
|
|
|
|
continue;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
|
|
|
|
2016-02-02 23:47:42 +00:00
|
|
|
/* Success, don't try any more addresses */
|
|
|
|
break;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
|
|
|
|
2016-02-02 23:47:42 +00:00
|
|
|
if (*sock == INVALID_SOCKET) {
|
2018-02-08 09:49:02 +00:00
|
|
|
if (bindaddr != NULL && !found) {
|
|
|
|
BIO_printf(bio_err, "Can't bind %saddress for %s%s%s\n",
|
|
|
|
BIO_ADDRINFO_family(res) == AF_INET6 ? "IPv6 " :
|
|
|
|
BIO_ADDRINFO_family(res) == AF_INET ? "IPv4 " :
|
|
|
|
BIO_ADDRINFO_family(res) == AF_UNIX ? "unix " : "",
|
|
|
|
bindhost != NULL ? bindhost : "",
|
|
|
|
bindport != NULL ? ":" : "",
|
|
|
|
bindport != NULL ? bindport : "");
|
|
|
|
ERR_clear_error();
|
|
|
|
ret = 0;
|
|
|
|
}
|
2016-02-02 23:47:42 +00:00
|
|
|
ERR_print_errors(bio_err);
|
|
|
|
} else {
|
2016-05-04 08:12:27 +00:00
|
|
|
/* Remove any stale errors from previous connection attempts */
|
|
|
|
ERR_clear_error();
|
2016-02-02 23:47:42 +00:00
|
|
|
ret = 1;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
2018-02-08 09:49:02 +00:00
|
|
|
out:
|
|
|
|
if (bindaddr != NULL) {
|
|
|
|
BIO_ADDRINFO_free (bindaddr);
|
|
|
|
}
|
2016-02-02 23:47:42 +00:00
|
|
|
BIO_ADDRINFO_free(res);
|
|
|
|
return ret;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
s_client/s_server: support unix domain sockets
The "-unix <path>" argument allows s_server and s_client to use a unix
domain socket in the filesystem instead of IPv4 ("-connect", "-port",
"-accept", etc). If s_server exits gracefully, such as when "-naccept"
is used and the requested number of SSL/TLS connections have occurred,
then the domain socket file is removed. On ctrl-C, it is likely that
the stale socket file will be left over, such that s_server would
normally fail to restart with the same arguments. For this reason,
s_server also supports an "-unlink" option, which will clean up any
stale socket file before starting.
If you have any reason to want encrypted IPC within an O/S instance,
this concept might come in handy. Otherwise it just demonstrates that
there is nothing about SSL/TLS that limits it to TCP/IP in any way.
(There might also be benchmarking and profiling use in this path, as
unix domain sockets are much lower overhead than connecting over local
IP addresses).
Signed-off-by: Geoff Thorpe <geoff@openssl.org>
2014-04-26 05:22:54 +00:00
|
|
|
|
2016-02-02 23:47:42 +00:00
|
|
|
/*
|
|
|
|
* do_server - helper routine to perform a server operation
|
|
|
|
* @accept_sock: pointer to storage of resulting socket.
|
|
|
|
* @host: the host name or path (for AF_UNIX) to connect to.
|
|
|
|
* @port: the port to connect to (ignored for AF_UNIX).
|
|
|
|
* @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
|
|
|
|
* @cb: pointer to a function that receives the accepted socket and
|
|
|
|
* should perform the communication with the connecting client.
|
|
|
|
* @context: pointer to memory that's passed verbatim to the cb function.
|
|
|
|
* @naccept: number of times an incoming connect should be accepted. If -1,
|
|
|
|
* unlimited number.
|
|
|
|
*
|
|
|
|
* This will create a socket and use it to listen to a host:port, or if
|
|
|
|
* family == AF_UNIX, to the path found in host, then start accepting
|
|
|
|
* incoming connections and run cb on the resulting socket.
|
|
|
|
*
|
|
|
|
* 0 on failure, something other on success.
|
|
|
|
*/
|
|
|
|
int do_server(int *accept_sock, const char *host, const char *port,
|
2017-04-20 08:56:56 +00:00
|
|
|
int family, int type, int protocol, do_server_cb cb,
|
2018-03-30 19:13:25 +00:00
|
|
|
unsigned char *context, int naccept, BIO *bio_s_out)
|
2015-01-22 03:40:55 +00:00
|
|
|
{
|
2016-02-02 23:47:42 +00:00
|
|
|
int asock = 0;
|
2015-01-22 03:40:55 +00:00
|
|
|
int sock;
|
|
|
|
int i;
|
2016-02-02 23:47:42 +00:00
|
|
|
BIO_ADDRINFO *res = NULL;
|
2018-01-23 16:43:45 +00:00
|
|
|
const BIO_ADDRINFO *next;
|
2018-04-17 19:30:22 +00:00
|
|
|
int sock_family, sock_type, sock_protocol, sock_port;
|
2018-01-23 16:43:45 +00:00
|
|
|
const BIO_ADDR *sock_address;
|
|
|
|
int sock_options = BIO_SOCK_REUSEADDR;
|
2016-02-02 23:47:42 +00:00
|
|
|
int ret = 0;
|
|
|
|
|
2017-06-25 17:09:46 +00:00
|
|
|
if (BIO_sock_init() != 1)
|
2016-02-02 23:47:42 +00:00
|
|
|
return 0;
|
|
|
|
|
2017-04-20 08:56:56 +00:00
|
|
|
if (!BIO_lookup_ex(host, port, BIO_LOOKUP_SERVER, family, type, protocol,
|
|
|
|
&res)) {
|
2016-02-02 23:47:42 +00:00
|
|
|
ERR_print_errors(bio_err);
|
|
|
|
return 0;
|
|
|
|
}
|
2015-01-22 03:40:55 +00:00
|
|
|
|
2016-02-24 15:59:14 +00:00
|
|
|
/* Admittedly, these checks are quite paranoid, we should not get
|
|
|
|
* anything in the BIO_ADDRINFO chain that we haven't asked for */
|
2016-02-02 23:47:42 +00:00
|
|
|
OPENSSL_assert((family == AF_UNSPEC || family == BIO_ADDRINFO_family(res))
|
2017-04-20 08:56:56 +00:00
|
|
|
&& (type == 0 || type == BIO_ADDRINFO_socktype(res))
|
|
|
|
&& (protocol == 0 || protocol == BIO_ADDRINFO_protocol(res)));
|
2016-02-02 23:47:42 +00:00
|
|
|
|
2018-01-23 16:43:45 +00:00
|
|
|
sock_family = BIO_ADDRINFO_family(res);
|
|
|
|
sock_type = BIO_ADDRINFO_socktype(res);
|
|
|
|
sock_protocol = BIO_ADDRINFO_protocol(res);
|
|
|
|
sock_address = BIO_ADDRINFO_address(res);
|
|
|
|
next = BIO_ADDRINFO_next(res);
|
2018-01-26 18:15:28 +00:00
|
|
|
if (sock_family == AF_INET6)
|
2018-01-23 16:43:45 +00:00
|
|
|
sock_options |= BIO_SOCK_V6_ONLY;
|
|
|
|
if (next != NULL
|
2018-01-26 18:15:28 +00:00
|
|
|
&& BIO_ADDRINFO_socktype(next) == sock_type
|
|
|
|
&& BIO_ADDRINFO_protocol(next) == sock_protocol) {
|
|
|
|
if (sock_family == AF_INET
|
|
|
|
&& BIO_ADDRINFO_family(next) == AF_INET6) {
|
2018-01-23 16:43:45 +00:00
|
|
|
sock_family = AF_INET6;
|
|
|
|
sock_address = BIO_ADDRINFO_address(next);
|
2018-01-26 18:15:28 +00:00
|
|
|
} else if (sock_family == AF_INET6
|
|
|
|
&& BIO_ADDRINFO_family(next) == AF_INET) {
|
2018-01-23 16:43:45 +00:00
|
|
|
sock_options &= ~BIO_SOCK_V6_ONLY;
|
2018-01-26 18:15:28 +00:00
|
|
|
}
|
2018-01-23 16:43:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
asock = BIO_socket(sock_family, sock_type, sock_protocol, 0);
|
2016-02-02 23:47:42 +00:00
|
|
|
if (asock == INVALID_SOCKET
|
2018-01-23 16:43:45 +00:00
|
|
|
|| !BIO_listen(asock, sock_address, sock_options)) {
|
2016-02-02 23:47:42 +00:00
|
|
|
BIO_ADDRINFO_free(res);
|
|
|
|
ERR_print_errors(bio_err);
|
|
|
|
if (asock != INVALID_SOCKET)
|
|
|
|
BIO_closesocket(asock);
|
|
|
|
goto end;
|
|
|
|
}
|
2015-01-22 03:40:55 +00:00
|
|
|
|
2017-04-20 08:56:56 +00:00
|
|
|
#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
|
|
|
|
|
2018-04-17 19:30:22 +00:00
|
|
|
sock_port = BIO_ADDR_rawport(sock_address);
|
|
|
|
|
2016-02-02 23:47:42 +00:00
|
|
|
BIO_ADDRINFO_free(res);
|
2016-02-14 03:33:56 +00:00
|
|
|
res = NULL;
|
2016-02-02 23:47:42 +00:00
|
|
|
|
2018-04-17 19:30:22 +00:00
|
|
|
if (sock_port == 0) {
|
2018-04-14 19:42:21 +00:00
|
|
|
/* dynamically allocated port, report which one */
|
2018-03-30 19:13:25 +00:00
|
|
|
union BIO_sock_info_u info;
|
|
|
|
char *hostname = NULL;
|
|
|
|
char *service = NULL;
|
|
|
|
int success = 0;
|
|
|
|
|
|
|
|
if ((info.addr = BIO_ADDR_new()) != NULL
|
|
|
|
&& BIO_sock_info(asock, BIO_SOCK_INFO_ADDRESS, &info)
|
|
|
|
&& (hostname = BIO_ADDR_hostname_string(info.addr, 1)) != NULL
|
|
|
|
&& (service = BIO_ADDR_service_string(info.addr, 1)) != NULL
|
|
|
|
&& BIO_printf(bio_s_out,
|
|
|
|
strchr(hostname, ':') == NULL
|
|
|
|
? /* IPv4 */ "ACCEPT %s:%s\n"
|
|
|
|
: /* IPv6 */ "ACCEPT [%s]:%s\n",
|
|
|
|
hostname, service) > 0)
|
|
|
|
success = 1;
|
|
|
|
|
|
|
|
(void)BIO_flush(bio_s_out);
|
|
|
|
OPENSSL_free(hostname);
|
|
|
|
OPENSSL_free(service);
|
|
|
|
BIO_ADDR_free(info.addr);
|
|
|
|
if (!success) {
|
|
|
|
BIO_closesocket(asock);
|
|
|
|
ERR_print_errors(bio_err);
|
|
|
|
goto end;
|
|
|
|
}
|
2018-04-14 19:42:21 +00:00
|
|
|
} else {
|
|
|
|
(void)BIO_printf(bio_s_out, "ACCEPT\n");
|
|
|
|
(void)BIO_flush(bio_s_out);
|
2018-03-30 19:13:25 +00:00
|
|
|
}
|
|
|
|
|
2016-02-14 03:33:56 +00:00
|
|
|
if (accept_sock != NULL)
|
2016-02-02 23:47:42 +00:00
|
|
|
*accept_sock = asock;
|
2015-01-22 03:40:55 +00:00
|
|
|
for (;;) {
|
2018-05-20 21:03:47 +00:00
|
|
|
char sink[64];
|
|
|
|
struct timeval timeout;
|
|
|
|
fd_set readfds;
|
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
if (type == SOCK_STREAM) {
|
2017-09-12 15:19:09 +00:00
|
|
|
BIO_ADDR_free(ourpeer);
|
|
|
|
ourpeer = BIO_ADDR_new();
|
|
|
|
if (ourpeer == NULL) {
|
|
|
|
BIO_closesocket(asock);
|
|
|
|
ERR_print_errors(bio_err);
|
|
|
|
goto end;
|
|
|
|
}
|
2016-02-14 03:33:56 +00:00
|
|
|
do {
|
2017-09-12 15:19:09 +00:00
|
|
|
sock = BIO_accept_ex(asock, ourpeer, 0);
|
2017-07-17 09:51:19 +00:00
|
|
|
} while (sock < 0 && BIO_sock_should_retry(sock));
|
2016-02-02 23:47:42 +00:00
|
|
|
if (sock < 0) {
|
2016-02-14 03:33:56 +00:00
|
|
|
ERR_print_errors(bio_err);
|
2016-03-02 21:12:46 +00:00
|
|
|
BIO_closesocket(asock);
|
2016-02-14 03:33:56 +00:00
|
|
|
break;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
2018-04-05 16:59:36 +00:00
|
|
|
BIO_set_tcp_ndelay(sock, 1);
|
2017-04-20 08:56:56 +00:00
|
|
|
i = (*cb)(sock, type, protocol, context);
|
2018-01-15 09:40:24 +00:00
|
|
|
|
2017-09-04 10:20:27 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2018-01-14 17:17:59 +00:00
|
|
|
shutdown(sock, 1); /* SHUT_WR */
|
2018-05-20 21:03:47 +00:00
|
|
|
/*
|
|
|
|
* We just said we have nothing else to say, but it doesn't mean
|
|
|
|
* that the other side has nothing. It's even recommended to
|
|
|
|
* consume incoming data. [In testing context this ensures that
|
|
|
|
* alerts are passed on...]
|
|
|
|
*/
|
|
|
|
timeout.tv_sec = 0;
|
|
|
|
timeout.tv_usec = 500000; /* some extreme round-trip */
|
|
|
|
do {
|
|
|
|
FD_ZERO(&readfds);
|
|
|
|
openssl_fdset(sock, &readfds);
|
|
|
|
} while (select(sock + 1, &readfds, NULL, NULL, &timeout) > 0
|
|
|
|
&& readsocket(sock, sink, sizeof(sink)) > 0);
|
|
|
|
|
2016-03-02 21:12:46 +00:00
|
|
|
BIO_closesocket(sock);
|
2016-02-02 23:47:42 +00:00
|
|
|
} else {
|
2017-04-20 08:56:56 +00:00
|
|
|
i = (*cb)(asock, type, protocol, context);
|
2016-02-02 23:47:42 +00:00
|
|
|
}
|
|
|
|
|
2015-01-22 03:40:55 +00:00
|
|
|
if (naccept != -1)
|
|
|
|
naccept--;
|
|
|
|
if (i < 0 || naccept == 0) {
|
2016-03-02 21:12:46 +00:00
|
|
|
BIO_closesocket(asock);
|
2016-02-02 23:47:42 +00:00
|
|
|
ret = i;
|
|
|
|
break;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
end:
|
2016-02-02 23:47:42 +00:00
|
|
|
# ifdef AF_UNIX
|
|
|
|
if (family == AF_UNIX)
|
|
|
|
unlink(host);
|
2015-01-22 03:40:55 +00:00
|
|
|
# endif
|
2017-09-12 15:19:09 +00:00
|
|
|
BIO_ADDR_free(ourpeer);
|
|
|
|
ourpeer = NULL;
|
2016-02-02 23:47:42 +00:00
|
|
|
return ret;
|
2015-01-22 03:40:55 +00:00
|
|
|
}
|
1998-12-21 10:52:47 +00:00
|
|
|
|
2016-02-02 23:47:42 +00:00
|
|
|
#endif /* OPENSSL_NO_SOCK */
|