From 5c0f1dac088a16895e590a26458a66730e6e7086 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 22 Nov 2015 23:19:46 -0500 Subject: [PATCH] saving ongoing work. Implementation almoast finished. --- libretroshare/src/gxstunnel/p3gxstunnel.cc | 70 ++++++++++++++++------ libretroshare/src/gxstunnel/p3gxstunnel.h | 48 +++++++++++++-- libretroshare/src/retroshare/rsgxstunnel.h | 8 +-- libretroshare/src/retroshare/rsids.h | 2 + 4 files changed, 101 insertions(+), 27 deletions(-) diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index 869326795..a619e9460 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -82,11 +82,12 @@ void p3GxsTunnelService::flush() time_t now = time(NULL) ; - for(std::map::iterator it(_gxs_tunnel_contacts.begin());it!=_gxs_tunnel_contacts.end();++it) + for(std::map::iterator it(_gxs_tunnel_contacts.begin());it!=_gxs_tunnel_contacts.end();++it) { if(it->second.last_contact+20+GXS_TUNNEL_KEEP_ALIVE_TIMEOUT < now && it->second.status == RS_GXS_TUNNEL_STATUS_CAN_TALK) { std::cerr << "(II) GxsTunnelService:: connexion interrupted with peer." << std::endl; + it->second.status = RS_GXS_TUNNEL_STATUS_TUNNEL_DN ; it->second.virtual_peer_id.clear() ; @@ -232,7 +233,7 @@ void p3GxsTunnelService::addVirtualPeer(const TurtleFileHash& hash,const TurtleV else // client side { RsGxsId to_gxs_id = gxsIdFromHash(hash) ; - std::map::const_iterator it = _gxs_tunnel_contacts.find(to_gxs_id) ; + std::map::const_iterator it = _gxs_tunnel_contacts.find(to_gxs_id) ; if(it == _gxs_tunnel_contacts.end()) { @@ -273,6 +274,7 @@ void p3GxsTunnelService::locked_restartDHSession(const RsPeerId& virtual_peer_id GxsTunnelDHInfo& dhinfo = _gxs_tunnel_virtual_peer_ids[virtual_peer_id] ; dhinfo.status = RS_GXS_TUNNEL_DH_STATUS_UNINITIALIZED ; + dhinfo.own_gxs_id = own_gxs_id ; if(!locked_initDHSessionKey(dhinfo.dh)) { @@ -313,7 +315,7 @@ void p3GxsTunnelService::removeVirtualPeer(const TurtleFileHash& hash,const Turt DH_free(it->second.dh) ; _gxs_tunnel_virtual_peer_ids.erase(it) ; - std::map::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ; + std::map::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ; if(it2 == _gxs_tunnel_contacts.end()) { @@ -436,7 +438,7 @@ bool p3GxsTunnelService::handleEncryptedData(const uint8_t *data_bytes,uint32_t } RsGxsId gxs_id = it->second.gxs_id ; - std::map::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ; + std::map::iterator it2 = _gxs_tunnel_contacts.find(gxs_id) ; if(it2 == _gxs_tunnel_contacts.end()) { @@ -636,22 +638,25 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) #ifdef DEBUG_GXS_TUNNEL std::cerr << " DH key computation successed. New key in place." << std::endl; #endif - GxsTunnelPeerInfo& pinfo(_gxs_tunnel_contacts[senders_id]) ; + // make a hash of destination and source GXS ids in order to create the tunnel name + + RsGxsId own_id = it->second.own_gxs_id ; + RsGxsTunnelId tunnel_id = makeGxsTunnelId(own_id,senders_id) ; + + GxsTunnelPeerInfo& pinfo(_gxs_tunnel_contacts[tunnel_id]) ; // Now hash the key buffer into a 16 bytes key. assert(GXS_TUNNEL_AES_KEY_SIZE <= Sha1CheckSum::SIZE_IN_BYTES) ; memcpy(pinfo.aes_key, RsDirUtil::sha1sum(key_buff,size).toByteArray(),GXS_TUNNEL_AES_KEY_SIZE) ; delete[] key_buff ; - + pinfo.last_contact = time(NULL) ; pinfo.last_keep_alive_sent = time(NULL) ; pinfo.status = RS_GXS_TUNNEL_STATUS_CAN_TALK ; pinfo.virtual_peer_id = vpid ; pinfo.direction = it->second.direction ; - - if(pinfo.direction == RsTurtleGenericTunnelItem::DIRECTION_CLIENT) - pinfo.own_gxs_id = gxsIdFromHash(it->second.hash) ; + pinfo.own_gxs_id = own_id ; #ifdef DEBUG_GXS_TUNNEL std::cerr << " DH key computed. Tunnel is now secured!" << std::endl; @@ -676,6 +681,29 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) //RsServer::notify()->notifyListChange(NOTIFY_LIST_PRIVATE_INCOMING_CHAT, NOTIFY_TYPE_ADD); } +RsGxsTunnelId p3GxsTunnelService::makeGxsTunnelId(const RsGxsId& own_id,const RsGxsId& distant_id) const +{ + unsigned char mem[RsGxsId::SIZE_IN_BYTES * 2] ; + + // Always sort the ids, as a matter to avoid confusion between the two. Also that generates the same tunnel ID on both sides + // which helps debugging. If the code is right this is not needed anyway. + + if(own_id < distant_id) + { + memcpy(mem, own_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ; + memcpy(mem+RsGxsId::SIZE_IN_BYTES, distant_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ; + } + else + { + memcpy(mem, distant_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ; + memcpy(mem+RsGxsId::SIZE_IN_BYTES, own_id.toBytesArray(), RsGxsId::SIZE_IN_BYTES) ; + } + + assert( RsGxsTunnelId::SIZE_IN_BYTES <= Sha1CheckSum::SIZE_IN_BYTES ) ; + + return RsGxsTunnelId( RsUtil::sha1sum(mem, 2*RsGxsId::SIZE_IN_BYTES).toByteArray() ) ; +} + bool p3GxsTunnelService::locked_sendDHPublicKey(const DH *dh,const RsGxsId& own_gxs_id,const RsPeerId& virtual_peer_id) { if(dh == NULL) @@ -847,7 +875,7 @@ void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rs #endif RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + std::map::iterator it = _gxs_tunnel_contacts.find(gxs_id) ; if(it == _gxs_tunnel_contacts.end()) { @@ -912,7 +940,7 @@ void p3GxsTunnelService::sendEncryptedTurtleData(const uint8_t *buff,uint32_t rs mTurtle->sendTurtleData(virtual_peer_id,gitem) ; } -bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,RsGxsTunnelClientService *client,uint32_t& error_code) +bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, RsGxsTunnelId &tunnel_id, uint32_t& error_code) { // should be a parameter. @@ -942,14 +970,17 @@ bool p3GxsTunnelService::requestSecuredTunnel(const RsGxsId& to_gxs_id,const RsG return true ; } -void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id) +void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,RsGxsTunnelId& tunnel_id) { + RsGxsTunnelId tnl_id = makeGxsTunnelId(from_gxs_id,to_gxs_id) ; + tunnel_id = tnl_id ; + { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - if(_gxs_tunnel_contacts.find(to_gxs_id) != _gxs_tunnel_contacts.end()) + if(_gxs_tunnel_contacts.find(tunnel_id) != _gxs_tunnel_contacts.end()) { - std::cerr << "GxsTunnelService:: asking distant chat connexion to a peer who's already in a chat. Ignoring." << std::endl; + std::cerr << "GxsTunnelService:: asking GXS tunnel for a configuration that already exits.Ignoring." << std::endl; return ; } } @@ -961,6 +992,7 @@ void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id info.last_keep_alive_sent = now ; info.status = RS_GXS_TUNNEL_STATUS_TUNNEL_DN ; info.own_gxs_id = from_gxs_id ; + info.to_gxs_id = to_gxs_id ; info.direction = RsTurtleGenericTunnelItem::DIRECTION_SERVER ; info.virtual_peer_id.clear(); @@ -968,11 +1000,13 @@ void p3GxsTunnelService::startClientGxsTunnelConnection(const RsGxsId& to_gxs_id { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - _gxs_tunnel_contacts[to_gxs_id] = info ; + + _gxs_tunnel_contacts[tnt_id] = info ; } // Now ask the turtle router to manage a tunnel for that hash. +#warning need to make sure that we can ask the same hash if the from ID is different. What's going to happen?? RsFileHash hash = hashFromGxsId(to_gxs_id) ; #ifdef DEBUG_GXS_TUNNEL std::cerr << "Starting distant chat to " << to_gxs_id << ", hash = " << hash << ", from " << from_gxs_id << std::endl; @@ -1032,7 +1066,7 @@ bool p3GxsTunnelService::getTunnelStatus(const RsGxsId& gxs_id,uint32_t& status, { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + std::map::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ; if(it != _gxs_tunnel_contacts.end()) { @@ -1049,7 +1083,7 @@ bool p3GxsTunnelService::getTunnelStatus(const RsGxsId& gxs_id,uint32_t& status, return false ; } -bool p3GxsTunnelService::closeExistingTunnel(const RsGxsId& gxs_id) +bool p3GxsTunnelService::closeExistingTunnel(const RsGxsTunnelId& tunnel_id) { // two cases: // - client needs to stop asking for tunnels => remove the hash from the list of tunnelled files @@ -1058,7 +1092,7 @@ bool p3GxsTunnelService::closeExistingTunnel(const RsGxsId& gxs_id) { RsStackMutex stack(mGxsTunnelMtx); /********** STACK LOCKED MTX ******/ - std::map::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ; + std::map::const_iterator it = _gxs_tunnel_contacts.find(gxs_id) ; if(it == _gxs_tunnel_contacts.end()) { diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.h b/libretroshare/src/gxstunnel/p3gxstunnel.h index a33c60862..a5efcfdc5 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.h +++ b/libretroshare/src/gxstunnel/p3gxstunnel.h @@ -51,6 +51,42 @@ // // Data is send to a service ID (could be any existing service ID). The endpoint of the tunnel must register each service, in order to // allow the data to be transmitted/sent from/to that service. Otherwise an error is issued. +// +// Algorithms +// +// Tunnel establishment +// * we need to layers: the turtle layer, and the GXS id layer. +// * at the turtle layer: +// - accept virtual peers from turtle tunnel service. The hash for that VP only depends on the server GXS id at server side, which is our +// own ID at server side, and destination ID at client side. What happens if two different clients request to talk to the same GXS id? (same hash) +// They should use different virtual peers, so it should be ok. +// - multiple tunnels may end up to the same hash, but will correspond to different GXS tunnels since the GXS id in the other side is different. +// +// * at the GXS layer +// - we should be able to have as many tunnels as they are different couples of GXS ids to interact. That means the tunnel should be determined +// by a mix between our own GXS id and the GXS id we're talking to. That is what the TunnelVirtualPeer is. +// + +// +// RequestTunnel(source_own_id,destination_id) +// | +// +---------------------------> p3Turtle::monitorTunnels( hash(destination_id) ) +// | +// [Turtle async work] -------------------+ +// | | +// handleTunnelRequest() <-----------------------------------------------+ | +// | | +// +---------------- keep record in _gxs_tunnel_virtual_peer_id, initiate DH exchange | +// | +// handleDHPublicKey() <-----------------------------------------------------------------------------+ +// | +// +---------------- update _gxs_tunnel_contacts[ tunnel_hash = hash(own_id, destination_id) ] +// | +// +---------------- notify client service that Peer(destination_id, tunnel_hash) is ready to talk to +// +// Notes +// * one other option would be to make the turtle hash depend on both GXS ids in a way that it is possible to find which are the two ids on the server side. +// but that would prevent the use of unknown IDs, which we would like to offer as well. #include #include @@ -74,9 +110,9 @@ public: // Creates the invite if the public key of the distant peer is available. // Om success, stores the invite in the map above, so that we can respond to tunnel requests. // - virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelClientService *client,uint32_t& error_code) ; - virtual bool closeExistingTunnel(const RsGxsId& pid) ; - virtual bool getTunnelStatus(const RsGxsId &gxs_id,uint32_t &status, RsGxsId *from_gxs_id=NULL) ; + virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelId& tunnel_id,uint32_t& error_code) ; + virtual bool closeExistingTunnel(const RsGxsTunnelId &tunnel_id) ; + virtual bool getTunnelStatus(const RsGxsTunnelId& tunnel_id,uint32_t &status); private: void flush() ; @@ -108,6 +144,7 @@ private: DH *dh ; RsGxsId gxs_id ; + RsGxsId own_gxs_id ; RsTurtleGenericTunnelItem::Direction direction ; uint32_t status ; TurtleFileHash hash ; @@ -115,7 +152,7 @@ private: // This maps contains the current peers to talk to with distant chat. // - std::map _gxs_tunnel_contacts ; // current peers we can talk to + std::map _gxs_tunnel_contacts ; // current peers we can talk to std::map _gxs_tunnel_virtual_peer_ids ; // current virtual peers. Used to figure out tunnels, etc. // List of items to be sent asap. Used to store items that we cannot pass directly to @@ -133,7 +170,7 @@ private: // session handling handles void markGxsTunnelAsClosed(const RsGxsId &gxs_id) ; - void startClientGxsTunnelConnection(const RsGxsId &to_gxs_id, const RsGxsId& from_gxs_id) ; + void startClientGxsTunnelConnection(const RsGxsId &to_gxs_id, const RsGxsId& from_gxs_id, RsGxsTunnelId &tunnel_id) ; void locked_restartDHSession(const RsPeerId &virtual_peer_id, const RsGxsId &own_gxs_id) ; // utility functions @@ -148,6 +185,7 @@ private: bool locked_initDHSessionKey(DH *&dh); TurtleVirtualPeerId virtualPeerIdFromHash(const TurtleFileHash& hash) ; // ... and to a hash for p3turtle + RsGxsTunnelId makeGxsTunnelId(const RsGxsId &own_id, const RsGxsId &distant_id) const; // creates a unique ID from two GXS ids. // item handling diff --git a/libretroshare/src/retroshare/rsgxstunnel.h b/libretroshare/src/retroshare/rsgxstunnel.h index 3024b96d7..cd3498877 100644 --- a/libretroshare/src/retroshare/rsgxstunnel.h +++ b/libretroshare/src/retroshare/rsgxstunnel.h @@ -36,7 +36,7 @@ public: static const uint32_t RS_GXS_TUNNEL_ERROR_NO_ERROR = 0x0000 ; static const uint32_t RS_GXS_TUNNEL_ERROR_UNKNOWN_GXS_ID = 0x0001 ; - typedef TurtleVirtualPeerId RsGxsTunnelId ; + typedef GXSTunnelId RsGxsTunnelId ; class RsGxsTunnelClientService { @@ -44,12 +44,12 @@ public: // The client should derive this in order to handle notifications from the tunnel service. // This cannot be ignored because the client needs to know when the tunnel is active. - virtual void notifyTunnelStatus(const RsGxsId& id,uint32_t tunnel_status) =0; + virtual void notifyTunnelStatus(const RsGxsTunnelId& tunnel_id,uint32_t tunnel_status) =0; // Data obtained from the corresponding GXS id. The memory ownership is transferred to the client, which // is responsible to free it using free() once used. - virtual void receiveData(const RsGxsId& id,unsigned char *data,uint32_t data_size) =0; + virtual void receiveData(const RsGxsTunnelId& id,const RsGxsId& from_id,unsigned char *data,uint32_t data_size) =0; }; class GxsTunnelInfo @@ -88,7 +88,7 @@ public: // When the tunnel is secured, the client---here supplied as argument---will be notified. He can // then send data into the tunnel. The same tunnel may be used by different clients. - virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,uint32_t& error_code) =0 ; + virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelId& tunnel_id,uint32_t& error_code) =0 ; // Data is sent through the established tunnel, possibly multiple times, until reception is acknowledged. If the tunnel does not exist, the item is rejected and // an error is issued. In any case, the memory ownership of the data is transferred to the tunnel service, so the client should not use it afterwards. diff --git a/libretroshare/src/retroshare/rsids.h b/libretroshare/src/retroshare/rsids.h index 5b1a60bfa..6893e8c11 100644 --- a/libretroshare/src/retroshare/rsids.h +++ b/libretroshare/src/retroshare/rsids.h @@ -218,6 +218,7 @@ static const uint32_t RS_GENERIC_ID_GXS_ID_TYPE = 0x0006 ; static const uint32_t RS_GENERIC_ID_GXS_MSG_ID_TYPE = 0x0007 ; static const uint32_t RS_GENERIC_ID_GXS_CIRCLE_ID_TYPE = 0x0008 ; static const uint32_t RS_GENERIC_ID_GROUTER_ID_TYPE = 0x0009 ; +static const uint32_t RS_GENERIC_ID_GXS_TUNNEL_ID_TYPE = 0x0010 ; typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_SSL_ID_TYPE> SSLIdType ; typedef t_RsGenericIdType< PGP_KEY_ID_SIZE , true, RS_GENERIC_ID_PGP_ID_TYPE> PGPIdType ; @@ -227,4 +228,5 @@ typedef t_RsGenericIdType< PGP_KEY_FINGERPRINT_SIZE, true, RS_GENERIC_ID_PGP_F typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_GROUP_ID_TYPE > GXSGroupId ; typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_ID_TYPE > GXSId ; typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_CIRCLE_ID_TYPE > GXSCircleId ; +typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_GXS_TUNNEL_ID_TYPE > GXSTunnelId ;