[PATCH 5/8] Add workarounds for EPSV/PASV data connection failures.



- don't use EPSV if we get successful return codes but fails to connect.
- don't use address in PASV response if we fail to connect to it
  (use the same address as the command connection is established to).
---
 daemon/gvfsbackendftp.c |   51 ++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/daemon/gvfsbackendftp.c b/daemon/gvfsbackendftp.c
index b05e164..bddab49 100644
--- a/daemon/gvfsbackendftp.c
+++ b/daemon/gvfsbackendftp.c
@@ -107,6 +107,11 @@ typedef enum {
   FTP_SYSTEM_WINDOWS
 } FtpSystem;
 
+typedef enum {
+  FTP_WORKAROUND_BROKEN_EPSV = (1 << 0),
+  FTP_WORKAROUND_PASV_ADDR = (1 << 1),
+} FtpWorkarounds;
+
 struct _GVfsBackendFtp
 {
   GVfsBackend		backend;
@@ -147,6 +152,7 @@ struct _FtpConnection
 
   FtpFeatures		features;
   FtpSystem		system;
+  FtpWorkarounds	workarounds;
 
   SoupSocket *		commands;
   gchar *	      	read_buffer;
@@ -811,10 +817,14 @@ ftp_connection_ensure_data_connection_epsv (FtpConnection *conn)
   guint port;
   SoupAddress *addr;
   guint status;
+  gboolean connected;
 
   if ((conn->features & FTP_FEATURE_EPSV) == 0)
     return FALSE;
 
+  if (conn->workarounds & FTP_WORKAROUND_BROKEN_EPSV)
+    return FALSE;
+
   status = ftp_connection_send (conn, RESPONSE_PASS_500, "EPSV");
   if (STATUS_GROUP (status) != 2)
     return FALSE;
@@ -832,7 +842,14 @@ ftp_connection_ensure_data_connection_epsv (FtpConnection *conn)
 		      soup_address_get_name (soup_socket_get_remote_address (conn->commands)),
 		      port);
 
-  return _ftp_connection_ensure_data_connection (conn, addr);
+  connected = _ftp_connection_ensure_data_connection (conn, addr);
+  if (!connected)
+    {
+      DEBUG("Successful EPSV response code, but data connection failed. Enabling FTP_WORKAROUND_BROKEN_EPSV.\n");
+      conn->workarounds |= FTP_WORKAROUND_BROKEN_EPSV;
+      g_clear_error(&conn->error);
+    }
+  return connected;
 }
 
 static gboolean
@@ -866,11 +883,35 @@ ftp_connection_ensure_data_connection_pasv (FtpConnection *conn)
       return FALSE;
     }
 
-  ip = g_strdup_printf ("%u.%u.%u.%u", ip1, ip2, ip3, ip4);
-  addr = soup_address_new (ip, port1 << 8 | port2);
-  g_free (ip);
+  if (conn->workarounds & FTP_WORKAROUND_PASV_ADDR)
+    {
+      SoupAddress *raddr;
+
+      raddr = soup_socket_get_remote_address (conn->commands);
+      addr = soup_address_new (soup_address_get_name (raddr),
+                               port1 << 8 | port2);
+      return _ftp_connection_ensure_data_connection (conn, addr);
+    }
+  else
+    {
+      gboolean connected;
+
+      ip = g_strdup_printf ("%u.%u.%u.%u", ip1, ip2, ip3, ip4);
+      addr = soup_address_new (ip, port1 << 8 | port2);
+      g_free (ip);
+
+      connected = _ftp_connection_ensure_data_connection (conn, addr);
+      if (!connected)
+        {
+          /* enable workaround and try again */
+          DEBUG("Successfull PASV response but data connection failed. Enabling FTP_WORKAROUND_PASV_ADDR.\n");
+          conn->workarounds |= FTP_WORKAROUND_PASV_ADDR;
+          g_clear_error(&conn->error);
+          return ftp_connection_ensure_data_connection_pasv (conn);
+	}
+      return connected;
+    }
 
-  return _ftp_connection_ensure_data_connection (conn, addr);
 }
 
 static gboolean
-- 
1.5.6.5



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