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

gFTP client with issues handling IPv6 data connections



Hi list,

some days ago since I moved my root server to another provider willing
to provide native IPv6 support, I had to find out that my favorite
client program gFTP experiences issues working with my newly moved IPv6
enabled server :-/

I digged a bit in the source code (which seem to be not very up-to-date
:-() and found the pieces where things go wrong.

A few changes make gFTP work with IPv6. The issue was improper
implementation of RFC2428 (FTP Extensions for IPv6 and NATs).

Because it doesn't seem to be much speed on the project, though I want
to speed things a bit for all IPv6 fans and share the patch so that it
can be applied before the patch results in the offical sources.

It has to be applied in the "gftp-2.0.19/lib" directory using the
command `patch -p2 /path/to/gftp-ipv6-dataconn.patch`.

Have fun

-- Alex
--- gftp-2.0.19/lib/socket-connect-getaddrinfo.c	2008-03-28 00:29:26.000000000 +0100
+++ gftp-workingcopy/lib/socket-connect-getaddrinfo.c	2012-08-30 21:11:16.000000000 +0200
@@ -26,6 +26,7 @@
 get_port (struct addrinfo *addr)
 {
   struct sockaddr_in * saddr;
+  struct sockaddr_in6 * saddr6;
   int port;
 
   if (addr->ai_family == AF_INET)
@@ -33,6 +34,11 @@
       saddr = (struct sockaddr_in *) addr->ai_addr;
       port = ntohs (saddr->sin_port);
     }
+  else if (addr->ai_family == AF_INET6)
+  {
+      saddr6 = (struct sockaddr_in6*) addr->ai_addr;
+      port = ntohs(saddr6->sin6_port);
+  }
   else
     port = 0;
 
@@ -145,8 +151,15 @@
 
   request->remote_addr_len = current_hostp->ai_addrlen;
   request->remote_addr = g_malloc0 (request->remote_addr_len);
-  memcpy (request->remote_addr, &((struct sockaddr_in *) current_hostp->ai_addr)->sin_addr,
-          request->remote_addr_len);
+
+  if (current_hostp->ai_family == AF_INET) {
+      memcpy (request->remote_addr, &((struct sockaddr_in *) current_hostp->ai_addr)->sin_addr,
+              request->remote_addr_len);
+  }
+  else if (current_hostp->ai_family == AF_INET6) {
+      memcpy (request->remote_addr, &((struct sockaddr_in6 *) current_hostp->ai_addr)->sin6_addr,
+              request->remote_addr_len);
+  }
 
   request->logging_function (gftp_logging_misc, request,
                              _("Connected to %s:%d\n"), res[0].ai_canonname,

--- gftp-2.0.19/lib/rfc959.c	2008-03-04 13:02:48.000000000 +0100
+++ gftp-workingcopy/lib/rfc959.c	2012-08-30 21:11:16.000000000 +0200
@@ -863,7 +863,8 @@
 rfc959_ipv6_data_connection_new (gftp_request * request)
 {
   struct sockaddr_in6 data_addr;
-  char *pos, buf[64], *command;
+  socklen_t data_addr_len;
+  char *pos, addrstr[INET6_ADDRSTRLEN], *command;
   intptr_t passive_transfer;
   rfc959_parms * parms;
   unsigned int port;
@@ -897,7 +898,8 @@
       return (GFTP_EFATAL);
     }
 
-  memset (&data_addr, 0, sizeof (data_addr));
+  data_addr_len = sizeof(data_addr);
+  memset (&data_addr, 0, data_addr_len);
   data_addr.sin6_family = AF_INET6;
 
   gftp_lookup_request_option (request, "passive_transfer", &passive_transfer);
@@ -935,7 +937,7 @@
           return (GFTP_EFATAL);
         }
 
-      memcpy (&data_addr, request->remote_addr, request->remote_addr_len);
+      memcpy (&data_addr.sin6_addr, request->remote_addr, request->remote_addr_len);
       data_addr.sin6_port = htons (port);
 
       if (connect (parms->data_connection, (struct sockaddr *) &data_addr, 
@@ -950,11 +952,20 @@
     }
   else
     {
-      memcpy (&data_addr, request->remote_addr, request->remote_addr_len);
-      data_addr.sin6_port = 0;
 
+      if (getsockname (request->datafd, (struct sockaddr *) &data_addr, 
+                       &data_addr_len) == -1)
+        {
+          request->logging_function (gftp_logging_error, request,
+           _("Cannot get socket name: %s\n"),
+             g_strerror (errno));
+          gftp_disconnect (request);
+          return (GFTP_ERETRYABLE);
+        }
+
+      data_addr.sin6_port = 0;
       if (bind (parms->data_connection, (struct sockaddr *) &data_addr, 
-                request->remote_addr_len) == -1)
+                data_addr_len) == -1)
 	{
 	  request->logging_function (gftp_logging_error, request,
 				     _("Cannot bind a port: %s\n"),
@@ -964,7 +975,7 @@
 	}
 
       if (getsockname (parms->data_connection, (struct sockaddr *) &data_addr, 
-                       &request->remote_addr_len) == -1)
+                       &data_addr_len) == -1)
         {
           request->logging_function (gftp_logging_error, request,
 				     _("Cannot get socket name: %s\n"),
@@ -983,7 +994,7 @@
 	  return (GFTP_ERETRYABLE);
 	}
 
-      if (inet_ntop (AF_INET6, &data_addr.sin6_addr, buf, sizeof (buf)) == NULL)
+      if (inet_ntop (AF_INET6, &data_addr.sin6_addr, addrstr, INET6_ADDRSTRLEN) == NULL)
         {
           request->logging_function (gftp_logging_error, request,
 				     _("Cannot get address of local socket: %s\n"),
@@ -992,7 +1003,7 @@
 	  return (GFTP_ERETRYABLE);
         }
 
-      command = g_strdup_printf ("EPRT |2|%s|%d|\n", buf,
+      command = g_strdup_printf ("EPRT |2|%s|%d|\n", addrstr,
                                  ntohs (data_addr.sin6_port));
 
       resp = rfc959_send_command (request, command, -1, 1, 1);

Reply to: