Browse Source

Merge branch '43-flood-improvements'

* 43-flood-improvements:
  Add flood counters to memberlist and split channel by uhost (#43)
Bryan Drewery 14 năm trước cách đây
mục cha
commit
e14441a580

+ 1 - 0
doc/UPDATES

@@ -37,6 +37,7 @@
   * Bots now ask for ops quicker if another bot is opped
   * Bots now request/join +ilk channels much quicker
   * Add 'chanset revenge' which will react/kick/ban/remove users who kick/ban/deop bots.
+  * Fix flood kicking not properly tracking multiple clients at once (#43)
 
 1.3.4 - http://wraith.botpack.net/milestone/1.3.4
   * Fix various compile warnings with newer GCC

+ 6 - 3
src/chan.h

@@ -27,6 +27,8 @@ typedef struct memstruct {
   char from[NICKLEN + UHOSTLEN];   /* nick!user@host */
   char fromip[NICKLEN + UHOSTLEN]; /* nick!user@ip */
   bool is_me;
+  bd::HashTable<flood_t, time_t>     *floodtime; // floodtime[FLOOD_PRIVMSG] = now;
+  bd::HashTable<flood_t, int>         *floodnum; // floodnum[FLOOD_PRIVMSG] = 1;
 } memberlist;
 
 #define CHAN_FLAG_OP	1
@@ -122,6 +124,10 @@ struct chan_t {
   char *topic;
   char *key;
   unsigned short int mode;
+
+  // Shared non-member counts (JOIN/PART)
+  bd::HashTable<bd::String, bd::HashTable<flood_t, time_t> >     *floodtime; // floodtime[uhost][FLOOD_PRIVMSG] = now;
+  bd::HashTable<bd::String, bd::HashTable<flood_t, int> >         *floodnum; //  floodnum[uhost][FLOOD_PRIVMSG] = 1;
 };
 
 #define CHANINV    BIT0		/* +i					*/
@@ -158,7 +164,6 @@ struct chanset_t {
     char *op;
   } ccmode[MODES_PER_LINE_MAX];                 /* parameter-type mode changes -        */
   /* detect floods */
-  time_t floodtime[FLOOD_CHAN_MAX];
   uint32_t status;
   uint32_t ircnet_status;
   int flood_pub_thr;
@@ -208,7 +213,6 @@ struct chanset_t {
   size_t bytes;			/* total bytes so far			*/
   size_t cbytes;
   int compat;			/* to prevent mixing old/new modes	*/
-  int floodnum[FLOOD_CHAN_MAX];
   int opreqtime[5];             /* remember when ops was requested */
 
   char *key;			/* new key to set			*/
@@ -223,7 +227,6 @@ struct chanset_t {
  */
   char topic[121];
   char added_by[HANDLEN + 1];	/* who added the channel? */
-  char floodwho[FLOOD_CHAN_MAX][128];
   char dname[81];               /* what the users know the channel as like !eggdev */
   char name[81];                /* what the servers know the channel as, like !ABCDEeggdev */
 };

+ 23 - 8
src/eggdrop.h

@@ -127,14 +127,29 @@ enum {		/* TAKE A GUESS */
 
 
 /* chan & global */
-#define FLOOD_PRIVMSG    0
-#define FLOOD_NOTICE     1
-#define FLOOD_CTCP       2
-#define FLOOD_NICK       3
-#define FLOOD_JOIN       4
-#define FLOOD_KICK       5
-#define FLOOD_DEOP       6
-#define FLOOD_PART       7
+enum flood_t {
+  FLOOD_PRIVMSG  = 0,
+  FLOOD_NOTICE   = 1,
+  FLOOD_CTCP     = 2,
+  FLOOD_NICK     = 3,
+  FLOOD_JOIN     = 4,
+  FLOOD_KICK     = 5,
+  FLOOD_DEOP     = 6,
+  FLOOD_PART     = 7
+};
+
+
+#include <bdlib/src/bdlib.h>
+BDLIB_NS_BEGIN
+template<typename T>
+  struct Hash;
+
+template<>
+  struct Hash<flood_t>
+  {
+    inline size_t operator()(flood_t val) const { return static_cast<size_t>(val); }
+  };
+BDLIB_NS_END
 
 #define FLOOD_CHAN_MAX   8
 #define FLOOD_GLOBAL_MAX 3

+ 12 - 0
src/mod/channels.mod/chanmisc.c

@@ -897,6 +897,8 @@ static void init_channel(struct chanset_t *chan, bool reset)
   chan->channel.member->nick[0] = 0;
   chan->channel.member->next = NULL;
   chan->channel.topic = NULL;
+  chan->channel.floodtime = new bd::HashTable<bd::String, bd::HashTable<flood_t, time_t> >;
+  chan->channel.floodnum  = new bd::HashTable<bd::String, bd::HashTable<flood_t, int> >;
 }
 
 static void clear_masklist(masklist *m)
@@ -923,6 +925,8 @@ void clear_channel(struct chanset_t *chan, bool reset)
     free(chan->channel.topic);
   for (m = chan->channel.member; m; m = m1) {
     m1 = m->next;
+    delete m->floodtime;
+    delete m->floodnum;
     free(m);
   }
 
@@ -938,6 +942,11 @@ void clear_channel(struct chanset_t *chan, bool reset)
   chan->ircnet_status = 0;
 //  chan->ircnet_status &= ~CHAN_HAVEBANS;
 
+  delete chan->channel.floodtime;
+  chan->channel.floodtime = NULL;
+  delete chan->channel.floodnum;
+  chan->channel.floodnum = NULL;
+
   if (reset)
     init_channel(chan, 1);
   for (size_t i = 0; i < MODES_PER_LINE_MAX; ++i) {
@@ -950,6 +959,7 @@ void clear_channel(struct chanset_t *chan, bool reset)
       chan->ccmode[i].op = NULL;
     }
   }
+
 }
 
 /* Create new channel and parse commands.
@@ -1050,6 +1060,8 @@ int channel_add(char *result, const char *newname, char *options, bool isdefault
     chan->channel.drone_jointime = 0;
     chan->channel.drone_joins = 0;
     chan->channel.last_eI = 0;
+    chan->channel.floodtime = NULL;
+    chan->channel.floodnum = NULL;
 
     /* We _only_ put the dname (display name) in here so as not to confuse
      * any code later on. chan->name gets updated with the channel name as

+ 2 - 0
src/mod/channels.mod/channels.c

@@ -723,6 +723,8 @@ void remove_channel(struct chanset_t *chan)
    if (chan->groups) {
      delete(chan->groups);
    }
+   delete chan->channel.floodtime;
+   delete chan->channel.floodnum;
    free(chan);
 }
 

+ 42 - 15
src/mod/irc.mod/chan.c

@@ -280,6 +280,8 @@ static memberlist *newmember(struct chanset_t *chan, char *nick)
   }
 
   ++(chan->channel.members);
+  n->floodtime = new bd::HashTable<flood_t, time_t>;
+  n->floodnum  = new bd::HashTable<flood_t, int>;
   return n;
 }
 
@@ -538,7 +540,7 @@ static void do_mask(struct chanset_t *chan, masklist *m, char *mask, char Mode)
 /* This is a clone of detect_flood, but works for channel specificity now
  * and handles kick & deop as well.
  */
-static bool detect_chan_flood(memberlist* m, const char *from, struct chanset_t *chan, int which, const char *msg)
+static bool detect_chan_flood(memberlist* m, const char *from, struct chanset_t *chan, flood_t which, const char *msg)
 {
   /* Do not punish non-existant channel members and IRC services like
    * ChanServ
@@ -624,24 +626,49 @@ static bool detect_chan_flood(memberlist* m, const char *from, struct chanset_t
     if (!p)
       return 0;
   }
-  if (rfc_casecmp(chan->floodwho[which], p)) {	/* new */
-    strlcpy(chan->floodwho[which], p, sizeof(chan->floodwho[which]));
-    chan->floodtime[which] = now;
-    chan->floodnum[which] = 1;
-    return 0;
+
+  bd::HashTable<flood_t, time_t>      *floodtime; // floodtime[FLOOD_PRIVMSG] = now;
+  bd::HashTable<flood_t, int>         *floodnum;  //  floodnum[FLOOD_PRIVMSG] = 1;
+
+  switch (which) {
+    // These 2 don't have a persistent member, use chan list
+    case FLOOD_JOIN:
+    case FLOOD_PART:
+      // If not found, add them and start the count for next iteration
+      if (!chan->channel.floodtime->contains(m->userhost)) {
+        (*chan->channel.floodtime)[m->userhost][which] = now;
+        (*chan->channel.floodnum)[m->userhost][which] = 1;
+        return 0;
+      } else {
+        floodtime = &(*chan->channel.floodtime)[m->userhost];
+        floodnum = &(*chan->channel.floodnum)[m->userhost];
+      }
+      break;
+    default:
+      // Everything else, log to the member
+      // If not found, add them and start the count for next iteration
+      if (!m->floodtime->contains(which)) {
+        (*m->floodtime)[which] = now;
+        (*m->floodnum)[which] = 1;
+        return 0;
+      } else {
+        floodtime = m->floodtime;
+        floodnum = m->floodnum;
+      }
+      break;
   }
-  if (chan->floodtime[which] < now - lapse) {
+
+  if ((*floodtime)[which] < now - lapse) {
     /* Flood timer expired, reset it */
-    chan->floodtime[which] = now;
-    chan->floodnum[which] = 1;
+    (*floodtime)[which] = now;
+    (*floodnum)[which] = 1;
     return 0;
   }
-  chan->floodnum[which]++;
-  if (chan->floodnum[which] >= thr) {	/* FLOOD */
+  (*floodnum)[which]++;
+  if ((*floodnum)[which] >= thr) {	/* FLOOD */
     /* Reset counters */
-    chan->floodnum[which] = 0;
-    chan->floodtime[which] = 0;
-    chan->floodwho[which][0] = 0;
+    (*floodnum).remove(which);
+    (*floodtime).remove(which);
     switch (which) {
     case FLOOD_PRIVMSG:
     case FLOOD_NOTICE:
@@ -685,7 +712,7 @@ static bool detect_chan_flood(memberlist* m, const char *from, struct chanset_t
       if (!channel_enforcebans(chan) && me_op(chan)) {
 	  for (m = chan->channel.member; m && m->nick[0]; m = m->next) {	  
 	    if (!chan_sentkick(m) && wild_match(h, m->from) &&
-		(m->joined >= chan->floodtime[which]) &&
+		(m->joined >= (*floodtime)[which]) &&
 		!m->is_me && me_op(chan)) {
 	      m->flags |= SENTKICK;
 	      if (which == FLOOD_JOIN)

+ 2 - 0
src/mod/irc.mod/irc.c

@@ -1077,6 +1077,8 @@ killmember(struct chanset_t *chan, char *nick)
     old->next = x->next;
   else
     chan->channel.member = x->next;
+  delete x->floodtime;
+  delete x->floodnum;
   free(x);
   chan->channel.members--;
 

+ 1 - 1
src/mod/irc.mod/irc.h

@@ -82,7 +82,7 @@ static void do_protect(struct chanset_t* chan, const char* reason);
 static bool do_op(char *, struct chanset_t *, bool, bool);
 static void request_op(struct chanset_t *);
 static void request_in(struct chanset_t *);
-static bool detect_chan_flood(memberlist *m, const char* from, struct chanset_t *chan, int which, const char *msg = NULL);
+static bool detect_chan_flood(memberlist *m, const char* from, struct chanset_t *chan, flood_t which, const char *msg = NULL);
 static bool new_mask(masklist *, char *, char *);
 static void do_closed_kick(struct chanset_t *, memberlist *);
 static char *quickban(struct chanset_t *, const char *);