[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: How do we best approach IPv6 for OpenSSL?



Hello again,

tisdag den 29 juni 2010 klockan 21:35 skrev Hagen Paul Pfeifer detta:
> * Mats Erik Andersson | 2010-06-29 20:04:07 [+0200]:
> 
> >in that direction, but in comparison, my presently
> >oldest OpenBSD runs version 4.4, and there IPv6
> >is fully applied on top of OpenSSL.
> 
> Well, bio_* to some extends is already IPv6 aware (configured with
> OPENSSL_USE_IPV6) other components (s_{client, server}) still lacks IPv6
> support. Mainly because changes must be multi-platform aware and it is still
> horrible to implement IPv6 under M$. So changes for UNIX derived OS may be the
> effort of several hours, where for M$ and other platforms the effort is not to
> underestimate.
> 
> Not sure if there is currently any upstream effort. I do not track the actual
> openssl development.
> 

I can offer for testing a patch that allows the subcommand "openssl s_client"
to use IPv4 as well as IPv6. This also implements switches '-4' and '-6' for
cases where on wants to restrict to a single family. Of course, this patch
is intended for the Debian package, but I have not modified any platform
dependent code as of yet.

Observe that any host that simply drops a connection attempt, instead of
denying access by an ICMP[v6] return message, will trap the client with
IPv4 as well as with IPv6, so do not blame this behaviour on my patch.

It would be an elementary step to modify the code further to allow
symbolic service names, in addition to numerical ports.


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 subcommand "s_client".
 A straightforward migration to getaddrinfo(3) is sufficient to
 let the service "openssl s_client" use IPv6 as well as IPv4 as
 address family.
 .
 The additional command line switches '-4' and '-6' are able to
 limit address resolving to a single family.
Author: Mats Erik Andersson <debian@gisladisker.se>
Forwarded: no
Last-Update: 2010-06-30
--- 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/apps/s_apps.h	2009-09-04 19:53:29.000000000 +0200
+++ openssl-0.9.8o/apps/s_apps.h	2010-06-30 14:43:48.000000000 +0200
@@ -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_socket.c	2009-08-26 13:21:57.000000000 +0200
+++ openssl-0.9.8o/apps/s_socket.c	2010-06-30 16:08:12.000000000 +0200
@@ -102,7 +102,7 @@ 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_client_ip(int *sock, char *host, int port, int type, int af);
 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 do_accept(int acc_sock, int *sock, char **host);
@@ -234,57 +234,75 @@ 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)
@@ -481,7 +499,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 +540,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 +553,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];

Attachment: signature.asc
Description: Digital signature


Reply to: