Package: openssl
Version: 0.9.8o-1
Severity: wishlist
Tags: ipv6 patch

May I propose that the two applications "s_client" and "s_server"
be made IPv6-capable. I supply a patch that accomplishes this.

The resulting software has been tested with invokations like

   ./apps/openssl s_client -connect ipv6.google.com:https

   ./apps/openssl s_client -connect 2a00:1450:8003::6a:443

and

   ./apps/openssl s_server -cert path/server.pem -www -accept https -4

   ./apps/openssl s_server -cert path/server.pem -www -accept https -6

to full satisfaction.

OpenBSD has for some years patched "s_client" to be IPv6-capable,
but FreeBSD has not done so. Neither of them have touched "s_server".

Keeping in mind that upstream expressedly states "s_client" and "s_server"
to be testing tools, very seldomly touched upon, I see some merit in expanding
them to be fit for IPv6, even though only for Debian GNU/Linux. Clearly,
"certtool/gnutls-bin" offer these testing tools already, but I imagine many
network administrators or developers that are more used to fall back on OpenSSL
for testing.

An incorporation of the present suggestion would comply to the release goal
for Squeeze of improving IPv6 support.

An argument against this wishlist bug, would be that Debian tries to fiddle
as little as possible with non-dormant upstream source code.


Best regards,

Mats Erik Andersson, fil. dr
2459 41E9 C420 3F6D F68B  2E88 F768 4541 F25B 5D41

Abonnerar på: debian-mentors, debian-devel-games, debian-perl,
              debian-ipv6, debian-qa
Description: Implement IPv6 transport for the "s_client" and "s_server.
 A straightforward migration to getaddrinfo(3) is sufficient to
 let the service "openssl s_client" use IPv6 as well as IPv4 as
 address family.
 .
 An analysis of unused code functionality for the server parts
 as contained in "apps/s_socket.c", allows a fairly natural
 migration to allow also "s_server" to use IPv6 as well as IPv4,
 one at a time, as listening socket.
 .
 The additional command line switches '-4' and '-6' are able to
 limit address resolving to a single family.
Author: Mats Erik Andersson <deb...@gisladisker.se>
Forwarded: no
Last-Update: 2010-07-18
--- openssl-0.9.8o.orig/apps/s_apps.h	2009-09-04 19:53:29.000000000 +0200
+++ openssl-0.9.8o/apps/s_apps.h	2010-07-02 12:42:03.000000000 +0200
@@ -148,7 +148,7 @@ typedef fd_mask fd_set;
 #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 family);
 #ifdef HEADER_X509_H
 int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx);
 #endif
@@ -156,7 +156,7 @@ 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 af);
 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-0.9.8o.orig/apps/s_client.c	2009-12-16 21:34:19.000000000 +0100
+++ openssl-0.9.8o/apps/s_client.c	2010-06-30 15:08:35.000000000 +0200
@@ -192,6 +192,8 @@ 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 address for host\n");
+	BIO_printf(bio_err," -6             - use IPv6 address for host\n");
 	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);
@@ -296,6 +298,7 @@ int MAIN(int argc, char **argv)
 	int sbuf_len,sbuf_off;
 	fd_set readfds,writefds;
 	short port=PORT;
+	int family=AF_UNSPEC;
 	int full_log=1;
 	char *host=SSL_HOST_NAME;
 	char *cert_file=NULL,*key_file=NULL;
@@ -396,6 +399,10 @@ int MAIN(int argc, char **argv)
 			port=atoi(*(++argv));
 			if (port == 0) goto bad;
 			}
+		else if (strcmp(*argv,"-6") == 0)
+			family = AF_INET6;
+		else if (strcmp(*argv,"-4") == 0)
+			family = AF_INET;
 		else if (strcmp(*argv,"-connect") == 0)
 			{
 			if (--argc < 1) goto bad;
@@ -806,7 +813,7 @@ bad:
 
 re_start:
 
-	if (init_client(&s,host,port,sock_type) == 0)
+	if (init_client(&s,host,port,sock_type,family) == 0)
 		{
 		BIO_printf(bio_err,"connect:errno=%d\n",get_last_socket_error());
 		SHUTDOWN(s);
--- openssl-0.9.8o.orig/apps/s_server.c	2010-01-24 14:52:38.000000000 +0100
+++ openssl-0.9.8o/apps/s_server.c	2010-07-02 12:41:21.000000000 +0200
@@ -326,6 +326,8 @@ static void sv_usage(void)
 	{
 	BIO_printf(bio_err,"usage: s_server [args ...]\n");
 	BIO_printf(bio_err,"\n");
+	BIO_printf(bio_err," -4            - use IPv4 sockets\n");
+	BIO_printf(bio_err," -6            - use IPv6 sockets\n");
 	BIO_printf(bio_err," -accept arg   - port to accept on (default is %d)\n",PORT);
 	BIO_printf(bio_err," -context arg  - set session ID context\n");
 	BIO_printf(bio_err," -verify arg   - turn on peer certificate verification\n");
@@ -751,6 +753,7 @@ int MAIN(int argc, char *argv[])
 	X509_STORE *store = NULL;
 	int vflags = 0;
 	short port=PORT;
+	int family=AF_UNSPEC;
 	char *CApath=NULL,*CAfile=NULL;
 	unsigned char *context = NULL;
 	char *dhfile = NULL;
@@ -821,6 +824,10 @@ int MAIN(int argc, char *argv[])
 			if (!extract_port(*(++argv),&port))
 				goto bad;
 			}
+		else if (strcmp(*argv,"-4") == 0)
+			family = AF_INET;
+		else if (strcmp(*argv,"-6") == 0)
+			family = AF_INET6;
 		else if	(strcmp(*argv,"-verify") == 0)
 			{
 			s_server_verify=SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE;
@@ -1536,9 +1543,9 @@ bad:
 		}
 	BIO_printf(bio_s_out,"ACCEPT\n");
 	if (www)
-		do_server(port,socket_type,&accept_socket,www_body, context);
+		do_server(port,socket_type,&accept_socket,www_body, context, family);
 	else
-		do_server(port,socket_type,&accept_socket,sv_body, context);
+		do_server(port,socket_type,&accept_socket,sv_body, context, family);
 	print_stats(bio_s_out,ctx);
 	ret=0;
 end:
--- openssl-0.9.8o.orig/apps/s_socket.c	2009-08-26 13:21:57.000000000 +0200
+++ openssl-0.9.8o/apps/s_socket.c	2010-07-18 11:49:29.000000000 +0200
@@ -102,9 +102,9 @@ static struct hostent *GetHostByName(cha
 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, char *host, int port, int type, int af);
+static int init_server(int *sock, int port, int type, int af);
+static int init_server_long(int *sock, int port,char *ip, int type, int af);
 static int do_accept(int acc_sock, int *sock, char **host);
 static int host_ip(char *str, unsigned char ip[4]);
 
@@ -234,67 +234,85 @@ 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 af)
 	{
-	unsigned char ip[4];
-	short p=0;
-
-	if (!host_ip(host,&(ip[0])))
-		{
-		return(0);
-		}
-	if (p != 0) port=p;
-	return(init_client_ip(sock,ip,port,type));
+	/* Only a wrapper functionality remains. */
+	return(init_client_ip(sock,host,port,type,af));
 	}
 
-static int init_client_ip(int *sock, unsigned char ip[4], int port, int type)
+static int init_client_ip(int *sock, char *host, int port, int type, int af)
 	{
 	unsigned long addr;
-	struct sockaddr_in them;
-	int s,i;
+	struct sockaddr_storage them;
+	struct addrinfo hints, *ai, *aiptr;
+	char portstr[12];
+	int s, ret;
 
 	if (!ssl_sock_init()) return(0);
 
+	snprintf(portstr, sizeof(portstr), "%u", port);
+
 	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);
-			
-	if (s == INVALID_SOCKET) { perror("socket"); return(0); }
+	memset(&hints, '\0', sizeof(hints));
+	hints.ai_family = af;
+	hints.ai_socktype = type;
+	hints.ai_flags = AI_ADDRCONFIG;
 
-#ifndef OPENSSL_SYS_MPE
-	if (type == SOCK_STREAM)
+	if ((ret = getaddrinfo(host, portstr, &hints, &aiptr)))
 		{
-		i=0;
-		i=setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
-		if (i < 0) { perror("keepalive"); return(0); }
+		/* Lookup failed. */
+		fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(ret));
+		return(0);
 		}
+
+	for (ai = aiptr; ai != NULL; ai = ai->ai_next)
+		{
+		if ( (s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0 )
+			continue;
+
+#ifndef OPENSSL_SYS_MPE
+		if (type == SOCK_STREAM)
+			{
+			int i=0;
+			i=setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
+			if (i < 0)
+				{
+				close(s);
+				continue;
+				}
+			}
 #endif
 
-	if (connect(s,(struct sockaddr *)&them,sizeof(them)) == -1)
-		{ close(s); perror("connect"); return(0); }
-	*sock=s;
-	return(1);
+		if ( connect(s, ai->ai_addr, ai->ai_addrlen) < 0 )
+			{
+			close(s);
+			continue;
+			}
+
+		/* Connection has been established. */
+		break;
+		}
+
+	freeaddrinfo(aiptr);
+
+	if (ai)
+		{
+		/* Success. */
+		*sock = s;
+		return(1);
+		}
+	else
+		return(0);
 	}
 
-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 family)
 	{
 	int sock;
 	char *name = NULL;
 	int accept_socket;
 	int i;
 
-	if (!init_server(&accept_socket,port,type)) return(0);
+	if (!init_server(&accept_socket,port,type,family)) return(0);
 
 	if (ret != NULL)
 		{
@@ -325,52 +343,66 @@ 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 af)
 	{
-	int ret=0;
-	struct sockaddr_in server;
+	int ret=0, rc;
+	char portstr[12];
+	struct addrinfo hints, *ai, *aiptr;
 	int s= -1,i;
 
 	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 (beck...@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);
+	snprintf(portstr, sizeof(portstr), "%u", port);
 
-	if (s == INVALID_SOCKET) goto err;
-#if defined SOL_SOCKET && defined SO_REUSEADDR
+	memset(&hints, '\0', sizeof(hints));
+	hints.ai_family = af;
+	hints.ai_socktype = type;
+	hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV | AI_ADDRCONFIG;
+
+	if ( (rc = getaddrinfo(NULL, portstr, &hints, &aiptr)) )
 		{
-		int j = 1;
-		setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
-			   (void *) &j, sizeof j);
+		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rc));
+		goto err;
 		}
-#endif
-	if (bind(s,(struct sockaddr *)&server,sizeof(server)) == -1)
+	else
 		{
-#ifndef OPENSSL_SYS_WINDOWS
-		perror("bind");
+		for (ai = aiptr; ai; ai = ai->ai_next)
+			{
+			if ( (s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0 )
+				continue;
+
+#if defined SOL_SOCKET && defined SO_REUSEADDR
+			{
+			int j = 1;
+			setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+				   (void *) &j, sizeof j);
+			}
 #endif
-		goto err;
+			if (bind(s, ai->ai_addr, ai->ai_addrlen) < 0)
+				{
+				close(s);
+				s = -1;
+				continue;
+				}
+			/* Make it 128 for linux */
+			if (type==SOCK_STREAM && listen(s,128) == -1)
+				{
+				close(s);
+				s = -1;
+				continue;
+			}
+			/* Successfully listening. */
+			break;
+			}
+		freeaddrinfo(aiptr);
+		if (ai)
+			{
+			/* Success. */
+			i=0;
+			*sock=s;
+			ret=1;
+			}
 		}
-	/* Make it 128 for linux */
-	if (type==SOCK_STREAM && listen(s,128) == -1) goto err;
-	i=0;
-	*sock=s;
-	ret=1;
 err:
 	if ((ret == 0) && (s != -1))
 		{
@@ -379,16 +411,16 @@ err:
 	return(ret);
 	}
 
-static int init_server(int *sock, int port, int type)
+static int init_server(int *sock, int port, int type, int family)
 	{
-	return(init_server_long(sock, port, NULL, type));
+	return(init_server_long(sock, port, NULL, type, family));
 	}
 
 static int do_accept(int acc_sock, int *sock, char **host)
 	{
-	int ret,i;
-	struct hostent *h1,*h2;
-	static struct sockaddr_in from;
+	int ret,i,rc;
+	struct hostent *h2;
+	static struct sockaddr_storage from;
 	int len;
 /*	struct linger ling; */
 
@@ -434,41 +466,34 @@ redoit:
 */
 
 	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)
+
+	if ((*host=(char *)OPENSSL_malloc(INET_ADDRSTRLEN)) == NULL)
+		{
+		perror("OPENSSL_malloc");
+		return(0);
+		}
+	if ((rc = getnameinfo((struct sockaddr *) &from, len, *host, INET6_ADDRSTRLEN, NULL, 0, 0)))
 		{
-		BIO_printf(bio_err,"bad gethostbyaddr\n");
+		fprintf(stderr, "getnameinfo(): %s\n", gai_strerror(rc));
+		OPENSSL_free(*host);
 		*host=NULL;
-		/* return(0); */
 		}
 	else
 		{
-		if ((*host=(char *)OPENSSL_malloc(strlen(h1->h_name)+1)) == NULL)
-			{
-			perror("OPENSSL_malloc");
-			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");
 			return(0);
 			}
+#if 0
 		i=0;
 		if (h2->h_addrtype != AF_INET)
 			{
 			BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
 			return(0);
 			}
+#endif
 		}
 end:
 	*sock=ret;
@@ -481,7 +506,7 @@ 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");
@@ -522,7 +547,8 @@ static int host_ip(char *str, unsigned c
 		{ /* do a gethostbyname */
 		struct hostent *he;
 
-		if (!ssl_sock_init()) return(0);
+		if (!ssl_sock_init())
+			goto err;
 
 		he=GetHostByName(str);
 		if (he == NULL)
@@ -534,7 +560,7 @@ static int host_ip(char *str, unsigned c
 		if ((short)he->h_addrtype != AF_INET)
 			{
 			BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
-			return(0);
+			goto err;
 			}
 		ip[0]=he->h_addr_list[0][0];
 		ip[1]=he->h_addr_list[0][1];
--- openssl-0.9.8o.orig/doc/apps/s_client.pod	2007-08-23 14:16:03.000000000 +0200
+++ openssl-0.9.8o/doc/apps/s_client.pod	2010-06-30 15:46:39.000000000 +0200
@@ -8,6 +8,8 @@ s_client - SSL/TLS client program
 =head1 SYNOPSIS
 
 B<openssl> B<s_client>
+[B<-4>]
+[B<-6>]
 [B<-connect host:port>]
 [B<-verify depth>]
 [B<-cert filename>]
@@ -54,6 +56,14 @@ SSL servers.
 
 =over 4
 
+=item B<-4>
+
+Use only IPv4 addresses when resolving the host name.
+
+=item B<-6>
+
+Use only IPv6 addresses when resolving the host name.
+
 =item B<-connect host:port>
 
 This specifies the host and optional port to connect to. If not specified
--- openssl-0.9.8o.orig/doc/apps/s_server.pod	2008-05-19 09:52:17.000000000 +0200
+++ openssl-0.9.8o/doc/apps/s_server.pod	2010-07-02 16:45:01.000000000 +0200
@@ -8,6 +8,8 @@ s_server - SSL/TLS server program
 =head1 SYNOPSIS
 
 B<openssl> B<s_server>
+[B<-4>]
+[B<-6>]
 [B<-accept port>]
 [B<-context id>]
 [B<-verify depth>]
@@ -64,6 +66,14 @@ for connections on a given port using SS
 
 =over 4
 
+=item B<-4>
+
+let the server listen using IPv4.
+
+=item B<-6>
+
+let the server listen using IPv6.
+
 =item B<-accept port>
 
 the TCP port to listen on for connections. If not specified 4433 is used.

Attachment: signature.asc
Description: Digital signature

Reply via email to