Added FTP_SKIP_PASV_IP and --ftp-skip-pasv-ip
authorDaniel Stenberg <daniel@haxx.se>
Sun, 4 Sep 2005 05:16:06 +0000 (05:16 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 4 Sep 2005 05:16:06 +0000 (05:16 +0000)
docs/curl.1
docs/libcurl/curl_easy_setopt.3
include/curl/curl.h
lib/ftp.c
lib/url.c
lib/urldata.h
src/main.c
tests/FILEFORMAT
tests/data/Makefile.am
tests/data/test270 [new file with mode: 0644]
tests/ftpserver.pl

index 40b29d0..0175b5a 100644 (file)
@@ -348,6 +348,15 @@ using this option can be used to override a previous --ftp-port option. (Added
 in 7.11.0)
 
 If this option is used twice, the second will again disable silent failure.
+.IP "--ftp-skip-pasv-ip"
+(FTP) Tell curl to not use the IP address the server suggests in its response
+to curl's PASV command when curl connects the data connection. Instead curl
+will re-use the same IP address it already uses for the control
+connection. (Added in 7.14.1)
+
+This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
+
+If this option is used twice, the second will again disable silent failure.
 .IP "--ftp-ssl"
 (FTP) Make the FTP connection switch to use SSL/TLS. (Added in 7.11.0)
 
index ea009ca..aa351e9 100644 (file)
@@ -767,6 +767,14 @@ curl is waiting for a response, this value overrides \fICURLOPT_TIMEOUT\fP. It
 is recommended that if used in conjunction with \fICURLOPT_TIMEOUT\fP, you set
 \fICURLOPT_FTP_RESPONSE_TIMEOUT\fP to a value smaller than
 \fICURLOPT_TIMEOUT\fP.  (Added in 7.10.8)
+.IP CURLOPT_FTP_SKIP_PASV_IP
+Pass a long. If set to a non-zero value, it instructs libcurl to not use the
+IP address the server suggests in its 227-response to libcurl's PASV command
+when libcurl connects the data connection. Instead libcurl will re-use the
+same IP address it already uses for the control connection. But it will use
+the port number from the 227-response. (Added in 7.14.1)
+
+This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
 .IP CURLOPT_FTP_SSL
 Pass a long using one of the values from below, to make libcurl use your
 desired level of SSL for the ftp transfer. (Added in 7.11.0)
index daacf78..48c8961 100644 (file)
@@ -903,6 +903,12 @@ typedef enum {
   /* ignore Content-Length */
   CINIT(IGNORE_CONTENT_LENGTH, LONG, 136),
 
+  /* Set to non-zero to skip the IP address received in a 227 PASV FTP server
+     response. Typically used for FTP-SSL purposes but is not restricted to
+     that. libcurl will then instead use the same IP address it used for the
+     control connection. */
+  CINIT(FTP_SKIP_PASV_IP, LONG, 137),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
index bc30e22..4d89723 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -1601,8 +1601,18 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
       return CURLE_FTP_WEIRD_227_FORMAT;
     }
 
-    snprintf(newhost, sizeof(newhost),
-             "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
+    /* we got OK from server */
+    if(data->set.ftp_skip_ip) {
+      /* told to ignore the remotely given IP but instead use the one we used
+         for the control connection */
+      infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
+            ip[0], ip[1], ip[2], ip[3],
+            conn->ip_addr_str);
+      snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str);
+    }
+    else
+      snprintf(newhost, sizeof(newhost),
+               "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
     newport = (port[0]<<8) + port[1];
   }
   else if(ftp->count1 == 0) {
@@ -1622,8 +1632,6 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
     return CURLE_FTP_WEIRD_PASV_REPLY;
   }
 
-  /* we got OK from server */
-
   if(data->change.proxy && *data->change.proxy) {
     /*
      * This is a tunnel through a http proxy and we need to connect to the
index 06784fe..c256cf2 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -965,6 +965,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     data->set.ftp_use_epsv = va_arg(param, long)?TRUE:FALSE;
     break;
 
+  case CURLOPT_FTP_SKIP_PASV_IP:
+    /*
+     * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the
+     * bypass of the IP address in PASV responses.
+     */
+    data->set.ftp_skip_ip = (bool)va_arg(param, long);
+    break;
+
   case CURLOPT_INFILE:
     /*
      * FILE pointer to read the file to be uploaded from. Or possibly
@@ -1240,7 +1248,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     /*
      * Set a SSL_CTX callback
      */
-       data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
+    data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
     break;
   case CURLOPT_SSL_CTX_DATA:
     /*
index 3436b17..ff0b23a 100644 (file)
@@ -1072,8 +1072,9 @@ struct UserDefined {
   bool no_signal;        /* do not use any signal/alarm handler */
   bool global_dns_cache; /* subject for future removal */
   bool tcp_nodelay;      /* whether to enable TCP_NODELAY or not */
-
   bool ignorecl;         /* ignore content length */
+  bool ftp_skip_ip;      /* skip the IP address the FTP server passes on to
+                            us */
 };
 
 /*
index e0eb6bb..dda4dab 100644 (file)
@@ -315,6 +315,7 @@ struct Configurable {
   bool insecure_ok; /* set TRUE to allow insecure SSL connects */
   bool create_dirs;
   bool ftp_create_dirs;
+  bool ftp_skip_ip;
   bool proxyntlm;
   bool proxydigest;
   bool proxybasic;
@@ -508,7 +509,8 @@ static void help(void)
     "    --crlf          Convert LF to CRLF in upload",
     " -f/--fail          Fail silently (no output at all) on errors (H)",
     "    --ftp-create-dirs Create the remote dirs if not present (F)",
-    "    --ftp-pasv      Use PASV instead of PORT (F)",
+    "    --ftp-pasv      Use PASV/EPSV instead of PORT (F)",
+    "    --ftp-skip-pasv-ip Skip the IP address for PASV (F)\n"
     "    --ftp-ssl       Enable SSL/TLS for the ftp transfer (F)",
     " -F/--form <name=content> Specify HTTP multipart POST data (H)",
     "    --form-string <name=string> Specify HTTP multipart POST data (H)",
@@ -1313,6 +1315,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
     {"$n", "proxy-anyauth", FALSE},
     {"$o", "trace-time", FALSE},
     {"$p", "ignore-content-length", FALSE},
+    {"$q", "ftp-skip-pasv-ip", FALSE},
 
     {"0", "http1.0",     FALSE},
     {"1", "tlsv1",       FALSE},
@@ -1709,6 +1712,9 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
       case 'p': /* --ignore-content-length */
         config->ignorecl ^= TRUE;
         break;
+      case 'q': /* --ftp-skip-pasv-ip */
+        config->ftp_skip_ip ^= TRUE;
+        break;
       }
       break;
     case '#': /* --progress-bar */
@@ -3905,6 +3911,10 @@ operate(struct Configurable *config, int argc, char *argv[])
 
         curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl);
 
+        /* curl 7.14.1 */
+        curl_easy_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP,
+                         config->ftp_skip_ip);
+
         retry_numretries = config->req_retry;
 
         retrystart = curlx_tvnow();
index 57850fb..e862f90 100644 (file)
@@ -81,6 +81,7 @@ RETRWEIRDO
 RETRNOSIZE
 NOSAVE
 SLOWDOWN
+PASVBADIP  - makes PASV send back an illegal IP in its 227 response
 
 For HTTP, one specified command is supported:
  "auth_required" - if this is set and a POST/PUT is made without auth, the
index 416c2bb..0b9e4a2 100644 (file)
@@ -33,4 +33,4 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46           \
  test237 test238 test239 test243 test245 test246 test247 test248 test249   \
  test250 test251 test252 test253 test254 test255 test521 test522 test523   \
  test256 test257 test258 test259 test260 test261 test262 test263 test264   \
- test265 test266 test267 test268 test269
+ test265 test266 test267 test268 test269 test270
diff --git a/tests/data/test270 b/tests/data/test270
new file mode 100644 (file)
index 0000000..6c47b55
--- /dev/null
@@ -0,0 +1,48 @@
+<info>
+<keywords>
+FTP
+PASV
+RETR
+</keywords>
+</info>
+# Server-side
+<reply>
+<data>
+data
+    to
+      see
+that FTP
+works
+  so does it?
+</data>
+<servercmd>
+PASVBADIP
+</servercmd>
+</reply>
+
+# Client-side
+<client>
+<server>
+ftp
+</server>
+ <name>
+FTP RETR PASV --ftp-skip-pasv-ip
+ </name>
+ <command>
+ftp://%HOSTIP:%FTPPORT/270 --ftp-skip-pasv-ip --disable-epsv
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+USER anonymous\r
+PASS curl_by_daniel@haxx.se\r
+PWD\r
+PASV\r
+TYPE I\r
+SIZE 270\r
+RETR 270\r
+QUIT\r
+</protocol>
+</verify>
index e721bec..4c74cc1 100644 (file)
@@ -70,6 +70,7 @@ sub ftpmsg {
 }
 
 my $verbose=0; # set to 1 for debugging
+my $pasvbadip=0;
 my $retrweirdo=0;
 my $retrnosize=0;
 my $srcdir=".";
@@ -564,7 +565,11 @@ sub PASV_command {
 
     if($cmd ne "EPSV") {
         # PASV reply
-        sendcontrol sprintf("227 Entering Passive Mode (127,0,0,1,%d,%d)\n",
+        my $p="127,0,0,1";
+        if($pasvbadip) {
+            $p="1,2,3,4";
+        }
+        sendcontrol sprintf("227 Entering Passive Mode ($p,%d,%d)\n",
                             ($pasvport/256), ($pasvport%256));
     }
     else {
@@ -703,6 +708,10 @@ sub customize {
             logmsg "FTPD: instructed to use RETRNOSIZE\n";
             $retrnosize=1;
         }
+        elsif($_ =~ /PASVBADIP/) {
+            logmsg "FTPD: instructed to use PASVBADIP\n";
+            $pasvbadip=1;
+        }
         elsif($_ =~ /NOSAVE/) {
             # don't actually store the file we upload - to be used when
             # uploading insanely huge amounts