/*
* 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.
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;
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 */
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))
{
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)
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;
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))
{
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))
return 1;
}
}
- else
- chptr->received_number_of_privmsgs++;
+
+ ++chptr->received_number_of_privmsgs;
}
return 0;
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)
{ "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 },
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;
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; }
%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
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 |
ConfigFileEntry.default_floodcount = $3;
};
+general_default_floodtime: DEFAULT_FLOODTIME '=' NUMBER ';'
+{
+ ConfigFileEntry.default_floodtime = $3;
+};
+
/***************************************************************************
* section channel
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;
tests/join.c \
tests/mode.c \
tests/nick.c \
+ tests/privmsg.c \
tests/session.c \
tests/upgrade.c
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);
}
{
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);
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 *, ...);
nick_setup(s);
extban_setup(s);
session_setup(s);
+ privmsg_setup(s);
}
int
--- /dev/null
+/*
+ * 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);
+}