Bläddra i källkod

Merge branch 'protect'

* protect:
  * Fix typo
  * Don't enforce +protect/mdop/mop against servers (netsplit bursts)
  * If reversing modes, dump them out quickly
  * Don't count bot actions as fighting
  * fight-threshold is now a +protect trigger
  * Don't enforce_bitch() on the trigger.
  * When enforcing +protect, reverse the modes which triggered it.
  * React to non-users for 'mop/mdop' and +protect
  * Implement protect-backup
  * Add chanset 'protect-backup' which will optionally set +backup in the event of a takeover with +protect.
  * Implement +protect
  * Add chanset '+/-protect' which will set +botbitch and mass deop if any takeover is detected.

Conflicts:
	doc/help.txt
	src/chan.h
	src/mod/channels.mod/channels.c
	src/mod/channels.mod/tclchan.c
	src/mod/channels.mod/userchan.c
	src/mod/irc.mod/irc.h
	src/mod/irc.mod/mode.c
Bryan Drewery 16 år sedan
förälder
incheckning
cd3397ecb5

+ 4 - 0
doc/UPDATES

@@ -111,6 +111,10 @@
   * Credits/cmd_about updates.
   * Add chanset '+/-voicebitch' for a +bitch style enforcement over voices.
   * Add cmd_netmsg back in. It may only be used to message channels the bots are opped in.
+  * Add chanset '+/-protect' which will set +botbitch and mass deop if any takeover is detected.
+  * Add chanset 'protect-backup' which will optionally set +backup in the event of a takeover with +protect.
+  * Channel settings 'mop' and 'mdop' now react to non-users.
+  * set 'fight-threshold' now requires +protect and is a trigger for +protect. See 'help chanset' for +protect info.
 
 1.2.16.1
 * Fix linux compile errors

+ 9 - 3
doc/help.txt

@@ -355,7 +355,7 @@ See also: version, netversion, about%{+m|m}, status%{-}
 %{-}
  
 See also: link
-::chaninfo:
+::chaninfo
 ###  $bchaninfo$b <channel>
    This lists all the settings for the bot on the given channel.
    It shows any of the following:
@@ -427,6 +427,8 @@ See also: link
                           channel is set to +i. Once the channel is -i then the
                           invite will be removed the next time the bot checks.
                           Please note that this is an IRCnet feature.
+        $bprotect-backup$b    Set +backup in the event of a takeover if the
+                          channel is +protect.
         $bvoice-non-ident$b   If channel is +voice, clients without an ident will 
                           be voiced. Set to 0 to not voice clients without ident.
  
@@ -486,6 +488,9 @@ See also: link
                        Users who lose access to a channel because of this setting
                        will see no reference to it over the botnet in any place.
                        The +o restriction goes for +v as well.
+        $bprotect$b        Set chan +botbitch and mass deop the channel if someone
+                       attempts to takeover. The channel is also set +backup
+                       if protect-backup is set.
         $brbl$b             Do RBL lookups on clients and ban on matches.
                        Uses 'rbl-servers'. See also '%dhelp set'. Only the
                        +r bot will do lookups. On positive match, the bot
@@ -1680,8 +1685,9 @@ See also: reload, backup
 [N]  $blag-threshold$b   Maximum acceptable server lag for the bot to send/honor requests.
 [N]  $bkill-threshold$b  When more than this many bots have been killed/klined in the last
                           minute, close all channels.
-[N]  $bfight-threshold$b When more than this many +ob/-ob/kicks have happened on a channel in 
-                          1 minute, the channel is closed.
+[N]  $bfight-threshold$b When more than this many +obeI/-obeI/kicks have happened on a channel
+                          in 1 minute, the channel is locked down. Channel must be +protect.
+                          See also '%dhelp chanset' for +protect.
  
 [N]  $bcloak-script$b    Decides which script the bot cloaks as. 
                           If set to 0, a random script will be used.

+ 3 - 1
src/chan.h

@@ -179,6 +179,7 @@ struct chanset_t {
   int ban_type;
   interval_t auto_delay;
   int knock_flags;
+  int protect_backup;
 /* Chanint template 
  *int temp;
  */
@@ -230,7 +231,7 @@ struct chanset_t {
 #define CHAN_CLOSED         BIT3	/* Only users +o can join */
 #define CHAN_BITCH          BIT4	/* be a tightwad with ops             */
 #define CHAN_TAKE 	    BIT5	/* When a bot gets opped, take the chan */
-//#define CHAN_KNOCK 	    BIT6	/* Auto invite qualifying people when they knock */
+#define CHAN_PROTECT 	    BIT6	/* Go +bitch and mass deop if anyone mass ops or mass deops */
 #define CHAN_BOTBITCH       BIT7        /* only let bots be opped? */
 #define CHAN_BACKUP         BIT8	/* Join the BOT_BACKUP bots when set */
 #define CHAN_SECRET         BIT9	/* don't advertise channel on botnet  */
@@ -310,6 +311,7 @@ struct chanset_t *findchan_by_dname(const char *name);
 #define channel_meankicks(chan) (chan->status & CHAN_MEANKICKS)
 #define channel_rbl(chan) (chan->status & CHAN_RBL)
 #define channel_voicebitch(chan) (chan->status & CHAN_VOICEBITCH)
+#define channel_protect(chan) (chan->status & CHAN_PROTECT)
 /* Chanflag template
  *#define channel_temp(chan) (chan->status & CHAN_PRIVATE)
  */

+ 1 - 1
src/chanprog.c

@@ -54,7 +54,7 @@
 #endif
 #include <sys/utsname.h>
 
-char *def_chanset = "+enforcebans +dynamicbans +userbans -bitch +cycle -inactive +userexempts -dynamicexempts +userinvites -dynamicinvites -nodesynch -closed -take -voice -private -fastop +meankicks ban-type 3";
+char *def_chanset = "+enforcebans +dynamicbans +userbans -bitch +cycle -inactive +userexempts -dynamicexempts +userinvites -dynamicinvites -nodesynch -closed -take -voice -private -fastop +meankicks ban-type 3 protect-backup 1";
 struct chanset_t 	*chanset = NULL;	/* Channel list			*/
 struct chanset_t	*chanset_default = NULL;	/* Default channel list */
 char 			admin[121] = "";	/* Admin info			*/

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

@@ -885,6 +885,8 @@ void channels_report(int idx, int details)
           i += my_strcpy(s + i, "rbl ");
         if (channel_voicebitch(chan))
           i += my_strcpy(s + i, "voicebitch ");
+        if (channel_protect(chan))
+          i += my_strcpy(s + i, "protect ");
 /* Chanflag template
  *	if (channel_temp(chan))
  *	  i += my_strcpy(s + i, "temp ");

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

@@ -1249,6 +1249,7 @@ static void cmd_chaninfo(int idx, char *par)
     SHOW_FLAG("nodesynch",	channel_nodesynch(chan));
     SHOW_FLAG("nomassjoin",	channel_nomassjoin(chan));
     SHOW_FLAG("private",	channel_privchan(chan));
+    SHOW_FLAG("protect",	channel_protect(chan));
     SHOW_FLAG("rbl",		channel_rbl(chan));
 //    SHOW_FLAG("revengebot",	channel_revengebot(chan));
 //    SHOW_FLAG("revenge",	channel_revenge(chan));
@@ -1297,6 +1298,7 @@ static void cmd_chaninfo(int idx, char *par)
     deflag = chan->mop;
     SHOW_INT("Mop: ", chan->mop, P_STR, "Ignore");
 //    SHOW_INT("Revenge-mode: ", chan->revenge_mode, NULL, NULL);
+    SHOW_INT("Protect-backup: ", chan->protect_backup, "Do!", "Don't!");
     SHOW_INT("Voice-non-ident: ", chan->voice_non_ident, "Do!", "Don't!");
 
     dprintf(idx, "Flood settings:   chan ctcp join kick deop nick mjoin\n");

+ 13 - 0
src/mod/channels.mod/tclchan.c

@@ -543,6 +543,14 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
         return ERROR;
       }
       chan->ban_type = atoi(item[i]);
+    } else if (!strcmp(item[i], "protect-backup")) {
+      i++;
+      if (i >= items) {
+        if (result)
+          strlcpy(result, "channel protect-backup needs argument", RESULT_LEN);
+        return ERROR;
+      }
+      chan->protect_backup = atoi(item[i]);
      
 
 /* Chanint template
@@ -646,6 +654,10 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
       chan->status |= CHAN_VOICEBITCH;
     else if (!strcmp(item[i], "-voicebitch"))
       chan->status &= ~CHAN_VOICEBITCH;
+    else if (!strcmp(item[i], "+protect"))
+      chan->status |= CHAN_PROTECT;
+    else if (!strcmp(item[i], "-protect"))
+      chan->status &= ~CHAN_PROTECT;
 /* Chanflag template
  *  else if (!strcmp(item[i], "+temp"))
  *    chan->status |= CHAN_TEMP;
@@ -975,6 +987,7 @@ int channel_add(char *result, char *newname, char *options, bool isdefault)
 /* Chanint template
  *  chan->temp = 0;
  */
+    chan->protect_backup = 1;
     chan->knock_flags = 0;
     chan->flood_lock_time = 120;
     chan->flood_exempt_mode = 0;

+ 3 - 1
src/mod/channels.mod/userchan.c

@@ -734,7 +734,7 @@ flood-exempt %d flood-lock-time %d knock %d \
 %cmeankicks %cenforcebans %cdynamicbans %cuserbans %cbitch \
 %cprivate %ccycle %cinactive %cdynamicexempts %cuserexempts \
 %cdynamicinvites %cuserinvites %cnodesynch %cclosed %cvoice \
-%cfastop %cautoop %cbotbitch %cbackup %cnomassjoin %crbl %cvoicebitch %c%s",
+%cfastop %cautoop %cbotbitch %cbackup %cnomassjoin %crbl %cvoicebitch %cprotect protect-backup %d %c%s",
 	w,
 /* Chanchar template
  *      temp,
@@ -790,6 +790,8 @@ flood-exempt %d flood-lock-time %d knock %d \
         PLSMNS(channel_nomassjoin(chan)),
         PLSMNS(channel_rbl(chan)),
         PLSMNS(channel_voicebitch(chan)),
+        PLSMNS(channel_protect(chan)),
+        chan->protect_backup,
 	HAVE_TAKE ? PLSMNS(channel_take(chan)) : ' ',
         HAVE_TAKE ? "take " : " "
 /* Chanflag template

+ 6 - 1
src/mod/irc.mod/chan.c

@@ -704,6 +704,8 @@ static bool detect_chan_flood(char *floodnick, char *floodhost, char *from,
         dprintf(DP_MODE, "KICK %s %s :%s%s\n", chan->name, floodnick, kickprefix, response(RES_KICKFLOOD));
 	m->flags |= SENTKICK;
       }
+      if (channel_protect(chan))
+        do_protect(chan, "Mass Kick");
     return 1;
     case FLOOD_DEOP:
       if (me_op(chan) && !chan_sentkick(m)) {
@@ -718,6 +720,8 @@ static bool detect_chan_flood(char *floodnick, char *floodhost, char *from,
         simple_snprintf(s, sizeof(s), "Mass deop on %s by %s", chan->dname, from);
         deflag_user(u, DEFLAG_MDOP, s, chan);
       }
+      if (channel_protect(chan))
+        do_protect(chan, "Mass Deop");
       return 1;
     }
   }
@@ -2882,9 +2886,10 @@ static int gotkick(char *from, char *origmsg)
     struct userrec *u = NULL;
     struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0 };
 
-    chan->channel.fighting++;
     fixcolon(msg);
     u = get_user_by_host(from);
+    if (!u || (u && !u->bot))
+      chan->channel.fighting++;
     strlcpy(uhost, from, sizeof(buf));
     whodid = splitnick(&uhost);
     detect_chan_flood(whodid, uhost, from, chan, FLOOD_KICK, nick);

+ 20 - 8
src/mod/irc.mod/irc.c

@@ -1439,17 +1439,29 @@ check_servers(struct chanset_t *chan)
   }
 }
 
+static void do_protect(struct chanset_t* chan, const char* reason) {
+  // Don't bother with these if already botbitch, already processed it, or it's a hacked bot and +botbitch won't help.
+  if (!channel_botbitch(chan)) {
+    if (chan->protect_backup) {
+      putlog(LOG_MISC, "*", "%s detected in %s: Setting +botbitch/+backup to protect the channel.", reason, chan->dname);
+      do_chanset(NULL, chan, "+botbitch +bitch +backup", DO_LOCAL | DO_NET);
+    } else {
+      putlog(LOG_MISC, "*", "%s detected in %s: Setting +botbitch to protect the channel.", reason, chan->dname);
+      do_chanset(NULL, chan, "+botbitch +bitch", DO_LOCAL | DO_NET);
+    }
+//        enforce_closed(chan);
+//        dprintf(DP_MODE, "TOPIC %s :Auto-closed - channel fight\n", chan->name);
+//    enforce_bitch(chan);
+    reversing = 1; // Reverse any modes which triggered this.
+  }
+}
+
 static void
 check_netfight(struct chanset_t *chan)
 {
-  if (fight_threshold) {
-    if ((chan->channel.fighting) && (chan->channel.fighting > fight_threshold)) {
-      if (!chan_bitch(chan) || !channel_closed(chan)) {
-        putlog(LOG_WARN, "*", "Auto-closed %s - channel fight", chan->dname);
-        do_chanset(NULL, chan, "+bitch +closed +backup", DO_LOCAL | DO_NET);
-        enforce_closed(chan);
-        dprintf(DP_MODE, "TOPIC %s :Auto-closed - channel fight\n", chan->name);
-      }
+  if (channel_protect(chan) && fight_threshold) {
+    if ((chan->channel.fighting) && (chan->channel.fighting > fight_threshold) && !chan_bitch(chan)) {
+      do_protect(chan, "Channel fight");
     }
   }
   chan->channel.fighting = 0;   /* we put this here because we need to clear it once per min */

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

@@ -71,6 +71,7 @@ static bool any_ops(struct chanset_t *);
 static char *getchanmode(struct chanset_t *);
 static void flush_mode(struct chanset_t *, int);
 static bool member_getuser(memberlist* m, bool act_on_lookup = 0);
+static void do_protect(struct chanset_t* chan, const char* reason);
 
 /* reset(bans|exempts|invites) are now just macros that call resetmasks
  * in order to reduce the code duplication. <cybah>

+ 33 - 18
src/mod/irc.mod/mode.c

@@ -1070,21 +1070,25 @@ gotmode(char *from, char *msg)
       if (me_op(chan)) {
         char tmp[1024] = "";
 
-        if (role && u && !u->bot) {
-          if (m && !chan_sentkick(m) && deops >= 3 && chan->mdop) {
-            if (role < 5) {
-              m->flags |= SENTKICK;
-              const size_t len = simple_snprintf(tmp, sizeof(tmp), "KICK %s %s :%s%s\r\n", chan->name, m->nick, kickprefix, response(RES_MASSDEOP));
-              if (role <= 2)
-                tputs(serv, tmp, len);
-              else
-                dprintf(DP_MODE, "%s", tmp);
-            } else {
-              if (u) {
-                simple_snprintf(tmp, sizeof(tmp), "Mass deop on %s by %s", chan->dname, m->nick);
-                deflag_user(u, DEFLAG_MDOP, tmp, chan);
+        if (!isserver[0] && role && (!u || (u && !u->bot))) {
+          if (m && deops >= 3) {
+            if (chan->mdop) {
+              if (role < 5 && !chan_sentkick(m)) {
+                m->flags |= SENTKICK;
+                const size_t len = simple_snprintf(tmp, sizeof(tmp), "KICK %s %s :%s%s\r\n", chan->name, m->nick, kickprefix, response(RES_MASSDEOP));
+                if (role <= 2)
+                  tputs(serv, tmp, len);
+                else
+                  dprintf(DP_MODE, "%s", tmp);
+              } else {
+                if (u) {
+                  simple_snprintf(tmp, sizeof(tmp), "Mass deop on %s by %s", chan->dname, m->nick);
+                  deflag_user(u, DEFLAG_MDOP, tmp, chan);
+                }
               }
             }
+            if (channel_protect(chan))
+              do_protect(chan, "Mass Deop");
           }
 
           /* check for mop */
@@ -1105,8 +1109,12 @@ gotmode(char *from, char *msg)
                   }
                 }
               }
-              enforce_bitch(chan);        /* deop quick! */
+              // Don't mass deop if protect is set, it'll happen anyway below
+              if (!channel_protect(chan))
+                enforce_bitch(chan);        /* deop quick! */
             }
+            if (channel_protect(chan))
+              do_protect(chan, "Mass OP");
           }
         }
         if (ops) {
@@ -1380,7 +1388,8 @@ gotmode(char *from, char *msg)
             }
             break;
           case 'o':
-            chan->channel.fighting++;
+            if (!u || (u && !u->bot))
+              chan->channel.fighting++;
             mv = assert_ismember(chan, mparam);
             if (mv) {
               if (msign == '+')
@@ -1442,21 +1451,24 @@ gotmode(char *from, char *msg)
             }
             break;
           case 'b':
-            chan->channel.fighting++;
+            if (!u || (u && !u->bot))
+              chan->channel.fighting++;
             if (msign == '+')
               got_ban(chan, m, mparam, isserver);
             else
               got_unban(chan, m, mparam);
             break;
           case 'e':
-            chan->channel.fighting++;
+            if (!u || (u && !u->bot))
+              chan->channel.fighting++;
             if (msign == '+')
               got_exempt(chan, m, mparam, isserver);
             else
               got_unexempt(chan, m, mparam);
             break;
           case 'I':
-            chan->channel.fighting++;
+            if (!u || (u && !u->bot))
+              chan->channel.fighting++;
             if (msign == '+')
               got_invite(chan, m, mparam, isserver);
             else
@@ -1480,6 +1492,9 @@ gotmode(char *from, char *msg)
           }
         }
       }
+      // If reversing, dump the modes out
+      if (reversing)
+        flush_mode(chan, QUICK);
       for (i = 0; i < modecnt; i++)
         if (modes[i])
           free(modes[i]);