diff --git a/src/crypto/hashstream.cc b/src/crypto/hashstream.cc index 1d3c46b75..e1c39a60c 100644 --- a/src/crypto/hashstream.cc +++ b/src/crypto/hashstream.cc @@ -54,7 +54,12 @@ namespace librs return Sha1CheckSum(h); } - + template<> + HashStream& operator<<(HashStream& u,const std::pair& p) + { + EVP_DigestUpdate(u.mdctx,p.first,p.second) ; + return u; + } template<> HashStream& operator<<(HashStream& u,const std::string& s) { diff --git a/src/friend_server/fsclient.cc b/src/friend_server/fsclient.cc new file mode 100644 index 000000000..4104b0e6a --- /dev/null +++ b/src/friend_server/fsclient.cc @@ -0,0 +1,202 @@ +/******************************************************************************* + * libretroshare/src/file_sharing: fsclient.cc * + * * + * libretroshare: retroshare core library * + * * + * Copyright 2021 by retroshare team * + * * + * 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 "pqi/pqithreadstreamer.h" +#include "retroshare/rspeers.h" + +#include "fsclient.h" +#include "pqi/pqifdbin.h" +#include "pqi/pqiproxy.h" + +bool FsClient::requestFriends(const std::string& address,uint16_t port, + const std::string& proxy_address,uint16_t proxy_port, + uint32_t reqs,std::map& friend_certificates) +{ + // send our own certificate to publish and expects response frmo the server , decrypts it and reutnrs friend list + + RsFriendServerClientPublishItem *pitem = new RsFriendServerClientPublishItem(); + + pitem->n_requested_friends = reqs; + + std::string pgp_base64_string,pgp_base64_checksum,short_invite; + rsPeers->GetPGPBase64StringAndCheckSum(rsPeers->getGPGOwnId(),pgp_base64_string,pgp_base64_checksum); + + if(!rsPeers->getShortInvite(short_invite,RsPeerId(),RetroshareInviteFlags::RADIX_FORMAT | RetroshareInviteFlags::DNS)) + { + RsErr() << "Cannot request own short invite! Something's very wrong." ; + return false; + } + + pitem->pgp_public_key_b64 = pgp_base64_string; + pitem->short_invite = short_invite; + + std::list response; + sendItem(address,port,proxy_address,proxy_port,pitem,response); + + // now decode the response + + friend_certificates.clear(); + + for(auto item:response) + { + // auto *encrypted_response_item = dynamic_cast(item); + + // if(!encrypted_response_item) + // { + // delete item; + // continue; + // } + + // For now, also handle unencrypted response items. Will be disabled in production + + auto *response_item = dynamic_cast(item); + + if(response_item) + handleServerResponse(response_item); + + delete item; + } + return friend_certificates.size(); +} + +void FsClient::handleServerResponse(RsFriendServerServerResponseItem *item) +{ + std::cerr << "Received a response item from server: " << std::endl; + std::cerr << *item << std::endl; + + // for(const auto& it:response_item->friend_invites) + // friend_certificates.insert(it); +} + +bool FsClient::sendItem(const std::string& server_address,uint16_t server_port, + const std::string& proxy_address,uint16_t proxy_port, + RsItem *item,std::list& response) +{ + // open a connection + + RsDbg() << "Sending item to friend server at \"" << server_address << ":" << server_port << " through proxy " << proxy_address << ":" << proxy_port; + + int CreateSocket = 0; + char dataReceived[1024]; + struct sockaddr_in ipOfServer; + + memset(dataReceived, '0' ,sizeof(dataReceived)); + + if((CreateSocket = socket(AF_INET, SOCK_STREAM, 0))< 0) + { + printf("Socket not created \n"); + return 1; + } + + ipOfServer.sin_family = AF_INET; + ipOfServer.sin_port = htons(proxy_port); + ipOfServer.sin_addr.s_addr = inet_addr(proxy_address.c_str()); + + if(connect(CreateSocket, (struct sockaddr *)&ipOfServer, sizeof(ipOfServer))<0) + { + printf("Connection to proxy failed due to port and ip problems, or proxy is not available\n"); + return false; + } + + // Now connect to the proxy + + int ret=0; + pqiproxyconnection proxy; + proxy.setRemoteAddress(server_address); + proxy.setRemotePort(server_port); + + while(1 != (ret = proxy.proxy_negociate_connection(CreateSocket))) + if(ret < 0) + { + RsErr() << "FriendServer client: Connection problem to the proxy!" ; + return false; + } + else + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + + // Serialise the item and send it. + + FsSerializer *fss = new FsSerializer; + RsSerialiser *rss = new RsSerialiser(); // deleted by ~pqistreamer() + rss->addSerialType(fss); + + RsFdBinInterface *bio = new RsFdBinInterface(CreateSocket,true); // deleted by ~pqistreamer() + + pqithreadstreamer p(this,rss,RsPeerId(),bio,BIN_FLAGS_READABLE | BIN_FLAGS_WRITEABLE | BIN_FLAGS_NO_CLOSE); + p.start(); + + uint32_t ss; + p.SendItem(item,ss); + + RsDbg() << "Item sent. Waiting for response..." ; + + // Now attempt to read and deserialize anything that comes back from that connexion until it gets closed by the server. + + while(true) + { + p.tick(); // ticks bio + + RsItem *item = GetItem(); +#ifdef DEBUG_FSCLIENT + RsDbg() << "Ticking for response..."; +#endif + if(item) + { + response.push_back(item); + std::cerr << "Got a response item: " << std::endl; + std::cerr << *item << std::endl; + + RsDbg() << "End of transmission. " ; + break; + } + else + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + } + + RsDbg() << " Stopping/killing pqistreamer" ; + p.fullstop(); + + RsDbg() << " Closing socket." ; + close(CreateSocket); + CreateSocket=0; + + RsDbg() << " Exiting loop." ; + + return true; +} + +bool FsClient::RecvItem(RsItem *item) +{ + mIncomingItems.push_back(item); + return true; +} + +RsItem *FsClient::GetItem() +{ + if(mIncomingItems.empty()) + return nullptr; + + RsItem *item = mIncomingItems.front(); + mIncomingItems.pop_front(); + + return item; +} diff --git a/src/friend_server/fsclient.h b/src/friend_server/fsclient.h new file mode 100644 index 000000000..b682a8bc4 --- /dev/null +++ b/src/friend_server/fsclient.h @@ -0,0 +1,54 @@ +/******************************************************************************* + * libretroshare/src/file_sharing: fsclient.h * + * * + * libretroshare: retroshare core library * + * * + * Copyright 2021 by retroshare team * + * * + * 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 +#include "fsitem.h" +#include "pqi/pqi_base.h" + +// This class runs a client connection to the friend server. It opens a socket at each connection. + +class FsClient: public PQInterface +{ +public: + FsClient() :PQInterface(RsPeerId()) {} + + bool requestFriends(const std::string& address, uint16_t port, + const std::string &proxy_address, uint16_t proxy_port, + uint32_t reqs, std::map& friend_certificates); + +protected: + // Implements PQInterface + + bool RecvItem(RsItem *item) override; + int SendItem(RsItem *) override { RsErr() << "FsClient::SendItem() called although it should not." ; return 0;} + RsItem *GetItem() override; + +private: + bool sendItem(const std::string &server_address, uint16_t server_port, + const std::string &proxy_address, uint16_t proxy_port, + RsItem *item, std::list &response); + + void handleServerResponse(RsFriendServerServerResponseItem *item); + + std::list mIncomingItems; +}; + diff --git a/src/friend_server/fsitem.h b/src/friend_server/fsitem.h new file mode 100644 index 000000000..95522b550 --- /dev/null +++ b/src/friend_server/fsitem.h @@ -0,0 +1,185 @@ +/******************************************************************************* + * libretroshare/src/file_sharing: fsitem.h * + * * + * libretroshare: retroshare core library * + * * + * Copyright 2021 by retroshare team * + * * + * 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 . * + * * + ******************************************************************************/ + +#pragma once + +#include "serialiser/rsserial.h" +#include "serialiser/rsserializer.h" + +#include "rsitems/rsitem.h" +#include "serialiser/rstlvbinary.h" +#include "rsitems/rsserviceids.h" +#include "rsitems/itempriorities.h" + +const uint8_t RS_PKT_SUBTYPE_FS_CLIENT_PUBLISH = 0x01 ; +const uint8_t RS_PKT_SUBTYPE_FS_CLIENT_REMOVE = 0x02 ; +const uint8_t RS_PKT_SUBTYPE_FS_SERVER_RESPONSE = 0x03 ; +const uint8_t RS_PKT_SUBTYPE_FS_SERVER_ENCRYPTED_RESPONSE = 0x04 ; +const uint8_t RS_PKT_SUBTYPE_FS_SERVER_STATUS = 0x05 ; + +class RsFriendServerItem: public RsItem +{ +public: + RsFriendServerItem(uint8_t item_subtype) : RsItem(RS_PKT_VERSION_SERVICE,RS_SERVICE_TYPE_FRIEND_SERVER,item_subtype) + { + setPriorityLevel(QOS_PRIORITY_DEFAULT) ; + } + virtual ~RsFriendServerItem() {} + virtual void clear() override {} +}; + +class RsFriendServerClientPublishItem: public RsFriendServerItem +{ +public: + RsFriendServerClientPublishItem() : RsFriendServerItem(RS_PKT_SUBTYPE_FS_CLIENT_PUBLISH) {} + + void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) override + { + RS_SERIAL_PROCESS(n_requested_friends); + RS_SERIAL_PROCESS(short_invite); + RS_SERIAL_PROCESS(pgp_public_key_b64); + } + virtual void clear() override + { + pgp_public_key_b64.clear(); + short_invite.clear(); + n_requested_friends=0; + } + + // specific members for that item + + uint32_t n_requested_friends; + std::string short_invite; + std::string pgp_public_key_b64; +}; + +class RsFriendServerStatusItem: public RsFriendServerItem +{ +public: + RsFriendServerStatusItem() : RsFriendServerItem(RS_PKT_SUBTYPE_FS_SERVER_STATUS) {} + + void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) override + { + RS_SERIAL_PROCESS(status); + } + + enum ConnectionStatus: uint8_t + { + UNKNOWN = 0x00, + END_OF_TRANSMISSION = 0x01 + }; + + // specific members for that item + + ConnectionStatus status; +}; + +class RsFriendServerClientRemoveItem: public RsFriendServerItem +{ +public: + RsFriendServerClientRemoveItem() : RsFriendServerItem(RS_PKT_SUBTYPE_FS_CLIENT_REMOVE) {} + + void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) + { + RS_SERIAL_PROCESS(peer_id); + RS_SERIAL_PROCESS(nonce); + } + + // Peer ID for the peer to remove. + + RsPeerId peer_id; + + // Nonce that was returned by the server after the last client request. Should match in order to proceed. This prevents + // a malicious actor from removing peers from the server. Since the nonce is sent through Tor tunnels, it cannot be known by + // anyone else than the client. + + uint64_t nonce; +}; + +class RsFriendServerEncryptedServerResponseItem: public RsFriendServerItem +{ +public: + RsFriendServerEncryptedServerResponseItem() : RsFriendServerItem(RS_PKT_SUBTYPE_FS_SERVER_ENCRYPTED_RESPONSE) {} + + void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) override + { + RsTypeSerializer::RawMemoryWrapper prox(bin_data, bin_len); + RsTypeSerializer::serial_process(j, ctx, prox, "data"); + } + + virtual void clear() override + { + free(bin_data); + bin_len = 0; + bin_data = nullptr; + } + // + + void *bin_data; + uint32_t bin_len; +}; + +class RsFriendServerServerResponseItem: public RsFriendServerItem +{ +public: + RsFriendServerServerResponseItem() : RsFriendServerItem(RS_PKT_SUBTYPE_FS_SERVER_RESPONSE) {} + + void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) override + { + RS_SERIAL_PROCESS(nonce); + RS_SERIAL_PROCESS(friend_invites); + } + + virtual void clear() override + { + friend_invites.clear(); + nonce = 0; + } + // specific members for that item + + uint64_t nonce; + std::map friend_invites; +}; + +struct FsSerializer : RsServiceSerializer +{ + FsSerializer(RsSerializationFlags flags = RsSerializationFlags::NONE): RsServiceSerializer(RS_SERVICE_TYPE_FRIEND_SERVER, flags) {} + + virtual RsItem *create_item(uint16_t service_id,uint8_t item_sub_id) const + { + if(service_id != static_cast(RsServiceType::FRIEND_SERVER)) + return nullptr; + + switch(item_sub_id) + { + case RS_PKT_SUBTYPE_FS_CLIENT_REMOVE: return new RsFriendServerClientRemoveItem(); + case RS_PKT_SUBTYPE_FS_CLIENT_PUBLISH: return new RsFriendServerClientPublishItem(); + case RS_PKT_SUBTYPE_FS_SERVER_RESPONSE: return new RsFriendServerServerResponseItem(); + case RS_PKT_SUBTYPE_FS_SERVER_STATUS: return new RsFriendServerStatusItem(); + case RS_PKT_SUBTYPE_FS_SERVER_ENCRYPTED_RESPONSE: return new RsFriendServerEncryptedServerResponseItem(); + default: + RsErr() << "Unknown subitem type " << item_sub_id << " in FsSerialiser" ; + return nullptr; + } + + } +}; diff --git a/src/friend_server/fsmanager.cc b/src/friend_server/fsmanager.cc new file mode 100644 index 000000000..ff6571ef7 --- /dev/null +++ b/src/friend_server/fsmanager.cc @@ -0,0 +1,123 @@ +#include +#include "fsmanager.h" +#include "fsclient.h" + +RsFriendServer *rsFriendServer = nullptr; + +static const rstime_t MIN_DELAY_BETWEEN_FS_REQUESTS = 30; +static const rstime_t MAX_DELAY_BETWEEN_FS_REQUESTS = 3600; +static const uint32_t DEFAULT_FRIENDS_TO_REQUEST = 10; + +static const std::string DEFAULT_PROXY_ADDRESS = "127.0.0.1"; +static const uint16_t DEFAULT_FRIEND_SERVER_PORT = 2017; +static const uint16_t DEFAULT_PROXY_PORT = 9050; + +FriendServerManager::FriendServerManager() +{ + mLastFriendReqestCampain = 0; + mFriendsToRequest = DEFAULT_FRIENDS_TO_REQUEST; + + mProxyAddress = DEFAULT_PROXY_ADDRESS; + mProxyPort = DEFAULT_PROXY_PORT; + mServerPort = DEFAULT_FRIEND_SERVER_PORT; +} +void FriendServerManager::startServer() +{ + if(!isRunning()) + { + std::cerr << "Starting Friend Server Manager." << std::endl; + RsTickingThread::start() ; + } +} +void FriendServerManager::stopServer() +{ + if(isRunning() && !shouldStop()) + { + std::cerr << "Stopping Friend Server Manager." << std::endl; + RsTickingThread::askForStop() ; + } +} +void FriendServerManager::checkServerAddress_async(const std::string& addr,uint16_t, const std::function& callback) +{ +#warning TODO + std::this_thread::sleep_for(std::chrono::seconds(1)); + + callback(addr,true); +} + +void FriendServerManager::setServerAddress(const std::string& addr,uint16_t port) +{ + mServerAddress = addr; + mServerPort = port; +} +void FriendServerManager::setProxyAddress(const std::string& addr,uint16_t port) +{ + mProxyAddress = addr; + mProxyPort = port; +} +void FriendServerManager::setFriendsToRequest(uint32_t n) +{ + mFriendsToRequest = n; +} + +void FriendServerManager::threadTick() +{ + std::cerr << "Ticking FriendServerManager..." << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(2)); + + if(mServerAddress.empty()) + { + RsErr() << "No friend server address has been setup. This is probably a bug."; + return; + } + // Check for requests. Compute how much to wait based on how many friends we have already + + std::vector friends; + rsPeers->getPgpFriendList(friends); + + // log-scale interpolation of the delay between two requests. + + if(mFriendsToRequest == 0 || mFriendsToRequest < friends.size()) + { + RsErr() << "No friends to request! This is unexpected. Returning." << std::endl; + return; + } + + // This formula makes RS wait much longuer between two requests to the server when the number of friends is close the + // wanted number + // Delay for 0 friends: 30 secs. + // Delay for 1 friends: 30 secs. + // Delay for 2 friends: 32 secs. + // Delay for 3 friends: 35 secs. + // Delay for 4 friends: 44 secs. + // Delay for 5 friends: 66 secs. + // Delay for 6 friends: 121 secs. + // Delay for 7 friends: 258 secs. + // Delay for 8 friends: 603 secs. + // Delay for 9 friends: 1466 secs. + + RsDbg() << friends.size() << " friends already, " << mFriendsToRequest << " friends to request"; + + double s = (friends.size() < mFriendsToRequest)? ( (mFriendsToRequest - friends.size())/(double)mFriendsToRequest) : 1.0; + rstime_t delay_for_request = MIN_DELAY_BETWEEN_FS_REQUESTS + (int)floor(exp(-1*s + log(MAX_DELAY_BETWEEN_FS_REQUESTS)*(1.0-s))); + + std::cerr << "Delay for " << friends.size() << " friends: " << delay_for_request << " secs." << std::endl; + + rstime_t now = time(nullptr); + + if(mLastFriendReqestCampain + delay_for_request < now) + { + mLastFriendReqestCampain = now; + + std::cerr << "Requesting new friends to friend server..." << std::endl; + + std::map friend_certificates; + FsClient().requestFriends(mServerAddress,mServerPort,mProxyAddress,mProxyPort,mFriendsToRequest,friend_certificates); // blocking call + + std::cerr << "Got the following list of friend certificates:" << std::endl; + + for(const auto& it:friend_certificates) + std::cerr << it.first << " : " << it.second << std::endl; + } +} + diff --git a/src/friend_server/fsmanager.h b/src/friend_server/fsmanager.h new file mode 100644 index 000000000..583a5febc --- /dev/null +++ b/src/friend_server/fsmanager.h @@ -0,0 +1,51 @@ +#include + +#include "util/rsthreads.h" +#include "retroshare/rsfriendserver.h" +#include "retroshare/rspeers.h" + +struct FriendServerPeerInfo +{ + enum FriendServerPeerStatus: uint8_t + { + UNKNOWN = 0x00, + LOCALLY_ACCEPTED = 0x01, + HAS_ACCEPTED_ME = 0x02, + ALREADY_CONNECTED = 0x03 + }; + + uint32_t status ; + rstime_t received_TS; +}; + +class FriendServerManager: public RsFriendServer, public RsTickingThread +{ +public: + FriendServerManager(); + + virtual void startServer() override ; + virtual void stopServer() override ; + + virtual void checkServerAddress_async(const std::string& addr,uint16_t, const std::function& callback) override ; + virtual void setServerAddress(const std::string&,uint16_t) override ; + virtual void setProxyAddress(const std::string&,uint16_t) override ; + virtual void setFriendsToRequest(uint32_t) override ; + + virtual uint32_t friendsToRequest() override { return mFriendsToRequest ; } + virtual uint16_t friendsServerPort() override { return mServerPort ; } + virtual std::string friendsServerAddress() override { return mServerAddress ; } +protected: + virtual void threadTick() override; + +private: + uint32_t mFriendsToRequest; + rstime_t mLastFriendReqestCampain; + + // encode the current list of friends obtained through the friendserver and their status + + std::map mPeers; + std::string mServerAddress ; + uint16_t mServerPort; + std::string mProxyAddress ; + uint16_t mProxyPort; +}; diff --git a/src/libretroshare.pro b/src/libretroshare.pro index 4f23ecc6c..4d84b6fc7 100644 --- a/src/libretroshare.pro +++ b/src/libretroshare.pro @@ -391,6 +391,7 @@ HEADERS += pqi/authssl.h \ pqi/pqissl.h \ pqi/pqissllistener.h \ pqi/pqisslpersongrp.h \ + pqi/pqiproxy.h \ pqi/pqisslproxy.h \ pqi/pqistore.h \ pqi/pqistreamer.h \ @@ -559,6 +560,7 @@ SOURCES += pqi/authgpg.cc \ pqi/pqissl.cc \ pqi/pqissllistener.cc \ pqi/pqisslpersongrp.cc \ + pqi/pqiproxy.cc \ pqi/pqisslproxy.cc \ pqi/pqistore.cc \ pqi/pqistreamer.cc \ @@ -825,6 +827,22 @@ wikipoos { rsitems/rswikiitems.cc \ } +# Friend server + +rs_efs { + DEFINES *= RS_EMBEDED_FRIEND_SERVER + + HEADERS += friend_server/fsclient.h \ + friend_server/fsitem.h \ + friend_server/fsmanager.h \ + retroshare/rsfriendserver.h + + SOURCES += friend_server/fsclient.cc \ + friend_server/fsmanager.cc +} + +# The Wire + gxsthewire { DEFINES *= RS_USE_WIRE diff --git a/src/pgp/openpgpsdkhandler.cc b/src/pgp/openpgpsdkhandler.cc index c6d6da764..c619ca4c5 100644 --- a/src/pgp/openpgpsdkhandler.cc +++ b/src/pgp/openpgpsdkhandler.cc @@ -1642,7 +1642,10 @@ bool OpenPGPSDKHandler::locked_syncPublicKeyring() #else if(-1 == stat64(_pubring_path.c_str(), &buf)) #endif + { RsErr() << "OpenPGPSDKHandler::syncDatabase(): can't stat file " << _pubring_path << ". Can't sync public keyring." ; + buf.st_mtime = 0; + } if(_pubring_last_update_time < buf.st_mtime) { diff --git a/src/pgp/pgphandler.cc b/src/pgp/pgphandler.cc index 850338868..2d3625f24 100644 --- a/src/pgp/pgphandler.cc +++ b/src/pgp/pgphandler.cc @@ -357,12 +357,13 @@ bool PGPHandler::locked_syncTrustDatabase() librs::util::ConvertUtf8ToUtf16(_trustdb_path, wfullname); if(-1 == _wstati64(wfullname.c_str(), &buf)) #else - if(-1 == stat64(_trustdb_path.c_str(), &buf)) + if(-1 == stat64(_trustdb_path.c_str(), &buf)) #endif - { - RsErr() << "PGPHandler::syncDatabase(): can't stat file " << _trustdb_path << ". Will force write it." ; - _trustdb_changed = true ; // we force write of trust database if it does not exist. - } + { + RsErr() << "PGPHandler::syncDatabase(): can't stat file " << _trustdb_path << ". Will force write it." ; + _trustdb_changed = true ; // we force write of trust database if it does not exist. + buf.st_mtime = 0; + } if(_trustdb_last_update_time < buf.st_mtime) { diff --git a/src/pgp/pgpkeyutil.cc b/src/pgp/pgpkeyutil.cc index 76b332edf..105556ebb 100644 --- a/src/pgp/pgpkeyutil.cc +++ b/src/pgp/pgpkeyutil.cc @@ -21,6 +21,7 @@ *******************************************************************************/ #include #include +#include #include "pgpkeyutil.h" #include @@ -181,6 +182,59 @@ uint32_t PGPKeyManagement::compute24bitsCRC(unsigned char *octets, size_t len) return crc & 0xFFFFFFL; } +bool PGPKeyManagement::parsePGPPublicKey(const unsigned char *keydata, size_t keylen, PGPKeyInfo& info) +{ +#ifdef DEBUG_PGPUTIL + std::cerr << "Total size: " << keylen << std::endl; +#endif + unsigned char *data = (unsigned char*)keydata; + + uint8_t packet_tag; + uint32_t packet_length ; + + PGPKeyParser::read_packetHeader(data,packet_tag,packet_length) ; + +#ifdef DEBUG_PGPUTIL + std::cerr << "Packet tag : " << (int)packet_tag << ", length=" << packet_length << std::endl; +#endif + if(packet_tag != PGPKeyParser::PGP_PACKET_TAG_PUBLIC_KEY) + { + std::cerr << "(EE) Parsing error in PGP public key. Expected a public key tag (6). Found " << (int)packet_tag << " instead." << std::endl; + return false; + } + librs::crypto::HashStream H(librs::crypto::HashStream::SHA1); + + H << (uint8_t)0x99; // RFC_4880 + + std::cerr << "Packet length = " << packet_length << std::endl; + + H << (uint8_t)(packet_length >> 8); + H << (uint8_t)(packet_length); + H << std::make_pair(data,packet_length) ; + + auto hash = H.hash(); + + memcpy(info.fingerprint, hash.toByteArray(),hash.SIZE_IN_BYTES); + + data += packet_length; + + // Read user ID. + + PGPKeyParser::read_packetHeader(data,packet_tag,packet_length) ; + + if(packet_tag != PGPKeyParser::PGP_PACKET_TAG_USER_ID) + { + std::cerr << "(EE) Parsing error in PGP public key. Expected a user ID key tag (13). Found " << (int)packet_tag << " instead." << std::endl; + return false; + } + + info.user_id.clear(); + + for(uint32_t i=0;i #include #include +#include #include "rscertificate.h" #include "util/rsstring.h" #include "util/stacktrace.h" @@ -619,6 +620,140 @@ bool RsCertificate::cleanRadix64(const std::string& instr,std::string& str,uint3 return true ; } +bool RsCertificate::decodeRadix64ShortInvite(const std::string& rsInvite, RsPeerDetails& details, uint32_t& err_code) +{ + err_code = 0; + std::vector bf = Radix64::decode(rsInvite); + size_t size = bf.size(); + + unsigned char* buf = bf.data(); + size_t total_s = 0; + bool CRC_ok = false ; // not checked yet + + while(total_s < size) + { + RsShortInviteFieldType ptag = RsShortInviteFieldType(buf[0]); + buf = &buf[1]; + + unsigned char *buf2 = buf; + uint32_t s = 0; + + try { s = PGPKeyParser::read_125Size(buf); } + catch (...) + { + err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR; + return false; + } + + total_s += 1 + ( reinterpret_cast(buf) - reinterpret_cast(buf2) ); + + if(total_s > size) + { + err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR; + return false; + } + + Dbg3() << __PRETTY_FUNCTION__ << " Read ptag: " + << static_cast(ptag) + << ", size " << s << ", total_s = " << total_s + << ", expected total = " << size << std::endl; + + switch(ptag) + { + case RsShortInviteFieldType::SSL_ID: + details.id = RsPeerId::fromBufferUnsafe(buf) ; + break; + + case RsShortInviteFieldType::PEER_NAME: + details.name = std::string((char*)buf,s); + break; + + case RsShortInviteFieldType::PGP_FINGERPRINT: + details.fpr = RsPgpFingerprint::fromBufferUnsafe(buf); + details.gpg_id = PGPHandler::pgpIdFromFingerprint(details.fpr); + break; + + case RsShortInviteFieldType::LOCATOR: + { + std::string locatorStr((char*)buf,s); + details.ipAddressList.push_back(locatorStr); + } + break; + + case RsShortInviteFieldType::DNS_LOCATOR: + details.extPort = (((int)buf[0]) << 8) + buf[1]; + details.dyndns = std::string((char*)&buf[2],s-2); + break; + + case RsShortInviteFieldType::LOC4_LOCATOR: + { + uint32_t t4Addr = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3]; + sockaddr_in tLocalAddr; + tLocalAddr.sin_addr.s_addr = t4Addr; + + details.localAddr = rs_inet_ntoa(tLocalAddr.sin_addr); + details.localPort = (((uint32_t)buf[4])<<8) + (uint32_t)buf[5]; + } + break; + + case RsShortInviteFieldType::EXT4_LOCATOR: + { + uint32_t t4Addr = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3]; + sockaddr_in tExtAddr; + tExtAddr.sin_addr.s_addr = t4Addr; + + details.extAddr = rs_inet_ntoa(tExtAddr.sin_addr); + details.extPort = (((uint32_t)buf[4])<<8) + (uint32_t)buf[5]; + } + break; + + case RsShortInviteFieldType::HIDDEN_LOCATOR: + details.hiddenType = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3]; + details.hiddenNodePort = (((uint32_t)buf[4]) << 8)+ (uint32_t)buf[5]; + details.isHiddenNode = true; + details.hiddenNodeAddress = std::string((char*)&buf[6],s-6); + break; + + case RsShortInviteFieldType::CHECKSUM: + { + if(s != 3 || total_s+3 != size) // make sure the checksum is the last section + { + err_code = CERTIFICATE_PARSING_ERROR_INVALID_CHECKSUM_SECTION; + return false; + } + uint32_t computed_crc = PGPKeyManagement::compute24bitsCRC(bf.data(),size-5); + uint32_t certificate_crc = static_cast( buf[0] + (buf[1] << 8) + (buf[2] << 16) ); + + if(computed_crc != certificate_crc) + { + err_code = CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR; + return false; + } + CRC_ok = true; + break; + } + + } + + buf = &buf[s]; + total_s += s; + } + + if(details.id.isNull()) + { + err_code = CERTIFICATE_PARSING_ERROR_MISSING_LOCATION_ID; + return false; + } + if(!CRC_ok) + { + err_code = CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR; + return false; + } + + return true; +} + + diff --git a/src/pgp/rscertificate.h b/src/pgp/rscertificate.h index 977493e69..28e3c2bae 100644 --- a/src/pgp/rscertificate.h +++ b/src/pgp/rscertificate.h @@ -36,6 +36,21 @@ struct RsPeerDetails; class RsCertificate { public: + enum class RsShortInviteFieldType : uint8_t + { + SSL_ID = 0x00, + PEER_NAME = 0x01, + LOCATOR = 0x02, + PGP_FINGERPRINT = 0x03, + CHECKSUM = 0x04, + + /* The following will be deprecated, and ported to LOCATOR when generic transport layer will be implemented */ + HIDDEN_LOCATOR = 0x90, + DNS_LOCATOR = 0x91, + EXT4_LOCATOR = 0x92, // external IPv4 address + LOC4_LOCATOR = 0x93 // local IPv4 address + }; + typedef enum { RS_CERTIFICATE_OLD_FORMAT, RS_CERTIFICATE_RADIX, RS_CERTIFICATE_SHORT_RADIX } Format; /** @@ -64,6 +79,8 @@ public: ~RsCertificate(); + static bool decodeRadix64ShortInvite(const std::string& short_invite_b64,RsPeerDetails& det,uint32_t& error_code); + /// Convert to certificate radix string std::string toStdString() const; diff --git a/src/pqi/pqi_base.h b/src/pqi/pqi_base.h index 51980b501..72d5d540b 100644 --- a/src/pqi/pqi_base.h +++ b/src/pqi/pqi_base.h @@ -280,7 +280,8 @@ public: * Sends data to a prescribed location (implementation dependent) *@param data what will be sent *@param len the size of data pointed to in memory - */ + *@returns total number of bytes actually sent + */ virtual int senddata(void *data, int len) = 0; /** diff --git a/src/pqi/pqifdbin.cc b/src/pqi/pqifdbin.cc index 20c2451f0..5ba6af155 100644 --- a/src/pqi/pqifdbin.cc +++ b/src/pqi/pqifdbin.cc @@ -236,6 +236,7 @@ int RsFdBinInterface::readline(void *data, int len) return 0; } + int RsFdBinInterface::readdata(void *data, int len) { // read incoming bytes in the buffer diff --git a/src/pqi/pqiproxy.cc b/src/pqi/pqiproxy.cc new file mode 100644 index 000000000..008466847 --- /dev/null +++ b/src/pqi/pqiproxy.cc @@ -0,0 +1,469 @@ +#include "util/rsdebug.h" +#include "util/rsnet.h" + +#include "pqi/pqiproxy.h" + +//#define PROXY_DEBUG 1 + +int pqiproxyconnection::proxy_negociate_connection(int sockfd) +{ + int ret = 0; + switch(mProxyState) + { + case PROXY_STATE_INIT: + ret = Proxy_Send_Method(sockfd); // checks basic conn, sends Method when able. + break; + + case PROXY_STATE_WAITING_METHOD_RESPONSE: + ret = Proxy_Send_Address(sockfd); // waits for Method Response, send Address when able. + break; + + case PROXY_STATE_WAITING_SOCKS_RESPONSE: + ret = Proxy_Connection_Complete(sockfd); // wait for ACK. + + if(ret < 1) + break; + + case PROXY_STATE_CONNECTION_COMPLETE: + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Basic_Connection_Complete() COMPLETED"; + std::cerr << std::endl; +#endif + + return 1; + + case PROXY_STATE_FAILED: + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Basic_Connection_Complete() FAILED"; + std::cerr << std::endl; +#endif + + return -1; + } + + if(ret < 0) + return -1; + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Basic_Connection_Complete() IN PROGRESS"; + std::cerr << std::endl; +#endif + + // In Progress. + return 0; +} + + +int pqiproxyconnection::Proxy_Send_Method(int sockfd) +{ + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Send_Method() Basic complete, sending Method"; + std::cerr << std::endl; +#endif + + /* send hello to proxy server */ + char method_hello_data[3] = { 0x05, 0x01, 0x00 }; // [ Ver | nMethods (1) | No Auth Method ] + + int sent = send(sockfd, method_hello_data, 3, 0); + if (sent != 3) + { + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Send_Method() Send Failure"; + std::cerr << std::endl; +#endif + return -1; + } + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Send_Method() Send Method Okay"; + std::cerr << std::endl; +#endif + + mProxyState = PROXY_STATE_WAITING_METHOD_RESPONSE; + + return 1; +} + +int pqiproxyconnection::Proxy_Method_Response(int sockfd) +{ + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Method_Response()"; + std::cerr << std::endl; +#endif + + /* get response from proxy server */ + + char method_response[2]; + + /* + first it was: + + int recvd = recv(sockfd, method_response, 2, MSG_WAITALL); + + this does not work on windows, because the socket is in nonblocking mode + the winsock reference says about the recv function and MSG_WAITALL: + + "Note that if the underlying transport does not support MSG_WAITALL, + or if the socket is in a non-blocking mode, then this call will fail with WSAEOPNOTSUPP." + + now it is a two step process: + + int recvd = recv(sockfd, method_response, 2, MSG_PEEK); // test how many bytes are in the input queue + if (enaugh bytes available){ + recvd = recv(sockfd, method_response, 2, 0); + } + + this does not work on windows: + if ((recvd == -1) && (errno == EAGAIN)) return TRY_AGAIN_LATER; + + instead have to do: + if ((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK)) return TRY_AGAIN_LATER; + */ + + // test how many bytes can be read from the queue + int recvd = recv(sockfd, method_response, 2, MSG_PEEK); + if (recvd != 2) + { +#ifdef WINDOWS_SYS + if ((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK)) + { +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Method_Response() waiting for more data (windows)"; + std::cerr << std::endl; +#endif + return 0; + } +#endif + if ((recvd == -1) && (errno == EAGAIN)) + { + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Method_Response() EAGAIN"; + std::cerr << std::endl; +#endif + + return 0; + } + else if (recvd == -1) + { +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Method_Response() recv error peek"; + std::cerr << std::endl; +#endif + return -1; + } + else + { +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Method_Response() waiting for more data"; + std::cerr << std::endl; +#endif + return 0; + } + } + + // read the bytes + recvd = recv(sockfd, method_response, 2, 0); + if (recvd != 2) + { +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Method_Response() recv error"; + std::cerr << std::endl; +#endif + return -1; + } + + // does it make sense? + if (method_response[0] != 0x05) + { + + // Error. +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Method_Response() Error response[0] != 0x05. Is: "; + std::cerr << (uint32_t) method_response[0]; + std::cerr << std::endl; +#endif + return -1; + } + + if (method_response[1] != 0x00) + { + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Method_Response() Error response[0] != 0x00. Is: "; + std::cerr << (uint32_t) method_response[1]; + std::cerr << std::endl; +#endif + // Error. + return -1; + } + + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Method_Response() Response Okay"; + std::cerr << std::endl; +#endif + + return 1; +} + +#define MAX_SOCKS_REQUEST_LEN 262 // 4 + 1 + 255 + 2. + +int pqiproxyconnection::Proxy_Send_Address(int sockfd) +{ + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Send_Address() Checking Method Response"; + std::cerr << std::endl; +#endif + + // Check Method Response. + int ret = Proxy_Method_Response(sockfd); + if (ret != 1) + { + return ret; // Method Response not complete. + } + + char socks_request[MAX_SOCKS_REQUEST_LEN] = { + 0x05, // SOCKS VERSION. + 0x01, // CONNECT (Tor doesn't support BIND or UDP). + 0x00, // RESERVED. + 0x03, // ADDRESS TYPE (Domain Name) + 0x00, // Length of Domain name... the rest is variable so can't hard code it! + }; + + /* get the length of the domain name, pack so we can't overflow uint8_t */ + uint8_t len = mDomainAddress.length(); + socks_request[4] = len; + for(int i = 0; i < len; i++) + socks_request[5 + i] = mDomainAddress[i]; + + /* now add the port, being careful with packing */ + uint16_t net_port = htons(mRemotePort); + socks_request[5 + len] = ((uint8_t *) &net_port)[0]; + socks_request[5 + len + 1] = ((uint8_t *) &net_port)[1]; + + int pkt_len = 5 + len + 2; + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Send_Address() Sending String: "; + for(int i = 0; i < pkt_len; i++) + std::cerr << (uint32_t) socks_request[i]; + std::cerr << std::endl; +#endif + int sent = send(sockfd, socks_request, pkt_len, 0); + if (sent != pkt_len) + { + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Send_Address() Send Error"; + std::cerr << std::endl; +#endif + + return -1; + } + + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Send_Address() Sent Okay"; + std::cerr << std::endl; +#endif + + mProxyState = PROXY_STATE_WAITING_SOCKS_RESPONSE; + return 1; +} + +int pqiproxyconnection::Proxy_Connection_Complete(int sockfd) +{ + /* get response from proxy server */ + /* response is similar format to request - with variable length data */ + + char socks_response[MAX_SOCKS_REQUEST_LEN]; + + // test how many bytes can be read + int recvd = recv(sockfd, socks_response, 5, MSG_PEEK); + if (recvd != 5) + { +#ifdef WINDOWS_SYS + if ((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK)) + { +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data (windows)"; + std::cerr << std::endl; +#endif + return 0; + } +#endif + if ((recvd == -1) && (errno == EAGAIN)) + { +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() EAGAIN"; + std::cerr << std::endl; +#endif + return 0; + } + else if (recvd == -1) + { +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() recv error peek"; + std::cerr << std::endl; +#endif + return -1; + } + else + { +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data"; + std::cerr << std::endl; +#endif + return 0; + } + } + + // read the bytes + recvd = recv(sockfd, socks_response, 5, 0); + if (recvd != 5) + { +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() recv error"; + std::cerr << std::endl; +#endif + return -1; + } + + // error checking. + if (socks_response[0] != 0x05) + { + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR socks_response[0] != 0x05. is: "; + std::cerr << (uint32_t) socks_response[0]; + std::cerr << std::endl; +#endif + + // error. + return -1; + } + + if (socks_response[1] != 0x00) + { + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR socks_response[1] != 0x00. is: "; + std::cerr << (uint32_t) socks_response[1]; + std::cerr << std::endl; +#endif + + // connection failed. + return -1; + } + + int address_bytes = 0; + switch(socks_response[3]) // Address Type. + { + case 0x01: + // IPv4 4 address bytes. + address_bytes = 4; +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() IPv4 Address Type"; + std::cerr << std::endl; +#endif + break; + case 0x04: + // IPv6 16 address bytes. + address_bytes = 16; +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() IPv6 Address Type"; + std::cerr << std::endl; +#endif + break; + case 0x03: + // Variable address bytes - specified in next byte. + address_bytes = 1 + socks_response[4]; +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() Domain Address Type. len: " << address_bytes; + std::cerr << std::endl; +#endif + break; + default: + // unknown error. +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR Unknown Address Type"; + std::cerr << std::endl; +#endif + return -1; + break; + } + + + // test how many bytes can be read + recvd = recv(sockfd, &(socks_response[5]), address_bytes + 1, MSG_PEEK); // address_bytes - 1 + 2... + if (recvd != address_bytes + 1) + { +#ifdef WINDOWS_SYS + if((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK)) + { +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data(2) (windows)"; + std::cerr << std::endl; +#endif + return 0; + } +#endif + if ((recvd == -1) && (errno == EAGAIN)) + { +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR EAGAIN at end."; + std::cerr << std::endl; +#endif + // Waiting - shouldn't happen. + return 0; + } + else if (recvd == -1) + { +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR recving(2)"; + std::cerr << std::endl; +#endif + return -1; + } + else + { +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data(2)"; + std::cerr << std::endl; +#endif + return 0; + } + } + + // read the bytes + recvd = recv(sockfd, &(socks_response[5]), address_bytes + 1, 0); // address_bytes - 1 + 2... + if (recvd != address_bytes + 1) + { +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() recv error (2)"; + std::cerr << std::endl; +#endif + return -1; + } + +#ifdef PROXY_DEBUG + std::cerr << "pqisslproxy::Proxy_Connection_Complete() Received String: "; + for(int i = 0; i < 4 + address_bytes + 2; i++) + std::cerr << (uint32_t) socks_response[i]; + std::cerr << std::endl; +#endif + + // should print address. + // if we get here - connection is good!. + mProxyState = PROXY_STATE_CONNECTION_COMPLETE; + return 1; + +} + diff --git a/src/pqi/pqiproxy.h b/src/pqi/pqiproxy.h new file mode 100644 index 000000000..6862342bb --- /dev/null +++ b/src/pqi/pqiproxy.h @@ -0,0 +1,72 @@ +/******************************************************************************* + * libretroshare/src/pqi: pqiproxy.h * + * * + * libretroshare: retroshare core library * + * * + * Copyright 2004-2013 by Robert Fernie. * + * Copyright 2004-2021 by retroshare team * + * * + * 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 . * + * * + *******************************************************************************/ + +#pragma once + +#include + +class pqiproxyconnection +{ +public: + enum ProxyState: uint8_t { + PROXY_STATE_FAILED = 0x00, + PROXY_STATE_INIT = 0x01, + PROXY_STATE_WAITING_METHOD_RESPONSE = 0x02, + PROXY_STATE_WAITING_SOCKS_RESPONSE = 0x03, + PROXY_STATE_CONNECTION_COMPLETE = 0x04 + }; + + pqiproxyconnection() : mProxyState(PROXY_STATE_INIT) {} + + /*! + * \brief proxy_negotiate_connection + * Negotiate the connection with the proxy that is connected with openned socket sockfd. The caller needs to + * connect the socket *before* trying to call proxy_negotiate_connection(). The function must be called as many times as + * necessary until it returns 1 (success) or -1 (error) in which case the socket needs to be closed. + * \return + * -1 : error. The socket must be closed as soon as possible. + * 0 : in progress. The function needs to be called again asap. + * 1 : proxy connection is fully negociated. Client can send data to the socket. + */ + int proxy_negociate_connection(int sockfd); + + void setRemotePort(uint16_t v) { mRemotePort = v; } + void setRemoteAddress(const std::string& s) { mDomainAddress = s; } + + ProxyState proxyConnectionState() const { return mProxyState ; } + + void proxy_init() { mProxyState = PROXY_STATE_INIT; } +private: + + ProxyState mProxyState; + + std::string mDomainAddress; + uint16_t mRemotePort; + + // These are the internal steps in setting up the Proxy Connection. + int Proxy_Send_Method(int sockfd); + int Proxy_Method_Response(int sockfd); + int Proxy_Send_Address(int sockfd); + int Proxy_Connection_Complete(int sockfd); +}; + diff --git a/src/pqi/pqisslproxy.cc b/src/pqi/pqisslproxy.cc index 0f6c4ae11..7a64a03a8 100644 --- a/src/pqi/pqisslproxy.cc +++ b/src/pqi/pqisslproxy.cc @@ -38,12 +38,6 @@ static struct RsLog::logInfo pqisslproxyzoneInfo = {RsLog::Default, "pqisslproxy // #define PROXY_DEBUG 1 // #define PROXY_DEBUG_LOG 1 -#define PROXY_STATE_FAILED 0 -#define PROXY_STATE_INIT 1 -#define PROXY_STATE_WAITING_METHOD_RESPONSE 2 -#define PROXY_STATE_WAITING_SOCKS_RESPONSE 3 -#define PROXY_STATE_CONNECTION_COMPLETE 4 - pqisslproxy::pqisslproxy(pqissllistener *l, PQInterface *parent, p3LinkMgr *lm) :pqissl(l, parent, lm) { @@ -74,7 +68,7 @@ int pqisslproxy::Initiate_Connection() rslog(RSL_DEBUG_BASIC, pqisslproxyzone, "pqisslproxy::Initiate_Connection() Connection to Proxy"); /* init proxy state */ - mProxyState = PROXY_STATE_INIT; + proxy_init(); /* call standard Init_Conn() */ return pqissl::Initiate_Connection(); @@ -84,499 +78,31 @@ int pqisslproxy::Initiate_Connection() /********* VERY DIFFERENT **********/ int pqisslproxy::Basic_Connection_Complete() { - rslog(RSL_DEBUG_BASIC, pqisslproxyzone, - "pqisslproxy::Basic_Connection_Complete()..."); + rslog(RSL_DEBUG_BASIC, pqisslproxyzone, + "pqisslproxy::Basic_Connection_Complete()..."); #ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Basic_Connection_Complete() STATE: " << mProxyState; - std::cerr << std::endl; + std::cerr << "pqisslproxy::Basic_Connection_Complete() STATE: " << mProxyState; + std::cerr << std::endl; #endif - if (CheckConnectionTimeout()) - { - // calls reset. - return -1; - } - - int ret = 0; - switch(mProxyState) - { - case PROXY_STATE_INIT: - ret = Proxy_Send_Method(); // checks basic conn, sends Method when able. - break; - - case PROXY_STATE_WAITING_METHOD_RESPONSE: - ret = Proxy_Send_Address(); // waits for Method Response, send Address when able. - break; - - case PROXY_STATE_WAITING_SOCKS_RESPONSE: - ret = Proxy_Connection_Complete(); // wait for ACK. - break; - - case PROXY_STATE_CONNECTION_COMPLETE: - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Basic_Connection_Complete() COMPLETED"; - std::cerr << std::endl; -#endif - - return 1; - - case PROXY_STATE_FAILED: - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Basic_Connection_Complete() FAILED"; - std::cerr << std::endl; -#endif - - reset_locked(); - return -1; - } - - if (ret < 0) - { - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Basic_Connection_Complete() FAILED(2)"; - std::cerr << std::endl; -#endif - reset_locked(); - return -1; // FAILURE. - } - - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Basic_Connection_Complete() IN PROGRESS"; - std::cerr << std::endl; -#endif - - // In Progress. - return 0; -} - - -int pqisslproxy::Proxy_Send_Method() -{ - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Send_Method() Checking pqissl::Basic_Connection_Complete()"; - std::cerr << std::endl; -#endif - - int ret = pqissl::Basic_Connection_Complete(); - if (ret != 1) - { - return ret; // basic connection not complete. - } - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Send_Method() Basic complete, sending Method"; - std::cerr << std::endl; -#endif - - /* send hello to proxy server */ - char method_hello_data[3] = { 0x05, 0x01, 0x00 }; // [ Ver | nMethods (1) | No Auth Method ] - - int sent = send(sockfd, method_hello_data, 3, 0); - if (sent != 3) - { - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Send_Method() Send Failure"; - std::cerr << std::endl; -#endif - return -1; - } - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Send_Method() Send Method Okay"; - std::cerr << std::endl; -#endif - - mProxyState = PROXY_STATE_WAITING_METHOD_RESPONSE; - - return 1; -} - -int pqisslproxy::Proxy_Method_Response() -{ - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Method_Response()"; - std::cerr << std::endl; -#endif - - /* get response from proxy server */ - - char method_response[2]; - - /* - first it was: - - int recvd = recv(sockfd, method_response, 2, MSG_WAITALL); - - this does not work on windows, because the socket is in nonblocking mode - the winsock reference says about the recv function and MSG_WAITALL: - - "Note that if the underlying transport does not support MSG_WAITALL, - or if the socket is in a non-blocking mode, then this call will fail with WSAEOPNOTSUPP." - - now it is a two step process: - - int recvd = recv(sockfd, method_response, 2, MSG_PEEK); // test how many bytes are in the input queue - if (enaugh bytes available){ - recvd = recv(sockfd, method_response, 2, 0); - } - - this does not work on windows: - if ((recvd == -1) && (errno == EAGAIN)) return TRY_AGAIN_LATER; - - instead have to do: - if ((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK)) return TRY_AGAIN_LATER; - */ - - // test how many bytes can be read from the queue - int recvd = recv(sockfd, method_response, 2, MSG_PEEK); - if (recvd != 2) - { -#ifdef WINDOWS_SYS - if ((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK)) - { -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Method_Response() waiting for more data (windows)"; - std::cerr << std::endl; -#endif - return 0; - } -#endif - if ((recvd == -1) && (errno == EAGAIN)) - { - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Method_Response() EAGAIN"; - std::cerr << std::endl; -#endif - - return 0; - } - else if (recvd == -1) - { -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Method_Response() recv error peek"; - std::cerr << std::endl; -#endif - return -1; - } - else - { -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Method_Response() waiting for more data"; - std::cerr << std::endl; -#endif - return 0; - } - } - - // read the bytes - recvd = recv(sockfd, method_response, 2, 0); - if (recvd != 2) + if (CheckConnectionTimeout()) { -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Method_Response() recv error"; - std::cerr << std::endl; -#endif + // calls reset. return -1; } - // does it make sense? - if (method_response[0] != 0x05) - { + int ret; - // Error. -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Method_Response() Error response[0] != 0x05. Is: "; - std::cerr << (uint32_t) method_response[0]; - std::cerr << std::endl; -#endif - return -1; - } + if(proxyConnectionState() == PROXY_STATE_INIT && 1!=(ret=pqissl::Basic_Connection_Complete())) + return ret; // basic connection not complete. - if (method_response[1] != 0x00) - { + ret = proxy_negociate_connection(sockfd); -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Method_Response() Error response[0] != 0x00. Is: "; - std::cerr << (uint32_t) method_response[1]; - std::cerr << std::endl; -#endif - // Error. - return -1; - } - - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Method_Response() Response Okay"; - std::cerr << std::endl; -#endif - - return 1; -} - -#define MAX_SOCKS_REQUEST_LEN 262 // 4 + 1 + 255 + 2. - -int pqisslproxy::Proxy_Send_Address() -{ - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Send_Address() Checking Method Response"; - std::cerr << std::endl; -#endif - - // Check Method Response. - int ret = Proxy_Method_Response(); - if (ret != 1) - { - return ret; // Method Response not complete. - } - - char socks_request[MAX_SOCKS_REQUEST_LEN] = - { 0x05, // SOCKS VERSION. - 0x01, // CONNECT (Tor doesn't support BIND or UDP). - 0x00, // RESERVED. - 0x03, // ADDRESS TYPE (Domain Name) - 0x00, // Length of Domain name... the rest is variable so can't hard code it! - }; - - /* get the length of the domain name, pack so we can't overflow uint8_t */ - uint8_t len = mDomainAddress.length(); - socks_request[4] = len; - for(int i = 0; i < len; i++) - { - socks_request[5 + i] = mDomainAddress[i]; - } - - /* now add the port, being careful with packing */ - uint16_t net_port = htons(mRemotePort); - socks_request[5 + len] = ((uint8_t *) &net_port)[0]; - socks_request[5 + len + 1] = ((uint8_t *) &net_port)[1]; - - int pkt_len = 5 + len + 2; - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Send_Address() Sending String: "; - for(int i = 0; i < pkt_len; i++) - std::cerr << (uint32_t) socks_request[i]; - std::cerr << std::endl; -#endif - int sent = send(sockfd, socks_request, pkt_len, 0); - if (sent != pkt_len) - { - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Send_Address() Send Error"; - std::cerr << std::endl; -#endif - - return -1; - } - - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Send_Address() Sent Okay"; - std::cerr << std::endl; -#endif - - mProxyState = PROXY_STATE_WAITING_SOCKS_RESPONSE; - return 1; -} - -int pqisslproxy::Proxy_Connection_Complete() -{ - /* get response from proxy server */ - /* response is similar format to request - with variable length data */ - - char socks_response[MAX_SOCKS_REQUEST_LEN]; - - // test how many bytes can be read - int recvd = recv(sockfd, socks_response, 5, MSG_PEEK); - if (recvd != 5) - { -#ifdef WINDOWS_SYS - if ((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK)) - { -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data (windows)"; - std::cerr << std::endl; -#endif - return 0; - } -#endif - if ((recvd == -1) && (errno == EAGAIN)) - { -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() EAGAIN"; - std::cerr << std::endl; -#endif - return 0; - } - else if (recvd == -1) - { -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() recv error peek"; - std::cerr << std::endl; -#endif - return -1; - } - else - { -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data"; - std::cerr << std::endl; -#endif - return 0; - } - } - - // read the bytes - recvd = recv(sockfd, socks_response, 5, 0); - if (recvd != 5) - { -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() recv error"; - std::cerr << std::endl; -#endif - return -1; - } - - // error checking. - if (socks_response[0] != 0x05) - { - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR socks_response[0] != 0x05. is: "; - std::cerr << (uint32_t) socks_response[0]; - std::cerr << std::endl; -#endif - - // error. - return -1; - } - - if (socks_response[1] != 0x00) - { - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR socks_response[1] != 0x00. is: "; - std::cerr << (uint32_t) socks_response[1]; - std::cerr << std::endl; -#endif - - // connection failed. - return -1; - } - - int address_bytes = 0; - switch(socks_response[3]) // Address Type. - { - case 0x01: - // IPv4 4 address bytes. - address_bytes = 4; -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() IPv4 Address Type"; - std::cerr << std::endl; -#endif - break; - case 0x04: - // IPv6 16 address bytes. - address_bytes = 16; -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() IPv6 Address Type"; - std::cerr << std::endl; -#endif - break; - case 0x03: - // Variable address bytes - specified in next byte. - address_bytes = 1 + socks_response[4]; -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() Domain Address Type. len: " << address_bytes; - std::cerr << std::endl; -#endif - break; - default: - // unknown error. -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR Unknown Address Type"; - std::cerr << std::endl; -#endif - return -1; - break; - } - - - // test how many bytes can be read - recvd = recv(sockfd, &(socks_response[5]), address_bytes + 1, MSG_PEEK); // address_bytes - 1 + 2... - if (recvd != address_bytes + 1) - { -#ifdef WINDOWS_SYS - if((recvd == -1) && (WSAGetLastError() == WSAEWOULDBLOCK)) - { -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data(2) (windows)"; - std::cerr << std::endl; -#endif - return 0; - } -#endif - if ((recvd == -1) && (errno == EAGAIN)) - { -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR EAGAIN at end."; - std::cerr << std::endl; -#endif - // Waiting - shouldn't happen. - return 0; - } - else if (recvd == -1) - { -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() ERROR recving(2)"; - std::cerr << std::endl; -#endif - return -1; - } - else - { -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() waiting for more data(2)"; - std::cerr << std::endl; -#endif - return 0; - } - } - - // read the bytes - recvd = recv(sockfd, &(socks_response[5]), address_bytes + 1, 0); // address_bytes - 1 + 2... - if (recvd != address_bytes + 1) - { -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() recv error (2)"; - std::cerr << std::endl; -#endif - return -1; - } - -#ifdef PROXY_DEBUG - std::cerr << "pqisslproxy::Proxy_Connection_Complete() Received String: "; - for(int i = 0; i < 4 + address_bytes + 2; i++) - std::cerr << (uint32_t) socks_response[i]; - std::cerr << std::endl; -#endif - - // should print address. - // if we get here - connection is good!. - mProxyState = PROXY_STATE_CONNECTION_COMPLETE; - return 1; + if(ret < 0) + reset_locked(); + return ret; } bool pqisslproxy::connect_parameter(uint32_t type, const std::string &value) @@ -591,7 +117,7 @@ bool pqisslproxy::connect_parameter(uint32_t type, const std::string &value) rs_sprintf(out, "pqisslproxy::connect_parameter() Peer: %s DOMAIN_ADDRESS: %s", PeerId().toStdString().c_str(), value.c_str()); rslog(RSL_WARNING, pqisslproxyzone, out); #endif - mDomainAddress = value; + setRemoteAddress(value); #ifdef PROXY_DEBUG std::cerr << out << std::endl; #endif @@ -614,7 +140,7 @@ bool pqisslproxy::connect_parameter(uint32_t type, uint32_t value) #ifdef PROXY_DEBUG_LOG rslog(RSL_WARNING, pqisslproxyzone, out); #endif - mRemotePort = value; + setRemotePort(value); #ifdef PROXY_DEBUG std::cerr << out << std::endl; #endif diff --git a/src/pqi/pqisslproxy.h b/src/pqi/pqisslproxy.h index dc34295ad..7071f4dfb 100644 --- a/src/pqi/pqisslproxy.h +++ b/src/pqi/pqisslproxy.h @@ -24,6 +24,7 @@ // operating system specific network header. #include "pqi/pqinetwork.h" +#include "pqi/pqiproxy.h" #include #include @@ -39,40 +40,27 @@ * fns declared here are different -> all others are identical. */ -class pqisslproxy: public pqissl +class pqisslproxy: public pqissl, public pqiproxyconnection { public: - pqisslproxy(pqissllistener *l, PQInterface *parent, p3LinkMgr *lm); -virtual ~pqisslproxy(); + pqisslproxy(pqissllistener *l, PQInterface *parent, p3LinkMgr *lm); + virtual ~pqisslproxy(); - // NetInterface. Is the same. - // BinInterface. Is the same. + // NetInterface. Is the same. + // BinInterface. Is the same. -virtual bool connect_parameter(uint32_t type, const std::string &value); -virtual bool connect_parameter(uint32_t type, uint32_t value); + virtual bool connect_parameter(uint32_t type, const std::string &value); + virtual bool connect_parameter(uint32_t type, uint32_t value); protected: -//Initiate is the same - except it uses the Proxy Address rather than the Peer Address. -// minor tweaks to setup data state. -virtual int Initiate_Connection(); + //Initiate is the same - except it uses the Proxy Address rather than the Peer Address. + // minor tweaks to setup data state. + virtual int Initiate_Connection(); -// The real overloading is done in Basic Connection Complete. -// Instead of just checking for an open socket, we need to communicate with the SOCKS5 proxy. -virtual int Basic_Connection_Complete(); - -// These are the internal steps in setting up the Proxy Connection. -virtual int Proxy_Send_Method(); -virtual int Proxy_Method_Response(); -virtual int Proxy_Send_Address(); -virtual int Proxy_Connection_Complete(); - -private: - - uint32_t mProxyState; - - std::string mDomainAddress; - uint16_t mRemotePort; + // The real overloading is done in Basic Connection Complete. + // Instead of just checking for an open socket, we need to communicate with the SOCKS5 proxy. + virtual int Basic_Connection_Complete(); }; #endif // MRK_PQI_SSL_PROXY_HEADER diff --git a/src/pqi/pqistreamer.cc b/src/pqi/pqistreamer.cc index db38bfde2..7f5a42301 100644 --- a/src/pqi/pqistreamer.cc +++ b/src/pqi/pqistreamer.cc @@ -357,6 +357,7 @@ int pqistreamer::status() // this method is overloaded by pqiqosstreamer void pqistreamer::locked_storeInOutputQueue(void *ptr,int,int) { + RsDbg() << "Storing packet " << std::hex << ptr << std::dec << " in outqueue."; mOutPkts.push_back(ptr); } @@ -521,7 +522,7 @@ int pqistreamer::handleoutgoing_locked() { /* if we are not active - clear anything in the queues. */ locked_clear_out_queue() ; -#ifdef DEBUG_PACKET_SLICING +#ifdef DEBUG_PACKET_SLICING std::cerr << "(II) Switching off packet slicing." << std::endl; #endif mAcceptsPacketSlicing = false ; @@ -683,7 +684,7 @@ int pqistreamer::handleoutgoing_locked() outSentBytes_locked(mPkt_wpending_size); // this is the only time where we know exactly what was sent. #ifdef DEBUG_TRANSFERS - std::cerr << "pqistreamer::handleoutgoing_locked() Sent Packet len: " << mPkt_wpending_size << " @ " << RsUtil::AccurateTimeString(); + std::cerr << "pqistreamer::handleoutgoing_locked() Sent Packet len: " << mPkt_wpending_size << " @ " << getCurrentTS(); std::cerr << std::endl; #endif @@ -693,7 +694,7 @@ int pqistreamer::handleoutgoing_locked() mPkt_wpending = NULL; mPkt_wpending_size = 0 ; - sent = true; + sent = true; } } #ifdef DEBUG_PQISTREAMER @@ -802,11 +803,14 @@ start_packet_read: if(!memcmp(block,PACKET_SLICING_PROBE_BYTES,8)) { - mAcceptsPacketSlicing = !DISABLE_PACKET_SLICING; + mAcceptsPacketSlicing = !DISABLE_PACKET_SLICING; #ifdef DEBUG_PACKET_SLICING std::cerr << "(II) Enabling packet slicing!" << std::endl; #endif - } + mReading_state = reading_state_initial ; // restart at state 1. + mFailed_read_attempts = 0 ; + return 0; + } } continue_packet: { @@ -1430,8 +1434,12 @@ void *pqistreamer::locked_pop_out_data(uint32_t /*max_slice_size*/, uint32_t &si { res = *(mOutPkts.begin()); mOutPkts.pop_front(); + + // In pqistreamer, we do not split outgoing packets. For now only pqiQoSStreamer supports packet slicing. + size = getRsItemSize(res); + #ifdef DEBUG_TRANSFERS - std::cerr << "pqistreamer::locked_pop_out_data() getting next pkt from mOutPkts queue"; + std::cerr << "pqistreamer::locked_pop_out_data() getting next pkt " << std::hex << res << std::dec << " from mOutPkts queue"; std::cerr << std::endl; #endif } diff --git a/src/pqi/pqithreadstreamer.h b/src/pqi/pqithreadstreamer.h index 7ba1690c8..5b6fa3763 100644 --- a/src/pqi/pqithreadstreamer.h +++ b/src/pqi/pqithreadstreamer.h @@ -31,8 +31,8 @@ public: pqithreadstreamer(PQInterface *parent, RsSerialiser *rss, const RsPeerId& peerid, BinInterface *bio_in, int bio_flagsin); // from pqistreamer - virtual bool RecvItem(RsItem *item); - virtual int tick(); + virtual bool RecvItem(RsItem *item) override; + virtual int tick() override; protected: void threadTick() override; /// @see RsTickingThread diff --git a/src/retroshare/rsfriendserver.h b/src/retroshare/rsfriendserver.h new file mode 100644 index 000000000..80bf2a029 --- /dev/null +++ b/src/retroshare/rsfriendserver.h @@ -0,0 +1,39 @@ +#include +#include +#include "util/rstime.h" + +// The Friend Server component of Retroshare automatically adds/removes some friends so that the +// +// The current strategy is: +// +// - if total nb of friends < S +// request new friends to the FS +// - if total nb of friends >= S +// do not request anymore (and unpublish the key), but keep the friends already here +// +// Possible states: +// - not started +// - maintain friend list +// - actively request friends +// +// The friend server internally keeps track of which friends have been added using the friend server. +// It's important to keep the ones that are already connected because they may count on us. +// Friends supplied by the FS who never connected for a few days should be removed automatically. + +class RsFriendServer +{ +public: + virtual void startServer() =0; + virtual void stopServer() =0; + + virtual void checkServerAddress_async(const std::string& addr,uint16_t, const std::function& callback) =0; + virtual void setServerAddress(const std::string&,uint16_t) =0; + virtual void setProxyAddress(const std::string&,uint16_t) =0; + virtual void setFriendsToRequest(uint32_t) =0; + + virtual uint32_t friendsToRequest() =0; + virtual uint16_t friendsServerPort() =0; + virtual std::string friendsServerAddress() =0; +}; + +extern RsFriendServer *rsFriendServer; diff --git a/src/retroshare/rsids.h b/src/retroshare/rsids.h index d38ee4518..c7fec6725 100644 --- a/src/retroshare/rsids.h +++ b/src/retroshare/rsids.h @@ -168,6 +168,15 @@ struct t_RsGenericIdType return ret; } + inline Id_t operator^ (const Id_t& fp) const + { + Id_t ret; + for(uint32_t i=0; i < ID_SIZE_IN_BYTES; ++i) + ret.bytes[i] = bytes[i] ^ fp.bytes[i]; + return ret; + } + + inline bool isNull() const { for(uint32_t i=0; i < SIZE_IN_BYTES; ++i) diff --git a/src/rsitems/rsserviceids.h b/src/rsitems/rsserviceids.h index eb08db07c..a80931aca 100644 --- a/src/rsitems/rsserviceids.h +++ b/src/rsitems/rsserviceids.h @@ -54,7 +54,8 @@ enum class RsServiceType : uint16_t BANLIST = 0x0101, STATUS = 0x0102, - NXS = 0x0200, + FRIEND_SERVER = 0x0103, + NXS = 0x0200, GXSID = 0x0211, PHOTO = 0x0212, WIKI = 0x0213, @@ -115,6 +116,8 @@ RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_DISTANT_CHAT = RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_GXS_TUNNEL = 0x0028; RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_BANLIST = 0x0101; RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_STATUS = 0x0102; +RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_FRIEND_SERVER = 0x0103; + /// Rs Network Exchange Service RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_TYPE_NXS = 0x0200; RS_DEPRECATED_FOR(RsServiceType) const uint16_t RS_SERVICE_GXS_TYPE_GXSID = 0x0211; diff --git a/src/rsserver/p3peers.cc b/src/rsserver/p3peers.cc index 2ca178c0a..53cd3b5d7 100644 --- a/src/rsserver/p3peers.cc +++ b/src/rsserver/p3peers.cc @@ -48,6 +48,7 @@ #include "pqi/authssl.h" +typedef RsCertificate::RsShortInviteFieldType RsShortInviteFieldType; // locally in this file to avoid renaming everything. RsPeers *rsPeers = NULL; @@ -1162,22 +1163,6 @@ bool p3Peers::GetPGPBase64StringAndCheckSum( return true; } -enum class RsShortInviteFieldType : uint8_t -{ - SSL_ID = 0x00, - PEER_NAME = 0x01, - LOCATOR = 0x02, - PGP_FINGERPRINT = 0x03, - CHECKSUM = 0x04, - - /* The following will be deprecated, and ported to LOCATOR when generic - * trasport layer will be implemented */ - HIDDEN_LOCATOR = 0x90, - DNS_LOCATOR = 0x91, - EXT4_LOCATOR = 0x92, // external IPv4 address - LOC4_LOCATOR = 0x93 // local IPv4 address -}; - static void addPacketHeader(RsShortInviteFieldType ptag, size_t size, unsigned char *& buf, uint32_t& offset, uint32_t& buf_size) { // Check that the buffer has sufficient size. If not, increase it. @@ -1373,136 +1358,23 @@ bool p3Peers::getShortInvite(std::string& invite, const RsPeerId& _sslId, Retros bool p3Peers::parseShortInvite(const std::string& inviteStrUrl, RsPeerDetails& details, uint32_t &err_code ) { - if(inviteStrUrl.empty()) - { - RsErr() << __PRETTY_FUNCTION__ << " can't parse empty invite" - << std::endl; - return false; - } - std::string rsInvite = inviteStrUrl; + if(inviteStrUrl.empty()) + { + RsErr() << __PRETTY_FUNCTION__ << " can't parse empty invite" + << std::endl; + return false; + } + std::string rsInvite = inviteStrUrl; - RsUrl inviteUrl(inviteStrUrl); + RsUrl inviteUrl(inviteStrUrl); - if(inviteUrl.hasQueryK("rsInvite")) - rsInvite = *inviteUrl.getQueryV("rsInvite"); + if(inviteUrl.hasQueryK("rsInvite")) + rsInvite = *inviteUrl.getQueryV("rsInvite"); - std::vector bf = Radix64::decode(rsInvite); - size_t size = bf.size(); + if(!RsCertificate::decodeRadix64ShortInvite(rsInvite, details, err_code)) + return false; - unsigned char* buf = bf.data(); - size_t total_s = 0; - bool CRC_ok = false ; // not checked yet - - while(total_s < size) - { - RsShortInviteFieldType ptag = RsShortInviteFieldType(buf[0]); - buf = &buf[1]; - - unsigned char *buf2 = buf; - uint32_t s = 0; - - try { s = PGPKeyParser::read_125Size(buf); } - catch (...) - { - err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR; - return false; - } - - total_s += 1 + ( reinterpret_cast(buf) - reinterpret_cast(buf2) ); - - if(total_s > size) - { - err_code = CERTIFICATE_PARSING_ERROR_SIZE_ERROR; - return false; - } - - Dbg3() << __PRETTY_FUNCTION__ << " Read ptag: " - << static_cast(ptag) - << ", size " << s << ", total_s = " << total_s - << ", expected total = " << size << std::endl; - - switch(ptag) - { - case RsShortInviteFieldType::SSL_ID: - details.id = RsPeerId::fromBufferUnsafe(buf) ; - break; - - case RsShortInviteFieldType::PEER_NAME: - details.name = std::string((char*)buf,s); - break; - - case RsShortInviteFieldType::PGP_FINGERPRINT: - details.fpr = RsPgpFingerprint::fromBufferUnsafe(buf); - details.gpg_id = PGPHandler::pgpIdFromFingerprint(details.fpr); - break; - - case RsShortInviteFieldType::LOCATOR: - { - std::string locatorStr((char*)buf,s); - details.ipAddressList.push_back(locatorStr); - } - break; - - case RsShortInviteFieldType::DNS_LOCATOR: - details.extPort = (((int)buf[0]) << 8) + buf[1]; - details.dyndns = std::string((char*)&buf[2],s-2); - break; - - case RsShortInviteFieldType::LOC4_LOCATOR: - { - uint32_t t4Addr = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3]; - sockaddr_in tLocalAddr; - tLocalAddr.sin_addr.s_addr = t4Addr; - - details.localAddr = rs_inet_ntoa(tLocalAddr.sin_addr); - details.localPort = (((uint32_t)buf[4])<<8) + (uint32_t)buf[5]; - } - break; - - case RsShortInviteFieldType::EXT4_LOCATOR: - { - uint32_t t4Addr = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3]; - sockaddr_in tExtAddr; - tExtAddr.sin_addr.s_addr = t4Addr; - - details.extAddr = rs_inet_ntoa(tExtAddr.sin_addr); - details.extPort = (((uint32_t)buf[4])<<8) + (uint32_t)buf[5]; - } - break; - - case RsShortInviteFieldType::HIDDEN_LOCATOR: - details.hiddenType = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3]; - details.hiddenNodePort = (((uint32_t)buf[4]) << 8)+ (uint32_t)buf[5]; - details.isHiddenNode = true; - details.hiddenNodeAddress = std::string((char*)&buf[6],s-6); - break; - - case RsShortInviteFieldType::CHECKSUM: - { - if(s != 3 || total_s+3 != size) // make sure the checksum is the last section - { - err_code = CERTIFICATE_PARSING_ERROR_INVALID_CHECKSUM_SECTION; - return false; - } - uint32_t computed_crc = PGPKeyManagement::compute24bitsCRC(bf.data(),size-5); - uint32_t certificate_crc = static_cast( buf[0] + (buf[1] << 8) + (buf[2] << 16) ); - - if(computed_crc != certificate_crc) - { - err_code = CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR; - return false; - } - CRC_ok = true; - break; - } - - } - - buf = &buf[s]; - total_s += s; - } - - // now check if the PGP key is available. If so, add it in the PeerDetails: + // Also check if the PGP key is available. If so, add it in the PeerDetails: RsPeerDetails pgp_det ; if(getGPGDetails(PGPHandler::pgpIdFromFingerprint(details.fpr),pgp_det) && pgp_det.fpr == details.fpr) @@ -1519,23 +1391,13 @@ bool p3Peers::parseShortInvite(const std::string& inviteStrUrl, RsPeerDetails& d else details.skip_pgp_signature_validation = true; - if(!CRC_ok) - { - err_code = CERTIFICATE_PARSING_ERROR_CHECKSUM_ERROR; - return false; - } if(details.gpg_id.isNull()) { err_code = CERTIFICATE_PARSING_ERROR_MISSING_PGP_FINGERPRINT; return false; } - if(details.id.isNull()) - { - err_code = CERTIFICATE_PARSING_ERROR_MISSING_LOCATION_ID; - return false; - } - err_code = CERTIFICATE_PARSING_ERROR_NO_ERROR; - return true; + err_code = CERTIFICATE_PARSING_ERROR_NO_ERROR; + return true; } bool p3Peers::acceptInvite( const std::string& invite, diff --git a/src/rsserver/rsinit.cc b/src/rsserver/rsinit.cc index 53d2b3a52..5729b552c 100644 --- a/src/rsserver/rsinit.cc +++ b/src/rsserver/rsinit.cc @@ -52,6 +52,10 @@ #include "rsserver/rsloginhandler.h" #include "rsserver/rsaccounts.h" +#ifdef RS_EMBEDED_FRIEND_SERVER +#include "friend_server/fsmanager.h" +#endif + #include #include @@ -1175,6 +1179,11 @@ int RsServer::StartupRetroShare() serviceCtrl->setServiceServer(pqih) ; +#ifdef RS_EMBEDED_FRIEND_SERVER + // setup friend server + rsFriendServer = new FriendServerManager(); +#endif + /****** New Ft Server **** !!! */ ftServer *ftserver = new ftServer(mPeerMgr, serviceCtrl); ftserver->setConfigDirectory(RsAccounts::AccountDirectory()); @@ -1936,6 +1945,12 @@ int RsServer::StartupRetroShare() std::string RsInit::executablePath() { + if(rsInitConfig->mainExecutablePath.empty()) + { + RsErr() << "Main executable path not set! Plz call RsInit::InitRetroShare(conf) with conf.main_executable_path = argv[0]"; + assert(false); + } + return rsInitConfig->mainExecutablePath; } bool RsInit::startAutoTor() diff --git a/src/tor/TorManager.cpp b/src/tor/TorManager.cpp index 0b0f59cef..7fa275c5a 100644 --- a/src/tor/TorManager.cpp +++ b/src/tor/TorManager.cpp @@ -142,6 +142,8 @@ std::string TorManager::torDataDirectory() const void TorManager::setTorDataDirectory(const std::string &path) { + assert(RsDirUtil::checkCreateDirectory(std::string(path))); + d->dataDir = path; if (!d->dataDir.empty() && !ByteArray(d->dataDir).endsWith('/'))