]>
Commit | Line | Data |
---|---|---|
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 | 24 | static void syn_ratecheck(hook_channel_joinpart_t *data); |
2c57ef4d SB |
25 | |
26 | static void syn_cmd_setrate(sourceinfo_t *si, int parc, char **parv); | |
47e48552 | 27 | static void syn_cmd_showrate(sourceinfo_t *si, int parc, char **parv); |
2c57ef4d | 28 | |
47e48552 SB |
29 | command_t syn_setrate = { "SETRATE", N_("Sets join-rate monitoring thresholds"), "syn:general", 3, syn_cmd_setrate }; |
30 | command_t syn_showrate = { "SHOWRATE", N_("Displays join-rate monitoring thresholds"), "syn:general", 1, syn_cmd_showrate }; | |
2c57ef4d | 31 | |
47e48552 SB |
32 | int default_rate; |
33 | int default_burst; | |
2c57ef4d SB |
34 | int warn_time; |
35 | ||
36 | typedef 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 | ||
48 | mowgli_patricia_t *channellist; | |
b918d5d9 | 49 | mowgli_heap_t *channelheap; |
2c57ef4d SB |
50 | static void free_channelentry(const char *, void *data, void *); |
51 | ||
47e48552 SB |
52 | void 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 | ||
101 | void 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 | 120 | static 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 | 140 | static 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 | ||
152 | static void free_channelentry(const char *key, void *data, void *privdata) | |
153 | { | |
b918d5d9 | 154 | mowgli_heap_free(channelheap, data); |
2c57ef4d SB |
155 | } |
156 | ||
a3064be2 | 157 | static 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 | 197 | static 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 |
217 | static 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 | |
299 | DECLARE_MODULE_V1 | |
300 | ( | |
301 | "syn/joinrate", false, mod_init, mod_deinit, | |
302 | "$Revision$", | |
303 | "Stephen Bennett <stephen -at- freenode.net>" | |
304 | ); |