]> jfr.im git - irc/rizon/plexus4.git/commitdiff
Add floodtime
authorAdam <redacted>
Mon, 7 Nov 2016 00:09:36 +0000 (19:09 -0500)
committerAdam <redacted>
Mon, 7 Nov 2016 00:47:45 +0000 (19:47 -0500)
14 files changed:
doc/reference.conf
include/conf.h
include/ircd.h
modules/core/m_message.c
modules/m_set.c
src/conf.c
src/conf_lexer.l
src/conf_parser.y
src/ircd.c
test/Makefile.am
test/expect.c
test/plexus_test.h
test/test.c
test/tests/privmsg.c [new file with mode: 0644]

index e785fff62368f86ec16c196376a3b8239294ece2..d43d3de0d4436a8c49149fa51e1478b3b8365ac6 100644 (file)
@@ -1146,10 +1146,16 @@ general {
        /*
         * default_floodcount: the default value of floodcount that is configurable
         * via /quote set floodcount. This is the number of lines a user
-        * may send to any other user/channel in one second.
+        * may send to any other user/channel per floodtime.
         */
        default_floodcount = 50;
 
+       /*
+        * default_floodtime: the default value of floodtime that is configurable
+        * via /quote set floodtime.
+        */
+       default_floodtime = 1;
+
        /*
         * failed_oper_notice: send a notice to all opers on the server when
         * someone tries to OPER and uses the wrong password, host or ident.
index 0157b732f3e4f216b8254c4f4d8d65402bb4473b..c727cf602bfc2998e0e2881a7991cde52e29ba97 100644 (file)
@@ -267,6 +267,7 @@ struct config_file_entry
   int min_nonwildcard_simple;
   int kill_chase_time_limit;
   int default_floodcount;
+  int default_floodtime;
   int throttle_num;
   /* 0 == don't use throttle... */
   int throttle_time;
index c7b3511b3844402b0e1bde6563bde07e7c9eeeda..24e6e56e48f40a886ce1d66f0400dc25a8c3972e 100644 (file)
@@ -35,7 +35,8 @@
 struct SetOptions
 {
   int autoconn;      /* autoconn enabled for all servers? */
-  int floodcount;    /* Number of messages in 1 second    */
+  int floodcount;    /* Number of messages in floodtime seconds */
+  int floodtime;
   int joinfloodtime;
   int joinfloodcount;
   int ident_timeout; /* timeout for identd lookups        */
index af09b58f37c2e25ba97abd531941acc7e0fcac0a..a1679fea5c16f6a8406c2214b04819eb5702fc94 100644 (file)
@@ -121,24 +121,20 @@ flood_attack_client(int p_or_n, struct Client *source_p,
   assert(MyClient(target_p));
   assert(IsClient(source_p));
 
-  if (GlobalSetOptions.floodcount && !IsCanFlood(source_p) && !HasUMode(source_p, UMODE_OPER) && !HasFlag(source_p, FLAGS_SERVICE))
+  if (GlobalSetOptions.floodcount && GlobalSetOptions.floodtime
+      && !IsCanFlood(source_p) && !HasUMode(source_p, UMODE_OPER) && !HasFlag(source_p, FLAGS_SERVICE))
   {
-    if ((target_p->localClient->first_received_message_time + 1)
-        < CurrentTime)
+    if (target_p->localClient->first_received_message_time + GlobalSetOptions.floodtime < CurrentTime)
     {
-      int delta = CurrentTime - target_p->localClient->first_received_message_time;
-      target_p->localClient->received_number_of_privmsgs -= delta;
-      target_p->localClient->first_received_message_time = CurrentTime;
-
-      if (target_p->localClient->received_number_of_privmsgs <= 0)
-      {
-        target_p->localClient->received_number_of_privmsgs = 0;
+      if (target_p->localClient->received_number_of_privmsgs == 0)
         DelFlag(target_p, FLAGS_FLOOD_NOTICED);
-      }
+      else
+        target_p->localClient->received_number_of_privmsgs = 0;
+
+      target_p->localClient->first_received_message_time = CurrentTime;
     }
 
-    if ((target_p->localClient->received_number_of_privmsgs >=
-         GlobalSetOptions.floodcount) || HasFlag(target_p, FLAGS_FLOOD_NOTICED))
+    if (target_p->localClient->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
     {
       if (!HasFlag(target_p, FLAGS_FLOOD_NOTICED))
       {
@@ -147,9 +143,6 @@ flood_attack_client(int p_or_n, struct Client *source_p,
                        get_client_name(source_p, HIDE_IP),
                        source_p->servptr->name, target_p->name);
         AddFlag(target_p, FLAGS_FLOOD_NOTICED);
-
-        /* Add a bit of penalty */
-        target_p->localClient->received_number_of_privmsgs += 2;
       }
 
       if (p_or_n != NOTICE)
@@ -158,8 +151,8 @@ flood_attack_client(int p_or_n, struct Client *source_p,
                    ID_or_name(&me, source_p), ID_or_name(source_p, source_p), target_p->name);
       return 1;
     }
-    else
-      target_p->localClient->received_number_of_privmsgs++;
+
+    ++target_p->localClient->received_number_of_privmsgs;
   }
 
   return 0;
@@ -178,26 +171,22 @@ static int
 flood_attack_channel(int p_or_n, struct Client *source_p,
                      struct Channel *chptr)
 {
-  int delta;
   int conf_exempt = MyClient(source_p) && (get_flood_burst(&source_p->localClient->confs) || get_flood_limit(&source_p->localClient->confs));
 
-  if (GlobalSetOptions.floodcount && !IsCanFlood(source_p) && !HasUMode(source_p, UMODE_OPER) && !HasFlag(source_p, FLAGS_SERVICE) && !conf_exempt)
+  if (GlobalSetOptions.floodcount && GlobalSetOptions.floodtime
+      && !IsCanFlood(source_p) && !HasUMode(source_p, UMODE_OPER) && !HasFlag(source_p, FLAGS_SERVICE) && !conf_exempt)
   {
-    if ((chptr->first_received_message_time + 1) < CurrentTime)
+    if (chptr->first_received_message_time + GlobalSetOptions.floodtime < CurrentTime)
     {
-      delta = CurrentTime - chptr->first_received_message_time;
-      chptr->received_number_of_privmsgs -= delta;
-      chptr->first_received_message_time = CurrentTime;
-
-      if (chptr->received_number_of_privmsgs <= 0)
-      {
-        chptr->received_number_of_privmsgs = 0;
+      if (chptr->received_number_of_privmsgs == 0)
         ClearFloodNoticed(chptr);
-      }
+      else
+        chptr->received_number_of_privmsgs = 0;
+
+      chptr->first_received_message_time = CurrentTime;
     }
 
-    if ((chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount) ||
-         IsSetFloodNoticed(chptr))
+    if (chptr->received_number_of_privmsgs >= GlobalSetOptions.floodcount)
     {
       if (!IsSetFloodNoticed(chptr))
       {
@@ -206,9 +195,6 @@ flood_attack_channel(int p_or_n, struct Client *source_p,
                        get_client_name(source_p, HIDE_IP),
                        source_p->servptr->name, chptr->chname);
         SetFloodNoticed(chptr);
-
-        /* Add a bit of penalty */
-        chptr->received_number_of_privmsgs += 2;
       }
 
       if (MyClient(source_p))
@@ -220,8 +206,8 @@ flood_attack_channel(int p_or_n, struct Client *source_p,
         return 1;
       }
     }
-    else
-      chptr->received_number_of_privmsgs++;
+
+    ++chptr->received_number_of_privmsgs;
   }
 
   return 0;
index 1c6e3dec9c2a8efef057c1e01811bbdff3c4d37a..b9ff69a4ce80b5a77dc70e672e2adacd04f4bd3f 100644 (file)
@@ -110,6 +110,22 @@ quote_floodcount(struct Client *source_p, int newval)
                me.name, source_p->name, GlobalSetOptions.floodcount);
 }
 
+/* SET FLOODTIME */
+static void
+quote_floodtime(struct Client *source_p, int newval)
+{
+  if (newval >= 0)
+  {
+    GlobalSetOptions.floodtime = newval;
+    sendto_snomask(SNO_ALL, L_ALL,
+                   "%s has changed FLOODTIME to %i",
+                   get_oper_name(source_p), GlobalSetOptions.floodtime);
+  }
+  else
+    sendto_one(source_p, ":%s NOTICE %s :FLOODTIME is currently %i",
+                         me.name, source_p->name, GlobalSetOptions.floodtime);
+}
+
 /* SET IDENTTIMEOUT */
 static void
 quote_identtimeout(struct Client *source_p, int newval)
@@ -435,6 +451,7 @@ static const struct SetStruct set_cmd_table[] =
   { "AUTOCONN",         quote_autoconn,         1,      1 },
   { "AUTOCONNALL",      quote_autoconnall,      0,      1 },
   { "FLOODCOUNT",       quote_floodcount,       0,      1 },
+  { "FLOODTIME",        quote_floodtime,        0,      1 },
   { "IDENTTIMEOUT",     quote_identtimeout,     0,      1 },
   { "MAX",              quote_max,              0,      1 },
   { "SPAMNUM",          quote_spamnum,          0,      1 },
index 0a80e05a2086a672c5483b0a63a387b50b9b5da7..2a5cf2e15e6f9b80358e109603fa08a718624dbe 100644 (file)
@@ -1273,6 +1273,7 @@ set_default_conf(void)
   ConfigFileEntry.disable_auth = 0;
   ConfigFileEntry.kill_chase_time_limit = 90;
   ConfigFileEntry.default_floodcount = 8;
+  ConfigFileEntry.default_floodtime = 1;
   ConfigFileEntry.failed_oper_notice = 1;
   ConfigFileEntry.dots_in_ident = 0;
   ConfigFileEntry.min_nonwildcard = 4;
index 5984eb606e1e09a165c8028ae4e777884a9a1cb4..f47706b29fe3430a618f05abd42f63b663612d18 100644 (file)
@@ -174,6 +174,7 @@ cycle_on_host_change        { return CYCLE_ON_HOST_CHANGE; }
 deaf                        { return T_DEAF; }
 debug                       { return T_DEBUG; }
 default_floodcount          { return DEFAULT_FLOODCOUNT; }
+default_floodtime           { return DEFAULT_FLOODTIME; }
 default_split_server_count  { return DEFAULT_SPLIT_SERVER_COUNT; }
 default_split_user_count    { return DEFAULT_SPLIT_USER_COUNT; }
 defer                       { return DEFER; }
index ae1e1b6c82ac6e450ec5357fa972ef0e5e8fad06..7eca38f3e8ec9cb29f89a837a548a5a2768db85b 100644 (file)
@@ -183,6 +183,7 @@ reset_block_state(void)
 %token  CONNECTFREQ
 %token  CYCLE_ON_HOST_CHANGE
 %token  DEFAULT_FLOODCOUNT
+%token  DEFAULT_FLOODTIME
 %token  DEFAULT_SPLIT_SERVER_COUNT
 %token  DEFAULT_SPLIT_USER_COUNT
 %token  DEFER
@@ -2885,7 +2886,7 @@ general_item:       general_hide_spoof_ips | general_ignore_bogus_ts |
                     general_oper_pass_resv |
                     general_oper_only_umodes | general_max_targets |
                     general_oper_umodes | general_oper_snomasks | general_caller_id_wait |
-                    general_opers_bypass_callerid | general_default_floodcount |
+                    general_opers_bypass_callerid | general_default_floodcount | general_default_floodtime |
                     general_min_nonwildcard | general_min_nonwildcard_simple |
                     general_throttle_num | general_throttle_time | general_havent_read_conf |
                     general_ping_cookie | general_nick_collide_realhost | 
@@ -3423,6 +3424,11 @@ general_default_floodcount: DEFAULT_FLOODCOUNT '=' NUMBER ';'
   ConfigFileEntry.default_floodcount = $3;
 };
 
+general_default_floodtime: DEFAULT_FLOODTIME '=' NUMBER ';'
+{
+  ConfigFileEntry.default_floodtime = $3;
+};
+
 
 /***************************************************************************
  *  section channel
index b9e6260a93f671cf2f9bc57c0522c3f77d6d65d3..0937102e90e37d9f6a15283947ce962a7aafc116 100644 (file)
@@ -291,6 +291,11 @@ initialize_global_set_options(void)
   else
     GlobalSetOptions.floodcount = 10;
 
+  if (ConfigFileEntry.default_floodtime)
+    GlobalSetOptions.floodtime = ConfigFileEntry.default_floodtime;
+  else
+    GlobalSetOptions.floodtime = 1;
+
   /* XXX I have no idea what to try here - Dianora */
   GlobalSetOptions.joinfloodcount = 16;
   GlobalSetOptions.joinfloodtime = 8;
index 9aa9ffee5eb94cccca35f1c6888e5665bf4bc55f..bb274d3fb75c3bc79a33335fef59176083a3ce2d 100644 (file)
@@ -28,6 +28,7 @@ check_plexus_SOURCES = \
        tests/join.c \
        tests/mode.c \
        tests/nick.c \
+       tests/privmsg.c \
        tests/session.c \
        tests/upgrade.c
 
index 0a2ad4abd13acf46b24499d826afc106f9fb3c8d..5d34f8415d5955637256eb3993c22a85afb64f7b 100644 (file)
@@ -67,10 +67,10 @@ expect_message(struct PlexusClient *client, struct Client *from, const char *mes
 
   if (from == NULL)
     snprintf(buffer, sizeof(buffer), "%s *", message);
-  else if (IsServer(from) || IsMe(from))
-    snprintf(buffer, sizeof(buffer), ":%s %s *", ID_or_name(from, client->client), message);
-  else
+  else if (IsClient(from))
     snprintf(buffer, sizeof(buffer), ":%s!%s@%s %s *", from->name, from->username, from->host, message);
+  else
+    snprintf(buffer, sizeof(buffer), ":%s %s *", ID_or_name(from, client->client), message);
 
   expect(client, buffer);
 }
@@ -80,8 +80,12 @@ expect_message_args(struct PlexusClient *client, struct Client *from, const char
 {
   char buffer[IRCD_BUFSIZE];
   va_list args;
+  int off;
 
-  int off = snprintf(buffer, sizeof(buffer), ":%s!%s@%s ", from->name, from->username, from->host);
+  if (IsClient(from))
+    off = snprintf(buffer, sizeof(buffer), ":%s!%s@%s ", from->name, from->username, from->host);
+  else
+    off = snprintf(buffer, sizeof(buffer), ":%s ", from->name);
 
   va_start(args, fmt);
   vsnprintf(buffer + off, sizeof(buffer) - off, fmt, args);
index d23c7909119bc660b5e9d2032e15ff5efe4bd446..20cf0829de7ca5cf09fb7ff11177f8899451d997 100644 (file)
@@ -78,6 +78,7 @@ extern void dnsbl_setup(Suite *);
 extern void nick_setup(Suite *s);
 extern void extban_setup(Suite *s);
 extern void session_setup(Suite *s);
+extern void privmsg_setup(Suite *s);
 
 #define tlog(fmt, ...) plexus_log(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
 extern void plexus_log(const char *, int, const char *, ...);
index 12dce50bd52f7ed85fde9d875bb983aefce523b9..5f9e36ad631f0255c3883dd4dc51c182ed212b1c 100644 (file)
@@ -39,6 +39,7 @@ add_testcases(Suite *s)
   nick_setup(s);
   extban_setup(s);
   session_setup(s);
+  privmsg_setup(s);
 }
 
 int
diff --git a/test/tests/privmsg.c b/test/tests/privmsg.c
new file mode 100644 (file)
index 0000000..5f6cccd
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
+ *
+ *  Copyright (c) 2016 Adam <Adam@anope.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ *  USA
+ */
+
+#include "plexus_test.h"
+
+START_TEST(privmsg_flood)
+{
+  struct PlexusClient *client1 = client_register("test1"),
+                      *client2 = client_register("test2");
+
+  irc_join(client1, "#a");
+  expect_message(client1, client1->client, "JOIN");
+
+  irc_join(client2, "#a");
+  expect_message(client2, client2->client, "JOIN");
+
+  struct Channel *chptr = hash_find_channel("#a");
+  ck_assert_ptr_ne(chptr, NULL);
+
+  struct Membership *client1_ms = find_channel_link(client1->client, chptr);
+  ck_assert_ptr_ne(client1_ms, NULL);
+
+  client1_ms->flags = 0; // remove channel op
+
+  GlobalSetOptions.floodcount = 2;
+  GlobalSetOptions.floodtime = 60;
+
+  irc_privmsg(client1, "#a", "test");
+  expect_message(client2, client1->client, "PRIVMSG");
+
+  irc_privmsg(client1, "#a", "test");
+  expect_message(client2, client1->client, "PRIVMSG");
+
+  ck_assert_int_eq(chptr->received_number_of_privmsgs, 2);
+
+  irc_privmsg(client1, "#a", "test");
+  expect_message_args(client1, &me, "NOTICE %s :*** Message to %s throttled due to flooding", client1->client->name, chptr->chname);
+
+  ck_assert_int_eq(chptr->received_number_of_privmsgs, 2);
+
+  chptr->first_received_message_time -= 61;
+
+  irc_privmsg(client1, "#a", "test");
+  expect_message(client2, client1->client, "PRIVMSG");
+
+  ck_assert_int_eq(chptr->received_number_of_privmsgs, 1);
+}
+END_TEST
+
+void
+privmsg_setup(Suite *s)
+{
+  TCase *tc = tcase_create("privmsg");
+
+  tcase_add_checked_fixture(tc, plexus_up, plexus_down);
+  tcase_add_test(tc, privmsg_flood);
+
+  suite_add_tcase(s, tc);
+}