diff options
author | Bob Beck <beck@cvs.openbsd.org> | 2017-04-30 04:18:59 +0000 |
---|---|---|
committer | Bob Beck <beck@cvs.openbsd.org> | 2017-04-30 04:18:59 +0000 |
commit | 66ef76ef9a971e0672b9990583907d65a8423434 (patch) | |
tree | a7ab03f13cd490a3817dd4579c8c5c373c3ac5dd /lib | |
parent | 83c723d5f9c975faf01d5e93e06b41d87f909f1b (diff) |
Microsoft Windows hates BIO_get_accept_socket in portable. Fix it to
not be awful or have any claims on supporting ipv6 when it does so
very badly
ok jsing@
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libcrypto/bio/b_sock.c | 150 |
1 files changed, 35 insertions, 115 deletions
diff --git a/lib/libcrypto/bio/b_sock.c b/lib/libcrypto/bio/b_sock.c index 0cc570b66f5..cb5549434ff 100644 --- a/lib/libcrypto/bio/b_sock.c +++ b/lib/libcrypto/bio/b_sock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: b_sock.c,v 1.63 2017/01/29 17:49:22 beck Exp $ */ +/* $OpenBSD: b_sock.c,v 1.64 2017/04/30 04:18:58 beck Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -168,151 +168,71 @@ BIO_socket_ioctl(int fd, long type, void *arg) int BIO_get_accept_socket(char *host, int bind_mode) { - int ret = 0; - union { - struct sockaddr sa; - struct sockaddr_in sa_in; - struct sockaddr_in6 sa_in6; - } server, client; - int s = -1, cs, addrlen; - unsigned char ip[4]; - unsigned short port; - char *str = NULL, *e; - char *h, *p; - unsigned long l; - int err_num; + struct addrinfo hints = { + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM, + .ai_flags = AI_PASSIVE, + }; + struct addrinfo *res = NULL; + char *h, *p, *str = NULL; + int error, ret = 0, s = -1; if (host == NULL || (str = strdup(host)) == NULL) return (-1); - - h = p = NULL; + p = NULL; h = str; - for (e = str; *e; e++) { - if (*e == ':') { - p = e; - } else if (*e == '/') { - *e = '\0'; - break; - } + if ((p = strrchr(str, ':')) == NULL) { + BIOerror(BIO_R_NO_PORT_SPECIFIED); + goto err; } - /* points at last ':', '::port' is special [see below] */ - if (p) - *p++ = '\0'; - else - p = h, h = NULL; - - do { - struct addrinfo *res, hint; - - /* - * '::port' enforces IPv6 wildcard listener. Some OSes, - * e.g. Solaris, default to IPv6 without any hint. Also - * note that commonly IPv6 wildchard socket can service - * IPv4 connections just as well... - */ - memset(&hint, 0, sizeof(hint)); - hint.ai_flags = AI_PASSIVE; - if (h) { - if (strchr(h, ':')) { - if (h[1] == '\0') - h = NULL; - hint.ai_family = AF_INET6; - } else if (h[0] == '*' && h[1] == '\0') { - hint.ai_family = AF_INET; - h = NULL; - } - } - - if (getaddrinfo(h, p, &hint, &res)) - break; - - addrlen = res->ai_addrlen <= sizeof(server) ? - res->ai_addrlen : sizeof(server); - memcpy(&server, res->ai_addr, addrlen); - - freeaddrinfo(res); - goto again; - } while (0); - - if (!BIO_get_port(p, &port)) + *p++ = '\0'; + if (*p == '\0') { + BIOerror(BIO_R_NO_PORT_SPECIFIED); goto err; + } + if (*h == '\0' || strcmp(h, "*") == 0) + h = NULL; - memset((char *)&server, 0, sizeof(server)); - server.sa_in.sin_family = AF_INET; - server.sa_in.sin_port = htons(port); - addrlen = sizeof(server.sa_in); - - if (h == NULL || strcmp(h, "*") == 0) - server.sa_in.sin_addr.s_addr = INADDR_ANY; - else { - if (!BIO_get_host_ip(h, &(ip[0]))) - goto err; - l = (unsigned long)((unsigned long)ip[0]<<24L)| - ((unsigned long)ip[1]<<16L)| - ((unsigned long)ip[2]<< 8L)| - ((unsigned long)ip[3]); - server.sa_in.sin_addr.s_addr = htonl(l); + if ((error = getaddrinfo(h, p, &hints, &res)) != 0) { + ERR_asprintf_error_data("getaddrinfo: '%s:%s': %s'", h, p, + gai_strerror(error)); + goto err; + } + if (h == NULL) { + struct sockaddr_in *sin = (struct sockaddr_in *)res->ai_addr; + sin->sin_addr.s_addr = INADDR_ANY; } -again: - s = socket(server.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); + s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s == -1) { SYSerror(errno); - ERR_asprintf_error_data("port='%s'", host); + ERR_asprintf_error_data("host='%s'", host); BIOerror(BIO_R_UNABLE_TO_CREATE_SOCKET); goto err; } - if (bind_mode == BIO_BIND_REUSEADDR) { int i = 1; ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)); bind_mode = BIO_BIND_NORMAL; } - if (bind(s, &server.sa, addrlen) == -1) { - err_num = errno; - if ((bind_mode == BIO_BIND_REUSEADDR_IF_UNUSED) && - (err_num == EADDRINUSE)) { - client = server; - if (h == NULL || strcmp(h, "*") == 0) { - if (client.sa.sa_family == AF_INET6) { - memset(&client.sa_in6.sin6_addr, 0, - sizeof(client.sa_in6.sin6_addr)); - client.sa_in6.sin6_addr.s6_addr[15] = 1; - } else if (client.sa.sa_family == AF_INET) { - client.sa_in.sin_addr.s_addr = - htonl(0x7F000001); - } else - goto err; - } - cs = socket(client.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); - if (cs != -1) { - int ii; - ii = connect(cs, &client.sa, addrlen); - close(cs); - if (ii == -1) { - bind_mode = BIO_BIND_REUSEADDR; - close(s); - goto again; - } - /* else error */ - } - /* else error */ - } - SYSerror(err_num); - ERR_asprintf_error_data("port='%s'", host); + if (bind(s, res->ai_addr, res->ai_addrlen) == -1) { + SYSerror(errno); + ERR_asprintf_error_data("host='%s'", host); BIOerror(BIO_R_UNABLE_TO_BIND_SOCKET); goto err; } if (listen(s, SOMAXCONN) == -1) { SYSerror(errno); - ERR_asprintf_error_data("port='%s'", host); + ERR_asprintf_error_data("host='%s'", host); BIOerror(BIO_R_UNABLE_TO_LISTEN_SOCKET); goto err; } ret = 1; + err: free(str); + freeaddrinfo(res); if ((ret == 0) && (s != -1)) { close(s); s = -1; |