]> jfr.im git - irc/freenode/syn.git/blame - joinrate.c
add licence info
[irc/freenode/syn.git] / joinrate.c
CommitLineData
0a30e865
SB
1/*
2 * syn: a utility bot to manage IRC network access
3 * Copyright (C) 2009-2016 Stephen Bennett
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19
2c57ef4d
SB
20#include "atheme.h"
21
3e65cfbd
SB
22#include "syn.h"
23
a3064be2 24static void syn_ratecheck(hook_channel_joinpart_t *data);
2c57ef4d
SB
25
26static void syn_cmd_setrate(sourceinfo_t *si, int parc, char **parv);
47e48552 27static void syn_cmd_showrate(sourceinfo_t *si, int parc, char **parv);
2c57ef4d 28
47e48552
SB
29command_t syn_setrate = { "SETRATE", N_("Sets join-rate monitoring thresholds"), "syn:general", 3, syn_cmd_setrate };
30command_t syn_showrate = { "SHOWRATE", N_("Displays join-rate monitoring thresholds"), "syn:general", 1, syn_cmd_showrate };
2c57ef4d 31
47e48552
SB
32int default_rate;
33int default_burst;
2c57ef4d
SB
34int warn_time;
35
36typedef struct
37{
47e48552
SB
38 char chname[CHANNELLEN];
39
40 bool use_custom;
41 int rate[2];
42
43 time_t curr_rate_time;
44
2c57ef4d
SB
45 time_t last_warn_time;
46} channelentry;
47
48mowgli_patricia_t *channellist;
b918d5d9 49mowgli_heap_t *channelheap;
2c57ef4d
SB
50static void free_channelentry(const char *, void *data, void *);
51
47e48552
SB
52void load_rate_settings()
53{
54 FILE *f = fopen(DATADIR "/rates.db", "r");
55 if (!f)
56 {
57 slog(LG_DEBUG, "Couldn't open rates.db for reading: %s", strerror(errno));
58 return;
59 }
60
61 char line[BUFSIZE];
62 while (fgets(line, BUFSIZE, f))
63 {
64 char *chname = strtok(line, " ");
65
66 if (0 == strcmp(chname, "default"))
67 {
68 char *srate = strtok(NULL, " ");
69 char *sburst = strtok(NULL, " ");
70 if (!srate || !sburst)
71 continue;
72
73 default_rate = atoi(srate);
74 default_burst = atoi(sburst);
75
76 continue;
77 }
78
79 char *srate = strtok(NULL, " ");
80 char *sburst = strtok(NULL, " ");
81 if (!srate || !sburst)
82 continue;
83
84 int rate = atoi(srate), burst = atoi(sburst);
85
86 channelentry *ce = mowgli_patricia_retrieve(channellist, chname);
87 if (!ce)
88 {
b918d5d9 89 ce = mowgli_heap_alloc(channelheap);
47e48552
SB
90 strncpy(ce->chname, chname, CHANNELLEN);
91 ce->use_custom = true;
92 mowgli_patricia_add(channellist, chname, ce);
93 }
94 ce->rate[0] = rate;
95 ce->rate[1] = burst;
96 }
97
98 fclose(f);
99}
100
101void save_rate_settings()
102{
103 FILE *f = fopen(DATADIR "/rates.db", "w");
104 if (!f)
105 {
106 slog(LG_ERROR, "Couldn't open rates.db for writing: %s", strerror(errno));
107 return;
108 }
109 fprintf(f, "default %d %d\n", default_rate, default_burst);
110
111 channelentry *ce;
112 mowgli_patricia_iteration_state_t state;
113 MOWGLI_PATRICIA_FOREACH(ce, &state, channellist)
114 {
115 fprintf(f, "%s %d %d\n", ce->chname, ce->rate[0], ce->rate[1]);
116 }
117 fclose(f);
118}
119
492a4dc0 120static void mod_init(module_t *m)
2c57ef4d 121{
3e65cfbd 122 use_syn_main_symbols(m);
2c57ef4d 123
b918d5d9
SB
124 service_named_bind_command("syn", &syn_setrate);
125 service_named_bind_command("syn", &syn_showrate);
2c57ef4d
SB
126
127 hook_add_event("channel_join");
a3064be2 128 hook_add_channel_join(syn_ratecheck);
2c57ef4d
SB
129
130 channellist = mowgli_patricia_create(noopcanon);
b918d5d9 131 channelheap = mowgli_heap_create(sizeof(channelentry), 512, BH_NOW);
2c57ef4d 132
47e48552
SB
133 default_rate = 5;
134 default_burst = 5;
2c57ef4d
SB
135 warn_time = 30;
136
47e48552 137 load_rate_settings();
2c57ef4d
SB
138}
139
492a4dc0 140static void mod_deinit(module_unload_intent_t intent)
2c57ef4d 141{
47e48552
SB
142 save_rate_settings();
143
2c57ef4d 144 mowgli_patricia_destroy(channellist, free_channelentry, NULL);
47e48552 145
b918d5d9
SB
146 service_named_unbind_command("syn", &syn_setrate);
147 service_named_unbind_command("syn", &syn_showrate);
47e48552 148
a3064be2 149 hook_del_channel_join(syn_ratecheck);
2c57ef4d
SB
150}
151
152static void free_channelentry(const char *key, void *data, void *privdata)
153{
b918d5d9 154 mowgli_heap_free(channelheap, data);
2c57ef4d
SB
155}
156
a3064be2 157static void syn_ratecheck(hook_channel_joinpart_t *data)
2c57ef4d 158{
2c57ef4d
SB
159 chanuser_t *cu = data->cu;
160
b4fcac0e
SB
161 // Don't warn about burst joins.
162 if (me.bursting)
163 return;
164
2c57ef4d
SB
165 channelentry *ce = mowgli_patricia_retrieve(channellist, cu->chan->name);
166 if (!ce)
167 {
b918d5d9 168 ce = mowgli_heap_alloc(channelheap);
47e48552 169 strncpy(ce->chname, cu->chan->name, CHANNELLEN);
2c57ef4d
SB
170 mowgli_patricia_add(channellist, cu->chan->name, ce);
171 }
172
47e48552
SB
173 int rate, burst;
174 if (ce->use_custom)
175 {
176 rate = ce->rate[0];
177 burst = ce->rate[1];
178 }
179 else
180 {
181 rate = default_rate;
182 burst = default_burst;
183 }
184
185 if (ce->curr_rate_time < CURRTIME)
186 ce->curr_rate_time = CURRTIME;
187
188 ce->curr_rate_time += rate;
189 if (ce->curr_rate_time > (rate * burst) + CURRTIME &&
190 ce->last_warn_time + warn_time < CURRTIME)
2c57ef4d
SB
191 {
192 ce->last_warn_time = CURRTIME;
47e48552 193 syn_report("Join rate in %s exceeds warning threshold(%d/%d)", ce->chname, rate, burst);
2c57ef4d
SB
194 }
195}
196
47e48552 197static void syn_cmd_showrate(sourceinfo_t *si, int parc, char **parv)
2c57ef4d 198{
47e48552
SB
199 if (parc == 0)
200 {
767e4663 201 command_success_nodata(si, "Global warning threshold is %d seconds, %d burst", default_rate, default_burst);
47e48552
SB
202 return;
203 }
2c57ef4d 204
47e48552
SB
205 channelentry *ce = mowgli_patricia_retrieve(channellist, parv[0]);
206
207 if (!ce || !ce->use_custom)
2c57ef4d 208 {
767e4663 209 command_success_nodata(si, "No custom warning threshold is set for %s", parv[0]);
47e48552 210 return;
2c57ef4d 211 }
47e48552 212
767e4663 213 command_success_nodata(si, "Warning threshold for %s is %d seconds, %d burst", ce->chname, ce->rate[0], ce->rate[1]);
2c57ef4d
SB
214}
215
47e48552 216
2c57ef4d
SB
217static void syn_cmd_setrate(sourceinfo_t *si, int parc, char **parv)
218{
219 if (parc < 2)
220 {
767e4663
SB
221 command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SETRATE");
222 command_fail(si, fault_needmoreparams, _("Syntax: SETRATE [#channel] default|(<rate> <burst>)"));
2c57ef4d
SB
223 return;
224 }
47e48552
SB
225
226 if (parv[0][0] != '#')
227 {
228 int r, b;
229 r = atoi(parv[0]);
230 b = atoi(parv[1]);
231
232 if (r * b == 0)
233 {
767e4663
SB
234 command_fail(si, fault_badparams, STR_INVALID_PARAMS, "SETRATE");
235 command_fail(si, fault_needmoreparams, _("Syntax: SETRATE [#channel] default|(<rate> <burst>)"));
47e48552
SB
236 return;
237 }
238
239 default_rate = r;
240 default_burst = b;
241
d131c46d 242 syn_report("\002SETRATE\002 default->%d/%d by %s", default_rate, default_burst, get_oper_name(si));
767e4663 243 command_success_nodata(si, "Warning threshold set to %d seconds, with a burst of %d", default_rate, default_burst);
47acd50b 244 save_rate_settings();
47e48552
SB
245 return;
246 }
247
248 channelentry *ce = mowgli_patricia_retrieve(channellist, parv[0]);
249
250 if (0 == strcasecmp(parv[1], "default"))
251 {
252 if (!ce || !ce->use_custom)
253 {
767e4663 254 command_fail(si, fault_nochange, "No custom rate settings were defined for %s", parv[0]);
47e48552
SB
255 return;
256 }
257 ce->use_custom = false;
d131c46d 258 syn_report("\002SETRATE\002 %s->default by %s", parv[0], get_oper_name(si));
767e4663 259 command_success_nodata(si, "Custom rate settings have been disabled for %s", parv[0]);
47acd50b 260 save_rate_settings();
47e48552
SB
261 return;
262 }
263
264 if (parc < 3)
265 {
767e4663
SB
266 command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SETRATE");
267 command_fail(si, fault_needmoreparams, _("Syntax: SETRATE [#channel] default|(<rate> <burst>)"));
47e48552
SB
268 return;
269 }
270
271 if (!ce)
272 {
b918d5d9 273 ce = mowgli_heap_alloc(channelheap);
47e48552
SB
274 strncpy(ce->chname, parv[0], CHANNELLEN);
275 mowgli_patricia_add(channellist, parv[0], ce);
276 }
277
2c57ef4d 278 int r, b;
47e48552
SB
279 r = atoi(parv[1]);
280 b = atoi(parv[2]);
2c57ef4d
SB
281
282 if (r * b == 0)
283 {
767e4663
SB
284 command_fail(si, fault_badparams, STR_INVALID_PARAMS, "SETRATE");
285 command_fail(si, fault_needmoreparams, _("Syntax: SETRATE [#channel] default|(<rate> <burst>)"));
2c57ef4d
SB
286 return;
287 }
288
47e48552
SB
289 ce->use_custom = true;
290 ce->rate[0] = r;
291 ce->rate[1] = b;
c644ff10 292 ce->curr_rate_time = 0;
2c57ef4d 293
d131c46d 294 syn_report("\002SETRATE\002 %s->%d/%d by %s", parv[0], r, b, get_oper_name(si));
767e4663 295 command_success_nodata(si, "Warning threshold for %s set to %d seconds, with a burst of %d", parv[0], r, b);
47acd50b 296 save_rate_settings();
2c57ef4d 297}
492a4dc0
JK
298
299DECLARE_MODULE_V1
300(
301 "syn/joinrate", false, mod_init, mod_deinit,
302 "$Revision$",
303 "Stephen Bennett <stephen -at- freenode.net>"
304);