diff options
author | Tobias Markmann <tm@ayena.de> | 2015-01-09 16:39:11 (GMT) |
---|---|---|
committer | Swift Review <review@swift.im> | 2015-02-11 09:35:21 (GMT) |
commit | 779f0d57bc9d90300aad0b1386dc937612ac35f4 (patch) | |
tree | 2b7beb4db6af92eef45a6adaf0118d3ba149056b /Swiften/FileTransfer | |
parent | 66567c962202920b0d6bc06029ed37565cd4a81c (diff) | |
download | swift-779f0d57bc9d90300aad0b1386dc937612ac35f4.zip swift-779f0d57bc9d90300aad0b1386dc937612ac35f4.tar.bz2 |
Support domain names in S5B proxy <streamhost> 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
Diffstat (limited to 'Swiften/FileTransfer')
6 files changed, 158 insertions, 38 deletions
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 <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h> #include <boost/smart_ptr/make_shared.hpp> +#include <boost/bind.hpp> #include <Swiften/Base/foreach.h> #include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> #include <Swiften/Base/Log.h> +#include <Swiften/Network/DomainNameResolver.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/TimerFactory.h> +#include <Swiften/Network/DomainNameAddressQuery.h> +#include <Swiften/Network/DomainNameResolveError.h> 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<S5BProxyRequest::ref>(); + } + localS5BProxies_->push_back(proxy); + onDiscoveredProxiesChanged(); + } } -const std::vector<S5BProxyRequest::ref>& SOCKS5BytestreamProxiesManager::getS5BProxies() const { - return localS5BProxies; +const boost::optional<std::vector<S5BProxyRequest::ref> >& 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<Connection> conn = connectionFactory->createConnection(); + if (localS5BProxies_) { + foreach(S5BProxyRequest::ref proxy, localS5BProxies_.get()) { + boost::shared_ptr<Connection> conn = connectionFactory_->createConnection(); - boost::shared_ptr<SOCKS5BytestreamClientSession> session = boost::make_shared<SOCKS5BytestreamClientSession>(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<SOCKS5BytestreamClientSession> session = boost::make_shared<SOCKS5BytestreamClientSession>(conn, addressPort, sessionID, timerFactory_); + clientSessions[proxy->getStreamHost().get().jid] = session; + session->start(); + } } - proxySessions[sessionID] = clientSessions; + proxySessions_[sessionID] = clientSessions; } boost::shared_ptr<SOCKS5BytestreamClientSession> 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<SOCKS5BytestreamClientSession>(); } - if (proxySessions[sessionID].find(proxyJID) == proxySessions[sessionID].end()) { + if (proxySessions_[sessionID].find(proxyJID) == proxySessions_[sessionID].end()) { return boost::shared_ptr<SOCKS5BytestreamClientSession>(); } // get active session - boost::shared_ptr<SOCKS5BytestreamClientSession> activeSession = proxySessions[sessionID][proxyJID]; - proxySessions[sessionID].erase(proxyJID); + boost::shared_ptr<SOCKS5BytestreamClientSession> 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<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxiesManager::createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr) { - SOCKS5BytestreamClientSession::ref connection = boost::make_shared<SOCKS5BytestreamClientSession>(connectionFactory->createConnection(), addressPort, destAddr, timerFactory); + SOCKS5BytestreamClientSession::ref connection = boost::make_shared<SOCKS5BytestreamClientSession>(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<HostAddress>& address, boost::optional<DomainNameResolveError> 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<SOCKS5BytestreamProxyFinder>(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 <string> @@ -13,11 +20,13 @@ #include <Swiften/Elements/S5BProxyRequest.h> #include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> #include <Swiften/JID/JID.h> -#include <Swiften/Network/ConnectionFactory.h> -#include <Swiften/Network/TimerFactory.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h> 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<SOCKS5BytestreamProxiesDiscoverRequest> createDiscoverProxiesRequest(); + SOCKS5BytestreamProxiesManager(ConnectionFactory*, TimerFactory*, DomainNameResolver*, IQRouter*, const JID&); + ~SOCKS5BytestreamProxiesManager(); void addS5BProxy(S5BProxyRequest::ref); - const std::vector<S5BProxyRequest::ref>& 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<std::vector<S5BProxyRequest::ref> >& getOrDiscoverS5BProxies(); void connectToProxies(const std::string& sessionID); boost::shared_ptr<SOCKS5BytestreamClientSession> getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID); boost::shared_ptr<SOCKS5BytestreamClientSession> createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr); + public: + boost::signal<void ()> onDiscoveredProxiesChanged; + + private: + void handleProxyFound(S5BProxyRequest::ref proxy); + void handleNameLookupResult(const std::vector<HostAddress>&, boost::optional<DomainNameResolveError>, S5BProxyRequest::ref proxy); + + void queryForProxies(); + private: - ConnectionFactory* connectionFactory; - TimerFactory* timerFactory; + ConnectionFactory* connectionFactory_; + TimerFactory* timerFactory_; + DomainNameResolver* resolver_; + IQRouter* iqRouter_; + JID serviceRoot_; typedef std::map<JID, boost::shared_ptr<SOCKS5BytestreamClientSession> > ProxyJIDClientSessionMap; - std::map<std::string, ProxyJIDClientSessionMap> proxySessions; + std::map<std::string, ProxyJIDClientSessionMap> proxySessions_; + + boost::shared_ptr<SOCKS5BytestreamProxyFinder> proxyFinder_; - std::vector<S5BProxyRequest::ref> localS5BProxies; + boost::optional<std::vector<S5BProxyRequest::ref> > 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 <boost/shared_ptr.hpp> @@ -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 <Swiften/FileTransfer/IncomingJingleFileTransfer.h> #include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> #include <Swiften/Network/PlatformNetworkEnvironment.h> +#include <Swiften/Network/StaticDomainNameResolver.h> #include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h> #include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h> #include <Swiften/Jingle/FakeJingleSession.h> @@ -67,6 +68,7 @@ public: void setUp() { crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); eventLoop = new DummyEventLoop(); + resolver = new StaticDomainNameResolver(eventLoop); session = boost::make_shared<FakeJingleSession>("foo@bar.com/baz", "mysession"); jingleContentPayload = make_shared<JingleContentPayload>(); // fakeRJTCSF = make_shared<FakeRemoteJingleTransportCandidateSelectorFactory>(); @@ -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); |