diff options
author | cbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-12 18:06:01 +0000 |
---|---|---|
committer | cbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-12 18:06:01 +0000 |
commit | 83210f3fd6ced20b8af9e87f9faf7349a791b3e7 (patch) | |
tree | cc95829ed6c9d64388e4a7262c596ebaa676c8b9 /net/ftp/ftp_network_transaction_unittest.cc | |
parent | a93c437038ea156163901d4962f1881c98a55bd1 (diff) | |
download | chromium_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
Diffstat (limited to 'net/ftp/ftp_network_transaction_unittest.cc')
-rw-r--r-- | net/ftp/ftp_network_transaction_unittest.cc | 228 |
1 files changed, 206 insertions, 22 deletions
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); } |