summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-12 18:06:01 +0000
committercbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-12 18:06:01 +0000
commit83210f3fd6ced20b8af9e87f9faf7349a791b3e7 (patch)
treecc95829ed6c9d64388e4a7262c596ebaa676c8b9
parenta93c437038ea156163901d4962f1881c98a55bd1 (diff)
downloadchromium_src-83210f3fd6ced20b8af9e87f9faf7349a791b3e7.zip
chromium_src-83210f3fd6ced20b8af9e87f9faf7349a791b3e7.tar.gz
chromium_src-83210f3fd6ced20b8af9e87f9faf7349a791b3e7.tar.bz2
Modify FTP to implement EPSV per RFC 2428. EPSV is an extended version
of PASV, intended specifically to address IPv6 compatibility in FTP. With this change, we now always prefer EPSV over PASV, however our FTP client will fall back to PASV in the case that a remote host does not support EPSV. Contributed by: gavinp@google.com BUG=35050 TEST=ftp to an ipv6 site like ftp.netbsd.org and retrieve data Review URL: http://codereview.chromium.org/1600017 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@44262 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/ftp/ftp_network_transaction.cc151
-rw-r--r--net/ftp/ftp_network_transaction.h10
-rw-r--r--net/ftp/ftp_network_transaction_unittest.cc228
3 files changed, 325 insertions, 64 deletions
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc
index 86e19a0..33f7dba 100644
--- a/net/ftp/ftp_network_transaction.cc
+++ b/net/ftp/ftp_network_transaction.cc
@@ -43,6 +43,66 @@ bool IsValidFTPCommandString(const std::string& input) {
return true;
}
+// From RFC 2428 Section 3:
+// The text returned in response to the EPSV command MUST be:
+// <some text> (<d><d><d><tcp-port><d>)
+// <d> is a delimiter character, ideally to be |
+bool ExtractPortFromEPSVResponse(const net::FtpCtrlResponse& response,
+ int* port) {
+ if (response.lines.size() != 1)
+ return false;
+ const char* ptr = response.lines[0].c_str();
+ while (*ptr && *ptr != '(')
+ ++ptr;
+ if (!*ptr)
+ return false;
+ char sep = *(++ptr);
+ if (!sep || isdigit(sep) || *(++ptr) != sep || *(++ptr) != sep)
+ return false;
+ if (!isdigit(*(++ptr)))
+ return false;
+ *port = *ptr - '0';
+ while (isdigit(*(++ptr))) {
+ *port *= 10;
+ *port += *ptr - '0';
+ }
+ if (*ptr != sep)
+ return false;
+
+ return true;
+}
+
+// There are two way we can receive IP address and port.
+// (127,0,0,1,23,21) IP address and port encapsulated in ().
+// 127,0,0,1,23,21 IP address and port without ().
+//
+// See RFC 959, Section 4.1.2
+bool ExtractPortFromPASVResponse(const net::FtpCtrlResponse& response,
+ int* port) {
+ if (response.lines.size() != 1)
+ return false;
+ const char* ptr = response.lines[0].c_str();
+ while (*ptr && *ptr != '(') // Try with bracket.
+ ++ptr;
+ if (*ptr) {
+ ++ptr;
+ } else {
+ ptr = response.lines[0].c_str(); // Try without bracket.
+ while (*ptr && *ptr != ',')
+ ++ptr;
+ while (*ptr && *ptr != ' ')
+ --ptr;
+ }
+ int i0, i1, i2, i3, p0, p1;
+ if (sscanf_s(ptr, "%d,%d,%d,%d,%d,%d", &i0, &i1, &i2, &i3, &p0, &p1) != 6)
+ return false;
+
+ // Ignore the IP address supplied in the response. We are always going
+ // to connect back to the same server to prevent FTP PASV port scanning.
+ *port = (p0 << 8) + p1;
+ return true;
+}
+
} // namespace
namespace net {
@@ -66,6 +126,7 @@ FtpNetworkTransaction::FtpNetworkTransaction(
// whereas the ascii transfer may damage binary data.
data_type_(DATA_TYPE_IMAGE),
resource_type_(RESOURCE_TYPE_UNKNOWN),
+ use_epsv_(true),
data_connection_port_(0),
socket_factory_(socket_factory),
next_state_(STATE_NONE) {
@@ -252,6 +313,9 @@ int FtpNetworkTransaction::ProcessCtrlResponse() {
case COMMAND_TYPE:
rv = ProcessResponseTYPE(response);
break;
+ case COMMAND_EPSV:
+ rv = ProcessResponseEPSV(response);
+ break;
case COMMAND_PASV:
rv = ProcessResponsePASV(response);
break;
@@ -460,6 +524,10 @@ int FtpNetworkTransaction::DoLoop(int result) {
DCHECK(rv == OK);
rv = DoCtrlWriteTYPE();
break;
+ case STATE_CTRL_WRITE_EPSV:
+ DCHECK(rv == OK);
+ rv = DoCtrlWriteEPSV();
+ break;
case STATE_CTRL_WRITE_PASV:
DCHECK(rv == OK);
rv = DoCtrlWritePASV();
@@ -492,7 +560,6 @@ int FtpNetworkTransaction::DoLoop(int result) {
DCHECK(rv == OK);
rv = DoCtrlWriteQUIT();
break;
-
case STATE_DATA_CONNECT:
DCHECK(rv == OK);
rv = DoDataConnect();
@@ -537,9 +604,6 @@ int FtpNetworkTransaction::DoCtrlResolveHost() {
port = request_->url.EffectiveIntPort();
HostResolver::RequestInfo info(host, port);
- // TODO(wtc): Until we support the FTP extensions for IPv6 specified in
- // RFC 2428, we have to turn off IPv6 in FTP. See http://crbug.com/32945.
- info.set_address_family(ADDRESS_FAMILY_IPV4);
// No known referrer.
return resolver_.Resolve(info, &addresses_, &io_callback_, net_log_);
}
@@ -812,7 +876,7 @@ int FtpNetworkTransaction::ProcessResponseTYPE(
case ERROR_CLASS_INITIATED:
return Stop(ERR_INVALID_RESPONSE);
case ERROR_CLASS_OK:
- next_state_ = STATE_CTRL_WRITE_PASV;
+ next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV;
break;
case ERROR_CLASS_INFO_NEEDED:
return Stop(ERR_INVALID_RESPONSE);
@@ -855,6 +919,40 @@ int FtpNetworkTransaction::ProcessResponseACCT(
return OK;
}
+// EPSV command
+int FtpNetworkTransaction::DoCtrlWriteEPSV() {
+ const std::string command = "EPSV";
+ next_state_ = STATE_CTRL_READ;
+ return SendFtpCommand(command, COMMAND_EPSV);
+}
+
+int FtpNetworkTransaction::ProcessResponseEPSV(
+ const FtpCtrlResponse& response) {
+ switch (GetErrorClass(response.status_code)) {
+ case ERROR_CLASS_INITIATED:
+ return Stop(ERR_INVALID_RESPONSE);
+ case ERROR_CLASS_OK:
+ if (!ExtractPortFromEPSVResponse( response, &data_connection_port_))
+ return Stop(ERR_INVALID_RESPONSE);
+ if (data_connection_port_ < 1024 ||
+ !IsPortAllowedByFtp(data_connection_port_))
+ return Stop(ERR_UNSAFE_PORT);
+ next_state_ = STATE_DATA_CONNECT;
+ break;
+ case ERROR_CLASS_INFO_NEEDED:
+ return Stop(ERR_INVALID_RESPONSE);
+ case ERROR_CLASS_TRANSIENT_ERROR:
+ case ERROR_CLASS_PERMANENT_ERROR:
+ use_epsv_ = false;
+ next_state_ = STATE_CTRL_WRITE_PASV;
+ return OK;
+ default:
+ NOTREACHED();
+ return Stop(ERR_UNEXPECTED);
+ }
+ return OK;
+}
+
// PASV command
int FtpNetworkTransaction::DoCtrlWritePASV() {
std::string command = "PASV";
@@ -862,47 +960,18 @@ int FtpNetworkTransaction::DoCtrlWritePASV() {
return SendFtpCommand(command, COMMAND_PASV);
}
-// There are two way we can receive IP address and port.
-// TODO(phajdan.jr): Figure out how this should work for IPv6.
-// (127,0,0,1,23,21) IP address and port encapsulated in ().
-// 127,0,0,1,23,21 IP address and port without ().
int FtpNetworkTransaction::ProcessResponsePASV(
const FtpCtrlResponse& response) {
switch (GetErrorClass(response.status_code)) {
case ERROR_CLASS_INITIATED:
return Stop(ERR_INVALID_RESPONSE);
case ERROR_CLASS_OK:
- const char* ptr;
- int i0, i1, i2, i3, p0, p1;
- if (response.lines.size() != 1)
- return Stop(ERR_INVALID_RESPONSE);
- ptr = response.lines[0].c_str(); // Try with bracket.
- while (*ptr && *ptr != '(')
- ++ptr;
- if (*ptr) {
- ++ptr;
- } else {
- ptr = response.lines[0].c_str(); // Try without bracket.
- while (*ptr && *ptr != ',')
- ++ptr;
- while (*ptr && *ptr != ' ')
- --ptr;
- }
- if (sscanf_s(ptr, "%d,%d,%d,%d,%d,%d",
- &i0, &i1, &i2, &i3, &p0, &p1) == 6) {
- // Ignore the IP address supplied in the response. We are always going
- // to connect back to the same server to prevent FTP PASV port scanning.
-
- data_connection_port_ = (p0 << 8) + p1;
-
- if (data_connection_port_ < 1024 ||
- !IsPortAllowedByFtp(data_connection_port_))
- return Stop(ERR_UNSAFE_PORT);
-
- next_state_ = STATE_DATA_CONNECT;
- } else {
+ if (!ExtractPortFromPASVResponse(response, &data_connection_port_))
return Stop(ERR_INVALID_RESPONSE);
- }
+ if (data_connection_port_ < 1024 ||
+ !IsPortAllowedByFtp(data_connection_port_))
+ return Stop(ERR_UNSAFE_PORT);
+ next_state_ = STATE_DATA_CONNECT;
break;
case ERROR_CLASS_INFO_NEEDED:
return Stop(ERR_INVALID_RESPONSE);
@@ -973,7 +1042,7 @@ int FtpNetworkTransaction::ProcessResponseRETR(
next_state_ = STATE_CTRL_WRITE_QUIT;
break;
case ERROR_CLASS_INFO_NEEDED:
- next_state_ = STATE_CTRL_WRITE_PASV;
+ next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV;
break;
case ERROR_CLASS_TRANSIENT_ERROR:
if (response.status_code == 421 || response.status_code == 425 ||
@@ -992,7 +1061,7 @@ int FtpNetworkTransaction::ProcessResponseRETR(
// We're going to try CWD next, but first send a PASV one more time,
// because some FTP servers, including FileZilla, require that.
// See http://crbug.com/25316.
- next_state_ = STATE_CTRL_WRITE_PASV;
+ next_state_ = use_epsv_ ? STATE_CTRL_WRITE_EPSV : STATE_CTRL_WRITE_PASV;
break;
default:
NOTREACHED();
diff --git a/net/ftp/ftp_network_transaction.h b/net/ftp/ftp_network_transaction.h
index b74f39a..d80e564 100644
--- a/net/ftp/ftp_network_transaction.h
+++ b/net/ftp/ftp_network_transaction.h
@@ -53,6 +53,7 @@ class FtpNetworkTransaction : public FtpTransaction {
COMMAND_ACCT,
COMMAND_SYST,
COMMAND_TYPE,
+ COMMAND_EPSV,
COMMAND_PASV,
COMMAND_PWD,
COMMAND_SIZE,
@@ -61,7 +62,7 @@ class FtpNetworkTransaction : public FtpTransaction {
COMMAND_MLSD,
COMMAND_LIST,
COMMAND_MDTM,
- COMMAND_QUIT
+ COMMAND_QUIT,
};
enum ErrorClass {
@@ -164,6 +165,8 @@ class FtpNetworkTransaction : public FtpTransaction {
int ProcessResponsePWD(const FtpCtrlResponse& response);
int DoCtrlWriteTYPE();
int ProcessResponseTYPE(const FtpCtrlResponse& response);
+ int DoCtrlWriteEPSV();
+ int ProcessResponseEPSV(const FtpCtrlResponse& response);
int DoCtrlWritePASV();
int ProcessResponsePASV(const FtpCtrlResponse& response);
int DoCtrlWriteRETR();
@@ -228,6 +231,10 @@ class FtpNetworkTransaction : public FtpTransaction {
// Detected resource type (file or directory).
ResourceType resource_type_;
+ // Initially we favour EPSV over PASV for transfers but should any
+ // EPSV fail, we fall back to PASV for the duration of connection.
+ bool use_epsv_;
+
// We get username and password as wstrings in RestartWithAuth, so they are
// also kept as wstrings here.
std::wstring username_;
@@ -261,6 +268,7 @@ class FtpNetworkTransaction : public FtpTransaction {
STATE_CTRL_WRITE_ACCT,
STATE_CTRL_WRITE_SYST,
STATE_CTRL_WRITE_TYPE,
+ STATE_CTRL_WRITE_EPSV,
STATE_CTRL_WRITE_PASV,
STATE_CTRL_WRITE_PWD,
STATE_CTRL_WRITE_RETR,
diff --git a/net/ftp/ftp_network_transaction_unittest.cc b/net/ftp/ftp_network_transaction_unittest.cc
index ded0ad8..33145a5 100644
--- a/net/ftp/ftp_network_transaction_unittest.cc
+++ b/net/ftp/ftp_network_transaction_unittest.cc
@@ -36,15 +36,18 @@ class FtpSocketDataProvider : public DynamicSocketDataProvider {
PRE_SYST,
PRE_PWD,
PRE_TYPE,
+ PRE_EPSV,
PRE_PASV,
PRE_SIZE,
PRE_MDTM,
PRE_MLSD,
PRE_LIST,
PRE_RETR,
+ PRE_EPSV2,
PRE_PASV2,
PRE_CWD,
PRE_QUIT,
+ PRE_NOPASV,
QUIT
};
@@ -76,7 +79,13 @@ class FtpSocketDataProvider : public DynamicSocketDataProvider {
"257 \"/\" is your current location\r\n");
case PRE_TYPE:
return Verify(std::string("TYPE ") + data_type_ + "\r\n", data,
- PRE_PASV, "200 TYPE set successfully\r\n");
+ PRE_EPSV, "200 TYPE set successfully\r\n");
+ case PRE_EPSV:
+ return Verify("EPSV\r\n", data, PRE_SIZE,
+ "227 Entering Extended Passive Mode (|||31744|)\r\n");
+ case PRE_EPSV2:
+ return Verify("EPSV\r\n", data, PRE_CWD,
+ "227 Entering Extended Passive Mode (|||31744|)\r\n");
case PRE_PASV:
return Verify("PASV\r\n", data, PRE_SIZE,
"227 Entering Passive Mode 127,0,0,1,123,456\r\n");
@@ -84,6 +93,9 @@ class FtpSocketDataProvider : public DynamicSocketDataProvider {
// Parser should also accept format without parentheses.
return Verify("PASV\r\n", data, PRE_CWD,
"227 Entering Passive Mode 127,0,0,1,123,456\r\n");
+ case PRE_NOPASV:
+ return Verify("PASV\r\n", data, PRE_QUIT,
+ "500 not going to happen\r\n");
case PRE_QUIT:
return Verify("QUIT\r\n", data, QUIT, "221 Goodbye.\r\n");
default:
@@ -179,9 +191,8 @@ class FtpSocketDataProviderDirectoryListing : public FtpSocketDataProvider {
return Verify("MDTM /\r\n", data, PRE_RETR,
"213 20070221112533\r\n");
case PRE_RETR:
- return Verify("RETR /\r\n", data, PRE_PASV2,
+ return Verify("RETR /\r\n", data, PRE_EPSV2,
"550 Can't download directory\r\n");
-
case PRE_CWD:
return Verify("CWD /\r\n", data, PRE_MLSD, "200 OK\r\n");
case PRE_MLSD:
@@ -199,6 +210,32 @@ class FtpSocketDataProviderDirectoryListing : public FtpSocketDataProvider {
DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderDirectoryListing);
};
+class FtpSocketDataProviderDirectoryListingWithPasvFallback
+ : public FtpSocketDataProviderDirectoryListing {
+ public:
+ FtpSocketDataProviderDirectoryListingWithPasvFallback() {
+ }
+
+ virtual MockWriteResult OnWrite(const std::string& data) {
+ if (InjectFault())
+ return MockWriteResult(true, data.length());
+ switch (state()) {
+ case PRE_EPSV:
+ return Verify("EPSV\r\n", data, PRE_PASV,
+ "500 no EPSV for you\r\n");
+ case PRE_RETR:
+ return Verify("RETR /\r\n", data, PRE_PASV2,
+ "550 Can't download directory\r\n");
+ default:
+ return FtpSocketDataProviderDirectoryListing::OnWrite(data);
+ }
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(
+ FtpSocketDataProviderDirectoryListingWithPasvFallback);
+};
+
class FtpSocketDataProviderDirectoryListingWithTypecode
: public FtpSocketDataProvider {
public:
@@ -209,9 +246,9 @@ class FtpSocketDataProviderDirectoryListingWithTypecode
if (InjectFault())
return MockWriteResult(true, data.length());
switch (state()) {
- case PRE_PASV:
- return Verify("PASV\r\n", data, PRE_CWD,
- "227 Entering Passive Mode 127,0,0,1,123,456\r\n");
+ case PRE_EPSV:
+ return Verify("EPSV\r\n", data, PRE_CWD,
+ "227 Entering Passive Mode (|||31744|)\r\n");
case PRE_CWD:
return Verify("CWD /\r\n", data, PRE_MLSD, "200 OK\r\n");
case PRE_MLSD:
@@ -250,7 +287,7 @@ class FtpSocketDataProviderVMSDirectoryListing : public FtpSocketDataProvider {
return Verify("MDTM ANONYMOUS_ROOT:[000000]dir\r\n", data, PRE_RETR,
"213 20070221112533\r\n");
case PRE_RETR:
- return Verify("RETR ANONYMOUS_ROOT:[000000]dir\r\n", data, PRE_PASV2,
+ return Verify("RETR ANONYMOUS_ROOT:[000000]dir\r\n", data, PRE_EPSV2,
"550 Can't download directory\r\n");
case PRE_CWD:
return Verify("CWD ANONYMOUS_ROOT:[dir]\r\n", data, PRE_MLSD,
@@ -283,6 +320,9 @@ class FtpSocketDataProviderVMSDirectoryListingRootDirectory
case PRE_PWD:
return Verify("PWD\r\n", data, PRE_TYPE,
"257 \"ANONYMOUS_ROOT:[000000]\"\r\n");
+ case PRE_EPSV:
+ return Verify("EPSV\r\n", data, PRE_PASV,
+ "500 EPSV command unknown\r\n");
case PRE_SIZE:
return Verify("SIZE ANONYMOUS_ROOT\r\n", data, PRE_MDTM,
"550 I can only retrieve regular files\r\n");
@@ -335,6 +375,28 @@ class FtpSocketDataProviderFileDownload : public FtpSocketDataProvider {
DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderFileDownload);
};
+class FtpSocketDataProviderFileDownloadWithPasvFallback
+ : public FtpSocketDataProviderFileDownload {
+ public:
+ FtpSocketDataProviderFileDownloadWithPasvFallback() {
+ }
+
+ virtual MockWriteResult OnWrite(const std::string& data) {
+ if (InjectFault())
+ return MockWriteResult(true, data.length());
+ switch (state()) {
+ case PRE_EPSV:
+ return Verify("EPSV\r\n", data, PRE_PASV,
+ "500 No can do\r\n");
+ default:
+ return FtpSocketDataProviderFileDownload::OnWrite(data);
+ }
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderFileDownloadWithPasvFallback);
+};
+
class FtpSocketDataProviderVMSFileDownload : public FtpSocketDataProvider {
public:
FtpSocketDataProviderVMSFileDownload() {
@@ -488,10 +550,37 @@ class FtpSocketDataProviderFileDownloadRetrFail
DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderFileDownloadRetrFail);
};
-class FtpSocketDataProviderEvilPasv : public FtpSocketDataProviderFileDownload {
+class FtpSocketDataProviderEvilEpsv : public FtpSocketDataProviderFileDownload {
+ public:
+ explicit FtpSocketDataProviderEvilEpsv(const char* epsv_response,
+ State expected_state)
+ : epsv_response_(epsv_response),
+ expected_state_(expected_state) {
+ }
+
+ virtual MockWriteResult OnWrite(const std::string& data) {
+ if (InjectFault())
+ return MockWriteResult(true, data.length());
+ switch (state()) {
+ case PRE_EPSV:
+ return Verify("EPSV\r\n", data, expected_state_, epsv_response_);
+ default:
+ return FtpSocketDataProviderFileDownload::OnWrite(data);
+ }
+ }
+
+ private:
+ const char* epsv_response_;
+ const State expected_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(FtpSocketDataProviderEvilEpsv);
+};
+
+class FtpSocketDataProviderEvilPasv
+ : public FtpSocketDataProviderFileDownloadWithPasvFallback {
public:
explicit FtpSocketDataProviderEvilPasv(const char* pasv_response,
- State expected_state)
+ State expected_state)
: pasv_response_(pasv_response),
expected_state_(expected_state) {
}
@@ -503,7 +592,7 @@ class FtpSocketDataProviderEvilPasv : public FtpSocketDataProviderFileDownload {
case PRE_PASV:
return Verify("PASV\r\n", data, expected_state_, pasv_response_);
default:
- return FtpSocketDataProviderFileDownload::OnWrite(data);
+ return FtpSocketDataProviderFileDownloadWithPasvFallback::OnWrite(data);
}
}
@@ -700,6 +789,14 @@ TEST_F(FtpNetworkTransactionTest, DirectoryTransaction) {
EXPECT_EQ(-1, transaction_.GetResponseInfo()->expected_content_size);
}
+TEST_F(FtpNetworkTransactionTest, DirectoryTransactionWithPasvFallback) {
+ FtpSocketDataProviderDirectoryListingWithPasvFallback ctrl_socket;
+ ExecuteTransaction(&ctrl_socket, "ftp://host", OK);
+
+ EXPECT_TRUE(transaction_.GetResponseInfo()->is_directory_listing);
+ EXPECT_EQ(-1, transaction_.GetResponseInfo()->expected_content_size);
+}
+
TEST_F(FtpNetworkTransactionTest, DirectoryTransactionWithTypecode) {
FtpSocketDataProviderDirectoryListingWithTypecode ctrl_socket;
ExecuteTransaction(&ctrl_socket, "ftp://host;type=d", OK);
@@ -759,6 +856,14 @@ TEST_F(FtpNetworkTransactionTest, DownloadTransaction) {
EXPECT_EQ(18, transaction_.GetResponseInfo()->expected_content_size);
}
+TEST_F(FtpNetworkTransactionTest, DownloadTransactionWithPasvFallback) {
+ FtpSocketDataProviderFileDownloadWithPasvFallback ctrl_socket;
+ ExecuteTransaction(&ctrl_socket, "ftp://host/file", OK);
+
+ // We pass an artificial value of 18 as a response to the SIZE command.
+ EXPECT_EQ(18, transaction_.GetResponseInfo()->expected_content_size);
+}
+
TEST_F(FtpNetworkTransactionTest, DownloadTransactionWithTypecodeA) {
FtpSocketDataProviderFileDownload ctrl_socket;
ctrl_socket.set_data_type('A');
@@ -809,6 +914,12 @@ TEST_F(FtpNetworkTransactionTest, DownloadTransactionInvalidResponse) {
ExecuteTransaction(&ctrl_socket, "ftp://host/file", ERR_INVALID_RESPONSE);
}
+TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilPasvReallyBadFormat) {
+ FtpSocketDataProviderEvilPasv ctrl_socket("227 Portscan (127,0,0,\r\n",
+ FtpSocketDataProvider::PRE_QUIT);
+ ExecuteTransaction(&ctrl_socket, "ftp://host/file", ERR_INVALID_RESPONSE);
+}
+
TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilPasvUnsafePort1) {
FtpSocketDataProviderEvilPasv ctrl_socket("227 Portscan (127,0,0,1,0,22)\r\n",
FtpSocketDataProvider::PRE_QUIT);
@@ -871,6 +982,79 @@ TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilPasvUnsafeHost) {
}
}
+TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilEpsvReallyBadFormat1) {
+ FtpSocketDataProviderEvilEpsv ctrl_socket("227 Portscan (|||22)\r\n",
+ FtpSocketDataProvider::PRE_QUIT);
+ ExecuteTransaction(&ctrl_socket, "ftp://host/file", ERR_INVALID_RESPONSE);
+}
+
+TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilEpsvReallyBadFormat2) {
+ FtpSocketDataProviderEvilEpsv ctrl_socket("227 Portscan (||\r\n",
+ FtpSocketDataProvider::PRE_QUIT);
+ ExecuteTransaction(&ctrl_socket, "ftp://host/file", ERR_INVALID_RESPONSE);
+}
+
+TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilEpsvReallyBadFormat3) {
+ FtpSocketDataProviderEvilEpsv ctrl_socket("227 Portscan\r\n",
+ FtpSocketDataProvider::PRE_QUIT);
+ ExecuteTransaction(&ctrl_socket, "ftp://host/file", ERR_INVALID_RESPONSE);
+}
+
+TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilEpsvReallyBadFormat4) {
+ FtpSocketDataProviderEvilEpsv ctrl_socket("227 Portscan (||||)\r\n",
+ FtpSocketDataProvider::PRE_QUIT);
+ ExecuteTransaction(&ctrl_socket, "ftp://host/file", ERR_INVALID_RESPONSE);
+}
+
+TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilEpsvReallyBadFormat5) {
+ FtpSocketDataProviderEvilEpsv ctrl_socket("227 Portscan (\0\0\031773\0)\r\n",
+ FtpSocketDataProvider::PRE_QUIT);
+ ExecuteTransaction(&ctrl_socket, "ftp://host/file", ERR_UNEXPECTED);
+}
+
+TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilEpsvUnsafePort1) {
+ FtpSocketDataProviderEvilEpsv ctrl_socket("227 Portscan (|||22|)\r\n",
+ FtpSocketDataProvider::PRE_QUIT);
+ ExecuteTransaction(&ctrl_socket, "ftp://host/file", ERR_UNSAFE_PORT);
+}
+
+TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilEpsvUnsafePort2) {
+ FtpSocketDataProviderEvilEpsv ctrl_socket("227 Portscan (|||258|)\r\n",
+ FtpSocketDataProvider::PRE_QUIT);
+ ExecuteTransaction(&ctrl_socket, "ftp://host/file", ERR_UNSAFE_PORT);
+}
+
+TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilEpsvUnsafePort3) {
+ FtpSocketDataProviderEvilEpsv ctrl_socket("227 Portscan (|||772|)\r\n",
+ FtpSocketDataProvider::PRE_QUIT);
+ ExecuteTransaction(&ctrl_socket, "ftp://host/file", ERR_UNSAFE_PORT);
+}
+
+TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilEpsvUnsafePort4) {
+ FtpSocketDataProviderEvilEpsv ctrl_socket("227 Portscan (|||2049|)\r\n",
+ FtpSocketDataProvider::PRE_QUIT);
+ ExecuteTransaction(&ctrl_socket, "ftp://host/file", ERR_UNSAFE_PORT);
+}
+
+TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilEpsvWeirdSep) {
+ FtpSocketDataProviderEvilEpsv ctrl_socket("227 Portscan ($$$31744$)\r\n",
+ FtpSocketDataProvider::PRE_SIZE);
+ ExecuteTransaction(&ctrl_socket, "ftp://host/file", OK);
+}
+
+TEST_F(FtpNetworkTransactionTest,
+ DownloadTransactionEvilEpsvWeirdSepUnsafePort) {
+ FtpSocketDataProviderEvilEpsv ctrl_socket("227 Portscan ($$$317$)\r\n",
+ FtpSocketDataProvider::PRE_QUIT);
+ ExecuteTransaction(&ctrl_socket, "ftp://host/file", ERR_UNSAFE_PORT);
+}
+
+TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilEpsvIllegalHost) {
+ FtpSocketDataProviderEvilEpsv ctrl_socket("227 Portscan (|2|::1|31744|)\r\n",
+ FtpSocketDataProvider::PRE_QUIT);
+ ExecuteTransaction(&ctrl_socket, "ftp://host/file", ERR_INVALID_RESPONSE);
+}
+
TEST_F(FtpNetworkTransactionTest, DownloadTransactionEvilLoginBadUsername) {
FtpSocketDataProviderEvilLogin ctrl_socket("hello%0Aworld", "test");
ExecuteTransaction(&ctrl_socket, "ftp://hello%0Aworld:test@host/file", OK);
@@ -1035,13 +1219,13 @@ TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailType) {
ERR_FAILED);
}
-TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailPasv) {
+TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailEpsv) {
FtpSocketDataProviderDirectoryListing ctrl_socket;
TransactionFailHelper(&ctrl_socket,
"ftp://host",
- FtpSocketDataProvider::PRE_PASV,
- FtpSocketDataProvider::PRE_QUIT,
- "500 failed pasv\r\n",
+ FtpSocketDataProvider::PRE_EPSV,
+ FtpSocketDataProvider::PRE_NOPASV,
+ "500 failed epsv\r\n",
ERR_FTP_PASV_COMMAND_FAILED);
}
@@ -1065,13 +1249,13 @@ TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailMdtm) {
OK);
}
-TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailPasv2) {
+TEST_F(FtpNetworkTransactionTest, DirectoryTransactionFailEpsv2) {
FtpSocketDataProviderDirectoryListing ctrl_socket;
TransactionFailHelper(&ctrl_socket,
"ftp://host",
- FtpSocketDataProvider::PRE_PASV2,
- FtpSocketDataProvider::PRE_QUIT,
- "500 failed pasv2\r\n",
+ FtpSocketDataProvider::PRE_EPSV2,
+ FtpSocketDataProvider::PRE_NOPASV,
+ "500 failed epsv2\r\n",
ERR_FTP_PASV_COMMAND_FAILED);
}
@@ -1165,12 +1349,12 @@ TEST_F(FtpNetworkTransactionTest, DownloadTransactionFailType) {
ERR_FAILED);
}
-TEST_F(FtpNetworkTransactionTest, DownloadTransactionFailPasv) {
+TEST_F(FtpNetworkTransactionTest, DownloadTransactionFailEpsv) {
FtpSocketDataProviderFileDownload ctrl_socket;
TransactionFailHelper(&ctrl_socket,
"ftp://host/file",
- FtpSocketDataProvider::PRE_PASV,
- FtpSocketDataProvider::PRE_QUIT,
+ FtpSocketDataProvider::PRE_EPSV,
+ FtpSocketDataProvider::PRE_NOPASV,
"500 failed pasv\r\n",
ERR_FTP_PASV_COMMAND_FAILED);
}
@@ -1200,7 +1384,7 @@ TEST_F(FtpNetworkTransactionTest, DownloadTransactionFileNotFound) {
TransactionFailHelper(&ctrl_socket,
"ftp://host/file",
FtpSocketDataProvider::PRE_RETR,
- FtpSocketDataProvider::PRE_PASV2,
+ FtpSocketDataProvider::PRE_EPSV2,
"550 cannot open file\r\n",
ERR_FILE_NOT_FOUND);
}