gFTP client with issues handling IPv6 data connections
Alexander Koeppe <[email protected]> Thu, 30 Aug 2012 21:48:18 +0200
| Newsgroups | gmane.linux.debian.devel.ipv6 |
|---|---|
| Message-ID | <[email protected]> |
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-ipv6-dataconn.patch
(text/x-patch, 4.3 KB)
--- 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);