1 /*
2 * flood.c: handle channel flooding.
3 *
4 * This attempts to give you some protection from flooding. Basically, it keeps
5 * track of how far apart (timewise) messages come in from different people.
6 * If a single nickname sends more than 3 messages in a row in under a
7 * second, this is considered flooding. It then activates the ON FLOOD with
8 * the nickname and type (appropriate for use with IGNORE).
9 *
10 * Thanks to Tomi Ollila <f36664r@puukko.hut.fi> for this one.
11 */
12
13 #include "irc.h"
14 IRCII_RCSID("@(#)$eterna: flood.c,v 1.22 2014/01/31 12:35:57 mrg Exp $");
15
16 #include "hook.h"
17 #include "ircaux.h"
18 #include "ignore.h"
19 #include "flood.h"
20 #include "vars.h"
21 #include "output.h"
22
23 static char *ignore_types[NUMBER_OF_FLOODS] =
24 {
25 "MSG",
26 "PUBLIC",
27 "NOTICE",
28 "WALL",
29 "WALLOP"
30 };
31
32 typedef struct flood_stru
33 {
34 u_char *nick;
35 int type;
36 u_char flood;
37 long cnt;
38 time_t start;
39 } Flooding;
40
41 static Flooding *flood = NULL;
42
43 /*
44 * check_flooding: This checks for message flooding of the type specified for
45 * the given nickname. This is described above. This will return 0 if no
46 * flooding took place, or flooding is not being monitored from a certain
47 * person. It will return 1 if flooding is being check for someone and an ON
48 * FLOOD is activated.
49 *
50 * NOTE: flood's are never freed.
51 */
52 int
check_flooding(u_char * nick,u_char * to,int type,u_char * line)53 check_flooding(u_char *nick, u_char *to, int type, u_char *line)
54 {
55 static int users = 0,
56 pos = 0;
57 int i;
58 time_t flood_time,
59 diff;
60 Flooding *tmp;
61
62 if (users != get_int_var(FLOOD_USERS_VAR))
63 {
64 if ((users = get_int_var(FLOOD_USERS_VAR)) == 0)
65 return(1);
66 if (flood)
67 flood = new_realloc(flood, sizeof(*flood) * users);
68 else
69 flood = new_malloc(sizeof(*flood) * users);
70 for (i = 0; i < users; i++)
71 {
72 flood[i].nick = 0;
73 flood[i].cnt = 0;
74 flood[i].flood = 0;
75 }
76 }
77 if (users == 0)
78 return (1);
79 for (i = 0; i < users; i++)
80 {
81 if (flood[i].nick && *(flood[i].nick))
82 {
83 if ((my_stricmp(nick, flood[i].nick) == 0) &&
84 (type == flood[i].type))
85 break;
86 }
87 }
88 flood_time = time(0);
89 if (i == users)
90 {
91 pos = (pos + 1) % users;
92 tmp = &(flood[pos]);
93 tmp->nick = 0;
94 malloc_strcpy(&tmp->nick, nick);
95 tmp->type = type;
96 tmp->cnt = 1;
97 tmp->start = flood_time;
98 tmp->flood = 0;
99 return (1);
100 }
101 else
102 tmp = &(flood[i]);
103 tmp->cnt++;
104 diff = flood_time - tmp->start;
105 if (tmp->cnt > get_int_var(FLOOD_AFTER_VAR))
106 {
107 if ((diff == 0) || (tmp->cnt / diff) >
108 get_int_var(FLOOD_RATE_VAR))
109 {
110 if (tmp->flood == 0)
111 {
112 if (get_int_var(FLOOD_WARNING_VAR))
113 say("%s flooding detected from %s",
114 ignore_types[type], nick);
115 tmp->flood = 1;
116 }
117 return (do_hook(FLOOD_LIST, "%s %s %s %s", nick,
118 to, ignore_types[type], line));
119 }
120 else
121 {
122 tmp->flood = 0;
123 tmp->cnt = 1;
124 tmp->start = flood_time;
125 }
126 }
127 return (1);
128 }
129