aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/curl.19
-rw-r--r--docs/libcurl/curl_easy_setopt.38
-rw-r--r--include/curl/curl.h6
-rw-r--r--lib/ftp.c16
-rw-r--r--lib/url.c10
-rw-r--r--lib/urldata.h3
-rw-r--r--src/main.c12
-rw-r--r--tests/FILEFORMAT1
-rw-r--r--tests/data/Makefile.am2
-rw-r--r--tests/data/test27048
-rw-r--r--tests/ftpserver.pl11
11 files changed, 117 insertions, 9 deletions
diff --git a/docs/curl.1 b/docs/curl.1
index 40b29d049..0175b5a7c 100644
--- a/docs/curl.1
+++ b/docs/curl.1
@@ -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)
diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3
index ea009ca6c..aa351e959 100644
--- a/docs/libcurl/curl_easy_setopt.3
+++ b/docs/libcurl/curl_easy_setopt.3
@@ -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)
diff --git a/include/curl/curl.h b/include/curl/curl.h
index daacf781a..48c896119 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -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;
diff --git a/lib/ftp.c b/lib/ftp.c
index bc30e2258..4d89723c7 100644
--- 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
diff --git a/lib/url.c b/lib/url.c
index 06784fe34..c256cf23f 100644
--- 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:
/*
diff --git a/lib/urldata.h b/lib/urldata.h
index 3436b17da..ff0b23a54 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -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 */
};
/*
diff --git a/src/main.c b/src/main.c
index e0eb6bbc7..dda4dab80 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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();
diff --git a/tests/FILEFORMAT b/tests/FILEFORMAT
index 57850fb64..e862f90c8 100644
--- a/tests/FILEFORMAT
+++ b/tests/FILEFORMAT
@@ -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
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 416c2bb60..0b9e4a2ea 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -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
index 000000000..6c47b559e
--- /dev/null
+++ b/tests/data/test270
@@ -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
+PASS curl_by_daniel@haxx.se
+PWD
+PASV
+TYPE I
+SIZE 270
+RETR 270
+QUIT
+</protocol>
+</verify>
diff --git a/tests/ftpserver.pl b/tests/ftpserver.pl
index e721bec2a..4c74cc1cf 100644
--- a/tests/ftpserver.pl
+++ b/tests/ftpserver.pl
@@ -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