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
This commit is contained in:
csoler 2013-09-19 22:10:24 +00:00
parent 11435dfd61
commit 8ffc0e05de
2 changed files with 70 additions and 0 deletions

View File

@ -23,6 +23,7 @@
* *
*/ */
#include <math.h> #include <math.h>
#include <sstream>
#include "openssl/rand.h" #include "openssl/rand.h"
#include "pgp/rscertificate.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. // don't transfer correctly and can kill the system.
// Images are 96x96, which makes approx. 27000 bytes uncompressed. // 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_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) p3ChatService::p3ChatService(p3LinkMgr *lm, p3HistoryMgr *historyMgr)
:p3Service(RS_SERVICE_TYPE_CHAT), p3Config(CONFIG_TYPE_CHAT), mChatMtx("p3ChatService"), mLinkMgr(lm) , mHistoryMgr(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())) while(NULL != (item=recvItem()))
handleIncomingItem(item) ; 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<time_t> recv_times ;
};
bool p3ChatService::locked_bouncingObjectCheck(RsChatLobbyBouncingObject *obj,const std::string& peer_id,uint32_t lobby_count)
{
static std::map<std::string, std::list<time_t> > 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<time_t>::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<time_t>& 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) void p3ChatService::handleIncomingItem(RsItem *item)
{ {
#ifdef CHAT_DEBUG #ifdef CHAT_DEBUG
std::cerr << "p3ChatService::receiveChatQueue() Item:" << (void*)item << std::endl ; std::cerr << "p3ChatService::receiveChatQueue() Item:" << (void*)item << std::endl ;
#endif #endif
// RsChatMsgItems needs dynamic_cast, since they have derived siblings. // RsChatMsgItems needs dynamic_cast, since they have derived siblings.
// //
RsChatMsgItem *ci = dynamic_cast<RsChatMsgItem*>(item) ; RsChatMsgItem *ci = dynamic_cast<RsChatMsgItem*>(item) ;
@ -2139,6 +2201,7 @@ bool p3ChatService::bounceLobbyObject(RsChatLobbyBouncingObject *item,const std:
#endif #endif
return false ; return false ;
} }
ChatLobbyEntry& lobby(it->second) ; ChatLobbyEntry& lobby(it->second) ;
// Adds the peer id to the list of friend participants, even if it's not original msg source // 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.msg_cache[item->msg_id] = now ;
lobby.last_activity = 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<RsChatLobbyMsgItem*>(item)) ; bool is_message = (NULL != dynamic_cast<RsChatLobbyMsgItem*>(item)) ;
// Forward to allparticipating friends, except this peer. // Forward to allparticipating friends, except this peer.

View File

@ -230,6 +230,9 @@ class p3ChatService: public p3Service, public p3Config, public pqiMonitor, publi
void handleRecvChatLobbyList(RsChatLobbyListItem_deprecated2 *item) ; void handleRecvChatLobbyList(RsChatLobbyListItem_deprecated2 *item) ;
void handleRecvChatLobbyEventItem(RsChatLobbyEventItem *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 /// Sends a request for an avatar to the peer of given id
void sendAvatarRequest(const std::string& peer_id) ; void sendAvatarRequest(const std::string& peer_id) ;