Commit ab69ac00 authored by Richard Levitte's avatar Richard Levitte
Browse files

Refactoring BIO: Adapt s_client and s_server



s_socket.c gets brutally cleaned out and now consists of only two
functions, one for client and the other for server.  They both handle
AF_INET, AF_INET6 and additionally AF_UNIX where supported.  The rest
is just easy adaptation.

Both s_client and s_server get the new flags -4 and -6 to force the
use of IPv4 or IPv6 only.

Also, the default host "localhost" in s_client is removed.  It's not
certain that this host is set up for both IPv4 and IPv6.  For example,
Debian has "ip6-localhost" as the default hostname for [::1].  The
better way is to default |host| to NULL and rely on BIO_lookup() to
return a BIO_ADDRINFO with the appropriate loopback address for IPv4
or IPv6 as indicated by the |family| parameter.

Reviewed-by: default avatarKurt Roeckx <kurt@openssl.org>
parent d858c876
Loading
Loading
Loading
Loading
+6 −17
Original line number Diff line number Diff line
@@ -146,20 +146,14 @@ typedef fd_mask fd_set;
# define FD_ZERO(p)      memset((p), 0, sizeof(*(p)))
#endif

#define PORT            4433
#define PORT_STR        "4433"
#define PORT            "4433"
#define PROTOCOL        "tcp"

int do_server(int port, int type, int *ret,
              int (*cb) (char *hostname, int s, int stype,
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);
#ifndef NO_SYS_UN_H
int do_server_unix(const char *path, int *ret,
                   int (*cb) (char *hostname, int s, int stype,
                              unsigned char *context), unsigned char *context,
                   int naccept);
#endif
#ifdef HEADER_X509_H
int verify_callback(int ok, X509_STORE_CTX *ctx);
#endif
@@ -172,14 +166,9 @@ int ssl_print_point_formats(BIO *out, SSL *s);
int ssl_print_curves(BIO *out, SSL *s, int noshared);
#endif
int ssl_print_tmp_key(BIO *out, SSL *s);
int init_client(int *sock, const char *server, int port, int type);
#ifndef NO_SYS_UN_H
int init_client_unix(int *sock, const char *server);
#endif
int init_client(int *sock, const char *host, const char *port,
                int family, int type);
int should_retry(int i);
int extract_port(const char *str, unsigned short *port_ptr);
int extract_host_port(char *str, char **host_ptr, unsigned char *ip,
                      unsigned short *p);

long bio_dump_callback(BIO *bio, int cmd, const char *argp,
                       int argi, long argl, long ret);
+95 −22
Original line number Diff line number Diff line
@@ -173,8 +173,6 @@ typedef unsigned int u_int;
# undef FIONBIO
#endif

#define SSL_HOST_NAME   "localhost"

#undef BUFSIZZ
#define BUFSIZZ 1024*8
#define S_CLIENT_IRC_READ_TIMEOUT 8
@@ -634,7 +632,8 @@ static int tlsa_import_rrset(SSL *con, STACK_OF(OPENSSL_STRING) *rrset)

typedef enum OPTION_choice {
    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
    OPT_HOST, OPT_PORT, OPT_CONNECT, OPT_UNIX, OPT_XMPPHOST, OPT_VERIFY,
    OPT_4, OPT_6, OPT_HOST, OPT_PORT, OPT_CONNECT, OPT_UNIX,
    OPT_XMPPHOST, OPT_VERIFY,
    OPT_CERT, OPT_CRL, OPT_CRL_DOWNLOAD, OPT_SESS_OUT, OPT_SESS_IN,
    OPT_CERTFORM, OPT_CRLFORM, OPT_VERIFY_RET_ERROR, OPT_VERIFY_QUIET,
    OPT_BRIEF, OPT_PREXIT, OPT_CRLF, OPT_QUIET, OPT_NBIO,
@@ -664,10 +663,14 @@ OPTIONS s_client_options[] = {
    {"host", OPT_HOST, 's', "Use -connect instead"},
    {"port", OPT_PORT, 'p', "Use -connect instead"},
    {"connect", OPT_CONNECT, 's',
     "TCP/IP where to connect (default is " SSL_HOST_NAME ":" PORT_STR ")"},
     "TCP/IP where to connect (default is :" PORT ")"},
    {"proxy", OPT_PROXY, 's',
     "Connect to via specified proxy to the real server"},
#ifdef AF_UNIX
    {"unix", OPT_UNIX, 's', "Connect over unix domain sockets"},
#endif
    {"4", OPT_4, '-', "Use IPv4 only"},
    {"6", OPT_6, '-', "Use IPv6 only"},
    {"verify", OPT_VERIFY, 'p', "Turn on peer certificate verification"},
    {"cert", OPT_CERT, '<', "Certificate file to use, PEM format assumed"},
    {"certform", OPT_CERTFORM, 'F',
@@ -845,12 +848,12 @@ int s_client_main(int argc, char **argv)
    char *CApath = NULL, *CAfile = NULL, *cbuf = NULL, *sbuf = NULL;
    char *mbuf = NULL, *proxystr = NULL, *connectstr = NULL;
    char *cert_file = NULL, *key_file = NULL, *chain_file = NULL;
    char *chCApath = NULL, *chCAfile = NULL, *host = SSL_HOST_NAME;
    char *chCApath = NULL, *chCAfile = NULL, *host = NULL;
    char *port = BUF_strdup(PORT);
    char *inrand = NULL;
    char *passarg = NULL, *pass = NULL, *vfyCApath = NULL, *vfyCAfile = NULL;
    char *sess_in = NULL, *sess_out = NULL, *crl_file = NULL, *p;
    char *jpake_secret = NULL, *xmpphost = NULL;
    const char *unix_path = NULL;
    const char *ehlo = "mail.example.com";
    struct sockaddr peer;
    struct timeval timeout, *timeoutp;
@@ -862,12 +865,12 @@ int s_client_main(int argc, char **argv)
    int enable_timeouts = 0, sdebug = 0, peerlen = sizeof peer;
    int reconnect = 0, verify = SSL_VERIFY_NONE, vpmtouched = 0;
    int ret = 1, in_init = 1, i, nbio_test = 0, s = -1, k, width, state = 0;
    int sbuf_len, sbuf_off, socket_type = SOCK_STREAM, cmdletters = 1;
    int sbuf_len, sbuf_off, cmdletters = 1;
    int socket_family = AF_UNSPEC, socket_type = SOCK_STREAM;
    int starttls_proto = PROTO_OFF, crl_format = FORMAT_PEM, crl_download = 0;
    int write_tty, read_tty, write_ssl, read_ssl, tty_on, ssl_pending;
    int fallback_scsv = 0;
    long socket_mtu = 0, randamt = 0;
    unsigned short port = PORT;
    OPTION_CHOICE o;
#ifndef OPENSSL_NO_ENGINE
    ENGINE *ssl_client_engine = NULL;
@@ -926,22 +929,72 @@ int s_client_main(int argc, char **argv)
            opt_help(s_client_options);
            ret = 0;
            goto end;
        case OPT_4:
#ifdef AF_UNIX
            if (socket_family == AF_UNIX) {
                OPENSSL_free(host); host = NULL;
                OPENSSL_free(port); port = NULL;
            }
#endif
            socket_family = AF_INET;
            break;
        case OPT_6:
            if (1) {
#ifdef AF_INET6
#ifdef AF_UNIX
                if (socket_family == AF_UNIX) {
                    OPENSSL_free(host); host = NULL;
                    OPENSSL_free(port); port = NULL;
                }
#endif
                socket_family = AF_INET6;
            } else {
#endif
                BIO_printf(bio_err, "%s: IPv6 domain sockets unsupported\n", prog);
                goto end;
            }
            break;
        case OPT_HOST:
            host = opt_arg();
#ifdef AF_UNIX
            if (socket_family == AF_UNIX) {
                OPENSSL_free(host); host = NULL;
                OPENSSL_free(port); port = NULL;
                socket_family = AF_UNSPEC;
            }
#endif
            OPENSSL_free(host); host = BUF_strdup(opt_arg());
            break;
        case OPT_PORT:
            port = atoi(opt_arg());
#ifdef AF_UNIX
            if (socket_family == AF_UNIX) {
                OPENSSL_free(host); host = NULL;
                OPENSSL_free(port); port = NULL;
                socket_family = AF_UNSPEC;
            }
#endif
            OPENSSL_free(port); port = BUF_strdup(opt_arg());
            break;
        case OPT_CONNECT:
#ifdef AF_UNIX
            if (socket_family == AF_UNIX) {
                socket_family = AF_UNSPEC;
            }
#endif
            OPENSSL_free(host); host = NULL;
            OPENSSL_free(port); port = NULL;
            connectstr = opt_arg();
            break;
        case OPT_PROXY:
            proxystr = opt_arg();
            starttls_proto = PROTO_CONNECT;
            break;
#ifdef AF_UNIX
        case OPT_UNIX:
            unix_path = opt_arg();
            socket_family = AF_UNIX;
            OPENSSL_free(host); host = BUF_strdup(opt_arg());
            OPENSSL_free(port); port = NULL;
            break;
#endif
        case OPT_XMPPHOST:
            xmpphost = opt_arg();
            break;
@@ -1286,18 +1339,41 @@ int s_client_main(int argc, char **argv)
    argv = opt_rest();

    if (proxystr) {
        int res;
        char *tmp_host = host, *tmp_port = port;
        if (connectstr == NULL) {
            BIO_printf(bio_err, "%s: -proxy requires use of -connect\n", prog);
            goto opthelp;
        }
        if (!extract_host_port(proxystr, &host, NULL, &port))
        res = BIO_parse_hostserv(proxystr, &host, &port, BIO_PARSE_PRIO_HOST);
        if (tmp_host != host)
            OPENSSL_free(tmp_host);
        if (tmp_port != port)
            OPENSSL_free(tmp_port);
        if (!res) {
            BIO_printf(bio_err, "%s: -proxy argument malformed or ambiguous\n",
                       prog);
            goto end;
        }
    else if (connectstr != NULL
            && !extract_host_port(connectstr, &host, NULL, &port))
    } else {
        int res = 1;
        char *tmp_host = host, *tmp_port = port;
        if (connectstr != NULL)
            res = BIO_parse_hostserv(connectstr, &host, &port,
                                     BIO_PARSE_PRIO_HOST);
        if (tmp_host != host)
            OPENSSL_free(tmp_host);
        if (tmp_port != port)
            OPENSSL_free(tmp_port);
        if (!res) {
            BIO_printf(bio_err,
                       "%s: -connect argument malformed or ambiguous\n",
                       prog);
            goto end;
        }
    }

    if (unix_path && (socket_type != SOCK_STREAM)) {
    if (socket_family == AF_UNIX && socket_type != SOCK_STREAM) {
        BIO_printf(bio_err,
                   "Can't use unix sockets and datagrams together\n");
        goto end;
@@ -1610,12 +1686,7 @@ int s_client_main(int argc, char **argv)
    }

 re_start:
#ifdef NO_SYS_UN_H
    if (init_client(&s, host, port, socket_type) == 0)
#else
    if ((!unix_path && (init_client(&s, host, port, socket_type) == 0)) ||
        (unix_path && (init_client_unix(&s, unix_path) == 0)))
#endif
    if (init_client(&s, host, port, socket_family, socket_type) == 0)
    {
        BIO_printf(bio_err, "connect:errno=%d\n", get_last_socket_error());
        SHUTDOWN(s);
@@ -2364,6 +2435,8 @@ int s_client_main(int argc, char **argv)
#ifndef OPENSSL_NO_SRP
    OPENSSL_free(srp_arg.srppassin);
#endif
    OPENSSL_free(host);
    OPENSSL_free(port);
    X509_VERIFY_PARAM_free(vpm);
    ssl_excert_free(exc);
    sk_OPENSSL_STRING_free(ssl_args);
+94 −37
Original line number Diff line number Diff line
@@ -191,9 +191,12 @@ typedef unsigned int u_int;
#endif

static int not_resumable_sess_cb(SSL *s, int is_forward_secure);
static int sv_body(char *hostname, int s, int stype, unsigned char *context);
static int www_body(char *hostname, int s, int stype, unsigned char *context);
static int rev_body(char *hostname, int s, int stype, unsigned char *context);
static int sv_body(const char *hostname, int s, int stype,
                   unsigned char *context);
static int www_body(const char *hostname, int s, int stype,
                    unsigned char *context);
static int rev_body(const char *hostname, int s, int stype,
                    unsigned char *context);
static void close_accept_socket(void);
static int init_ssl_connection(SSL *s);
static void print_stats(BIO *bp, SSL_CTX *ctx);
@@ -791,8 +794,8 @@ static char *srtp_profiles = NULL;
#endif

typedef enum OPTION_choice {
    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
    OPT_ENGINE, OPT_PORT, OPT_UNIX, OPT_UNLINK, OPT_NACCEPT,
    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_ENGINE,
    OPT_4, OPT_6, OPT_ACCEPT, OPT_PORT, OPT_UNIX, OPT_UNLINK, OPT_NACCEPT,
    OPT_VERIFY, OPT_UPPER_V_VERIFY, OPT_CONTEXT, OPT_CERT, OPT_CRL,
    OPT_CRL_DOWNLOAD, OPT_SERVERINFO, OPT_CERTFORM, OPT_KEY, OPT_KEYFORM,
    OPT_PASS, OPT_CERT_CHAIN, OPT_DHPARAM, OPT_DCERTFORM, OPT_DCERT,
@@ -821,9 +824,13 @@ typedef enum OPTION_choice {
OPTIONS s_server_options[] = {
    {"help", OPT_HELP, '-', "Display this summary"},
    {"port", OPT_PORT, 'p'},
    {"accept", OPT_PORT, 'p',
     "TCP/IP port to accept on (default is " PORT_STR ")"},
    {"accept", OPT_ACCEPT, 's',
     "TCP/IP port or service to accept on (default is " PORT ")"},
#ifdef AF_UNIX
    {"unix", OPT_UNIX, 's', "Unix domain socket to accept on"},
#endif
    {"4", OPT_4, '-', "Use IPv4 only"},
    {"6", OPT_6, '-', "Use IPv6 only"},
    {"unlink", OPT_UNLINK, '-', "For -unix, unlink existing socket first"},
    {"context", OPT_CONTEXT, 's', "Set session ID context"},
    {"verify", OPT_VERIFY, 'n', "Turn on peer certificate verification"},
@@ -998,11 +1005,10 @@ int s_server_main(int argc, char *argv[])
#ifndef OPENSSL_NO_PSK
    char *p;
#endif
    const char *unix_path = NULL;
#ifndef NO_SYS_UN_H
#ifdef AF_UNIX
    int unlink_unix_path = 0;
#endif
    int (*server_cb) (char *hostname, int s, int stype,
    int (*server_cb) (const char *hostname, int s, int stype,
                      unsigned char *context);
    int vpmtouched = 0, build_chain = 0, no_cache = 0, ext_cache = 0;
#ifndef OPENSSL_NO_DH
@@ -1012,9 +1018,11 @@ int s_server_main(int argc, char *argv[])
    int noCApath = 0, noCAfile = 0;
    int s_cert_format = FORMAT_PEM, s_key_format = FORMAT_PEM;
    int s_dcert_format = FORMAT_PEM, s_dkey_format = FORMAT_PEM;
    int rev = 0, naccept = -1, sdebug = 0, socket_type = SOCK_STREAM;
    int rev = 0, naccept = -1, sdebug = 0;
    int socket_family = AF_UNSPEC, socket_type = SOCK_STREAM;
    int state = 0, crl_format = FORMAT_PEM, crl_download = 0;
    unsigned short port = PORT;
    char *host = NULL;
    char *port = BUF_strdup(PORT);
    unsigned char *context = NULL;
    OPTION_CHOICE o;
    EVP_PKEY *s_key2 = NULL;
@@ -1059,26 +1067,71 @@ int s_server_main(int argc, char *argv[])
            ret = 0;
            goto end;

        case OPT_PORT:
            if (!extract_port(opt_arg(), &port))
        case OPT_4:
#ifdef AF_UNIX
            if (socket_family == AF_UNIX) {
                OPENSSL_free(host); host = NULL;
                OPENSSL_free(port); port = NULL;
            }
#endif
            socket_family = AF_INET;
            break;
        case OPT_6:
            if (1) {
#ifdef AF_INET6
#ifdef AF_UNIX
                if (socket_family == AF_UNIX) {
                    OPENSSL_free(host); host = NULL;
                    OPENSSL_free(port); port = NULL;
                }
#endif
                socket_family = AF_INET6;
            } else {
#endif
                BIO_printf(bio_err, "%s: IPv6 domain sockets unsupported\n", prog);
                goto end;
            }
            break;
        case OPT_UNIX:
#ifdef NO_SYS_UN_H
            BIO_printf(bio_err, "unix domain sockets unsupported\n");
        case OPT_PORT:
#ifdef AF_UNIX
            if (socket_family == AF_UNIX) {
                socket_family = AF_UNSPEC;
            }
#endif
            OPENSSL_free(port); port = NULL;
            OPENSSL_free(host); host = NULL;
            if (BIO_parse_hostserv(opt_arg(), NULL, &port, BIO_PARSE_PRIO_SERV) < 1) {
                BIO_printf(bio_err,
                           "%s: -port argument malformed or ambiguous\n",
                           port);
                goto end;
#else
            unix_path = opt_arg();
            }
            break;
        case OPT_ACCEPT:
#ifdef AF_UNIX
            if (socket_family == AF_UNIX) {
                socket_family = AF_UNSPEC;
            }
#endif
            OPENSSL_free(port); port = NULL;
            OPENSSL_free(host); host = NULL;
            if (BIO_parse_hostserv(opt_arg(), &host, &port, BIO_PARSE_PRIO_SERV) < 1) {
                BIO_printf(bio_err,
                           "%s: -accept argument malformed or ambiguous\n",
                           port);
                goto end;
            }
            break;
#ifdef AF_UNIX
        case OPT_UNIX:
            socket_family = AF_UNIX;
            OPENSSL_free(host); host = BUF_strdup(opt_arg());
            OPENSSL_free(port); port = NULL;
            break;
        case OPT_UNLINK:
#ifdef NO_SYS_UN_H
            BIO_printf(bio_err, "unix domain sockets unsupported\n");
            goto end;
#else
            unlink_unix_path = 1;
#endif
            break;
#endif
        case OPT_NACCEPT:
            naccept = atol(opt_arg());
            break;
@@ -1462,11 +1515,13 @@ int s_server_main(int argc, char *argv[])
    }
#endif

    if (unix_path && (socket_type != SOCK_STREAM)) {
#ifdef AF_UNIX
    if (socket_family == AF_UNIX && socket_type != SOCK_STREAM) {
        BIO_printf(bio_err,
                   "Can't use unix sockets and datagrams together\n");
        goto end;
    }
#endif
#if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK)
    if (jpake_secret) {
        if (psk_key) {
@@ -1929,16 +1984,13 @@ int s_server_main(int argc, char *argv[])
        server_cb = www_body;
    else
        server_cb = sv_body;
#ifndef NO_SYS_UN_H
    if (unix_path) {
        if (unlink_unix_path)
            unlink(unix_path);
        do_server_unix(unix_path, &accept_socket, server_cb, context,
                       naccept);
    } else
#ifdef AF_UNIX
    if (socket_family == AF_UNIX
        && unlink_unix_path)
        unlink(host);
#endif
        do_server(port, socket_type, &accept_socket, server_cb, context,
                  naccept);
    do_server(&accept_socket, host, port, socket_family, socket_type,
              server_cb, context, naccept);
    print_stats(bio_s_out, ctx);
    ret = 0;
 end:
@@ -1952,6 +2004,8 @@ int s_server_main(int argc, char *argv[])
    sk_X509_pop_free(s_dchain, X509_free);
    OPENSSL_free(pass);
    OPENSSL_free(dpass);
    OPENSSL_free(host);
    OPENSSL_free(port);
    X509_VERIFY_PARAM_free(vpm);
    free_sessions();
    OPENSSL_free(tlscstatp.host);
@@ -2006,7 +2060,8 @@ static void print_stats(BIO *bio, SSL_CTX *ssl_ctx)
               SSL_CTX_sess_get_cache_size(ssl_ctx));
}

static int sv_body(char *hostname, int s, int stype, unsigned char *context)
static int sv_body(const char *hostname, int s, int stype,
                   unsigned char *context)
{
    char *buf = NULL;
    fd_set readfds;
@@ -2599,7 +2654,8 @@ static DH *load_dh_param(const char *dhfile)
}
#endif

static int www_body(char *hostname, int s, int stype, unsigned char *context)
static int www_body(const char *hostname, int s, int stype,
                    unsigned char *context)
{
    char *buf = NULL;
    int ret = 1;
@@ -2986,7 +3042,8 @@ static int www_body(char *hostname, int s, int stype, unsigned char *context)
    return (ret);
}

static int rev_body(char *hostname, int s, int stype, unsigned char *context)
static int rev_body(const char *hostname, int s, int stype,
                    unsigned char *context)
{
    char *buf = NULL;
    int i;
+169 −529

File changed.

Preview size limit exceeded, changes collapsed.