Commit ebc01683 authored by John Hughes's avatar John Hughes Committed by Andy Polyakov
Browse files

Add BIO_bind function to bind local address for a socket.



Add -bind option to s_client application to allow specification of
local address for connection.

Reviewed-by: default avatarAndy Polyakov <appro@openssl.org>
Reviewed-by: default avatarRich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/5272)
parent b383aa20
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ int ssl_print_groups(BIO *out, SSL *s, int noshared);
#endif
int ssl_print_tmp_key(BIO *out, SSL *s);
int init_client(int *sock, const char *host, const char *port,
                const char *bindhost, const char *bindport,
                int family, int type, int protocol);
int should_retry(int i);

+22 −4
Original line number Diff line number Diff line
@@ -570,7 +570,7 @@ 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_4, OPT_6, OPT_HOST, OPT_PORT, OPT_CONNECT, OPT_UNIX,
    OPT_4, OPT_6, OPT_HOST, OPT_PORT, OPT_CONNECT, OPT_BIND, OPT_UNIX,
    OPT_XMPPHOST, OPT_VERIFY, OPT_NAMEOPT,
    OPT_CERT, OPT_CRL, OPT_CRL_DOWNLOAD, OPT_SESS_OUT, OPT_SESS_IN,
    OPT_CERTFORM, OPT_CRLFORM, OPT_VERIFY_RET_ERROR, OPT_VERIFY_QUIET,
@@ -612,6 +612,7 @@ const OPTIONS s_client_options[] = {
    {"port", OPT_PORT, 'p', "Use -connect instead"},
    {"connect", OPT_CONNECT, 's',
     "TCP/IP where to connect (default is :" PORT ")"},
    {"bind", OPT_BIND, 's', "bind local address for connection"},
    {"proxy", OPT_PROXY, 's',
     "Connect to via specified proxy to the real server"},
#ifdef AF_UNIX
@@ -884,10 +885,11 @@ int s_client_main(int argc, char **argv)
    const SSL_METHOD *meth = TLS_client_method();
    const char *CApath = NULL, *CAfile = NULL;
    char *cbuf = NULL, *sbuf = NULL;
    char *mbuf = NULL, *proxystr = NULL, *connectstr = NULL;
    char *mbuf = NULL, *proxystr = NULL, *connectstr = NULL, *bindstr = NULL;
    char *cert_file = NULL, *key_file = NULL, *chain_file = NULL;
    char *chCApath = NULL, *chCAfile = NULL, *host = NULL;
    char *port = OPENSSL_strdup(PORT);
    char *bindhost = NULL, *bindport = NULL;
    char *passarg = NULL, *pass = NULL, *vfyCApath = NULL, *vfyCAfile = NULL;
    char *ReqCAfile = NULL;
    char *sess_in = NULL, *crl_file = NULL, *p;
@@ -1053,6 +1055,9 @@ int s_client_main(int argc, char **argv)
            connect_type = use_inet;
            freeandcopy(&connectstr, opt_arg());
            break;
        case OPT_BIND:
            freeandcopy(&bindstr, opt_arg());
            break;
        case OPT_PROXY:
            proxystr = opt_arg();
            starttls_proto = PROTO_CONNECT;
@@ -1554,6 +1559,18 @@ int s_client_main(int argc, char **argv)
        }
    }

    if (bindstr != NULL) {
        int res;
        res = BIO_parse_hostserv(bindstr, &bindhost, &bindport,
                                 BIO_PARSE_PRIO_HOST);
        if (!res) {
            BIO_printf(bio_err,
                       "%s: -bind argument parameter malformed or ambiguous\n",
                       prog);
            goto end;
        }
    }

#ifdef AF_UNIX
    if (socket_family == AF_UNIX && socket_type != SOCK_STREAM) {
        BIO_printf(bio_err,
@@ -1976,8 +1993,8 @@ int s_client_main(int argc, char **argv)
    }

 re_start:
    if (init_client(&s, host, port, socket_family, socket_type, protocol)
            == 0) {
    if (init_client(&s, host, port, bindhost, bindport, socket_family,
                    socket_type, protocol) == 0) {
        BIO_printf(bio_err, "connect:errno=%d\n", get_last_socket_error());
        BIO_closesocket(s);
        goto end;
@@ -3082,6 +3099,7 @@ int s_client_main(int argc, char **argv)
    OPENSSL_free(srp_arg.srppassin);
#endif
    OPENSSL_free(connectstr);
    OPENSSL_free(bindstr);
    OPENSSL_free(host);
    OPENSSL_free(port);
    X509_VERIFY_PARAM_free(vpm);
+49 −0
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@ BIO_ADDR *ourpeer = NULL;
 * @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).
 * @bindhost: source host or path (for AF_UNIX).
 * @bindport: source port (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
@@ -58,10 +60,14 @@ BIO_ADDR *ourpeer = NULL;
 * Returns 1 on success, 0 on failure.
 */
int init_client(int *sock, const char *host, const char *port,
                const char *bindhost, const char *bindport,
                int family, int type, int protocol)
{
    BIO_ADDRINFO *res = NULL;
    BIO_ADDRINFO *bindaddr = NULL;
    const BIO_ADDRINFO *ai = NULL;
    const BIO_ADDRINFO *bi = NULL;
    int found = 0;
    int ret;

    if (BIO_sock_init() != 1)
@@ -74,6 +80,15 @@ int init_client(int *sock, const char *host, const char *port,
        return 0;
    }

    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;
        }
    }

    ret = 0;
    for (ai = res; ai != NULL; ai = BIO_ADDRINFO_next(ai)) {
        /* Admittedly, these checks are quite paranoid, we should not get
@@ -85,6 +100,16 @@ int init_client(int *sock, const char *host, const char *port,
                       && (protocol == 0
                           || protocol == BIO_ADDRINFO_protocol(ai)));

        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;
        }

        *sock = BIO_socket(BIO_ADDRINFO_family(ai), BIO_ADDRINFO_socktype(ai),
                           BIO_ADDRINFO_protocol(ai), 0);
        if (*sock == INVALID_SOCKET) {
@@ -94,6 +119,15 @@ int init_client(int *sock, const char *host, const char *port,
            continue;
        }

        if (bi != NULL) {
            if (!BIO_bind(*sock, BIO_ADDRINFO_address(bi),
                          BIO_SOCK_REUSEADDR)) {
                BIO_closesocket(*sock);
                *sock = INVALID_SOCKET;
                break;
            }
        }

#ifndef OPENSSL_NO_SCTP
        if (protocol == IPPROTO_SCTP) {
            /*
@@ -123,12 +157,27 @@ int init_client(int *sock, const char *host, const char *port,
    }

    if (*sock == INVALID_SOCKET) {
        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;
        }
        ERR_print_errors(bio_err);
    } else {
        /* Remove any stale errors from previous connection attempts */
        ERR_clear_error();
        ret = 1;
    }
out:
    if (bindaddr != NULL) {
        BIO_ADDRINFO_free (bindaddr);
    }
    BIO_ADDRINFO_free(res);
    return ret;
}
+50 −19
Original line number Diff line number Diff line
@@ -115,6 +115,55 @@ int BIO_connect(int sock, const BIO_ADDR *addr, int options)
    return 1;
}

/*-
 * BIO_bind - bind socket to address
 * @sock: the socket to set
 * @addr: local address to bind to
 * @options: BIO socket options
 *
 * Binds to the address using the given socket and options.
 *
 * Options can be a combination of the following:
 * - BIO_SOCK_REUSEADDR: Try to reuse the address and port combination
 *   for a recently closed port.
 *
 * 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_bind(int sock, const BIO_ADDR *addr, int options)
{
    int on = 1;

    if (sock == -1) {
        BIOerr(BIO_F_BIO_BIND, BIO_R_INVALID_SOCKET);
        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,
                       (const void *)&on, sizeof(on)) != 0) {
            SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error());
            BIOerr(BIO_F_BIO_BIND, BIO_R_UNABLE_TO_REUSEADDR);
            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_BIND, BIO_R_UNABLE_TO_BIND_SOCKET);
        return 0;
    }

    return 1;
}

/*-
 * BIO_listen - Creates a listen socket
 * @sock: the socket to listen with
@@ -174,21 +223,6 @@ int BIO_listen(int sock, const BIO_ADDR *addr, int options)
    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,
                       (const void *)&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,
                       (const void *)&on, sizeof(on)) != 0) {
@@ -223,11 +257,8 @@ int BIO_listen(int sock, const BIO_ADDR *addr, int options)
    }
# 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);
    if (!BIO_bind(sock, addr, options))
        return 0;
    }

    if (socktype != SOCK_DGRAM && listen(sock, MAX_LISTEN) == -1) {
        SYSerr(SYS_F_LISTEN, get_last_socket_error());
+1 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ static const ERR_STRING_DATA BIO_str_functs[] = {
    {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ACCEPT, 0), "BIO_accept"},
    {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ACCEPT_EX, 0), "BIO_accept_ex"},
    {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ADDR_NEW, 0), "BIO_ADDR_new"},
    {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_BIND, 0), "BIO_bind"},
    {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_CALLBACK_CTRL, 0), "BIO_callback_ctrl"},
    {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_CONNECT, 0), "BIO_connect"},
    {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_CTRL, 0), "BIO_ctrl"},
Loading