diff options
Diffstat (limited to 'src/crypto/bio/connect.c')
-rw-r--r-- | src/crypto/bio/connect.c | 126 |
1 files changed, 60 insertions, 66 deletions
diff --git a/src/crypto/bio/connect.c b/src/crypto/bio/connect.c index 0b34d7f..2ed2def 100644 --- a/src/crypto/bio/connect.c +++ b/src/crypto/bio/connect.c @@ -93,6 +93,7 @@ typedef struct bio_connect_st { char *param_port; int nbio; + uint8_t ip[4]; unsigned short port; struct sockaddr_storage them; @@ -113,59 +114,23 @@ static int closesocket(int sock) { } #endif -/* split_host_and_port sets |*out_host| and |*out_port| to the host and port - * parsed from |name|. It returns one on success or zero on error. Even when - * successful, |*out_port| may be NULL on return if no port was specified. */ -static int split_host_and_port(char **out_host, char **out_port, const char *name) { - const char *host, *port = NULL; - size_t host_len = 0; +/* maybe_copy_ipv4_address sets |*ipv4| to the IPv4 address from |ss| (in + * big-endian order), if |ss| contains an IPv4 socket address. */ +static void maybe_copy_ipv4_address(uint8_t *ipv4, + const struct sockaddr_storage *ss) { + const struct sockaddr_in *sin; - *out_host = NULL; - *out_port = NULL; - - if (name[0] == '[') { /* bracketed IPv6 address */ - const char *close = strchr(name, ']'); - if (close == NULL) { - return 0; - } - host = name + 1; - host_len = close - host; - if (close[1] == ':') { /* [IP]:port */ - port = close + 2; - } else if (close[1] != 0) { - return 0; - } - } else { - const char *colon = strchr(name, ':'); - if (colon == NULL || strchr(colon + 1, ':') != NULL) { /* IPv6 address */ - host = name; - host_len = strlen(name); - } else { /* host:port */ - host = name; - host_len = colon - name; - port = colon + 1; - } + if (ss->ss_family != AF_INET) { + return; } - *out_host = BUF_strndup(host, host_len); - if (*out_host == NULL) { - return 0; - } - if (port == NULL) { - *out_port = NULL; - return 1; - } - *out_port = OPENSSL_strdup(port); - if (*out_port == NULL) { - OPENSSL_free(*out_host); - *out_host = NULL; - return 0; - } - return 1; + sin = (const struct sockaddr_in*) ss; + memcpy(ipv4, &sin->sin_addr, 4); } static int conn_state(BIO *bio, BIO_CONNECT *c) { int ret = -1, i; + char *p, *q; int (*cb)(const BIO *, int, int) = NULL; if (c->info_callback != NULL) { @@ -175,30 +140,36 @@ static int conn_state(BIO *bio, BIO_CONNECT *c) { for (;;) { switch (c->state) { case BIO_CONN_S_BEFORE: - /* If there's a hostname and a port, assume that both are - * exactly what they say. If there is only a hostname, try - * (just once) to split it into a hostname and port. */ - - if (c->param_hostname == NULL) { + p = c->param_hostname; + if (p == NULL) { OPENSSL_PUT_ERROR(BIO, BIO_R_NO_HOSTNAME_SPECIFIED); goto exit_loop; } + for (; *p != 0; p++) { + if (*p == ':' || *p == '/') { + break; + } + } - if (c->param_port == NULL) { - char *host, *port; - if (!split_host_and_port(&host, &port, c->param_hostname) || - port == NULL) { - OPENSSL_free(host); - OPENSSL_free(port); - OPENSSL_PUT_ERROR(BIO, BIO_R_NO_PORT_SPECIFIED); - ERR_add_error_data(2, "host=", c->param_hostname); - goto exit_loop; + i = *p; + if (i == ':' || i == '/') { + *(p++) = 0; + if (i == ':') { + for (q = p; *q; q++) { + if (*q == '/') { + *q = 0; + break; + } + } + OPENSSL_free(c->param_port); + c->param_port = BUF_strdup(p); } + } - OPENSSL_free(c->param_port); - c->param_port = port; - OPENSSL_free(c->param_hostname); - c->param_hostname = host; + if (c->param_port == NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_R_NO_PORT_SPECIFIED); + ERR_add_error_data(2, "host=", c->param_hostname); + goto exit_loop; } if (!bio_ip_and_port_to_socket_and_addr( @@ -209,6 +180,9 @@ static int conn_state(BIO *bio, BIO_CONNECT *c) { goto exit_loop; } + memset(c->ip, 0, 4); + maybe_copy_ipv4_address(c->ip, &c->them); + if (c->nbio) { if (!bio_socket_nbio(bio->num, 1)) { OPENSSL_PUT_ERROR(BIO, BIO_R_ERROR_SETTING_NBIO); @@ -402,6 +376,7 @@ static int conn_write(BIO *bio, const char *in, int in_len) { static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) { int *ip; + const char **pptr; long ret = 1; BIO_CONNECT *data; @@ -422,6 +397,25 @@ static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) { ret = 1; } break; + case BIO_C_GET_CONNECT: + /* TODO(fork): can this be removed? (Or maybe this whole file). */ + if (ptr != NULL) { + pptr = (const char **)ptr; + if (num == 0) { + *pptr = data->param_hostname; + } else if (num == 1) { + *pptr = data->param_port; + } else if (num == 2) { + *pptr = (char *) &data->ip[0]; + } else if (num == 3) { + *((int *)ptr) = data->port; + } + if (!bio->init) { + *pptr = "not initialized"; + } + ret = 1; + } + break; case BIO_C_SET_CONNECT: if (ptr != NULL) { bio->init = 1; @@ -451,9 +445,9 @@ static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) { if (ip != NULL) { *ip = bio->num; } - ret = bio->num; + ret = 1; } else { - ret = -1; + ret = 0; } break; case BIO_CTRL_GET_CLOSE: |