/******************************************************************************* * libretroshare/src/gxs: gxsnettunnel.h * * * * libretroshare: retroshare core library * * * * Copyright (C) 2018 Cyril Soler * * Copyright (C) 2021 Gioacchino Mazzurco * * Copyright (C) 2021 AsociaciĆ³n Civil Altermundi * * * * 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 #include #include "turtle/p3turtle.h" #include "retroshare/rsgxsdistsync.h" /*! * \brief The RsGxsNetTunnelService class takes care of requesting tunnels to the turtle router, through which it is possible to sync * a particular GXS group. For each group, a set of virtual peers, corresponding to active tunnels will be made available * to RsGxsNetService. * * It is the responsibility of RsGxsNetService to activate/desactivate tunnels for each particular group, depending on wether the group * is already available at regular friends or not. * * Tunnel management is done at the level of groups rather than services, because we would like to keep the possibility to not * request tunnels for some groups which do not need it, and only request tunnels for specific groups that cannot be provided * by direct connections. */ // Protocol: // * request tunnels based on H(GroupId) // * encrypt tunnel data using chacha20+HMAC-SHA256 using AEAD( GroupId, 96bits IV, tunnel ID ) (similar to what FT does) // * when tunnel is established, exchange virtual peer names: vpid = H( GroupID | Random bias ) // * when vpid is known, notify the client (GXS net service) which can use the virtual peer to sync // * only use a single tunnel per virtual peer ID // - // Client ------------------ TR(H(GroupId)) --------------> Server | // | Turtle // Client <-------------------- T OK ---------------------- Server | // - // Here, a turtle vpid is known | [ addVirtualPeer() called by turtle ] // - // [Encrypted traffic using H(GroupId | Tunnel ID, 96bits IV)] | // | // Client <--------- VPID = H( Random IV | GroupId ) ------ Server | // | | | // +--------------> Mark the virtual peer active <-----------+ | Encrypted traffic decoded locally and sorted // | // Here, a consistent virtual peer ID is known | // | // Client <------------------- GXS Data ------------------> Server | // - // Notes: // * tunnels are established symmetrically. If a distant peers wants to sync the same group, they'll have to open a single tunnel, with a different ID. // Groups therefore have two states: // - managed : the group can be used to answer tunnel requests. If server tunnels are established, the group will be synced with these peers // - tunneled: the group will actively request tunnels. If tunnels are established both ways, the same virtual peers will be used so the tunnels are "merged". // * In practice, that means one of the two tunnels will not be used and therefore die. // * If a tunneled group already has enough virtual peers, it will not request for tunnels itself. // // Group policy | Request tunnels | SyncWithPeers | Item receipt // --------------------+-------------------+-----------------------+---------------- // Passive | no | If peers present | If peers present // Active | yes, if no peers | If peers present | If peers present // | | | // // * when a service has the DistSync flag set, groups to sync are communicated passively to the GxsNetTunnel service when requesting distant peers. // However, a call should be made to set a particular group policy to "ACTIVE" for group that do not have peers and need some. // // * services also need to retrieve GXS data items that come out of tunnels. These will be available as (data,len) type, since they are not de-serialized. // // * GxsNetService stores data information (such as update maps) per peerId, so it makes sense to use the same PeerId for all groups of a given service // Therefore, virtual peers are stored separately from groups, because each one can sync multiple groups. // // * virtual peers are also shared among services. This reduces the required amount of tunnels and tunnel requests to send. // // * tunnels for a given service may also be used by the net service of p3IdService in order to explicitely request missing GxsIds. // So GxsNetTunnel somehow allows different services to use the same tunnel. However we make sure that this traffic is limited to only p3IdService. // // How do we know that a group needs distant sync? // * look into GrpConfigMap for suppliers. Suppliers is cleared at load. // * last_update_TS in GrpConfigMap is randomised so it cannot be used // * we need a way to know that there's no suppliers for good reasons (not that we just started) // // Security // * the question of sync-ing with distant anonymous peers is a bit tricky because these peers can try to generate fake requests or change which messages are available // and there is no way to prevent it. We therefore rely on GXS data integrity system to prevent this to happen. // struct RsGxsNetTunnelItem; class RsNetworkExchangeService ; class RsGxsNetTunnelService: public RsTurtleClientService, public RsTickingThread, public p3Config, public RsGxsDistSync { public: RsGxsNetTunnelService(); ~RsGxsNetTunnelService() override; /*! * \brief registerSearchableService * Adds the network exchange service as a possible search source. This is used to allow distant search on the corresponding * GXS service. * \return * always returns true. */ bool registerSearchableService(RsNetworkExchangeService *) ; /*! * \brief Manage tunnels for this group * @param group_id group for which tunnels should be released */ bool requestDistantPeers(uint16_t service_id,const RsGxsGroupId&group_id) ; /*! * \brief Stop managing tunnels for this group * @param group_id group for which tunnels should be released */ bool releaseDistantPeers(uint16_t service_id, const RsGxsGroupId&group_id) ; /*! * \brief Get the list of active virtual peers for a given group. This implies that a tunnel is up and * alive. This function also "registers" the group which allows to handle tunnel requests in the server side. */ bool getVirtualPeers(std::list& peers) ; // returns the virtual peers for this service /*! * \brief serviceId * Overloads the method in RsTurtleClientService. * \return * The service id for RsGxsNetTunnel. */ uint16_t serviceId() const override ; /*! * \brief sendData * send data to this virtual peer, and takes memory ownership (deletes the item) * \param item item to send * \param virtual_peer destination virtual peer * \return * true if succeeded. */ bool sendTunnelData(uint16_t service_id,unsigned char *& data, uint32_t data_len, const RsGxsNetTunnelVirtualPeerId& virtual_peer) ; /*! * \brief receiveData * returns the next piece of data received, and the virtual GXS peer that sended it. * \param data memory check containing the data. Memory ownership belongs to the client. * \param data_len length of memory chunk * \param virtual_peer peer who sent the data * \return * true if something is returned. If not, data is set to NULL, data_len to 0. */ bool receiveTunnelData(uint16_t service_id, unsigned char *& data, uint32_t& data_len, RsGxsNetTunnelVirtualPeerId& virtual_peer) ; /*! * \brief isDistantPeer * returns wether the peer is in the list of available distant peers or not * \param group_id returned by the service to indicate which group this peer id is designed for. * \return true if the peer is a distant GXS peer. */ bool isDistantPeer(const RsGxsNetTunnelVirtualPeerId& virtual_peer,RsGxsGroupId& group_id) ; /*! * \brief dumps all information about monitored groups. */ void dump() const; /*! * Should be called after allocating a RsGxsNetTunnelService * \param tr turtle router object */ void connectToTurtleRouter(p3turtle *tr) override; /** Gxs services (channels, forums...) are supposed to use this to request * searches on distant peers */ std::error_condition turtleSearchRequest( rs_owner_ptr searchData, uint32_t dataSize, RsServiceType serviceType, TurtleRequestId& requestId ); ///@see RsTurtleClientService bool receiveSearchRequest( unsigned char* search_request_data, uint32_t search_request_data_len, unsigned char*& search_result_data, uint32_t& search_result_data_len, uint32_t& max_allowed_hits ) override; ///@see RsTurtleClientService virtual void receiveSearchResult( TurtleSearchRequestId request_id, unsigned char* search_result_data, uint32_t search_result_data_len ) override; TurtleRequestId turtleGroupRequest( const RsGxsGroupId& group_id, RsNetworkExchangeService* client_service ); /// @see RsTickingThread void threadTick() override; // Overloads p3Config RsSerialiser *setupSerialiser()override ; bool saveList(bool& cleanup, std::list& save)override ; bool loadList(std::list &load)override ; // Overloads RsGxsDistSync void getStatistics(std::map& groups, // groups on the client and server side std::map& virtual_peers, // current virtual peers, which group they provide, and how to talk to them through turtle std::map& turtle_vpid_to_net_tunnel_vpid, Bias20Bytes& bias) const override ; RS_DEPRECATED TurtleRequestId turtleSearchRequest( const std::string& match_string, RsNetworkExchangeService* client_service ); protected: // interaction with turtle router virtual bool handleTunnelRequest(const RsFileHash &hash,const RsPeerId& peer_id) override ; virtual void receiveTurtleData(const RsTurtleGenericTunnelItem *item,const RsFileHash& hash,const RsPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) override ; void addVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&,RsTurtleGenericTunnelItem::Direction dir) override ; void removeVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&) override ; const Bias20Bytes& locked_randomBias() ; p3turtle *mTurtle ; static const uint32_t RS_GXS_TUNNEL_CONST_RANDOM_BIAS_SIZE = 20 ; static const uint32_t RS_GXS_TUNNEL_CONST_EKEY_SIZE = 32 ; mutable Bias20Bytes mRandomBias ; // constant accross reboots. Allows to disguise the real SSL id while providing a consistent value accross time. private: void autowash() ; void sendKeepAlivePackets() ; void handleIncoming(RsGxsNetTunnelItem *item) ; void flush_pending_items(); rs_view_ptr retrievieSearchableServiceLocking( uint16_t serviceType ); std::map mGroups ; // groups on the client and server side std::map mVirtualPeers ; // current virtual peers, which group they provide, and how to talk to them through turtle std::map mHandledHashes ; // hashes asked to turtle. Used to answer tunnel requests std::map mTurtle2GxsPeer ; // convertion table to find GXS peer id from turtle std::list > mPendingTurtleItems ; // items that need to be sent off-turtle Mutex. std::map > > mIncomingData; // list of incoming data items std::map mSearchableServices ; /*! * \brief Generates the hash to request tunnels for this group. This hash is only used by turtle, and is used to * hide the real group id. */ RsFileHash calculateGroupHash(const RsGxsGroupId&group_id) const ; /*! * \brief makeVirtualPeerIdForGroup creates a virtual peer id that can be used and that will be constant accross time, whatever the * tunnel ID and turtle virtual peer id. This allows RsGxsNetService to keep sync-ing the data consistently. */ RsGxsNetTunnelVirtualPeerId locked_makeVirtualPeerId(const RsGxsGroupId& group_id) ; static void generateEncryptionKey(const RsGxsGroupId& group_id,const TurtleVirtualPeerId& vpid,unsigned char key[RS_GXS_TUNNEL_CONST_EKEY_SIZE]) ; mutable RsMutex mGxsNetTunnelMtx; friend class RsGxsTunnelRandomBiasItem ; friend class StoreHere ; rstime_t mLastKeepAlive ; rstime_t mLastAutoWash ; rstime_t mLastDump ; };