Description: Implement support for IPv6.
 In addition to IPv6 code and address independ code,
 some select cleanup could not be avoided.
 .
 Every port number is internally handled in host byte order.
 All network byte order manipulations are hidden inside
 get_port() and set_port().
 .
 UNIX sockets are distinguished as 'named', 'unnamed', or 'abstract'.
 This effects printout.
Author: Mats Erik Andersson <debian@gisladisker.se>
Forwarded: no
Last-Update: 2010-04-23
diff -Naurp netpipes-4.2.debian//common.c netpipes-4.2//common.c
--- netpipes-4.2.debian//common.c
+++ netpipes-4.2//common.c
@@ -99,11 +99,35 @@ void dup_n(socket)
 
 /**********************************************************************/
 
+inline int get_port(ss)
+struct sockaddr_storage *ss;
+/* Extract port number. Return value in host byte order. */
+{
+  return ntohs((ss->ss_family == AF_INET6)
+		? ((struct sockaddr_in6 *) ss)->sin6_port
+		: ((struct sockaddr_in *) ss)->sin_port);
+} /* get_port(struct sockaddr_storage *) */
+
+void set_port(ss, port)
+struct sockaddr_storage *ss;
+int port;
+/* Set port number. Input value in host byte order. */
+{
+  switch (ss->ss_family) {
+    case AF_INET6:
+	((struct sockaddr_in6 *) ss)->sin6_port = htons(port);
+	break;
+    case AF_INET:
+    default:
+	((struct sockaddr_in *) ss)->sin_port = htons(port);
+  }
+} /* set_port(struct sockaddr_storage *, short int) */
+
 int name_to_inet_port(portname)
 char *portname;
 /* This procedure converts a character string to a port number.  It looks
    up the service by name and if there is none, then it converts the string
-   to a number with sscanf */
+   to a number with sscanf. Return value in host byte order! */
 {
   struct servent	*p;
 
@@ -123,18 +147,54 @@ char *portname;
 	  return 0;
 	}
       else
-	return htons(port);
+	return port;
     }
 }
 
-struct in_addr ** /* addr_array */
+struct sockaddr_storage ** /* addr_array */
 convert_hostname(name, count_ret)
     char	*name;
     int		*count_ret;
 {
-  struct hostent	*hp;
-  struct in_addr	**rval;
+  //struct hostent	*hp;
+  struct addrinfo hints, *ai, *aiptr;
+  struct sockaddr_storage **rval;
+  int rc, count = 0;
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME;
+  hints.ai_family = AF_UNSPEC;
+
+  if ( (rc = getaddrinfo(name, NULL, &hints, &aiptr)) == 0 ) {
+    /* Count the relevant entries. */
+    for (ai = aiptr; ai; ai = ai->ai_next)
+      if ( ai->ai_family == AF_INET6 || ai->ai_family == AF_INET )
+	++count;
+
+    if (count) {
+      int i = 0;
+
+      *count_ret = count;
+      rval = (struct sockaddr_storage **) malloc(sizeof(*rval) * (count+1));
+
+      /* Recover the found address structures. */
+      for (ai = aiptr; ai; ai = ai->ai_next) {
+	if ( ai->ai_family != AF_INET6 && ai->ai_family != AF_INET )
+	  continue;
+
+	rval[i] = (struct sockaddr_storage *) malloc(sizeof(**rval));
+	memcpy(rval[i], ai->ai_addr, ai->ai_addrlen);
+	++i;
+      }
+      rval[count] = NULL;
+    }
+    freeaddrinfo(aiptr);
 
+    if (count)
+      return rval;
+  }
+#if 0
   hp = gethostbyname(name);
   if (hp != NULL) {
     int	i;
@@ -144,20 +204,24 @@ convert_hostname(name, count_ret)
     for (i = 0; hp->h_addr_list[i]; i++)
 	{ }
     *count_ret = i;
-    rval = (struct in_addr **)malloc(sizeof(*rval) * (i+1));
+    rval = (struct sockaddr_storage **)malloc(sizeof(*rval) * (i+1));
     for (i=0; i<*count_ret; i++) {
-	rval[i] = (struct in_addr*)malloc(hp->h_length);
+	rval[i] = (struct sockaddr_storage *)malloc(hp->h_length);
 	memcpy((char*)rval[i], hp->h_addr_list[i], hp->h_length);
     }
     rval[*count_ret] = 0;
     return rval;
   } else {
+#endif
+
+#if 0
 #ifndef HAVE_INET_ATON
       int	count, len;
       unsigned int	a1,a2,a3,a4;
 #endif
-      rval = (struct in_addr**)malloc(2*sizeof(*rval));
-      rval[0] = (struct in_addr*)malloc(sizeof(struct in_addr));
+      rval = (struct sockaddr_storage **)malloc(2*sizeof(*rval));
+      rval[0] = (struct sockaddr_storage *)
+			malloc(sizeof(struct sockaddr_storage));
 #ifdef HAVE_INET_ATON
       if (0==inet_aton(name, rval[0])) {
 	  *count_ret = 0;
@@ -176,27 +240,23 @@ convert_hostname(name, count_ret)
 
       return rval;
   }
+#else
+  return NULL;
+#endif
 }
 
 
 /* print an internet host address prettily */
 void printhost(fp, addr)
      FILE	*fp;
-     struct in_addr	*addr;
+     struct sockaddr	*addr;
 {
-  struct hostent	*h;
-  char	*s,**p;
+  int rc;
+  char hostip[INET6_ADDRSTRLEN];
 
-  h = gethostbyaddr((char*)addr, sizeof(*addr),AF_INET);
-  s = (h==NULL) ? NULL : (char*)/*gratuitous cast away const*/h->h_name;
-
-  fputs(inet_ntoa(*addr), fp);
-
-  fprintf(fp, "(%s",s?s:"name unknown");
-  if (s)
-    for (p=h->h_aliases; *p; p++)
-      fprintf(fp, ",%s",*p);
-  fprintf(fp, ")");
+  rc = getnameinfo(addr, sizeof(struct sockaddr_storage),
+		  hostip, sizeof(hostip), NULL, 0, NI_NUMERICHOST);
+  fprintf(fp, "%s", hostip);
 }
 
 #ifdef NO_STRERROR
@@ -228,9 +288,9 @@ bindlocal(fd, name, addrname, domain, re
   struct sockaddr	*laddr;
   int	addrlen;
   int	countdown;
-  int	rval;
+  int	rval, port;
   
-  if (reuseaddr && domain == AF_INET) {
+  if (reuseaddr && (domain == AF_INET || domain == AF_INET6)) {
 #ifdef SO_REUSEADDR
       /* The below fix is based on articles that came from comp.sys.hp.hpux
 	 with the problem of having FIN_WAIT_2 statuses on sockets.  But even
@@ -251,39 +311,44 @@ bindlocal(fd, name, addrname, domain, re
 #endif
   }
 
-  if (domain==AF_INET)
+  if (domain==AF_INET || domain==AF_INET6)
     {
-      static struct sockaddr_in	srv;
+      static struct sockaddr_storage	srv;
       static int	initted=0;
 
       laddr = (struct sockaddr*)&srv;
       addrlen = sizeof(srv);
+      memset(&srv, 0, sizeof(srv));
 
       if (!initted) {
-	srv.sin_family = AF_INET;
+	srv.ss_family = domain;
 
 	if (addrname) {
-	    int	count;
-	    struct in_addr **addresses;
+	    int	count, j = 0;
+	    struct sockaddr_storage **addresses;
 	    addresses = convert_hostname(addrname, &count);
 	    if (addresses == 0) {
 		fprintf(stderr, "%s: Unable to convert %s to an internet address\n", progname, addrname);
 		errno=0;
 		return 0;
 	    }
-	    srv.sin_addr = *(addresses[0]);
-	} else {
-	    srv.sin_addr.s_addr = INADDR_ANY;
+	    while (addresses[j] && addresses[j]->ss_family != AF_INET
+			    && addresses[j]->ss_family != AF_INET6)
+	      ++j;
+	    if (addresses[j])
+	      memcpy(&srv, addresses[j], sizeof(srv));
 	}
 	
-	srv.sin_port = name_to_inet_port(name);
+	port = name_to_inet_port(name);
       
-	if (srv.sin_port==0)
+	if (port==0)
 	  {
 	    fprintf(stderr, "%s: port %s unknown\n", progname, name);
 	    errno = 0;
 	    return 0;
 	  }
+
+	set_port(&srv, port);
       }
       initted = 1;		/* bindlocal is only called once in
 				   each netpipes program */
@@ -307,7 +372,7 @@ bindlocal(fd, name, addrname, domain, re
       exit(EXITCODE_ARGS);
     }
   
-  countdown= (domain!=AF_INET || reuseaddr)?1:10;
+  countdown= ((domain!=AF_INET && domain!=AF_INET6)|| reuseaddr)?1:10;
   do {
     rval = bind(fd, laddr, addrlen);
     if (rval != 0)
diff -Naurp netpipes-4.2.debian//common.h netpipes-4.2//common.h
--- netpipes-4.2.debian//common.h
+++ netpipes-4.2//common.h
@@ -50,17 +50,20 @@ void dup_n(/*int socket */);
 
 /**********************************************************************/
 
+inline int get_port(/* struct sockaddr_storage * */);
+void set_port(/* struct sockaddr_storage *, int */);
+
 int name_to_inet_port(/* char* */);
 
 /**********************************************************************/
 
-struct in_addr ** /* addr_array */
+struct sockaddr_storage ** /* addr_array */
 convert_hostname(/* char *, int * */);
 
 /**********************************************************************/
 
 void
-printhost(/* struct in_addr * */);
+printhost(/* FILE, struct sockaddr * */);
 
 /**********************************************************************/
 
diff -Naurp netpipes-4.2.debian//encapsulate.c netpipes-4.2//encapsulate.c
--- netpipes-4.2.debian//encapsulate.c
+++ netpipes-4.2//encapsulate.c
@@ -181,7 +181,7 @@ static void probe_child();
 static int Im_server_p(sock_fd)
      int	sock_fd;
 {
-    struct sockaddr_in	me, him;
+    struct sockaddr_storage	me, him;
     socklen_t len;
     int i;
 
@@ -191,13 +191,24 @@ static int Im_server_p(sock_fd)
     len = sizeof(him);
     getpeername(sock_fd, (struct sockaddr*)&him, &len);
 
-    i = memcmp(&me.sin_addr, &him.sin_addr, 4);
+    if(me.ss_family != him.ss_family)
+	return (me.ss_family == AF_INET) ? 1 : 0;
+
+    if(me.ss_family == AF_INET)
+	i = memcmp(&(((struct sockaddr_in *) &me)->sin_addr),
+			&(((struct sockaddr_in *) &me)->sin_addr),
+			sizeof(struct in_addr));
+    else
+	i = memcmp(&((struct sockaddr_in6 *) &me)->sin6_addr,
+			&((struct sockaddr_in6 *) &me)->sin6_addr,
+			sizeof(struct in6_addr));
     if (i<0)
 	return 1;
     else if (i>0)
 	return 0;
 
-    if (me.sin_port<him.sin_port)
+
+    if (get_port(&me) < get_port(&him))
 	return 1;
     else
 	return 0;
diff -Naurp netpipes-4.2.debian//faucet.c netpipes-4.2//faucet.c
--- netpipes-4.2.debian//faucet.c
+++ netpipes-4.2//faucet.c
@@ -80,16 +80,11 @@ int	mastersocket;
 int	doflags=0;
 int	running=1;
 
-struct in_addr ** /* addr_array */ convert_hostname();
-
 char	*localhost=NULL;
 char	*foreignhost=NULL,*foreignport=NULL;
 int	foreignPORT;
 int	foreignCOUNT=0;
-struct in_addr	**foreignHOST;
-
-
-int name_to_inet_port();
+struct sockaddr_storage	**foreignHOST;
 
 void usage () {
   fprintf(stderr,"Usage : %s <port> (--in|--out|--err|--fd N)+ [--once] [--verb(|ose)] [--quiet] [--unix] [--foreignport <port>] [--foreignhost <inet-addr>] [--localhost <inet-addr>] [--daemon] [--serial] [--shutdown (r|w)] [--pidfile fname] [--noreuseaddr] [--backlog n] -[i][o][e][#3[,4[,5...]]][v][1][q][u][d][s] [-p <foreign port>] [-h <foreign host>] [-H <local host>] command args\n", progname);
@@ -111,7 +106,7 @@ int	reuseaddr;
 /* This procedure creates a socket and handles retries on the inet domain.
    Sockets seem to "stick" on my system (SunOS [43].x) */
 {
-  int	sock;
+  int	sock, zero = 0;
   int	family;
 
 #ifdef DOUNIX
@@ -119,7 +114,7 @@ int	reuseaddr;
     family = AF_UNIX;
   else
 #endif
-    family = AF_INET;
+    family = AF_INET6;
 
   sock = socket(family, SOCK_STREAM,
 #ifdef DOUNIX
@@ -135,6 +130,8 @@ int	reuseaddr;
       exit(EXITCODE_CONNECTION);
   }
 
+  setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero));
+
   if (!bindlocal(sock, name, localhost,
 		 family,
 		 reuseaddr)) {
@@ -146,7 +143,9 @@ int	reuseaddr;
   /* We used to ask for NOFILE (max number of open files) for the size
      of the connect queue.  Linux didn't like it (NOFILE=256) so we
      hardcoded a smaller value. */
-  listen(sock, (backlog>0 ? backlog : 5) );
+  if (listen(sock, (backlog>0 ? backlog : 5)) < 0) {
+    perror("listen failed");
+  }
 
   return(sock);
 }
@@ -173,7 +172,7 @@ authorize_address(sin)
     
     if (foreignport != NULL && 0!=strcmp(foreignport, srv->sun_path)) {
       if (doflags&DOVERBOSE) {
-	  fprintf(stderr, "%s: refusing connection from port %s\n",
+	  fprintf(stderr, "%s: Refusing UNIX connection from port %s\n",
 		  progname, srv->sun_path);
       }
       return 0;
@@ -181,29 +180,45 @@ authorize_address(sin)
   } else
 #endif
     {
-      struct sockaddr_in	*srv = (struct sockaddr_in*)sin;
+      int is_ipv6 = (sin->sa_family == AF_INET6);
+      struct sockaddr_in *srv	= (struct sockaddr_in *) sin;
+      struct sockaddr_in6 *srv6	= (struct sockaddr_in6 *) sin;
       int	i;
 
+      if (doflags&DOVERBOSE) {
+	  fprintf(stderr, "%s: Incoming connection from ", progname);
+	  printhost(stderr, sin);
+	  fprintf(stderr, " port %d\n",
+			  get_port((struct sockaddr_storage *) sin));
+      }
+
       if (foreignhost) {
 	  for (i=0; i<foreignCOUNT; i++) {
-	      if (0==memcmp(&srv->sin_addr,
-			    foreignHOST[i], sizeof(struct in_addr)))
+	      if (!is_ipv6 && foreignHOST[i]->ss_family==AF_INET &&
+			0==memcmp(&srv->sin_addr,
+				&((struct sockaddr_in *)foreignHOST[i])->sin_addr,
+				sizeof(struct in_addr)))
+		  break;
+	      if (is_ipv6 && foreignHOST[i]->ss_family==AF_INET6 &&
+		    IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr,
+			&((struct sockaddr_in6 *)foreignHOST[i])->sin6_addr))
 		  break;
 	  }
 	  if (i>=foreignCOUNT) {
 	      if (doflags&DOVERBOSE) {
-		  fprintf(stderr, "refusing connection from host ");
-		  printhost(stderr, &srv->sin_addr);
+		  fprintf(stderr, "%s: Refusing connection from host ", progname);
+		  printhost(stderr, sin);
 		  fprintf(stderr, ".\n");
 	      }
 	      return 0;
 	  }
     }
     
-    if (foreignport!=NULL && foreignPORT != srv->sin_port) {
+    if (foreignport!=NULL &&
+	! (foreignPORT == get_port((struct sockaddr_storage *) sin)) ) {
       if (doflags&DOVERBOSE) {
-	fprintf(stderr, "refusing connection from port %d.\n",
-	       ntohs(srv->sin_port));
+	fprintf(stderr, "%s: Refusing connection from port %d.\n", progname,
+		get_port((struct sockaddr_storage *) sin));
       }
       return 0;
     }
@@ -279,12 +294,13 @@ char ** argv;
 {
   int	rval, i;
   union {
-    struct sockaddr_in	in;
+    struct sockaddr	sa;
+    struct sockaddr_storage ss;
 #ifdef DOUNIX
     struct sockaddr_un	un;
 #endif
   } saddr;
-  struct sockaddr_in	*sinp = &saddr.in;
+
 #ifdef DOUNIX
   struct sockaddr_un	*sunp = &saddr.un;
 #endif
@@ -601,13 +617,12 @@ char ** argv;
     {
       socklen_t length;
     
-      length = sizeof(saddr);
-    
-      rval = accept(mastersocket,(struct sockaddr*)&saddr,&length);
+      length = sizeof(saddr.ss);
+      memset(&saddr, 0, sizeof(saddr));
+      rval = accept(mastersocket, &saddr.sa, &length);
     }
     
     if (rval<0) {
-
       if (errno==EWOULDBLOCK) {
 	  /* this can't happen, but why take chances? */
 	  fprintf(stderr, "%s: No more connections to talk to.\n",progname);
@@ -618,22 +633,25 @@ char ** argv;
       }
       continue;
     }
-    
-    if (!authorize_address(&saddr)) {
+
+    if (!authorize_address(&saddr.sa)) {
       close(rval);
       continue;
     }
-    
+
     if ( doflags&DOVERBOSE ) {
       fprintf(stderr, "%s: Got connection from ",progname);
 #ifdef DOUNIX
       if ( doflags&DOUNIX ) {
-	puts(sunp->sun_path);
+	fprintf(stderr, "UNIX %s\n",
+			(*sunp->sun_path == '\0') ? "(abstract)"
+				: (*sunp->sun_path == '/') ? sunp->sun_path
+					: "(unnamed)");
       } else
 #endif
 	  {
-	      printhost(stderr, &sinp->sin_addr);
-	      fprintf(stderr, " port %d\n",ntohs(sinp->sin_port));
+	      printhost(stderr, &saddr.sa);
+	      fprintf(stderr, " port %d\n", get_port(&saddr.ss));
 	  }
     }
     
diff -Naurp netpipes-4.2.debian//getpeername.c netpipes-4.2//getpeername.c
--- netpipes-4.2.debian//getpeername.c
+++ netpipes-4.2//getpeername.c
@@ -63,11 +63,14 @@ int main(argc, argv)
 	peer_not_sock = 0;
 
     for (i=1; i<argc; i++) {
-	if (0==strncmp(argv[i], "-verbose", strlen(argv[i]))) {
+	char *name = argv[i];
+	while( *name && *name=='-' )
+	    ++name;
+	if (0==strncmp(name, "verbose", strlen(name))) {
 	    verbose++;
-	} else if (0==strncmp(argv[i], "-sock", strlen(argv[i]))) {
+	} else if (0==strncmp(name, "sock", strlen(name))) {
 	    peer_not_sock=0;
-	} else if (0==strncmp(argv[i], "-peer", strlen(argv[i]))) {
+	} else if (0==strncmp(name, "peer", strlen(name))) {
 	    peer_not_sock=1;
 	} else {
 	    break;
@@ -88,19 +91,22 @@ int main(argc, argv)
 
     {
 	union {
-	    struct sockaddr	base;
+	    struct sockaddr_storage	base;
 	    struct sockaddr_in	in;
+	    struct sockaddr_in6 in6;
 #ifndef NOUNIXSOCKETS
 	    struct sockaddr_un	un;
 #endif
 	} saddr;
 	struct sockaddr_in	*sinp = &saddr.in;
+	struct sockaddr_in6	*sin6p = &saddr.in6;
 #ifndef NOUNIXSOCKETS
 	struct sockaddr_un	*sunp = &saddr.un;
 #endif
 	int	saddrlen = sizeof(saddr);
 	int (*f)();
 	char	*name;
+
 	if (peer_not_sock) {
 	    f = getpeername;
 	    name = "peer";
@@ -109,57 +115,51 @@ int main(argc, argv)
 	    name = "sock";
 	}
 
+	memset(&saddr, 0, sizeof(saddr));
+
 	if (0!= f(fd, &saddr, &saddrlen)) {
 	    fprintf(stderr, "%s: get%sname failed on descriptor %d: ", progname, name, fd);
 	    perror("");
 	    exit(1);
 	}
 #ifndef NOUNIXSOCKETS
-	if (saddr.base.sa_family == AF_UNIX) {
-	    if (verbose) puts("Unix\nPort");
-	    puts(sunp->sun_path); /* with newline */
+	if (saddr.base.ss_family == AF_UNIX) {
+	    if (verbose)
+		printf("UNIX, path ");
+	    printf("%s\n", (*sunp->sun_path == '\0') ? "(abstract)"
+				: (*sunp->sun_path == '/') ? sunp->sun_path
+					: "(unnamed)");
 	} else
 #endif
-	  if (saddr.base.sa_family == AF_INET) {
-	    if (verbose) puts("Internet\nPort");
-	    printf("%d\n", ntohs(sinp->sin_port));
-	    if (verbose) puts("Host");
+	  if (saddr.base.ss_family == AF_INET ||
+		saddr.base.ss_family == AF_INET6) {
+	    const int is_inet6 = ( saddr.base.ss_family == AF_INET6 );
+
+	    if (verbose)
+		printf("Internet, port ");
+	    printf("%d\n", ntohs( is_inet6 ? sin6p->sin6_port
+				    : sinp->sin_port));
+	    if (verbose)
+		printf("Host ");
+
 	    {
-		struct in_addr* addr = &sinp->sin_addr;
-		int	i;
-		printf("%d", ((u_char*)addr)[0]);
-		for (i=1; i<sizeof(*addr); i++)
-		    printf(".%d",((u_char*)addr)[i]);
-		printf("\n");
+		char ip[INET6_ADDRSTRLEN];
+
+		getnameinfo((struct sockaddr *) &saddr.base,
+				sizeof(struct sockaddr_storage),
+				ip, sizeof(ip), NULL, 0, NI_NUMERICHOST);
+		printf("%s%s", ip, verbose ? " " : "\n");
 	    }
 	    if (verbose) {
-		struct hostent	*host;
-		host = gethostbyaddr((char*)&sinp->sin_addr, sizeof(sinp->sin_addr),
-				     AF_INET);
-		if (host) {
-		    int	j,k;
-		    for (j=0; host->h_addr_list[j]; j++) {
-			struct in_addr	*ia =
-			    (struct in_addr *)host->h_addr_list[j];
-			if (0==memcmp(host->h_addr_list[j],
-				      &sinp->sin_addr, host->h_length)) {
-			    continue; /* skip this one */
-			}
-			printf("%d", ((u_char*)ia)[0]);
-			for (k=1; k<sizeof(*ia); k++)
-			    printf(".%d",((u_char*)ia)[k]);
-			printf("\n");
-		    }
-		    puts(host->h_name);
-		    for (j=0; host->h_aliases[j]; j++) {
-			puts(host->h_aliases[j]);
-		    }
-		} else {
-		    puts(" (no name for host)");
-		}
+		char host[NI_MAXHOST];
+
+		getnameinfo((struct sockaddr *) &saddr.base,
+				sizeof(struct sockaddr_storage),
+				host, sizeof(host), NULL, 0, 0);
+		printf("%s\n", host);
 	    }
 	} else {
-	    fprintf(stderr, "%s: unknown address family (%d) returned by get%sname\n", progname, saddr.base.sa_family, name);
+	    fprintf(stderr, "%s: unknown address family (%d) returned by get%sname\n", progname, saddr.base.ss_family, name);
 	}
     }
 
diff -Naurp netpipes-4.2.debian//hose.c netpipes-4.2//hose.c
--- netpipes-4.2.debian//hose.c
+++ netpipes-4.2//hose.c
@@ -78,7 +78,6 @@ static char info[] = "hose: a network ut
 #define	EXITCODE_FAILED_SYSCALL	125
 #define	EXITCODE_PIPE	124
 
-struct in_addr ** /* addr_array */ convert_hostname();
 long	doflags=0;
 
 int	retry=0;	       /* how many times to retry after ECONNREFUSED */
@@ -103,15 +102,16 @@ int	reuseaddr;
 
 {
   int	sock = -1;
-  struct in_addr ** addresses=0;
+  struct sockaddr_storage ** addresses=0;
 #ifdef DOUNIX
   struct sockaddr_un	unix_addr;
 #endif
-  struct sockaddr_in	inet_addr;
+  struct sockaddr_storage	inet_addr;
   int	num_addresses;
   int length;
   int tries;
   int cstat;
+  int port = 0;
 
 #ifdef DOUNIX
   if (doflags&DOUNIX) {
@@ -122,104 +122,100 @@ int	reuseaddr;
       num_addresses = 1;
   } else
 #endif
-    {
-      inet_addr.sin_family = AF_INET;
-
-      if (0==(addresses = convert_hostname(hostname, &num_addresses))) {
-	  fprintf(stderr, "%s: could not translate %s to a host address\n",
+  {
+    if (0==(addresses = convert_hostname(hostname, &num_addresses))) {
+      fprintf(stderr, "%s: could not translate %s to a host address\n",
 		  progname, hostname);
-	  exit(EXITCODE_CONNECTION);
-      }
-
-      inet_addr.sin_port = name_to_inet_port(portname);
-      if (inet_addr.sin_port==0) {
-	  fprintf(stderr,"%s: bogus port number %s\n",progname,portname);
-	  exit(EXITCODE_CONNECTION);
-      }
+      exit(EXITCODE_CONNECTION);
+    }
 
-      length = sizeof(struct sockaddr_in);
+    if( (port = name_to_inet_port(portname)) == 0 ) {
+      fprintf(stderr,"%s: bogus port number %s\n",progname,portname);
+      exit(EXITCODE_CONNECTION);
     }
+  }
   
   for (tries = 0; retry<0 || tries <= retry; tries++) {
     int	j;
     int	family;
 
-#ifdef DOUNIX
-  if (doflags&DOUNIX)
-    family = AF_UNIX;
-  else
-#endif
-    family = AF_INET;
-
     /* multi-homed hosts are a little tricky */
     for ( j=0; j<num_addresses; j++) {
+#ifdef DOUNIX
+      if (doflags&DOUNIX)
+        family = AF_UNIX;
+      else
+#endif
+        family = addresses[j]->ss_family;
 
-	sock = socket(family, SOCK_STREAM, 0);
-	if (sock <0) {
-	    perror("opening stream socket");
-	    exit(EXITCODE_CONNECTION);
-	}
+      sock = socket(family, SOCK_STREAM, 0);
+      if (sock <0) {
+	perror("opening stream socket");
+	exit(EXITCODE_CONNECTION);
+      }
 
-	if ((localport) &&
-	    !bindlocal(sock, localport, localaddr,
-		       family, reuseaddr) ) {
-	    fprintf(stderr,"%s: error binding stream socket %s (%s)\n",
+      if ((localport) && !bindlocal(sock, localport, localaddr,
+					family, reuseaddr) ) {
+	fprintf(stderr,"%s: error binding stream socket %s (%s)\n",
 		    progname,localport,strerror(errno));
-	    exit(EXITCODE_CONNECTION);
-	}
+	exit(EXITCODE_CONNECTION);
+      }
 #ifdef DOUNIX
-	if (!(doflags&DOUNIX))
+      if (!(doflags&DOUNIX))
 #endif
-	    {
-		inet_addr.sin_addr = *(addresses[j]);
-	    }
-	if (doflags&DOVERBOSE) {
-	    fprintf(stderr, "%s: attempting to connect to ", progname);
+      {
+	memcpy(&inet_addr, addresses[j], sizeof(struct sockaddr_storage));
+	set_port(&inet_addr, port);
+      }
+      if (doflags&DOVERBOSE) {
+	fprintf(stderr, "%s: attempting to connect to ", progname);
 #ifdef DOUNIX
-	    if (doflags&DOUNIX) {
-		fputs(unix_addr.sun_path, stderr);
-	    } else
+	if (doflags&DOUNIX) {
+	  fprintf(stderr, "UNIX %s\n", unix_addr.sun_path);
+	} else
 #endif
-	      {
-		printhost(stderr, &inet_addr.sin_addr);
-		fprintf(stderr, " port %d\n", ntohs(inet_addr.sin_port));
-	      }
+	{
+	  printhost(stderr, (struct sockaddr *) &inet_addr);
+	  fprintf(stderr, " port %d\n", get_port(&inet_addr));
 	}
-	cstat=connect(sock,
+      }
+
+      length = (inet_addr.ss_family == AF_INET6)
+			? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
 #ifdef DOUNIX
-		      (doflags&DOUNIX) ?
-		      ((struct sockaddr*)&unix_addr) :
+      cstat=connect(sock, (doflags&DOUNIX) ? ((struct sockaddr*)&unix_addr)
+					   : ((struct sockaddr*)&inet_addr),
+			length);
+#else
+      cstat=connect(sock, ((struct sockaddr*)&inet_addr), length);
 #endif
-		      ((struct sockaddr*)&inet_addr) ,
-		      length);
-	if (cstat==0)
-	    break;		/* success */
+      if (cstat==0)
+	break;		/* success */
 
-	if (errno==ECONNREFUSED) {
-	    close(sock);
-	    sock = -1;
-	} else {
-	    perror("connecting");
-	    exit(EXITCODE_CONNECTION);
-	}
+      if ( errno == ECONNREFUSED || errno == ETIMEDOUT) {
+	close(sock);
+	sock = -1;
+	continue;
+      } else {
+	perror("connecting");
+	exit(EXITCODE_CONNECTION);
+      }
     }
-    if (j<num_addresses)
-	break;			/* success */
 
     if (tries<retry) {
-	/* failed, retry all addresses after a delay */
-	if (doflags&DOVERBOSE) {
-	    fprintf(stderr, "sleeping before retry...");
-	    fflush(stdout);
-	}
-	sleep(delay);
-	if (doflags&DOVERBOSE)
-	    fprintf(stderr, "\n");
+      /* failed, retry all addresses after a delay */
+      if (doflags&DOVERBOSE) {
+	fprintf(stderr, "sleeping before retry...");
+	fflush(stdout);
+      }
+      sleep(delay);
+      if (doflags&DOVERBOSE)
+	fprintf(stderr, "\n");
     }
   }
 
   if (sock < 0) {
-    fprintf(stderr, "%s: Retries exhausted, failing connect to %s:%s\n",
+    fprintf(stderr, "%s: Retries exhausted, failing connect to %s port %s\n",
 	    progname, hostname, portname);
     exit(EXITCODE_CONNECTION);
   }
@@ -706,6 +702,7 @@ int main (argc,argv)
     /* we are supposed to shutdown(2) the socket and we are the parent */
     int	status;
     int	pid;
+
     pid = wait(&status);
     if (pid != -1 && i!=pid)
       fprintf(stderr, "Strange, wait returned a child I don't know about.  I'm an unwed father!\n");
