--- a/apps/s_apps.h +++ b/apps/s_apps.h @@ -151,7 +151,7 @@ typedef fd_mask fd_set; #define PORT_STR "4433" #define PROTOCOL "tcp" -int do_server(int port, int type, int *ret, +int do_server(char *port, int type, int *ret, int (*cb) (char *hostname, int s, int stype, unsigned char *context), unsigned char *context, int naccept); @@ -167,11 +167,10 @@ 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, char *server, int port, int type); +int init_client(int *sock, char *server, char *port, int type); int should_retry(int i); int extract_port(char *str, short *port_ptr); -int extract_host_port(char *str, char **host_ptr, unsigned char *ip, - short *p); +int extract_host_port(char *str, char **host_ptr, char **port_ptr); long MS_CALLBACK bio_dump_callback(BIO *bio, int cmd, const char *argp, int argi, long argl, long ret); --- a/apps/s_client.c +++ b/apps/s_client.c @@ -678,7 +678,7 @@ int MAIN(int argc, char **argv) int cbuf_len, cbuf_off; int sbuf_len, sbuf_off; fd_set readfds, writefds; - short port = PORT; + char *port_str = PORT_STR; char *http_proxy_str = NULL, *connect_str = NULL; int full_log = 1; char *host = SSL_HOST_NAME; @@ -803,9 +803,7 @@ int MAIN(int argc, char **argv) } else if (strcmp(*argv, "-port") == 0) { if (--argc < 1) goto bad; - port = atoi(*(++argv)); - if (port == 0) - goto bad; + port_str = *(++argv); } else if (strcmp(*argv, "-connect") == 0) { if (--argc < 1) goto bad; @@ -1156,10 +1154,10 @@ int MAIN(int argc, char **argv) } if (http_proxy_str) { - if (!extract_host_port(http_proxy_str, &host, NULL, &port)) + if (!extract_host_port(http_proxy_str, &host, &port_str)) goto bad; } else if (connect_str) { - if (!extract_host_port(connect_str, &host, NULL, &port)) + if (!extract_host_port(connect_str, &host, &port_str)) goto bad; } @@ -1456,7 +1454,7 @@ int MAIN(int argc, char **argv) re_start: - if (init_client(&s, host, port, socket_type) == 0) { + if (init_client(&s, host, port_str, socket_type) == 0) { BIO_printf(bio_err, "connect:errno=%d\n", get_last_socket_error()); SHUTDOWN(s); goto end; --- a/apps/s_server.c +++ b/apps/s_server.c @@ -1093,7 +1093,7 @@ int MAIN(int argc, char *argv[]) { X509_VERIFY_PARAM *vpm = NULL; int badarg = 0; - short port = PORT; + char *port_str = PORT_STR; char *CApath = NULL, *CAfile = NULL; char *chCApath = NULL, *chCAfile = NULL; char *vfyCApath = NULL, *vfyCAfile = NULL; @@ -1180,7 +1180,8 @@ int MAIN(int argc, char *argv[]) if ((strcmp(*argv, "-port") == 0) || (strcmp(*argv, "-accept") == 0)) { if (--argc < 1) goto bad; - if (!extract_port(*(++argv), &port)) + port_str = *(++argv); + if (port_str == NULL || *port_str == '\0') goto bad; } else if (strcmp(*argv, "-naccept") == 0) { if (--argc < 1) @@ -2056,13 +2057,13 @@ int MAIN(int argc, char *argv[]) BIO_printf(bio_s_out, "ACCEPT\n"); (void)BIO_flush(bio_s_out); if (rev) - do_server(port, socket_type, &accept_socket, rev_body, context, + do_server(port_str, socket_type, &accept_socket, rev_body, context, naccept); else if (www) - do_server(port, socket_type, &accept_socket, www_body, context, + do_server(port_str, socket_type, &accept_socket, www_body, context, naccept); else - do_server(port, socket_type, &accept_socket, sv_body, context, + do_server(port_str, socket_type, &accept_socket, sv_body, context, naccept); print_stats(bio_s_out, ctx); ret = 0; --- a/apps/s_socket.c +++ b/apps/s_socket.c @@ -106,9 +106,7 @@ static struct hostent *GetHostByName(char *name); static void ssl_sock_cleanup(void); # endif static int ssl_sock_init(void); -static int init_client_ip(int *sock, unsigned char ip[4], int port, int type); -static int init_server(int *sock, int port, int type); -static int init_server_long(int *sock, int port, char *ip, int type); +static int init_server(int *sock, char *port, int type); static int do_accept(int acc_sock, int *sock, char **host); static int host_ip(char *str, unsigned char ip[4]); @@ -231,65 +229,66 @@ static int ssl_sock_init(void) return (1); } -int init_client(int *sock, char *host, int port, int type) +int init_client(int *sock, char *host, char *port, int type) { - unsigned char ip[4]; - - memset(ip, '\0', sizeof ip); - if (!host_ip(host, &(ip[0]))) - return 0; - return init_client_ip(sock, ip, port, type); -} - -static int init_client_ip(int *sock, unsigned char ip[4], int port, int type) -{ - unsigned long addr; - struct sockaddr_in them; - int s, i; + struct addrinfo *res, *res0, hints; + char *failed_call = NULL; + int s; + int e; if (!ssl_sock_init()) return (0); - memset((char *)&them, 0, sizeof(them)); - them.sin_family = AF_INET; - them.sin_port = htons((unsigned short)port); - addr = (unsigned long) - ((unsigned long)ip[0] << 24L) | - ((unsigned long)ip[1] << 16L) | - ((unsigned long)ip[2] << 8L) | ((unsigned long)ip[3]); - them.sin_addr.s_addr = htonl(addr); - - if (type == SOCK_STREAM) - s = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL); - else /* ( type == SOCK_DGRAM) */ - s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + memset(&hints, '\0', sizeof(hints)); + hints.ai_socktype = type; + hints.ai_flags = AI_ADDRCONFIG; - if (s == INVALID_SOCKET) { - perror("socket"); + e = getaddrinfo(host, port, &hints, &res); + if (e) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(e)); + if (e == EAI_SYSTEM) + perror("getaddrinfo"); return (0); } + + res0 = res; + while (res) { + s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (s == INVALID_SOCKET) { + failed_call = "socket"; + goto nextres; + } # if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE) - if (type == SOCK_STREAM) { - i = 0; - i = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof(i)); - if (i < 0) { - closesocket(s); - perror("keepalive"); - return (0); + if (type == SOCK_STREAM) { + int i = 0; + i = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, + (char *)&i, sizeof(i)); + if (i < 0) { + failed_call = "keepalive"; + goto nextres; + } } - } # endif + if (connect(s, (struct sockaddr *)res->ai_addr, res->ai_addrlen) == 0) { + freeaddrinfo(res0); + *sock = s; + return (1); + } - if (connect(s, (struct sockaddr *)&them, sizeof(them)) == -1) { - closesocket(s); - perror("connect"); - return (0); + failed_call = "socket"; + nextres: + if (s != INVALID_SOCKET) + close(s); + res = res->ai_next; } - *sock = s; - return (1); + freeaddrinfo(res0); + closesocket(s); + + perror(failed_call); + return (0); } -int do_server(int port, int type, int *ret, +int do_server(char *port, int type, int *ret, int (*cb) (char *hostname, int s, int stype, unsigned char *context), unsigned char *context, int naccept) @@ -328,69 +327,89 @@ int do_server(int port, int type, int *ret, } } -static int init_server_long(int *sock, int port, char *ip, int type) +static int init_server(int *sock, char *port, int type) { - int ret = 0; - struct sockaddr_in server; - int s = -1; + struct addrinfo *res, *res0 = NULL, hints; + char *failed_call = NULL; + int s = INVALID_SOCKET; + int e; if (!ssl_sock_init()) return (0); - memset((char *)&server, 0, sizeof(server)); - server.sin_family = AF_INET; - server.sin_port = htons((unsigned short)port); - if (ip == NULL) - server.sin_addr.s_addr = INADDR_ANY; - else -/* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */ -# ifndef BIT_FIELD_LIMITS - memcpy(&server.sin_addr.s_addr, ip, 4); -# else - memcpy(&server.sin_addr, ip, 4); -# endif - - if (type == SOCK_STREAM) - s = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL); - else /* type == SOCK_DGRAM */ - s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + memset(&hints, '\0', sizeof(hints)); + hints.ai_family = AF_INET6; + tryipv4: + hints.ai_socktype = type; + hints.ai_flags = AI_PASSIVE; + + e = getaddrinfo(NULL, port, &hints, &res); + if (e) { + if (hints.ai_family == AF_INET) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(e)); + if (e == EAI_SYSTEM) + perror("getaddrinfo"); + return (0); + } else + res = NULL; + } - if (s == INVALID_SOCKET) - goto err; + res0 = res; + while (res) { + s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (s == INVALID_SOCKET) { + failed_call = "socket"; + goto nextres; + } + if (hints.ai_family == AF_INET6) { + int j = 0; + setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&j, sizeof j); + } # if defined SOL_SOCKET && defined SO_REUSEADDR - { - int j = 1; - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&j, sizeof j); - } -# endif - if (bind(s, (struct sockaddr *)&server, sizeof(server)) == -1) { -# ifndef OPENSSL_SYS_WINDOWS - perror("bind"); + { + int j = 1; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&j, sizeof j); + } # endif - goto err; + + if (bind(s, (struct sockaddr *)res->ai_addr, res->ai_addrlen) == -1) { + failed_call = "bind"; + goto nextres; + } + if (type == SOCK_STREAM && listen(s, 128) == -1) { + failed_call = "listen"; + goto nextres; + } + + *sock = s; + return (1); + + nextres: + if (s != INVALID_SOCKET) + close(s); + res = res->ai_next; } - /* Make it 128 for linux */ - if (type == SOCK_STREAM && listen(s, 128) == -1) - goto err; - *sock = s; - ret = 1; - err: - if ((ret == 0) && (s != -1)) { - SHUTDOWN(s); + if (res0) + freeaddrinfo(res0); + + if (s == INVALID_SOCKET) { + if (hints.ai_family == AF_INET6) { + hints.ai_family = AF_INET; + goto tryipv4; + } + perror("socket"); + return (0); } - return (ret); -} -static int init_server(int *sock, int port, int type) -{ - return (init_server_long(sock, port, NULL, type)); + perror(failed_call); + return (0); } static int do_accept(int acc_sock, int *sock, char **host) { + static struct sockaddr_storage from; + char buffer[NI_MAXHOST]; int ret; - struct hostent *h1, *h2; - static struct sockaddr_in from; int len; /* struct linger ling; */ @@ -432,134 +451,60 @@ static int do_accept(int acc_sock, int *sock, char **host) ling.l_onoff=1; ling.l_linger=0; i=setsockopt(ret,SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling)); - if (i < 0) { perror("linger"); return(0); } + if (i < 0) { closesocket(ret); perror("linger"); return(0); } i=0; i=setsockopt(ret,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i)); - if (i < 0) { perror("keepalive"); return(0); } + if (i < 0) { closesocket(ret); perror("keepalive"); return(0); } */ if (host == NULL) goto end; -# ifndef BIT_FIELD_LIMITS - /* I should use WSAAsyncGetHostByName() under windows */ - h1 = gethostbyaddr((char *)&from.sin_addr.s_addr, - sizeof(from.sin_addr.s_addr), AF_INET); -# else - h1 = gethostbyaddr((char *)&from.sin_addr, - sizeof(struct in_addr), AF_INET); -# endif - if (h1 == NULL) { - BIO_printf(bio_err, "bad gethostbyaddr\n"); + + if (getnameinfo((struct sockaddr *)&from, sizeof(from), + buffer, sizeof(buffer), NULL, 0, 0)) { + BIO_printf(bio_err, "getnameinfo failed\n"); *host = NULL; /* return(0); */ } else { - if ((*host = (char *)OPENSSL_malloc(strlen(h1->h_name) + 1)) == NULL) { + if ((*host = (char *)OPENSSL_malloc(strlen(buffer) + 1)) == NULL) { perror("OPENSSL_malloc"); closesocket(ret); return (0); } - BUF_strlcpy(*host, h1->h_name, strlen(h1->h_name) + 1); - - h2 = GetHostByName(*host); - if (h2 == NULL) { - BIO_printf(bio_err, "gethostbyname failure\n"); - closesocket(ret); - return (0); - } - if (h2->h_addrtype != AF_INET) { - BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n"); - closesocket(ret); - return (0); - } + strcpy(*host, buffer); } end: *sock = ret; return (1); } -int extract_host_port(char *str, char **host_ptr, unsigned char *ip, - short *port_ptr) +int extract_host_port(char *str, char **host_ptr, char **port_ptr) { - char *h, *p; - - h = str; - p = strchr(str, ':'); + char *h, *p, *x; + + x = h = str; + if (*h == '[') { + h++; + p = strchr(h, ']'); + if (p == NULL) { + BIO_printf(bio_err, "no ending bracket for IPv6 address\n"); + return (0); + } + *(p++) = '\0'; + x = p; + } + p = strchr(x, ':'); if (p == NULL) { BIO_printf(bio_err, "no port defined\n"); return (0); } *(p++) = '\0'; - if ((ip != NULL) && !host_ip(str, ip)) - goto err; if (host_ptr != NULL) *host_ptr = h; + if (port_ptr != NULL) + *port_ptr = p; - if (!extract_port(p, port_ptr)) - goto err; - return (1); - err: - return (0); -} - -static int host_ip(char *str, unsigned char ip[4]) -{ - unsigned int in[4]; - int i; - - if (sscanf(str, "%u.%u.%u.%u", &(in[0]), &(in[1]), &(in[2]), &(in[3])) == - 4) { - for (i = 0; i < 4; i++) - if (in[i] > 255) { - BIO_printf(bio_err, "invalid IP address\n"); - goto err; - } - ip[0] = in[0]; - ip[1] = in[1]; - ip[2] = in[2]; - ip[3] = in[3]; - } else { /* do a gethostbyname */ - struct hostent *he; - - if (!ssl_sock_init()) - return (0); - - he = GetHostByName(str); - if (he == NULL) { - BIO_printf(bio_err, "gethostbyname failure\n"); - goto err; - } - /* cast to short because of win16 winsock definition */ - if ((short)he->h_addrtype != AF_INET) { - BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n"); - return (0); - } - ip[0] = he->h_addr_list[0][0]; - ip[1] = he->h_addr_list[0][1]; - ip[2] = he->h_addr_list[0][2]; - ip[3] = he->h_addr_list[0][3]; - } - return (1); - err: - return (0); -} - -int extract_port(char *str, short *port_ptr) -{ - int i; - struct servent *s; - - i = atoi(str); - if (i != 0) - *port_ptr = (unsigned short)i; - else { - s = getservbyname(str, "tcp"); - if (s == NULL) { - BIO_printf(bio_err, "getservbyname failure for %s\n", str); - return (0); - } - *port_ptr = ntohs((unsigned short)s->s_port); - } return (1); }