ftp PORT: don't hang if bind() fails
authorDaniel Stenberg <daniel@haxx.se>
Sun, 6 Nov 2011 15:53:07 +0000 (16:53 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 6 Nov 2011 22:02:27 +0000 (23:02 +0100)
When the user requests PORT with a specific port or port range, the code
could lock up in an endless loop. There's now an extra conditional that
makes sure to special treat the error and try the local address only
once so a second failure will abort the loop correctly.

Bug: http://curl.haxx.se/bug/view.cgi?id=3433968
Reported by: Gokhan Sengun

lib/ftp.c

index c1dc6689aa3811935dc8d2b06c676105775e83e4..e5b1682fcb943746d7260465bc4c6b9de7a38d79 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -753,6 +753,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
   unsigned short port_min = 0;
   unsigned short port_max = 0;
   unsigned short port;
+  bool possibly_non_local = TRUE;
 
   char *addr = NULL;
 
@@ -869,6 +870,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
       break;
     }
     host = hbuf; /* use this host name */
+    possibly_non_local = FALSE; /* we know it is local now */
   }
 
   /* resolv ip/host to ip */
@@ -932,12 +934,12 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
     if(bind(portsock, sa, sslen) ) {
       /* It failed. */
       error = SOCKERRNO;
-      if(error == EADDRNOTAVAIL) {
-
+      if(possibly_non_local && (error == EADDRNOTAVAIL)) {
         /* The requested bind address is not local.  Use the address used for
          * the control connection instead and restart the port loop
          */
-        failf(data, "bind(port=%hu) failed: %s", port,
+
+        infof(data, "bind(port=%hu) on non-local address failed: %s", port,
               Curl_strerror(conn, error) );
 
         sslen = sizeof(ss);
@@ -948,6 +950,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
           return CURLE_FTP_PORT_FAILED;
         }
         port = port_min;
+        possibly_non_local = FALSE; /* don't try this again */
         continue;
       }
       else if(error != EADDRINUSE && error != EACCES) {