/******************************************************************************* * libretroshare/src/pqi: p3peermgr.cc * * * * libretroshare: retroshare core library * * * * Copyright (C) 2007-2011 Robert Fernie * * Copyright (C) 2015-2019 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public License * * along with this program. If not, see . * * * *******************************************************************************/ #include // for std::vector #include // for std::shuffle #include // std::default_random_engine #include // std::chrono::system_clock #include "rsserver/p3face.h" #include "util/rsnet.h" #include "pqi/authgpg.h" #include "pqi/authssl.h" #include "pqi/p3peermgr.h" #include "pqi/p3linkmgr.h" #include "pqi/p3netmgr.h" #include "pqi/p3historymgr.h" #include "pqi/pqinetwork.h" // for getLocalAddresses #include "util/rsprint.h" #include "util/rsstring.h" #include "util/rsdebug.h" #include "rsitems/rsconfigitems.h" #include "retroshare/rsiface.h" // Needed for rsicontrol (should remove this dependancy) #include "retroshare/rspeers.h" // Needed for Group Parameters. #include "retroshare/rsbanlist.h" // Needed for banned IPs /* Network setup States */ //Defined and used in /libretroshare/src/pqi/p3netmgr.cc //const uint32_t RS_NET_NEEDS_RESET = 0x0000; //const uint32_t RS_NET_UNKNOWN = 0x0001; //const uint32_t RS_NET_UPNP_INIT = 0x0002; //const uint32_t RS_NET_UPNP_SETUP = 0x0003; //const uint32_t RS_NET_EXT_SETUP = 0x0004; //const uint32_t RS_NET_DONE = 0x0005; //const uint32_t RS_NET_LOOPBACK = 0x0006; //const uint32_t RS_NET_DOWN = 0x0007; //const uint32_t MIN_TIME_BETWEEN_NET_RESET = 5; //const uint32_t PEER_IP_CONNECT_STATE_MAX_LIST_SIZE = 4; static struct RsLog::logInfo p3peermgrzoneInfo = {RsLog::Default, "p3peermgr"}; #define p3peermgrzone &p3peermgrzoneInfo /**** * #define PEER_DEBUG 1 * #define PEER_DEBUG_LOG 1 ***/ #define MAX_AVAIL_PERIOD 230 //times a peer stay in available state when not connected #define MIN_RETRY_PERIOD 140 static const std::string kConfigDefaultProxyServerIpAddr = "127.0.0.1"; static const uint16_t kConfigDefaultProxyServerPortTor = 9050; // standard port. static const uint16_t kConfigDefaultProxyServerPortI2P = 4447; // I2Pd's standard port static const std::string kConfigKeyExtIpFinder = "USE_EXTR_IP_FINDER"; static const std::string kConfigKeyProxyServerIpAddrTor = "PROXY_SERVER_IPADDR"; static const std::string kConfigKeyProxyServerPortTor = "PROXY_SERVER_PORT"; static const std::string kConfigKeyProxyServerIpAddrI2P = "PROXY_SERVER_IPADDR_I2P"; static const std::string kConfigKeyProxyServerPortI2P = "PROXY_SERVER_PORT_I2P"; void printConnectState(std::ostream &out, peerState &peer); peerState::peerState() :skip_pgp_signature_validation(false),netMode(RS_NET_MODE_UNKNOWN), vs_disc(RS_VS_DISC_FULL), vs_dht(RS_VS_DHT_FULL), lastcontact(0), hiddenNode(false), hiddenPort(0), hiddenType(RS_HIDDEN_TYPE_NONE) { sockaddr_storage_clear(localaddr); sockaddr_storage_clear(serveraddr); return; } std::string textPeerConnectState(peerState &state) { std::string out = "Id: " + state.id.toStdString() + "\n"; rs_sprintf_append(out, "NetMode: %lu\n", state.netMode); rs_sprintf_append(out, "VisState: Disc: %u Dht: %u\n", state.vs_disc, state.vs_dht); out += "laddr: "; out += sockaddr_storage_tostring(state.localaddr); out += "\neaddr: "; out += sockaddr_storage_tostring(state.serveraddr); out += "\n"; return out; } p3PeerMgrIMPL::p3PeerMgrIMPL(const RsPeerId& ssl_own_id, const RsPgpId& gpg_own_id, const std::string& gpg_own_name, const std::string& ssl_own_location) :p3Config(), mPeerMtx("p3PeerMgr"), mStatusChanged(false) { { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ mLinkMgr = NULL; mNetMgr = NULL; /* setup basics of own state */ mOwnState.id = ssl_own_id ; mOwnState.gpg_id = gpg_own_id ; mOwnState.name = gpg_own_name ; mOwnState.location = ssl_own_location ; mOwnState.netMode = RS_NET_MODE_UPNP; // Default to UPNP. mOwnState.vs_disc = RS_VS_DISC_FULL; mOwnState.vs_dht = RS_VS_DHT_FULL; // setup default ProxyServerAddress. // Tor sockaddr_storage_clear(mProxyServerAddressTor); sockaddr_storage_ipv4_aton(mProxyServerAddressTor, kConfigDefaultProxyServerIpAddr.c_str()); sockaddr_storage_ipv4_setport(mProxyServerAddressTor, kConfigDefaultProxyServerPortTor); // I2P sockaddr_storage_clear(mProxyServerAddressI2P); sockaddr_storage_ipv4_aton(mProxyServerAddressI2P, kConfigDefaultProxyServerIpAddr.c_str()); sockaddr_storage_ipv4_setport(mProxyServerAddressI2P, kConfigDefaultProxyServerPortI2P); mProxyServerStatusTor = RS_NET_PROXY_STATUS_UNKNOWN ; mProxyServerStatusI2P = RS_NET_PROXY_STATUS_UNKNOWN; // Init standard groups. const int standardGroupCount = 5; const RsNodeGroupId standardGroupIds [standardGroupCount] = { RS_GROUP_ID_FRIENDS, RS_GROUP_ID_FAMILY, RS_GROUP_ID_COWORKERS, RS_GROUP_ID_OTHERS, RS_GROUP_ID_FAVORITES }; const char *standardGroupNames[standardGroupCount] = { RS_GROUP_DEFAULT_NAME_FRIENDS, RS_GROUP_DEFAULT_NAME_FAMILY, RS_GROUP_DEFAULT_NAME_COWORKERS, RS_GROUP_DEFAULT_NAME_OTHERS, RS_GROUP_DEFAULT_NAME_FAVORITES }; for(uint32_t k=0;kOwnId(), loopback); mNetMgr->setIPServersEnabled(false); IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); /**** INDICATE MSG CONFIG CHANGED! *****/ return true; } bool p3PeerMgrIMPL::setOwnNetworkMode(uint32_t netMode) { bool changed = false; { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::setOwnNetworkMode() :"; std::cerr << " Existing netMode: " << mOwnState.netMode; std::cerr << " Input netMode: " << netMode; std::cerr << std::endl; #endif if (mOwnState.netMode != (netMode & RS_NET_MODE_ACTUAL)) { mOwnState.netMode = (netMode & RS_NET_MODE_ACTUAL); IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); /**** INDICATE MSG CONFIG CHANGED! *****/ changed = true; } } // Pass on Flags to NetMgr. mNetMgr->setNetworkMode((netMode & RS_NET_MODE_ACTUAL)); return changed; } bool p3PeerMgrIMPL::setOwnVisState(uint16_t vs_disc, uint16_t vs_dht) { bool changed = false; { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ std::string out; rs_sprintf(out, "p3PeerMgr::setOwnVisState() Existing vis: %u/%u Input vis: %u/%u", mOwnState.vs_disc, mOwnState.vs_dht, vs_disc, vs_dht); rslog(RSL_WARNING, p3peermgrzone, out); #ifdef PEER_DEBUG std::cerr << out.c_str() << std::endl; #endif if (mOwnState.vs_disc != vs_disc || mOwnState.vs_dht != vs_dht) { mOwnState.vs_disc = vs_disc; mOwnState.vs_dht = vs_dht; changed = true; IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); /**** INDICATE MSG CONFIG CHANGED! *****/ } } // Pass on Flags to NetMgr. mNetMgr->setVisState(vs_disc, vs_dht); return changed; } void p3PeerMgrIMPL::tick() { static const rstime_t INTERVAL_BETWEEN_LOCATION_CLEANING = 300 ; // Remove unused locations and clean IPs every 10 minutes. static rstime_t last_friends_check = time(NULL) ; // first cleaning after 1 hour. rstime_t now = time(NULL) ; if(now > INTERVAL_BETWEEN_LOCATION_CLEANING + last_friends_check ) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::tick(): cleaning unused locations." << std::endl ; #endif rslog(RSL_WARNING, p3peermgrzone, "p3PeerMgr::tick() removeUnusedLocations()"); removeUnusedLocations() ; #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::tick(): cleaning banned/old IPs." << std::endl ; #endif removeBannedIps() ; last_friends_check = now ; } } /******************************** Network Status ********************************* * Configuration Loading / Saving. */ const RsPeerId& p3PeerMgrIMPL::getOwnId() { return AuthSSL::getAuthSSL()->OwnId(); } bool p3PeerMgrIMPL::getOwnNetStatus(peerState &state) { RS_STACK_MUTEX(mPeerMtx); state = mOwnState; return true; } bool p3PeerMgrIMPL::isFriend(const RsPeerId& id) { #ifdef PEER_DEBUG_COMMON std::cerr << "p3PeerMgrIMPL::isFriend(" << id << ") called" << std::endl; #endif RS_STACK_MUTEX(mPeerMtx); bool ret = (mFriendList.end() != mFriendList.find(id)); #ifdef PEER_DEBUG_COMMON std::cerr << "p3PeerMgrIMPL::isFriend(" << id << ") returning : " << ret << std::endl; #endif return ret; } bool p3PeerMgrIMPL::isSslOnlyFriend(const RsPeerId& id) { #ifdef PEER_DEBUG_COMMON std::cerr << "p3PeerMgrIMPL::isFriend(" << id << ") called" << std::endl; #endif RS_STACK_MUTEX(mPeerMtx); auto it = mFriendList.find(id); bool ret = it != mFriendList.end() && it->second.skip_pgp_signature_validation ; #ifdef PEER_DEBUG_COMMON std::cerr << "p3PeerMgrIMPL::isFriend(" << id << ") returning : " << ret << std::endl; #endif return ret; } bool p3PeerMgrIMPL::getPeerName(const RsPeerId &ssl_id, std::string &name) { RS_STACK_MUTEX(mPeerMtx); /* check for existing */ std::map::iterator it; it = mFriendList.find(ssl_id); if (it == mFriendList.end()) { return false; } name = it->second.name + " (" + it->second.location + ")"; return true; } bool p3PeerMgrIMPL::getGpgId(const RsPeerId &ssl_id, RsPgpId &gpgId) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ /* check for existing */ std::map::iterator it; it = mFriendList.find(ssl_id); if (it == mFriendList.end()) { return false; } gpgId = it->second.gpg_id; return true; } /**** HIDDEN STUFF ****/ bool p3PeerMgrIMPL::isHidden() { RS_STACK_MUTEX(mPeerMtx); return mOwnState.hiddenNode; } /** * @brief checks the hidden type of the own peer. * @param type type to check * @return true when the peer has the same hidden type than type */ bool p3PeerMgrIMPL::isHidden(const uint32_t type) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ switch (type) { case RS_HIDDEN_TYPE_TOR: return mOwnState.hiddenType == RS_HIDDEN_TYPE_TOR; break; case RS_HIDDEN_TYPE_I2P: return mOwnState.hiddenType == RS_HIDDEN_TYPE_I2P; break; default: #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::isHidden(" << type << ") unkown type -> false"; std::cerr << std::endl; #endif return false; break; } } bool p3PeerMgrIMPL::isHiddenPeer(const RsPeerId &ssl_id) { return isHiddenPeer(ssl_id, RS_HIDDEN_TYPE_NONE); } /** * @brief checks the hidden type of a given ssl id. When type RS_HIDDEN_TYPE_NONE is choosen it returns the 'hiddenNode' value instead * @param ssl_id to check * @param type type to check. Use RS_HIDDEN_TYPE_NONE to check 'hiddenNode' value * @return true when the peer has the same hidden type than type */ bool p3PeerMgrIMPL::isHiddenPeer(const RsPeerId &ssl_id, const uint32_t type) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ /* check for existing */ std::map::iterator it; it = mFriendList.find(ssl_id); if (it == mFriendList.end()) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::isHiddenPeer(" << ssl_id << ") Missing Peer => false"; std::cerr << std::endl; #endif return false; } #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::isHiddenPeer(" << ssl_id << ") = " << (it->second).hiddenNode; std::cerr << std::endl; #endif switch (type) { case RS_HIDDEN_TYPE_TOR: return (it->second).hiddenType == RS_HIDDEN_TYPE_TOR; break; case RS_HIDDEN_TYPE_I2P: return (it->second).hiddenType == RS_HIDDEN_TYPE_I2P; break; default: return (it->second).hiddenNode; break; } } bool hasEnding (std::string const &fullString, std::string const &ending) { if (fullString.length() < ending.length()) return false; return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); } /** * @brief resolves the hidden type (tor or i2p) from a domain * @param domain to check * @return RS_HIDDEN_TYPE_TOR, RS_HIDDEN_TYPE_I2P or RS_HIDDEN_TYPE_NONE * * Tor: ^[a-z2-7]{16}\.onion$ * * I2P: There is more than one address: * - pub. key in base64 * - hash in base32 ( ^[a-z2-7]{52}\.b32\.i2p$ ) * - "normal" .i2p domains */ uint32_t p3PeerMgrIMPL::hiddenDomainToHiddenType(const std::string &domain) { if(hasEnding(domain, ".onion")) return RS_HIDDEN_TYPE_TOR; if(hasEnding(domain, ".i2p")) return RS_HIDDEN_TYPE_I2P; #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::hiddenDomainToHiddenType() unknown hidden type: " << domain; std::cerr << std::endl; #endif return RS_HIDDEN_TYPE_UNKNOWN; } /** * @brief returns the hidden type of a peer * @param ssl_id peer id * @return hidden type */ uint32_t p3PeerMgrIMPL::getHiddenType(const RsPeerId &ssl_id) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ if (ssl_id == AuthSSL::getAuthSSL()->OwnId()) return mOwnState.hiddenType; /* check for existing */ std::map::iterator it; it = mFriendList.find(ssl_id); if (it == mFriendList.end()) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::getHiddenType(" << ssl_id << ") Missing Peer => false"; std::cerr << std::endl; #endif return false; } #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::getHiddenType(" << ssl_id << ") = " << (it->second).hiddenType; std::cerr << std::endl; #endif return (it->second).hiddenType; } bool p3PeerMgrIMPL::isHiddenNode(const RsPeerId& id) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ if (id == AuthSSL::getAuthSSL()->OwnId()) return mOwnState.hiddenNode ; else { std::map::const_iterator it = mFriendList.find(id); if (it == mFriendList.end()) { std::cerr << "p3PeerMgrIMPL::isHiddenNode() Peer Not Found" << std::endl; return false; } return it->second.hiddenNode ; } } /** * @brief sets hidden domain and port for a given ssl ID * @param ssl_id peer to set domain and port for * @param domain_addr * @param domain_port * @return true on success */ bool p3PeerMgrIMPL::setHiddenDomainPort(const RsPeerId &ssl_id, const std::string &domain_addr, const uint16_t domain_port) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::setHiddenDomainPort()"; std::cerr << std::endl; #endif std::string domain = domain_addr; // trim whitespace! size_t pos = domain.find_last_not_of(" \t\n"); if (std::string::npos != pos) { domain = domain.substr(0, pos + 1); } pos = domain.find_first_not_of(" \t\n"); if (std::string::npos != pos) { domain = domain.substr(pos); } IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); /**** INDICATE MSG CONFIG CHANGED! *****/ if (ssl_id == AuthSSL::getAuthSSL()->OwnId()) { mOwnState.hiddenNode = true; mOwnState.hiddenDomain = domain; mOwnState.hiddenPort = domain_port; mOwnState.hiddenType = hiddenDomainToHiddenType(domain); #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::setHiddenDomainPort() Set own State"; std::cerr << std::endl; #endif return true; } /* check for existing */ std::map::iterator it; it = mFriendList.find(ssl_id); if (it == mFriendList.end()) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::setHiddenDomainPort() Peer Not Found"; std::cerr << std::endl; #endif return false; } it->second.hiddenDomain = domain; it->second.hiddenPort = domain_port; it->second.hiddenNode = true; it->second.hiddenType = hiddenDomainToHiddenType(domain); #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::setHiddenDomainPort() Set Peers State"; std::cerr << std::endl; #endif return true; } /** * @brief sets the proxy server address for a hidden service * @param type hidden service type * @param proxy_addr proxy address * @return true on success */ bool p3PeerMgrIMPL::setProxyServerAddress(const uint32_t type, const struct sockaddr_storage &proxy_addr) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ switch (type) { case RS_HIDDEN_TYPE_I2P: if (!sockaddr_storage_same(mProxyServerAddressI2P, proxy_addr)) { IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); /**** INDICATE MSG CONFIG CHANGED! *****/ mProxyServerAddressI2P = proxy_addr; } break; case RS_HIDDEN_TYPE_TOR: if (!sockaddr_storage_same(mProxyServerAddressTor, proxy_addr)) { IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); /**** INDICATE MSG CONFIG CHANGED! *****/ mProxyServerAddressTor = proxy_addr; } break; case RS_HIDDEN_TYPE_UNKNOWN: default: #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::setProxyServerAddress() unknown hidden type " << type << " -> false"; std::cerr << std::endl; #endif return false; } return true; } bool p3PeerMgrIMPL::resetOwnExternalAddressList() { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ mOwnState.ipAddrs.mLocal.mAddrs.clear() ; mOwnState.ipAddrs.mExt.mAddrs.clear() ; IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); /**** INDICATE MSG CONFIG CHANGED! *****/ return true ; } /** * @brief returs proxy server status for a hidden service proxy * @param type hidden service type * @param proxy_status * @return true on success */ bool p3PeerMgrIMPL::getProxyServerStatus(const uint32_t type, uint32_t& proxy_status) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ switch (type) { case RS_HIDDEN_TYPE_I2P: proxy_status = mProxyServerStatusI2P; break; case RS_HIDDEN_TYPE_TOR: proxy_status = mProxyServerStatusTor; break; case RS_HIDDEN_TYPE_UNKNOWN: default: #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::getProxyServerStatus() unknown hidden type " << type << " -> false"; std::cerr << std::endl; #endif return false; } return true; } /** * @brief returs proxy server address for a hidden service proxy * @param type hidden service type * @param proxy_addr * @return true on success */ bool p3PeerMgrIMPL::getProxyServerAddress(const uint32_t type, struct sockaddr_storage &proxy_addr) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ switch (type) { case RS_HIDDEN_TYPE_I2P: proxy_addr = mProxyServerAddressI2P; break; case RS_HIDDEN_TYPE_TOR: proxy_addr = mProxyServerAddressTor; break; case RS_HIDDEN_TYPE_UNKNOWN: default: #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::getProxyServerAddress() unknown hidden type " << type << " -> false"; std::cerr << std::endl; #endif return false; } return true; } /** * @brief looks up the proxy address and domain/port that have to be used when connecting to a peer * @param ssl_id peer to connect to * @param proxy_addr proxy address to be used * @param domain_addr domain to connect to * @param domain_port port to connect to * @return true on success */ bool p3PeerMgrIMPL::getProxyAddress(const RsPeerId &ssl_id, struct sockaddr_storage &proxy_addr, std::string &domain_addr, uint16_t &domain_port) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ /* check for existing */ std::map::iterator it; it = mFriendList.find(ssl_id); if (it == mFriendList.end()) { return false; } if (!it->second.hiddenNode) { return false; } domain_addr = it->second.hiddenDomain; domain_port = it->second.hiddenPort; switch (it->second.hiddenType) { case RS_HIDDEN_TYPE_I2P: proxy_addr = mProxyServerAddressI2P; break; case RS_HIDDEN_TYPE_TOR: proxy_addr = mProxyServerAddressTor; break; case RS_HIDDEN_TYPE_UNKNOWN: default: #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::getProxyAddress() no valid hidden type (" << it->second.hiddenType << ") for peer id " << ssl_id << " -> false"; std::cerr << std::endl; #endif return false; } return true; } // Placeholder until we implement this functionality. uint32_t p3PeerMgrIMPL::getConnectionType(const RsPeerId &/*sslId*/) { return RS_NET_CONN_TYPE_FRIEND; } int p3PeerMgrIMPL::getFriendCount(bool ssl, bool online) { if (online) { // count only online id's std::list onlineIds; mLinkMgr->getOnlineList(onlineIds); RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ std::set gpgIds; int count = 0; std::map::iterator it; for(it = mFriendList.begin(); it != mFriendList.end(); ++it) { if (online && std::find(onlineIds.begin(), onlineIds.end(), it->first) == onlineIds.end()) { continue; } if (ssl) { // count ssl id's only count++; } else { // count unique gpg id's gpgIds.insert(it->second.gpg_id); } } return ssl ? count : gpgIds.size(); } if (ssl) { // count all ssl id's RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ return mFriendList.size(); } // count all gpg id's std::list gpgIds; AuthPGP::getPgpAcceptedList(gpgIds); // add own gpg id, if we have more than one location std::list ownSslIds; getAssociatedPeers(AuthPGP::getPgpOwnId(), ownSslIds); return gpgIds.size() + ((ownSslIds.size() > 0) ? 1 : 0); } bool p3PeerMgrIMPL::getFriendNetStatus(const RsPeerId &id, peerState &state) { RS_STACK_MUTEX(mPeerMtx); /* check for existing */ std::map::iterator it; it = mFriendList.find(id); if (it == mFriendList.end()) return false; state = it->second; return true; } int p3PeerMgrIMPL::getConnectAddresses( const RsPeerId &id, sockaddr_storage &lAddr, sockaddr_storage &eAddr, pqiIpAddrSet &histAddrs, std::string &dyndns ) { RS_STACK_MUTEX(mPeerMtx); /* check for existing */ std::map::iterator it; it = mFriendList.find(id); if (it == mFriendList.end()) { /* ERROR */ std::cerr << "p3PeerMgrIMPL::getConnectAddresses() ERROR unknown Peer"; std::cerr << std::endl; return 0; } lAddr = it->second.localaddr; eAddr = it->second.serveraddr; histAddrs = it->second.ipAddrs; dyndns = it->second.dyndns; return 1; } bool p3PeerMgrIMPL::haveOnceConnected() { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ /* check for existing */ for(auto it = mFriendList.begin(); it != mFriendList.end(); ++it) { if (it->second.lastcontact > 0) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::haveOnceConnected() lastcontact: "; std::cerr << time(NULL) - it->second.lastcontact << " for id: " << it->first; std::cerr << std::endl; #endif return true; } } #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::haveOnceConnected() all Last Contacts = 0"; std::cerr << std::endl; #endif return false; } bool p3PeerMgrIMPL::notifyPgpKeyReceived(const RsPgpId& pgp_id) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ bool changed = false; for(auto it(mFriendList.begin());it!=mFriendList.end();++it) { if(it->second.gpg_id == pgp_id) { std::cerr << "(WW) notification that full key " << pgp_id << " is available. Reseting short invite flag for peer " << it->first << std::endl; it->second.skip_pgp_signature_validation = false; changed = true; } } if(changed) IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_NOW); return true; } /*******************************************************************/ /*******************************************************************/ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg_id, uint32_t netMode, uint16_t vs_disc, uint16_t vs_dht, rstime_t lastContact,ServicePermissionFlags service_flags) { bool notifyLinkMgr = false; RsPeerId id = input_id ; RsPgpId gpg_id = input_gpg_id ; #ifdef PEER_DEBUG_LOG rslog(RSL_WARNING, p3peermgrzone, "p3PeerMgr::addFriend() id: " + id.toStdString()); #endif { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ if (id == AuthSSL::getAuthSSL()->OwnId()) { RsErr() << "p3PeerMgrIMPL::addFriend() cannot add own id as a friend. That's a bug!" << std::endl; /* (1) already exists */ return false; } /* so four possibilities * (1) already exists as friend -> do nothing. * (2) is in others list -> move over. * (3) is non-existant -> create new one. */ #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::addFriend() " << id << "; gpg_id : " << gpg_id << std::endl; #endif std::map::iterator it; if (mFriendList.end() != (it=mFriendList.find(id))) { // The friend may already be here, including with a short invite (meaning the PGP key is unknown). if(it->second.gpg_id != input_gpg_id)// already exists as a friend with a different PGP id!! { RsErr() << "Trying to add SSL id (" << id << ") that is already a friend with existing PGP key (" << it->second.gpg_id << ") but using a different PGP key (" << input_gpg_id << "). This is a bug!" << std::endl; return false; } else return true; /* (1) already exists */ } // check that the PGP key is known if(!AuthPGP::isPGPId(gpg_id)) { RsErr() << "Trying to add SSL id (" << id << ") to be validated with unknown PGP key (" << gpg_id << ". This is a bug!" << std::endl; return false; } //Authentication is now tested at connection time, we don't store the ssl cert anymore // if (!AuthPGP::isPGPAccepted(gpg_id) && gpg_id != AuthPGP::getPgpOwnId()) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::addFriend() gpg is not accepted" << std::endl; #endif /* no auth */ return false; } // after that, we know that we have the key, because AuthGPG wouldn't answer yes for a key it doesn't know. /* check if it is in others */ // if (mOthersList.end() != (it = mOthersList.find(id))) // { // /* (2) in mOthersList -> move over */ //#ifdef PEER_DEBUG // std::cerr << "p3PeerMgrIMPL::addFriend() Move from Others" << std::endl; //#endif // if(!it->second.gpg_id.isNull() && it->second.gpg_id != input_gpg_id)// already exists as a friend with a different PGP id!! // RsErr() << "Trying to add SSL id (" << id << ") that is already known (but not friend) with existing PGP key (" << it->second.gpg_id // << ") but using a different PGP key (" << input_gpg_id << "). This looks like a bug! The friend will be added again with the new PGP key ID." << std::endl; // // mFriendList[id] = it->second; // mOthersList.erase(it); // // it = mFriendList.find(id); // // /* setup connectivity parameters */ // it->second.vs_disc = vs_disc; // it->second.vs_dht = vs_dht; // // it->second.netMode = netMode; // it->second.lastcontact = lastContact; // // it->second.gpg_id = input_gpg_id; // it->second.skip_pgp_signature_validation = false; // // mStatusChanged = true; // // notifyLinkMgr = true; // // IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ // } // else #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::addFriend() Creating New Entry" << std::endl; #endif /* create a new entry */ peerState pstate; pstate.id = id; pstate.gpg_id = gpg_id; pstate.name = AuthPGP::getPgpName(gpg_id); pstate.vs_disc = vs_disc; pstate.vs_dht = vs_dht; pstate.netMode = netMode; pstate.lastcontact = lastContact; pstate.gpg_id = input_gpg_id; pstate.skip_pgp_signature_validation = false; /* addr & timestamps -> auto cleared */ mFriendList[id] = pstate; mStatusChanged = true; notifyLinkMgr = true; IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_NOW); /**** INDICATE MSG CONFIG CHANGED! *****/ } if (notifyLinkMgr) { mLinkMgr->addFriend(id, vs_dht != RS_VS_DHT_OFF); } service_flags &= servicePermissionFlags(gpg_id) ; // Always reduce the permissions. #ifdef RS_CHATSERVER //Defined by chatserver setServicePermissionFlags(gpg_id,RS_NODE_PERM_NONE) ; #else setServicePermissionFlags(gpg_id,service_flags) ; #endif #ifdef PEER_DEBUG printPeerLists(std::cerr); mLinkMgr->printPeerLists(std::cerr); #endif return true; } bool p3PeerMgrIMPL::addSslOnlyFriend( const RsPeerId& sslId, const RsPgpId& pgp_id, const RsPeerDetails& dt ) { constexpr auto fname = __PRETTY_FUNCTION__; const auto failure = [&](const std::string& err) { RsErr() << fname << " " << err << std::endl; return false; }; if(sslId.isNull()) return failure("Cannot add a null ID as SSL-only friend"); if(pgp_id.isNull()) return failure( " Cannot add as SSL-only friend a peer with null PGP"); if(sslId == getOwnId()) return failure( "Cannot add yourself as SSL-only friend id:" + sslId.toStdString() ); bool alreadySslFriend = false; peerState pstate; { RS_STACK_MUTEX(mPeerMtx); auto it = mFriendList.find(sslId); if( it != mFriendList.end() ) { alreadySslFriend = true; /* If it is already friend override pstate so we don't loose already * known information about the peer, in particular overriding * pstate.skip_pgp_signature_validation is important for security. */ pstate = it->second; } } // RS_STACK_MUTEX(mPeerMtx); /* If it is already friend check if PGP id of the invite matches with the * PGP id we already know, to avoid nasty tricks with malevolently forged * short invites.*/ if(alreadySslFriend && pstate.gpg_id != pgp_id) return failure( "Cannot SSL-only friend for a pre-existing friend with " "mismatching PGP-id known: " + pstate.gpg_id.toStdString() + " new: " + pgp_id.toStdString() ); /* It is very important to be expecially carefull setting * pstate.skip_pgp_signature_validation to true because this effectively * disables PGP signature verification on connection attempt. * This check in particular avoid someone attempting to trick the user into * accepting as SSL-only friend a malevolently forged short invite, with the * PGP id of an already known friend but the SSL-id of a location generated * by the attacker which doesn't have access to the legitimate PGP * certificate. * In that case being pstate.skip_pgp_signature_validation false on * connection attempt the PGP signaure verification would fail and the * connection closed. * Instead if pstate.skip_pgp_signature_validation would have been * superficially set to true the PGP signature verification would have been * skipped and the attacker connection would be accepted. * If the PGP key is available add it as full friend. */ if(AuthPGP::isPgpPubKeyAvailable(pgp_id)) AuthPGP::AllowConnection(pgp_id, true); else pstate.skip_pgp_signature_validation = true; pstate.gpg_id = pgp_id; pstate.id = sslId; /* At this point if we got info about the peer just update with the new * values. */ if(!dt.name.empty()) pstate.name = dt.name; if(!dt.dyndns.empty()) { pstate.dyndns = dt.dyndns; if(dt.extPort) { /* If there is no IPv4 address available yet add a placeholder to * not loose the port, because the address is invalid. */ if(!sockaddr_storage_isValidNet(pstate.serveraddr)) sockaddr_storage_inet_pton(pstate.serveraddr, "192.0.2.0"); sockaddr_storage_setport(pstate.serveraddr, dt.extPort); } } pstate.hiddenNode = dt.isHiddenNode; if(!dt.hiddenNodeAddress.empty()) pstate.hiddenDomain = dt.hiddenNodeAddress; if(dt.hiddenNodePort) pstate.hiddenPort = dt.hiddenNodePort; if(dt.hiddenType) pstate.hiddenType = dt.hiddenType; if(!dt.location.empty()) pstate.location = dt.location; { RS_STACK_MUTEX(mPeerMtx); mFriendList[sslId] = pstate; mStatusChanged = true; } // RS_STACK_MUTEX(mPeerMtx); IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_NOW); mLinkMgr->addFriend(sslId, dt.vs_dht != RS_VS_DHT_OFF); /* To update IP addresses is much more confortable to use locators, beside * of the easy to use another benefit is that this way we don't loose * previously known IP addresses */ if(!dt.isHiddenNode) { for(const std::string& ipStr : dt.ipAddressList) addPeerLocator(sslId, RsUrl(ipStr)); if(dt.extPort && !dt.extAddr.empty()) { RsUrl locator; locator.setScheme("ipv4").setHost(dt.extAddr) .setPort(dt.extPort); addPeerLocator(sslId, locator); } if(dt.localPort && !dt.localAddr.empty()) { RsUrl locator; locator.setScheme("ipv4").setHost(dt.localAddr) .setPort(dt.localPort); addPeerLocator(sslId, locator); } } return true; } bool p3PeerMgrIMPL::removeFriend(const RsPgpId &id) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::removeFriend() for id : " << id << std::endl; std::cerr << "p3PeerMgrIMPL::removeFriend() mFriendList.size() : " << mFriendList.size() << std::endl; #endif rslog(RSL_WARNING, p3peermgrzone, "p3PeerMgr::removeFriend() id: " + id.toStdString()); std::list sslid_toRemove; // This is a list of SSLIds. rsPeers->getAssociatedSSLIds(id,sslid_toRemove) ; { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ /* move to othersList */ //bool success = false; std::map::iterator it; //remove ssl and gpg_ids for(it = mFriendList.begin(); it != mFriendList.end(); ++it) { if (find(sslid_toRemove.begin(),sslid_toRemove.end(),it->second.id) != sslid_toRemove.end()) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::removeFriend() friend found in the list." << id << std::endl; #endif peerState peer = it->second; sslid_toRemove.push_back(it->second.id); //mOthersList[it->second.id] = peer; mStatusChanged = true; //success = true; } } for(std::list::iterator rit = sslid_toRemove.begin(); rit != sslid_toRemove.end(); ++rit) if (mFriendList.end() != (it = mFriendList.find(*rit))) mFriendList.erase(it); std::map::iterator it2 = mFriendsPermissionFlags.find(id) ; if(it2 != mFriendsPermissionFlags.end()) mFriendsPermissionFlags.erase(it2); #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::removeFriend() new mFriendList.size() : " << mFriendList.size() << std::endl; #endif } std::list::iterator rit; for(rit = sslid_toRemove.begin(); rit != sslid_toRemove.end(); ++rit) { mLinkMgr->removeFriend(*rit); } /* remove id from all groups */ std::list ids ; ids.push_back(id) ; assignPeersToGroup(RsNodeGroupId(), ids, false); IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_NOW); /**** INDICATE MSG CONFIG CHANGED! *****/ #ifdef PEER_DEBUG printPeerLists(std::cerr); mLinkMgr->printPeerLists(std::cerr); #endif return !sslid_toRemove.empty(); } bool p3PeerMgrIMPL::removeFriend(const RsPeerId &id, bool removePgpId) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::removeFriend() for id : " << id << std::endl; std::cerr << "p3PeerMgrIMPL::removeFriend() mFriendList.size() : " << mFriendList.size() << std::endl; #endif rslog(RSL_WARNING, p3peermgrzone, "p3PeerMgr::removeFriend() id: " + id.toStdString()); std::list sslid_toRemove; // This is a list of SSLIds. std::list pgpid_toRemove; // This is a list of SSLIds. { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ /* move to othersList */ //bool success = false; std::map::iterator it; //remove ssl and gpg_ids for(it = mFriendList.begin(); it != mFriendList.end(); ++it) { if (it->second.id == id) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::removeFriend() friend found in the list." << id << std::endl; #endif peerState peer = it->second; sslid_toRemove.push_back(it->second.id); if(removePgpId) pgpid_toRemove.push_back(it->second.gpg_id); //mOthersList[id] = peer; mStatusChanged = true; //success = true; } } for(std::list::iterator rit = sslid_toRemove.begin(); rit != sslid_toRemove.end(); ++rit) if (mFriendList.end() != (it = mFriendList.find(*rit))) mFriendList.erase(it); std::map::iterator it2 ; for(std::list::iterator rit = pgpid_toRemove.begin(); rit != pgpid_toRemove.end(); ++rit) if (mFriendsPermissionFlags.end() != (it2 = mFriendsPermissionFlags.find(*rit))) mFriendsPermissionFlags.erase(it2); #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::removeFriend() new mFriendList.size() : " << mFriendList.size() << std::endl; #endif } std::list::iterator rit; for(rit = sslid_toRemove.begin(); rit != sslid_toRemove.end(); ++rit) { mLinkMgr->removeFriend(*rit); } /* remove id from all groups */ assignPeersToGroup(RsNodeGroupId(), pgpid_toRemove, false); IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_NOW); /**** INDICATE MSG CONFIG CHANGED! *****/ #ifdef PEER_DEBUG printPeerLists(std::cerr); mLinkMgr->printPeerLists(std::cerr); #endif return !sslid_toRemove.empty(); } void p3PeerMgrIMPL::printPeerLists(std::ostream &out) { { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ out << "p3PeerMgrIMPL::printPeerLists() Friend List"; out << std::endl; std::map::iterator it; for(it = mFriendList.begin(); it != mFriendList.end(); ++it) { out << "\t SSL ID: " << it->second.id; out << "\t GPG ID: " << it->second.gpg_id; out << std::endl; } // out << "p3PeerMgrIMPL::printPeerLists() Others List"; // out << std::endl; // for(it = mOthersList.begin(); it != mOthersList.end(); ++it) // { // out << "\t SSL ID: " << it->second.id; // out << "\t GPG ID: " << it->second.gpg_id; // out << std::endl; // } } return; } /*******************************************************************/ /*******************************************************************/ /********************************************************************** ********************************************************************** ******************** External Setup ********************************** ********************************************************************** **********************************************************************/ /* This function should only be called from NetMgr, * as it doesn't call back to there. */ bool p3PeerMgrIMPL::UpdateOwnAddress( const sockaddr_storage& pLocalAddr, const sockaddr_storage& pExtAddr ) { sockaddr_storage localAddr; sockaddr_storage_copy(pLocalAddr, localAddr); sockaddr_storage_ipv6_to_ipv4(localAddr); sockaddr_storage extAddr; sockaddr_storage_copy(pExtAddr, extAddr); sockaddr_storage_ipv6_to_ipv4(extAddr); #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::UpdateOwnAddress(" << sockaddr_storage_tostring(localAddr) << ", " << sockaddr_storage_tostring(extAddr) << ")" << std::endl; #endif if( rsBanList && !rsBanList->isAddressAccepted(localAddr, RSBANLIST_CHECKING_FLAGS_BLACKLIST) ) { std::cerr << "(SS) Trying to set own IP to a banned IP " << sockaddr_storage_iptostring(localAddr) << ". This probably" << "means that a friend in under traffic re-routing attack." << std::endl; return false; } { RS_STACK_MUTEX(mPeerMtx); //update ip address list pqiIpAddress ipAddressTimed; sockaddr_storage_copy(localAddr, ipAddressTimed.mAddr); ipAddressTimed.mSeenTime = time(NULL); ipAddressTimed.mSrc = 0; mOwnState.ipAddrs.updateLocalAddrs(ipAddressTimed); if(!mOwnState.hiddenNode) { /* Workaround to spread multiple local ip addresses when presents. * This is needed because RS wrongly assumes that there is just one * active local ip address at time. */ std::vector addrs; if(getLocalAddresses(addrs)) { /* To work around MAX_ADDRESS_LIST_SIZE addresses limitation, * let's shuffle the list of local addresses in the hope that * with enough time every local address is advertised to * trusted nodes so they may try to connect to all of them * including the most convenient if a local connection exists. */ auto seed = std::chrono::system_clock::now(). time_since_epoch().count(); std::shuffle( addrs.begin(), addrs.end(), std::default_random_engine(seed) ); for (auto it = addrs.begin(); it!=addrs.end(); ++it) { sockaddr_storage& addr(*it); if( sockaddr_storage_isValidNet(addr) && !sockaddr_storage_isLoopbackNet(addr) && /* Avoid IPv6 link local addresses as we don't have * implemented the logic needed to handle sin6_scope_id. * To properly handle sin6_scope_id it would probably * require deep reenginering of the RetroShare * networking stack */ !sockaddr_storage_ipv6_isLinkLocalNet(addr) ) { sockaddr_storage_ipv6_to_ipv4(addr); pqiIpAddress pqiIp; sockaddr_storage_clear(pqiIp.mAddr); pqiIp.mAddr.ss_family = addr.ss_family; sockaddr_storage_copyip(pqiIp.mAddr, addr); sockaddr_storage_setport( pqiIp.mAddr, sockaddr_storage_port(localAddr) ); pqiIp.mSeenTime = time(nullptr); pqiIp.mSrc = 0; mOwnState.ipAddrs.updateLocalAddrs(pqiIp); } } } } sockaddr_storage_copy(localAddr, mOwnState.localaddr); } { RS_STACK_MUTEX(mPeerMtx); //update ip address list pqiIpAddress ipAddressTimed; sockaddr_storage_copy(extAddr, ipAddressTimed.mAddr); ipAddressTimed.mSeenTime = time(NULL); ipAddressTimed.mSrc = 0; mOwnState.ipAddrs.updateExtAddrs(ipAddressTimed); /* Attempted Fix to MANUAL FORWARD Mode.... * don't update the server address - if we are in this mode * * It is okay - if they get it wrong, as we put the address in the address list anyway. * This should keep people happy, and allow for misconfiguration! */ if (mOwnState.netMode & RS_NET_MODE_TRY_EXT) { /**** THIS CASE SHOULD NOT BE TRIGGERED ****/ std::cerr << "p3PeerMgrIMPL::UpdateOwnAddress() Disabling Update of Server Port "; std::cerr << " as MANUAL FORWARD Mode (ERROR - SHOULD NOT BE TRIGGERED: TRY_EXT_MODE)"; std::cerr << std::endl; std::cerr << "Address is Now: "; std::cerr << sockaddr_storage_tostring(mOwnState.serveraddr); std::cerr << std::endl; } else if (mOwnState.netMode & RS_NET_MODE_EXT) { sockaddr_storage_copyip(mOwnState.serveraddr, extAddr); std::cerr << "p3PeerMgrIMPL::UpdateOwnAddress() Disabling Update of Server Port "; std::cerr << " as MANUAL FORWARD Mode"; std::cerr << std::endl; std::cerr << "Address is Now: "; std::cerr << sockaddr_storage_tostring(mOwnState.serveraddr); std::cerr << std::endl; } else { sockaddr_storage_copy(extAddr, mOwnState.serveraddr); } } IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_LESS); /**** INDICATE MSG CONFIG CHANGED! *****/ mLinkMgr->setLocalAddress(localAddr); return true; } bool p3PeerMgrIMPL::addPeerLocator(const RsPeerId &sslId, const RsUrl& locator) { std::string host(locator.host()); pqiIpAddress ip; if(!locator.hasPort() || host.empty() || !sockaddr_storage_inet_pton(ip.mAddr, host) || !sockaddr_storage_setport(ip.mAddr, locator.port())) return false; ip.mSeenTime = time(NULL); bool changed = false; if (sslId == AuthSSL::getAuthSSL()->OwnId()) { RS_STACK_MUTEX(mPeerMtx); changed = mOwnState.ipAddrs.updateLocalAddrs(ip); } else { RS_STACK_MUTEX(mPeerMtx); auto it = mFriendList.find(sslId); if (it == mFriendList.end()) { #ifdef PEER_DEBUG std::cerr << __PRETTY_FUNCTION__ << "cannot add address " << "info, peer id: " << sslId << " not found in list" << std::endl; #endif return false; } changed = it->second.ipAddrs.updateLocalAddrs(ip); } if (changed) { #ifdef PEER_DEBUG std::cerr << __PRETTY_FUNCTION__ << " Added locator: " << locator.toString() << std::endl; #endif IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); } return changed; } bool p3PeerMgrIMPL::setLocalAddress( const RsPeerId &id, const sockaddr_storage &addr ) { bool changed = false; if (id == AuthSSL::getAuthSSL()->OwnId()) { { RS_STACK_MUTEX(mPeerMtx); if (!sockaddr_storage_same(mOwnState.localaddr, addr)) { mOwnState.localaddr = addr; changed = true; } } if (changed) { IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); /**** INDICATE MSG CONFIG CHANGED! *****/ mNetMgr->setLocalAddress(addr); mLinkMgr->setLocalAddress(addr); } return changed; } RS_STACK_MUTEX(mPeerMtx); /* check if it is a friend */ std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { std::cerr << "(EE) p3PeerMgrIMPL::setLocalAddress() cannot add addres " << "info : peer id not found in friend list id: " << id << std::endl; return false; } /* "it" points to peer */ if (!sockaddr_storage_same(it->second.localaddr, addr)) { it->second.localaddr = addr; changed = true; } #if 0 //update ip address list IpAddressTimed ipAddressTimed; ipAddressTimed.ipAddr = addr; ipAddressTimed.seenTime = time(NULL); it->second.updateIpAddressList(ipAddressTimed); #endif if (changed) IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); return changed; } bool p3PeerMgrIMPL::setExtAddress( const RsPeerId &id, const sockaddr_storage &addr ) { bool changed = false; uint32_t check_res = 0; if(rsBanList && !rsBanList->isAddressAccepted( addr, RSBANLIST_CHECKING_FLAGS_BLACKLIST, check_res )) { RsErr() << __PRETTY_FUNCTION__ << " trying to set external contact " << "address for peer: " << id << " to a banned address " << addr << std::endl; return false; } if (id == AuthSSL::getAuthSSL()->OwnId()) { { RS_STACK_MUTEX(mPeerMtx); if (!sockaddr_storage_same(mOwnState.serveraddr, addr)) { mOwnState.serveraddr = addr; changed = true; } } mNetMgr->setExtAddress(addr); return changed; } RS_STACK_MUTEX(mPeerMtx); /* check if it is a friend */ std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { std::cerr << "(EE) p3PeerMgrIMPL::setExtAddress() cannot add addres " << "info : peer id not found in friend list id: " << id << std::endl; return false; } /* "it" points to peer */ if (!sockaddr_storage_same(it->second.serveraddr, addr)) { it->second.serveraddr = addr; changed = true; } #if 0 //update ip address list IpAddressTimed ipAddressTimed; ipAddressTimed.ipAddr = addr; ipAddressTimed.seenTime = time(NULL); it->second.updateIpAddressList(ipAddressTimed); #endif if (changed) { IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_LESS); /**** INDICATE MSG CONFIG CHANGED! *****/ } return changed; } bool p3PeerMgrIMPL::setDynDNS(const RsPeerId &id, const std::string &dyndns) { bool changed = false; if (id == AuthSSL::getAuthSSL()->OwnId()) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ if (mOwnState.dyndns.compare(dyndns) != 0) { mOwnState.dyndns = dyndns; IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); /**** INDICATE MSG CONFIG CHANGED! *****/ changed = true; if(rsEvents) { auto ev = std::make_shared(); ev->mNetworkEventCode = RsNetworkEventCode::EXTERNAL_IP_UPDATED; ev->mDNS = dyndns; rsEvents->postEvent(ev); } } return changed; } RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ /* check if it is a friend */ std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::setDynDNS() cannot add dyn dns info : peer id not found in friend list id: " << id << std::endl; #endif return false; } /* "it" points to peer */ if (it->second.dyndns.compare(dyndns) != 0) { it->second.dyndns = dyndns; IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); /**** INDICATE MSG CONFIG CHANGED! *****/ changed = true; } return changed; } namespace pqi { struct ZeroedInt { ZeroedInt() { n=0 ;} int n ; }; } bool p3PeerMgrIMPL::addCandidateForOwnExternalAddress(const RsPeerId &from, const sockaddr_storage &addr) { // The algorithm is the following: // - collect for each friend the last external connection address that is reported // - everytime the list is changed, parse it entirely and // * emit a warnign when the address is unknown // * if multiple peers report the same address => notify the LinkMgr that the external address had changed. sockaddr_storage addr_filtered ; sockaddr_storage_clear(addr_filtered) ; sockaddr_storage_copyip(addr_filtered,addr) ; #ifndef PEER_DEBUG std::cerr << "Own external address is " << sockaddr_storage_iptostring(addr_filtered) << ", as reported by friend " << from << std::endl; #endif if(!sockaddr_storage_isExternalNet(addr_filtered)) { #ifdef PEER_DEBUG std::cerr << " address is not an external address. Returning false" << std::endl ; #endif return false ; } // Update a list of own IPs: // - remove old values for that same peer // - remove values for non connected peers { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ mReportedOwnAddresses[from] = addr_filtered ; for(std::map::iterator it(mReportedOwnAddresses.begin());it!=mReportedOwnAddresses.end();) if(!mLinkMgr->isOnline(it->first)) { std::map::iterator tmp(it) ; ++tmp ; mReportedOwnAddresses.erase(it) ; it=tmp ; } else ++it ; sockaddr_storage current_best_ext_address_guess ; uint32_t count ; locked_computeCurrentBestOwnExtAddressCandidate(current_best_ext_address_guess,count) ; std::cerr << "p3PeerMgr:: Current external address is calculated to be: " << sockaddr_storage_iptostring(current_best_ext_address_guess) << " (simultaneously reported by " << count << " peers)." << std::endl; } // now current sockaddr_storage own_addr ; if(!mNetMgr->getExtAddress(own_addr)) { #ifdef PEER_DEBUG std::cerr << " cannot get current external address. Returning false" << std::endl; #endif return false ; } #ifdef PEER_DEBUG std::cerr << " current external address is known to be " << sockaddr_storage_iptostring(own_addr) << std::endl; #endif // Notify for every friend that has reported a wrong external address, except if that address is in the IP whitelist. if((rsBanList && !rsBanList->isAddressAccepted(addr_filtered, RSBANLIST_CHECKING_FLAGS_WHITELIST)) && !sockaddr_storage_sameip(own_addr, addr_filtered) ) { RsInfo() << __PRETTY_FUNCTION__ << " Peer " << from << " reports a connection address (" << addr_filtered <<") that is not your current external address (" << own_addr << "). This is weird." << std::endl; if(rsEvents) { auto ev = std::make_shared(); ev->mSslId = from; ev->mOwnLocator = RsUrl(own_addr); ev->mReportedLocator = RsUrl(addr); ev->mConnectionInfoCode = RsConnectionEventCode::PEER_REPORTS_WRONG_IP; rsEvents->postEvent(ev); } } // we could also sweep over all connected friends and see if some report a different address. return true ; } bool p3PeerMgrIMPL::locked_computeCurrentBestOwnExtAddressCandidate(sockaddr_storage& addr, uint32_t& count) { sockaddr_storage_clear(addr); std::map addr_counts ; for(std::map::iterator it(mReportedOwnAddresses.begin());it!=mReportedOwnAddresses.end();++it) ++addr_counts[it->second].n ; #ifdef PEER_DEBUG std::cerr << "Current ext addr statistics:" << std::endl; #endif count = 0 ; for(std::map::const_iterator it(addr_counts.begin());it!=addr_counts.end();++it) { if(uint32_t(it->second.n) > count) { addr = it->first ; count = it->second.n ; } #ifdef PEER_DEBUG std::cerr << sockaddr_storage_iptostring(it->first) << " : " << it->second.n << std::endl; #endif } return count > 0 ; } bool p3PeerMgrIMPL::getExtAddressReportedByFriends(sockaddr_storage &addr, uint8_t& /*isstable*/) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ uint32_t count =0; locked_computeCurrentBestOwnExtAddressCandidate(addr,count) ; #ifdef PEER_DEBUG std::cerr << "Estimation count = " << count << ". Trusted? = " << (count>=2) << std::endl; #endif return count >= 2 ;// 2 is not conservative enough. 3 should be probably better. } static bool cleanIpList(std::list& lst,const RsPeerId& pid,p3LinkMgr *link_mgr) { bool changed = false ; #ifdef PEER_DEBUG rstime_t now = time(NULL) ; #endif for(std::list::iterator it2(lst.begin());it2 != lst.end();) { #ifdef PEER_DEBUG std::cerr << "Checking IP address " << sockaddr_storage_iptostring( (*it2).mAddr) << " for peer " << pid << ", age = " << now - (*it2).mSeenTime << std::endl; #else /* remove unused parameter warnings */ (void) pid; #endif if(!link_mgr->checkPotentialAddr((*it2).mAddr)) { #ifdef PEER_DEBUG std::cerr << " (SS) Removing Banned/old IP address " << sockaddr_storage_iptostring( (*it2).mAddr) << " from peer " << pid << ", age = " << now - (*it2).mSeenTime << std::endl; #endif std::list::iterator ittmp = it2 ; ++ittmp ; lst.erase(it2) ; it2 = ittmp ; changed = true ; } else ++it2 ; } return changed ; } bool p3PeerMgrIMPL::updateAddressList(const RsPeerId& id, const pqiIpAddrSet &addrs) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::setAddressList() called for id : " << id << std::endl; #endif // first clean the list from potentially banned IPs. pqiIpAddrSet clean_set = addrs ; cleanIpList(clean_set.mExt.mAddrs,id,mLinkMgr) ; cleanIpList(clean_set.mLocal.mAddrs,id,mLinkMgr) ; bool am_I_a_hidden_node = isHiddenNode(getOwnId()) ; RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ /* check if it is our own ip */ if (id == getOwnId()) { mOwnState.ipAddrs.updateAddrs(clean_set); return true; } /* check if it is a friend */ std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::setLocalAddress() cannot add addres info : peer id not found in friend list. id: " << id << std::endl; #endif return false; } /* "it" points to peer */ if(!am_I_a_hidden_node) it->second.ipAddrs.updateAddrs(clean_set); else it->second.ipAddrs.clear(); #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::setLocalAddress() Updated Address for: " << id; std::cerr << std::endl; std::string addrstr; it->second.ipAddrs.printAddrs(addrstr); std::cerr << addrstr; std::cerr << std::endl; #endif IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_LESS); /**** INDICATE MSG CONFIG CHANGED! *****/ return true; } bool p3PeerMgrIMPL::updateCurrentAddress(const RsPeerId& id, const pqiIpAddress &addr) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::updateCurrentAddress() called for id : " << id << std::endl; #endif RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ /* cannot be own id */ /* check if it is a friend */ std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { std::cerr << "p3PeerMgrIMPL::updateCurrentAddress() ERROR peer id not found: " << id << std::endl; return false; } if (sockaddr_storage_isPrivateNet(addr.mAddr)) { it->second.ipAddrs.updateLocalAddrs(addr); it->second.localaddr = addr.mAddr; } else { it->second.ipAddrs.updateExtAddrs(addr); it->second.serveraddr = addr.mAddr; } #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::updatedCurrentAddress() Updated Address for: " << id; std::cerr << std::endl; std::string addrstr; it->second.ipAddrs.printAddrs(addrstr); std::cerr << addrstr; std::cerr << std::endl; #endif IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_LESS); /**** INDICATE MSG CONFIG CHANGED! *****/ return true; } bool p3PeerMgrIMPL::updateLastContact(const RsPeerId& id) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::updateLastContact() called for id : " << id << std::endl; #endif RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ /* cannot be own id */ /* check if it is a friend */ std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { std::cerr << "p3PeerMgrIMPL::updateLastContact() ERROR peer id not found: " << id << std::endl; return false; } it->second.lastcontact = time(NULL); IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ return true; } bool p3PeerMgrIMPL::setNetworkMode(const RsPeerId &id, uint32_t netMode) { if (id == AuthSSL::getAuthSSL()->OwnId()) { return setOwnNetworkMode(netMode); } RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ /* check if it is a friend */ std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { return false; } bool changed = false; /* "it" points to peer */ if (it->second.netMode != netMode) { it->second.netMode = netMode; IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_LESS); /**** INDICATE MSG CONFIG CHANGED! *****/ changed = true; } return changed; } bool p3PeerMgrIMPL::setLocation(const RsPeerId &id, const std::string &location) { bool changed = false; RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::setLocation() called for id : " << id << "; with location " << location << std::endl; #endif if (id == AuthSSL::getAuthSSL()->OwnId()) { if (mOwnState.location.compare(location) != 0) { mOwnState.location = location; changed = true; } IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_LESS); /**** INDICATE MSG CONFIG CHANGED! *****/ return changed; } /* check if it is a friend */ std::map::iterator it; if (mFriendList.end() != (it = mFriendList.find(id))) { if (it->second.location.compare(location) != 0) { it->second.location = location; changed = true; } } IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_LESS); /**** INDICATE MSG CONFIG CHANGED! *****/ return changed; } bool p3PeerMgrIMPL::setVisState(const RsPeerId &id, uint16_t vs_disc, uint16_t vs_dht) { { std::string out; rs_sprintf(out, "p3PeerMgr::setVisState(%s, %u, %u)", id.toStdString().c_str(), vs_disc, vs_dht); rslog(RSL_WARNING, p3peermgrzone, out); } if (id == AuthSSL::getAuthSSL()->OwnId()) { return setOwnVisState(vs_disc, vs_dht); } bool isFriend = false; bool changed = false; { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ /* check if it is a friend */ std::map::iterator it; if (mFriendList.end() == (it = mFriendList.find(id))) { return false; } else { isFriend = true; } /* "it" points to peer */ if ((it->second.vs_disc != vs_disc) || (it->second.vs_dht = vs_dht)) { it->second.vs_disc = vs_disc; it->second.vs_dht = vs_dht; changed = true; #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::setVisState(" << id << ", DISC: " << vs_disc << " DHT: " << vs_dht << ") "; std::cerr << " NAME: " << it->second.name; switch(it->second.vs_disc) { default: case RS_VS_DISC_OFF: std::cerr << " NO-DISC "; break; case RS_VS_DISC_MINIMAL: std::cerr << " MIN-DISC "; break; case RS_VS_DISC_FULL: std::cerr << " FULL-DISC "; break; } switch(it->second.vs_dht) { default: case RS_VS_DHT_OFF: std::cerr << " NO-DHT "; break; case RS_VS_DHT_PASSIVE: std::cerr << " PASSIVE-DHT "; break; case RS_VS_DHT_FULL: std::cerr << " FULL-DHT "; break; } std::cerr << std::endl; #endif } } if(isFriend && changed) { mLinkMgr->setFriendVisibility(id, vs_dht != RS_VS_DHT_OFF); } if (changed) IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_LESS); /**** INDICATE MSG CONFIG CHANGED! *****/ return changed; } /*******************************************************************/ /********************************************************************** ********************************************************************** ******************** p3Config functions ****************************** ********************************************************************** **********************************************************************/ /* Key Functions to be overloaded for Full Configuration */ RsSerialiser *p3PeerMgrIMPL::setupSerialiser() { RsSerialiser *rss = new RsSerialiser(); rss->addSerialType(new RsPeerConfigSerialiser()); rss->addSerialType(new RsGeneralConfigSerialiser()) ; return rss; } bool p3PeerMgrIMPL::saveList(bool &cleanup, std::list& saveData) { /* create a list of current peers */ cleanup = true; bool useExtAddrFinder = mNetMgr->getIPServersEnabled(); /* gather these information before mPeerMtx is locked! */ struct sockaddr_storage proxy_addr_tor, proxy_addr_i2p; getProxyServerAddress(RS_HIDDEN_TYPE_TOR, proxy_addr_tor); getProxyServerAddress(RS_HIDDEN_TYPE_I2P, proxy_addr_i2p); mPeerMtx.lock(); /****** MUTEX LOCKED *******/ RsPeerNetItem *item = new RsPeerNetItem(); item->clear(); item->nodePeerId = getOwnId(); item->pgpId = mOwnState.gpg_id; item->location = mOwnState.location; #if 0 if (mOwnState.netMode & RS_NET_MODE_TRY_EXT) { item->netMode = RS_NET_MODE_EXT; } else if (mOwnState.netMode & RS_NET_MODE_TRY_UPNP) { item->netMode = RS_NET_MODE_UPNP; } else { item->netMode = RS_NET_MODE_UDP; } #endif item->netMode = mOwnState.netMode; item->vs_disc = mOwnState.vs_disc; item->vs_dht = mOwnState.vs_dht; item->lastContact = mOwnState.lastcontact; item->localAddrV4.addr = mOwnState.localaddr; item->extAddrV4.addr = mOwnState.serveraddr; sockaddr_storage_clear(item->localAddrV6.addr); sockaddr_storage_clear(item->extAddrV6.addr); item->dyndns = mOwnState.dyndns; mOwnState.ipAddrs.mLocal.loadTlv(item->localAddrList); mOwnState.ipAddrs.mExt.loadTlv(item->extAddrList); item->domain_addr = mOwnState.hiddenDomain; item->domain_port = mOwnState.hiddenPort; #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::saveList() Own Config Item:" << std::endl; item->print(std::cerr, 10); std::cerr << std::endl; #endif saveData.push_back(item); /* iterate through all friends and save */ std::map::iterator it; for(it = mFriendList.begin(); it != mFriendList.end(); ++it) { item = new RsPeerNetItem(); item->clear(); item->nodePeerId = it->first; item->pgpId = (it->second).gpg_id; item->location = (it->second).location; item->netMode = (it->second).netMode; item->vs_disc = (it->second).vs_disc; item->vs_dht = (it->second).vs_dht; item->lastContact = (it->second).lastcontact; item->localAddrV4.addr = (it->second).localaddr; item->extAddrV4.addr = (it->second).serveraddr; sockaddr_storage_clear(item->localAddrV6.addr); sockaddr_storage_clear(item->extAddrV6.addr); item->dyndns = (it->second).dyndns; (it->second).ipAddrs.mLocal.loadTlv(item->localAddrList); (it->second).ipAddrs.mExt.loadTlv(item->extAddrList); item->domain_addr = (it->second).hiddenDomain; item->domain_port = (it->second).hiddenPort; saveData.push_back(item); #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::saveList() Peer Config Item:" << std::endl; item->print(std::cerr, 10); std::cerr << std::endl; #endif } RsPeerBandwidthLimitsItem *pblitem = new RsPeerBandwidthLimitsItem ; pblitem->peers = mPeerBandwidthLimits ; saveData.push_back(pblitem) ; RsPeerServicePermissionItem *sitem = new RsPeerServicePermissionItem ; for(std::map::const_iterator it(mFriendsPermissionFlags.begin());it!=mFriendsPermissionFlags.end();++it) { sitem->pgp_ids.push_back(it->first) ; sitem->service_flags.push_back(it->second) ; } saveData.push_back(sitem) ; // Now save config for network digging strategies RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet ; RsTlvKeyValue kv; kv.key = kConfigKeyExtIpFinder; kv.value = (useExtAddrFinder)?"TRUE":"FALSE" ; vitem->tlvkvs.pairs.push_back(kv) ; // Store Proxy Server. // Tor #ifdef PEER_DEBUG std::cerr << "Saving proxyServerAddress for Tor: " << sockaddr_storage_tostring(proxy_addr_tor); std::cerr << std::endl; #endif kv.key = kConfigKeyProxyServerIpAddrTor; kv.value = sockaddr_storage_iptostring(proxy_addr_tor); vitem->tlvkvs.pairs.push_back(kv) ; kv.key = kConfigKeyProxyServerPortTor; kv.value = sockaddr_storage_porttostring(proxy_addr_tor); vitem->tlvkvs.pairs.push_back(kv) ; // I2P #ifdef PEER_DEBUG std::cerr << "Saving proxyServerAddress for I2P: " << sockaddr_storage_tostring(proxy_addr_i2p); std::cerr << std::endl; #endif kv.key = kConfigKeyProxyServerIpAddrI2P; kv.value = sockaddr_storage_iptostring(proxy_addr_i2p); vitem->tlvkvs.pairs.push_back(kv) ; kv.key = kConfigKeyProxyServerPortI2P; kv.value = sockaddr_storage_porttostring(proxy_addr_i2p); vitem->tlvkvs.pairs.push_back(kv) ; saveData.push_back(vitem); /* save groups */ for ( std::map::iterator groupIt = groupList.begin(); groupIt != groupList.end(); ++groupIt) { RsNodeGroupItem *itm = new RsNodeGroupItem(groupIt->second); saveData.push_back(itm) ; } return true; } bool p3PeerMgrIMPL::getMaxRates(const RsPeerId& pid,uint32_t& maxUp,uint32_t& maxDn) { RsPgpId pgp_id ; { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ std::map::const_iterator it = mFriendList.find(pid) ; if(it == mFriendList.end()) { maxUp = 0; maxDn = 0; return false ; } pgp_id = it->second.gpg_id ; } return getMaxRates(pgp_id,maxUp,maxDn) ; } bool p3PeerMgrIMPL::getMaxRates(const RsPgpId& pid,uint32_t& maxUp,uint32_t& maxDn) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ std::map::const_iterator it2 = mPeerBandwidthLimits.find(pid) ; if(it2 != mPeerBandwidthLimits.end()) { maxUp = it2->second.max_up_rate_kbs ; maxDn = it2->second.max_dl_rate_kbs ; return true ; } else { maxUp = 0; maxDn = 0; return false ; } } bool p3PeerMgrIMPL::setMaxRates(const RsPgpId& pid,uint32_t maxUp,uint32_t maxDn) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ PeerBandwidthLimits& p(mPeerBandwidthLimits[pid]) ; if(maxUp == p.max_up_rate_kbs && maxDn == p.max_dl_rate_kbs) return true ; std::cerr << "Updating max rates for peer " << pid << " to " << maxUp << " kB/s (up), " << maxDn << " kB/s (dn)" << std::endl; p.max_up_rate_kbs = maxUp ; p.max_dl_rate_kbs = maxDn ; IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_LESS); return true ; } void p3PeerMgrIMPL::saveDone() { /* clean up the save List */ std::list::iterator it; for(it = saveCleanupList.begin(); it != saveCleanupList.end(); ++it) { delete (*it); } saveCleanupList.clear(); /* unlock mutex */ mPeerMtx.unlock(); /****** MUTEX UNLOCKED *******/ } bool p3PeerMgrIMPL::loadList(std::list& load) { // DEFAULTS. bool useExtAddrFinder = true; std::string proxyIpAddressTor = kConfigDefaultProxyServerIpAddr; uint16_t proxyPortTor = kConfigDefaultProxyServerPortTor; std::string proxyIpAddressI2P = kConfigDefaultProxyServerIpAddr; uint16_t proxyPortI2P = kConfigDefaultProxyServerPortI2P; if (load.empty()) { std::cerr << "p3PeerMgrIMPL::loadList() list is empty, it may be a configuration problem." << std::endl; return false; } #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::loadList() Item Count: " << load.size() << std::endl; #endif RsPeerId ownId = getOwnId(); bool am_I_a_hidden_node = isHiddenNode(ownId) ; /* load the list of peers */ std::list::iterator it; for(it = load.begin(); it != load.end(); ++it) { RsPeerNetItem *pitem = dynamic_cast(*it); if (pitem) { RsPeerId peer_id = pitem->nodePeerId ; RsPgpId peer_pgp_id = pitem->pgpId ; if (peer_id == ownId) { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::loadList() Own Config Item:" << std::endl; pitem->print(std::cerr, 10); std::cerr << std::endl; #endif /* add ownConfig */ setOwnNetworkMode(pitem->netMode); setOwnVisState(pitem->vs_disc, pitem->vs_dht); mOwnState.gpg_id = AuthPGP::getPgpOwnId(); mOwnState.location = AuthSSL::getAuthSSL()->getOwnLocation(); } else { #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::loadList() Peer Config Item:" << std::endl; pitem->print(std::cerr, 10); std::cerr << std::endl; #endif /* ************* */ // permission flags is used as a mask for the existing perms, so we set it to 0xffff RsPeerDetails det ; if(!rsPeers->getGPGDetails(peer_pgp_id,det)) { // would be better to add flags into RsPeerNetItem so that we already have this information. However, it's possible that the PGP key // has been added in the meantime, so the peer would be loaded with the right pGP key attached. RsInfo() << __PRETTY_FUNCTION__ << " loading SSL-only " << "friend: " << peer_id << " " << pitem->location << std::endl; addSslOnlyFriend(peer_id,peer_pgp_id); } else if(!addFriend( peer_id, peer_pgp_id, pitem->netMode, pitem->vs_disc, pitem->vs_dht, pitem->lastContact, RS_NODE_PERM_ALL )) { RsInfo() << __PRETTY_FUNCTION__ << " cannot add friend friend: " << peer_id << " " << pitem->location << ". Somthing's wrong." << std::endl; } setLocation(pitem->nodePeerId, pitem->location); } if (pitem->netMode == RS_NET_MODE_HIDDEN) { /* set only the hidden stuff & localAddress */ setLocalAddress(peer_id, pitem->localAddrV4.addr); setHiddenDomainPort(peer_id, pitem->domain_addr, pitem->domain_port); } else { pqiIpAddrSet addrs; if(!am_I_a_hidden_node) // clear IPs if w're a hidden node. Friend's clear node IPs where previously sent. { setLocalAddress(peer_id, pitem->localAddrV4.addr); setExtAddress(peer_id, pitem->extAddrV4.addr); setDynDNS (peer_id, pitem->dyndns); /* convert addresses */ addrs.mLocal.extractFromTlv(pitem->localAddrList); addrs.mExt.extractFromTlv(pitem->extAddrList); } updateAddressList(peer_id, addrs); } delete(*it); continue; } RsConfigKeyValueSet *vitem = dynamic_cast(*it) ; if (vitem) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::loadList() General Variable Config Item:" << std::endl; vitem->print(std::cerr, 10); std::cerr << std::endl; #endif std::list::iterator kit; for(kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit) { if (kit->key == kConfigKeyExtIpFinder) { useExtAddrFinder = (kit->value == "TRUE"); #ifdef PEER_DEBUG std::cerr << "setting use_extr_addr_finder to " << useExtAddrFinder << std::endl ; #endif } // Tor else if (kit->key == kConfigKeyProxyServerIpAddrTor) { proxyIpAddressTor = kit->value; #ifdef PEER_DEBUG std::cerr << "Loaded proxyIpAddress for Tor: " << proxyIpAddressTor; std::cerr << std::endl ; #endif } else if (kit->key == kConfigKeyProxyServerPortTor) { uint16_t p = atoi(kit->value.c_str()); if(p >= 1024) proxyPortTor = p; #ifdef PEER_DEBUG std::cerr << "Loaded proxyPort for Tor: " << proxyPortTor; std::cerr << std::endl ; #endif } // I2p else if (kit->key == kConfigKeyProxyServerIpAddrI2P) { proxyIpAddressI2P = kit->value; #ifdef PEER_DEBUG std::cerr << "Loaded proxyIpAddress for I2P: " << proxyIpAddressI2P; std::cerr << std::endl ; #endif } else if (kit->key == kConfigKeyProxyServerPortI2P) { uint16_t p = atoi(kit->value.c_str()); if(p >= 1024) proxyPortI2P = p; #ifdef PEER_DEBUG std::cerr << "Loaded proxyPort for I2P: " << proxyPortI2P; std::cerr << std::endl ; #endif } } delete(*it); continue; } RsNodeGroupItem *gitem2 = dynamic_cast(*it) ; if (gitem2) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ #ifdef PEER_DEBUG std::cerr << "p3PeerMgrIMPL::loadList() Peer group item:" << std::endl; gitem->print(std::cerr, 10); std::cerr << std::endl; #endif RsGroupInfo info ; info.peerIds = gitem2->pgpList.ids ; info.id = gitem2->id ; info.name = gitem2->name ; info.flag = gitem2->flag ; std::cerr << "(II) Loaded group in new format. ID = " << info.id << std::endl; groupList[info.id] = info ; delete *it ; continue; } RsPeerBandwidthLimitsItem *pblitem = dynamic_cast(*it) ; if(pblitem) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ #ifdef PEER_DEBUG std::cerr << "Loaded service permission item: " << std::endl; #endif mPeerBandwidthLimits = pblitem->peers ; } RsPeerServicePermissionItem *sitem = dynamic_cast(*it) ; if(sitem) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ #ifdef PEER_DEBUG std::cerr << "Loaded service permission item: " << std::endl; #endif for(uint32_t i=0;ipgp_ids.size();++i) if(AuthPGP::isPGPAccepted(sitem->pgp_ids[i]) || sitem->pgp_ids[i] == AuthPGP::getPgpOwnId()) { mFriendsPermissionFlags[sitem->pgp_ids[i]] = sitem->service_flags[i] ; #ifdef PEER_DEBUG std::cerr << " " << sitem->pgp_ids[i] << " - " << sitem->service_flags[i] << std::endl; #endif } #ifdef PEER_DEBUG else std::cerr << " " << sitem->pgp_ids[i] << " - Not a friend!" << std::endl; #endif } delete (*it); } { /* set missing groupIds */ RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ // Also filter out profiles in groups that are not friends. Normally this shouldn't be needed, but it's a precaution for(auto group_pair:groupList) { for(auto profileIdIt(group_pair.second.peerIds.begin());profileIdIt!=group_pair.second.peerIds.end();) if(AuthPGP::isPGPAccepted(*profileIdIt) || *profileIdIt == AuthPGP::getPgpOwnId()) ++profileIdIt; else { std::cerr << "(WW) filtering out profile " << profileIdIt->toStdString() << " from group " << group_pair.first.toStdString() << " because it is not a friend anymore" << std::endl; auto tmp = profileIdIt; ++tmp; group_pair.second.peerIds.erase(profileIdIt); profileIdIt=tmp; IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); } } } // If we are hidden - don't want ExtAddrFinder - ever! if (isHidden()) useExtAddrFinder = false; mNetMgr->setIPServersEnabled(useExtAddrFinder); // Configure Proxy Server. struct sockaddr_storage proxy_addr; // Tor sockaddr_storage_clear(proxy_addr); sockaddr_storage_ipv4_aton(proxy_addr, proxyIpAddressTor.c_str()); sockaddr_storage_ipv4_setport(proxy_addr, proxyPortTor); if (sockaddr_storage_isValidNet(proxy_addr)) { setProxyServerAddress(RS_HIDDEN_TYPE_TOR, proxy_addr); } // I2P sockaddr_storage_clear(proxy_addr); sockaddr_storage_ipv4_aton(proxy_addr, proxyIpAddressI2P.c_str()); sockaddr_storage_ipv4_setport(proxy_addr, proxyPortI2P); if (sockaddr_storage_isValidNet(proxy_addr)) { setProxyServerAddress(RS_HIDDEN_TYPE_I2P, proxy_addr); } load.clear() ; return true; } #if 0 void printConnectState(std::ostream &out, peerState &peer) { out << "Friend: " << peer.name << " Id: " << peer.id << " State: " << peer.state; if (peer.state & RS_PEER_S_FRIEND) out << " S:RS_PEER_S_FRIEND"; if (peer.state & RS_PEER_S_ONLINE) out << " S:RS_PEER_S_ONLINE"; if (peer.state & RS_PEER_S_CONNECTED) out << " S:RS_PEER_S_CONNECTED"; out << " Actions: " << peer.actions; if (peer.actions & RS_PEER_NEW) out << " A:RS_PEER_NEW"; if (peer.actions & RS_PEER_MOVED) out << " A:RS_PEER_MOVED"; if (peer.actions & RS_PEER_CONNECTED) out << " A:RS_PEER_CONNECTED"; if (peer.actions & RS_PEER_DISCONNECTED) out << " A:RS_PEER_DISCONNECTED"; if (peer.actions & RS_PEER_CONNECT_REQ) out << " A:RS_PEER_CONNECT_REQ"; out << std::endl; return; } #endif /********************************************************************** ********************************************************************** ************************** Groups ************************************ ********************************************************************** **********************************************************************/ bool p3PeerMgrIMPL::addGroup(RsGroupInfo &groupInfo) { { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ do { groupInfo.id = RsNodeGroupId::random(); } while(groupList.find(groupInfo.id) != groupList.end()) ; RsGroupInfo groupItem(groupInfo) ; // remove standard flag groupItem.flag &= ~RS_GROUP_FLAG_STANDARD; groupList[groupInfo.id] = groupItem; std::cerr << "(II) Added new group with ID " << groupInfo.id << ", name=\"" << groupInfo.name << "\"" << std::endl; } RsServer::notify()->notifyListChange(NOTIFY_LIST_GROUPLIST, NOTIFY_TYPE_ADD); IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); return true; } bool p3PeerMgrIMPL::editGroup(const RsNodeGroupId& groupId, RsGroupInfo &groupInfo) { if (groupId.isNull()) return false; bool changed = false; { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ std::map::iterator it = groupList.find(groupId) ; if(it == groupList.end()) { std::cerr << "(EE) cannot find local node group with ID " << groupId << std::endl; return false ; } if (it->second.flag & RS_GROUP_FLAG_STANDARD) { // can't edit standard groups std::cerr << "(EE) cannot edit standard group with ID " << groupId << std::endl; return false ; } else { changed = true; it->second = groupInfo; } } if (changed) { RsServer::notify()->notifyListChange(NOTIFY_LIST_GROUPLIST, NOTIFY_TYPE_MOD); IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); } return changed; } bool p3PeerMgrIMPL::removeGroup(const RsNodeGroupId& groupId) { bool changed = false; { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ std::map::iterator it = groupList.find(groupId) ; if (it != groupList.end()) { if (it->second.flag & RS_GROUP_FLAG_STANDARD) { // can't remove standard groups std::cerr << "(EE) cannot remove standard group with ID " << groupId << std::endl; return false ; } #warning csoler: we need to check that the local group is not used. Otherwise deleting it is going to cause problems! // else if(!it->second.used_gxs_groups.empty()) // { // std::cerr << "(EE) cannot remove standard group with ID " << groupId << " because it is used in the following groups: " << std::endl; // for(std::set::const_iterator it2(it->second.used_gxs_groups.begin());it2!=it->second.used_gxs_groups.end();++it2) // std::cerr << " " << *it2 << std::endl; // // return false ; // } else { changed = true; groupList.erase(it); } } } if (changed) { RsServer::notify()->notifyListChange(NOTIFY_LIST_GROUPLIST, NOTIFY_TYPE_DEL); IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); } return changed; } bool p3PeerMgrIMPL::getGroupInfoByName(const std::string& groupName, RsGroupInfo &groupInfo) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ for(std::map::iterator it = groupList.begin();it!=groupList.end();++it) if(it->second.name == groupName) { groupInfo = it->second ; return true ; } std::cerr << "(EE) getGroupInfoByName: no known group for name " << groupName << std::endl; return false ; } bool p3PeerMgrIMPL::getGroupInfo(const RsNodeGroupId& groupId, RsGroupInfo &groupInfo) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ std::map::iterator it = groupList.find(groupId) ; if(it == groupList.end()) return false ; groupInfo = it->second; return true; } bool p3PeerMgrIMPL::getGroupInfoList(std::list& groupInfoList) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ for(std::map ::const_iterator groupIt = groupList.begin(); groupIt != groupList.end(); ++groupIt) groupInfoList.push_back(groupIt->second) ; return true; } // groupId.isNull() && assign == false -> remove from all groups bool p3PeerMgrIMPL::assignPeersToGroup(const RsNodeGroupId &groupId, const std::list &peerIds, bool assign) { if (groupId.isNull() && assign == true) return false; if (peerIds.empty()) return false; bool changed = false; { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ for (std::map::iterator groupIt = groupList.begin(); groupIt != groupList.end(); ++groupIt) if (groupId.isNull() || groupIt->first == groupId) { RsGroupInfo& groupItem = groupIt->second; for (std::list::const_iterator peerIt = peerIds.begin(); peerIt != peerIds.end(); ++peerIt) { //std::set::iterator peerIt1 = groupItem.peerIds.find(*peerIt); if (assign) { groupItem.peerIds.insert(*peerIt); changed = true; } else { groupItem.peerIds.erase(*peerIt); changed = true; } } if (!groupId.isNull()) break; } } if (changed) { RsServer::notify()->notifyListChange(NOTIFY_LIST_GROUPLIST, NOTIFY_TYPE_MOD); IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); } return changed; } /********************************************************************** ********************************************************************** ******************** Service permission stuff ************************ ********************************************************************** **********************************************************************/ ServicePermissionFlags p3PeerMgrIMPL::servicePermissionFlags(const RsPeerId& ssl_id) { RsPgpId gpg_id ; { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ std::map::const_iterator it = mFriendList.find(ssl_id); if(it == mFriendList.end()) return RS_NODE_PERM_DEFAULT ; gpg_id = it->second.gpg_id ; } return servicePermissionFlags(gpg_id) ; } ServicePermissionFlags p3PeerMgrIMPL::servicePermissionFlags(const RsPgpId& pgp_id) { { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ std::map::const_iterator it = mFriendsPermissionFlags.find( pgp_id ) ; if(it == mFriendsPermissionFlags.end()) return RS_NODE_PERM_DEFAULT ; else return it->second ; } } void p3PeerMgrIMPL::setServicePermissionFlags(const RsPgpId& pgp_id, const ServicePermissionFlags& flags) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ // Check that we have a PGP id. This should not be necessary, but because // we use std::string, anything can get passed down here. // mFriendsPermissionFlags[pgp_id] = flags ; IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); /**** INDICATE MSG CONFIG CHANGED! *****/ } /********************************************************************** ********************************************************************** ******************** Stuff moved from p3peers ************************ ********************************************************************** **********************************************************************/ bool p3PeerMgrIMPL::removeAllFriendLocations(const RsPgpId &gpgid) { std::list sslIds; if (!getAssociatedPeers(gpgid, sslIds)) { return false; } std::list::iterator it; for(it = sslIds.begin(); it != sslIds.end(); ++it) { removeFriend(*it, true); } return true; } bool p3PeerMgrIMPL::getAssociatedPeers(const RsPgpId &gpg_id, std::list &ids) { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ #ifdef PEER_DEBUG std::cerr << "p3PeerMgr::getAssociatedPeers() for id : " << gpg_id << std::endl; #endif int count = 0; std::map::iterator it; for(it = mFriendList.begin(); it != mFriendList.end(); ++it) { if (it->second.gpg_id == gpg_id) { count++; ids.push_back(it->first); #ifdef PEER_DEBUG std::cerr << "p3PeerMgr::getAssociatedPeers() found ssl id : " << it->first << std::endl; #endif } } return (count > 0); } // goes through the list of known friend IPs and remove the ones that are banned by p3LinkMgr. bool p3PeerMgrIMPL::removeBannedIps() { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ #ifdef PEER_DEBUG std::cerr << "Cleaning known IPs for all peers." << std::endl; #endif bool changed = false ; for( std::map::iterator it = mFriendList.begin(); it != mFriendList.end(); ++it) { if(cleanIpList(it->second.ipAddrs.mExt.mAddrs,it->first,mLinkMgr)) changed = true ; if(cleanIpList(it->second.ipAddrs.mLocal.mAddrs,it->first,mLinkMgr)) changed = true ; if(rsBanList!=NULL && !rsBanList->isAddressAccepted(it->second.serveraddr,RSBANLIST_CHECKING_FLAGS_BLACKLIST)) { sockaddr_storage_clear(it->second.serveraddr) ; std::cerr << "(SS) Peer " << it->first << " has a banned server address. Wiping it out." << std::endl; } } if(cleanIpList(mOwnState.ipAddrs.mExt.mAddrs,mOwnState.id,mLinkMgr) ) changed = true ; if(cleanIpList(mOwnState.ipAddrs.mLocal.mAddrs,mOwnState.id,mLinkMgr) ) changed = true ; if(changed) IndicateConfigChanged(RsConfigMgr::CheckPriority::SAVE_OFTEN); return true ; } // /* This only removes SSL certs, that are old... Can end up with no Certs per GPG Id // * We are removing the concept of a "DummyId" - There is no need for it. // */ // // bool isDummyFriend(RsPeerId id) // { // bool ret = (id.substr(0,5) == "dummy"); // return ret; // } /** * @brief p3PeerMgrIMPL::removeUnusedLocations Removes all location offline for RS_PEER_OFFLINE_DELETE seconds or more. Keeps the most recent location per PGP id. * @return true on success * * This function removes all location that are offline for too long defined by RS_PEER_OFFLINE_DELETE. * It also makes sure that at least one location (the most recent) is kept. * * The idea of the function is the following: * - keep track if there is at least one location per PGP id that is not offline for too long * -> hasRecentLocation * - keep track of most recent location per PGP id that is offline for too long (and its time stamp) * -> mostRecentLocation * -> mostRecentTime * * When a location is found that is offline for too long the following points are checked from the top to the bottom: * 1) remove it when the PGP id has a location that is not offline for too long * 2) remove it when the PGP id has a more recent location * 3) keep it when it is the most recent location * This location will possibly be removed when a more recent (but still offline for too long) is found */ bool p3PeerMgrIMPL::removeUnusedLocations() { std::list toRemove; std::map mostRecentTime; const rstime_t now = time(NULL); std::list pgpList ; if (!rsPeers->getGPGAcceptedList(pgpList)) return false ; { RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ // First put a sensible number in all PGP ids for(std::list::const_iterator it = pgpList.begin(); it != pgpList.end(); ++it) mostRecentTime[*it] = (rstime_t)0; #ifdef PEER_DEBUG std::cerr << "p3PeerMgr::removeUnusedLocations()" << std::endl; #endif // Then compute the most recently used location for all PGP ids for( std::map::iterator it = mFriendList.begin(); it != mFriendList.end(); ++it) { rstime_t& bst(mostRecentTime[it->second.gpg_id]) ; bst = std::max(bst,it->second.lastcontact) ; } // And remove all locations that are too old and also older than the most recent location. Doing this we're sure to always keep at least one location per PGP id. for( std::map::iterator it = mFriendList.begin(); it != mFriendList.end(); ++it) { if (now > it->second.lastcontact + RS_PEER_OFFLINE_DELETE && it->second.lastcontact < mostRecentTime[it->second.gpg_id]) toRemove.push_back(it->first); #ifdef PEER_DEBUG std::cerr << "Location " << it->first << " PGP id " << it->second.gpg_id << " last contact " << it->second.lastcontact << " remove: " << (now > it->second.lastcontact + RS_PEER_OFFLINE_DELETE) << " most recent: " << mostRecentTime[it->second.gpg_id] << ". Final result remove: " << (it->second.lastcontact < mostRecentTime[it->second.gpg_id] && now > it->second.lastcontact + RS_PEER_OFFLINE_DELETE )<< std::endl; #endif } } for (std::list::iterator it = toRemove.begin(); it != toRemove.end(); ++it) removeFriend(*it, false) ; return true; } p3PeerMgr::~p3PeerMgr() = default;