]> jfr.im git - irc/freenode/syn.git/blob - kline.c
add licence info
[irc/freenode/syn.git] / kline.c
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
20 #include "atheme.h"
21 #include "pmodule.h"
22
23 #include "syn.h"
24
25 mowgli_patricia_t *ircd_klines;
26 mowgli_list_t ircd_wildcard_klines;
27 mowgli_heap_t *ircd_kline_heap;
28
29 mowgli_eventloop_timer_t *expire_timer = 0;
30
31 static void syn_m_kline(sourceinfo_t *si, int parc, char **parv);
32 static void syn_m_ban(sourceinfo_t *si, int parc, char **parv);
33 static void syn_m_unkline(sourceinfo_t *si, int parc, char **parv);
34 static void expire_klines(void *unused);
35
36 char *kline_kill_reason = 0;
37
38 static void mod_init(module_t *m)
39 {
40 use_syn_main_symbols(m);
41
42 ircd_klines = mowgli_patricia_create(noopcanon);
43 ircd_kline_heap = mowgli_heap_create(sizeof(kline_t), 512, BH_NOW);
44
45 hook_add_event("syn_kline_added");
46
47 add_dupstr_conf_item("KLINE_KILL_REASON", &syn->conf_table, 0, &kline_kill_reason, "Banned");
48
49 pcommand_add("KLINE", syn_m_kline, 5, MSRC_USER);
50 pcommand_add("BAN", syn_m_ban, 8, MSRC_USER | MSRC_SERVER);
51 pcommand_add("UNKLINE", syn_m_unkline, 3, MSRC_USER);
52
53 expire_timer = mowgli_timer_add(base_eventloop, "expire_ircd_klines", expire_klines, NULL, 120);
54 }
55
56 static void mod_deinit(module_unload_intent_t intent)
57 {
58 pcommand_delete("KLINE");
59 pcommand_delete("BAN");
60 pcommand_delete("UNKLINE");
61 mowgli_timer_destroy(base_eventloop, expire_timer);
62 }
63
64 kline_t* _syn_find_kline(const char *user, const char *host)
65 {
66 kline_t *k;
67 if ((k = mowgli_patricia_retrieve(ircd_klines, host)))
68 return k;
69
70 mowgli_node_t *n;
71 MOWGLI_LIST_FOREACH(n, ircd_wildcard_klines.head)
72 {
73 k = n->data;
74 if (0 == match(k->host, host))
75 return k;
76 if (0 == match_ips(k->host, host))
77 return k;
78 }
79 return NULL;
80 }
81
82 static void syn_add_kline(const char *setter, const char *user, const char *host, int duration, const char *reason)
83 {
84 if (_syn_find_kline(user, host))
85 {
86 syn_debug(3, "Duplicate K:line %s@%s", user, host);
87 return;
88 }
89
90 if (host[0] == '*' && host[1] == '\0')
91 {
92 wallops("%s is an idiot. Dropping *@* kline.", setter);
93 return;
94 }
95
96 kline_t *k = mowgli_heap_alloc(ircd_kline_heap);
97 k->duration = duration;
98 k->settime = CURRTIME;
99 k->expires = CURRTIME + k->duration;
100 k->user = sstrdup(user);
101 k->host = sstrdup(host);
102 k->reason = sstrdup(reason);
103
104 char *p;
105 if (NULL != (p = strchr(k->reason, '|')))
106 {
107 *p = '\0';
108 }
109
110 if (strchr(k->host, '*') || strchr(k->host, '?') || (strchr(k->host, '/') && valid_ip_or_mask(k->host)))
111 {
112 mowgli_node_t *n = mowgli_node_create();
113 mowgli_node_add(k, n, &ircd_wildcard_klines);
114 }
115 else
116 {
117 mowgli_patricia_add(ircd_klines, k->host, k);
118 }
119
120 hook_call_event("syn_kline_added", k);
121
122 syn_debug(1, "Added K:line %s@%s (%s)", k->user, k->host, k->reason);
123 }
124
125 static void syn_remove_kline(const char *user, const char *host)
126 {
127 mowgli_node_t *n, *tn;
128 kline_t *k;
129
130 kline_t *removed = mowgli_patricia_delete(ircd_klines, host);
131 if (removed)
132 {
133 syn_debug(1, "Removing K:line on %s@%s", removed->user, removed->host);
134 free(removed->user);
135 free(removed->host);
136 free(removed->reason);
137 mowgli_heap_free(ircd_kline_heap, removed);
138 return;
139 }
140
141 MOWGLI_LIST_FOREACH_SAFE(n, tn, ircd_wildcard_klines.head)
142 {
143 k = (kline_t*) n->data;
144 if (0 == strcasecmp(k->user, user) &&
145 0 == strcasecmp(k->host, host))
146 {
147 syn_debug(1, "Removing K:line on %s@%s", k->user, k->host);
148 mowgli_node_delete(n, &ircd_wildcard_klines);
149 free(k->user);
150 free(k->host);
151 free(k->reason);
152 mowgli_heap_free(ircd_kline_heap, k);
153 }
154 }
155 }
156
157 static void expire_klines(void *unused)
158 {
159 mowgli_node_t *n, *tn;
160 kline_t *k;
161
162 MOWGLI_LIST_FOREACH_SAFE(n, tn, ircd_wildcard_klines.head)
163 {
164 k = (kline_t*) n->data;
165
166 if (k->duration == 0)
167 continue;
168
169 if (k->expires <= CURRTIME)
170 {
171 syn_debug(1, "Expiring K:line on %s@%s", k->user, k->host);
172 mowgli_node_delete(n, &ircd_wildcard_klines);
173 free(k->user);
174 free(k->host);
175 free(k->reason);
176 mowgli_heap_free(ircd_kline_heap, k);
177 }
178 }
179
180 mowgli_patricia_iteration_state_t state;
181 MOWGLI_PATRICIA_FOREACH(k, &state, ircd_klines)
182 {
183 if (k->duration == 0)
184 continue;
185 if (k->expires <= CURRTIME)
186 {
187 syn_debug(1, "Expiring K:line on %s@%s", k->user, k->host);
188 mowgli_patricia_delete(ircd_klines, k->host);
189 free(k->user);
190 free(k->host);
191 free(k->reason);
192 mowgli_heap_free(ircd_kline_heap, k);
193 }
194 }
195 }
196
197 static void _syn_vkline(const char *host, int duration, const char *reason, va_list ap)
198 {
199 /* if (_syn_find_kline("*", host))
200 return;
201 */
202 char buf[BUFSIZE];
203 vsnprintf(buf, BUFSIZE, reason, ap);
204
205 kline_t *k = mowgli_heap_alloc(ircd_kline_heap);
206 k->duration = duration;
207 k->settime = CURRTIME;
208 k->expires = CURRTIME + duration;
209 k->user = sstrdup("*");
210 k->host = sstrdup(host);
211 k->reason = sstrdup(buf);
212
213 char *p;
214 if (NULL != (p = strchr(k->reason, '|')))
215 {
216 *p = '\0';
217 }
218
219 if (strchr(k->host, '*') || strchr(k->host, '?') || (strchr(k->host, '/') && valid_ip_or_mask(k->host)))
220 {
221 mowgli_node_t *n = mowgli_node_create();
222 mowgli_node_add(k, n, &ircd_wildcard_klines);
223 }
224 else
225 {
226 mowgli_patricia_add(ircd_klines, k->host, k);
227 }
228
229 kline_sts("*", "*", k->host, k->duration, k->reason);
230
231 hook_call_event("syn_kline_added", k);
232
233 syn_debug(1, "Added K:line %s@%s (%s)", k->user, k->host, k->reason);
234 }
235
236 void _syn_kline(const char *host, int duration, const char *reason, ...)
237 {
238 va_list ap;
239 va_start(ap, reason);
240 _syn_vkline(host, duration, reason, ap);
241 va_end(ap);
242 }
243
244 static void _syn_vkill(user_t *victim, const char *reason, va_list ap)
245 {
246 char buf[BUFSIZE];
247 vsnprintf(buf, BUFSIZE, reason, ap);
248 notice(syn->nick, victim->nick, "%s", buf);
249 kill_user(syn->me, victim, "%s", kline_kill_reason);
250 }
251
252
253 void _syn_kill(user_t *victim, const char *reason, ...)
254 {
255 va_list ap;
256
257 va_start(ap, reason);
258 _syn_vkill(victim, reason, ap);
259 va_end(ap);
260 }
261
262 static void _syn_vkill2(user_t *victim, const char *killreason, const char *reason, va_list ap)
263 {
264 char buf[BUFSIZE];
265 vsnprintf(buf, BUFSIZE, reason, ap);
266 notice(syn->nick, victim->nick, "%s", buf);
267 kill_user(syn->me, victim, "%s", killreason);
268 }
269
270
271 void _syn_kill2(user_t *victim, const char *killreason, const char *reason, ...)
272 {
273 va_list ap;
274
275 va_start(ap, reason);
276 _syn_vkill2(victim, killreason, reason, ap);
277 va_end(ap);
278 }
279
280 void _syn_kill_or_kline(user_t *victim, int duration, const char *reason, ...)
281 {
282 va_list ap;
283 va_start(ap, reason);
284 if (!victim->ip || victim->ip[0] == '\0')
285 {
286 // No IP means an auth spoofed user, probably a gateway. Kill it instead.
287 // Don't give away the oper reason, though.
288 char user_reason[BUFSIZE];
289 strncpy(user_reason, reason, sizeof(user_reason));
290 char *pipe;
291 if (0 != (pipe = strchr(user_reason, '|')))
292 *pipe = '\0';
293
294 _syn_vkill(victim, user_reason, ap);
295 }
296 else
297 {
298 _syn_vkline(victim->ip, duration, reason, ap);
299 }
300 va_end(ap);
301 }
302
303 static void syn_m_kline(sourceinfo_t *si, int parc, char **parv)
304 {
305 syn_add_kline(si->su->nick, parv[2], parv[3], atoi(parv[1]), parv[4]);
306 }
307
308 static void syn_m_unkline(sourceinfo_t *si, int parc, char **parv)
309 {
310 syn_remove_kline(parv[1], parv[2]);
311 }
312
313 static void syn_m_ban(sourceinfo_t *si, int parc, char **parv)
314 {
315 if (parv[0][0] != 'K')
316 {
317 // Not a K:line; ignore
318 return;
319 }
320
321 const char *user = parv[1], *host = parv[2], *setter = parv[6], *reason = parv[7];
322 int duration = atoi(parv[4]); // creation = atoi(parv[3]), lifetime = atoi(parv[5]);
323
324 if (setter[0] == '*' && si->su)
325 setter = si->su->nick;
326
327 if (duration != 0)
328 {
329 syn_add_kline(setter, user, host, duration, reason);
330 }
331 else
332 {
333 syn_remove_kline(user, host);
334 }
335 }
336
337 DECLARE_MODULE_V1
338 (
339 "syn/kline", false, mod_init, mod_deinit,
340 "$Revision$",
341 "Stephen Bennett <stephen -at- freenode.net>"
342 );