diff options
author | Thilo Cestonaro <thilo@cestona.ro> | 2011-04-14 08:25:33 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2011-04-18 19:11:45 (GMT) |
commit | 427db871922a028bb299dd66c37f3cca4010fd47 (patch) | |
tree | 95c0c4bb407a5fd3ec49c138ec5fbff8cf3a7d7a /Swiften/Network | |
parent | 0b0164a4cdae89afc254bd7aa6f14af81c6b9196 (diff) | |
download | swift-427db871922a028bb299dd66c37f3cca4010fd47.zip swift-427db871922a028bb299dd66c37f3cca4010fd47.tar.bz2 |
Support for SOCKS5 and HTTPConnect proxies.
automatic proxy settings detection;
SOCKS5 proxied connection;
HTTPConnect proxied connection;
License: This patch is BSD-licensed, see http://www.opensource.org/licenses/bsd-license.php
Diffstat (limited to 'Swiften/Network')
25 files changed, 1068 insertions, 2 deletions
diff --git a/Swiften/Network/EnvironmentProxyProvider.cpp b/Swiften/Network/EnvironmentProxyProvider.cpp new file mode 100644 index 0000000..b3bd0f6 --- /dev/null +++ b/Swiften/Network/EnvironmentProxyProvider.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> + +#include "Swiften/Base/Log.h" +#include "Swiften/Network/EnvironmentProxyProvider.h" + +namespace Swift { + +EnvironmentProxyProvider::EnvironmentProxyProvider() { + socksProxy = getFromEnv("all_proxy", "socks"); + httpProxy = getFromEnv("http_proxy", "http"); + SWIFT_LOG(debug) << "Environment: SOCKS5 => " << socksProxy.toString() << "; HTTP Connect => " << httpProxy.toString() << std::endl; +} + +HostAddressPort EnvironmentProxyProvider::getHTTPConnectProxy() const { + return httpProxy; +} + +HostAddressPort EnvironmentProxyProvider::getSOCKS5Proxy() const { + return socksProxy; +} + +HostAddressPort EnvironmentProxyProvider::getFromEnv(const char* envVarName, std::string proxyProtocol) { + char* envVar = NULL; + std::string address; + int port = 0; + + envVar = getenv(envVarName); + + proxyProtocol += "://"; + address = envVar != NULL ? envVar : "0.0.0.0"; + if(envVar != NULL && address.compare(0, proxyProtocol.length(), proxyProtocol) == 0) { + address = address.substr(proxyProtocol.length(), address.length()); + port = atoi(address.substr(address.find(':') + 1, address.length()).c_str()); + address = address.substr(0, address.find(':')); + } + + return HostAddressPort(HostAddress(address), port); +} + +} diff --git a/Swiften/Network/EnvironmentProxyProvider.h b/Swiften/Network/EnvironmentProxyProvider.h new file mode 100644 index 0000000..1743269 --- /dev/null +++ b/Swiften/Network/EnvironmentProxyProvider.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Network/ProxyProvider.h" + +namespace Swift { + class EnvironmentProxyProvider : public ProxyProvider { + public: + EnvironmentProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + private: + HostAddressPort getFromEnv(const char* envVarName, std::string proxyProtocol); + HostAddressPort socksProxy; + HostAddressPort httpProxy; + }; +} + + diff --git a/Swiften/Network/GConfProxyProvider.cpp b/Swiften/Network/GConfProxyProvider.cpp new file mode 100644 index 0000000..687bf77 --- /dev/null +++ b/Swiften/Network/GConfProxyProvider.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> + +#include <gconf/gconf-client.h> + +#include "Swiften/Base/Log.h" +#include "Swiften/Network/GConfProxyProvider.h" + +namespace Swift { + +GConfProxyProvider::GConfProxyProvider() { + socksProxy = getFromGConf("/system/proxy/socks_host", "/system/proxy/socks_port"); + httpProxy = getFromGConf("/system/http_proxy/host", "/system/http_proxy/port"); + SWIFT_LOG(debug) << "GConf: SOCKS5 => " << socksProxy.toString() << "; HTTP Connect => " << httpProxy.toString() << std::endl; +} + +HostAddressPort GConfProxyProvider::getHTTPConnectProxy() const { + return httpProxy; +} + +HostAddressPort GConfProxyProvider::getSOCKS5Proxy() const { + return socksProxy; +} + +HostAddressPort GConfProxyProvider::getFromGConf(const char* gcHost, const char* gcPort) { + std::string address; + int port = 0; + gchar* str; + + GConfClient* client = gconf_client_get_default(); + + str = gconf_client_get_string(client, gcHost, NULL); + port = static_cast<int> (gconf_client_get_int(client, gcPort, NULL)); + + if(str) { + address = static_cast<char*> (str); + g_free(str); + } + + g_object_unref(client); + return HostAddressPort(HostAddress(address), port); +} + +} diff --git a/Swiften/Network/GConfProxyProvider.h b/Swiften/Network/GConfProxyProvider.h new file mode 100644 index 0000000..15586ad --- /dev/null +++ b/Swiften/Network/GConfProxyProvider.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Network/ProxyProvider.h" + +namespace Swift { + class GConfProxyProvider : public ProxyProvider { + public: + GConfProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + private: + HostAddressPort getFromGConf(const char* gcHost, const char* gcPort); + HostAddressPort socksProxy; + HostAddressPort httpProxy; + }; +} + + diff --git a/Swiften/Network/HTTPConnectProxiedConnection.cpp b/Swiften/Network/HTTPConnectProxiedConnection.cpp new file mode 100644 index 0000000..4e05f29 --- /dev/null +++ b/Swiften/Network/HTTPConnectProxiedConnection.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Network/HTTPConnectProxiedConnection.h" + +#include <iostream> +#include <boost/bind.hpp> +#include <boost/thread.hpp> +#include <boost/lexical_cast.hpp> +#include <math.h> + +#include "Swiften/Base/Log.h" +#include "Swiften/Base/String.h" +#include "Swiften/Base/ByteArray.h" +#include "Swiften/Network/HostAddressPort.h" + +namespace Swift { + +HTTPConnectProxiedConnection::HTTPConnectProxiedConnection(ConnectionFactory* connectionFactory, HostAddressPort proxy) +: connectionFactory_(connectionFactory), proxy_(proxy), server_(HostAddressPort(HostAddress("0.0.0.0"), 0)) +{ + connected_ = false; +} + +HTTPConnectProxiedConnection::~HTTPConnectProxiedConnection() { + if(connection_) { + connection_->onDataRead.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleDataRead, shared_from_this(), _1)); + connection_->onDisconnected.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleDisconnected, shared_from_this(), _1)); + } + + if(connected_) { + std::cerr << "Warning: Connection was still established." << std::endl; + } +} + +void HTTPConnectProxiedConnection::connect(const HostAddressPort& server) { + server_ = server; + connection_ = connectionFactory_->createConnection(); + connection_->onConnectFinished.connect(boost::bind(&HTTPConnectProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); + connection_->onDataRead.connect(boost::bind(&HTTPConnectProxiedConnection::handleDataRead, shared_from_this(), _1)); + connection_->onDisconnected.connect(boost::bind(&HTTPConnectProxiedConnection::handleDisconnected, shared_from_this(), _1)); + connection_->connect(proxy_); +} + +void HTTPConnectProxiedConnection::listen() { + assert(false); + connection_->listen(); +} + +void HTTPConnectProxiedConnection::disconnect() { + connected_ = false; + connection_->disconnect(); +} + +void HTTPConnectProxiedConnection::handleDisconnected(const boost::optional<Error>& error) { + onDisconnected(error); +} + +void HTTPConnectProxiedConnection::write(const ByteArray& data) { + connection_->write(data); +} + +void HTTPConnectProxiedConnection::handleConnectionConnectFinished(bool error) { + connection_->onConnectFinished.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); + if(!error) { + proxyState_ = ProxyConnecting; + std::stringstream connect; + connect << "CONNECT " << server_.getAddress().toString() << ":" << server_.getPort() << " HTTP/1.1\r\n\r\n"; + connection_->write(ByteArray(connect.str())); + } + else { + onConnectFinished(true); + } +} + +void HTTPConnectProxiedConnection::handleDataRead(const ByteArray& data) { + if (!connected_) { + if (proxyState_ == ProxyConnecting) { + SWIFT_LOG(debug) << data.toString() << std::endl; + std::vector<std::string> tmp = String::split(data.toString(), ' '); + if(tmp.size() > 1) { + int status = boost::lexical_cast<int> (tmp[1].c_str()); + SWIFT_LOG(debug) << "Proxy Status: " << status << std::endl; + if (status / 100 == 2) { // all 2XX states are OK + connected_ = true; + onConnectFinished(false); + return; + } + } + + std::cerr << "HTTP Proxy returned an error: " << data.toString() << std::endl; + return; + } + } + else { + onDataRead(data); + return; + } + disconnect(); + onConnectFinished(true); +} + +HostAddressPort HTTPConnectProxiedConnection::getLocalAddress() const { + return connection_->getLocalAddress(); +} + +//namespace +} diff --git a/Swiften/Network/HTTPConnectProxiedConnection.h b/Swiften/Network/HTTPConnectProxiedConnection.h new file mode 100644 index 0000000..88b4f66 --- /dev/null +++ b/Swiften/Network/HTTPConnectProxiedConnection.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/enable_shared_from_this.hpp> + +#include "Swiften/Network/ConnectionFactory.h" +#include "Swiften/Network/Connection.h" +#include "Swiften/Network/HostAddressPort.h" + +namespace boost { + class thread; + namespace system { + class error_code; + } +} + +namespace Swift { + class HTTPConnectProxiedConnection : public Connection, public boost::enable_shared_from_this<HTTPConnectProxiedConnection> { + public: + typedef boost::shared_ptr<HTTPConnectProxiedConnection> ref; + + ~HTTPConnectProxiedConnection(); + + static ref create(ConnectionFactory* connectionFactory, HostAddressPort proxy) { + return ref(new HTTPConnectProxiedConnection(connectionFactory, proxy)); + } + + virtual void listen(); + virtual void connect(const HostAddressPort& address); + virtual void disconnect(); + virtual void write(const ByteArray& data); + + virtual HostAddressPort getLocalAddress() const; + private: + enum { + ProxyAuthenticating = 0, + ProxyConnecting, + } proxyState_; + + HTTPConnectProxiedConnection(ConnectionFactory* connectionFactory, HostAddressPort proxy); + + void handleConnectionConnectFinished(bool error); + void handleDataRead(const ByteArray& data); + void handleDisconnected(const boost::optional<Error>& error); + + private: + bool connected_; + ConnectionFactory* connectionFactory_; + HostAddressPort proxy_; + HostAddressPort server_; + boost::shared_ptr<Connection> connection_; + }; +} diff --git a/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp b/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp new file mode 100644 index 0000000..0212945 --- /dev/null +++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Network/HTTPConnectProxiedConnectionFactory.h" +#include "Swiften/Network/HTTPConnectProxiedConnection.h" + +namespace Swift { + +HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(ConnectionFactory* connectionFactory, HostAddressPort proxy) +: connectionFactory_(connectionFactory), proxy_(proxy) +{ + +} + +boost::shared_ptr<Connection> HTTPConnectProxiedConnectionFactory::createConnection() { + return HTTPConnectProxiedConnection::create(connectionFactory_, proxy_); +} + +} diff --git a/Swiften/Network/HTTPConnectProxiedConnectionFactory.h b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h new file mode 100644 index 0000000..7aeb337 --- /dev/null +++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Network/ConnectionFactory.h" +#include "Swiften/Network/HTTPConnectProxiedConnection.h" +#include "Swiften/Network/HostAddressPort.h" + +namespace Swift { + class HTTPConnectProxiedConnection; + + class HTTPConnectProxiedConnectionFactory : public ConnectionFactory { + public: + HTTPConnectProxiedConnectionFactory(ConnectionFactory* connectionFactory, HostAddressPort proxy); + + virtual boost::shared_ptr<Connection> createConnection(); + + private: + ConnectionFactory* connectionFactory_; + HostAddressPort proxy_; + }; +} diff --git a/Swiften/Network/HostAddress.cpp b/Swiften/Network/HostAddress.cpp index 331a233..f734329 100644 --- a/Swiften/Network/HostAddress.cpp +++ b/Swiften/Network/HostAddress.cpp @@ -57,4 +57,8 @@ bool HostAddress::isValid() const { return !(address_.is_v4() && address_.to_v4().to_ulong() == 0); } +boost::asio::ip::address HostAddress::getRawAddress() const { + return address_; +} + } diff --git a/Swiften/Network/HostAddress.h b/Swiften/Network/HostAddress.h index 3e9c8a6..0b3bdda 100644 --- a/Swiften/Network/HostAddress.h +++ b/Swiften/Network/HostAddress.h @@ -3,7 +3,6 @@ * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ - #pragma once #include <string> @@ -18,6 +17,7 @@ namespace Swift { HostAddress(const boost::asio::ip::address& address); std::string toString() const; + boost::asio::ip::address getRawAddress() const; bool operator==(const HostAddress& o) const { return address_ == o.address_; diff --git a/Swiften/Network/HostAddressPort.h b/Swiften/Network/HostAddressPort.h index c99ca65..5655f4d 100644 --- a/Swiften/Network/HostAddressPort.h +++ b/Swiften/Network/HostAddressPort.h @@ -7,6 +7,7 @@ #pragma once #include <boost/asio/ip/tcp.hpp> +#include <boost/lexical_cast.hpp> #include "Swiften/Network/HostAddress.h" @@ -37,6 +38,10 @@ namespace Swift { bool isValid() const { return address_.isValid() && port_ > 0; } + + std::string toString() const { + return getAddress().toString() + ":" + boost::lexical_cast<std::string>(getPort()); + } private: HostAddress address_; diff --git a/Swiften/Network/MacOSXProxyProvider.cpp b/Swiften/Network/MacOSXProxyProvider.cpp new file mode 100644 index 0000000..babcc7f --- /dev/null +++ b/Swiften/Network/MacOSXProxyProvider.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> +#include <utility> + +#include "Swiften/Network/MacOSXProxyProvider.h" +#include <SystemConfiguration/SystemConfiguration.h> + +namespace Swift { + +MacOSXProxyProvider::MacOSXProxyProvider() +: ProxyProvider() +{ + CFDictionaryRef proxies = SCDynamicStoreCopyProxies(NULL); + if(proxies != NULL) { + socksProxy = getFromDictionary(proxies, kSCPropNetProxiesSOCKSEnable, kSCPropNetProxiesSOCKSProxy, kSCPropNetProxiesSOCKSPort); + httpProxy = getFromDictionary(proxies, kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort); + } +} + +HostAddressPort MacOSXProxyProvider::getHTTPConnectProxy() const { + return httpProxy; +} + +HostAddressPort MacOSXProxyProvider::getSOCKS5Proxy() const { + return socksProxy; +} + +HostAddressPort MacOSXProxyProvider::getFromDictionary(CFDictionaryRef dict, CFStringRef enabledKey, CFStringRef hostKey, CFStringRef portKey) { + CFNumberRef numberValue = NULL; + HostAddressPort ret = HostAddressPort(HostAddress(), 0); + + if(CFDictionaryGetValueIfPresent(dict, reinterpret_cast<const void*> (enabledKey), reinterpret_cast<const void**> (&numberValue)) == true) { + const int i = 0; + CFNumberRef zero = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &i); + CFComparisonResult result = CFNumberCompare(numberValue, zero, NULL); + CFRelease(numberValue); + + if(result != kCFCompareEqualTo) { + int port = 0; + std::string host = ""; + + try { + CFNumberRef numberValue = reinterpret_cast<CFNumberRef> (CFDictionaryGetValue(dict, portKey)); + if(numberValue != NULL) { + CFNumberGetValue(numberValue, kCFNumberIntType, &port); + CFRelease(numberValue); + } + + CFStringRef stringValue = reinterpret_cast<CFStringRef> (CFDictionaryGetValue(dict, hostKey)); + if(stringValue != NULL) { + std::vector<char> buffer; + // length must be +1 for the ending zero; and the Docu of CFStringGetCString tells it like + // if the string is toby the length must be at least 5. + CFIndex length = CFStringGetLength(stringValue) + 1; + buffer.resize(length); + if(CFStringGetCString(stringValue, &buffer[0], length, kCFStringEncodingMacRoman)) { + for(std::vector<char>::iterator iter = buffer.begin(); iter != buffer.end(); iter++) { + host += *iter; + } + } + CFRelease(stringValue); + } + } + catch(...) { + std::cerr << "Exception caught ... " << std::endl; + } + + if(host != "" && port != 0) { + ret = HostAddressPort(HostAddress(host), port); + } + } + } + return ret; +} + +} diff --git a/Swiften/Network/MacOSXProxyProvider.h b/Swiften/Network/MacOSXProxyProvider.h new file mode 100644 index 0000000..1cb001f --- /dev/null +++ b/Swiften/Network/MacOSXProxyProvider.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once +#include "Swiften/Network/ProxyProvider.h" +#include <CoreFoundation/CoreFoundation.h> + +namespace Swift { + class MacOSXProxyProvider : public ProxyProvider { + public: + MacOSXProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + + private: + HostAddressPort getFromDictionary(CFDictionaryRef dict, CFStringRef enabledKey, CFStringRef hostKey, CFStringRef portKey); + HostAddressPort socksProxy; + HostAddressPort httpProxy; + }; +} diff --git a/Swiften/Network/PlatformProxyProvider.h b/Swiften/Network/PlatformProxyProvider.h new file mode 100644 index 0000000..13b15d2 --- /dev/null +++ b/Swiften/Network/PlatformProxyProvider.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swiften/Base/Platform.h" + +#if defined(SWIFTEN_PLATFORM_MACOSX) +#include "Swiften/Network/MacOSXProxyProvider.h" +namespace Swift { + typedef MacOSXProxyProvider PlatformProxyProvider; +} +#elif defined(SWIFTEN_PLATFORM_WIN32) +#include "Swiften/Network/WindowsProxyProvider.h" +namespace Swift { + typedef WindowsProxyProvider PlatformProxyProvider; +} +#else +#include "Swiften/Network/UnixProxyProvider.h" +namespace Swift { + typedef UnixProxyProvider PlatformProxyProvider; +} +#endif diff --git a/Swiften/Network/ProxyProvider.cpp b/Swiften/Network/ProxyProvider.cpp new file mode 100644 index 0000000..fe235b1 --- /dev/null +++ b/Swiften/Network/ProxyProvider.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "ProxyProvider.h" + +namespace Swift { + +ProxyProvider::ProxyProvider() +{ +} + +ProxyProvider::~ProxyProvider() +{ +} + +} diff --git a/Swiften/Network/ProxyProvider.h b/Swiften/Network/ProxyProvider.h new file mode 100644 index 0000000..05bb5a7 --- /dev/null +++ b/Swiften/Network/ProxyProvider.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once +#include <map> + +#include "Swiften/Base/Log.h" +#include "Swiften/Network/HostAddressPort.h" +#include "Swiften/Base/String.h" + +namespace Swift { + class ProxyProvider { + public: + ProxyProvider(); + virtual ~ProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const = 0; + virtual HostAddressPort getSOCKS5Proxy() const = 0; + }; +} + diff --git a/Swiften/Network/SConscript b/Swiften/Network/SConscript index 93732d1..426118b 100644 --- a/Swiften/Network/SConscript +++ b/Swiften/Network/SConscript @@ -6,6 +6,10 @@ if myenv.get("HAVE_CARES", False) : myenv.MergeFlags(myenv.get("CARES_FLAGS", {})) sourceList = [ + "HTTPConnectProxiedConnection.cpp", + "HTTPConnectProxiedConnectionFactory.cpp", + "SOCKS5ProxiedConnection.cpp", + "SOCKS5ProxiedConnectionFactory.cpp", "BoostConnection.cpp", "BoostConnectionFactory.cpp", "BoostConnectionServer.cpp", @@ -30,10 +34,25 @@ sourceList = [ "NetworkFactories.cpp", "BoostNetworkFactories.cpp", "Timer.cpp", - "BoostTimer.cpp"] + "BoostTimer.cpp", + "ProxyProvider.cpp" + ] + if myenv.get("HAVE_CARES", False) : sourceList.append("CAresDomainNameResolver.cpp") +if myenv["PLATFORM"] == "darwin" : + myenv.Append(FRAMEWORKS = ["CoreServices", "SystemConfiguration"]) + sourceList += [ "MacOSXProxyProvider.cpp" ] +elif myenv["PLATFORM"] == "win32" : + sourceList += [ "WindowsProxyProvider.cpp" ] +else : + sourceList += [ "UnixProxyProvider.cpp" ] + sourceList += [ "EnvironmentProxyProvider.cpp" ] + if myenv.get("HAVE_GCONF", 0) : + myenv.Append(CPPDEFINES = "HAVE_GCONF") + myenv.MergeFlags(myenv["GCONF_FLAGS"]) + sourceList += [ "GConfProxyProvider.cpp" ] objects = myenv.SwiftenObject(sourceList) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/Network/SOCKS5ProxiedConnection.cpp b/Swiften/Network/SOCKS5ProxiedConnection.cpp new file mode 100644 index 0000000..d32a0f9 --- /dev/null +++ b/Swiften/Network/SOCKS5ProxiedConnection.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Network/SOCKS5ProxiedConnection.h" + +#include <iostream> +#include <boost/bind.hpp> +#include <boost/thread.hpp> +#include <math.h> + +#include "Swiften/Base/Log.h" +#include "Swiften/Base/String.h" +#include "Swiften/Base/ByteArray.h" +#include "Swiften/Network/HostAddressPort.h" + +namespace Swift { + +SOCKS5ProxiedConnection::SOCKS5ProxiedConnection(ConnectionFactory* connectionFactory, HostAddressPort proxy) +: connectionFactory_(connectionFactory), proxy_(proxy), server_(HostAddressPort(HostAddress("0.0.0.0"), 0)) +{ + connected_ = false; +} + +SOCKS5ProxiedConnection::~SOCKS5ProxiedConnection() { + if(connection_) { + connection_->onDataRead.disconnect(boost::bind(&SOCKS5ProxiedConnection::handleDataRead, shared_from_this(), _1)); + connection_->onDisconnected.disconnect(boost::bind(&SOCKS5ProxiedConnection::handleDisconnected, shared_from_this(), _1)); + } + + if(connected_) { + std::cerr << "Warning: Connection was still established." << std::endl; + } +} + +void SOCKS5ProxiedConnection::connect(const HostAddressPort& server) { + server_ = server; + connection_ = connectionFactory_->createConnection(); + connection_->onConnectFinished.connect(boost::bind(&SOCKS5ProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); + connection_->onDataRead.connect(boost::bind(&SOCKS5ProxiedConnection::handleDataRead, shared_from_this(), _1)); + connection_->onDisconnected.connect(boost::bind(&SOCKS5ProxiedConnection::handleDisconnected, shared_from_this(), _1)); + SWIFT_LOG(debug) << "Trying to connect via proxy " << proxy_.getAddress().toString() << ":" << proxy_.getPort() << std::endl; + SWIFT_LOG(debug) << "to server " << server.getAddress().toString() << ":" << server.getPort() << std::endl; + connection_->connect(proxy_); +} + +void SOCKS5ProxiedConnection::listen() { + assert(false); + connection_->listen(); +} + +void SOCKS5ProxiedConnection::disconnect() { + connected_ = false; + if(connection_) + connection_->disconnect(); +} + +void SOCKS5ProxiedConnection::handleDisconnected(const boost::optional<Error>& error) { + onDisconnected(error); +} + +void SOCKS5ProxiedConnection::write(const ByteArray& data) { + if(connection_) + connection_->write(data); +} + +void SOCKS5ProxiedConnection::handleConnectionConnectFinished(bool error) { + connection_->onConnectFinished.disconnect(boost::bind(&SOCKS5ProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); + if(!error) { + SWIFT_LOG(debug) << "Connection to proxy established, now connect to the server via it." << std::endl; + + proxyState_ = ProxyAuthenticating; + ByteArray socksConnect; + socksConnect += 0x05; // VER = SOCKS5 = 0x05 + socksConnect += 0x01; // Number of authentication methods after this byte. + socksConnect += 0x00; // 0x00 == no authentication + // buffer.push_back(0x01); // 0x01 == GSSAPI + // buffer.push_back(0x02); // 0x02 == Username/Password + // rest see RFC 1928 (http://tools.ietf.org/html/rfc1928) + connection_->write(socksConnect); + } + else { + onConnectFinished(true); + } +} + +void SOCKS5ProxiedConnection::handleDataRead(const ByteArray& data) { + ByteArray socksConnect; + boost::asio::ip::address rawAddress = server_.getAddress().getRawAddress(); + assert(rawAddress.is_v4() || rawAddress.is_v6()); + if (!connected_) { + if (proxyState_ == ProxyAuthenticating) { + SWIFT_LOG(debug) << "ProxyAuthenticating response received, reply with the connect BYTEs" << std::endl; + unsigned char choosenMethod = static_cast<unsigned char> (data[1]); + if (data[0] == 0x05 && choosenMethod != 0xFF) { + switch(choosenMethod) { // use the correct Method + case 0x00: + try { + proxyState_ = ProxyConnecting; + socksConnect += 0x05; // VER = SOCKS5 = 0x05 + socksConnect += 0x01; // Construct a TCP connection. (CMD) + socksConnect += 0x00; // reserved. + socksConnect += rawAddress.is_v4() ? 0x01 : 0x04; // IPv4 == 0x01, Hostname == 0x02, IPv6 == 0x04. (ATYP) + size_t size = rawAddress.is_v4() ? rawAddress.to_v4().to_bytes().size() : rawAddress.to_v6().to_bytes().size(); + for (size_t s = 0; s < size; s++) { + unsigned char uc; + if(rawAddress.is_v4()) { + uc = rawAddress.to_v4().to_bytes()[s]; // the address. + } + else + uc = rawAddress.to_v6().to_bytes()[s]; // the address. + socksConnect += static_cast<char> (uc); + + } + socksConnect += static_cast<unsigned char> (server_.getPort() >> 8); // highbyte of the port. + socksConnect += static_cast<unsigned char> (server_.getPort()); // lowbyte of the port. + connection_->write(socksConnect); + return; + } + catch(...) { + std::cerr << "exception caught" << std::endl; + } + connection_->write(socksConnect); + break; + default: + onConnectFinished(true); + break; + } + return; + } + } + else if (proxyState_ == ProxyConnecting) { + SWIFT_LOG(debug) << "Connect response received, check if successfully." << std::endl; + SWIFT_LOG(debug) << "Errorbyte: 0x" << std::hex << static_cast<int> (data[1]) << std::dec << std::endl; + /* + + data.at(1) can be one of the following: + 0x00 succeeded + 0x01 general SOCKS server failure + 0x02 connection not allowed by ruleset + 0x03 Network unreachable + 0x04 Host unreachable + 0x05 Connection refused + 0x06 TTL expired + 0x07 Command not supported (CMD) + 0x08 Address type not supported (ATYP) + 0x09 bis 0xFF unassigned + */ + if (data[0] == 0x05 && data[1] == 0x0) { + SWIFT_LOG(debug) << "Successfully connected the server via the proxy." << std::endl; + connected_ = true; + onConnectFinished(false); + return; + } + else { + std::cerr << "SOCKS Proxy returned an error: " << std::hex << data[1] << std::endl; + } + return; + } + } + else { + onDataRead(data); + return; + } + disconnect(); + onConnectFinished(true); +} + +HostAddressPort SOCKS5ProxiedConnection::getLocalAddress() const { + return connection_->getLocalAddress(); +} + +//namespace +} diff --git a/Swiften/Network/SOCKS5ProxiedConnection.h b/Swiften/Network/SOCKS5ProxiedConnection.h new file mode 100644 index 0000000..b222fd7 --- /dev/null +++ b/Swiften/Network/SOCKS5ProxiedConnection.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/asio.hpp> +#include <boost/enable_shared_from_this.hpp> + +#include "Swiften/Network/ConnectionFactory.h" +#include "Swiften/Network/Connection.h" +#include "Swiften/Network/HostAddressPort.h" + +namespace boost { + class thread; + namespace system { + class error_code; + } +} + +namespace Swift { + class SOCKS5ProxiedConnection : public Connection, public boost::enable_shared_from_this<SOCKS5ProxiedConnection> { + public: + typedef boost::shared_ptr<SOCKS5ProxiedConnection> ref; + + ~SOCKS5ProxiedConnection(); + + static ref create(ConnectionFactory* connectionFactory, HostAddressPort proxy) { + return ref(new SOCKS5ProxiedConnection(connectionFactory, proxy)); + } + + virtual void listen(); + virtual void connect(const HostAddressPort& address); + virtual void disconnect(); + virtual void write(const ByteArray& data); + + virtual HostAddressPort getLocalAddress() const; + private: + enum { + ProxyAuthenticating = 0, + ProxyConnecting, + } proxyState_; + + SOCKS5ProxiedConnection(ConnectionFactory* connectionFactory, HostAddressPort proxy); + + void handleConnectionConnectFinished(bool error); + void handleDataRead(const ByteArray& data); + void handleDisconnected(const boost::optional<Error>& error); + + private: + bool connected_; + ConnectionFactory* connectionFactory_; + HostAddressPort proxy_; + HostAddressPort server_; + boost::shared_ptr<Connection> connection_; + }; +} diff --git a/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp b/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp new file mode 100644 index 0000000..0be0931 --- /dev/null +++ b/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swiften/Network/SOCKS5ProxiedConnectionFactory.h" +#include "Swiften/Network/SOCKS5ProxiedConnection.h" + +namespace Swift { + +SOCKS5ProxiedConnectionFactory::SOCKS5ProxiedConnectionFactory(ConnectionFactory* connectionFactory, HostAddressPort proxy) +: connectionFactory_(connectionFactory), proxy_(proxy) +{ + +} + +boost::shared_ptr<Connection> SOCKS5ProxiedConnectionFactory::createConnection() { + return SOCKS5ProxiedConnection::create(connectionFactory_, proxy_); +} + +} diff --git a/Swiften/Network/SOCKS5ProxiedConnectionFactory.h b/Swiften/Network/SOCKS5ProxiedConnectionFactory.h new file mode 100644 index 0000000..a78a9e8 --- /dev/null +++ b/Swiften/Network/SOCKS5ProxiedConnectionFactory.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/asio.hpp> + +#include "Swiften/Network/ConnectionFactory.h" +#include "Swiften/Network/SOCKS5ProxiedConnection.h" +#include "Swiften/Network/HostAddressPort.h" + +namespace Swift { + class SOCKS5ProxiedConnection; + + class SOCKS5ProxiedConnectionFactory : public ConnectionFactory { + public: + SOCKS5ProxiedConnectionFactory(ConnectionFactory* connectionFactory, HostAddressPort proxy); + + virtual boost::shared_ptr<Connection> createConnection(); + + private: + ConnectionFactory* connectionFactory_; + HostAddressPort proxy_; + }; +} diff --git a/Swiften/Network/UnixProxyProvider.cpp b/Swiften/Network/UnixProxyProvider.cpp new file mode 100644 index 0000000..e21b310 --- /dev/null +++ b/Swiften/Network/UnixProxyProvider.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> + +#include "Swiften/Base/foreach.h" +#include "Swiften/Network/UnixProxyProvider.h" + +namespace Swift { + +UnixProxyProvider::UnixProxyProvider() : +#if defined(HAVE_GCONF) + gconfProxyProvider(), +#endif + environmentProxyProvider() +{ +} + +HostAddressPort UnixProxyProvider::getSOCKS5Proxy() const { + HostAddressPort proxy; +#if defined(HAVE_GCONF) + proxy = gconfProxyProvider.getSOCKS5Proxy(); + if(proxy.isValid()) { + return proxy; + } +#endif + proxy = environmentProxyProvider.getSOCKS5Proxy(); + if(proxy.isValid()) { + return proxy; + } + return HostAddressPort(HostAddress(), 0); +} + +HostAddressPort UnixProxyProvider::getHTTPConnectProxy() const { + HostAddressPort proxy; +#if defined(HAVE_GCONF) + proxy = gconfProxyProvider.getHTTPConnectProxy(); + if(proxy.isValid()) { + return proxy; + } +#endif + proxy = environmentProxyProvider.getHTTPConnectProxy(); + if(proxy.isValid()) { + return proxy; + } + return HostAddressPort(HostAddress(), 0); +} + + +} diff --git a/Swiften/Network/UnixProxyProvider.h b/Swiften/Network/UnixProxyProvider.h new file mode 100644 index 0000000..509cf4b --- /dev/null +++ b/Swiften/Network/UnixProxyProvider.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once +#if defined(HAVE_GCONF) +# include "Swiften/Network/GConfProxyProvider.h" +#endif +#include "Swiften/Network/EnvironmentProxyProvider.h" + +namespace Swift { + class UnixProxyProvider : public ProxyProvider { + public: + UnixProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + private: +#if defined(HAVE_GCONF) + GConfProxyProvider gconfProxyProvider; +#endif + EnvironmentProxyProvider environmentProxyProvider; + }; +} diff --git a/Swiften/Network/WindowsProxyProvider.cpp b/Swiften/Network/WindowsProxyProvider.cpp new file mode 100644 index 0000000..5f6f5d2 --- /dev/null +++ b/Swiften/Network/WindowsProxyProvider.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <iostream> +#include <boost/lexical_cast.hpp> + +#include "Swiften/Base/log.h" +#include "Swiften/Base/foreach.h" +#include "Swiften/Network/WindowsProxyProvider.h" +#include "Swiften/Base/ByteArray.h" + +#include <windows.h> + +namespace Swift { + +WindowsProxyProvider::WindowsProxyProvider() +: ProxyProvider() +{ + HKEY hKey = (HKEY)INVALID_HANDLE_VALUE; + long result; + + result = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", 0, KEY_READ, &hKey); + if (result == ERROR_SUCCESS && hKey != INVALID_HANDLE_VALUE && proxyEnabled(hKey)) { + DWORD dataType = REG_SZ; + DWORD dataSize = 0; + ByteArray dataBuffer; + + result = RegQueryValueEx(hKey, "ProxyServer", NULL, &dataType, NULL, &dataSize); + if(result != ERROR_SUCCESS) { + return; + } + dataBuffer.resize(dataSize); + result = RegQueryValueEx(hKey, "ProxyServer", NULL, &dataType, reinterpret_cast<BYTE*>(dataBuffer.getData()), &dataSize); + if(result == ERROR_SUCCESS) { + std::vector<std::string> proxies = String::split(dataBuffer.toString(), ';'); + std::pair<std::string, std::string> protocolAndProxy; + foreach(std::string proxy, proxies) { + if(proxy.find('=') != std::string::npos) { + protocolAndProxy = String::getSplittedAtFirst(proxy, '='); + SWIFT_LOG(debug) << "Found proxy: " << protocolAndProxy.first << " => " << protocolAndProxy.second << std::endl; + if(protocolAndProxy.first.compare("socks") == 0) { + socksProxy = getAsHostAddressPort(protocolAndProxy.second); + } + else if (protocolAndProxy.first.compare("http") == 0) { + httpProxy = getAsHostAddressPort(protocolAndProxy.second); + } + } + } + } + } +} + +HostAddressPort WindowsProxyProvider::getHTTPConnectProxy() const { + return httpProxy; +} + +HostAddressPort WindowsProxyProvider::getSOCKS5Proxy() const { + return socksProxy; +} + +HostAddressPort WindowsProxyProvider::getAsHostAddressPort(std::string proxy) { + HostAddressPort ret(HostAddress(), 0); + + try { + std::pair<std::string, std::string> tmp; + int port = 0; + tmp = String::getSplittedAtFirst(proxy, ':'); + // .c_str() is needed as tmp.second can include a \0 char which will end in an exception of the lexical cast. + // with .c_str() the \0 will not be part of the string which is to be casted + port = boost::lexical_cast<int> (tmp.second.c_str()); + ret = HostAddressPort(HostAddress(tmp.first), port); + } + catch(...) { + std::cerr << "Exception occured while parsing windows proxy \"getHostAddressPort\"." << std::endl; + } + + return ret; +} + + +bool WindowsProxyProvider::proxyEnabled(HKEY hKey) const { + bool ret = false; + long result; + DWORD dataType = REG_DWORD; + DWORD dataSize = 0; + DWORD data = 0; + ByteArray dataBuffer; + + if(hKey == INVALID_HANDLE_VALUE) + return ret; + + result = RegQueryValueEx(hKey, "ProxyEnable", NULL, &dataType, NULL, &dataSize); + if(result != ERROR_SUCCESS) + return ret; + + dataBuffer.resize(dataSize); + result = RegQueryValueEx(hKey, "ProxyEnable", NULL, &dataType, reinterpret_cast<BYTE*>(dataBuffer.getData()), &dataSize); + if(result != ERROR_SUCCESS) + return ret; + + for(size_t t = 0; t < dataBuffer.getSize(); t++) { + data += static_cast<int> (dataBuffer[t]) * pow(256, static_cast<double>(t)); + } + return (data == 1); +} + +} diff --git a/Swiften/Network/WindowsProxyProvider.h b/Swiften/Network/WindowsProxyProvider.h new file mode 100644 index 0000000..d8d08f0 --- /dev/null +++ b/Swiften/Network/WindowsProxyProvider.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once +#include "Swiften/Network/ProxyProvider.h" + +namespace Swift { + class WindowsProxyProvider : public ProxyProvider { + public: + WindowsProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + private: + HostAddressPort getAsHostAddressPort(std::string proxy); + bool proxyEnabled(HKEY hKey) const; + HostAddressPort socksProxy; + HostAddressPort httpProxy; + }; +} |