
# Add IPv6 support; original patch from KIMURA Yasuhiro.
# Closes: #430415
diff -ruN cvs-1.12.13-old/src/client.c cvs-1.12.13/src/client.c
--- cvs-1.12.13-old/src/client.c	2005-10-02 16:17:20.000000000 +0100
+++ cvs-1.12.13/src/client.c	2008-01-27 22:43:45.000000000 +0000
@@ -14,6 +14,10 @@
 # include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#ifdef HAVE_KERBEROS
+# error kerberos is not supported with the IPv6 patch
+#endif
+
 #include "cvs.h"
 #include "getline.h"
 #include "edit.h"
@@ -71,7 +75,7 @@
 static size_t try_read_from_server (char *, size_t);
 
 static void auth_server (cvsroot_t *, struct buffer *, struct buffer *,
-			 int, int, struct hostent *);
+			 int, int, struct addrinfo *);
 
 
 
@@ -3500,44 +3504,48 @@
     int sock;
     int port_number,
 	proxy_port_number = 0; /* Initialize to silence -Wall.  Dumb.  */
-    union sai {
-	struct sockaddr_in addr_in;
-	struct sockaddr addr;
-    } client_sai;
-    struct hostent *hostinfo;
+    char *hostname;
+    struct addrinfo hints, *res, *res0 = NULL;
+    char pbuf[10], aibuf[NI_MAXHOST];
+    int e;
     struct buffer *to_server, *from_server;
 
-    sock = socket (AF_INET, SOCK_STREAM, 0);
-    if (sock == -1)
-	error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO));
+    memset (&hints, 0, sizeof (hints));
+    hints.ai_family = ipv4 ? (ipv6 ? AF_UNSPEC : AF_INET) :
+        (ipv6 ? AF_INET6 : AF_UNSPEC);
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = AI_CANONNAME;
+    /* if we have a proxy connect to that instead */
+    hostname = root->proxy_hostname ? root->proxy_hostname : root->hostname;
     port_number = get_cvs_port_number (root);
+    snprintf (pbuf, sizeof (pbuf), "%d", root->proxy_hostname ?
+              (proxy_port_number = get_proxy_port_number (root)) : port_number);
+    e = getaddrinfo (hostname, pbuf, &hints, &res0);
+    if (e)
+        error (1, 0, "%s", gai_strerror (e));
+
+    sock = -1;
+    for (res = res0; res; res = res->ai_next)
+    {
+        sock = socket (res->ai_family, res->ai_socktype, res->ai_protocol);
+        getnameinfo (res->ai_addr, res->ai_addrlen,
+                     aibuf, sizeof (aibuf), NULL, 0, NI_NUMERICHOST);
+        if (sock < 0)
+          continue;
 
-    /* if we have a proxy connect to that instead */
-    if (root->proxy_hostname)
-    {
-        proxy_port_number = get_proxy_port_number (root);
-	hostinfo = init_sockaddr (&client_sai.addr_in, root->proxy_hostname,
-                                  proxy_port_number);
-        TRACE (TRACE_FUNCTION, "Connecting to %s:%d via proxy %s(%s):%d.",
-               root->hostname, port_number, root->proxy_hostname,
-               inet_ntoa (client_sai.addr_in.sin_addr), proxy_port_number);
-    }
-    else
-    {
-	hostinfo = init_sockaddr (&client_sai.addr_in, root->hostname,
-				  port_number);
-        TRACE (TRACE_FUNCTION, "Connecting to %s(%s):%d.",
-               root->hostname,
-               inet_ntoa (client_sai.addr_in.sin_addr), port_number);
+        TRACE (1, "Connecting to %s(%s):%s", hostname, aibuf, pbuf);
+        if (connect (sock, res->ai_addr, res->ai_addrlen) < 0)
+        {
+            close (sock);
+            sock = -1;
+            continue;
+        }
+        break;
     }
 
-    if (connect (sock, &client_sai.addr, sizeof (client_sai))
-	< 0)
-	error (1, 0, "connect to %s(%s):%d failed: %s",
-	       root->proxy_hostname ? root->proxy_hostname : root->hostname,
-	       inet_ntoa (client_sai.addr_in.sin_addr),
-	       root->proxy_hostname ? proxy_port_number : port_number,
-               SOCK_STRERROR (SOCK_ERRNO));
+    if (sock < 0)
+        error (1, 0, "connect to %s(%s):%s failed: %s",
+               hostname, aibuf, pbuf, SOCK_STRERROR (SOCK_ERRNO));
 
     make_bufs_from_fds (sock, sock, 0, root, &to_server, &from_server, 1);
 
@@ -3580,7 +3588,7 @@
     }
 
     auth_server (root, to_server, from_server, verify_only, do_gssapi,
-                 hostinfo);
+                 res0);
 
     if (verify_only)
     {
@@ -3608,6 +3616,8 @@
 	*from_server_p = from_server;
     }
 
+    if (res0)
+        freeaddrinfo(res0);
     return;
 }
 
@@ -3616,7 +3626,7 @@
 static void
 auth_server (cvsroot_t *root, struct buffer *to_server,
              struct buffer *from_server, int verify_only, int do_gssapi,
-             struct hostent *hostinfo)
+             struct addrinfo *res0)
 {
     char *username = NULL;		/* the username we use to connect */
     char no_passwd = 0;			/* gets set if no password found */
@@ -3634,7 +3644,8 @@
                    "gserver currently only enabled for socket connections");
 	}
 
-	if (! connect_to_gserver (root, fd, hostinfo))
+    if (! connect_to_gserver (root, fd,
+                              res0->ai_canonname ? res0->ai_canonname : root->hostname))
 	{
 	    error (1, 0,
 		    "authorization failed: server %s rejected access to %s",
diff -ruN cvs-1.12.13-old/src/cvs.h cvs-1.12.13/src/cvs.h
--- cvs-1.12.13-old/src/cvs.h	2005-10-02 16:17:20.000000000 +0100
+++ cvs-1.12.13/src/cvs.h	2008-01-27 22:32:30.000000000 +0000
@@ -363,6 +363,7 @@
 /* Option flags for Parse_Info() */
 #define PIOPT_ALL 1	/* accept "all" keyword */
 
+extern int ipv4, ipv6;
 extern const char *program_name, *program_path, *cvs_cmd_name;
 extern char *Editor;
 extern int cvsadmin_root;
diff -ruN cvs-1.12.13-old/src/gssapi-client.c cvs-1.12.13/src/gssapi-client.c
--- cvs-1.12.13-old/src/gssapi-client.c	2005-09-25 01:38:29.000000000 +0100
+++ cvs-1.12.13/src/gssapi-client.c	2008-01-27 22:45:33.000000000 +0000
@@ -77,7 +77,7 @@
  */
 #define BUFSIZE 1024
 int
-connect_to_gserver (cvsroot_t *root, int sock, struct hostent *hostinfo)
+connect_to_gserver (cvsroot_t *root, int sock, const char *hostname)
 {
     char *str;
     char buf[BUFSIZE];
@@ -90,9 +90,9 @@
     if (send (sock, str, strlen (str), 0) < 0)
 	error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
 
-    if (strlen (hostinfo->h_name) > BUFSIZE - 5)
+    if (strlen (hostname) > BUFSIZE - 5)
 	error (1, 0, "Internal error: hostname exceeds length of buffer");
-    sprintf (buf, "cvs@%s", hostinfo->h_name);
+    sprintf (buf, "cvs@%s", hostname);
     tok_in.length = strlen (buf);
     tok_in.value = buf;
     gss_import_name (&stat_min, &tok_in, GSS_C_NT_HOSTBASED_SERVICE,
diff -ruN cvs-1.12.13-old/src/gssapi-client.h cvs-1.12.13/src/gssapi-client.h
--- cvs-1.12.13-old/src/gssapi-client.h	2005-09-25 01:38:29.000000000 +0100
+++ cvs-1.12.13/src/gssapi-client.h	2008-01-27 22:46:01.000000000 +0000
@@ -51,7 +51,7 @@
 						   gss_ctx_id_t gcontext,
 						   void (*memory) (struct buffer *) );
 
-int connect_to_gserver (cvsroot_t *, int, struct hostent *);
+int connect_to_gserver (cvsroot_t *, int, const char *);
 
 extern void initialize_gssapi_buffers (struct buffer **to_server_p,
 					     struct buffer **from_server_p);
diff -ruN cvs-1.12.13-old/src/main.c cvs-1.12.13/src/main.c
--- cvs-1.12.13-old/src/main.c	2005-10-02 16:17:21.000000000 +0100
+++ cvs-1.12.13/src/main.c	2008-01-27 22:34:27.000000000 +0000
@@ -34,6 +34,8 @@
 /* FIXME: Perhaps this should be renamed original_hostname or the like?  */
 char *server_hostname;
 
+int ipv4 = 0;
+int ipv6 = 0;
 int use_editor = 1;
 int use_cvsrc = 1;
 int cvswrite = !CVSREAD_DFLT;
@@ -299,6 +301,8 @@
 #endif
     "    -a           Authenticate all net traffic.\n",
 #endif
+    "    -4           Use IPv4 addresses only.\n",
+    "    -6           Use IPv6 addresses only.\n",
     "    -s VAR=VAL   Set CVS user variable.\n",
     "(Specify the --help option for a list of other help options)\n",
     NULL
@@ -511,7 +515,7 @@
     int help = 0;		/* Has the user asked for help?  This
 				   lets us support the `cvs -H cmd'
 				   convention to give help for cmd. */
-    static const char short_options[] = "+QqrwtnRvb:T:e:d:Hfz:s:xa";
+    static const char short_options[] = "+QqrwtnRvb:T:e:d:Hfz:s:xa46";
     static struct option long_options[] =
     {
         {"help", 0, NULL, 'H'},
@@ -753,9 +757,15 @@
                    We will issue an error later if stream
                    authentication is not supported.  */
 		break;
+	    case '4':
+            ipv4 = 1;
+            break;
+        case '6':
+            ipv6 = 1;
+            break;
 	    case '?':
 	    default:
-                usage (usg);
+            usage (usg);
 	}
     }
 
diff -ruN cvs-1.12.13-old/src/server.c cvs-1.12.13/src/server.c
--- cvs-1.12.13-old/src/server.c	2005-09-28 16:25:59.000000000 +0100
+++ cvs-1.12.13/src/server.c	2008-01-27 22:49:10.000000000 +0000
@@ -7292,19 +7292,20 @@
 {
     int status;
     char instance[INST_SZ];
-    struct sockaddr_in peer;
-    struct sockaddr_in laddr;
-    int len;
+    struct sockaddr_storage peer;
+    struct sockaddr_storage laddr;
+    int plen, llen;
     KTEXT_ST ticket;
     AUTH_DAT auth;
     char version[KRB_SENDAUTH_VLEN];
     char user[ANAME_SZ];
 
     strcpy (instance, "*");
-    len = sizeof peer;
-    if (getpeername (STDIN_FILENO, (struct sockaddr *) &peer, &len) < 0
+    plen = sizeof peer;
+    llen = sizeof laddr;
+    if (getpeername (STDIN_FILENO, (struct sockaddr *) &peer, &plen) < 0
 	|| getsockname (STDIN_FILENO, (struct sockaddr *) &laddr,
-			&len) < 0)
+			&llen) < 0)
     {
 	printf ("E Fatal error, aborting.\n\
 error %s getpeername or getsockname failed\n", strerror (errno));

