From a3ee85a30d9db4903785637e06a0567c73a555ae Mon Sep 17 00:00:00 2001 From: sehraf Date: Sun, 9 Oct 2016 14:32:52 +0200 Subject: [PATCH] Add I2P BOB support to libretroashare and RetroShare GUI --- libresapi/src/api/RsControlModule.cpp | 6 +- libretroshare/src/libretroshare.pro | 15 +- libretroshare/src/pqi/authssl.cc | 34 +- libretroshare/src/pqi/p3notify.cc | 1 + libretroshare/src/pqi/p3notify.h | 1 + libretroshare/src/pqi/pqiperson.cc | 24 +- libretroshare/src/pqi/pqissli2pbob.cpp | 31 + libretroshare/src/pqi/pqissli2pbob.h | 31 + libretroshare/src/pqi/pqisslpersongrp.cc | 43 +- libretroshare/src/pqi/pqisslproxy.h | 2 +- libretroshare/src/retroshare/rsinit.h | 2 +- libretroshare/src/retroshare/rsnotify.h | 1 + libretroshare/src/rsserver/p3face-config.cc | 4 + libretroshare/src/rsserver/p3face.h | 4 +- libretroshare/src/rsserver/rsinit.cc | 83 +- .../src/services/autoproxy/p3i2pbob.cc | 1118 ++++++++++++ .../src/services/autoproxy/p3i2pbob.h | 248 +++ .../services/autoproxy/rsautoproxymonitor.cc | 305 ++++ .../services/autoproxy/rsautoproxymonitor.h | 216 +++ libretroshare/src/util/radix32.h | 50 + libretroshare/src/util/rsprint.cc | 21 + libretroshare/src/util/rsprint.h | 2 + retroshare-gui/src/gui/GenCertDialog.cpp | 38 +- retroshare-gui/src/gui/GenCertDialog.h | 1 + retroshare-gui/src/gui/GenCertDialog.ui | 7 + retroshare-gui/src/gui/notifyqt.cpp | 14 + retroshare-gui/src/gui/notifyqt.h | 2 + .../src/gui/qss/stylesheet/Standard.qss | 15 + .../src/gui/settings/ServerPage.cpp | 1576 +++++++++++------ retroshare-gui/src/gui/settings/ServerPage.h | 50 +- retroshare-gui/src/gui/settings/ServerPage.ui | 1164 ++++++++---- 31 files changed, 4150 insertions(+), 959 deletions(-) create mode 100644 libretroshare/src/pqi/pqissli2pbob.cpp create mode 100644 libretroshare/src/pqi/pqissli2pbob.h create mode 100644 libretroshare/src/services/autoproxy/p3i2pbob.cc create mode 100644 libretroshare/src/services/autoproxy/p3i2pbob.h create mode 100644 libretroshare/src/services/autoproxy/rsautoproxymonitor.cc create mode 100644 libretroshare/src/services/autoproxy/rsautoproxymonitor.h create mode 100644 libretroshare/src/util/radix32.h diff --git a/libresapi/src/api/RsControlModule.cpp b/libresapi/src/api/RsControlModule.cpp index ece94b7af..8b366686e 100644 --- a/libresapi/src/api/RsControlModule.cpp +++ b/libresapi/src/api/RsControlModule.cpp @@ -443,8 +443,10 @@ void RsControlModule::handleCreateLocation(Request &req, Response &resp) } } - if(hidden_port) - RsInit::SetHiddenLocation(hidden_address, hidden_port); + if(hidden_port) { + /// TODO add bob to webui + RsInit::SetHiddenLocation(hidden_address, hidden_port, false); + } std::string ssl_password = RSRandom::random_alphaNumericString(RsInit::getSslPwdLen()) ; diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 26fe31169..ce30ea5f6 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -140,7 +140,6 @@ PUBLIC_HEADERS = retroshare/rsdisc.h \ retroshare/rsversion.h \ retroshare/rsservicecontrol.h \ - HEADERS += plugins/pluginmanager.h \ plugins/dlfcn_win32.h \ rsitems/rspluginitems.h \ @@ -429,6 +428,7 @@ HEADERS += pqi/authssl.h \ pqi/pqissl.h \ pqi/pqissllistener.h \ pqi/pqisslpersongrp.h \ + pqi/pqissli2pbob.h \ pqi/pqissludp.h \ pqi/pqisslproxy.h \ pqi/pqistore.h \ @@ -493,7 +493,9 @@ HEADERS += rsitems/rsitem.h \ rsitems/rsgxsupdateitems.h \ rsitems/rsserviceinfoitems.h \ -HEADERS += services/p3msgservice.h \ +HEADERS += services/autoproxy/p3i2pbob.h \ + services/autoproxy/rsautoproxymonitor.h \ + services/p3msgservice.h \ services/p3service.h \ services/p3statusservice.h \ services/p3banlist.h \ @@ -518,6 +520,9 @@ HEADERS += util/folderiterator.h \ util/rsnet.h \ util/extaddrfinder.h \ util/dnsresolver.h \ + util/radix32.h \ + util/radix64.h \ + util/rsinitedptr.h \ util/rsprint.h \ util/rsstring.h \ util/rsstd.h \ @@ -525,7 +530,6 @@ HEADERS += util/folderiterator.h \ util/rsversioninfo.h \ util/rswin.h \ util/rsrandom.h \ - util/radix64.h \ util/pugiconfig.h \ util/rsmemcache.h \ util/rstickevent.h \ @@ -580,6 +584,7 @@ SOURCES += pqi/authgpg.cc \ pqi/pqissl.cc \ pqi/pqissllistener.cc \ pqi/pqisslpersongrp.cc \ + pqi/pqissli2pbob.cpp \ pqi/pqissludp.cc \ pqi/pqisslproxy.cc \ pqi/pqistore.cc \ @@ -638,7 +643,9 @@ SOURCES += serialiser/rsbaseserial.cc \ rsitems/rsgxsupdateitems.cc \ rsitems/rsserviceinfoitems.cc \ -SOURCES += services/p3msgservice.cc \ +SOURCES += services/autoproxy/rsautoproxymonitor.cc \ + services/autoproxy/p3i2pbob.cc \ + services/p3msgservice.cc \ services/p3service.cc \ services/p3statusservice.cc \ services/p3banlist.cc \ diff --git a/libretroshare/src/pqi/authssl.cc b/libretroshare/src/pqi/authssl.cc index d0a83643c..ebd336b85 100644 --- a/libretroshare/src/pqi/authssl.cc +++ b/libretroshare/src/pqi/authssl.cc @@ -1586,20 +1586,26 @@ bool AuthSSLimpl::FailedCertificate(X509 *x509, const RsPgpId& gpgid, switch(auth_diagnostic) { - case RS_SSL_HANDSHAKE_DIAGNOSTIC_CERTIFICATE_MISSING: RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_MISSING_CERTIFICATE, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); - break ; - case RS_SSL_HANDSHAKE_DIAGNOSTIC_CERTIFICATE_NOT_VALID: RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_BAD_CERTIFICATE, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); - break ; - case RS_SSL_HANDSHAKE_DIAGNOSTIC_ISSUER_UNKNOWN: RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_UNKNOWN_IN , gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); - break ; - case RS_SSL_HANDSHAKE_DIAGNOSTIC_MALLOC_ERROR: RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_INTERNAL_ERROR , gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); - break ; - case RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE: RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_WRONG_SIGNATURE, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); - break ; - case RS_SSL_HANDSHAKE_DIAGNOSTIC_OK: - case RS_SSL_HANDSHAKE_DIAGNOSTIC_UNKNOWN: - default: - RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_CONNECT_ATTEMPT, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); + case RS_SSL_HANDSHAKE_DIAGNOSTIC_CERTIFICATE_MISSING: + RsServer::notify()->notifyConnectionWithoutCert(); + RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_MISSING_CERTIFICATE, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); + break ; + case RS_SSL_HANDSHAKE_DIAGNOSTIC_CERTIFICATE_NOT_VALID: + RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_BAD_CERTIFICATE, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); + break ; + case RS_SSL_HANDSHAKE_DIAGNOSTIC_ISSUER_UNKNOWN: + RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_UNKNOWN_IN , gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); + break ; + case RS_SSL_HANDSHAKE_DIAGNOSTIC_MALLOC_ERROR: + RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_INTERNAL_ERROR , gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); + break ; + case RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE: + RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_WRONG_SIGNATURE, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); + break ; + case RS_SSL_HANDSHAKE_DIAGNOSTIC_OK: + case RS_SSL_HANDSHAKE_DIAGNOSTIC_UNKNOWN: + default: + RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_CONNECT_ATTEMPT, gpgid.toStdString(), sslid.toStdString(), sslcn, ip_address); } #ifdef AUTHSSL_DEBUG diff --git a/libretroshare/src/pqi/p3notify.cc b/libretroshare/src/pqi/p3notify.cc index c110665f8..bd92891cf 100644 --- a/libretroshare/src/pqi/p3notify.cc +++ b/libretroshare/src/pqi/p3notify.cc @@ -237,6 +237,7 @@ void p3Notify::notifyOwnStatusMessageChanged() void p3Notify::notifyDiskFull (uint32_t location , uint32_t size_limit_in_MB ) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyDiskFull (location,size_limit_in_MB) ; } void p3Notify::notifyPeerStatusChanged (const std::string& peer_id , uint32_t status ) { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyPeerStatusChanged (peer_id,status) ; } void p3Notify::notifyGxsChange (const RsGxsChanges& changes) {FOR_ALL_NOTIFY_CLIENTS (*it)->notifyGxsChange(changes) ;} +void p3Notify::notifyConnectionWithoutCert () { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyConnectionWithoutCert(); } void p3Notify::notifyPeerStatusChangedSummary () { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyPeerStatusChangedSummary() ; } void p3Notify::notifyDiscInfoChanged () { FOR_ALL_NOTIFY_CLIENTS (*it)->notifyDiscInfoChanged () ; } diff --git a/libretroshare/src/pqi/p3notify.h b/libretroshare/src/pqi/p3notify.h index 60b3759a6..f39201ea7 100644 --- a/libretroshare/src/pqi/p3notify.h +++ b/libretroshare/src/pqi/p3notify.h @@ -112,6 +112,7 @@ class p3Notify: public RsNotify void notifyDiskFull (uint32_t /* location */, uint32_t /* size limit in MB */) ; void notifyPeerStatusChanged (const std::string& /* peer_id */, uint32_t /* status */) ; void notifyGxsChange (const RsGxsChanges& /* changes */); + void notifyConnectionWithoutCert (); void notifyPeerStatusChangedSummary () ; void notifyDiscInfoChanged () ; diff --git a/libretroshare/src/pqi/pqiperson.cc b/libretroshare/src/pqi/pqiperson.cc index e7d1cf18b..7f33a3e1b 100644 --- a/libretroshare/src/pqi/pqiperson.cc +++ b/libretroshare/src/pqi/pqiperson.cc @@ -521,12 +521,14 @@ int pqiperson::connect(uint32_t type, const sockaddr_storage &raddr, return 0; } + pqiconnect *pqi = it->second; + #ifdef PERSON_DEBUG std::cerr << "pqiperson::connect() resetting for new connection attempt" << std::endl; #endif /* set the parameters */ - (it->second)->reset(); + pqi->reset(); #ifdef PERSON_DEBUG std::cerr << "pqiperson::connect() clearing rate cap" << std::endl; @@ -538,22 +540,22 @@ int pqiperson::connect(uint32_t type, const sockaddr_storage &raddr, #endif // These two are universal. - (it->second)->connect_parameter(NET_PARAM_CONNECT_DELAY, delay); - (it->second)->connect_parameter(NET_PARAM_CONNECT_TIMEOUT, timeout); + pqi->connect_parameter(NET_PARAM_CONNECT_DELAY, delay); + pqi->connect_parameter(NET_PARAM_CONNECT_TIMEOUT, timeout); // these 5 are only used by UDP connections. - (it->second)->connect_parameter(NET_PARAM_CONNECT_PERIOD, period); - (it->second)->connect_parameter(NET_PARAM_CONNECT_FLAGS, flags); - (it->second)->connect_parameter(NET_PARAM_CONNECT_BANDWIDTH, bandwidth); + pqi->connect_parameter(NET_PARAM_CONNECT_PERIOD, period); + pqi->connect_parameter(NET_PARAM_CONNECT_FLAGS, flags); + pqi->connect_parameter(NET_PARAM_CONNECT_BANDWIDTH, bandwidth); - (it->second)->connect_additional_address(NET_PARAM_CONNECT_PROXY, proxyaddr); - (it->second)->connect_additional_address(NET_PARAM_CONNECT_SOURCE, srcaddr); + pqi->connect_additional_address(NET_PARAM_CONNECT_PROXY, proxyaddr); + pqi->connect_additional_address(NET_PARAM_CONNECT_SOURCE, srcaddr); // These are used by Proxy/Hidden - (it->second)->connect_parameter(NET_PARAM_CONNECT_DOMAIN_ADDRESS, domain_addr); - (it->second)->connect_parameter(NET_PARAM_CONNECT_REMOTE_PORT, domain_port); + pqi->connect_parameter(NET_PARAM_CONNECT_DOMAIN_ADDRESS, domain_addr); + pqi->connect_parameter(NET_PARAM_CONNECT_REMOTE_PORT, domain_port); - (it->second)->connect(raddr); + pqi->connect(raddr); // flag if we started a new connectionAttempt. inConnectAttempt = true; diff --git a/libretroshare/src/pqi/pqissli2pbob.cpp b/libretroshare/src/pqi/pqissli2pbob.cpp new file mode 100644 index 000000000..4b1b05dc6 --- /dev/null +++ b/libretroshare/src/pqi/pqissli2pbob.cpp @@ -0,0 +1,31 @@ +#include "pqissli2pbob.h" + +bool pqissli2pbob::connect_parameter(uint32_t type, const std::string &value) +{ + if (type == NET_PARAM_CONNECT_DOMAIN_ADDRESS) + { + RS_STACK_MUTEX(mSslMtx); + // a new line must be appended! + mI2pAddr = value + '\n'; + return true; + } + + return pqissl::connect_parameter(type, value); +} + +int pqissli2pbob::Basic_Connection_Complete() +{ + int ret; + + if ((ret = pqissl::Basic_Connection_Complete()) != 1) + { + // basic connection not complete. + return ret; + } + + // send addr. (new line is already appended) + ret = send(sockfd, mI2pAddr.c_str(), mI2pAddr.length(), 0); + if (ret != (int)mI2pAddr.length()) + return -1; + return 1; +} diff --git a/libretroshare/src/pqi/pqissli2pbob.h b/libretroshare/src/pqi/pqissli2pbob.h new file mode 100644 index 000000000..e36112c08 --- /dev/null +++ b/libretroshare/src/pqi/pqissli2pbob.h @@ -0,0 +1,31 @@ +#ifndef PQISSLI2PBOB_H +#define PQISSLI2PBOB_H + +#include "pqi/pqissl.h" + +/* + * This class is a minimal varied version of pqissl to work with I2P BOB tunnels. + * The only difference is that the [.b32].i2p addresses must be sent first. + * + * Everything else is untouched. + */ + +class pqissli2pbob : public pqissl +{ +public: + pqissli2pbob(pqissllistener *l, PQInterface *parent, p3LinkMgr *lm) + : pqissl(l, parent, lm) {} + + // NetInterface interface +public: + bool connect_parameter(uint32_t type, const std::string &value); + + // pqissl interface +protected: + int Basic_Connection_Complete(); + +private: + std::string mI2pAddr; +}; + +#endif // PQISSLI2PBOB_H diff --git a/libretroshare/src/pqi/pqisslpersongrp.cc b/libretroshare/src/pqi/pqisslpersongrp.cc index 3670fb5fe..6e6847dc0 100644 --- a/libretroshare/src/pqi/pqisslpersongrp.cc +++ b/libretroshare/src/pqi/pqisslpersongrp.cc @@ -24,6 +24,7 @@ */ #include "serialiser/rsserializer.h" +#include "services/autoproxy/rsautoproxymonitor.h" #include "util/rsdebug.h" #include "pqi/pqisslpersongrp.h" @@ -49,6 +50,7 @@ static struct RsLog::logInfo pqipersongrpzoneInfo = {RsLog::Default, "pqipersong #endif #include "pqi/pqisslproxy.h" +#include "pqi/pqissli2pbob.h" pqilistener * pqisslpersongrp::locked_createListener(const struct sockaddr_storage &laddr) { @@ -76,29 +78,34 @@ pqiperson * pqisslpersongrp::locked_createPerson(const RsPeerId& id, pqilistener std::cerr << std::endl; #endif - pqisslproxy *pqis = new pqisslproxy((pqissllistener *) listener, pqip, mLinkMgr); - - /* construct the serialiser .... - * Needs: - * * FileItem - * * FileData - * * ServiceGeneric - */ + // Use pqicI2PBOB for I2P + pqiconnect *pqicSOCKSProxy, *pqicI2PBOB; + { + pqisslproxy *pqis = new pqisslproxy((pqissllistener *) listener, pqip, mLinkMgr); + RsSerialiser *rss = new RsSerialiser(); + rss->addSerialType(new RsRawSerialiser()); + pqicSOCKSProxy = new pqiconnect(pqip, rss, pqis); + } + if (rsAutoProxyMonitor::instance()->isEnabled(autoProxyType::I2PBOB)) + { + pqissli2pbob *pqis = new pqissli2pbob((pqissllistener *) listener, pqip, mLinkMgr); + RsSerialiser *rss = new RsSerialiser(); + rss->addSerialType(new RsRawSerialiser()); + + pqicI2PBOB = new pqiconnect(pqip, rss, pqis); + } else { + pqicI2PBOB = pqicSOCKSProxy; + } + - - RsSerialiser *rss = new RsSerialiser(); - rss->addSerialType(new RsRawSerialiser()); - - pqiconnect *pqisc = new pqiconnect(pqip, rss, pqis); - /* first select type based on peer */ uint32_t typePeer = mPeerMgr->getHiddenType(id); switch (typePeer) { case RS_HIDDEN_TYPE_TOR: - pqip -> addChildInterface(PQI_CONNECT_HIDDEN_TOR_TCP, pqisc); + pqip -> addChildInterface(PQI_CONNECT_HIDDEN_TOR_TCP, pqicSOCKSProxy); break; case RS_HIDDEN_TYPE_I2P: - pqip -> addChildInterface(PQI_CONNECT_HIDDEN_I2P_TCP, pqisc); + pqip -> addChildInterface(PQI_CONNECT_HIDDEN_I2P_TCP, pqicI2PBOB); break; default: /* peer is not a hidden one but we are */ @@ -106,7 +113,7 @@ pqiperson * pqisslpersongrp::locked_createPerson(const RsPeerId& id, pqilistener uint32_t typeOwn = mPeerMgr->getHiddenType(AuthSSL::getAuthSSL()->OwnId()); switch (typeOwn) { case RS_HIDDEN_TYPE_I2P: - pqip -> addChildInterface(PQI_CONNECT_HIDDEN_I2P_TCP, pqisc); + pqip -> addChildInterface(PQI_CONNECT_HIDDEN_I2P_TCP, pqicI2PBOB); break; default: /* this case shouldn't happen! */ @@ -117,7 +124,7 @@ pqiperson * pqisslpersongrp::locked_createPerson(const RsPeerId& id, pqilistener std::cerr << " - hidden types: peer=" << typePeer << " own=" << typeOwn << std::endl; std::cerr << " --> falling back to Tor" << std::endl; case RS_HIDDEN_TYPE_TOR: - pqip -> addChildInterface(PQI_CONNECT_HIDDEN_TOR_TCP, pqisc); + pqip -> addChildInterface(PQI_CONNECT_HIDDEN_TOR_TCP, pqicSOCKSProxy); break; } } diff --git a/libretroshare/src/pqi/pqisslproxy.h b/libretroshare/src/pqi/pqisslproxy.h index f9918832f..347a9fa7f 100755 --- a/libretroshare/src/pqi/pqisslproxy.h +++ b/libretroshare/src/pqi/pqisslproxy.h @@ -81,7 +81,7 @@ private: uint32_t mProxyState; std::string mDomainAddress; - uint16_t mRemotePort; + uint16_t mRemotePort; }; #endif // MRK_PQI_SSL_PROXY_HEADER diff --git a/libretroshare/src/retroshare/rsinit.h b/libretroshare/src/retroshare/rsinit.h index c7abc7bf6..18326d3a1 100644 --- a/libretroshare/src/retroshare/rsinit.h +++ b/libretroshare/src/retroshare/rsinit.h @@ -78,7 +78,7 @@ class RsInit /*! * Setup Hidden Location; */ - static bool SetHiddenLocation(const std::string& hiddenaddress, uint16_t port); + static void SetHiddenLocation(const std::string& hiddenaddress, uint16_t port, bool useBob); static bool LoadPassword(const std::string& passwd) ; diff --git a/libretroshare/src/retroshare/rsnotify.h b/libretroshare/src/retroshare/rsnotify.h index 7ca7385ee..8a2dfff8b 100644 --- a/libretroshare/src/retroshare/rsnotify.h +++ b/libretroshare/src/retroshare/rsnotify.h @@ -228,6 +228,7 @@ class NotifyClient virtual void notifyDiskFull (uint32_t /* location */, uint32_t /* size limit in MB */) {} virtual void notifyPeerStatusChanged (const std::string& /* peer_id */, uint32_t /* status */) {} virtual void notifyGxsChange (const RsGxsChanges& /* changes */) {} + virtual void notifyConnectionWithoutCert () {} /* one or more peers has changed the states */ virtual void notifyPeerStatusChangedSummary () {} diff --git a/libretroshare/src/rsserver/p3face-config.cc b/libretroshare/src/rsserver/p3face-config.cc index 4b1f12036..be9a75a82 100644 --- a/libretroshare/src/rsserver/p3face-config.cc +++ b/libretroshare/src/rsserver/p3face-config.cc @@ -45,6 +45,8 @@ const int p3facemsgzone = 11453; // TO SHUTDOWN THREADS. #ifdef RS_ENABLE_GXS +#include "services/autoproxy/rsautoproxymonitor.h" + #include "services/p3idservice.h" #include "services/p3gxscircles.h" #include "services/p3wiki.h" @@ -89,6 +91,8 @@ void RsServer::rsGlobalShutDown() mNetMgr->shutdown(); /* Handles UPnP */ + rsAutoProxyMonitor::instance()->stopAllRSShutdown(); + fullstop() ; // kill all registered service threads diff --git a/libretroshare/src/rsserver/p3face.h b/libretroshare/src/rsserver/p3face.h index 3d88e22fb..41da04d33 100644 --- a/libretroshare/src/rsserver/p3face.h +++ b/libretroshare/src/rsserver/p3face.h @@ -46,6 +46,7 @@ class p3heartbeat; class p3discovery2; +class p3I2pBob; /* GXS Classes - just declare the classes. so we don't have to totally recompile to switch */ @@ -129,7 +130,7 @@ class RsServer: public RsControl, public RsTickingThread * This function is responsible for ensuring Retroshare exits in a legal state: * i.e. releases all held resources and saves current configuration */ - virtual void rsGlobalShutDown( ); + virtual void rsGlobalShutDown( ); /****************************************/ @@ -164,6 +165,7 @@ class RsServer: public RsControl, public RsTickingThread p3ChatService *chatSrv; p3StatusService *mStatusSrv; p3GxsTunnelService *mGxsTunnels; + p3I2pBob *mI2pBob; // This list contains all threaded services. It will be used to shut them down properly. diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index fd378b286..42860efab 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -121,6 +121,8 @@ class RsInitConfig std::string hiddenNodeAddress; uint16_t hiddenNodePort; + bool hiddenNodeI2PBOB; + /* Logging */ bool haveLogFile; bool outStderr; @@ -790,13 +792,13 @@ void RsInit::setAutoLogin(bool autoLogin){ } /* Setup Hidden Location; */ -bool RsInit::SetHiddenLocation(const std::string& hiddenaddress, uint16_t port) +void RsInit::SetHiddenLocation(const std::string& hiddenaddress, uint16_t port, bool useBob) { /* parse the bugger (todo) */ rsInitConfig->hiddenNodeSet = true; rsInitConfig->hiddenNodeAddress = hiddenaddress; rsInitConfig->hiddenNodePort = port; - return true; + rsInitConfig->hiddenNodeI2PBOB = useBob; } @@ -850,7 +852,10 @@ RsGRouter *rsGRouter = NULL ; #include "upnp/upnphandler_miniupnp.h" #endif #endif - + +#include "services/autoproxy/p3i2pbob.h" +#include "services/autoproxy/rsautoproxymonitor.h" + #include "services/p3gxsreputation.h" #include "services/p3serviceinfo.h" #include "services/p3heartbeat.h" @@ -1045,8 +1050,11 @@ int RsServer::StartupRetroShare() mPeerMgr->setManagers(mLinkMgr, mNetMgr); mNetMgr->setManagers(mPeerMgr, mLinkMgr); - - + + rsAutoProxyMonitor *autoProxy = rsAutoProxyMonitor::instance(); + mI2pBob = new p3I2pBob(mPeerMgr); + autoProxy->addProxy(autoProxyType::I2PBOB, mI2pBob); + //load all the SSL certs as friends // std::list sslIds; // AuthSSL::getAuthSSL()->getAuthenticatedList(sslIds); @@ -1260,12 +1268,6 @@ int RsServer::StartupRetroShare() rsFiles = ftserver; - - /* create Cache Services */ - std::string config_dir = rsAccounts->PathAccountDirectory(); - std::string localcachedir = config_dir + "/cache/local"; - std::string remotecachedir = config_dir + "/cache/remote"; - std::vector plugins_directories ; #ifdef __APPLE__ @@ -1672,6 +1674,7 @@ int RsServer::StartupRetroShare() //mConfigMgr->addConfiguration("photo.cfg", photo_ns); //mConfigMgr->addConfiguration("wire.cfg", wire_ns); #endif + mConfigMgr->addConfiguration("I2PBOB.cfg", mI2pBob); mPluginsManager->addConfigurations(mConfigMgr) ; @@ -1717,12 +1720,46 @@ int RsServer::StartupRetroShare() { mPeerMgr->setOwnNetworkMode(RS_NET_MODE_EXT); mPeerMgr->setOwnVisState(RS_VS_DISC_FULL, RS_VS_DHT_FULL); - } if (rsInitConfig->hiddenNodeSet) { - mPeerMgr->setupHiddenNode(rsInitConfig->hiddenNodeAddress, rsInitConfig->hiddenNodePort); + std::cout << "RsServer::StartupRetroShare setting up hidden locations" << std::endl; + + if (rsInitConfig->hiddenNodeI2PBOB) { + std::cout << "RsServer::StartupRetroShare setting up BOB" << std::endl; + + // we need a local port! + mNetMgr->checkNetAddress(); + + // add i2p proxy + // bob will use this address + sockaddr_storage i2pInstance; + sockaddr_storage_ipv4_aton(i2pInstance, rsInitConfig->hiddenNodeAddress.c_str()); + mPeerMgr->setProxyServerAddress(RS_HIDDEN_TYPE_I2P, i2pInstance); + + std::string addr; // will be set by auto proxy service + uint16_t port = rsInitConfig->hiddenNodePort; // unused by bob + + bool r = autoProxy->initialSetup(autoProxyType::I2PBOB, addr, port); + + if (r && !addr.empty()) { + mPeerMgr->setupHiddenNode(addr, port); + + // now enable bob + bobSettings bs; + autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::getSettings, &bs); + bs.enableBob = true; + autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &bs); + } else { + std::cerr << "RsServer::StartupRetroShare failed to receive keys" << std::endl; + /// TODO add notify for failed bob setup + } + } else { + mPeerMgr->setupHiddenNode(rsInitConfig->hiddenNodeAddress, rsInitConfig->hiddenNodePort); + } + + std::cout << "RsServer::StartupRetroShare hidden location set up" << std::endl; } else if (isHiddenNode) { @@ -1731,15 +1768,27 @@ int RsServer::StartupRetroShare() mNetMgr -> checkNetAddress(); + if (rsInitConfig->hiddenNodeSet) { + // newly created location + // mNetMgr->checkNetAddress() will setup ports for us + // trigger updates for auto proxy services + std::vector types; + + // i2p bob need to rebuild its command map + types.push_back(autoProxyType::I2PBOB); + + rsAutoProxyMonitor::taskSync(types, autoProxyTask::reloadConfig); + } + /**************************************************************************/ /* startup (stuff dependent on Ids/peers is after this point) */ /**************************************************************************/ + autoProxy->startAll(); + pqih->init_listener(); mNetMgr->addNetListener(pqih); /* add listener so we can reset all sockets later */ - - /**************************************************************************/ /* load caches and secondary data */ /**************************************************************************/ @@ -1766,8 +1815,10 @@ int RsServer::StartupRetroShare() /* Start up Threads */ /**************************************************************************/ -#ifdef RS_ENABLE_GXS + // auto proxy threads + startServiceThread(mI2pBob, "I2P-BOB"); +#ifdef RS_ENABLE_GXS // Must Set the GXS pointers before starting threads. rsIdentity = mGxsIdService; rsGxsCircles = mGxsCircles; diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.cc b/libretroshare/src/services/autoproxy/p3i2pbob.cc new file mode 100644 index 000000000..5d3c4c6c0 --- /dev/null +++ b/libretroshare/src/services/autoproxy/p3i2pbob.cc @@ -0,0 +1,1118 @@ +#include + +#include "p3i2pbob.h" + +#include "pqi/p3peermgr.h" +#include "rsitems/rsconfigitems.h" +#include "util/radix32.h" +#include "util/radix64.h" +#include "util/rsdebug.h" +#include "util/rsprint.h" +#include "util/rsrandom.h" + +static const std::string kConfigKeyBOBEnable = "BOB_ENABLE"; +static const std::string kConfigKeyBOBKey = "BOB_KEY"; +static const std::string kConfigKeyBOBAddr = "BOB_ADDR"; +static const std::string kConfigKeyInLength = "IN_LENGTH"; +static const std::string kConfigKeyInQuantity = "IN_QUANTITY"; +static const std::string kConfigKeyInVariance = "IN_VARIANCE"; +static const std::string kConfigKeyOutLength = "OUT_LENGTH"; +static const std::string kConfigKeyOutQuantity = "OUT_QUANTITY"; +static const std::string kConfigKeyOutVariance = "OUT_VARIANCE"; + +static const bool kDefaultBOBEnable = false; +static const int8_t kDefaultLength = 3; +static const int8_t kDefaultQuantity = 4; +static const int8_t kDefaultVariance = 0; + +/// Sleep duration for receiving loop +static const useconds_t sleepTimeRecv = 10; // times 1000 = 10ms +/// Sleep duration for everything else +static const useconds_t sleepTimeWait = 50; // times 1000 = 50ms or 0.05s +static const int sleepFactorDefault = 10; // 0.5s +static const int sleepFactorFast = 1; // 0.05s +static const int sleepFactorSlow = 20; // 1s + +static struct RsLog::logInfo i2pBobLogInfo = {RsLog::Debug_All, "p3I2pBob"}; + +static const time_t selfCheckPeroid = 30; + +void doSleep(useconds_t timeToSleepMS) { +#ifndef WINDOWS_SYS + usleep((useconds_t) (timeToSleepMS * 1000)); +#else + Sleep((int) (timeToSleepMS)); +#endif +} + +p3I2pBob::p3I2pBob(p3PeerMgr *peerMgr) + : RsTickingThread(), p3Config(), + mState(csIdel), mTask(ctIdle), + mStateOld(csIdel), mTaskOld(ctIdle), + mBOBState(bsCleared), mPeerMgr(peerMgr), + mConfigLoaded(false), mSocket(0), + mLastProxyCheck(time(NULL)), + mProcessing(NULL), mLock("I2P-BOB") +{ + // set defaults + mSetting.enableBob = kDefaultBOBEnable; + mSetting.keys = ""; + mSetting.addr = ""; + mSetting.inLength = kDefaultLength; + mSetting.inQuantity = kDefaultQuantity; + mSetting.inVariance = kDefaultVariance; + mSetting.outLength = kDefaultLength; + mSetting.outQuantity = kDefaultQuantity; + mSetting.outVariance = kDefaultVariance; + + mCommands.clear(); +} + +bool p3I2pBob::isEnabled() +{ + RS_STACK_MUTEX(mLock); + return mSetting.enableBob; +} + +bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/) +{ + std::cout << "p3I2pBob::initialSetup" << std::endl; + + // update config + { + RS_STACK_MUTEX(mLock); + if (!mConfigLoaded) { + finalizeSettings_locked(); + mConfigLoaded = true; + } else { + updateSettings_locked(); + } + } + + std::cout << "p3I2pBob::initialSetup config updated" << std::endl; + + // request keys + // p3I2pBob::stateMachineBOB expects mProcessing to be set therefore + // we create this fake ticket without a callback or data + // ticket gets deleted later by this service + taskTicket *fakeTicket = rsAutoProxyMonitor::getTicket(); + fakeTicket->task = autoProxyTask::receiveKey; + processTaskAsync(fakeTicket); + + std::cout << "p3I2pBob::initialSetup fakeTicket requested" << std::endl; + + // now start thread + start("I2P-BOB gen key"); + + std::cout << "p3I2pBob::initialSetup thread started" << std::endl; + + int counter = 0; + // wait for keys + for(;;) { + doSleep(sleepTimeWait * sleepFactorDefault); + + RS_STACK_MUTEX(mLock); + + // wait for tast change + if (mTask != ctRunGetKeys) + break; + + if (++counter > 30) { + std::cout << "p3I2pBob::initialSetup timeout!" << std::endl; + return false; + } + } + + std::cout << "p3I2pBob::initialSetup got keys" << std::endl; + + // stop thread + fullstop(); + + std::cout << "p3I2pBob::initialSetup thread stopped" << std::endl; + + { + RS_STACK_MUTEX(mLock); + addr = mSetting.addr; + } + + std::cout << "p3I2pBob::initialSetup addr '" << addr << "'" << std::endl; + + return true; +} + +void p3I2pBob::processTaskAsync(taskTicket *ticket) +{ + switch (ticket->task) { + case autoProxyTask::start: + case autoProxyTask::stop: + case autoProxyTask::receiveKey: + case autoProxyTask::proxyStatusCheck: + { + RS_STACK_MUTEX(mLock); + mPending.push(ticket); + } + break; + default: + rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::processTaskAsync unknown task"); + rsAutoProxyMonitor::taskError(ticket); + break; + } +} + +void p3I2pBob::processTaskSync(taskTicket *ticket) +{ + bool data = !!ticket->data; + + // check wether we can process the task immediately or have to queue it + switch (ticket->task) { + case autoProxyTask::status: + // check if everything needed is set + if (!data) { + rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::status autoProxyTask::status data is missing"); + rsAutoProxyMonitor::taskError(ticket); + break; + } + + // get states + getStates((struct bobStates*)ticket->data); + + // finish task + rsAutoProxyMonitor::taskDone(ticket, autoProxyStatus::ok); + break; + case autoProxyTask::getSettings: + // check if everything needed is set + if (!data) { + rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::data_tick autoProxyTask::getSettings data is missing"); + rsAutoProxyMonitor::taskError(ticket); + break; + } + + // get settings + getBOBSettings((struct bobSettings *)ticket->data); + + // finish task + rsAutoProxyMonitor::taskDone(ticket, autoProxyStatus::ok); + break; + case autoProxyTask::setSettings: + // check if everything needed is set + if (!data) { + rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::data_tick autoProxyTask::setSettings data is missing"); + rsAutoProxyMonitor::taskError(ticket); + break; + } + + // set settings + setBOBSettings((struct bobSettings *)ticket->data); + + // finish task + rsAutoProxyMonitor::taskDone(ticket, autoProxyStatus::ok); + break; + case autoProxyTask::reloadConfig: + { + RS_STACK_MUTEX(mLock); + updateSettings_locked(); + } + rsAutoProxyMonitor::taskDone(ticket, autoProxyStatus::ok); + break; + case autoProxyTask::getErrorInfo: + if (!data) { + rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::data_tick autoProxyTask::getErrorInfo data is missing"); + rsAutoProxyMonitor::taskError(ticket); + } else { + RS_STACK_MUTEX(mLock); + *(std::string *)ticket->data = mErrorMsg; + rsAutoProxyMonitor::taskDone(ticket, autoProxyStatus::ok); + } + break; + default: + rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::processTaskSync unknown task"); + rsAutoProxyMonitor::taskError(ticket); + break; + } +} + +std::string p3I2pBob::keyToBase32Addr(const std::string &key) +{ + std::string copy(key); + + // replace I2P specific chars + std::replace(copy.begin(), copy.end(), '~', '/'); + std::replace(copy.begin(), copy.end(), '-', '+'); + + // decode + std::vector bin = Radix64::decode(copy); + // hash + std::vector sha256 = RsUtil::BinToSha256(bin); + // encode + std::string out = Radix32::encode(sha256); + + // i2p uses lowercase + std::transform(out.begin(), out.end(), out.begin(), ::tolower); + out.append(".b32.i2p"); + + return out; +} + +bool inline isAnswerOk(const std::string &answer) { + return (answer.compare(0, 2, "OK") == 0); +} + +bool inline isTunnelActiveError(const std::string &answer) { + return answer.compare(0, 22, "ERROR tunnel is active") == 0; +} + +void p3I2pBob::data_tick() +{ + int sleepTime = 0; + { + RS_STACK_MUTEX(mLock); + std::stringstream ss; + ss << "data_tick mState: " << mState << " mTask: " << mTask << " mBOBState: " << mBOBState << " mPending: " << mPending.size(); + rslog(RsLog::Debug_All, &i2pBobLogInfo, ss.str()); + } + + sleepTime += stateMachineController(); + sleepTime += stateMachineBOB(); + + sleepTime >>= 1; + + // sleep outisde of lock! + doSleep(sleepTime * sleepTimeWait); +} + +int p3I2pBob::stateMachineBOB() +{ + std::string answer; + bobStateInfo currentState; + + { + RS_STACK_MUTEX(mLock); + if (mBOBState == bsCleared || !mConfigLoaded) { + // we don't have work to do - sleep longer + return sleepFactorSlow; + } + + // get next command + currentState = mCommands[mBOBState]; + } + + // this call can take a while + // do NOT hold the lock + answer = executeCommand(currentState.command); + + // can hold the lock for the rest of the function + RS_STACK_MUTEX(mLock); + + // special state first + if (mBOBState == bsList) { + int counter = 0; + while (answer.find("OK Listing done") == std::string::npos) { + std::stringstream ss; + ss << "stateMachineBOB status check: read loop, counter: " << counter; + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, ss.str()); + answer += recv(); + counter++; + } + + if (answer.find(mTunnelName) == std::string::npos) { + rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineBOB status check: tunnel down!"); + // signal error + *((bool *)mProcessing->data) = true; + } + + mBOBState = currentState.nextState; + } else if (isAnswerOk(answer)) { + // check for other special states + std::string key; + switch (mBOBState) { + case bsNewkeysN: + key = answer.substr(3, answer.length()-3); + mSetting.addr = keyToBase32Addr(key); + IndicateConfigChanged(); + break; + case bsGetkeys: + key = answer.substr(3, answer.length()-3); + mSetting.keys = key; + IndicateConfigChanged(); + break; + default: + break; + } + + // goto next command + mBOBState = currentState.nextState; + } else { + return stateMachineBOB_locked_failure(answer, currentState); + } + return sleepFactorFast; +} + +int p3I2pBob::stateMachineBOB_locked_failure(const std::string &answer, const bobStateInfo ¤tState) +{ + // wait in case of active tunnel + // happens when trying to clear a stopping tunnel + if (isTunnelActiveError(answer)) { + return sleepFactorDefault; + } + + rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineBOB FAILED to run command '" + currentState.command + "'"); + rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineBOB '" + answer + "'"); + + mErrorMsg.append("FAILED to run command '" + currentState.command + "'" + '\n'); + mErrorMsg.append("reason '" + answer + "'" + '\n'); + + // this error handling needs testing! + mStateOld = mState; + mState = csError; + switch (mBOBState) { + case bsGetnick: + // failed getting nick + // tunnel is probably non existing + case bsClear: + // tunnel is cleared + mBOBState = bsQuit; + break; + case bsStop: + // failed stopping + // tunnel us probably not running + // continue to clearing + mBOBState = bsClear; + break; + case bsQuit: + // this can happen when the + // connection is somehow broken + // just try to disconnect + disconnectI2P(); + mBOBState = bsCleared; + break; + default: + // try to recover + mBOBState = bsGetnick; + break; + } + + return sleepFactorFast; +} + +int p3I2pBob::stateMachineController() +{ + RS_STACK_MUTEX(mLock); + + switch (mState) { + case csIdel: + return stateMachineController_locked_idle(); + case csDoConnect: + if (!connectI2P()) { + rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController doConnect: unable to connect"); + mStateOld = mState; + mState = csError; + mErrorMsg = "unable to connect to BOB port"; + return sleepFactorSlow; + } + + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController doConnect: connected"); + mState = csConnected; + break; + case csConnected: + return stateMachineController_locked_connected(); + case csWaitForBob: + // check connection problems + if (mSocket == 0) { + rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController waitForBob: conection lost"); + mStateOld = mState; + mState = csError; + mErrorMsg = "connection lost to BOB"; + return sleepFactorDefault; + } + + // check for finished BOB protocol + if (mBOBState == bsCleared) { + // done + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController waitForBob: mBOBState == bsCleared"); + mState = csDoDisconnect; + } + break; + case csDoDisconnect: + if (!disconnectI2P() || mSocket != 0) { + // just in case + rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController doDisconnect: can't disconnect"); + mStateOld = mState; + mState = csError; + mErrorMsg = "unable to disconnect from BOB"; + return sleepFactorDefault; + } + + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController doDisconnect: disconnected"); + mState = csDisconnected; + break; + case csDisconnected: + return stateMachineController_locked_disconnected(); + case csError: + return stateMachineController_locked_error(); + } + + return sleepFactorFast; +} + +int p3I2pBob::stateMachineController_locked_idle() +{ + // do some sanity checks + // use asserts becasue these things indicate wrong/broken state machines that need to be fixed ASAP! + assert(mBOBState == bsCleared); + assert(mSocket == 0); + assert(mState == csIdel || mState == csDisconnected); + + controllerTask oldTask = mTask; + // check for new task + if (mProcessing == NULL && !mPending.empty()) { + mProcessing = mPending.front(); + mPending.pop(); + + if (!mSetting.enableBob && ( + mProcessing->task == autoProxyTask::start || + mProcessing->task == autoProxyTask::stop || + mProcessing->task == autoProxyTask::proxyStatusCheck)) { + // skip since we are not enabled + rslog(RsLog::Debug_Alert, &i2pBobLogInfo, "stateMachineController_locked_idle: disabled -> skipping ticket"); + rsAutoProxyMonitor::taskDone(mProcessing, autoProxyStatus::disabled); + mProcessing = NULL; + } else { + // set states + switch (mProcessing->task) { + case autoProxyTask::start: + mLastProxyCheck = time(NULL); + mTask = ctRunSetUp; + break; + case autoProxyTask::stop: + mTask = ctRunShutDown; + break; + case autoProxyTask::receiveKey: + mTaskOld = mTask; + mTask = ctRunGetKeys; + break; + case autoProxyTask::proxyStatusCheck: + mTaskOld = mTask; + mTask = ctRunCheck; + break; + default: + rslog(RsLog::Debug_Alert, &i2pBobLogInfo, "stateMachineController_locked_idle unknown async task"); + rsAutoProxyMonitor::taskError(mProcessing); + mProcessing = NULL; + break; + } + } + + mErrorMsg.clear(); + } + + // periodically check + if (mTask == ctRunSetUp && mLastProxyCheck < time(NULL) - selfCheckPeroid) { + taskTicket *tt = rsAutoProxyMonitor::getTicket(); + tt->task = autoProxyTask::proxyStatusCheck; + tt->data = (void *) new bool; + + *((bool *)tt->data) = false; + + mPending.push(tt); + + mLastProxyCheck = time(NULL); + } + + // wait for new task + if (!!mProcessing) { + // check if task was changed + if (mTask != oldTask) { + mState = csDoConnect; + } else { + // A ticket shall be processed but the state didn't change. + // This means that what ever is requested in the ticket + // was requested before already. + // -> set mState to csDisconnected to answer the ticket + mState = csDisconnected; + } + return sleepFactorFast; + } + + return sleepFactorSlow; +} + +int p3I2pBob::stateMachineController_locked_connected() +{ + // set proper bob state + switch (mTask) { + case ctRunSetUp: + // when we have a key use it for server tunnel! + if(mSetting.keys.empty()) { + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickC"); + mBOBState = bsSetnickC; + } else { + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickS"); + mBOBState = bsSetnickS; + } + break; + case ctRunShutDown: + // shut down existing tunnel + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = getnick"); + mBOBState = bsGetnick; + break; + case ctRunCheck: + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = list"); + mBOBState = bsList; + break; + case ctRunGetKeys: + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickN"); + mBOBState = bsSetnickN; + break; + case ctIdle: + rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_connected: task is idle. This should not happen!"); + break; + } + + mState = csWaitForBob; + return sleepFactorFast; +} + +int p3I2pBob::stateMachineController_locked_disconnected() +{ + // check if we had an error + bool errorHappened = (mStateOld == csError); + + if(errorHappened) { + // reset old state + mStateOld = csIdel; + rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_disconnected: error during process!"); + } + + // answer ticket + controllerState newState = csIdel; + switch (mTask) { + case ctRunSetUp: + if (errorHappened) { + rsAutoProxyMonitor::taskError(mProcessing); + // switch to error + newState = csError; + } else { + rsAutoProxyMonitor::taskDone(mProcessing, autoProxyStatus::online); + } + break; + case ctRunShutDown: + // don't care about error here + rsAutoProxyMonitor::taskDone(mProcessing, autoProxyStatus::offline); + break; + case ctRunCheck: + // get result and delete dummy ticket + errorHappened |= *((bool *)mProcessing->data); + delete (bool *)mProcessing->data; + delete mProcessing; + + // restore old task + mTask = mTaskOld; + + if (!errorHappened) { + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_disconnected: run check result: ok"); + break; + } + // switch to error + newState = csError; + rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_disconnected: run check result: error"); + mErrorMsg = "Connection check failed. Will try to restart tunnel."; + + break; + case ctRunGetKeys: + if (!errorHappened) { + // rebuild commands + updateSettings_locked(); + + if (mProcessing->data) + *((struct bobSettings *)mProcessing->data) = mSetting; + + rsAutoProxyMonitor::taskDone(mProcessing, autoProxyStatus::ok); + } else { + rsAutoProxyMonitor::taskError(mProcessing); + // switch to error + newState = csError; + } + + // restore old task + mTask = mTaskOld; + break; + case ctIdle: + rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_disconnected: task is idle. This should not happen!"); + rsAutoProxyMonitor::taskError(mProcessing); + } + mProcessing = NULL; + mState = newState; + + if (newState == csError) + mLastProxyCheck = time(NULL); + + return sleepFactorFast; +} + +int p3I2pBob::stateMachineController_locked_error() +{ + // wait for bob protocoll + if (mBOBState != bsCleared) { + rslog(RsLog::Debug_All, &i2pBobLogInfo, "stateMachineController_locked_error: waiting for BOB"); + return sleepFactorFast; + } + +#if 0 + std::stringstream ss; + ss << "stateMachineController_locked_error: mProcessing: " << (mProcessing ? "not null" : "null"); + rslog(RsLog::Debug_All, &i2pBobLogInfo, ss.str()); +#endif + + // try to finish ticket + if (mProcessing) { + switch (mTask) { + case ctRunCheck: + // connection check failed at some point + rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: failed to check proxy status (it's likely dead)!"); + *((bool *)mProcessing->data) = true; + mState = csDoDisconnect; + mStateOld = csIdel; + // keep the error message + break; + case ctRunShutDown: + // not a big deal though + rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: failed to shut down tunnel (it's likely dead though)!"); + mState = csDoDisconnect; + mStateOld = csIdel; + mErrorMsg.clear(); + break; + case ctIdle: + // should not happen but we need to deal with it + // this will produce some error messages in the log and finish the task (marked as failed) + rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: task is idle. This should not happen!"); + mState = csDoDisconnect; + mStateOld = csIdel; + mErrorMsg.clear(); + break; + case ctRunGetKeys: + case ctRunSetUp: + rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: failed to receive key / start up"); + mStateOld = csError; + mState = csDoDisconnect; + // keep the error message + break; + } + return sleepFactorFast; + } + + // periodically retry + if (mLastProxyCheck < time(NULL) - (selfCheckPeroid >> 1) && mTask == ctRunSetUp) { + rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: retrying"); + + mLastProxyCheck = time(NULL); + mErrorMsg.clear(); + + // create fake ticket + taskTicket *tt = rsAutoProxyMonitor::getTicket(); + tt->task = autoProxyTask::start; + mPending.push(tt); + } + + // check for new tickets + if (!mPending.empty()) { + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_error: processing new ticket"); + + // reset and try new task + mTask = ctIdle; + mState = csIdel; + return sleepFactorFast; + } + + return sleepFactorDefault; +} + +RsSerialiser *p3I2pBob::setupSerialiser() +{ + RsSerialiser* rsSerialiser = new RsSerialiser(); + rsSerialiser->addSerialType(new RsGeneralConfigSerialiser()); + + return rsSerialiser; +} + +#define addKVS(_vitem, _kv, _key, _value) \ + _kv.key = _key;\ + _kv.value = _value;\ + _vitem->tlvkvs.pairs.push_back(_kv); + +#define addKVSInt(_vitem, _kv, _key, _value) \ + _kv.key = _key;\ + rs_sprintf(_kv.value, "%d", _value);\ + _vitem->tlvkvs.pairs.push_back(_kv); + +bool p3I2pBob::saveList(bool &cleanup, std::list &lst) +{ + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "saveList"); + + cleanup = true; + RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet; + RsTlvKeyValue kv; + + RS_STACK_MUTEX(mLock); + addKVS(vitem, kv, kConfigKeyBOBEnable, mSetting.enableBob ? "TRUE" : "FALSE") + addKVS(vitem, kv, kConfigKeyBOBKey, mSetting.keys) + addKVS(vitem, kv, kConfigKeyBOBAddr, mSetting.addr) + addKVSInt(vitem, kv, kConfigKeyInLength, mSetting.inLength) + addKVSInt(vitem, kv, kConfigKeyInQuantity, mSetting.inQuantity) + addKVSInt(vitem, kv, kConfigKeyInVariance, mSetting.inVariance) + addKVSInt(vitem, kv, kConfigKeyOutLength, mSetting.outLength) + addKVSInt(vitem, kv, kConfigKeyOutQuantity, mSetting.outQuantity) + addKVSInt(vitem, kv, kConfigKeyOutVariance, mSetting.outVariance) + + lst.push_back(vitem); + + return true; +} + +#undef addKVS +#undef addKVSUInt + +#define getKVSUInt(_kit, _key, _value) \ + else if (_kit->key == _key) {\ + std::istringstream is(_kit->value);\ + int tmp;\ + is >> tmp;\ + _value = (int8_t)tmp;\ + } + +bool p3I2pBob::loadList(std::list &load) +{ + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "loadList"); + + for(std::list::const_iterator it = load.begin(); it!=load.end(); ++it) { + RsConfigKeyValueSet *vitem = dynamic_cast(*it); + if(vitem != NULL) { + RS_STACK_MUTEX(mLock); + for(std::list::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit) { + if (kit->key == kConfigKeyBOBEnable) + mSetting.enableBob = kit->value == "TRUE"; + else if (kit->key == kConfigKeyBOBKey) + mSetting.keys = kit->value; + else if (kit->key == kConfigKeyBOBAddr) + mSetting.addr = kit->value; + getKVSUInt(kit, kConfigKeyInLength, mSetting.inLength) + getKVSUInt(kit, kConfigKeyInQuantity, mSetting.inQuantity) + getKVSUInt(kit, kConfigKeyInVariance, mSetting.inVariance) + getKVSUInt(kit, kConfigKeyOutLength, mSetting.outLength) + getKVSUInt(kit, kConfigKeyOutQuantity, mSetting.outQuantity) + getKVSUInt(kit, kConfigKeyOutVariance, mSetting.outVariance) + else + rslog(RsLog::Warning, &i2pBobLogInfo, "loadList unknown key: " + kit->key); + } + } + delete vitem; + } + + RS_STACK_MUTEX(mLock); + finalizeSettings_locked(); + mConfigLoaded = true; + + return true; +} + +#undef getKVSUInt + +void p3I2pBob::getBOBSettings(bobSettings *settings) +{ + if (settings == NULL) + return; + + RS_STACK_MUTEX(mLock); + *settings = mSetting; + +} + +void p3I2pBob::setBOBSettings(const bobSettings *settings) +{ + if (settings == NULL) + return; + + RS_STACK_MUTEX(mLock); + mSetting = *settings; + + IndicateConfigChanged(); + + // Note: + // We don't take care of updating a running BOB session here + // This can be done manually by stoping and restarting the session + + // Note2: + // In case there is no config yet to load + // finalize settings here instead + if (!mConfigLoaded) { + finalizeSettings_locked(); + mConfigLoaded = true; + } else { + updateSettings_locked(); + } +} + +void p3I2pBob::getStates(bobStates *bs) +{ + if (bs == NULL) + return; + + RS_STACK_MUTEX(mLock); + bs->cs = mState; + bs->ct = mTask; + bs->bs = mBOBState; + bs->tunnelName = mTunnelName; +} + +std::string p3I2pBob::executeCommand(const std::string &command) +{ + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "executeCommand_locked running '" + command + "'"); + + std::string copy = command; + copy.push_back('\n'); + + // send command + // there is only one thread that touches mSocket - no need for a lock + ::send(mSocket, copy.c_str(), copy.size(), 0); + + // receive answer (trailing new line is already removed!) + std::string ans = recv(); + + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "executeCommand_locked answer '" + ans + "'"); + + return ans; +} + +bool p3I2pBob::connectI2P() +{ + // there is only one thread that touches mSocket - no need for a lock + + if (mSocket != 0) { + rslog(RsLog::Warning, &i2pBobLogInfo, "connectI2P_locked mSocket != 0"); + return false; + } + + // create socket + mSocket = unix_socket(AF_INET, SOCK_STREAM, 0); + if (mSocket < 0) + { + rslog(RsLog::Warning, &i2pBobLogInfo, "connectI2P_locked Failed to open socket! Socket Error: " + socket_errorType(errno)); + return false; + } + + // connect + int err = unix_connect(mSocket, (struct sockaddr *)&mI2PProxyAddr, sizeof(mI2PProxyAddr)); + if (err != 0) { + rslog(RsLog::Warning, &i2pBobLogInfo, "connectI2P_locked Failed to connect to BOB! Socket Error: " + socket_errorType(errno)); + return false; + } + + // receive hello msg + recv(); + + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "connectI2P_locked done"); + return true; +} + +bool p3I2pBob::disconnectI2P() +{ + // there is only one thread that touches mSocket - no need for a lock + + if (mSocket == 0) { + rslog(RsLog::Warning, &i2pBobLogInfo, "disconnectI2P_locked mSocket == 0"); + return true; + } + + int err = unix_close(mSocket); + if (err != 0) { + rslog(RsLog::Warning, &i2pBobLogInfo, "disconnectI2P_locked Failed to close socket! Socket Error: " + socket_errorType(errno)); + return false; + } + + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "disconnectI2P_locked done"); + mSocket = 0; + return true; +} + +std::string toString(const std::string &a, const int b) { + std::ostringstream oss; + oss << b; + return a + oss.str();; +} + +std::string toString(const std::string &a, const uint16_t b) { + return toString(a, (int)b); +} + +std::string toString(const std::string &a, const int8_t b) { + return toString(a, (int)b); +} + +void p3I2pBob::finalizeSettings_locked() +{ + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked"); + + sockaddr_storage_clear(mI2PProxyAddr); + // get i2p proxy addr + sockaddr_storage proxy; + mPeerMgr->getProxyServerAddress(RS_HIDDEN_TYPE_I2P, proxy); + + // overwrite port to bob port + sockaddr_storage_setipv4(mI2PProxyAddr, (sockaddr_in*)&proxy); + sockaddr_storage_setport(mI2PProxyAddr, 2827); + + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using " + sockaddr_storage_tostring(mI2PProxyAddr)); + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using " + mSetting.addr); + + peerState ps; + mPeerMgr->getOwnNetStatus(ps); + + // setup commands + // new lines are appended later! + + // generate random suffix for name + // RSRandom::random_alphaNumericString can return very weird looking strings like: ,,@z+M + // use base32 instead + size_t len = 5; // 5 characters = 8 base32 symbols + std::vector tmp(len); + RSRandom::random_bytes(tmp.data(), len); + const std::string location = Radix32::encode(tmp.data(), len); + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using suffix " + location); + mTunnelName = "RetroShare-" + location; + + const std::string setnick = "setnick RetroShare-" + location; + const std::string getnick = "getnick RetroShare-" + location; + const std::string newkeys = "newkeys"; + const std::string getkeys = "getkeys"; + const std::string setkeys = "setkeys " + mSetting.keys; + const std::string inhost = "inhost " + sockaddr_storage_iptostring(proxy); + const std::string inport = toString("inport ", sockaddr_storage_port(proxy)); + const std::string outhost = "outhost " + sockaddr_storage_iptostring(ps.localaddr); + const std::string outport = toString("outport ", sockaddr_storage_port(ps.localaddr)); + // length + const std::string inlength = toString("option inbound.length=", mSetting.inLength); + const std::string outlength = toString("option outbound.length=", mSetting.outLength); + // variance + const std::string invariance = toString("option inbound.lengthVariance=", mSetting.inVariance); + const std::string outvariance= toString("option outbound.lengthVariance=", mSetting.outVariance); + // quantity + const std::string inquantity = toString("option inbound.quantity=", mSetting.inQuantity); + const std::string outquantity= toString("option outbound.quantity=", mSetting.outQuantity); + const std::string quiet = "quiet true"; + const std::string start = "start"; + const std::string stop = "stop"; + const std::string clear = "clear"; + const std::string list = "list"; + const std::string quit = "quit"; + + // setup state machine + + // start chain + // -> A: server and client tunnel + mCommands[bsSetnickS] = {setnick, bsSetkeys}; + mCommands[bsSetkeys] = {setkeys, bsOuthost}; + mCommands[bsOuthost] = {outhost, bsOutport}; + mCommands[bsOutport] = {outport, bsInhost}; + // -> B: only client tunnel + mCommands[bsSetnickC] = {setnick, bsNewkeysC}; + mCommands[bsNewkeysC] = {newkeys, bsInhost}; + // -> both + mCommands[bsInhost] = {inhost, bsInport}; + mCommands[bsInport] = {inport, bsInlength}; + mCommands[bsInlength] = {inlength, bsOutlength}; + mCommands[bsOutlength] = {outlength, bsInvariance}; + mCommands[bsInvariance] = {invariance, bsOutvariance}; + mCommands[bsOutvariance]= {outvariance,bsInquantity}; + mCommands[bsInquantity] = {inquantity, bsOutquantity}; + mCommands[bsOutquantity]= {outquantity,bsQuiet}; + mCommands[bsQuiet] = {quiet, bsStart}; + mCommands[bsStart] = {start, bsQuit}; + mCommands[bsQuit] = {quit, bsCleared}; + + // stop chain + mCommands[bsGetnick] = {getnick, bsStop}; + mCommands[bsStop] = {stop, bsClear}; + mCommands[bsClear] = {clear, bsQuit}; + + // getkeys chain + mCommands[bsSetnickN] = {setnick, bsNewkeysN}; + mCommands[bsNewkeysN] = {newkeys, bsGetkeys}; + mCommands[bsGetkeys] = {getkeys, bsClear}; + + // list chain + mCommands[bsList] = {list, bsQuit}; +} + +void p3I2pBob::updateSettings_locked() +{ + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "updateSettings_locked"); + + sockaddr_storage proxy; + mPeerMgr->getProxyServerAddress(RS_HIDDEN_TYPE_I2P, proxy); + + peerState ps; + mPeerMgr->getOwnNetStatus(ps); + + const std::string setkeys = "setkeys " + mSetting.keys; + const std::string inhost = "inhost " + sockaddr_storage_iptostring(proxy); + const std::string inport = toString("inport ", sockaddr_storage_port(proxy)); + const std::string outhost = "outhost " + sockaddr_storage_iptostring(ps.localaddr); + const std::string outport = toString("outport ", sockaddr_storage_port(ps.localaddr)); + + // length + const std::string inlength = toString("option inbound.length=", mSetting.inLength); + const std::string outlength = toString("option outbound.length=", mSetting.outLength); + // variance + const std::string invariance = toString("option inbound.lengthVariance=", mSetting.inVariance); + const std::string outvariance= toString("option outbound.lengthVariance=", mSetting.outVariance); + // quantity + const std::string inquantity = toString("option inbound.quantity=", mSetting.inQuantity); + const std::string outquantity= toString("option outbound.quantity=", mSetting.outQuantity); + + mCommands[bsSetkeys] = {setkeys, bsOuthost}; + mCommands[bsOuthost] = {outhost, bsOutport}; + mCommands[bsOutport] = {outport, bsInhost}; + mCommands[bsInhost] = {inhost, bsInport}; + mCommands[bsInport] = {inport, bsInlength}; + + mCommands[bsInlength] = {inlength, bsOutlength}; + mCommands[bsOutlength] = {outlength, bsInvariance}; + mCommands[bsInvariance] = {invariance, bsOutvariance}; + mCommands[bsOutvariance]= {outvariance,bsInquantity}; + mCommands[bsInquantity] = {inquantity, bsOutquantity}; + mCommands[bsOutquantity]= {outquantity,bsQuiet}; +} + +std::string p3I2pBob::recv() +{ + std::string ans; + ssize_t length; + const uint16_t bufferSize = 128; + std::vector buffer(bufferSize); + + do { + doSleep(sleepTimeRecv); + + // there is only one thread that touches mSocket - no need for a lock + length = ::recv(mSocket, buffer.data(), buffer.size(), 0); + if (length < 0) + continue; + + ans.append(buffer.begin(), buffer.end()); + + // clean received string + ans.erase(std::remove(ans.begin(), ans.end(), '\0'), ans.end()); + ans.erase(std::remove(ans.begin(), ans.end(), '\n'), ans.end()); + +#if 0 + std::stringstream ss; + ss << "recv length: " << length << " (bufferSize: " << bufferSize << ") ans: " << ans.length(); + rslog(RsLog::Debug_All, &i2pBobLogInfo, ss.str()); +#endif + + // clear and resize buffer again + buffer.clear(); + buffer.resize(bufferSize); + } while(length == bufferSize || ans.size() < 4); + + return ans; +} diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.h b/libretroshare/src/services/autoproxy/p3i2pbob.h new file mode 100644 index 000000000..b86ae5507 --- /dev/null +++ b/libretroshare/src/services/autoproxy/p3i2pbob.h @@ -0,0 +1,248 @@ +#ifndef P3I2PBOB_H +#define P3I2PBOB_H + +#include +#include +#include +#include +#include + +#include "services/autoproxy/rsautoproxymonitor.h" +#include "util/rsthreads.h" +#include "pqi/p3cfgmgr.h" + +/* + * This class implements I2P BOB (BASIC OPEN BRIDGE) communication to allow RS + * to automatically remote control I2P to setup the needed tunnel. + * BOB is a simple text-based interface: https://geti2p.net/en/docs/api/bob + * + * Note 1: + * One tunnel is enough even for hidden locations since it can be used + * bidirectional. (In contrast to what RS I2P users had to set up manually.) + * + * Note 2: + * BOB tunnels are no SOCKS tunnel. Therefore pqissli2pbob implements a simplified + * proxy specially for BOB tunnels. + * + * Note 3: + * BOB needs a unique name as an ID for each tunnel. + * We use 'RetroShare-' + 8 base32 characters. + * + * Design: + * The service uses three state machines to manage its task: + * int stateMachineBOB(); + * mBOBState + * int stateMachineController(); + * mState + * mTask + * + * stateMachineBOB: + * This state machine manages the low level communication with BOB. It basically has a linked + * list (currently a implemented as a std::map) that contains a command and the next + * state. + * Each high level operation (start up / shut down / get keys) is represented by a + * chain of states. E.g. the chain to retrieve new keys: + * mCommands[bobState::setnickN] = {setnick, bobState::newkeysN}; + * mCommands[bobState::newkeysN] = {newkeys, bobState::getkeys}; + * mCommands[bobState::getkeys] = {getkeys, bobState::clear}; + * mCommands[bobState::clear] = {clear, bobState::quit}; + * mCommands[bobState::quit] = {quit, bobState::cleared}; + * + * stateMachineController: + * This state machone manages the high level tasks. + * It is controlled by mState and mTask. + * + * mTast: + * Tracks the high level operation (like start up). + * It will keep its value even when a task is done to track + * the requested BOB state. + * When other operations are performed like a conection check + * the last task gets backed up and is later restored again + * + * mState: + * This state lives only for one operation an manages the communication + * with the BOB instance. This is basically connecting, starting BOB + * protocol and disconnecting + * + * How a task looks like: + * 1) RS sets task using the ticket system + * 2) stateMachineController connects to BOBs control port, sets mBobState to a lists head + * 3) stateMachineBOB processes command chain + * 4) stateMachineBOB is done and sets mBobState to cleared signaling that the connection + * is cleared and can be closed + * 5) stateMachineController disconnects from BOBs control port and updates mState + */ + +/// +/// \brief The controllerState enum +/// States for the controller to keep track of what he is currently doing +enum controllerState { + csIdel, + csDoConnect, + csConnected, + csWaitForBob, + csDoDisconnect, + csDisconnected, + csError +}; + +/// +/// \brief The controllerTask enum +/// This state tracks the controllers tast (e.g. setup a BOB tunnel or shut down +/// an existing one). +enum controllerTask { + ctIdle, + ctRunSetUp, + ctRunShutDown, + ctRunGetKeys, + ctRunCheck +}; + +/// +/// \brief The bobState enum +/// One state for each message +/// +enum bobState { + bsCleared, + bsSetnickC, // chain head for only client tunnel + bsSetnickN, // chain head for getting new (server) keys + bsSetnickS, // chain head for client and server tunnel + bsGetnick, + bsNewkeysC, // part of chain for only client tunnel + bsNewkeysN, // part of chain for getting new (server) keys + bsGetkeys, + bsSetkeys, + bsInhost, + bsOuthost, + bsInport, + bsOutport, + bsInlength, + bsOutlength, + bsInvariance, + bsOutvariance, + bsInquantity, + bsOutquantity, + bsQuiet, + bsStart, + bsStop, + bsClear, + bsList, // chain head for 'list' command + bsQuit +}; + +/// +/// \brief The bobStateInfo struct +/// State machine with commands +/// \todo This could be replaced by a linked list instead of a map +struct bobStateInfo { + std::string command; + bobState nextState; +}; + +struct bobSettings { + bool enableBob; ///< This field is used by the pqi subsystem to determinine whether SOCKS proxy or BOB is used for I2P connections + std::string keys; ///< (optional) server keys + std::string addr; ///< (optional) hidden service addr. in base32 form + + int8_t inLength; + int8_t inQuantity; + int8_t inVariance; + + int8_t outLength; + int8_t outQuantity; + int8_t outVariance; +}; + +/// +/// \brief The bobStates struct +/// This container struct is used to pass all states. +/// Additionally, the tunnel name is included to to show it in the GUI. +/// The advantage of a struct is that it can be forward declared. +struct bobStates { + bobState bs; + controllerState cs; + controllerTask ct; + + std::string tunnelName; +}; + +class p3PeerMgr; + +class p3I2pBob : public RsTickingThread, public p3Config, public autoProxyService +{ +public: + p3I2pBob(p3PeerMgr *peerMgr); + + // autoProxyService interface +public: + bool isEnabled(); + bool initialSetup(std::string &addr, uint16_t &); + void processTaskAsync(taskTicket *ticket); + void processTaskSync(taskTicket *ticket); + + static std::string keyToBase32Addr(const std::string &key); + + // RsTickingThread interface +public: + void data_tick(); + +private: + int stateMachineBOB(); + int stateMachineBOB_locked_failure(const std::string &answer, const bobStateInfo ¤tState); + + int stateMachineController(); + int stateMachineController_locked_idle(); + int stateMachineController_locked_connected(); + int stateMachineController_locked_disconnected(); + int stateMachineController_locked_error(); + + // p3Config interface +protected: + RsSerialiser *setupSerialiser(); + bool saveList(bool &cleanup, std::list &lst); + bool loadList(std::list &load); + +private: + // helpers + void getBOBSettings(bobSettings *settings); + void setBOBSettings(const bobSettings *settings); + void getStates(bobStates *bs); + + std::string executeCommand(const std::string &command); + bool connectI2P(); + bool disconnectI2P(); + + void finalizeSettings_locked(); + void updateSettings_locked(); + + std::string recv(); + + // states for state machines + controllerState mState; + controllerTask mTask; + // used to store old state when in error state + // mStateOld is also used as a flag when an error occured in BOB protocol + controllerState mStateOld; + // mTaskOld is used to keep the previous task (start up / shut down) when requesting keys or checking the connection + controllerTask mTaskOld; + bobSettings mSetting; + bobState mBOBState; + + // used variables + p3PeerMgr *mPeerMgr; + bool mConfigLoaded; + int mSocket; + time_t mLastProxyCheck; + sockaddr_storage mI2PProxyAddr; + std::map mCommands; + std::string mErrorMsg; + std::string mTunnelName; + + std::queue mPending; + taskTicket *mProcessing; + + // mutex + RsMutex mLock; +}; + +#endif // P3I2PBOB_H diff --git a/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc b/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc new file mode 100644 index 000000000..87e058f3a --- /dev/null +++ b/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc @@ -0,0 +1,305 @@ +#include "rsautoproxymonitor.h" + +rsAutoProxyMonitor *rsAutoProxyMonitor::mInstance = NULL; + +rsAutoProxyMonitor::rsAutoProxyMonitor() + : mRSShutDown(false), mLock("rs auto proxy monitor") +{ + mProxies.clear(); +} + +rsAutoProxyMonitor *rsAutoProxyMonitor::instance() +{ + if (mInstance == NULL) + mInstance = new rsAutoProxyMonitor(); + return mInstance; +} + +void rsAutoProxyMonitor::addProxy(autoProxyType::autoProxyType_enum type, autoProxyService *service) +{ + RS_STACK_MUTEX(mLock); + if (mProxies.find(type) != mProxies.end()) + std::cerr << "sAutoProxyMonitor::addProxy type " << type << " already added - OVERWRITING" << std::endl; + + mProxies[type] = service; +} + +void rsAutoProxyMonitor::startAll() +{ + // create ticket + taskTicket *tt = getTicket(); + tt->cb = this; + tt->task = autoProxyTask::start; + + { + std::map::const_iterator it; + + // fill types + RS_STACK_MUTEX(mLock); + for (it = mProxies.begin(); it != mProxies.end(); ++it) + if (it->second->isEnabled()) + tt->types.push_back(it->first); + } + + task(tt); +} + +void rsAutoProxyMonitor::stopAll() +{ + // create ticket + taskTicket *tt = getTicket(); + tt->cb = this; + tt->task = autoProxyTask::stop; + + { + std::map::const_iterator it; + + // fill types + RS_STACK_MUTEX(mLock); + for (it = mProxies.begin(); it != mProxies.end(); ++it) + if (it->second->isEnabled()) + tt->types.push_back(it->first); + } + + task(tt); +} + +void rsAutoProxyMonitor::stopAllRSShutdown() +{ + { + RS_STACK_MUTEX(mLock); + mRSShutDown = true; + + // remove disabled services + std::vector toRemove; + std::map::const_iterator it; + for (it = mProxies.begin(); it != mProxies.end(); ++it) { + if (!it->second->isEnabled()) { + toRemove.push_back(it->first); + } + } + + std::vector::const_iterator it2; + for (it2 = toRemove.begin(); it2 != toRemove.end(); ++it2) { + mProxies.erase(*it2); + } + } + + // stop all remaining + stopAll(); + + // wait for shutdown of all services + uint32_t t = 0, timeout = 15; + do { +#ifndef WINDOWS_SYS + usleep(1000 * 1000); +#else + Sleep(1000); +#endif + RS_STACK_MUTEX(mLock); + std::cout << "(II) waiting for auto proxy service(s) to shut down " << t << "/" << timeout << " (remaining: " << mProxies.size() << ")" << std::endl; + if (mProxies.empty()) + break; + t++; + } while (t < timeout ); +} + +bool rsAutoProxyMonitor::isEnabled(autoProxyType::autoProxyType_enum t) +{ + autoProxyService *s = lookUpService(t); + if (s == NULL) + return false; + + return s->isEnabled(); +} + +bool rsAutoProxyMonitor::initialSetup(autoProxyType::autoProxyType_enum t, std::string &addr, uint16_t &port) +{ + autoProxyService *s = lookUpService(t); + if (s == NULL) + return false; + + return s->initialSetup(addr, port); +} + +void rsAutoProxyMonitor::task(taskTicket *ticket) +{ + // sanity checks + if (!ticket->async && ticket->types.size() > 1) { + std::cerr << "(WW) rsAutoProxyMonitor::task synchronous call to multiple services. This can cause problems!" << std::endl; + } + if (ticket->async && !ticket->cb && ticket->data) { + std::cerr << "(WW) rsAutoProxyMonitor::task asynchronous call with data but no callback. This will likely causes memory leak!" << std::endl; + } + if (ticket->types.size() > 1 && ticket->data) { + std::cerr << "(WW) rsAutoProxyMonitor::task call with data to multiple services. This will likely causes memory leak!" << std::endl; + } + + std::vector::const_iterator it; + + for (it = ticket->types.begin(); it != ticket->types.end(); ++it) { + autoProxyService* s = lookUpService(*it); + if (s == NULL) + continue; + + if (ticket->async) { + // copy ticket + taskTicket *tt = new taskTicket(); + *tt = *ticket; + tt->types.clear(); + tt->types.push_back(*it); + s->processTaskAsync(tt); + } else { + s->processTaskSync(ticket); + } + } +} + +void rsAutoProxyMonitor::taskAsync(autoProxyType::autoProxyType_enum type, autoProxyTask::autoProxyTask_enum task, autoProxyCallback *cb, void *data) +{ + std::vector types; + types.push_back(type); + taskAsync(types, task, cb, data); +} + +void rsAutoProxyMonitor::taskAsync(std::vector types, autoProxyTask::autoProxyTask_enum task, autoProxyCallback *cb, void *data) +{ + if (!isAsyncTask(task)) { + // Usually the services will reject this ticket. + // Just print a warning - maybe there is some special case where this is a good idea. + std::cerr << "(WW) rsAutoProxyMonitor::taskAsync called with a synchronous task!" << std::endl; + } + + taskTicket *tt = getTicket(); + tt->task = task; + tt->types = types; + if (cb) + tt->cb = cb; + if (data) + tt->data = data; + + instance()->task(tt); + // tickets were copied, clean up + delete tt; +} + +void rsAutoProxyMonitor::taskSync(autoProxyType::autoProxyType_enum type, autoProxyTask::autoProxyTask_enum task, void *data) +{ + std::vector types; + types.push_back(type); + taskSync(types, task, data); +} + +void rsAutoProxyMonitor::taskSync(std::vector types, autoProxyTask::autoProxyTask_enum task, void *data) +{ + if (isAsyncTask(task)) { + // Usually the services will reject this ticket. + // Just print a warning - maybe there is some special case where this is a good idea. + std::cerr << "(WW) rsAutoProxyMonitor::taskSync called with an asynchronous task!" << std::endl; + } + + taskTicket *tt = getTicket(); + tt->async = false; + tt->task = task; + tt->types = types; + if (data) + tt->data = data; + + instance()->task(tt); + // call done, clean up + delete tt; +} + +void rsAutoProxyMonitor::taskError(taskTicket *t) +{ + taskDone(t, autoProxyStatus::error); +} + +void rsAutoProxyMonitor::taskDone(taskTicket *t, autoProxyStatus::autoProxyStatus_enum status) +{ + bool cleanUp = false; + + t->result = status; + if (t->cb) { + t->cb->taskFinished(t); + if (t != NULL) { + // callack did not clean up properly + std::cerr << "(WW) rsAutoProxyMonitor::taskFinish callback did not clean up!" << std::endl; + cleanUp = true; + } + } else if (t->async){ + // async and no callback + // we must take care of deleting + cleanUp = true; + if(t->data) + std::cerr << "(WW) rsAutoProxyMonitor::taskFinish async call with data attached but no callback set!" << std::endl; + } + + if (cleanUp) { + if (t->data) { + std::cerr << "(WW) rsAutoProxyMonitor::taskFinish will try to delete void pointer!" << std::endl; +#pragma GCC diagnostic ignored "-Wdelete-incomplete" + delete t->data; +#pragma GCC diagnostic pop + t->data = NULL; + } + delete t; + t = NULL; + } +} + +taskTicket *rsAutoProxyMonitor::getTicket() +{ + taskTicket *tt = new taskTicket(); + tt->cb = NULL; + tt->data = NULL; + tt->async = true; + tt->result = autoProxyStatus::undefined; + return tt; +} + +void rsAutoProxyMonitor::taskFinished(taskTicket *&ticket) +{ + { + RS_STACK_MUTEX(mLock); + if (mRSShutDown && ticket->task == autoProxyTask::stop) { + mProxies.erase(ticket->types.front()); + } + } + + // clean up + if (ticket->data) { + std::cerr << "rsAutoProxyMonitor::taskFinished data set. Will try to delete void pointer" << std::endl; +#pragma GCC diagnostic ignored "-Wdelete-incomplete" + delete ticket->data; +#pragma GCC diagnostic pop + ticket->data = NULL; + } + delete ticket; + ticket = NULL; +} + +autoProxyService *rsAutoProxyMonitor::lookUpService(autoProxyType::autoProxyType_enum t) +{ + RS_STACK_MUTEX(mLock); + std::map::const_iterator itService; + if ((itService = mProxies.find(t)) != mProxies.end()) { + return itService->second; + } + std::cerr << "sAutoProxyMonitor::lookUpService no service for type " << t << " found!" << std::endl; + return NULL; +} + +bool rsAutoProxyMonitor::isAsyncTask(autoProxyTask::autoProxyTask_enum t) +{ + switch (t) { + case autoProxyTask::start: + case autoProxyTask::stop: + case autoProxyTask::receiveKey: + return true; + break; + default: + break; + } + return false; +} diff --git a/libretroshare/src/services/autoproxy/rsautoproxymonitor.h b/libretroshare/src/services/autoproxy/rsautoproxymonitor.h new file mode 100644 index 000000000..21ea95c3b --- /dev/null +++ b/libretroshare/src/services/autoproxy/rsautoproxymonitor.h @@ -0,0 +1,216 @@ +#ifndef RSAUTOPROXYMONITOR_H +#define RSAUTOPROXYMONITOR_H + +#include +#include + +#include + +class autoProxyCallback; + +namespace autoProxyType { + enum autoProxyType_enum { + I2PBOB + }; +} + +namespace autoProxyTask { + enum autoProxyTask_enum { + /* async tasks */ + start, ///< start up proxy + stop, ///< shut down proxy + receiveKey, ///< renew proxy key (if any) + proxyStatusCheck, ///< use to check if the proxy is still running + /* sync tasks */ + status, ///< get status from auto proxy + getSettings, ///< get setting from auto proxy + setSettings, ///< set setting of auto proxy + reloadConfig, ///< signal config reload/rebuild + getErrorInfo ///< get error information from auto proxy + }; +} + +namespace autoProxyStatus { + enum autoProxyStatus_enum { + undefined, ///< undefined - usually not yet set + disabled, ///< used when a task cannot be done (e.g. a disabled service cannot be startet or stopped) + offline, ///< proxy is not set up + online, ///< proxy is set up + ok, ///< generic ok + error ///< generic error + }; +} + +struct taskTicket { + /// + /// \brief types auto proxy service types that should get the ticket + /// + std::vector types; + + /// + /// \brief task the task to satisfy + /// + autoProxyTask::autoProxyTask_enum task; + + /// + /// \brief cb (optional) callback that gets called once the task is done + /// + autoProxyCallback *cb; + + /// + /// \brief result (optional) result + /// + autoProxyStatus::autoProxyStatus_enum result; + + /// + /// \brief data (optional) service dependent data + /// + /// Needs to be allocated and freed by caller! + /// + void *data; + + /// + /// \brief async is the call Asynchronous + /// + /// Will create a copy of the ticket for each + /// service and delete the original ticket. + /// + bool async; +}; + +class autoProxyCallback { +public: + /// + /// \brief taskFinished called when a task is finished + /// \param ticket + /// + /// Remove everything: ticket and attached data if any! + /// + virtual void taskFinished(taskTicket *&ticket) = 0; +}; + +class autoProxyService { +public: + /// + /// \brief isEnabled must be provided to directly get a result without going through the ticket system + /// \return whether the auto proxy service is enabled or not + /// + virtual bool isEnabled() = 0; + + /// + /// \brief initialSetup used when creating a node + /// \param addr new address for the hidden service + /// \param port new port for the hidden service + /// \return true on success + /// + /// This function is used to do an initial setup when creating a new hidden node. + /// Nothing has been set up at this point to the auto proxy service must take care + /// of everything (e.g. starting (and stoping) of needed threads) + /// + virtual bool initialSetup(std::string &addr, uint16_t &port) = 0; + + /// + /// \brief processTaskAsync adds a ticket to the auto proxies task list + /// \param ticket + /// + /// Don't call the callback in this function as this can cause dead locks! + /// + virtual void processTaskAsync(taskTicket *ticket) = 0; + + /// + /// \brief processTaskSync taskTicket must be satisfied immediately + /// \param ticket + /// + virtual void processTaskSync(taskTicket *ticket) = 0; +}; + +class rsAutoProxyMonitor : autoProxyCallback +{ +public: + static rsAutoProxyMonitor *instance(); + + /// + /// \brief addProxy adds a new auto proxy service to the monitor + /// \param type type of the new auto proxy service + /// \param service pointer to the service + /// + void addProxy(autoProxyType::autoProxyType_enum type, autoProxyService *service); + + // global functions + void startAll(); + void stopAll(); + void stopAllRSShutdown(); + bool isEnabled(autoProxyType::autoProxyType_enum t); + // use this when creating a new node + bool initialSetup(autoProxyType::autoProxyType_enum t, std::string &addr, uint16_t &port); + + /// + /// \brief task Sends a task to all requested services + /// \param ticket Ticket containing required information + /// + /// There are two kind of tasks: asyn and sync. + /// All tasks that involve communication with the target program (e.g. I2P or Tor) are asynchronous. + /// All other task are synchronous (e.g. getting settings) + /// + /// + /// Synchronous: + /// When you want to get the settings from a service you can call task() with a ticket only listing + /// one service and data pointing to the service's settings class/struct. Set async to false so + /// that the service gets your original ticket. Ther service will process the request (get settings) + /// immediately and when the call to task() is done you can access the settings from your ticket. + /// + /// When additionally a call back is set the service will also call it. This can cause deadlocks! + /// + /// + /// Asynchronous: + /// When you want to start up all services or request new keys for all services you can call task() with a list + /// of services and set async to true. When each service has fullfilled the resquest he will + /// use the callback. The original caller ticket will be copied and each call to the callback + /// will use its copy of the original ticket. The attached data is not copied so each service gets + /// the same pointer! + /// + /// + /// Note: + /// Services should not delet or allocate anything unless no call back is provided and it is an + /// async call. In that case the service should delete the ticket and the attacked data. + /// Otherwise the caller must take care of cleaning up. + /// This class provides two wrappers to take care of this that should be used: taskError and taskDone + /// + /// Note2: + /// This function is private so that each user must use the wrappers taskAsync and taskSync that include + /// more sanity checks + /// +private: + void task(taskTicket *ticket); + +public: + static void taskAsync(autoProxyType::autoProxyType_enum type, autoProxyTask::autoProxyTask_enum task, autoProxyCallback *cb = NULL, void *data = NULL); + static void taskAsync(std::vector types, autoProxyTask::autoProxyTask_enum task, autoProxyCallback *cb = NULL, void *data = NULL); + static void taskSync (autoProxyType::autoProxyType_enum type, autoProxyTask::autoProxyTask_enum task, void *data = NULL); + static void taskSync (std::vector types, autoProxyTask::autoProxyTask_enum task, void *data = NULL); + + // usefull helpers + static void taskError(taskTicket *t); + static void taskDone(taskTicket *t, autoProxyStatus::autoProxyStatus_enum status); + static taskTicket *getTicket(); + + // autoProxyCallback interface +public: + void taskFinished(taskTicket *&ticket); + +private: + rsAutoProxyMonitor(); + + autoProxyService *lookUpService(autoProxyType::autoProxyType_enum t); + static bool isAsyncTask(autoProxyTask::autoProxyTask_enum t); + + std::map mProxies; + bool mRSShutDown; + RsMutex mLock; + + static rsAutoProxyMonitor *mInstance; +}; + + + +#endif // RSAUTOPROXYMONITOR_H diff --git a/libretroshare/src/util/radix32.h b/libretroshare/src/util/radix32.h new file mode 100644 index 000000000..008aa3e9f --- /dev/null +++ b/libretroshare/src/util/radix32.h @@ -0,0 +1,50 @@ +#ifndef RADIX32_H +#define RADIX32_H + +#include +#include +#include +#include + +class Radix32 +{ +public: + static std::string encode(const std::vector &in) { + return encode(in.data(), in.size()); + } + + static std::string encode(const uint8_t *data, size_t len) { + std::string out = ""; + + size_t pos = 1; + uint8_t bits = 8, index; + uint16_t tmp = data[0]; // need min. 16 bits here + while (bits > 0 || pos < len) { + if (bits < 5) { + if (pos < len) { + tmp <<= 8; + tmp |= data[pos++] & 0xFF; + bits += 8; + } else { // last byte + tmp <<= (5 - bits); + bits = 5; + } + } + + bits -= 5; + index = (tmp >> bits) & 0x1F; + out.push_back(bintoasc()[index]); + } + + // append padding + while(out.length() % 4 != 0) + out.push_back('='); + + return out; + } + +private: + static const inline char *bintoasc() { static const char bta[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; return bta ; } +}; + +#endif // RADIX32_H diff --git a/libretroshare/src/util/rsprint.cc b/libretroshare/src/util/rsprint.cc index e692f6c26..56d372a48 100644 --- a/libretroshare/src/util/rsprint.cc +++ b/libretroshare/src/util/rsprint.cc @@ -126,3 +126,24 @@ std::string RsUtil::HashId(const std::string &id, bool reverse) // out << std::setprecision(15) << getCurrentTS(); // return out.str(); //} + +std::vector RsUtil::BinToSha256(const std::vector &in) +{ + std::vector out; + + SHA256_CTX *sha_ctx = new SHA256_CTX; + uint8_t sha_hash[SHA256_DIGEST_LENGTH] = {0}; + + SHA256_Init(sha_ctx); + SHA256_Update(sha_ctx, in.data(), in.size()); + SHA256_Final(sha_hash, sha_ctx); + + for(uint16_t i = 0; i < SHA256_DIGEST_LENGTH; i++) + { + out.push_back(sha_hash[i]); + } + + /* cleanup */ + delete sha_ctx; + return out; +} diff --git a/libretroshare/src/util/rsprint.h b/libretroshare/src/util/rsprint.h index 37207ebde..a2c6405a3 100644 --- a/libretroshare/src/util/rsprint.h +++ b/libretroshare/src/util/rsprint.h @@ -30,6 +30,7 @@ #include #include +#include namespace RsUtil { @@ -38,6 +39,7 @@ std::string BinToHex(const char *arr, const uint32_t len); std::string BinToHex(const unsigned char *arr, const uint32_t len); std::string NumberToString(uint64_t n, bool hex=false); std::string HashId(const std::string &id, bool reverse = false); +std::vector BinToSha256(const std::vector &in); //std::string AccurateTimeString(); diff --git a/retroshare-gui/src/gui/GenCertDialog.cpp b/retroshare-gui/src/gui/GenCertDialog.cpp index 1887ca304..4f4193db6 100644 --- a/retroshare-gui/src/gui/GenCertDialog.cpp +++ b/retroshare-gui/src/gui/GenCertDialog.cpp @@ -149,6 +149,8 @@ GenCertDialog::GenCertDialog(bool onlyGenerateIdentity, QWidget *parent) connect(ui.node_input, SIGNAL(textChanged(QString)), this, SLOT(updateCheckLabels())); connect(ui.reuse_existing_node_CB, SIGNAL(toggled(bool)), this, SLOT(updateCheckLabels())); + connect(ui.cbUseBob, SIGNAL(clicked(bool)), this, SLOT(useBobChecked(bool)));; + entropy_timer = new QTimer ; entropy_timer->start(20) ; QObject::connect(entropy_timer,SIGNAL(timeout()),this,SLOT(grabMouse())) ; @@ -240,7 +242,7 @@ void GenCertDialog::mouseMoveEvent(QMouseEvent *e) void GenCertDialog::setupState() { - bool adv_state = ui.adv_checkbox->isChecked(); + bool adv_state = ui.adv_checkbox->isChecked(); if(!adv_state) { @@ -300,6 +302,7 @@ void GenCertDialog::setupState() ui.hiddenaddr_label->setVisible(hidden_state); ui.hiddenport_label->setVisible(hidden_state); ui.hiddenport_spinBox->setVisible(hidden_state); + ui.cbUseBob->setVisible(hidden_state); if(mEntropyOk && mAllFieldsOk) { @@ -379,7 +382,22 @@ void GenCertDialog::updateCheckLabels() else ui.randomness_check_LB->setPixmap(QPixmap(IMAGE_BAD)) ; - setupState(); + setupState(); +} + +void GenCertDialog::useBobChecked(bool checked) +{ + if (checked) { + ui.hiddenaddr_input->setPlaceholderText(tr("I2P instance address with BOB enabled")); + ui.hiddenaddr_label->setText(tr("I2P instance address")); + + ui.hiddenport_spinBox->setEnabled(false); + } else { + ui.hiddenaddr_input->setPlaceholderText(tr("hidden service address")); + ui.hiddenaddr_label->setText(tr("hidden address")); + + ui.hiddenport_spinBox->setEnabled(true); + } } bool GenCertDialog::importIdentity() @@ -454,15 +472,13 @@ void GenCertDialog::genPerson() { std::string hl = ui.hiddenaddr_input->text().toStdString(); uint16_t port = ui.hiddenport_spinBox->value(); - if (!RsInit::SetHiddenLocation(hl, port)) /* parses it */ - { - /* Message Dialog */ - QMessageBox::warning(this, - tr("Invalid hidden node"), - tr("Please enter a valid address of the form: 31769173498.onion:7800 or [52 characters].b32.i2p"), - QMessageBox::Ok); - return; - } + bool useBob = ui.cbUseBob->isChecked(); + + if (useBob && hl.empty()) + hl = "127.0.0.1"; + + RsInit::SetHiddenLocation(hl, port, useBob); /* parses it */ + isHiddenLoc = true; } diff --git a/retroshare-gui/src/gui/GenCertDialog.h b/retroshare-gui/src/gui/GenCertDialog.h index f32aa4166..605f9a31f 100644 --- a/retroshare-gui/src/gui/GenCertDialog.h +++ b/retroshare-gui/src/gui/GenCertDialog.h @@ -45,6 +45,7 @@ private slots: void switchReuseExistingNode(); void grabMouse(); void updateCheckLabels(); + void useBobChecked(bool checked); private: void initKeyList(); diff --git a/retroshare-gui/src/gui/GenCertDialog.ui b/retroshare-gui/src/gui/GenCertDialog.ui index 23b524f49..ba7c1e647 100644 --- a/retroshare-gui/src/gui/GenCertDialog.ui +++ b/retroshare-gui/src/gui/GenCertDialog.ui @@ -450,6 +450,13 @@ + + + + Use BOB + + + diff --git a/retroshare-gui/src/gui/notifyqt.cpp b/retroshare-gui/src/gui/notifyqt.cpp index c730ef406..91a6153a7 100644 --- a/retroshare-gui/src/gui/notifyqt.cpp +++ b/retroshare-gui/src/gui/notifyqt.cpp @@ -487,6 +487,20 @@ void NotifyQt::notifyChatLobbyTimeShift(int shift) emit chatLobbyTimeShift(shift) ; } +void NotifyQt::notifyConnectionWithoutCert() +{ + { + QMutexLocker m(&_mutex) ; + if(!_enabled) + return ; + } + +#ifdef NOTIFY_DEBUG + std::cerr << "notifyQt: Received notifyConnectionWithoutCert" << std::endl; +#endif + emit connectionWithoutCert(); +} + void NotifyQt::handleChatLobbyTimeShift(int /*shift*/) { return ; // we say nothing. The help dialog of lobbies explains this already. diff --git a/retroshare-gui/src/gui/notifyqt.h b/retroshare-gui/src/gui/notifyqt.h index bc5cac9db..f04394eb1 100644 --- a/retroshare-gui/src/gui/notifyqt.h +++ b/retroshare-gui/src/gui/notifyqt.h @@ -52,6 +52,7 @@ class NotifyQt: public QObject, public NotifyClient virtual void notifyOwnAvatarChanged() ; virtual void notifyChatLobbyEvent(uint64_t /* lobby id */, uint32_t /* event type */, const RsGxsId & /*nickname*/, const std::string& /* any string */) ; virtual void notifyChatLobbyTimeShift(int time_shift) ; + void notifyConnectionWithoutCert(); virtual void notifyOwnStatusMessageChanged() ; virtual void notifyDiskFull(uint32_t loc,uint32_t size_in_mb) ; @@ -143,6 +144,7 @@ class NotifyQt: public QObject, public NotifyClient void chatLobbyInviteReceived() ; void deferredSignatureHandlingRequested() ; void chatLobbyTimeShift(int time_shift) ; + void connectionWithoutCert(); /* Notify from GUI */ void chatFontChanged(); diff --git a/retroshare-gui/src/gui/qss/stylesheet/Standard.qss b/retroshare-gui/src/gui/qss/stylesheet/Standard.qss index 891dc72d3..138e48d52 100644 --- a/retroshare-gui/src/gui/qss/stylesheet/Standard.qss +++ b/retroshare-gui/src/gui/qss/stylesheet/Standard.qss @@ -519,6 +519,21 @@ ServerPage QPlainTextEdit#plainTextEdit { background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFFFD7, stop:1 #FFFFB2); } +ServerPage QPlainTextEdit#hiddenpageInHelpPlainTextEdit { + border: 1px solid #DCDC41; + border-radius: 6px; + background: #FFFFD7; + background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFFFD7, stop:1 #FFFFB2); +} + +ServerPage QPlainTextEdit#pteBobSimple { + border: 1px solid #DCDC41; + border-radius: 6px; + background: #FFFFD7; + background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFFFD7, stop:1 #FFFFB2); +} + + /* ProfileManager */ ProfileManager > QFrame#headerFrame { diff --git a/retroshare-gui/src/gui/settings/ServerPage.cpp b/retroshare-gui/src/gui/settings/ServerPage.cpp index d9dd900fb..41c612876 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.cpp +++ b/retroshare-gui/src/gui/settings/ServerPage.cpp @@ -21,6 +21,7 @@ #include "ServerPage.h" +#include #include "rshare.h" #include "rsharesettings.h" #include "util/RsNetUtil.h" @@ -43,7 +44,9 @@ #include #define ICON_STATUS_UNKNOWN ":/images/ledoff1.png" +#define ICON_STATUS_WORKING ":/images/yellowled.png" #define ICON_STATUS_OK ":/images/ledon1.png" +#define ICON_STATUS_ERROR ":/images/redled.png" #define COLUMN_RANGE 0 #define COLUMN_STATUS 1 @@ -51,10 +54,15 @@ #define COLUMN_REASON 3 #define COLUMN_COMMENT 4 +/// +/// \brief hiddenServiceIncomingTab index of hidden serice incoming tab +/// +const static uint32_t hiddenServiceIncomingTab = 2; + //#define SERVER_DEBUG 1 ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags) - : ConfigPage(parent, flags), mIsHiddenNode(false), mHiddenType(RS_HIDDEN_TYPE_NONE) + : ConfigPage(parent, flags), mIsHiddenNode(false), mHiddenType(RS_HIDDEN_TYPE_NONE) { /* Invoke the Qt Designer generated object setup routine */ ui.setupUi(this); @@ -75,20 +83,26 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags) timer->connect(timer, SIGNAL(timeout()), this, SLOT(updateStatus())); timer->start(1000); - //load(); - updateStatus(); + //load(); + updateStatus(); - bool b = rsPeers->getAllowServerIPDetermination() ; - ui.allowIpDeterminationCB->setChecked(b) ; - ui.IPServersLV->setEnabled(b) ; + bool b = rsPeers->getAllowServerIPDetermination() ; + ui.allowIpDeterminationCB->setChecked(b) ; + ui.IPServersLV->setEnabled(b) ; - std::list ip_servers ; - rsPeers->getIPServersList(ip_servers) ; + std::list ip_servers ; + rsPeers->getIPServersList(ip_servers) ; - for(std::list::const_iterator it(ip_servers.begin());it!=ip_servers.end();++it) - ui.IPServersLV->addItem(QString::fromStdString(*it)) ; + for(std::list::const_iterator it(ip_servers.begin());it!=ip_servers.end();++it) + ui.IPServersLV->addItem(QString::fromStdString(*it)) ; - ui.hiddenpage_incoming->setVisible(false); + ui.hiddenServiceTab->setTabEnabled(hiddenServiceIncomingTab, false); + ui.gbBob->setEnabled(false); + ui.swBobAdvanced->setCurrentIndex(0); + + ui.lBobB32Addr->hide(); + ui.leBobB32Addr->hide(); + ui.pbBobGenAddr->hide(); QObject::connect(ui.filteredIpsTable,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(ipFilterContextMenu(const QPoint&))) ; QObject::connect(ui.whiteListIpsTable,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(ipWhiteListContextMenu(const QPoint&))) ; @@ -103,39 +117,65 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags) QObject::connect(ui.filteredIpsTable,SIGNAL(currentCellChanged(int,int,int,int)),this,SLOT(updateSelectedBlackListIP(int,int,int,int))); QObject::connect(ui.whiteListIpsTable,SIGNAL(currentCellChanged(int,int,int,int)),this,SLOT(updateSelectedWhiteListIP(int,int,int,int))); + QObject::connect(ui.pbBobStart, SIGNAL(clicked()), this, SLOT(startBOB())); + QObject::connect(ui.pbBobRestart, SIGNAL(clicked()), this, SLOT(restartBOB())); + QObject::connect(ui.pbBobStop, SIGNAL(clicked()), this, SLOT(stopBOB())); + QObject::connect(ui.pbBobGenAddr, SIGNAL(clicked()), this, SLOT(getNewKey())); + QObject::connect(ui.pbBobLoadKey, SIGNAL(clicked()), this, SLOT(loadKey())); + QObject::connect(ui.cb_enableBob, SIGNAL(toggled(bool)), this, SLOT(enableBob(bool))); + + QObject::connect(ui.cbBobAdvanced, SIGNAL(toggled(bool)), this, SLOT(toggleBobAdvancedSettings(bool))); + + QObject::connect(ui.sbBobLengthIn, SIGNAL(valueChanged(int)), this, SLOT(tunnelSettingsChanged(int))); + QObject::connect(ui.sbBobLengthOut, SIGNAL(valueChanged(int)), this, SLOT(tunnelSettingsChanged(int))); + QObject::connect(ui.sbBobQuantityIn, SIGNAL(valueChanged(int)), this, SLOT(tunnelSettingsChanged(int))); + QObject::connect(ui.sbBobQuantityOut, SIGNAL(valueChanged(int)), this, SLOT(tunnelSettingsChanged(int))); + QObject::connect(ui.sbBobVarianceIn, SIGNAL(valueChanged(int)), this, SLOT(tunnelSettingsChanged(int))); + QObject::connect(ui.sbBobVarianceOut, SIGNAL(valueChanged(int)), this, SLOT(tunnelSettingsChanged(int))); + + // These two spin boxes are used for the same thing - keep them in sync! + QObject::connect(ui.hiddenpage_proxyPort_i2p, SIGNAL(valueChanged(int)), this, SLOT(syncI2PProxyPortNormal(int))); + QObject::connect(ui.hiddenpage_proxyPort_i2p_2, SIGNAL(valueChanged(int)), this, SLOT(syncI2PProxyPortBob(int))); + + // These two line edits are used for the same thing - keep them in sync! + QObject::connect(ui.hiddenpage_proxyAddress_i2p, SIGNAL(textChanged(QString)), this, SLOT(syncI2PProxyAddrNormal(QString))); + QObject::connect(ui.hiddenpage_proxyAddress_i2p_2, SIGNAL(textChanged(QString)), this, SLOT(syncI2PProxyAddrBob(QString))); + + connect(NotifyQt::getInstance(), SIGNAL(connectionWithoutCert()), this, SLOT(connectionWithoutCert())); + QObject::connect(ui.localPort,SIGNAL(valueChanged(int)),this,SLOT(saveAddresses())); QObject::connect(ui.extPort,SIGNAL(valueChanged(int)),this,SLOT(saveAddresses())); - connect( ui.netModeComboBox, SIGNAL( activated ( int ) ), this, SLOT( toggleUPnP( ) ) ); - connect( ui.allowIpDeterminationCB, SIGNAL( toggled( bool ) ), this, SLOT( toggleIpDetermination(bool) ) ); - connect( ui.cleanKnownIPs_PB, SIGNAL( clicked( ) ), this, SLOT( clearKnownAddressList() ) ); - connect( ui.testIncoming_PB, SIGNAL( clicked( ) ), this, SLOT( saveAndTestInProxy() ) ); + connect( ui.netModeComboBox, SIGNAL( activated ( int ) ), this, SLOT( toggleUPnP( ) ) ); + connect( ui.allowIpDeterminationCB, SIGNAL( toggled( bool ) ), this, SLOT( toggleIpDetermination(bool) ) ); + connect( ui.cleanKnownIPs_PB, SIGNAL( clicked( ) ), this, SLOT( clearKnownAddressList() ) ); + connect( ui.testIncoming_PB, SIGNAL( clicked( ) ), this, SLOT( saveAndTestInProxy() ) ); connect( ui.showDiscStatusBar,SIGNAL(toggled(bool)),this,SLOT(updateShowDiscStatusBar())) ; #ifdef SERVER_DEBUG - std::cerr << "ServerPage::ServerPage() called"; - std::cerr << std::endl; + std::cerr << "ServerPage::ServerPage() called"; + std::cerr << std::endl; #endif - connect(ui.netModeComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(saveAddresses())); - connect(ui.discComboBox, SIGNAL(currentIndexChanged(int)),this,SLOT(saveAddresses())); - connect(ui.localAddress, SIGNAL(textChanged(QString)),this,SLOT(saveAddresses())); - connect(ui.extAddress, SIGNAL(textChanged(QString)),this,SLOT(saveAddresses())); - connect(ui.dynDNS, SIGNAL(textChanged(QString)),this,SLOT(saveAddresses())); + connect(ui.netModeComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(saveAddresses())); + connect(ui.discComboBox, SIGNAL(currentIndexChanged(int)),this,SLOT(saveAddresses())); + connect(ui.localAddress, SIGNAL(textChanged(QString)),this,SLOT(saveAddresses())); + connect(ui.extAddress, SIGNAL(textChanged(QString)),this,SLOT(saveAddresses())); + connect(ui.dynDNS, SIGNAL(textChanged(QString)),this,SLOT(saveAddresses())); - connect(ui.hiddenpage_proxyAddress_tor, SIGNAL(textChanged(QString)),this,SLOT(saveAddresses())); - connect(ui.hiddenpage_proxyPort_tor, SIGNAL(valueChanged(int)),this,SLOT(saveAddresses())); - connect(ui.hiddenpage_proxyAddress_i2p, SIGNAL(textChanged(QString)),this,SLOT(saveAddresses())); - connect(ui.hiddenpage_proxyPort_i2p, SIGNAL(valueChanged(int)),this,SLOT(saveAddresses())); + connect(ui.hiddenpage_proxyAddress_tor, SIGNAL(textChanged(QString)),this,SLOT(saveAddresses())); + connect(ui.hiddenpage_proxyPort_tor, SIGNAL(valueChanged(int)),this,SLOT(saveAddresses())); + connect(ui.hiddenpage_proxyAddress_i2p, SIGNAL(textChanged(QString)),this,SLOT(saveAddresses())); + connect(ui.hiddenpage_proxyPort_i2p, SIGNAL(valueChanged(int)),this,SLOT(saveAddresses())); - connect(ui.totalDownloadRate,SIGNAL(valueChanged(int)),this,SLOT(saveRates())); - connect(ui.totalUploadRate, SIGNAL(valueChanged(int)),this,SLOT(saveRates())); + connect(ui.totalDownloadRate,SIGNAL(valueChanged(int)),this,SLOT(saveRates())); + connect(ui.totalUploadRate, SIGNAL(valueChanged(int)),this,SLOT(saveRates())); } void ServerPage::saveAndTestInProxy() { saveAddresses(); - updateInProxyIndicator() ; + updateInProxyIndicator() ; } void ServerPage::checkIpRange(const QString& ipstr) @@ -199,8 +239,8 @@ void ServerPage::clearKnownAddressList() void ServerPage::toggleIpDetermination(bool b) { - rsPeers->allowServerIPDetermination(b) ; - ui.IPServersLV->setEnabled(b) ; + rsPeers->allowServerIPDetermination(b) ; + ui.IPServersLV->setEnabled(b) ; } void ServerPage::toggleTunnelConnection(bool b) @@ -215,119 +255,124 @@ void ServerPage::updateShowDiscStatusBar() { Settings->setStatusBarFlag(STATUSBA void ServerPage::load() { #ifdef SERVER_DEBUG - std::cerr << "ServerPage::load() called"; - std::cerr << std::endl; + std::cerr << "ServerPage::load() called"; + std::cerr << std::endl; #endif - /* load up configuration from rsPeers */ - RsPeerDetails detail; - if (!rsPeers->getPeerDetails(rsPeers->getOwnId(), detail)) - { - return; + /* load up configuration from rsPeers */ + RsPeerDetails detail; + if (!rsPeers->getPeerDetails(rsPeers->getOwnId(), detail)) + { + return; } mIsHiddenNode = (detail.netMode == RS_NETMODE_HIDDEN); + rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::getSettings, &mBobSettings); + + loadCommon(); + updateStatus(); + if (mIsHiddenNode) { - mHiddenType = detail.hiddenType; + mHiddenType = detail.hiddenType; ui.tabWidget->setTabEnabled(1,false) ; - loadHiddenNode(); - return; - } + loadHiddenNode(); + return; + } - // (csoler) Disabling some signals in this block in order to avoid + // (csoler) Disabling some signals in this block in order to avoid // some nasty feedback. - { - loadFilteredIps() ; + { + loadFilteredIps() ; - ui.netModeComboBox->show() ; - ui.textlabel_upnp->show(); - ui.iconlabel_upnp->show(); - ui.label_nat->show(); + ui.netModeComboBox->show() ; + ui.textlabel_upnp->show(); + ui.iconlabel_upnp->show(); + ui.label_nat->show(); - ui.textlabel_hiddenMode->hide() ; - ui.iconlabel_hiddenMode->hide() ; + ui.textlabel_hiddenMode->hide() ; + ui.iconlabel_hiddenMode->hide() ; - /* set net mode */ - int netIndex = 0; - switch(detail.netMode) - { - case RS_NETMODE_EXT: - netIndex = 2; - break; - case RS_NETMODE_UDP: - netIndex = 1; - break; - default: - case RS_NETMODE_UPNP: - netIndex = 0; - break; - } - whileBlocking(ui.netModeComboBox)->setCurrentIndex(netIndex); + /* set net mode */ + int netIndex = 0; + switch(detail.netMode) + { + case RS_NETMODE_EXT: + netIndex = 2; + break; + case RS_NETMODE_UDP: + netIndex = 1; + break; + default: + case RS_NETMODE_UPNP: + netIndex = 0; + break; + } + whileBlocking(ui.netModeComboBox)->setCurrentIndex(netIndex); - /* DHT + Discovery: (public) - * Discovery only: (private) - * DHT only: (inverted) - * None: (dark net) - */ + /* DHT + Discovery: (public) + * Discovery only: (private) + * DHT only: (inverted) + * None: (dark net) + */ - netIndex = 3; // NONE. - if (detail.vs_dht != RS_VS_DHT_OFF) - { - if (detail.vs_disc != RS_VS_DISC_OFF) - netIndex = 0; // PUBLIC - else - netIndex = 2; // INVERTED - } - else - { - if (detail.vs_disc != RS_VS_DISC_OFF) - netIndex = 1; // PRIVATE - else - netIndex = 3; // NONE - } + netIndex = 3; // NONE. + if (detail.vs_dht != RS_VS_DHT_OFF) + { + if (detail.vs_disc != RS_VS_DISC_OFF) + netIndex = 0; // PUBLIC + else + netIndex = 2; // INVERTED + } + else + { + if (detail.vs_disc != RS_VS_DISC_OFF) + netIndex = 1; // PRIVATE + else + netIndex = 3; // NONE + } - whileBlocking(ui.discComboBox)->setCurrentIndex(netIndex); + whileBlocking(ui.discComboBox)->setCurrentIndex(netIndex); - int dlrate = 0; - int ulrate = 0; - rsConfig->GetMaxDataRates(dlrate, ulrate); - whileBlocking(ui.totalDownloadRate)->setValue(dlrate); - whileBlocking(ui.totalUploadRate)->setValue(ulrate); + int dlrate = 0; + int ulrate = 0; + rsConfig->GetMaxDataRates(dlrate, ulrate); + whileBlocking(ui.totalDownloadRate)->setValue(dlrate); + whileBlocking(ui.totalUploadRate)->setValue(ulrate); - toggleUPnP(); + toggleUPnP(); - /* Addresses must be set here - otherwise can't edit it */ - /* set local address */ - whileBlocking(ui.localAddress)->setText(QString::fromStdString(detail.localAddr)); - whileBlocking(ui.localPort )-> setValue(detail.localPort); - /* set the server address */ - whileBlocking(ui.extAddress)->setText(QString::fromStdString(detail.extAddr)); - whileBlocking(ui.extPort) -> setValue(detail.extPort); - /* set DynDNS */ - whileBlocking(ui.dynDNS) -> setText(QString::fromStdString(detail.dyndns)); + /* Addresses must be set here - otherwise can't edit it */ + /* set local address */ + whileBlocking(ui.localAddress)->setText(QString::fromStdString(detail.localAddr)); + whileBlocking(ui.localPort )-> setValue(detail.localPort); + /* set the server address */ + whileBlocking(ui.extAddress)->setText(QString::fromStdString(detail.extAddr)); + whileBlocking(ui.extPort) -> setValue(detail.extPort); + /* set DynDNS */ + whileBlocking(ui.dynDNS) -> setText(QString::fromStdString(detail.dyndns)); - whileBlocking(ui.showDiscStatusBar)->setChecked(Settings->getStatusBarFlags() & STATUSBAR_DISC); + whileBlocking(ui.showDiscStatusBar)->setChecked(Settings->getStatusBarFlags() & STATUSBAR_DISC); - whileBlocking(ui.ipAddressList)->clear(); - for(std::list::const_iterator it(detail.ipAddressList.begin());it!=detail.ipAddressList.end();++it) - whileBlocking(ui.ipAddressList)->addItem(QString::fromStdString(*it)); + whileBlocking(ui.ipAddressList)->clear(); + for(std::list::const_iterator it(detail.ipAddressList.begin());it!=detail.ipAddressList.end();++it) + whileBlocking(ui.ipAddressList)->addItem(QString::fromStdString(*it)); - /* HIDDEN PAGE SETTINGS - only Proxy (outgoing) */ - std::string proxyaddr; - uint16_t proxyport; - uint32_t status ; - // Tor - rsPeers->getProxyServer(RS_HIDDEN_TYPE_TOR, proxyaddr, proxyport, status); - whileBlocking(ui.hiddenpage_proxyAddress_tor) -> setText(QString::fromStdString(proxyaddr)); - whileBlocking(ui.hiddenpage_proxyPort_tor) -> setValue(proxyport); - // I2P - rsPeers->getProxyServer(RS_HIDDEN_TYPE_I2P, proxyaddr, proxyport, status); - whileBlocking(ui.hiddenpage_proxyAddress_i2p) -> setText(QString::fromStdString(proxyaddr)); - whileBlocking(ui.hiddenpage_proxyPort_i2p) -> setValue(proxyport); + /* HIDDEN PAGE SETTINGS - only Proxy (outgoing) */ + std::string proxyaddr; + uint16_t proxyport; + uint32_t status ; + // Tor + rsPeers->getProxyServer(RS_HIDDEN_TYPE_TOR, proxyaddr, proxyport, status); + whileBlocking(ui.hiddenpage_proxyAddress_tor) -> setText(QString::fromStdString(proxyaddr)); + whileBlocking(ui.hiddenpage_proxyPort_tor) -> setValue(proxyport); + // I2P + rsPeers->getProxyServer(RS_HIDDEN_TYPE_I2P, proxyaddr, proxyport, status); + whileBlocking(ui.hiddenpage_proxyAddress_i2p) -> setText(QString::fromStdString(proxyaddr)); + whileBlocking(ui.hiddenpage_proxyPort_i2p) -> setValue(proxyport); - updateOutProxyIndicator(); - } + updateOutProxyIndicator(); + } } void ServerPage::toggleAutoIncludeFriends(bool b) @@ -339,6 +384,7 @@ void ServerPage::toggleAutoIncludeDHT(bool b) { rsBanList->enableIPsFromDHT(b) ; } + void ServerPage::toggleIpFiltering(bool b) { rsBanList->enableIPFiltering(b) ; @@ -400,6 +446,7 @@ void ServerPage::loadFilteredIps() for(std::list::const_iterator it(lst.begin());it!=lst.end();++it,++row) addPeerToIPTable(ui.whiteListIpsTable,row,*it) ; } + void ServerPage::updateSelectedBlackListIP(int row,int,int,int) { QTableWidgetItem *item = ui.filteredIpsTable->item(row,COLUMN_RANGE); @@ -421,6 +468,7 @@ void ServerPage::updateSelectedBlackListIP(int row,int,int,int) ui.ipInputRange_SB->setValue(32 - 8*masked_bytes) ; ui.ipInputComment_LE->setText(ui.filteredIpsTable->item(row,COLUMN_COMMENT)->text()) ; } + void ServerPage::updateSelectedWhiteListIP(int row, int,int,int) { QTableWidgetItem *item = ui.whiteListIpsTable->item(row,COLUMN_RANGE); @@ -488,8 +536,8 @@ void ServerPage::addPeerToIPTable(QTableWidget *table,int row,const BanListPeer& } - void ServerPage::toggleGroupIps(bool b) { rsBanList->enableAutoRange(b) ; } + void ServerPage::setGroupIpLimit(int n) { rsBanList->setAutoRangeLimit(n) ; } void ServerPage::ipFilterContextMenu(const QPoint& /*point*/) @@ -550,7 +598,6 @@ bool ServerPage::removeCurrentRowFromBlackList(sockaddr_storage& collected_addr, return true ; } - bool ServerPage::removeCurrentRowFromWhiteList(sockaddr_storage& collected_addr,int &masked_bytes) { int row = ui.whiteListIpsTable->currentRow(); @@ -580,6 +627,7 @@ void ServerPage::moveToWhiteList0() rsBanList->addIpRange(addr,0,RSBANLIST_TYPE_WHITELIST, tr("Added by you").toStdString()); } + void ServerPage::moveToWhiteList1() { sockaddr_storage addr ; @@ -590,6 +638,7 @@ void ServerPage::moveToWhiteList1() rsBanList->addIpRange(addr,1,RSBANLIST_TYPE_WHITELIST, tr("Added by you").toStdString()); } + void ServerPage::moveToWhiteList2() { sockaddr_storage addr ; @@ -600,6 +649,7 @@ void ServerPage::moveToWhiteList2() rsBanList->addIpRange(addr,2,RSBANLIST_TYPE_WHITELIST, tr("Added by you").toStdString()); } + void ServerPage::ipWhiteListContextMenu(const QPoint& /* point */) { QMenu contextMenu(this) ; @@ -636,6 +686,7 @@ void ServerPage::ipWhiteListContextMenu(const QPoint& /* point */) contextMenu.exec(QCursor::pos()) ; } + void ServerPage::removeBannedIp() { sockaddr_storage addr; @@ -643,6 +694,7 @@ void ServerPage::removeBannedIp() removeCurrentRowFromBlackList(addr,bytes) ; } + void ServerPage::removeWhiteListedIp() { sockaddr_storage addr; @@ -655,205 +707,189 @@ void ServerPage::removeWhiteListedIp() void ServerPage::updateStatus() { #ifdef SERVER_DEBUG - std::cerr << "ServerPage::updateStatus() called"; - std::cerr << std::endl; + std::cerr << "ServerPage::updateStatus() called"; + std::cerr << std::endl; #endif - if(RsAutoUpdatePage::eventsLocked()) - return ; + if(RsAutoUpdatePage::eventsLocked()) + return ; - if(!isVisible()) - return ; + if(!isVisible()) + return ; loadFilteredIps() ; - if (mIsHiddenNode) - { - updateStatusHiddenNode(); - return; + updateStatusBob(); + + // this is used by BOB + if (mOngoingConnectivityCheck > 0) { + mOngoingConnectivityCheck--; + + if (mOngoingConnectivityCheck == 0) { + updateInProxyIndicatorResult(false); + mOngoingConnectivityCheck = -1; + } } - /* load up configuration from rsPeers */ - RsPeerDetails detail; - if (!rsPeers->getPeerDetails(rsPeers->getOwnId(), detail)) - return; + if (mIsHiddenNode) { + updateStatusHiddenNode(); + return; + } - /* only update if can't edit */ - if (!ui.localPort->isEnabled()) - { - /* set local address */ - whileBlocking(ui.localPort) -> setValue(detail.localPort); - whileBlocking(ui.extPort) -> setValue(detail.extPort); - } + /* load up configuration from rsPeers */ + RsPeerDetails detail; + if (!rsPeers->getPeerDetails(rsPeers->getOwnId(), detail)) + return; - /* set local address */ - whileBlocking(ui.localAddress)->setText(QString::fromStdString(detail.localAddr)); - /* set the server address */ - whileBlocking(ui.extAddress)->setText(QString::fromStdString(detail.extAddr)); + /* only update if can't edit */ + if (!ui.localPort->isEnabled()) + { + /* set local address */ + whileBlocking(ui.localPort) -> setValue(detail.localPort); + whileBlocking(ui.extPort) -> setValue(detail.extPort); + } + + /* set local address */ + whileBlocking(ui.localAddress)->setText(QString::fromStdString(detail.localAddr)); + /* set the server address */ + whileBlocking(ui.extAddress)->setText(QString::fromStdString(detail.extAddr)); - // Now update network bits. - RsConfigNetStatus net_status; - rsConfig->getConfigNetStatus(net_status); + // Now update network bits. + RsConfigNetStatus net_status; + rsConfig->getConfigNetStatus(net_status); - /******* Network Status Tab *******/ + /******* Network Status Tab *******/ - if(net_status.netUpnpOk) - ui.iconlabel_upnp->setPixmap(QPixmap(":/images/ledon1.png")); - else - ui.iconlabel_upnp->setPixmap(QPixmap(":/images/ledoff1.png")); + if(net_status.netUpnpOk) + ui.iconlabel_upnp->setPixmap(QPixmap(":/images/ledon1.png")); + else + ui.iconlabel_upnp->setPixmap(QPixmap(":/images/ledoff1.png")); - if (net_status.netLocalOk) - ui.iconlabel_netLimited->setPixmap(QPixmap(":/images/ledon1.png")); - else - ui.iconlabel_netLimited->setPixmap(QPixmap(":/images/ledoff1.png")); + if (net_status.netLocalOk) + ui.iconlabel_netLimited->setPixmap(QPixmap(":/images/ledon1.png")); + else + ui.iconlabel_netLimited->setPixmap(QPixmap(":/images/ledoff1.png")); - if (net_status.netExtAddressOk) - ui.iconlabel_ext->setPixmap(QPixmap(":/images/ledon1.png")); - else + if (net_status.netExtAddressOk) + ui.iconlabel_ext->setPixmap(QPixmap(":/images/ledon1.png")); + else ui.iconlabel_ext->setPixmap(QPixmap(":/images/ledoff1.png")); // check for Tor - updateOutProxyIndicator(); + updateOutProxyIndicator(); } void ServerPage::toggleUPnP() { - /* switch on the radioButton */ - bool settingChangeable = false; - if (0 != ui.netModeComboBox->currentIndex()) - { - settingChangeable = true; - } + /* switch on the radioButton */ + bool settingChangeable = false; + if (0 != ui.netModeComboBox->currentIndex()) + { + settingChangeable = true; + } - if (settingChangeable) - { - ui.localAddress->setEnabled(false); - ui.localPort -> setEnabled(true); - ui.extAddress -> setEnabled(false); - ui.extPort -> setEnabled(true); - } - else - { - ui.localAddress->setEnabled(false); - ui.localPort -> setEnabled(false); - ui.extAddress -> setEnabled(false); - ui.extPort -> setEnabled(false); - } + if (settingChangeable) + { + ui.localAddress->setEnabled(false); + ui.localPort -> setEnabled(true); + ui.extAddress -> setEnabled(false); + ui.extPort -> setEnabled(true); + } + else + { + ui.localAddress->setEnabled(false); + ui.localPort -> setEnabled(false); + ui.extAddress -> setEnabled(false); + ui.extPort -> setEnabled(false); + } } void ServerPage::saveAddresses() { - QString str; + bool saveAddr = false; - bool saveAddr = false; + saveCommon(); - if (mIsHiddenNode) - { - saveAddressesHiddenNode(); - return; - } + if (mIsHiddenNode) { + saveAddressesHiddenNode(); + return; + } - RsPeerDetails detail; + RsPeerDetails detail; RsPeerId ownId = rsPeers->getOwnId(); - if (!rsPeers->getPeerDetails(ownId, detail)) - return; + if (!rsPeers->getPeerDetails(ownId, detail)) + return; - int netIndex = ui.netModeComboBox->currentIndex(); + int netIndex = ui.netModeComboBox->currentIndex(); - /* Check if netMode has changed */ - uint32_t netMode = 0; - switch(netIndex) - { - case 3: - netMode = RS_NETMODE_HIDDEN; - break; - case 2: - netMode = RS_NETMODE_EXT; - break; - case 1: - netMode = RS_NETMODE_UDP; - break; - default: - case 0: - netMode = RS_NETMODE_UPNP; - break; - } + /* Check if netMode has changed */ + uint32_t netMode = 0; + switch(netIndex) + { + case 3: + netMode = RS_NETMODE_HIDDEN; + break; + case 2: + netMode = RS_NETMODE_EXT; + break; + case 1: + netMode = RS_NETMODE_UDP; + break; + default: + case 0: + netMode = RS_NETMODE_UPNP; + break; + } - if (detail.netMode != netMode) - rsPeers->setNetworkMode(ownId, netMode); + if (detail.netMode != netMode) + rsPeers->setNetworkMode(ownId, netMode); - uint16_t vs_disc = 0; - uint16_t vs_dht = 0; - /* Check if vis has changed */ - switch(ui.discComboBox->currentIndex()) - { - case 0: - vs_disc = RS_VS_DISC_FULL; - vs_dht = RS_VS_DHT_FULL; - break; - case 1: - vs_disc = RS_VS_DISC_FULL; - vs_dht = RS_VS_DHT_OFF; - break; - case 2: - vs_disc = RS_VS_DISC_OFF; - vs_dht = RS_VS_DHT_FULL; - break; - case 3: - default: - vs_disc = RS_VS_DISC_OFF; - vs_dht = RS_VS_DHT_OFF; - break; - } + uint16_t vs_disc = 0; + uint16_t vs_dht = 0; + /* Check if vis has changed */ + switch(ui.discComboBox->currentIndex()) + { + case 0: + vs_disc = RS_VS_DISC_FULL; + vs_dht = RS_VS_DHT_FULL; + break; + case 1: + vs_disc = RS_VS_DISC_FULL; + vs_dht = RS_VS_DHT_OFF; + break; + case 2: + vs_disc = RS_VS_DISC_OFF; + vs_dht = RS_VS_DHT_FULL; + break; + case 3: + default: + vs_disc = RS_VS_DISC_OFF; + vs_dht = RS_VS_DHT_OFF; + break; + } - if ((vs_disc != detail.vs_disc) || (vs_dht != detail.vs_dht)) - rsPeers->setVisState(ownId, vs_disc, vs_dht); + if ((vs_disc != detail.vs_disc) || (vs_dht != detail.vs_dht)) + rsPeers->setVisState(ownId, vs_disc, vs_dht); - if (0 != netIndex) - saveAddr = true; + if (0 != netIndex) + saveAddr = true; - if (saveAddr) - { - rsPeers->setLocalAddress(ownId, ui.localAddress->text().toStdString(), ui.localPort->value()); - rsPeers->setExtAddress(ownId, ui.extAddress->text().toStdString(), ui.extPort->value()); - } + if (saveAddr) + { + rsPeers->setLocalAddress(ownId, ui.localAddress->text().toStdString(), ui.localPort->value()); + rsPeers->setExtAddress(ownId, ui.extAddress->text().toStdString(), ui.extPort->value()); + } - rsPeers->setDynDNS(ownId, ui.dynDNS->text().toStdString()); + rsPeers->setDynDNS(ownId, ui.dynDNS->text().toStdString()); - // HANDLE PROXY SERVER. - std::string orig_proxyaddr, new_proxyaddr; - uint16_t orig_proxyport, new_proxyport; - uint32_t status ; - // Tor - rsPeers->getProxyServer(RS_HIDDEN_TYPE_TOR, orig_proxyaddr, orig_proxyport,status); - - new_proxyaddr = ui.hiddenpage_proxyAddress_tor -> text().toStdString(); - new_proxyport = ui.hiddenpage_proxyPort_tor -> value(); - - if ((new_proxyaddr != orig_proxyaddr) || (new_proxyport != orig_proxyport)) - { - rsPeers->setProxyServer(RS_HIDDEN_TYPE_TOR, new_proxyaddr, new_proxyport); - } - - // I2P - rsPeers->getProxyServer(RS_HIDDEN_TYPE_I2P, orig_proxyaddr, orig_proxyport,status); - - new_proxyaddr = ui.hiddenpage_proxyAddress_i2p -> text().toStdString(); - new_proxyport = ui.hiddenpage_proxyPort_i2p -> value(); - - if ((new_proxyaddr != orig_proxyaddr) || (new_proxyport != orig_proxyport)) - { - rsPeers->setProxyServer(RS_HIDDEN_TYPE_I2P, new_proxyaddr, new_proxyport); - } - - load(); + load(); } void ServerPage::saveRates() { - rsConfig->SetMaxDataRates( ui.totalDownloadRate->value(), ui.totalUploadRate->value() ); + rsConfig->SetMaxDataRates( ui.totalDownloadRate->value(), ui.totalUploadRate->value() ); } /***********************************************************************************/ @@ -866,294 +902,269 @@ void ServerPage::saveRates() void ServerPage::loadHiddenNode() { #ifdef SERVER_DEBUG - std::cerr << "ServerPage::loadHiddenNode() called"; - std::cerr << std::endl; + std::cerr << "ServerPage::loadHiddenNode() called"; + std::cerr << std::endl; #endif - /* load up configuration from rsPeers */ - RsPeerDetails detail; - if (!rsPeers->getPeerDetails(rsPeers->getOwnId(), detail)) - { - return; - } + /* load up configuration from rsPeers */ + RsPeerDetails detail; + if (!rsPeers->getPeerDetails(rsPeers->getOwnId(), detail)) + { + return; + } - /* At this point we want to force the Configuration Page to look different - * We will be called multiple times - so cannot just delete bad items. - * - * We want: - * NETMODE: HiddenNode FIXED. - * Disc/DHT: Discovery / No Discovery. - * Local Address: 127.0.0.1, Port: Listening Port. (listening port changable) - * External Address ==> Tor Address: 17621376587.onion + PORT. - * - * Known / Previous IPs: empty / removed. - * Ask about IP: Disabled. - */ + /* At this point we want to force the Configuration Page to look different + * We will be called multiple times - so cannot just delete bad items. + * + * We want: + * NETMODE: HiddenNode FIXED. + * Disc/DHT: Discovery / No Discovery. + * Local Address: 127.0.0.1, Port: Listening Port. (listening port changable) + * External Address ==> Tor Address: 17621376587.onion + PORT. + * + * Known / Previous IPs: empty / removed. + * Ask about IP: Disabled. + */ - // FIXED. - //ui.netModeComboBox->setCurrentIndex(3); - ui.netModeComboBox->hide(); - ui.textlabel_upnp->hide(); - ui.iconlabel_upnp->hide(); - ui.label_nat->hide(); - - ui.textlabel_hiddenMode->show(); - ui.iconlabel_hiddenMode->show() ; - ui.iconlabel_hiddenMode->setPixmap(QPixmap(":/images/ledon1.png")); + // FIXED. + //ui.netModeComboBox->setCurrentIndex(3); + ui.netModeComboBox->hide(); + ui.textlabel_upnp->hide(); + ui.iconlabel_upnp->hide(); + ui.label_nat->hide(); - // CHANGE OPTIONS ON - whileBlocking(ui.discComboBox)->removeItem(3); - whileBlocking(ui.discComboBox)->removeItem(2); - whileBlocking(ui.discComboBox)->removeItem(1); - whileBlocking(ui.discComboBox)->removeItem(0); - whileBlocking(ui.discComboBox)->insertItem (0, tr("Discovery On (recommended)")); - whileBlocking(ui.discComboBox)->insertItem (1, tr("Discovery Off")); + ui.textlabel_hiddenMode->show(); + ui.iconlabel_hiddenMode->show() ; + ui.iconlabel_hiddenMode->setPixmap(QPixmap(":/images/ledon1.png")); - int netIndex = 1; // OFF. - if (detail.vs_disc != RS_VS_DISC_OFF) - { - netIndex = 0; // DISC ON; - } - whileBlocking(ui.discComboBox)->setCurrentIndex(netIndex); + // CHANGE OPTIONS ON + whileBlocking(ui.discComboBox)->removeItem(3); + whileBlocking(ui.discComboBox)->removeItem(2); + whileBlocking(ui.discComboBox)->removeItem(1); + whileBlocking(ui.discComboBox)->removeItem(0); + whileBlocking(ui.discComboBox)->insertItem (0, tr("Discovery On (recommended)")); + whileBlocking(ui.discComboBox)->insertItem (1, tr("Discovery Off")); - // Download Rates - Stay the same as before. - int dlrate = 0; - int ulrate = 0; - rsConfig->GetMaxDataRates(dlrate, ulrate); - whileBlocking(ui.totalDownloadRate)->setValue(dlrate); - whileBlocking(ui.totalUploadRate)->setValue(ulrate); + int netIndex = 1; // OFF. + if (detail.vs_disc != RS_VS_DISC_OFF) + { + netIndex = 0; // DISC ON; + } + whileBlocking(ui.discComboBox)->setCurrentIndex(netIndex); - // Addresses. - ui.localAddress->setEnabled(false); - ui.localPort -> setEnabled(false); - ui.extAddress -> setEnabled(false); - ui.extPort -> setVisible(false); - ui.label_dynDNS->setVisible(false); - ui.dynDNS ->setVisible(false); + // Download Rates - Stay the same as before. + int dlrate = 0; + int ulrate = 0; + rsConfig->GetMaxDataRates(dlrate, ulrate); + whileBlocking(ui.totalDownloadRate)->setValue(dlrate); + whileBlocking(ui.totalUploadRate)->setValue(ulrate); - ui.hiddenpage_incoming->setVisible(true); + // Addresses. + ui.localAddress->setEnabled(false); + ui.localPort -> setEnabled(false); + ui.extAddress -> setEnabled(false); + ui.extPort -> setVisible(false); + ui.label_dynDNS->setVisible(false); + ui.dynDNS ->setVisible(false); - /* Addresses must be set here - otherwise can't edit it */ - /* set local address */ - whileBlocking(ui.localAddress)->setText(QString::fromStdString(detail.localAddr)); - whileBlocking(ui.localPort )-> setValue(detail.localPort); - /* set the server address */ + ui.hiddenServiceTab->setTabEnabled(hiddenServiceIncomingTab, true); - whileBlocking(ui.extAddress)->setText(tr("Hidden - See Config")); + /* Addresses must be set here - otherwise can't edit it */ + /* set local address */ + whileBlocking(ui.localAddress)->setText(QString::fromStdString(detail.localAddr)); + whileBlocking(ui.localPort )-> setValue(detail.localPort); + /* set the server address */ - whileBlocking(ui.showDiscStatusBar)->setChecked(Settings->getStatusBarFlags() & STATUSBAR_DISC); + whileBlocking(ui.extAddress)->setText(tr("Hidden - See Config")); + + whileBlocking(ui.showDiscStatusBar)->setChecked(Settings->getStatusBarFlags() & STATUSBAR_DISC); ui.showDiscStatusBar->hide() ; // hidden because not functional at the moment. //ui._turtle_enabled_CB->setChecked(rsTurtle->enabled()) ; - // show what we have in ipAddresses. (should be nothing!) - ui.ipAddressList->clear(); - for(std::list::const_iterator it(detail.ipAddressList.begin());it!=detail.ipAddressList.end();++it) - whileBlocking(ui.ipAddressList)->addItem(QString::fromStdString(*it)); + // show what we have in ipAddresses. (should be nothing!) + ui.ipAddressList->clear(); + for(std::list::const_iterator it(detail.ipAddressList.begin());it!=detail.ipAddressList.end();++it) + whileBlocking(ui.ipAddressList)->addItem(QString::fromStdString(*it)); - ui.iconlabel_upnp->setPixmap(QPixmap(":/images/ledoff1.png")); - ui.iconlabel_netLimited->setPixmap(QPixmap(":/images/ledoff1.png")); - ui.iconlabel_ext->setPixmap(QPixmap(":/images/ledoff1.png")); + ui.iconlabel_upnp->setPixmap(QPixmap(":/images/ledoff1.png")); + ui.iconlabel_netLimited->setPixmap(QPixmap(":/images/ledoff1.png")); + ui.iconlabel_ext->setPixmap(QPixmap(":/images/ledoff1.png")); - whileBlocking(ui.allowIpDeterminationCB)->setChecked(false); - whileBlocking(ui.allowIpDeterminationCB)->setEnabled(false); - whileBlocking(ui.IPServersLV)->setEnabled(false); + whileBlocking(ui.allowIpDeterminationCB)->setChecked(false); + whileBlocking(ui.allowIpDeterminationCB)->setEnabled(false); + whileBlocking(ui.IPServersLV)->setEnabled(false); - /* TOR PAGE SETTINGS */ + /* TOR PAGE SETTINGS */ - /* set local address */ - ui.hiddenpage_localAddress->setEnabled(false); - whileBlocking(ui.hiddenpage_localAddress)->setText(QString::fromStdString(detail.localAddr)); - whileBlocking(ui.hiddenpage_localPort) -> setValue(detail.localPort); + /* set local address */ + ui.hiddenpage_localAddress->setEnabled(false); + whileBlocking(ui.hiddenpage_localAddress)->setText(QString::fromStdString(detail.localAddr)); + whileBlocking(ui.hiddenpage_localPort) -> setValue(detail.localPort); - /* set the server address */ - whileBlocking(ui.hiddenpage_serviceAddress)->setText(QString::fromStdString(detail.hiddenNodeAddress)); - whileBlocking(ui.hiddenpage_servicePort) -> setValue(detail.hiddenNodePort); - /* in I2P there is no port - there is only the address */ - whileBlocking(ui.hiddenpage_servicePort)->setEnabled(detail.hiddenType != RS_HIDDEN_TYPE_I2P); + /* set the server address */ + whileBlocking(ui.hiddenpage_serviceAddress)->setText(QString::fromStdString(detail.hiddenNodeAddress)); + whileBlocking(ui.hiddenpage_servicePort) -> setValue(detail.hiddenNodePort); + /* in I2P there is no port - there is only the address */ + whileBlocking(ui.hiddenpage_servicePort)->setEnabled(detail.hiddenType != RS_HIDDEN_TYPE_I2P); - /* out proxy settings */ - std::string proxyaddr; - uint16_t proxyport; - uint32_t status ; - // Tor - rsPeers->getProxyServer(RS_HIDDEN_TYPE_TOR, proxyaddr, proxyport, status); - whileBlocking(ui.hiddenpage_proxyAddress_tor) -> setText(QString::fromStdString(proxyaddr)); - whileBlocking(ui.hiddenpage_proxyPort_tor) -> setValue(proxyport); - // I2P - rsPeers->getProxyServer(RS_HIDDEN_TYPE_I2P, proxyaddr, proxyport, status); - whileBlocking(ui.hiddenpage_proxyAddress_i2p) -> setText(QString::fromStdString(proxyaddr)); - whileBlocking(ui.hiddenpage_proxyPort_i2p) -> setValue(proxyport); + /* out proxy settings */ + std::string proxyaddr; + uint16_t proxyport; + uint32_t status ; + // Tor + rsPeers->getProxyServer(RS_HIDDEN_TYPE_TOR, proxyaddr, proxyport, status); + whileBlocking(ui.hiddenpage_proxyAddress_tor) -> setText(QString::fromStdString(proxyaddr)); + whileBlocking(ui.hiddenpage_proxyPort_tor) -> setValue(proxyport); + // I2P + rsPeers->getProxyServer(RS_HIDDEN_TYPE_I2P, proxyaddr, proxyport, status); + whileBlocking(ui.hiddenpage_proxyAddress_i2p) -> setText(QString::fromStdString(proxyaddr)); + whileBlocking(ui.hiddenpage_proxyPort_i2p) -> setValue(proxyport); - updateOutProxyIndicator(); + updateOutProxyIndicator(); - QString expected = ""; - switch (mHiddenType) { - case RS_HIDDEN_TYPE_I2P: - ui.l_serviceAddress->setText(tr("I2P Address")); - ui.l_incomingTestResult->setText(tr("I2P incoming ok")); + QString expected = ""; + switch (mHiddenType) { + case RS_HIDDEN_TYPE_I2P: + ui.l_serviceAddress->setText(tr("I2P Address")); + ui.l_incomingTestResult->setText(tr("I2P incoming ok")); - expected += "http://127.0.0.1:7657/i2ptunnelmgr - I2P Hidden Services\n"; - expected += tr("Points at: "); - expected += QString::fromStdString(detail.localAddr); - expected += ":"; - expected += QString::number(detail.localPort); - break; - case RS_HIDDEN_TYPE_TOR: - ui.l_serviceAddress->setText(tr("Onion Address")); - ui.l_incomingTestResult->setText(tr("Tor incoming ok")); + expected += "http://127.0.0.1:7657/i2ptunnelmgr - I2P Hidden Services\n"; + expected += tr("Points at: "); + expected += QString::fromStdString(detail.localAddr); + expected += ":"; + expected += QString::number(detail.localPort); + break; + case RS_HIDDEN_TYPE_TOR: + ui.l_serviceAddress->setText(tr("Onion Address")); + ui.l_incomingTestResult->setText(tr("Tor incoming ok")); - expected += "HiddenServiceDir \n"; - expected += "HiddenServicePort "; - expected += QString::number(detail.hiddenNodePort); - expected += " "; - expected += QString::fromStdString(detail.localAddr); - expected += ":"; - expected += QString::number(detail.localPort); - break; - default: - ui.l_serviceAddress->setText(tr("Service Address")); - ui.l_incomingTestResult->setText(tr("incoming ok")); + expected += "HiddenServiceDir \n"; + expected += "HiddenServicePort "; + expected += QString::number(detail.hiddenNodePort); + expected += " "; + expected += QString::fromStdString(detail.localAddr); + expected += ":"; + expected += QString::number(detail.localPort); + break; + default: + ui.l_serviceAddress->setText(tr("Service Address")); + ui.l_incomingTestResult->setText(tr("incoming ok")); - expected += "Please fill in a service address"; + expected += "Please fill in a service address"; - break; - } - whileBlocking(ui.hiddenpage_configuration)->setPlainText(expected); + break; + } + whileBlocking(ui.hiddenpage_configuration)->setPlainText(expected); } /** Loads the settings for this page */ void ServerPage::updateStatusHiddenNode() { #ifdef SERVER_DEBUG - std::cerr << "ServerPage::updateStatusHiddenNode() called"; - std::cerr << std::endl; + std::cerr << "ServerPage::updateStatusHiddenNode() called"; + std::cerr << std::endl; #endif // THIS IS DISABLED FOR NOW. #if 0 - /* load up configuration from rsPeers */ - RsPeerDetails detail; - if (!rsPeers->getPeerDetails(rsPeers->getOwnId(), detail)) - return; + /* load up configuration from rsPeers */ + RsPeerDetails detail; + if (!rsPeers->getPeerDetails(rsPeers->getOwnId(), detail)) + return; - /* only update if can't edit */ - if (!ui.localPort->isEnabled()) - { - /* set local address */ - ui.localPort -> setValue(detail.localPort); - ui.extPort -> setValue(detail.extPort); - } + /* only update if can't edit */ + if (!ui.localPort->isEnabled()) + { + /* set local address */ + ui.localPort -> setValue(detail.localPort); + ui.extPort -> setValue(detail.extPort); + } - /* set local address */ - ui.localAddress->setText(QString::fromStdString(detail.localAddr)); - /* set the server address */ - ui.extAddress->setText(QString::fromStdString(detail.extAddr)); + /* set local address */ + ui.localAddress->setText(QString::fromStdString(detail.localAddr)); + /* set the server address */ + ui.extAddress->setText(QString::fromStdString(detail.extAddr)); - // Now update network bits. - RsConfigNetStatus net_status; - rsConfig->getConfigNetStatus(net_status); + // Now update network bits. + RsConfigNetStatus net_status; + rsConfig->getConfigNetStatus(net_status); - /******* Network Status Tab *******/ + /******* Network Status Tab *******/ - if(net_status.netUpnpOk) - ui.iconlabel_upnp->setPixmap(QPixmap(":/images/ledon1.png")); - else - ui.iconlabel_upnp->setPixmap(QPixmap(":/images/ledoff1.png")); + if(net_status.netUpnpOk) + ui.iconlabel_upnp->setPixmap(QPixmap(":/images/ledon1.png")); + else + ui.iconlabel_upnp->setPixmap(QPixmap(":/images/ledoff1.png")); - if (net_status.netLocalOk) - ui.iconlabel_netLimited->setPixmap(QPixmap(":/images/ledon1.png")); - else - ui.iconlabel_netLimited->setPixmap(QPixmap(":/images/ledoff1.png")); + if (net_status.netLocalOk) + ui.iconlabel_netLimited->setPixmap(QPixmap(":/images/ledon1.png")); + else + ui.iconlabel_netLimited->setPixmap(QPixmap(":/images/ledoff1.png")); - if (net_status.netExtAddressOk) - ui.iconlabel_ext->setPixmap(QPixmap(":/images/ledon1.png")); - else - ui.iconlabel_ext->setPixmap(QPixmap(":/images/ledoff1.png")); + if (net_status.netExtAddressOk) + ui.iconlabel_ext->setPixmap(QPixmap(":/images/ledon1.png")); + else + ui.iconlabel_ext->setPixmap(QPixmap(":/images/ledoff1.png")); #endif - updateOutProxyIndicator(); + updateOutProxyIndicator(); } void ServerPage::saveAddressesHiddenNode() { - RsPeerDetails detail; + RsPeerDetails detail; RsPeerId ownId = rsPeers->getOwnId(); - if (!rsPeers->getPeerDetails(ownId, detail)) - return; + if (!rsPeers->getPeerDetails(ownId, detail)) + return; - // NETMODE IS UNCHANGABLE - uint16_t vs_disc = 0; - uint16_t vs_dht = 0; - /* Check if vis has changed */ - switch(ui.discComboBox->currentIndex()) - { - default: - case 0: - vs_disc = RS_VS_DISC_FULL; - vs_dht = RS_VS_DHT_OFF; - break; - case 1: - vs_disc = RS_VS_DISC_OFF; - vs_dht = RS_VS_DHT_OFF; - break; - } + // NETMODE IS UNCHANGABLE + uint16_t vs_disc = 0; + uint16_t vs_dht = 0; + /* Check if vis has changed */ + switch(ui.discComboBox->currentIndex()) + { + default: + case 0: + vs_disc = RS_VS_DISC_FULL; + vs_dht = RS_VS_DHT_OFF; + break; + case 1: + vs_disc = RS_VS_DISC_OFF; + vs_dht = RS_VS_DHT_OFF; + break; + } - if ((vs_disc != detail.vs_disc) || (vs_dht != detail.vs_dht)) - rsPeers->setVisState(ownId, vs_disc, vs_dht); + if ((vs_disc != detail.vs_disc) || (vs_dht != detail.vs_dht)) + rsPeers->setVisState(ownId, vs_disc, vs_dht); - if (detail.localPort != ui.hiddenpage_localPort->value()) - { - // Set Local Address - force to 127.0.0.1 - rsPeers->setLocalAddress(ownId, "127.0.0.1", ui.hiddenpage_localPort->value()); - } + if (detail.localPort != ui.hiddenpage_localPort->value()) + { + // Set Local Address - force to 127.0.0.1 + rsPeers->setLocalAddress(ownId, "127.0.0.1", ui.hiddenpage_localPort->value()); + } - std::string hiddenAddr = ui.hiddenpage_serviceAddress->text().toStdString(); - uint16_t hiddenPort = ui.hiddenpage_servicePort->value(); - if ((hiddenAddr != detail.hiddenNodeAddress) || (hiddenPort != detail.hiddenNodePort)) - { - rsPeers->setHiddenNode(ownId, hiddenAddr, hiddenPort); - } + std::string hiddenAddr = ui.hiddenpage_serviceAddress->text().toStdString(); + uint16_t hiddenPort = ui.hiddenpage_servicePort->value(); + if ((hiddenAddr != detail.hiddenNodeAddress) || (hiddenPort != detail.hiddenNodePort)) + { + rsPeers->setHiddenNode(ownId, hiddenAddr, hiddenPort); + } - // HANDLE PROXY SERVER. - std::string orig_proxyaddr,new_proxyaddr; - uint16_t orig_proxyport, new_proxyport; - uint32_t status ; - // Tor - rsPeers->getProxyServer(RS_HIDDEN_TYPE_TOR, orig_proxyaddr, orig_proxyport,status); - - new_proxyaddr = ui.hiddenpage_proxyAddress_tor -> text().toStdString(); - new_proxyport = ui.hiddenpage_proxyPort_tor -> value(); - - if ((new_proxyaddr != orig_proxyaddr) || (new_proxyport != orig_proxyport)) - { - rsPeers->setProxyServer(RS_HIDDEN_TYPE_TOR, new_proxyaddr, new_proxyport); - } - - // I2P - rsPeers->getProxyServer(RS_HIDDEN_TYPE_I2P, orig_proxyaddr, orig_proxyport,status); - - new_proxyaddr = ui.hiddenpage_proxyAddress_i2p -> text().toStdString(); - new_proxyport = ui.hiddenpage_proxyPort_i2p -> value(); - - if ((new_proxyaddr != orig_proxyaddr) || (new_proxyport != orig_proxyport)) - { - rsPeers->setProxyServer(RS_HIDDEN_TYPE_I2P, new_proxyaddr, new_proxyport); - } - - rsConfig->SetMaxDataRates( ui.totalDownloadRate->value(), ui.totalUploadRate->value() ); - load(); + rsConfig->SetMaxDataRates( ui.totalDownloadRate->value(), ui.totalUploadRate->value() ); + load(); } + void ServerPage::updateOutProxyIndicator() { QTcpSocket socket ; - // Tor - socket.connectToHost(ui.hiddenpage_proxyAddress_tor->text(),ui.hiddenpage_proxyPort_tor->text().toInt()); + // Tor + socket.connectToHost(ui.hiddenpage_proxyAddress_tor->text(),ui.hiddenpage_proxyPort_tor->text().toInt()); if(socket.waitForConnected(500)) { socket.disconnectFromHost(); @@ -1166,19 +1177,33 @@ void ServerPage::updateOutProxyIndicator() ui.iconlabel_tor_outgoing->setToolTip(tr("Tor proxy is not enabled")) ; } - // I2P - socket.connectToHost(ui.hiddenpage_proxyAddress_i2p->text(),ui.hiddenpage_proxyPort_i2p->text().toInt()); - if(socket.waitForConnected(500)) - { - socket.disconnectFromHost(); - ui.iconlabel_i2p_outgoing->setPixmap(QPixmap(ICON_STATUS_OK)) ; - ui.iconlabel_i2p_outgoing->setToolTip(tr("Proxy seems to work.")) ; - } - else - { - ui.iconlabel_i2p_outgoing->setPixmap(QPixmap(ICON_STATUS_UNKNOWN)) ; - ui.iconlabel_i2p_outgoing->setToolTip(tr("I2P proxy is not enabled")) ; - } + // I2P + socket.connectToHost(ui.hiddenpage_proxyAddress_i2p->text(),ui.hiddenpage_proxyPort_i2p->text().toInt()); + if(socket.waitForConnected(500)) + { + socket.disconnectFromHost(); + ui.iconlabel_i2p_outgoing->setPixmap(QPixmap(ICON_STATUS_OK)) ; + ui.iconlabel_i2p_outgoing->setToolTip(tr("Proxy seems to work.")) ; + } + else + { + ui.iconlabel_i2p_outgoing->setPixmap(QPixmap(ICON_STATUS_UNKNOWN)) ; + ui.iconlabel_i2p_outgoing->setToolTip(tr("I2P proxy is not enabled")) ; + } + + // I2P - BOB + socket.connectToHost(ui.hiddenpage_proxyAddress_i2p_2->text(), 2827); + if(true == (mBobAccessible = socket.waitForConnected(500))) + { + socket.disconnectFromHost(); + ui.iconlabel_i2p_outgoing_2->setPixmap(QPixmap(ICON_STATUS_OK)) ; + ui.iconlabel_i2p_outgoing_2->setToolTip(tr("BOB is running and accessible")) ; + } + else + { + ui.iconlabel_i2p_outgoing_2->setPixmap(QPixmap(ICON_STATUS_UNKNOWN)) ; + ui.iconlabel_i2p_outgoing_2->setToolTip(tr("BOB is not accessible! Is it running?")) ; + } } void ServerPage::updateInProxyIndicator() @@ -1188,65 +1213,522 @@ void ServerPage::updateInProxyIndicator() if(!mIsHiddenNode) return ; - if(manager == NULL) + //ui.iconlabel_tor_incoming->setPixmap(QPixmap(ICON_STATUS_UNKNOWN)) ; + //ui.testIncomingTor_PB->setIcon(QIcon(":/loader/circleball-16.gif")) ; + QMovie *movie = new QMovie(":/images/loader/circleball-16.gif"); + ui.iconlabel_service_incoming->setMovie(movie); + movie->start(); + + if (mHiddenType == RS_HIDDEN_TYPE_I2P && mBobSettings.enableBob) { + + QTcpSocket tcpSocket; + + const QString host = ui.hiddenpage_proxyAddress_i2p->text(); + qint16 port = ui.hiddenpage_proxyPort_i2p->text().toInt(); + QByteArray addr = ui.leBobB32Addr->text().toUtf8(); + addr.push_back('\n'); + + mOngoingConnectivityCheck = 5; // timeout in sec + + tcpSocket.connectToHost(host, port); + tcpSocket.write(addr); // write addr + tcpSocket.write(addr); // trigger connection error since RS expects a tls connection + tcpSocket.close(); + tcpSocket.waitForDisconnected(5 * 1000); + + return; + } + + if(manager == NULL) { manager = new QNetworkAccessManager(this); + connect(manager, SIGNAL(finished(QNetworkReply*)),this,SLOT(handleNetworkReply(QNetworkReply*))) ; + } QNetworkProxy proxy ; proxy.setType(QNetworkProxy::Socks5Proxy); - switch (mHiddenType) { - case RS_HIDDEN_TYPE_I2P: - proxy.setHostName(ui.hiddenpage_proxyAddress_i2p->text()); - proxy.setPort(ui.hiddenpage_proxyPort_i2p->text().toInt()); - break; - case RS_HIDDEN_TYPE_TOR: - proxy.setHostName(ui.hiddenpage_proxyAddress_tor->text()); - proxy.setPort(ui.hiddenpage_proxyPort_tor->text().toInt()); - break; - default: - return; - } + switch (mHiddenType) { + case RS_HIDDEN_TYPE_I2P: + proxy.setHostName(ui.hiddenpage_proxyAddress_i2p->text()); + proxy.setPort(ui.hiddenpage_proxyPort_i2p->text().toInt()); + break; + case RS_HIDDEN_TYPE_TOR: + proxy.setHostName(ui.hiddenpage_proxyAddress_tor->text()); + proxy.setPort(ui.hiddenpage_proxyPort_tor->text().toInt()); + break; + default: + return; + } proxy.setCapabilities(QNetworkProxy::HostNameLookupCapability | proxy.capabilities()) ; - //ui.iconlabel_tor_incoming->setPixmap(QPixmap(ICON_STATUS_UNKNOWN)) ; - //ui.testIncomingTor_PB->setIcon(QIcon(":/loader/circleball-16.gif")) ; - QMovie *movie = new QMovie(":/images/loader/circleball-16.gif"); - ui.iconlabel_service_incoming->setMovie(movie); - movie->start() ; - QNetworkProxy::setApplicationProxy(proxy) ; - QUrl url("https://"+ui.hiddenpage_serviceAddress->text() + ":" + ui.hiddenpage_servicePort->text()) ; + QUrl url("https://"+ui.hiddenpage_serviceAddress->text() + ":" + ui.hiddenpage_servicePort->text()); - std::cerr << "Setting proxy hostname+port to " << std::dec << ui.hiddenpage_proxyAddress_tor->text().toStdString() << ":" << ui.hiddenpage_proxyPort_tor->text().toInt() << std::endl; + std::cerr << "Setting proxy hostname+port to " << std::dec << ui.hiddenpage_proxyAddress_tor->text().toStdString() << ":" << ui.hiddenpage_proxyPort_tor->text().toInt() << std::endl; std::cerr << "Connecting to " << url.toString().toStdString() << std::endl; - connect(manager, SIGNAL(finished(QNetworkReply*)),this,SLOT(handleNetworkReply(QNetworkReply*))) ; manager->get( QNetworkRequest(url) ) ; QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy) ; } +void ServerPage::startBOB() +{ + rsAutoProxyMonitor::taskAsync(autoProxyType::I2PBOB, autoProxyTask::start); + + updateStatus(); +} + +void ServerPage::restartBOB() +{ + rsAutoProxyMonitor::taskAsync(autoProxyType::I2PBOB, autoProxyTask::stop); + rsAutoProxyMonitor::taskAsync(autoProxyType::I2PBOB, autoProxyTask::start); + + updateStatus(); +} + +void ServerPage::stopBOB() +{ + rsAutoProxyMonitor::taskAsync(autoProxyType::I2PBOB, autoProxyTask::stop); + + updateStatus(); +} + +void ServerPage::getNewKey() +{ + bobSettings *bs = new bobSettings(); + + rsAutoProxyMonitor::taskAsync(autoProxyType::I2PBOB, autoProxyTask::receiveKey, this, bs); + + updateStatus(); +} + +void ServerPage::loadKey() +{ + mBobSettings.keys = ui.pteBobServerKey->toPlainText().toStdString(); + mBobSettings.addr = p3I2pBob::keyToBase32Addr(mBobSettings.keys); + + rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings); +} + +void ServerPage::enableBob(bool checked) +{ + mBobSettings.enableBob = checked; + + rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings); + + setUpBobElements(); +} + +int8_t fitRange(int i, int min, int max) { + if (i < min) + i = min; + else if (i > max) + i = max; + + return (int8_t)i; +} + +void ServerPage::tunnelSettingsChanged(int) +{ + int li, lo, qi, qo, vi, vo; + li = ui.sbBobLengthIn->value(); + lo = ui.sbBobLengthOut->value(); + qi = ui.sbBobQuantityIn->value(); + qo = ui.sbBobQuantityOut->value(); + vi = ui.sbBobVarianceIn->value(); + vo = ui.sbBobVarianceOut->value(); + + mBobSettings.inLength = fitRange(li, 0, 7); + mBobSettings.outLength = fitRange(lo, 0, 7); + mBobSettings.inQuantity = fitRange(qi, 1, 16); + mBobSettings.outQuantity = fitRange(qo, 1, 16); + mBobSettings.inVariance = fitRange(vi, -1, 2); + mBobSettings.outVariance = fitRange(vo, -1, 2); + + rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings); +} + +void ServerPage::toggleBobAdvancedSettings(bool checked) +{ + ui.swBobAdvanced->setCurrentIndex(checked ? 1 : 0); + + if (!mBobSettings.keys.empty()) { + if (checked) { + ui.pbBobGenAddr->show(); + } else { + ui.pbBobGenAddr->hide(); + } + } +} + +void ServerPage::syncI2PProxyPortNormal(int i) +{ + ui.hiddenpage_proxyPort_i2p_2->setValue(i); +} + +void ServerPage::syncI2PProxyPortBob(int i) +{ + ui.hiddenpage_proxyPort_i2p->setValue(i); + + // update port + saveBob(); + rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::reloadConfig); +} + +void ServerPage::syncI2PProxyAddrNormal(QString t) +{ + ui.hiddenpage_proxyAddress_i2p_2->setText(t); +} + +void ServerPage::syncI2PProxyAddrBob(QString t) +{ + ui.hiddenpage_proxyAddress_i2p->setText(t); + + // update addr + saveBob(); + rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::reloadConfig); +} + +void ServerPage::taskFinished(taskTicket *&ticket) +{ + if (ticket->task == autoProxyTask::receiveKey) { + bobSettings *s = NULL; + switch (ticket->types.front()) { + case autoProxyType::I2PBOB: + // update settings + s = (struct bobSettings *)ticket->data; + mBobSettings = *s; + delete s; + s = NULL; + ticket->data = NULL; + break; + default: + break; + } + } + + if (ticket->data) + std::cerr << "(WW) ServerPage::taskFinished data set. This should NOT happen - check the code!" << std::endl; + + delete ticket; + ticket = NULL; +} + +void ServerPage::connectionWithoutCert() +{ + if (mOngoingConnectivityCheck > 0) { + mOngoingConnectivityCheck = -1; + updateInProxyIndicatorResult(true); + } +} + +void ServerPage::loadCommon() +{ + /* HIDDEN PAGE SETTINGS - only Proxy (outgoing) */ + /* out proxy settings */ + std::string proxyaddr; + uint16_t proxyport; + uint32_t status ; + + // Tor + rsPeers->getProxyServer(RS_HIDDEN_TYPE_TOR, proxyaddr, proxyport, status); + whileBlocking(ui.hiddenpage_proxyAddress_tor)->setText(QString::fromStdString(proxyaddr)); + whileBlocking(ui.hiddenpage_proxyPort_tor)->setValue(proxyport); + + // I2P + rsPeers->getProxyServer(RS_HIDDEN_TYPE_I2P, proxyaddr, proxyport, status); + whileBlocking(ui.hiddenpage_proxyAddress_i2p) -> setText(QString::fromStdString(proxyaddr)); + whileBlocking(ui.hiddenpage_proxyAddress_i2p_2)->setText(QString::fromStdString(proxyaddr)); // this one is for bob tab + whileBlocking(ui.hiddenpage_proxyPort_i2p) -> setValue(proxyport); + whileBlocking(ui.hiddenpage_proxyPort_i2p_2)->setValue(proxyport); // this one is for bob tab + + updateOutProxyIndicator(); + + // don't use whileBlocking here + ui.cb_enableBob->setChecked(mBobSettings.enableBob); + + if (!mBobSettings.keys.empty()) { + ui.lBobB32Addr->show(); + ui.leBobB32Addr->show(); + } +} + +void ServerPage::saveCommon() +{ + // HANDLE PROXY SERVER. + std::string orig_proxyaddr, new_proxyaddr; + uint16_t orig_proxyport, new_proxyport; + uint32_t status ; + // Tor + rsPeers->getProxyServer(RS_HIDDEN_TYPE_TOR, orig_proxyaddr, orig_proxyport, status); + + new_proxyaddr = ui.hiddenpage_proxyAddress_tor -> text().toStdString(); + new_proxyport = ui.hiddenpage_proxyPort_tor -> value(); + + if ((new_proxyaddr != orig_proxyaddr) || (new_proxyport != orig_proxyport)) { + rsPeers->setProxyServer(RS_HIDDEN_TYPE_TOR, new_proxyaddr, new_proxyport); + } + + saveBob(); +} + +void ServerPage::saveBob() +{ + std::string orig_proxyaddr, new_proxyaddr; + uint16_t orig_proxyport, new_proxyport; + uint32_t status; + // I2P + rsPeers->getProxyServer(RS_HIDDEN_TYPE_I2P, orig_proxyaddr, orig_proxyport, status); + + new_proxyaddr = ui.hiddenpage_proxyAddress_i2p -> text().toStdString(); + new_proxyport = ui.hiddenpage_proxyPort_i2p -> value(); + + if ((new_proxyaddr != orig_proxyaddr) || (new_proxyport != orig_proxyport)) { + rsPeers->setProxyServer(RS_HIDDEN_TYPE_I2P, new_proxyaddr, new_proxyport); + } +} + +void ServerPage::updateStatusBob() +{ + QString addr = QString::fromStdString(mBobSettings.addr); + if (ui.leBobB32Addr->text() != addr) { + ui.leBobB32Addr->setText(addr); + ui.hiddenpage_serviceAddress->setText(addr); + ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.keys)); + + ui.hiddenpage_serviceAddress->setText(addr); + + if (!mBobSettings.keys.empty()) { + // we have an addr -> show fields + ui.lBobB32Addr->show(); + ui.leBobB32Addr->show(); + + if (ui.cbBobAdvanced->checkState() == Qt::Checked) { + ui.pbBobGenAddr->show(); + } else { + ui.pbBobGenAddr->hide(); + } + } else { + // we don't have an addr -> hide fields + ui.lBobB32Addr->hide(); + ui.leBobB32Addr->hide(); + ui.pbBobGenAddr->hide(); + } + } + + bobStates bs; + rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::status, &bs); + + QString bobSimpleText = QString(); + bobSimpleText.append(tr("RetroShare uses BOB to set up a %1 tunnel at %2:%3 (named %4)\n\n" + "When changing options (e.g. port) use the buttons at the bottom to restart BOB.\n\n"). + arg(mBobSettings.keys.empty() ? tr("client") : tr("server"), + ui.hiddenpage_proxyAddress_i2p_2->text(), + ui.hiddenpage_proxyPort_i2p_2->text(), + bs.tunnelName.empty() ? tr("unknown") : + QString::fromStdString(bs.tunnelName))); + + // update BOB UI based on state + std::string errorString; + switch (bs.cs) { + case csDoConnect: + case csConnected: + case csDoDisconnect: + case csWaitForBob: + ui.iconlabel_i2p_bob->setPixmap(QPixmap(ICON_STATUS_WORKING)); + ui.iconlabel_i2p_bob->setToolTip(tr("BOB is processing a request")); + + enableBobElements(false); + + { + QString s; + switch (bs.ct) { + case ctRunCheck: + s = tr("connectivity check"); + break; + case ctRunGetKeys: + s = tr("generating key"); + break; + case ctRunSetUp: + s = tr("starting up"); + break; + case ctRunShutDown: + s = tr("shuting down"); + default: + break; + } + bobSimpleText.append(tr("BOB is processing a request: %1").arg(s)); + } + + ui.pbBobStart->setEnabled(false); + ui.pbBobRestart->setEnabled(false); + ui.pbBobStop->setEnabled(false); + break; + case csError: + // get error msg from bob + rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::getErrorInfo, &errorString); + + ui.iconlabel_i2p_bob->setPixmap(QPixmap(ICON_STATUS_ERROR)); + ui.iconlabel_i2p_bob->setToolTip(tr("BOB is broken\n") + QString::fromStdString(errorString)); + + enableBobElements(false); + + bobSimpleText.append(tr("BOB encountered an error:\n")); + bobSimpleText.append(QString::fromStdString(errorString)); + + ui.pbBobStart->setEnabled(true); + ui.pbBobRestart->setEnabled(false); + ui.pbBobStop->setEnabled(true); + break; + case csDisconnected: + case csIdel: + switch (bs.ct) { + case ctRunSetUp: + ui.iconlabel_i2p_bob->setPixmap(QPixmap(ICON_STATUS_OK)); + ui.iconlabel_i2p_bob->setToolTip(tr("BOB tunnel is running")); + + enableBobElements(false); + + bobSimpleText.append(tr("BOB is working fine: tunnel established")); + + ui.pbBobStart->setEnabled(false); + ui.pbBobRestart->setEnabled(true); + ui.pbBobStop->setEnabled(true); + break; + case ctRunCheck: + case ctRunGetKeys: + ui.iconlabel_i2p_bob->setPixmap(QPixmap(ICON_STATUS_WORKING)); + ui.iconlabel_i2p_bob->setToolTip(tr("BOB is processing a request")); + + enableBobElements(false); + + bobSimpleText.append(tr("BOB is processing a request")); + + ui.pbBobStart->setEnabled(false); + ui.pbBobRestart->setEnabled(false); + ui.pbBobStop->setEnabled(false); + break; + case ctRunShutDown: + case ctIdle: + ui.iconlabel_i2p_bob->setPixmap(QPixmap(ICON_STATUS_UNKNOWN)); + ui.iconlabel_i2p_bob->setToolTip(tr("BOB tunnel is not running")); + + enableBobElements(true); + + bobSimpleText.append(tr("BOB is inactive: tunnel closed")); + + ui.pbBobStart->setEnabled(true); + ui.pbBobRestart->setEnabled(false); + ui.pbBobStop->setEnabled(false); + break; + } + break; + + } + ui.pteBobSimple->setPlainText(bobSimpleText); + + // disable elements when BOB is not accessible + if (!mBobAccessible) { + ui.pbBobStart->setEnabled(false); + ui.pbBobStart->setToolTip("BOB is not accessible"); + ui.pbBobRestart->setEnabled(false); + ui.pbBobRestart->setToolTip("BOB is not accessible"); + ui.pbBobStop->setEnabled(false); + ui.pbBobStop->setToolTip("BOB is not accessible"); + } else { + ui.pbBobStart->setToolTip(""); + ui.pbBobRestart->setToolTip(""); + ui.pbBobStop->setToolTip(""); + } +} + +void ServerPage::setUpBobElements() +{ + ui.gbBob->setEnabled(mBobSettings.enableBob); + if (mBobSettings.enableBob) { + ui.hiddenpage_proxyAddress_i2p->setEnabled(false); + ui.hiddenpage_proxyAddress_i2p->setToolTip("Use I2P/BOB settings to change this value"); + ui.hiddenpage_proxyPort_i2p->setEnabled(false); + ui.hiddenpage_proxyPort_i2p->setToolTip("Use I2P/BOB settings to change this value"); + + ui.leBobB32Addr->setText(QString::fromStdString(mBobSettings.addr)); + ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.keys)); + + // cast to int to avoid problems + int li, lo, qi, qo, vi, vo; + li = mBobSettings.inLength; + lo = mBobSettings.outLength; + qi = mBobSettings.inQuantity; + qo = mBobSettings.outQuantity; + vi = mBobSettings.inVariance; + vo = mBobSettings.outVariance; + + ui.sbBobLengthIn ->setValue(li); + ui.sbBobLengthOut ->setValue(lo); + ui.sbBobQuantityIn ->setValue(qi); + ui.sbBobQuantityOut->setValue(qo); + ui.sbBobVarianceIn ->setValue(vi); + ui.sbBobVarianceOut->setValue(vo); + } else { + ui.hiddenpage_proxyAddress_i2p->setEnabled(true); + ui.hiddenpage_proxyAddress_i2p->setToolTip(QString()); + ui.hiddenpage_proxyPort_i2p->setEnabled(true); + ui.hiddenpage_proxyPort_i2p->setToolTip(QString()); + } +} + +void ServerPage::enableBobElements(bool enable) +{ + if (enable) { + ui.pbBobGenAddr->setEnabled(true); + ui.pbBobGenAddr->setToolTip(tr("request a new server key")); + + ui.pbBobLoadKey->setEnabled(true); + ui.pbBobLoadKey->setToolTip(tr("load server key from base64")); + + ui.cb_enableBob->setEnabled(true); + ui.cb_enableBob->setToolTip(tr("")); + } else { + ui.pbBobGenAddr->setEnabled(false); + ui.pbBobGenAddr->setToolTip(tr("stop BOB tunnel first to generate a new key")); + + ui.pbBobLoadKey->setEnabled(false); + ui.pbBobLoadKey->setToolTip(tr("stop BOB tunnel first to load a key")); + + ui.cb_enableBob->setEnabled(false); + ui.cb_enableBob->setToolTip(tr("stop BOB tunnel first to disable BOB")); + } +} + +void ServerPage::updateInProxyIndicatorResult(bool success) +{ + if (success) { + std::cerr <<"Connected!" << std::endl; + + ui.iconlabel_service_incoming->setPixmap(QPixmap(ICON_STATUS_OK)) ; + ui.iconlabel_service_incoming->setToolTip(tr("You are reachable through the hidden service.")) ; + //ui.testIncomingTor_PB->setIcon(QIcon(ICON_STATUS_OK)) ; + } else { + std::cerr <<"Failed!" << std::endl; + + //ui.testIncomingTor_PB->setIcon(QIcon(ICON_STATUS_UNKNOWN)) ; + ui.iconlabel_service_incoming->setPixmap(QPixmap(ICON_STATUS_UNKNOWN)) ; + ui.iconlabel_service_incoming->setToolTip(tr("The proxy is not enabled or broken.\nAre all services up and running fine??\nAlso check your ports!")) ; + } + // delete movie + delete ui.iconlabel_service_incoming->movie(); +} + void ServerPage::handleNetworkReply(QNetworkReply *reply) { int error = reply->error() ; if(reply->isOpen() && error == QNetworkReply::SslHandshakeFailedError) - { - std::cerr <<"Connected!" << std::endl; - ui.iconlabel_service_incoming->setPixmap(QPixmap(ICON_STATUS_OK)) ; - ui.iconlabel_service_incoming->setToolTip(tr("You are reachable through the hidden service.")) ; - //ui.testIncomingTor_PB->setIcon(QIcon(ICON_STATUS_OK)) ; - } + updateInProxyIndicatorResult(true); else - { - std::cerr <<"Failed!" << std::endl; - - //ui.testIncomingTor_PB->setIcon(QIcon(ICON_STATUS_UNKNOWN)) ; - ui.iconlabel_service_incoming->setPixmap(QPixmap(ICON_STATUS_UNKNOWN)) ; - ui.iconlabel_service_incoming->setToolTip(tr("The proxy is not enabled or broken.\nAre all services up and running fine??\nAlso check your ports!")) ; - } + updateInProxyIndicatorResult(false); reply->close(); } - diff --git a/retroshare-gui/src/gui/settings/ServerPage.h b/retroshare-gui/src/gui/settings/ServerPage.h index 5b300e084..767c45cf8 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.h +++ b/retroshare-gui/src/gui/settings/ServerPage.h @@ -22,9 +22,8 @@ #ifndef SERVERPAGE_H #define SERVERPAGE_H -#include #include "ui_ServerPage.h" -#include "RsAutoUpdatePage.h" + #include /* get OS-specific definitions for: * struct sockaddr_storage @@ -35,11 +34,18 @@ #include #endif +#include +#include + +#include +#include + + class QNetworkReply; class QNetworkAccessManager; class BanListPeer; -class ServerPage: public ConfigPage +class ServerPage: public ConfigPage, public autoProxyCallback { Q_OBJECT @@ -89,7 +95,40 @@ private slots: void handleNetworkReply(QNetworkReply *reply); void updateInProxyIndicator(); + // i2p bob + void startBOB(); + void restartBOB(); + void stopBOB(); + void getNewKey(); + void loadKey(); + void enableBob(bool checked); + void tunnelSettingsChanged(int); + + void toggleBobAdvancedSettings(bool checked); + + void syncI2PProxyPortNormal(int i); + void syncI2PProxyPortBob(int i); + + void syncI2PProxyAddrNormal(QString); + void syncI2PProxyAddrBob(QString); + + void connectionWithoutCert(); + + // autoProxyCallback interface +public: + void taskFinished(taskTicket *&ticket); + private: + void loadCommon(); + void saveCommon(); + void saveBob(); + void updateStatusBob(); + + void setUpBobElements(); + void enableBobElements(bool enable); + + void updateInProxyIndicatorResult(bool success); + // ban list void addPeerToIPTable(QTableWidget *table, int row, const BanListPeer &blp); bool removeCurrentRowFromBlackList(sockaddr_storage& collected_addr,int& masked_bytes); @@ -105,9 +144,12 @@ private: Ui::ServerPage ui; QNetworkAccessManager *manager ; + int mOngoingConnectivityCheck; - bool mIsHiddenNode; + bool mIsHiddenNode; uint32_t mHiddenType; + bobSettings mBobSettings; + bool mBobAccessible; // keeps track wether bob is accessable or not to en/disable the corresponding buttons }; #endif // !SERVERPAGE_H diff --git a/retroshare-gui/src/gui/settings/ServerPage.ui b/retroshare-gui/src/gui/settings/ServerPage.ui index 921e5b7df..59ee31a8e 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.ui +++ b/retroshare-gui/src/gui/settings/ServerPage.ui @@ -811,333 +811,838 @@ behind a firewall or a VPN. Hidden Service Configuration - + - - - Outgoing Connections + + + + 0 + 0 + - - - - - - - - - Tor Socks Proxy - - - - - - - - - - <html><head/><body><p>This is the port of the Tor Socks proxy. Your Retroshare node can use this port to connect to</p><p>Hidden nodes. The led at right turns green when this port is active on your computer. </p><p>This does not mean however that your Retroshare traffic transits though Tor. It does only if </p><p>you connect to Hidden nodes, or if you are running a Hidden node yourself.</p></body></html> - - - 1024 - - - 65535 - - - - - - - - - - - - 16 - 16 - - - - - - - :/images/ledoff1.png - - - - - - - <html><head/><body><p>The led on the left is green when the listening port is active on your computer. It does not</p><p>mean that your Retroshare traffic transits though Tor. It will do so only if </p><p>you connect to Hidden nodes, or if you are running a Hidden node yourself.</p></body></html> - - - Tor outgoing Okay - - - - - - - - - - - 0 - - - 0 - - - - - - - I2P Socks Proxy - - - - - - - - - - <html><head/><body><p>This is the port of the I2P Socks proxy. Your Retroshare node can use this port to connect to</p><p>Hidden nodes. The led at right turns green when this port is active on your computer. </p><p>This does not mean however that your Retroshare traffic transits though I2P. It does only if </p><p>you connect to Hidden nodes, or if you are running a Hidden node yourself.</p></body></html> - - - 1024 - - - 65535 - - - - - - - - - - - - - - :/images/ledoff1.png - - - - - - - <html><head/><body><p>The led on the left is green when the listening port is active on your computer. It does not</p><p>mean that your Retroshare traffic transits though I2P. It will do so only if </p><p>you connect to Hidden nodes, or if you are running a Hidden node yourself.</p></body></html> - - - I2P outgoing Okay - - - - - - - - - - - - 16777215 - 145 - - - - Qt::ScrollBarAsNeeded - - - true - - - Tor Socks Proxy default: 127.0.0.1:9050. Set in torrc config and update here. + + 0 + + + + Outgoing Manual Tor/I2P + + + + + + <html><head/><body><p>Outgoing Connctions</p><p>Configure your Tor and I2P SOCKS proxy here. <br/>If you prefer to use BOB to automatically manage I2P check the other tab.</p></body></html> + + + + + + + + + <html><head/><body><p>This is the port of the Tor Socks proxy. Your Retroshare node can use this port to connect to</p><p>Hidden nodes. The led at right turns green when this port is active on your computer. </p><p>This does not mean however that your Retroshare traffic transits though Tor. It does only if </p><p>you connect to Hidden nodes, or if you are running a Hidden node yourself.</p></body></html> + + + 10 + + + 65535 + + + + + + + + + + Tor Socks Proxy + + + + + + + + + + 16 + 16 + + + + + + + :/images/ledoff1.png + + + + + + + <html><head/><body><p>This led is green when the port listen on the left is active on your computer. It does not</p><p>mean that your Retroshare traffic transits though Tor. It will do so only if </p><p>you connect to Hidden nodes, or if you are running a Hidden node yourself.</p></body></html> + + + Tor outgoing Okay + + + + + + + + + I2P Socks Proxy + + + + + + + + 0 + 0 + + + + + + + + <html><head/><body><p>This is the port of the I2P Socks proxy. Your Retroshare node can use this port to connect to</p><p>Hidden nodes. The led at right turns green when this port is active on your computer. </p><p>This does not mean however that your Retroshare traffic transits though I2P. It does only if </p><p>you connect to Hidden nodes, or if you are running a Hidden node yourself.</p></body></html> + + + 10 + + + 65535 + + + + + + + + + + + + :/images/ledoff1.png + + + + + + + <html><head/><body><p>This led is green when the port listen on the left is active on your computer. It does not</p><p>mean that your Retroshare traffic transits though I2P. It will do so only if </p><p>you connect to Hidden nodes, or if you are running a Hidden node yourself.</p></body></html> + + + I2P outgoing Okay + + + + + + + + + + + + 0 + 0 + + + + + 16777215 + 190 + + + + Qt::ScrollBarAsNeeded + + + true + + + Tor Socks Proxy default: 127.0.0.1:9050. Set in torrc config and update here. I2P Socks Proxy: see http://127.0.0.1:7657/i2ptunnelmgr for setting up a client tunnel: Tunnel Wizard -> Client Tunnel -> SOCKS 4/4a/5 -> enter a name -> leave 'Outproxies' empty -> enter port (memorize!) [you may also want to set the reachability to 127.0.0.1] -> Next -> check 'Auto Start' -> finish! Now enter the address (e.g. 127.0.0.1) and the port you've picked before for the I2P Proxy. You can connect to Hidden Nodes, even if you are running a standard Node, so why not setup Tor and/or I2P? - - - - - - - - - - - 0 - 0 - - - - Incoming Service Connections - - - - - - - - 1024 - - - 65535 - - - - - + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Automatic I2P/BOB + + + + + + + + Enable I2P BOB - changing this requires a restart to fully take effect + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + enableds advanced settings + + + advanced mode + + + + + + + + + I2P Basic Open Bridge + + - - - <html><head/><body><p>This button simulates a SSL connection to your hidden address using the corresponding proxy. If your hidden node is reachable, it should cause a SSL handshake error, which RS will interpret as a valid connection state. This operation might also cause several &quot;security warning&quot; about connections from your local host IP (127.0.0.1) in the News Feed if you enabled it, which you should interpret as a sign of good communication.</p></body></html> + + + 0 - - Apply + + 0 + + + + + + I2P Instance address + + + + + + + + 0 + 0 + + + + 127.0.0.1 + + + + + + + I2P proxy port + + + + + + + 10 + + + 65535 + + + + + + + + + + + + :/images/ledoff1.png + + + + + + + <html><head/><body><p>This led is green when the port listen on the left is active on your computer. It does not</p><p>mean that your Retroshare traffic transits though I2P. It will do so only if </p><p>you connect to Hidden nodes, or if you are running a Hidden node yourself.</p></body></html> + + + BOB accessible + + + + + + + + + + + + + + + + 0 + 0 + + + + Address + + + + + + + + 0 + 0 + + + + .b32.i2p + + + + + + + + 0 + 0 + + + + generate new + + + + + + + + + true + + + 0 + + + + + + + + 0 + 0 + + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + Tunnel length (in/out) + + + + + + + + 0 + 0 + + + + 7 + + + 3 + + + + + + + + 0 + 0 + + + + 7 + + + 3 + + + + + + + + + + + Tunnel quantity (in/out) + + + + + + + + 0 + 0 + + + + 1 + + + 16 + + + 3 + + + + + + + + 0 + 0 + + + + 1 + + + 16 + + + 3 + + + + + + + + + + + Tunnel variance (in/out) + + + + + + + + 0 + 0 + + + + -1 + + + 2 + + + 0 + + + + + + + + 0 + 0 + + + + -1 + + + 2 + + + + + + + + + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Server Key - When a key it set it will be used to setup a hidden<br/>service for I2P. Otherwise only a client tunnel is created.</p></body></html> + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + load key + + + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Start + + + + + + + Restart + + + + + + + Stop + + + + + + + + + + :/images/ledoff1.png + + + + + + + BOB status + + + + + - - - - - 1024 - - - 65535 - - - - - - - Service Address - - - - - - - Local Address - - - - - - - <html><head/><body><p>This is your hidden address. It should look like <span style=" font-weight:600;">[something].onion</span> or <span style=" font-weight:600;">[something].b32.i2p. </span>If you configured a hidden service with Tor, the onion address is generated automatically by Tor. You can get it in e.g. <span style=" font-weight:600;">/var/lib/tor/[service name]/hostname</span>. For I2P: Setup a server tunnel ( http://127.0.0.1:7657/i2ptunnelmgr ) and copy it's base32 address when it is started (should end with .b32.i2p)</p></body></html> - - - - - - - <html><head/><body><p>This is the local address to which the hidden service points at your localhost. Most of the time, <span style=" font-weight:600;">127.0.0.1</span> is the right answer.</p></body></html> - - - - - - - - - - 16 - 16 - - - - - - - :/images/ledoff1.png - - - - - - - <html><head/><body><p>This led turns green only if you launch an active test using the above button. </p><p>When it does, it means that your hidden node can be reached from anywhere, using the Tor (resp. I2P) </p><p>network. Congratulations!</p></body></html> - - - incoming ok - - - - - - - - - - - - - Expected Configuration: - - - - - - - - 0 - 0 - - - - - 0 - 10 - - - - - 16777215 - 50 - - - - Qt::ScrollBarAlwaysOff - - - true - - - Please fill in a service address - - - - - - - - - - 0 - 0 - - - - - 16777215 - 100 - - - - true - - - To Receive Connections, you must first setup a Tor/I2P Hidden Service. + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Incoming + + + + + + <html><head/><body><p>Incoming Connection</p><p>Setup your hidden address (and port if needed)</p></body></html> + + + + + + + + + 10 + + + 65535 + + + + + + + + + <html><head/><body><p>This button simulates a SSL connection to your hidden address using the corresponding proxy. If your hidden node is reachable, it should cause a SSL handshake error, which RS will interpret as a valid connection state. This operation might also cause several &quot;security warning&quot; about connections from your local host IP (127.0.0.1) in the News Feed if you enabled it, which you should interpret as a sign of good communication.</p></body></html> + + + Test + + + + + + + + + 10 + + + 65535 + + + + + + + Service Address + + + + + + + Local Address + + + + + + + <html><head/><body><p>This is your hidden address. It should look like <span style=" font-weight:600;">[something].onion</span> or <span style=" font-weight:600;">[something].b32.i2p. </span>If you configured a hidden service with Tor, the onion address is generated automatically by Tor. You can get it in e.g. <span style=" font-weight:600;">/var/lib/tor/[service name]/hostname</span>. For I2P: Setup a server tunnel ( http://127.0.0.1:7657/i2ptunnelmgr ) and copy it's base32 address when it is started (should end with .b32.i2p)</p></body></html> + + + + + + + <html><head/><body><p>This is the local address to which the hidden service points at your localhost. Most of the time, <span style=" font-weight:600;">127.0.0.1</span> is the right answer.</p></body></html> + + + + + + + + + + 16 + 16 + + + + + + + :/images/ledoff1.png + + + + + + + <html><head/><body><p>This led turns green only if you launch an active test using the above button. </p><p>When it does, it means that your hidden node can be reached from anywhere, using the Tor (resp. I2P) </p><p>network. Congratulations!</p></body></html> + + + incoming ok + + + + + + + + + + + + + Expected Configuration: + + + + + + + + 0 + 0 + + + + + 0 + 10 + + + + + 16777215 + 50 + + + + Qt::ScrollBarAlwaysOff + + + true + + + Please fill in a service address + + + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + true + + + To Receive Connections, you must first setup a Tor/I2P Hidden Service. + For Tor: See torrc and documentation for HOWTO details. + For I2P: See http://127.0.0.1:7657/i2ptunnelmgr for setting up a server tunnel: Tunnel Wizard -> Server Tunnel -> Standard -> enter a name -> enter the address and port your RS is using (see Local Address above) -> check 'Auto Start' -> finish! @@ -1146,25 +1651,26 @@ This is your external address on the Tor/I2P network. Finally make sure that the Ports match the configuration. If you have issues connecting over Tor check the Tor logs too. - - - - + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + - - - - Qt::Vertical - - - - 20 - 18 - - - -