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