http://rt.openssl.org/Ticket/Display.html?id=2051&user=guest&pass=guest Forward ported from openssl-1.0.1e-ipv6.patch Signed-off-by: Lars Wendler --- openssl-1.0.1h/apps/s_apps.h +++ openssl-1.0.1h/apps/s_apps.h @@ -148,7 +148,7 @@ #define PORT_STR "4433" #define PROTOCOL "tcp" -int do_server(int port, int type, int *ret, int (*cb) (char *hostname, int s, unsigned char *context), unsigned char *context); +int do_server(int port, int type, int *ret, int (*cb) (char *hostname, int s, 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 @@ -156,7 +156,7 @@ 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,short *p); --- openssl-1.0.1h/apps/s_client.c +++ openssl-1.0.1h/apps/s_client.c @@ -285,6 +285,10 @@ { 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," -connect host:port - who to connect to (default is %s:%s)\n",SSL_HOST_NAME,PORT_STR); @@ -568,6 +572,7 @@ 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; @@ -613,7 +618,11 @@ #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 enable_timeouts = 0 ; long socket_mtu = 0; @@ -628,6 +637,12 @@ 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; @@ -949,6 +964,18 @@ 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) { @@ -1260,7 +1287,7 @@ 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); @@ -1286,7 +1313,7 @@ { 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()); --- openssl-1.0.1h/apps/s_server.c +++ openssl-1.0.1h/apps/s_server.c @@ -560,6 +560,10 @@ BIO_printf(bio_err," -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," -keymatexportlen len - Export len bytes of keying material (default 20)\n"); } @@ -947,6 +951,7 @@ 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; @@ -975,6 +980,12 @@ #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; @@ -1323,6 +1334,18 @@ 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) { @@ -1881,9 +1904,9 @@ 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.1h/apps/s_socket.c +++ openssl-1.0.1h/apps/s_socket.c @@ -97,16 +97,16 @@ #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 */ @@ -234,38 +234,68 @@ 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"); return(0); } @@ -277,29 +307,27 @@ if (i < 0) { closesocket(s); perror("keepalive"); return(0); } } #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); } *sock=s; return(1); } -int do_server(int port, int type, int *ret, int (*cb)(char *hostname, int s, unsigned char *context), unsigned char *context) +int do_server(int port, int type, int *ret, int (*cb)(char *hostname, int s, 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)) return(0); - + if (!init_server(&accept_socket,port,type, use_ipv4, use_ipv6)) return(0); if (ret != NULL) { *ret=accept_socket; /* return(1);*/ } - for (;;) - { + for (;;) + { if (type==SOCK_STREAM) { if (do_accept(accept_socket,&sock,&name) == 0) @@ -322,41 +350,88 @@ } } -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); - else /* type == SOCK_DGRAM */ - s=socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP); + if (type == SOCK_STREAM) + s=socket(domain,SOCK_STREAM,SOCKET_PROTOCOL); + else /* type == SOCK_DGRAM */ + s=socket(domain, SOCK_DGRAM,IPPROTO_UDP); if (s == INVALID_SOCKET) goto err; #if defined SOL_SOCKET && defined SO_REUSEADDR + { + int j = 1; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (void *) &j, sizeof j); + } +#endif +#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 { - int j = 1; - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - (void *) &j, sizeof j); + 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,sizeof(server)) == -1) + if (bind(s, (struct sockaddr *)&server, addr_len) == -1) { #ifndef OPENSSL_SYS_WINDOWS perror("bind"); @@ -375,16 +450,23 @@ 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; - static struct sockaddr_in from; +#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 + struct sockaddr_in from; + struct sockaddr_in *from_in = &from; +#endif int len; /* struct linger ling; */ @@ -431,13 +513,23 @@ */ 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); + /* I should use WSAAsyncGetHostByName() under windows */ + 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, - sizeof(struct in_addr),AF_INET); + 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) { @@ -455,16 +547,25 @@ } 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) +#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 is not AF_INET\n"); + BIO_printf(bio_err,"gethostbyname addr address is not correct\n"); closesocket(ret); return(0); } @@ -480,7 +581,7 @@ char *h,*p; h=str; - p=strchr(str,':'); + p=strrchr(str,':'); if (p == NULL) { BIO_printf(bio_err,"no port defined\n"); @@ -488,7 +589,7 @@ } *(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,48 +600,58 @@ 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 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]; - } + 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) + if ((short)he->h_addrtype != domain) { - BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n"); + 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); } @@ -577,7 +688,7 @@ 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; @@ -592,14 +703,20 @@ } 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 */ if(strlen(name) < sizeof ghbn_cache[0].name)