From 8ffc0e05de061f783b9e5b6909c0c4e1716c019f Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 19 Sep 2013 22:10:24 +0000 Subject: [PATCH] added control for suspicious message activity in chat lobbies. Lobby items are not bounced if coming from a peer that sends more messages per seconds than a given limit. The limit is adaptive and depends on lobby count git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@6751 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- libretroshare/src/services/p3chatservice.cc | 67 +++++++++++++++++++++ libretroshare/src/services/p3chatservice.h | 3 + 2 files changed, 70 insertions(+) diff --git a/libretroshare/src/services/p3chatservice.cc b/libretroshare/src/services/p3chatservice.cc index 7e1d27667..6dbc9478c 100644 --- a/libretroshare/src/services/p3chatservice.cc +++ b/libretroshare/src/services/p3chatservice.cc @@ -23,6 +23,7 @@ * */ #include +#include #include "openssl/rand.h" #include "pgp/rscertificate.h" @@ -71,6 +72,8 @@ static const uint32_t MAX_AVATAR_JPEG_SIZE = 32767; // Maximum size // don't transfer correctly and can kill the system. // Images are 96x96, which makes approx. 27000 bytes uncompressed. static const uint32_t MAX_ALLOWED_LOBBIES_IN_LIST_WARNING = 50 ; +static const uint32_t MAX_MESSAGES_PER_SECONDS_NUMBER = 5 ; // max number of messages from a given peer in a window for duration below +static const uint32_t MAX_MESSAGES_PER_SECONDS_PERIOD = 10 ; // duration window for max number of messages before messages get dropped. p3ChatService::p3ChatService(p3LinkMgr *lm, p3HistoryMgr *historyMgr) :p3Service(RS_SERVICE_TYPE_CHAT), p3Config(CONFIG_TYPE_CHAT), mChatMtx("p3ChatService"), mLinkMgr(lm) , mHistoryMgr(historyMgr) @@ -698,12 +701,71 @@ void p3ChatService::receiveChatQueue() while(NULL != (item=recvItem())) handleIncomingItem(item) ; } +class MsgCounter +{ + public: + MsgCounter() {} + + void clean(time_t max_time) + { + while(!recv_times.empty() && recv_times.front() < max_time) + recv_times.pop_front() ; + } + std::list recv_times ; +}; + + +bool p3ChatService::locked_bouncingObjectCheck(RsChatLobbyBouncingObject *obj,const std::string& peer_id,uint32_t lobby_count) +{ + static std::map > message_counts ; + + std::ostringstream os ; + os << obj->lobby_id ; + + std::string pid = peer_id + "_" + os.str() ; + + VisibleChatLobbyRecord& rec(_visible_lobbies[obj->lobby_id]) ; + lobby_count = rec.total_number_of_peers ; + + // max objects per second: lobby_count * 1/MAX_DELAY_BETWEEN_LOBBY_KEEP_ALIVE objects per second. + // So in cache, there is in average that number times MAX_MESSAGES_PER_SECONDS_PERIOD + // + float max_cnt = std::max(10.0f, 4*lobby_count / (float)MAX_DELAY_BETWEEN_LOBBY_KEEP_ALIVE * MAX_MESSAGES_PER_SECONDS_PERIOD) ; + +#ifdef CHAT_DEBUG + std::cerr << "lobby_count=" << lobby_count << std::endl; + std::cerr << "Got msg for peer " << pid << std::dec << ". Limit is " << max_cnt << ". List is " ; + for(std::list::const_iterator it(message_counts[pid].begin());it!=message_counts[pid].end();++it) + std::cerr << *it << " " ; + std::cerr << std::endl; +#endif + + time_t now = time(NULL) ; + + std::list& lst = message_counts[pid] ; + + // Clean old messages time stamps from the list. + // + while(!lst.empty() && lst.front() + MAX_MESSAGES_PER_SECONDS_PERIOD < now) + lst.pop_front() ; + + if(lst.size() > max_cnt) + { + std::cerr << "Too many messages from peer " << pid << ". Someone (name=" << obj->nick << ") is trying to flood this lobby. Message will not be forwarded." << std::endl; + return false; + } + else + lst.push_back(now) ; + + return true ; +} void p3ChatService::handleIncomingItem(RsItem *item) { #ifdef CHAT_DEBUG std::cerr << "p3ChatService::receiveChatQueue() Item:" << (void*)item << std::endl ; #endif + // RsChatMsgItems needs dynamic_cast, since they have derived siblings. // RsChatMsgItem *ci = dynamic_cast(item) ; @@ -2139,6 +2201,7 @@ bool p3ChatService::bounceLobbyObject(RsChatLobbyBouncingObject *item,const std: #endif return false ; } + ChatLobbyEntry& lobby(it->second) ; // Adds the peer id to the list of friend participants, even if it's not original msg source @@ -2167,6 +2230,10 @@ bool p3ChatService::bounceLobbyObject(RsChatLobbyBouncingObject *item,const std: lobby.msg_cache[item->msg_id] = now ; lobby.last_activity = now ; + // Check that if we have a lobby bouncing object, it's not flooding the lobby + if(!locked_bouncingObjectCheck(item,peer_id,lobby.participating_friends.size())) + return false; + bool is_message = (NULL != dynamic_cast(item)) ; // Forward to allparticipating friends, except this peer. diff --git a/libretroshare/src/services/p3chatservice.h b/libretroshare/src/services/p3chatservice.h index f0dbe03f5..b21ced51c 100644 --- a/libretroshare/src/services/p3chatservice.h +++ b/libretroshare/src/services/p3chatservice.h @@ -230,6 +230,9 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor, publi void handleRecvChatLobbyList(RsChatLobbyListItem_deprecated2 *item) ; void handleRecvChatLobbyEventItem(RsChatLobbyEventItem *item) ; + /// Checks that the lobby object is not flooding a lobby. + bool locked_bouncingObjectCheck(RsChatLobbyBouncingObject *obj,const std::string& peer_id,uint32_t lobby_count) ; + /// Sends a request for an avatar to the peer of given id void sendAvatarRequest(const std::string& peer_id) ;