From 779f0d57bc9d90300aad0b1386dc937612ac35f4 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Fri, 9 Jan 2015 17:39:11 +0100 Subject: Support domain names in S5B proxy tags. S5BProxyManager now resolves DNS names of proxy entries discovered via service discovery. Test-Information: Tested against a XMPP installation that uses domain names in proxy entires. Change-Id: I728243333ec6e62e86f088f2a7b6e222c629757b diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp index d2f8b7a..613249b 100644 --- a/Swiften/Client/Client.cpp +++ b/Swiften/Client/Client.cpp @@ -137,6 +137,7 @@ void Client::handleConnected() { getNetworkFactories()->getConnectionFactory(), getNetworkFactories()->getConnectionServerFactory(), getNetworkFactories()->getTimerFactory(), + getNetworkFactories()->getDomainNameResolver(), getNetworkFactories()->getNetworkEnvironment(), getNetworkFactories()->getNATTraverser(), getNetworkFactories()->getCryptoProvider()); diff --git a/Swiften/Elements/S5BProxyRequest.h b/Swiften/Elements/S5BProxyRequest.h index fcd0cb2..b7541fc 100644 --- a/Swiften/Elements/S5BProxyRequest.h +++ b/Swiften/Elements/S5BProxyRequest.h @@ -4,6 +4,12 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + #pragma once #include @@ -22,7 +28,8 @@ public: public: struct StreamHost { - HostAddressPort addressPort; + std::string host; + int port; JID jid; }; diff --git a/Swiften/FileTransfer/FileTransferManagerImpl.cpp b/Swiften/FileTransfer/FileTransferManagerImpl.cpp index f439197..ab4cb5c 100644 --- a/Swiften/FileTransfer/FileTransferManagerImpl.cpp +++ b/Swiften/FileTransfer/FileTransferManagerImpl.cpp @@ -48,6 +48,7 @@ FileTransferManagerImpl::FileTransferManagerImpl( ConnectionFactory* connectionFactory, ConnectionServerFactory* connectionServerFactory, TimerFactory* timerFactory, + DomainNameResolver* domainNameResolver, NetworkEnvironment* networkEnvironment, NATTraverser* natTraverser, CryptoProvider* crypto) : @@ -60,7 +61,7 @@ FileTransferManagerImpl::FileTransferManagerImpl( bytestreamRegistry = new SOCKS5BytestreamRegistry(); s5bServerManager = new SOCKS5BytestreamServerManager( bytestreamRegistry, connectionServerFactory, networkEnvironment, natTraverser); - bytestreamProxy = new SOCKS5BytestreamProxiesManager(connectionFactory, timerFactory); + bytestreamProxy = new SOCKS5BytestreamProxiesManager(connectionFactory, timerFactory, domainNameResolver, iqRouter, JID(ownFullJID.getDomain())); transporterFactory = new DefaultFileTransferTransporterFactory( bytestreamRegistry, diff --git a/Swiften/FileTransfer/FileTransferManagerImpl.h b/Swiften/FileTransfer/FileTransferManagerImpl.h index 678261a..de6e857 100644 --- a/Swiften/FileTransfer/FileTransferManagerImpl.h +++ b/Swiften/FileTransfer/FileTransferManagerImpl.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013 Isode Limited. + * Copyright (c) 2013-2015 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -33,21 +33,22 @@ namespace Swift { class ConnectionFactory; class ConnectionServerFactory; - class SOCKS5BytestreamServerManager; + class CryptoProvider; + class DomainNameResolver; class EntityCapsProvider; + class FileTransferTransporterFactory; class IQRouter; class IncomingFileTransferManager; class JingleSessionManager; - class OutgoingFileTransferManager; class NATTraverser; + class NetworkEnvironment; + class OutgoingFileTransferManager; class PresenceOracle; class ReadBytestream; - class FileTransferTransporterFactory; - class SOCKS5BytestreamRegistry; class SOCKS5BytestreamProxiesManager; + class SOCKS5BytestreamRegistry; + class SOCKS5BytestreamServerManager; class TimerFactory; - class CryptoProvider; - class NetworkEnvironment; class SWIFTEN_API FileTransferManagerImpl : public FileTransferManager { public: @@ -60,6 +61,7 @@ namespace Swift { ConnectionFactory* connectionFactory, ConnectionServerFactory* connectionServerFactory, TimerFactory* timerFactory, + DomainNameResolver* domainNameResolver, NetworkEnvironment* networkEnvironment, NATTraverser* natTraverser, CryptoProvider* crypto); diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp index 0b94763..ef0a733 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.cpp @@ -4,69 +4,144 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + + #include #include +#include #include #include #include +#include +#include +#include +#include +#include namespace Swift { -SOCKS5BytestreamProxiesManager::SOCKS5BytestreamProxiesManager(ConnectionFactory *connFactory, TimerFactory *timeFactory) : connectionFactory(connFactory), timerFactory(timeFactory) { +SOCKS5BytestreamProxiesManager::SOCKS5BytestreamProxiesManager(ConnectionFactory *connFactory, TimerFactory *timeFactory, DomainNameResolver* resolver, IQRouter* iqRouter, const JID& serviceRoot) : connectionFactory_(connFactory), timerFactory_(timeFactory), resolver_(resolver), iqRouter_(iqRouter), serviceRoot_(serviceRoot) { + +} +SOCKS5BytestreamProxiesManager::~SOCKS5BytestreamProxiesManager() { + if (proxyFinder_) { + proxyFinder_->stop(); + } } void SOCKS5BytestreamProxiesManager::addS5BProxy(S5BProxyRequest::ref proxy) { - localS5BProxies.push_back(proxy); + if (proxy) { + SWIFT_LOG_ASSERT(HostAddress(proxy->getStreamHost().get().host).isValid(), warning) << std::endl; + if (!localS5BProxies_) { + localS5BProxies_ = std::vector(); + } + localS5BProxies_->push_back(proxy); + onDiscoveredProxiesChanged(); + } } -const std::vector& SOCKS5BytestreamProxiesManager::getS5BProxies() const { - return localS5BProxies; +const boost::optional >& SOCKS5BytestreamProxiesManager::getOrDiscoverS5BProxies() { + if (!localS5BProxies_ && !proxyFinder_) { + queryForProxies(); + } + return localS5BProxies_; } void SOCKS5BytestreamProxiesManager::connectToProxies(const std::string& sessionID) { SWIFT_LOG(debug) << "session ID: " << sessionID << std::endl; ProxyJIDClientSessionMap clientSessions; - foreach(S5BProxyRequest::ref proxy, localS5BProxies) { - boost::shared_ptr conn = connectionFactory->createConnection(); + if (localS5BProxies_) { + foreach(S5BProxyRequest::ref proxy, localS5BProxies_.get()) { + boost::shared_ptr conn = connectionFactory_->createConnection(); - boost::shared_ptr session = boost::make_shared(conn, proxy->getStreamHost().get().addressPort, sessionID, timerFactory); - clientSessions[proxy->getStreamHost().get().jid] = session; - session->start(); + HostAddressPort addressPort = HostAddressPort(proxy->getStreamHost().get().host, proxy->getStreamHost().get().port); + SWIFT_LOG_ASSERT(addressPort.isValid(), warning) << std::endl; + boost::shared_ptr session = boost::make_shared(conn, addressPort, sessionID, timerFactory_); + clientSessions[proxy->getStreamHost().get().jid] = session; + session->start(); + } } - proxySessions[sessionID] = clientSessions; + proxySessions_[sessionID] = clientSessions; } boost::shared_ptr SOCKS5BytestreamProxiesManager::getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID) { // checking parameters - if (proxySessions.find(sessionID) == proxySessions.end()) { + if (proxySessions_.find(sessionID) == proxySessions_.end()) { return boost::shared_ptr(); } - if (proxySessions[sessionID].find(proxyJID) == proxySessions[sessionID].end()) { + if (proxySessions_[sessionID].find(proxyJID) == proxySessions_[sessionID].end()) { return boost::shared_ptr(); } // get active session - boost::shared_ptr activeSession = proxySessions[sessionID][proxyJID]; - proxySessions[sessionID].erase(proxyJID); + boost::shared_ptr activeSession = proxySessions_[sessionID][proxyJID]; + proxySessions_[sessionID].erase(proxyJID); // close other sessions - foreach(const ProxyJIDClientSessionMap::value_type& myPair, proxySessions[sessionID]) { + foreach(const ProxyJIDClientSessionMap::value_type& myPair, proxySessions_[sessionID]) { myPair.second->stop(); } - proxySessions.erase(sessionID); + proxySessions_.erase(sessionID); return activeSession; } boost::shared_ptr SOCKS5BytestreamProxiesManager::createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr) { - SOCKS5BytestreamClientSession::ref connection = boost::make_shared(connectionFactory->createConnection(), addressPort, destAddr, timerFactory); + SOCKS5BytestreamClientSession::ref connection = boost::make_shared(connectionFactory_->createConnection(), addressPort, destAddr, timerFactory_); return connection; } +void SOCKS5BytestreamProxiesManager::handleProxyFound(S5BProxyRequest::ref proxy) { + if (proxy) { + if (HostAddress(proxy->getStreamHost().get().host).isValid()) { + addS5BProxy(proxy); + } + else { + DomainNameAddressQuery::ref resolveRequest = resolver_->createAddressQuery(proxy->getStreamHost().get().host); + resolveRequest->onResult.connect(boost::bind(&SOCKS5BytestreamProxiesManager::handleNameLookupResult, this, _1, _2, proxy)); + resolveRequest->run(); + } + } + else { + onDiscoveredProxiesChanged(); + } + proxyFinder_->stop(); +} + +void SOCKS5BytestreamProxiesManager::handleNameLookupResult(const std::vector& address, boost::optional error, S5BProxyRequest::ref proxy) { + if (error) { + onDiscoveredProxiesChanged(); + } + else { + if (address.empty()) { + SWIFT_LOG(warning) << "S5B proxy hostname does not resolve." << std::endl; + onDiscoveredProxiesChanged(); + } + else { + S5BProxyRequest::StreamHost streamHost = proxy->getStreamHost().get(); + streamHost.host = address[0].toString(); + proxy->setStreamHost(streamHost); + addS5BProxy(proxy); + } + } +} + +void SOCKS5BytestreamProxiesManager::queryForProxies() { + proxyFinder_ = boost::make_shared(serviceRoot_, iqRouter_); + + proxyFinder_->onProxyFound.connect(boost::bind(&SOCKS5BytestreamProxiesManager::handleProxyFound, this, _1)); + proxyFinder_->start(); +} + } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h index f3fed80..06db76c 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h @@ -4,6 +4,13 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + + #pragma once #include @@ -13,11 +20,13 @@ #include #include #include -#include -#include +#include namespace Swift { - class SOCKS5BytestreamProxiesDiscoverRequest; + class TimerFactory; + class ConnectionFactory; + class DomainNameResolver; + class DomainNameResolveError; /** * - manages list of working S5B proxies @@ -25,26 +34,44 @@ namespace Swift { */ class SWIFTEN_API SOCKS5BytestreamProxiesManager { public: - SOCKS5BytestreamProxiesManager(ConnectionFactory*, TimerFactory*); - - boost::shared_ptr createDiscoverProxiesRequest(); + SOCKS5BytestreamProxiesManager(ConnectionFactory*, TimerFactory*, DomainNameResolver*, IQRouter*, const JID&); + ~SOCKS5BytestreamProxiesManager(); void addS5BProxy(S5BProxyRequest::ref); - const std::vector& getS5BProxies() const; + + /* + * Returns a list of external S5B proxies. If the optinal return value is not initialized a discovery process has been started and + * onDiscoveredProxiesChanged signal will be emitted when it is finished. + */ + const boost::optional >& getOrDiscoverS5BProxies(); void connectToProxies(const std::string& sessionID); boost::shared_ptr getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID); boost::shared_ptr createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr); + public: + boost::signal onDiscoveredProxiesChanged; + + private: + void handleProxyFound(S5BProxyRequest::ref proxy); + void handleNameLookupResult(const std::vector&, boost::optional, S5BProxyRequest::ref proxy); + + void queryForProxies(); + private: - ConnectionFactory* connectionFactory; - TimerFactory* timerFactory; + ConnectionFactory* connectionFactory_; + TimerFactory* timerFactory_; + DomainNameResolver* resolver_; + IQRouter* iqRouter_; + JID serviceRoot_; typedef std::map > ProxyJIDClientSessionMap; - std::map proxySessions; + std::map proxySessions_; + + boost::shared_ptr proxyFinder_; - std::vector localS5BProxies; + boost::optional > localS5BProxies_; }; } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h index 8265157..54c2075 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h @@ -4,6 +4,13 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + + #pragma once #include @@ -17,6 +24,10 @@ namespace Swift { class JID; class IQRouter; +/* + * This class is designed to find possible SOCKS5 bytestream proxies which are used for peer-to-peer data transfers in + * restrictive environments. + */ class SOCKS5BytestreamProxyFinder { public: SOCKS5BytestreamProxyFinder(const JID& service, IQRouter *iqRouter); diff --git a/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp b/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp index 207f590..aaf90ea 100644 --- a/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp +++ b/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013-2014 Isode Limited. + * Copyright (c) 2013-2015 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,7 @@ public: void setUp() { crypto = boost::shared_ptr(PlatformCryptoProvider::create()); eventLoop = new DummyEventLoop(); + resolver = new StaticDomainNameResolver(eventLoop); session = boost::make_shared("foo@bar.com/baz", "mysession"); jingleContentPayload = make_shared(); // fakeRJTCSF = make_shared(); @@ -81,7 +83,7 @@ public: bytestreamServerManager = new SOCKS5BytestreamServerManager(bytestreamRegistry, serverConnectionFactory, networkEnvironment, natTraverser); idGenerator = new SimpleIDGenerator(); timerFactory = new DummyTimerFactory(); - bytestreamProxy = new SOCKS5BytestreamProxiesManager(connectionFactory, timerFactory); + bytestreamProxy = new SOCKS5BytestreamProxiesManager(connectionFactory, timerFactory, resolver, iqRouter, "bar.com"); ftTransporterFactory = new DefaultFileTransferTransporterFactory(bytestreamRegistry, bytestreamServerManager, bytestreamProxy, idGenerator, connectionFactory, timerFactory, crypto.get(), iqRouter); } @@ -94,6 +96,7 @@ public: delete bytestreamRegistry; delete iqRouter; delete stanzaChannel; + delete resolver; delete eventLoop; Log::setLogLevel(Log::error); } @@ -232,6 +235,7 @@ private: NetworkEnvironment* networkEnvironment; NATTraverser* natTraverser; IDGenerator* idGenerator; + DomainNameResolver* resolver; }; CPPUNIT_TEST_SUITE_REGISTRATION(IncomingJingleFileTransferTest); diff --git a/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.cpp b/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.cpp index 6e33f16..5cfd28d 100644 --- a/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.cpp +++ b/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.cpp @@ -4,6 +4,12 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + #include "S5BProxyRequestParser.h" #include @@ -20,7 +26,7 @@ S5BProxyRequestParser::~S5BProxyRequestParser() { void S5BProxyRequestParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) { if (element == "streamhost") { if (attributes.getAttributeValue("host") && attributes.getAttributeValue("jid") && attributes.getAttributeValue("port")) { - HostAddress address = attributes.getAttributeValue("host").get_value_or(""); + std::string host = attributes.getAttributeValue("host").get_value_or(""); int port = -1; JID jid = attributes.getAttributeValue("jid").get_value_or(""); @@ -29,9 +35,10 @@ void S5BProxyRequestParser::handleStartElement(const std::string& element, const } catch (boost::bad_lexical_cast &) { port = -1; } - if (address.isValid() && port != -1 && jid.isValid()) { + if (!host.empty() && port != -1 && jid.isValid()) { S5BProxyRequest::StreamHost streamHost; - streamHost.addressPort = HostAddressPort(address, port); + streamHost.host = host; + streamHost.port = port; streamHost.jid = jid; getPayloadInternal()->setStreamHost(streamHost); } diff --git a/Swiften/Serializer/PayloadSerializers/S5BProxyRequestSerializer.h b/Swiften/Serializer/PayloadSerializers/S5BProxyRequestSerializer.h index b523588..e7cdbe8 100644 --- a/Swiften/Serializer/PayloadSerializers/S5BProxyRequestSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/S5BProxyRequestSerializer.h @@ -4,6 +4,11 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ #pragma once @@ -23,8 +28,8 @@ namespace Swift { XMLElement queryElement("query", "http://jabber.org/protocol/bytestreams"); if (s5bProxyRequest && s5bProxyRequest->getStreamHost()) { boost::shared_ptr streamHost = boost::make_shared("streamhost"); - streamHost->setAttribute("host", s5bProxyRequest->getStreamHost().get().addressPort.getAddress().toString()); - streamHost->setAttribute("port", boost::lexical_cast(s5bProxyRequest->getStreamHost().get().addressPort.getPort())); + streamHost->setAttribute("host", s5bProxyRequest->getStreamHost().get().host); + streamHost->setAttribute("port", boost::lexical_cast(s5bProxyRequest->getStreamHost().get().port)); streamHost->setAttribute("jid", s5bProxyRequest->getStreamHost().get().jid.toString()); queryElement.addNode(streamHost); } else if (s5bProxyRequest && s5bProxyRequest->getActivate()) { -- cgit v0.10.2-6-g49f6