diff options
| author | Thilo Cestonaro <thilo@cestona.ro> | 2011-05-04 17:00:08 (GMT) | 
|---|---|---|
| committer | Thilo Cestonaro <thilo@cestona.ro> | 2011-12-13 08:37:16 (GMT) | 
| commit | 73f9f0ee5dca1485a8f35ff67848be43a7d75978 (patch) | |
| tree | f0c35cd979e7c056709ae56cd2bcab8901d530dd | |
| parent | 81c09a0f6a3e87b078340d7f35d0dea4c03f3a6d (diff) | |
| download | swift-contrib-ephraim/SOCKS5Unittests.zip swift-contrib-ephraim/SOCKS5Unittests.tar.bz2 | |
some SOCKS5ProxiedConnection unittestsephraim/SOCKS5Unittests
fixed disconnecting when SOCKS Proxy response with an unsupported auth method
License: This patch is BSD-licensed, see http://www.opensource.org/licenses/bsd-license.php
| -rw-r--r-- | Swiften/Network/SOCKS5ProxiedConnection.cpp | 1 | ||||
| -rw-r--r-- | Swiften/Network/UnitTest/SOCKS5ProxiedConnectionTest.cpp | 317 | ||||
| -rw-r--r-- | Swiften/SConscript | 1 | 
3 files changed, 319 insertions, 0 deletions
| diff --git a/Swiften/Network/SOCKS5ProxiedConnection.cpp b/Swiften/Network/SOCKS5ProxiedConnection.cpp index 163e23a..838bcd2 100644 --- a/Swiften/Network/SOCKS5ProxiedConnection.cpp +++ b/Swiften/Network/SOCKS5ProxiedConnection.cpp @@ -126,6 +126,7 @@ void SOCKS5ProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> da  						connection_->write(socksConnect);  						break;  					default: +						disconnect();  						onConnectFinished(true);  						break;  				} diff --git a/Swiften/Network/UnitTest/SOCKS5ProxiedConnectionTest.cpp b/Swiften/Network/UnitTest/SOCKS5ProxiedConnectionTest.cpp new file mode 100644 index 0000000..c820221 --- /dev/null +++ b/Swiften/Network/UnitTest/SOCKS5ProxiedConnectionTest.cpp @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <boost/optional.hpp> +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/SOCKS5ProxiedConnection.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/EventLoop/DummyEventLoop.h> + +using namespace Swift; + +class SOCKS5ProxiedConnectionTest : public CppUnit::TestFixture { +		CPPUNIT_TEST_SUITE(SOCKS5ProxiedConnectionTest); +		CPPUNIT_TEST(testConnect_CreatesConnectionToProxy); +		CPPUNIT_TEST(testConnect_ConnectHandshake); +		CPPUNIT_TEST(testConnect_ReceiveMalformedConnectResponse); +		CPPUNIT_TEST(testConnect_ReceiveConnectResponseWithUnsupportedAuthMethod); +		CPPUNIT_TEST_SUITE_END(); + +	public: +		void setUp() { +			proxyHost = HostAddressPort(HostAddress("1.1.1.1"), 1234); +			host = HostAddressPort(HostAddress("2.2.2.2"), 2345); +			eventLoop = new DummyEventLoop(); +			connectionFactory = new MockConnectionFactory(eventLoop); +			connectFinished = false; +			disconnected = false; +		} + +		void tearDown() { +			delete connectionFactory; +			delete eventLoop; +		} + +		void testConnect_CreatesConnectionToProxy() { +			SOCKS5ProxiedConnection::ref testling(createTestling()); + +			testling->connect(host); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connectionFactory->connections.size())); +			CPPUNIT_ASSERT(connectionFactory->connections[0]->hostAddressPort); +			CPPUNIT_ASSERT(proxyHost == *connectionFactory->connections[0]->hostAddressPort); +			CPPUNIT_ASSERT(!connectFinished); +		} + +		void testConnect_ConnectHandshake() { +			ByteArray connectResponse; +			ByteArray connectRequest; +			SOCKS5ProxiedConnection::ref testling(createTestling()); +			testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); +			eventLoop->processEvents(); + +			// response is always first byte 0x05 and second 0x00 +			connectResponse += 0x05; +			connectResponse += 0x00; + +			// first part of the connection handshake +			connectRequest += 0x05; // Version: SOCKS5 = 0x05 +			connectRequest += 0x01; // Number of authentication methods after this byte. +			connectRequest += 0x00; // authmethod = noAuth = 0x00 + +			CPPUNIT_ASSERT_EQUAL(connectRequest, connectionFactory->connections[0]->dataWritten); + +			// response  +			connectionFactory->connections[0]->onDataRead(connectResponse); +			eventLoop->processEvents(); + + +			// second part of the connection handshake +			connectRequest += 0x05; // Version: SOCKS5 = 0x05 +			connectRequest += 0x01; // Number of authentication methods after this byte. +			connectRequest += 0x00; // authmethod = noAuth = 0x00 +			connectRequest += 0x01; // IPv4 +			connectRequest += 0x02; // IP +			connectRequest += 0x02; // IP +			connectRequest += 0x02; // IP +			connectRequest += 0x02; // IP +			connectRequest += 0x09; // Port +			connectRequest += 0x29; // Port +			 +			CPPUNIT_ASSERT_EQUAL(connectRequest, connectionFactory->connections[0]->dataWritten); + +			// response  +			connectionFactory->connections[0]->onDataRead(connectResponse); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT(connectFinished); +			CPPUNIT_ASSERT(!connectFinishedWithError); +			CPPUNIT_ASSERT(dataRead.isEmpty()); +		} + +		void testConnect_ReceiveMalformedConnectResponse() { +			SOCKS5ProxiedConnection::ref testling(createTestling()); +			testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); +			eventLoop->processEvents(); + +			connectionFactory->connections[0]->onDataRead(ByteArray("FLOOP")); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT(connectFinished); +			CPPUNIT_ASSERT(connectFinishedWithError); +			CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); +		} + +		void testConnect_ReceiveConnectResponseWithUnsupportedAuthMethod() { +			SOCKS5ProxiedConnection::ref testling(createTestling()); +			testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); +			eventLoop->processEvents(); + +			ByteArray connectResponse; +			connectResponse += 0x05; +			connectResponse += 0x01; + +			connectionFactory->connections[0]->onDataRead(connectResponse); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT(connectFinished); +			CPPUNIT_ASSERT(connectFinishedWithError); +			CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); +		} + +		void testConnect_ReceiveConnectResponseWithFailure() { +			ByteArray connectResponse; +			ByteArray connectRequest; +			SOCKS5ProxiedConnection::ref testling(createTestling()); +			testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); +			eventLoop->processEvents(); + +			// response is always first byte 0x05 and second 0x00 +			connectResponse += 0x05; +			connectResponse += 0x00; + +			// first part of the connection handshake +			connectRequest += 0x05; // Version: SOCKS5 = 0x05 +			connectRequest += 0x01; // Number of authentication methods after this byte. +			connectRequest += 0x00; // authmethod = noAuth = 0x00 + +			CPPUNIT_ASSERT_EQUAL(connectRequest, connectionFactory->connections[0]->dataWritten); + +			// response  +			connectionFactory->connections[0]->onDataRead(connectResponse); +			eventLoop->processEvents(); + + +			// second part of the connection handshake +			connectRequest += 0x05; // Version: SOCKS5 = 0x05 +			connectRequest += 0x01; // Number of authentication methods after this byte. +			connectRequest += 0x00; // authmethod = noAuth = 0x00 +			connectRequest += 0x01; // IPv4 +			connectRequest += 0x02; // IP +			connectRequest += 0x02; // IP +			connectRequest += 0x02; // IP +			connectRequest += 0x02; // IP +			connectRequest += 0x09; // Port +			connectRequest += 0x29; // Port +			 +			CPPUNIT_ASSERT_EQUAL(connectRequest, connectionFactory->connections[0]->dataWritten); + +			// response  +			connectResponse.clear(); +			connectResponse += 0x05; +			connectResponse += 0x01; // general SOCKS failure +			connectionFactory->connections[0]->onDataRead(connectResponse); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT(connectFinished); +			CPPUNIT_ASSERT(connectFinishedWithError); +			CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); +		} + +/* +		void testConnect_ReceiveDataAfterConnect() { +			SOCKS5ProxiedConnection::ref testling(createTestling()); +			testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); +			eventLoop->processEvents(); +			connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 200 Connection established\r\n\r\n")); +			eventLoop->processEvents(); + +			connectionFactory->connections[0]->onDataRead(ByteArray("abcdef")); + +			CPPUNIT_ASSERT_EQUAL(ByteArray("abcdef"), dataRead); +		} + +		void testWrite_AfterConnect() { +			SOCKS5ProxiedConnection::ref testling(createTestling()); +			testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); +			eventLoop->processEvents(); +			connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 200 Connection established\r\n\r\n")); +			eventLoop->processEvents(); +			connectionFactory->connections[0]->dataWritten.clear(); + +			testling->write(ByteArray("abcdef")); + +			CPPUNIT_ASSERT_EQUAL(ByteArray("abcdef"), connectionFactory->connections[0]->dataWritten); +		} + +		void testDisconnect_AfterConnectRequest() { +			SOCKS5ProxiedConnection::ref testling(createTestling()); +			testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); +			eventLoop->processEvents(); + +			testling->disconnect(); + +			CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); +			CPPUNIT_ASSERT(disconnected); +			CPPUNIT_ASSERT(!disconnectedError); +		} + +		void testDisconnect_AfterConnect() { +			SOCKS5ProxiedConnection::ref testling(createTestling()); +			testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); +			eventLoop->processEvents(); +			connectionFactory->connections[0]->onDataRead(ByteArray("HTTP/1.0 200 Connection established\r\n\r\n")); +			eventLoop->processEvents(); + +			testling->disconnect(); + +			CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); +			CPPUNIT_ASSERT(disconnected); +			CPPUNIT_ASSERT(!disconnectedError); +		} +*/ +	private: +		SOCKS5ProxiedConnection::ref createTestling() { +			boost::shared_ptr<SOCKS5ProxiedConnection> c = SOCKS5ProxiedConnection::create(connectionFactory, proxyHost); +			c->onConnectFinished.connect(boost::bind(&SOCKS5ProxiedConnectionTest::handleConnectFinished, this, _1)); +			c->onDisconnected.connect(boost::bind(&SOCKS5ProxiedConnectionTest::handleDisconnected, this, _1)); +			c->onDataRead.connect(boost::bind(&SOCKS5ProxiedConnectionTest::handleDataRead, this, _1)); +			return c; +		} + +		void handleConnectFinished(bool error) { +			connectFinished = true; +			connectFinishedWithError = error; +		} + +		void handleDisconnected(const boost::optional<Connection::Error>& e) { +			disconnected = true; +			disconnectedError = e; +		} + +		void handleDataRead(const ByteArray& d) { +			dataRead += d; +		} + +		struct MockConnection : public Connection { +			public: +				MockConnection(const std::vector<HostAddressPort>& failingPorts, EventLoop* eventLoop) : eventLoop(eventLoop), failingPorts(failingPorts), disconnected(false) { +				} + +				void listen() { assert(false); } + +				void connect(const HostAddressPort& address) { +					hostAddressPort = address; +					bool fail = std::find(failingPorts.begin(), failingPorts.end(), address) != failingPorts.end(); +					eventLoop->postEvent(boost::bind(boost::ref(onConnectFinished), fail)); +				} + +				HostAddressPort getLocalAddress() const { return HostAddressPort(); } + +				void disconnect() {  +					disconnected = true; +					onDisconnected(boost::optional<Connection::Error>()); +				} +				 +				void write(const ByteArray& d) {  +					dataWritten += d; +				} + +				EventLoop* eventLoop; +				boost::optional<HostAddressPort> hostAddressPort; +				std::vector<HostAddressPort> failingPorts; +				ByteArray dataWritten; +				bool disconnected; +		}; + +		struct MockConnectionFactory : public ConnectionFactory { +			MockConnectionFactory(EventLoop* eventLoop) : eventLoop(eventLoop) { +			} + +			boost::shared_ptr<Connection> createConnection() { +				boost::shared_ptr<MockConnection> connection = boost::make_shared<MockConnection>(failingPorts, eventLoop); +				connections.push_back(connection); +				return connection; +			} + +			EventLoop* eventLoop; +			std::vector< boost::shared_ptr<MockConnection> > connections; +			std::vector<HostAddressPort> failingPorts; +		}; + +	private: +		HostAddressPort proxyHost; +		HostAddressPort host; +		DummyEventLoop* eventLoop; +		MockConnectionFactory* connectionFactory; +		std::vector< boost::shared_ptr<MockConnection> > connections; +		bool connectFinished; +		bool connectFinishedWithError; +		bool disconnected; +		boost::optional<Connection::Error> disconnectedError; +		ByteArray dataRead; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(SOCKS5ProxiedConnectionTest); diff --git a/Swiften/SConscript b/Swiften/SConscript index 9e61fc6..151ab74 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -288,6 +288,7 @@ if env["SCONS_STAGE"] == "build" :  			File("Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp"),  			File("Network/UnitTest/BOSHConnectionTest.cpp"),  			File("Network/UnitTest/BOSHConnectionPoolTest.cpp"), +			File("Network/UnitTest/SOCKS5ProxiedConnectionTest.cpp"),  			File("Parser/PayloadParsers/UnitTest/BodyParserTest.cpp"),  			File("Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp"),  			File("Parser/PayloadParsers/UnitTest/ErrorParserTest.cpp"), | 
 Swift
 Swift