summaryrefslogtreecommitdiffstats
path: root/src/crypto/bio/connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/bio/connect.c')
-rw-r--r--src/crypto/bio/connect.c126
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: