]> jfr.im git - solanum.git/blob - ircd/reject.c
sasl_usercloak: make the magic string more specific
[solanum.git] / ircd / reject.c
1 /*
2 * ircd-ratbox: A slightly useful ircd
3 * reject.c: reject users with prejudice
4 *
5 * Copyright (C) 2003 Aaron Sethman <androsyn@ratbox.org>
6 * Copyright (C) 2003-2005 ircd-ratbox development team
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 * USA
22 */
23
24 #include "stdinc.h"
25 #include "client.h"
26 #include "s_conf.h"
27 #include "reject.h"
28 #include "s_stats.h"
29 #include "ircd.h"
30 #include "send.h"
31 #include "numeric.h"
32 #include "parse.h"
33 #include "hostmask.h"
34 #include "match.h"
35 #include "hash.h"
36
37 static rb_patricia_tree_t *reject_tree;
38 static rb_dlink_list delay_exit;
39 static rb_dlink_list reject_list;
40 static rb_dlink_list throttle_list;
41 static rb_patricia_tree_t *throttle_tree;
42 static void throttle_expires(void *unused);
43
44
45 typedef struct _reject_data
46 {
47 rb_dlink_node rnode;
48 struct ConfItem *aconf;
49 const char *reason;
50 time_t time;
51 unsigned int count;
52 uint32_t mask_hashv;
53 } reject_t;
54
55 typedef struct _delay_data
56 {
57 rb_dlink_node node;
58 rb_fde_t *F;
59 struct ConfItem *aconf;
60 const char *reason;
61 } delay_t;
62
63 typedef struct _throttle
64 {
65 rb_dlink_node node;
66 time_t last;
67 int count;
68 } throttle_t;
69
70 unsigned long
71 delay_exit_length(void)
72 {
73 return rb_dlink_list_length(&delay_exit);
74 }
75
76 static void
77 reject_free(reject_t *rdata)
78 {
79 struct ConfItem *aconf = rdata->aconf;
80
81 if (aconf)
82 deref_conf(aconf);
83
84 rb_free(rdata);
85 }
86
87 static void
88 reject_exit(void *unused)
89 {
90 static char dynamic_reason[BUFSIZE];
91 rb_dlink_node *ptr, *ptr_next;
92 delay_t *ddata;
93 static const char *errbuf = "ERROR :Closing Link: (*** Banned (cache))\r\n";
94
95 RB_DLINK_FOREACH_SAFE(ptr, ptr_next, delay_exit.head)
96 {
97 ddata = ptr->data;
98
99 *dynamic_reason = '\0';
100
101 if (ddata->aconf)
102 {
103 snprintf(dynamic_reason, BUFSIZE, form_str(ERR_YOUREBANNEDCREEP) "\r\n",
104 me.name, "*", get_user_ban_reason(ddata->aconf));
105 rb_write(ddata->F, dynamic_reason, strlen(dynamic_reason));
106
107 deref_conf(ddata->aconf);
108 }
109 else if (ddata->reason)
110 {
111 snprintf(dynamic_reason, BUFSIZE, ":%s 465 %s :%s\r\n",
112 me.name, "*", ddata->reason);
113 rb_write(ddata->F, dynamic_reason, strlen(dynamic_reason));
114 }
115
116 rb_write(ddata->F, errbuf, strlen(errbuf));
117 rb_close(ddata->F);
118 rb_free(ddata);
119 }
120
121 delay_exit.head = delay_exit.tail = NULL;
122 delay_exit.length = 0;
123 }
124
125 static void
126 reject_expires(void *unused)
127 {
128 rb_dlink_node *ptr, *next;
129 rb_patricia_node_t *pnode;
130 reject_t *rdata;
131
132 RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
133 {
134 pnode = ptr->data;
135 rdata = pnode->data;
136
137 if(rdata->time + ConfigFileEntry.reject_duration > rb_current_time())
138 continue;
139
140 rb_dlinkDelete(ptr, &reject_list);
141 reject_free(rdata);
142 rb_patricia_remove(reject_tree, pnode);
143 }
144 }
145
146 void
147 init_reject(void)
148 {
149 reject_tree = rb_new_patricia(PATRICIA_BITS);
150 throttle_tree = rb_new_patricia(PATRICIA_BITS);
151 rb_event_add("reject_exit", reject_exit, NULL, DELAYED_EXIT_TIME);
152 rb_event_add("reject_expires", reject_expires, NULL, 60);
153 rb_event_add("throttle_expires", throttle_expires, NULL, 10);
154 }
155
156 unsigned long
157 throttle_size(void)
158 {
159 unsigned long count;
160 rb_dlink_node *ptr;
161 rb_patricia_node_t *pnode;
162 throttle_t *t;
163
164 count = 0;
165 RB_DLINK_FOREACH(ptr, throttle_list.head)
166 {
167 pnode = ptr->data;
168 t = pnode->data;
169 if (t->count > ConfigFileEntry.throttle_count)
170 count++;
171 }
172
173 return count;
174 }
175
176 void
177 add_reject(struct Client *client_p, const char *mask1, const char *mask2, struct ConfItem *aconf, const char *reason)
178 {
179 rb_patricia_node_t *pnode;
180 reject_t *rdata;
181 uint32_t hashv;
182
183 /* Reject is disabled */
184 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
185 return;
186
187 hashv = 0;
188 if (mask1 != NULL)
189 hashv ^= fnv_hash_upper((const unsigned char *)mask1, 32);
190 if (mask2 != NULL)
191 hashv ^= fnv_hash_upper((const unsigned char *)mask2, 32);
192
193 if((pnode = rb_match_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip)) != NULL)
194 {
195 rdata = pnode->data;
196 rdata->time = rb_current_time();
197 rdata->count++;
198 }
199 else
200 {
201 int bitlen = 32;
202 if(GET_SS_FAMILY(&client_p->localClient->ip) == AF_INET6)
203 bitlen = 128;
204 pnode = make_and_lookup_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip, bitlen);
205 pnode->data = rdata = rb_malloc(sizeof(reject_t));
206 rb_dlinkAddTail(pnode, &rdata->rnode, &reject_list);
207 rdata->time = rb_current_time();
208 rdata->count = 1;
209 rdata->aconf = NULL;
210 rdata->reason = NULL;
211 }
212 rdata->mask_hashv = hashv;
213
214 if (aconf != NULL && aconf != rdata->aconf && (aconf->status & CONF_KILL) && aconf->passwd)
215 {
216 if (rdata->aconf != NULL)
217 deref_conf(rdata->aconf);
218 aconf->clients++;
219 rdata->aconf = aconf;
220 }
221 else if (reason != NULL)
222 {
223 if (rdata->aconf != NULL)
224 deref_conf(rdata->aconf);
225 rdata->aconf = NULL;
226 rdata->reason = reason;
227 }
228 }
229
230 int
231 check_reject(rb_fde_t *F, struct sockaddr *addr)
232 {
233 rb_patricia_node_t *pnode;
234 reject_t *rdata;
235 delay_t *ddata;
236 /* Reject is disabled */
237 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
238 return 0;
239
240 pnode = rb_match_ip(reject_tree, addr);
241 if(pnode != NULL)
242 {
243 rdata = pnode->data;
244
245 rdata->time = rb_current_time();
246 if(rdata->count > (unsigned long)ConfigFileEntry.reject_after_count)
247 {
248 ddata = rb_malloc(sizeof(delay_t));
249 ServerStats.is_rej++;
250 rb_setselect(F, RB_SELECT_WRITE | RB_SELECT_READ, NULL, NULL);
251 if(rdata->aconf)
252 {
253 ddata->aconf = rdata->aconf;
254 ddata->aconf->clients++;
255 ddata->reason = NULL;
256 }
257 else if(rdata->reason)
258 {
259 ddata->reason = rdata->reason;
260 ddata->aconf = NULL;
261 }
262 else
263 {
264 ddata->aconf = NULL;
265 ddata->reason = NULL;
266 }
267 ddata->F = F;
268 rb_dlinkAdd(ddata, &ddata->node, &delay_exit);
269 return 1;
270 }
271 }
272 /* Caller does what it wants */
273 return 0;
274 }
275
276 int
277 is_reject_ip(struct sockaddr *addr)
278 {
279 rb_patricia_node_t *pnode;
280 reject_t *rdata;
281 int duration;
282
283 /* Reject is disabled */
284 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
285 return 0;
286
287 pnode = rb_match_ip(reject_tree, addr);
288 if(pnode != NULL)
289 {
290 rdata = pnode->data;
291
292 if(rdata->count > (unsigned long)ConfigFileEntry.reject_after_count)
293 {
294 duration = rdata->time + ConfigFileEntry.reject_duration - rb_current_time();
295 return duration > 0 ? duration : 1;
296 }
297 }
298 return 0;
299 }
300
301 void
302 flush_reject(void)
303 {
304 rb_dlink_node *ptr, *next;
305 rb_patricia_node_t *pnode;
306 reject_t *rdata;
307
308 RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
309 {
310 pnode = ptr->data;
311 rdata = pnode->data;
312 rb_dlinkDelete(ptr, &reject_list);
313 reject_free(rdata);
314 rb_patricia_remove(reject_tree, pnode);
315 }
316 }
317
318 int
319 remove_reject_ip(const char *ip)
320 {
321 rb_patricia_node_t *pnode;
322
323 /* Reject is disabled */
324 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
325 return -1;
326
327 if((pnode = rb_match_string(reject_tree, ip)) != NULL)
328 {
329 reject_t *rdata = pnode->data;
330 rb_dlinkDelete(&rdata->rnode, &reject_list);
331 reject_free(rdata);
332 rb_patricia_remove(reject_tree, pnode);
333 return 1;
334 }
335 return 0;
336 }
337
338 int
339 remove_reject_mask(const char *mask1, const char *mask2)
340 {
341 rb_dlink_node *ptr, *next;
342 rb_patricia_node_t *pnode;
343 reject_t *rdata;
344 uint32_t hashv;
345 int n = 0;
346
347 hashv = 0;
348 if (mask1 != NULL)
349 hashv ^= fnv_hash_upper((const unsigned char *)mask1, 32);
350 if (mask2 != NULL)
351 hashv ^= fnv_hash_upper((const unsigned char *)mask2, 32);
352 RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
353 {
354 pnode = ptr->data;
355 rdata = pnode->data;
356 if (rdata->mask_hashv == hashv)
357 {
358 rb_dlinkDelete(ptr, &reject_list);
359 reject_free(rdata);
360 rb_patricia_remove(reject_tree, pnode);
361 n++;
362 }
363 }
364 return n;
365 }
366
367 int
368 throttle_add(struct sockaddr *addr)
369 {
370 throttle_t *t;
371 rb_patricia_node_t *pnode;
372
373 if((pnode = rb_match_ip(throttle_tree, addr)) != NULL)
374 {
375 t = pnode->data;
376
377 if(t->count > ConfigFileEntry.throttle_count)
378 {
379 ServerStats.is_thr++;
380 return 1;
381 }
382 /* Stop penalizing them after they've been throttled */
383 t->last = rb_current_time();
384 t->count++;
385
386 } else {
387 int bitlen = 32;
388 if(GET_SS_FAMILY(addr) == AF_INET6)
389 bitlen = 128;
390 t = rb_malloc(sizeof(throttle_t));
391 t->last = rb_current_time();
392 t->count = 1;
393 pnode = make_and_lookup_ip(throttle_tree, addr, bitlen);
394 pnode->data = t;
395 rb_dlinkAdd(pnode, &t->node, &throttle_list);
396 }
397 return 0;
398 }
399
400 int
401 is_throttle_ip(struct sockaddr *addr)
402 {
403 throttle_t *t;
404 rb_patricia_node_t *pnode;
405 int duration;
406
407 if((pnode = rb_match_ip(throttle_tree, addr)) != NULL)
408 {
409 t = pnode->data;
410 if(t->count > ConfigFileEntry.throttle_count)
411 {
412 duration = t->last + ConfigFileEntry.throttle_duration - rb_current_time();
413 return duration > 0 ? duration : 1;
414 }
415 }
416 return 0;
417 }
418
419 void
420 flush_throttle(void)
421 {
422 rb_dlink_node *ptr, *next;
423 rb_patricia_node_t *pnode;
424 throttle_t *t;
425
426 RB_DLINK_FOREACH_SAFE(ptr, next, throttle_list.head)
427 {
428 pnode = ptr->data;
429 t = pnode->data;
430
431 rb_dlinkDelete(ptr, &throttle_list);
432 rb_free(t);
433 rb_patricia_remove(throttle_tree, pnode);
434 }
435 }
436
437 static void
438 throttle_expires(void *unused)
439 {
440 rb_dlink_node *ptr, *next;
441 rb_patricia_node_t *pnode;
442 throttle_t *t;
443
444 RB_DLINK_FOREACH_SAFE(ptr, next, throttle_list.head)
445 {
446 pnode = ptr->data;
447 t = pnode->data;
448
449 if(t->last + ConfigFileEntry.throttle_duration > rb_current_time())
450 continue;
451
452 rb_dlinkDelete(ptr, &throttle_list);
453 rb_free(t);
454 rb_patricia_remove(throttle_tree, pnode);
455 }
456 }
457