http://rt.openssl.org/Ticket/Display.html?id=2051&user=guest&pass=guest Forward ported from openssl-1.0.1h-ipv6.patch Signed-off-by: Lars Wendler --- openssl-1.0.1m/apps/s_apps.h +++ openssl-1.0.1m/apps/s_apps.h @@ -153,7 +153,7 @@ typedef fd_mask fd_set; int do_server(int port, int type, int *ret, int (*cb) (char *hostname, int s, unsigned char *context), - unsigned char *context); + unsigned char *context, int use_ipv4, int use_ipv6); #ifdef HEADER_X509_H int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx); #endif @@ -161,7 +161,8 @@ int MS_CALLBACK verify_callback(int ok, int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file); int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key); #endif -int init_client(int *sock, char *server, int port, int type); +int init_client(int *sock, char *server, int port, int type, + int use_ipv4, int use_ipv6); 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, --- openssl-1.0.1m/apps/s_client.c +++ openssl-1.0.1m/apps/s_client.c @@ -299,6 +299,10 @@ static void sc_usage(void) { BIO_printf(bio_err, "usage: s_client args\n"); BIO_printf(bio_err, "\n"); + BIO_printf(bio_err," -4 - use IPv4 only\n"); +#if OPENSSL_USE_IPV6 + BIO_printf(bio_err," -6 - use IPv6 only\n"); +#endif BIO_printf(bio_err, " -host host - use -connect instead\n"); BIO_printf(bio_err, " -port port - use -connect instead\n"); BIO_printf(bio_err, @@ -629,6 +633,7 @@ int MAIN(int argc, char **argv) int sbuf_len, sbuf_off; fd_set readfds, writefds; short port = PORT; + int use_ipv4, use_ipv6; int full_log = 1; char *host = SSL_HOST_NAME; char *cert_file = NULL, *key_file = NULL; @@ -673,7 +678,11 @@ int MAIN(int argc, char **argv) #endif char *sess_in = NULL; char *sess_out = NULL; - struct sockaddr peer; +#if OPENSSL_USE_IPV6 + struct sockaddr_storage peer; +#else + struct sockaddr_in peer; +#endif int peerlen = sizeof(peer); int fallback_scsv = 0; int enable_timeouts = 0; @@ -689,6 +698,13 @@ int MAIN(int argc, char **argv) meth = SSLv23_client_method(); + use_ipv4 = 1; +#if OPENSSL_USE_IPV6 + use_ipv6 = 1; +#else + use_ipv6 = 0; +#endif + apps_startup(); c_Pause = 0; c_quiet = 0; @@ -985,6 +1001,16 @@ int MAIN(int argc, char **argv) jpake_secret = *++argv; } #endif + else if (strcmp(*argv,"-4") == 0) { + use_ipv4 = 1; + use_ipv6 = 0; + } +#if OPENSSL_USE_IPV6 + else if (strcmp(*argv,"-6") == 0) { + use_ipv4 = 0; + use_ipv6 = 1; + } +#endif #ifndef OPENSSL_NO_SRTP else if (strcmp(*argv, "-use_srtp") == 0) { if (--argc < 1) @@ -1256,7 +1282,7 @@ int MAIN(int argc, char **argv) re_start: - if (init_client(&s, host, port, socket_type) == 0) { + if (init_client(&s, host, port, socket_type, use_ipv4, use_ipv6) == 0) { BIO_printf(bio_err, "connect:errno=%d\n", get_last_socket_error()); SHUTDOWN(s); goto end; @@ -1279,7 +1305,7 @@ int MAIN(int argc, char **argv) if (SSL_version(con) == DTLS1_VERSION) { sbio = BIO_new_dgram(s, BIO_NOCLOSE); - if (getsockname(s, &peer, (void *)&peerlen) < 0) { + if (getsockname(s, (struct sockaddr *)&peer, (void *)&peerlen) < 0) { BIO_printf(bio_err, "getsockname:errno=%d\n", get_last_socket_error()); SHUTDOWN(s); --- openssl-1.0.1m/apps/s_server.c +++ openssl-1.0.1m/apps/s_server.c @@ -609,6 +609,10 @@ static void sv_usage(void) " -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n"); # endif #endif + BIO_printf(bio_err," -4 - use IPv4 only\n"); +#if OPENSSL_USE_IPV6 + BIO_printf(bio_err," -6 - use IPv6 only\n"); +#endif BIO_printf(bio_err, " -keymatexport label - Export keying material using label\n"); BIO_printf(bio_err, @@ -1003,6 +1007,7 @@ int MAIN(int argc, char *argv[]) int state = 0; const SSL_METHOD *meth = NULL; int socket_type = SOCK_STREAM; + int use_ipv4, use_ipv6; ENGINE *e = NULL; char *inrand = NULL; int s_cert_format = FORMAT_PEM, s_key_format = FORMAT_PEM; @@ -1031,6 +1036,13 @@ int MAIN(int argc, char *argv[]) #endif meth = SSLv23_server_method(); + use_ipv4 = 1; +#if OPENSSL_USE_IPV6 + use_ipv6 = 1; +#else + use_ipv6 = 0; +#endif + local_argc = argc; local_argv = argv; @@ -1356,6 +1368,16 @@ int MAIN(int argc, char *argv[]) jpake_secret = *(++argv); } #endif + else if (strcmp(*argv,"-4") == 0) { + use_ipv4 = 1; + use_ipv6 = 0; + } +#if OPENSSL_USE_IPV6 + else if (strcmp(*argv,"-6") == 0) { + use_ipv4 = 0; + use_ipv6 = 1; + } +#endif #ifndef OPENSSL_NO_SRTP else if (strcmp(*argv, "-use_srtp") == 0) { if (--argc < 1) @@ -1850,9 +1872,11 @@ int MAIN(int argc, char *argv[]) BIO_printf(bio_s_out, "ACCEPT\n"); (void)BIO_flush(bio_s_out); if (www) - do_server(port, socket_type, &accept_socket, www_body, context); + do_server(port, socket_type, &accept_socket, www_body, context, + use_ipv4, use_ipv6); else - do_server(port, socket_type, &accept_socket, sv_body, context); + do_server(port, socket_type, &accept_socket, sv_body, context, + use_ipv4, use_ipv6); print_stats(bio_s_out, ctx); ret = 0; end: --- openssl-1.0.1m/apps/s_socket.c +++ openssl-1.0.1m/apps/s_socket.c @@ -101,16 +101,16 @@ typedef unsigned int u_int; # include "netdb.h" # endif -static struct hostent *GetHostByName(char *name); +static struct hostent *GetHostByName(char *name, int domain); # if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)) 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_client_ip(int *sock, unsigned char *ip, int port, int type, int domain); +static int init_server(int *sock, int port, int type, int use_ipv4, int use_ipv6); +static int init_server_long(int *sock, int port, char *ip, int type, int use_ipv4, int use_ipv6); static int do_accept(int acc_sock, int *sock, char **host); -static int host_ip(char *str, unsigned char ip[4]); +static int host_ip(char *str, unsigned char *ip, int domain); # ifdef OPENSSL_SYS_WIN16 # define SOCKET_PROTOCOL 0 /* more microsoft stupidity */ @@ -231,38 +231,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, int port, int type, int use_ipv4, int use_ipv6) { +#if OPENSSL_USE_IPV6 + unsigned char ip[16]; +#else unsigned char ip[4]; +#endif - 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; + if (use_ipv4) + if (host_ip(host,ip,AF_INET)) + return(init_client_ip(sock,ip,port,type,AF_INET)); +#if OPENSSL_USE_IPV6 + if (use_ipv6) + if (host_ip(host,ip,AF_INET6)) + return(init_client_ip(sock,ip,port,type,AF_INET6)); +#endif + return 0; +} + +static int init_client_ip(int *sock, unsigned char ip[4], int port, int type, int domain) +{ +#if OPENSSL_USE_IPV6 + struct sockaddr_storage them; + struct sockaddr_in *them_in = (struct sockaddr_in *)&them; + struct sockaddr_in6 *them_in6 = (struct sockaddr_in6 *)&them; +#else struct sockaddr_in them; + struct sockaddr_in *them_in = &them; +#endif + socklen_t addr_len; int s, i; 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 (domain == AF_INET) { + addr_len = (socklen_t)sizeof(struct sockaddr_in); + them_in->sin_family=AF_INET; + them_in->sin_port=htons((unsigned short)port); +#ifndef BIT_FIELD_LIMITS + memcpy(&them_in->sin_addr.s_addr, ip, 4); +#else + memcpy(&them_in->sin_addr, ip, 4); +#endif + } else { +#if OPENSSL_USE_IPV6 + addr_len = (socklen_t)sizeof(struct sockaddr_in6); + them_in6->sin6_family=AF_INET6; + them_in6->sin6_port=htons((unsigned short)port); + memcpy(&(them_in6->sin6_addr), ip, sizeof(struct in6_addr)); + } +#else + return(0); +#endif if (type == SOCK_STREAM) - s = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL); + s = socket(domain, SOCK_STREAM, SOCKET_PROTOCOL); else /* ( type == SOCK_DGRAM) */ - s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + s = socket(domain, SOCK_DGRAM, IPPROTO_UDP); if (s == INVALID_SOCKET) { perror("socket"); @@ -280,7 +308,7 @@ static int init_client_ip(int *sock, uns } # endif - if (connect(s, (struct sockaddr *)&them, sizeof(them)) == -1) { + if (connect(s, (struct sockaddr *)&them, addr_len) == -1) { closesocket(s); perror("connect"); return (0); @@ -291,14 +319,14 @@ static int init_client_ip(int *sock, uns int do_server(int port, int type, int *ret, int (*cb) (char *hostname, int s, unsigned char *context), - unsigned char *context) + unsigned char *context, int use_ipv4, int use_ipv6) { int sock; char *name = NULL; int accept_socket = 0; int i; - if (!init_server(&accept_socket, port, type)) + if (!init_server(&accept_socket, port, type, use_ipv4, use_ipv6)) return (0); if (ret != NULL) { @@ -325,32 +353,45 @@ int do_server(int port, int type, int *r } } -static int init_server_long(int *sock, int port, char *ip, int type) +static int init_server_long(int *sock, int port, char *ip, int type, + int use_ipv4, int use_ipv6) { int ret = 0; + int domain; +#if OPENSSL_USE_IPV6 + struct sockaddr_storage server; + struct sockaddr_in *server_in = (struct sockaddr_in *)&server; + struct sockaddr_in6 *server_in6 = (struct sockaddr_in6 *)&server; +#else struct sockaddr_in server; + struct sockaddr_in *server_in = &server; +#endif + socklen_t addr_len; int s = -1; + if (!use_ipv4 && !use_ipv6) + goto err; +#if OPENSSL_USE_IPV6 + /* + * we are fine here + */ +#else + if (use_ipv6) + goto err; +#endif 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); +#if OPENSSL_USE_IPV6 + domain = use_ipv6 ? AF_INET6 : AF_INET; # else - memcpy(&server.sin_addr, ip, 4); + domain = AF_INET; # endif if (type == SOCK_STREAM) - s = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL); + s = socket(domain, SOCK_STREAM, SOCKET_PROTOCOL); else /* type == SOCK_DGRAM */ - s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + s = socket(domain, SOCK_DGRAM, IPPROTO_UDP); if (s == INVALID_SOCKET) goto err; @@ -360,7 +401,44 @@ static int init_server_long(int *sock, i setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&j, sizeof j); } # endif - if (bind(s, (struct sockaddr *)&server, sizeof(server)) == -1) { +#if OPENSSL_USE_IPV6 + if ((use_ipv4 == 0) && (use_ipv6 == 1)) { + const int on = 1; + + setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + (const void *) &on, sizeof(int)); + } +#endif + if (domain == AF_INET) { + addr_len = (socklen_t)sizeof(struct sockaddr_in); + memset(server_in, 0, sizeof(struct sockaddr_in)); + server_in->sin_family=AF_INET; + server_in->sin_port = htons((unsigned short)port); + if (ip == NULL) + server_in->sin_addr.s_addr = htonl(INADDR_ANY); + else +/* + * Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) + */ +#ifndef BIT_FIELD_LIMITS + memcpy(&server_in->sin_addr.s_addr, ip, 4); +#else + memcpy(&server_in->sin_addr, ip, 4); +#endif + } +#if OPENSSL_USE_IPV6 + else { + addr_len = (socklen_t)sizeof(struct sockaddr_in6); + memset(server_in6, 0, sizeof(struct sockaddr_in6)); + server_in6->sin6_family = AF_INET6; + server_in6->sin6_port = htons((unsigned short)port); + if (ip == NULL) + server_in6->sin6_addr = in6addr_any; + else + memcpy(&server_in6->sin6_addr, ip, sizeof(struct in6_addr)); + } +#endif + if (bind(s, (struct sockaddr *)&server, addr_len) == -1) { # ifndef OPENSSL_SYS_WINDOWS perror("bind"); # endif @@ -378,16 +456,24 @@ static int init_server_long(int *sock, i return (ret); } -static int init_server(int *sock, int port, int type) +static int init_server(int *sock, int port, int type, + int use_ipv4, int use_ipv6) { - return (init_server_long(sock, port, NULL, type)); + return (init_server_long(sock, port, NULL, type, use_ipv4, use_ipv6)); } static int do_accept(int acc_sock, int *sock, char **host) { int ret; struct hostent *h1, *h2; +#if OPENSSL_USE_IPV6 + struct sockaddr_storage from; + struct sockaddr_in *from_in = (struct sockaddr_in *)&from; + struct sockaddr_in6 *from_in6 = (struct sockaddr_in6 *)&from; +#else static struct sockaddr_in from; + struct sockaddr_in *from_in = &from; +#endif int len; /* struct linger ling; */ @@ -437,14 +523,24 @@ static int do_accept(int acc_sock, int * if (host == NULL) goto end; +#if OPENSSL_USE_IPV6 + if (from.ss_family == AF_INET) +#else + if (from.sin_family == AF_INET) +#endif # 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); + h1 = gethostbyaddr((char *)&from_in->sin_addr.s_addr, + sizeof(from_in->sin_addr.s_addr), AF_INET); # else - h1 = gethostbyaddr((char *)&from.sin_addr, + h1 = gethostbyaddr((char *)&from_in->sin_addr, sizeof(struct in_addr), AF_INET); # endif +#if OPENSSL_USE_IPV6 + else + h1 = gethostbyaddr((char *)&from_in6->sin6_addr, + sizeof(struct in6_addr), AF_INET6); +#endif if (h1 == NULL) { BIO_printf(bio_err, "bad gethostbyaddr\n"); *host = NULL; @@ -457,14 +553,23 @@ static int do_accept(int acc_sock, int * } BUF_strlcpy(*host, h1->h_name, strlen(h1->h_name) + 1); - h2 = GetHostByName(*host); +#if OPENSSL_USE_IPV6 + h2 = GetHostByName(*host, from.ss_family); +#else + h2 = GetHostByName(*host, from.sin_family); +#endif + 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"); +#if OPENSSL_USE_IPV6 + if (h2->h_addrtype != from.ss_family) { +#else + if (h2->h_addrtype != from.sin_family) { +#endif + BIO_printf(bio_err, "gethostbyname addr address is not correct\n"); closesocket(ret); return (0); } @@ -480,14 +585,14 @@ int extract_host_port(char *str, char ** char *h, *p; h = str; - p = strchr(str, ':'); + p = strrchr(str, ':'); if (p == NULL) { BIO_printf(bio_err, "no port defined\n"); return (0); } *(p++) = '\0'; - if ((ip != NULL) && !host_ip(str, ip)) + if ((ip != NULL) && !host_ip(str, ip, AF_INET)) goto err; if (host_ptr != NULL) *host_ptr = h; @@ -499,44 +604,54 @@ int extract_host_port(char *str, char ** return (0); } -static int host_ip(char *str, unsigned char ip[4]) +static int host_ip(char *str, unsigned char *ip, int domain) { unsigned int in[4]; + unsigned long l; int i; - if (sscanf(str, "%u.%u.%u.%u", &(in[0]), &(in[1]), &(in[2]), &(in[3])) == - 4) { + if ((domain == AF_INET) && + (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 */ + l=htonl((in[0]<<24L)|(in[1]<<16L)|(in[2]<<8L)|in[3]); + memcpy(ip, &l, 4); + return 1; + } +#if OPENSSL_USE_IPV6 + else if ((domain == AF_INET6) && + (inet_pton(AF_INET6, str, ip) == 1)) + return 1; +#endif + else { /* do a gethostbyname */ struct hostent *he; if (!ssl_sock_init()) return (0); - he = GetHostByName(str); + he = GetHostByName(str, domain); 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"); + if ((short)he->h_addrtype != domain) { + BIO_printf(bio_err, "gethostbyname addr family is not correct\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]; + if (domain == AF_INET) + memset(ip, 0, 4); +#if OPENSSL_USE_IPV6 + else + memset(ip, 0, 16); +#endif + memcpy(ip, he->h_addr_list[0], he->h_length); + return 1; } - return (1); err: return (0); } @@ -570,7 +685,7 @@ static struct ghbn_cache_st { static unsigned long ghbn_hits = 0L; static unsigned long ghbn_miss = 0L; -static struct hostent *GetHostByName(char *name) +static struct hostent *GetHostByName(char *name, int domain) { struct hostent *ret; int i, lowi = 0; @@ -582,13 +697,19 @@ static struct hostent *GetHostByName(cha lowi = i; } if (ghbn_cache[i].order > 0) { - if (strncmp(name, ghbn_cache[i].name, 128) == 0) + if ((strncmp(name, ghbn_cache[i].name, 128) == 0) && + (ghbn_cache[i].ent.h_addrtype == domain)) break; } } if (i == GHBN_NUM) { /* no hit */ ghbn_miss++; - ret = gethostbyname(name); + if (domain == AF_INET) + ret = gethostbyname(name); +#if OPENSSL_USE_IPV6 + else + ret=gethostbyname2(name, AF_INET6); +#endif if (ret == NULL) return (NULL); /* else add to cache */