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 * $Id: reject.c 26592 2009-06-05 15:02:08Z androsyn $
24 */
25
26 #include "stdinc.h"
27 #include "struct.h"
28 #include "client.h"
29 #include "s_conf.h"
30 #include "reject.h"
31 #include "s_stats.h"
32 #include "ircd.h"
33 #include "send.h"
34 #include "numeric.h"
35 #include "parse.h"
36 #include "hostmask.h"
37 #include "match.h"
38
39 static rb_patricia_tree_t *global_tree;
40 static rb_patricia_tree_t *reject_tree;
41 static rb_patricia_tree_t *dline_tree;
42 static rb_patricia_tree_t *eline_tree;
43 static rb_dlink_list delay_exit;
44 static rb_dlink_list reject_list;
45 static rb_dlink_list throttle_list;
46 static rb_patricia_tree_t *throttle_tree;
47 static void throttle_expires(void *unused);
48
49
50 typedef struct _reject_data
51 {
52 rb_dlink_node rnode;
53 time_t time;
54 unsigned int count;
55 } reject_t;
56
57 typedef struct _delay_data
58 {
59 rb_dlink_node node;
60 rb_fde_t *F;
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 typedef struct _global_data
71 {
72 int count;
73 } global_t;
74
75
76 static rb_patricia_node_t *
add_ipline(struct ConfItem * aconf,rb_patricia_tree_t * tree,struct sockaddr * addr,int cidr)77 add_ipline(struct ConfItem *aconf, rb_patricia_tree_t *tree, struct sockaddr *addr, int cidr)
78 {
79 rb_patricia_node_t *pnode;
80 pnode = make_and_lookup_ip(tree, addr, cidr);
81 if(pnode == NULL)
82 return NULL;
83 aconf->pnode = pnode;
84 pnode->data = aconf;
85 return (pnode);
86 }
87
88 int
add_dline(struct ConfItem * aconf)89 add_dline(struct ConfItem *aconf)
90 {
91 struct rb_sockaddr_storage st;
92 int bitlen;
93 if(parse_netmask(aconf->host, (struct sockaddr *)&st, &bitlen) == HM_HOST)
94 return 0;
95
96 if(add_ipline(aconf, dline_tree, (struct sockaddr *)&st, bitlen) != NULL)
97 return 1;
98 return 0;
99 }
100
101 int
add_eline(struct ConfItem * aconf)102 add_eline(struct ConfItem *aconf)
103 {
104 struct rb_sockaddr_storage st;
105 int bitlen;
106 if(parse_netmask(aconf->host, (struct sockaddr *)&st, &bitlen) == HM_HOST)
107 return 0;
108
109 if(add_ipline(aconf, eline_tree, (struct sockaddr *)&st, bitlen) != NULL)
110 return 1;
111 return 0;
112 }
113
114 unsigned long
delay_exit_length(void)115 delay_exit_length(void)
116 {
117 return rb_dlink_list_length(&delay_exit);
118 }
119
120 static void
reject_exit(void * unused)121 reject_exit(void *unused)
122 {
123 rb_dlink_node *ptr, *ptr_next;
124 delay_t *ddata;
125 static const char *errbuf = "ERROR :Closing Link: (*** Banned (cache))\r\n";
126
127 RB_DLINK_FOREACH_SAFE(ptr, ptr_next, delay_exit.head)
128 {
129 ddata = ptr->data;
130
131 rb_write(ddata->F, errbuf, strlen(errbuf));
132 rb_close(ddata->F);
133 rb_free(ddata);
134 }
135
136 delay_exit.head = delay_exit.tail = NULL;
137 delay_exit.length = 0;
138 }
139
140 static void
reject_expires(void * unused)141 reject_expires(void *unused)
142 {
143 rb_dlink_node *ptr, *next;
144 rb_patricia_node_t *pnode;
145 reject_t *rdata;
146
147 RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
148 {
149 pnode = ptr->data;
150 rdata = pnode->data;
151
152 if(rdata->time + ConfigFileEntry.reject_duration > rb_current_time())
153 continue;
154
155 rb_dlinkDelete(ptr, &reject_list);
156 rb_free(rdata);
157 rb_patricia_remove(reject_tree, pnode);
158 }
159 }
160
161 void
init_reject(void)162 init_reject(void)
163 {
164 reject_tree = rb_new_patricia(PATRICIA_BITS);
165 dline_tree = rb_new_patricia(PATRICIA_BITS);
166 eline_tree = rb_new_patricia(PATRICIA_BITS);
167 throttle_tree = rb_new_patricia(PATRICIA_BITS);
168 global_tree = rb_new_patricia(PATRICIA_BITS);
169 rb_event_add("reject_exit", reject_exit, NULL, DELAYED_EXIT_TIME);
170 rb_event_add("reject_expires", reject_expires, NULL, 60);
171 rb_event_add("throttle_expires", throttle_expires, NULL, 10);
172 }
173
174
175 void
add_reject(struct Client * client_p)176 add_reject(struct Client *client_p)
177 {
178 rb_patricia_node_t *pnode;
179 reject_t *rdata;
180
181 /* Reject is disabled */
182 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
183 return;
184
185 if((pnode =
186 rb_match_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip)) != NULL)
187 {
188 rdata = pnode->data;
189 rdata->time = rb_current_time();
190 rdata->count++;
191 }
192 else
193 {
194 int bitlen = 32;
195 #ifdef RB_IPV6
196 if(GET_SS_FAMILY(&client_p->localClient->ip) == AF_INET6)
197 bitlen = 128;
198 #endif
199 pnode = make_and_lookup_ip(reject_tree,
200 (struct sockaddr *)&client_p->localClient->ip, bitlen);
201 pnode->data = rdata = rb_malloc(sizeof(reject_t));
202 rb_dlinkAddTail(pnode, &rdata->rnode, &reject_list);
203 rdata->time = rb_current_time();
204 rdata->count = 1;
205 }
206 }
207
208
209 int
check_reject(rb_fde_t * F,struct sockaddr * addr)210 check_reject(rb_fde_t *F, struct sockaddr *addr)
211 {
212 rb_patricia_node_t *pnode;
213 reject_t *rdata;
214 delay_t *ddata;
215 /* Reject is disabled */
216 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
217 return 0;
218
219 pnode = rb_match_ip(reject_tree, addr);
220 if(pnode != NULL)
221 {
222 rdata = pnode->data;
223
224 rdata->time = rb_current_time();
225 if(rdata->count > (unsigned long)ConfigFileEntry.reject_after_count)
226 {
227 ddata = rb_malloc(sizeof(delay_t));
228 ServerStats.is_rej++;
229 rb_setselect(F, RB_SELECT_WRITE | RB_SELECT_READ, NULL, NULL);
230 ddata->F = F;
231 rb_dlinkAdd(ddata, &ddata->node, &delay_exit);
232 return 1;
233 }
234 }
235 /* Caller does what it wants */
236 return 0;
237 }
238
239 void
flush_reject(void)240 flush_reject(void)
241 {
242 rb_dlink_node *ptr, *next;
243 rb_patricia_node_t *pnode;
244 reject_t *rdata;
245 RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
246 {
247 pnode = ptr->data;
248 rdata = pnode->data;
249 rb_dlinkDelete(ptr, &reject_list);
250 rb_free(rdata);
251 rb_patricia_remove(reject_tree, pnode);
252 }
253 }
254
255 int
remove_reject(const char * ip)256 remove_reject(const char *ip)
257 {
258 rb_patricia_node_t *pnode;
259
260 /* Reject is disabled */
261 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
262 return -1;
263
264 if((pnode = rb_match_string(reject_tree, ip)) != NULL)
265 {
266 reject_t *rdata = pnode->data;
267 rb_dlinkDelete(&rdata->rnode, &reject_list);
268 rb_free(rdata);
269 rb_patricia_remove(reject_tree, pnode);
270 return 1;
271 }
272 return 0;
273 }
274
275 static void
delete_ipline(struct ConfItem * aconf,rb_patricia_tree_t * t)276 delete_ipline(struct ConfItem *aconf, rb_patricia_tree_t *t)
277 {
278 rb_patricia_remove(t, aconf->pnode);
279 if(!aconf->clients)
280 {
281 free_conf(aconf);
282 }
283 }
284
285 static struct ConfItem *
find_ipline(rb_patricia_tree_t * t,struct sockaddr * addr)286 find_ipline(rb_patricia_tree_t *t, struct sockaddr *addr)
287 {
288 rb_patricia_node_t *pnode;
289 pnode = rb_match_ip(t, addr);
290 if(pnode != NULL)
291 return (struct ConfItem *)pnode->data;
292 return NULL;
293 }
294
295 static struct ConfItem *
find_ipline_exact(rb_patricia_tree_t * t,struct sockaddr * addr,unsigned int bitlen)296 find_ipline_exact(rb_patricia_tree_t *t, struct sockaddr *addr, unsigned int bitlen)
297 {
298 rb_patricia_node_t *pnode;
299 pnode = rb_match_ip_exact(t, addr, bitlen);
300 if(pnode != NULL)
301 return (struct ConfItem *)pnode->data;
302 return NULL;
303 }
304
305
306 struct ConfItem *
find_dline(struct sockaddr * addr)307 find_dline(struct sockaddr *addr)
308 {
309 struct ConfItem *aconf;
310 aconf = find_ipline(eline_tree, addr);
311 if(aconf != NULL)
312 {
313 return aconf;
314 }
315 return (find_ipline(dline_tree, addr));
316 }
317
318 struct ConfItem *
find_dline_exact(struct sockaddr * addr,unsigned int bitlen)319 find_dline_exact(struct sockaddr *addr, unsigned int bitlen)
320 {
321 return find_ipline_exact(dline_tree, addr, bitlen);
322 }
323
324 void
remove_dline(struct ConfItem * aconf)325 remove_dline(struct ConfItem *aconf)
326 {
327 delete_ipline(aconf, dline_tree);
328 }
329
330 void
remove_perm_dlines(void)331 remove_perm_dlines(void)
332 {
333 rb_patricia_node_t *pnode;
334 struct ConfItem *aconf;
335 RB_PATRICIA_WALK(dline_tree->head, pnode)
336 {
337 aconf = pnode->data;
338 if(!(aconf->flags & CONF_FLAGS_TEMPORARY))
339 {
340 remove_dline(aconf);
341 }
342 }
343 RB_PATRICIA_WALK_END;
344 }
345
346 void
report_dlines(struct Client * source_p)347 report_dlines(struct Client *source_p)
348 {
349 rb_patricia_node_t *pnode;
350 struct ConfItem *aconf;
351 const char *host, *pass, *user, *oper_reason;
352 RB_PATRICIA_WALK(dline_tree->head, pnode)
353 {
354 aconf = pnode->data;
355 if(aconf->flags & CONF_FLAGS_TEMPORARY)
356 RB_PATRICIA_WALK_BREAK;
357 get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason);
358 sendto_one_numeric(source_p, RPL_STATSDLINE,
359 form_str(RPL_STATSDLINE),
360 'D', host, pass,
361 oper_reason ? "|" : "", oper_reason ? oper_reason : "");
362 }
363 RB_PATRICIA_WALK_END;
364 }
365
366 void
report_tdlines(struct Client * source_p)367 report_tdlines(struct Client *source_p)
368 {
369 rb_patricia_node_t *pnode;
370 struct ConfItem *aconf;
371 const char *host, *pass, *user, *oper_reason;
372 RB_PATRICIA_WALK(dline_tree->head, pnode)
373 {
374 aconf = pnode->data;
375 if(!(aconf->flags & CONF_FLAGS_TEMPORARY))
376 RB_PATRICIA_WALK_BREAK;
377 get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason);
378 sendto_one_numeric(source_p, RPL_STATSDLINE,
379 form_str(RPL_STATSDLINE),
380 'd', host, pass,
381 oper_reason ? "|" : "", oper_reason ? oper_reason : "");
382 }
383 RB_PATRICIA_WALK_END;
384 }
385
386 void
report_elines(struct Client * source_p)387 report_elines(struct Client *source_p)
388 {
389 rb_patricia_node_t *pnode;
390 struct ConfItem *aconf;
391 int port;
392 const char *name, *host, *pass, *user, *classname;
393 RB_PATRICIA_WALK(eline_tree->head, pnode)
394 {
395 aconf = pnode->data;
396 get_printable_conf(aconf, &name, &host, &pass, &user, &port, &classname);
397 sendto_one_numeric(source_p, RPL_STATSDLINE,
398 form_str(RPL_STATSDLINE), 'e', host, pass, "", "");
399 }
400 RB_PATRICIA_WALK_END;
401 }
402
403
404 unsigned long
throttle_size(void)405 throttle_size(void)
406 {
407 unsigned long count;
408 rb_dlink_node *ptr;
409 rb_patricia_node_t *pnode;
410 throttle_t *t;
411
412 count = 0;
413 RB_DLINK_FOREACH(ptr, throttle_list.head)
414 {
415 pnode = ptr->data;
416 t = pnode->data;
417 if (t->count > ConfigFileEntry.throttle_count)
418 count++;
419 }
420
421 return count;
422 }
423
424 int
throttle_add(struct sockaddr * addr)425 throttle_add(struct sockaddr *addr)
426 {
427 throttle_t *t;
428 rb_patricia_node_t *pnode;
429 char sockhost[HOSTIPLEN+1];
430 if((pnode = rb_match_ip(throttle_tree, addr)) != NULL)
431 {
432 t = pnode->data;
433
434 if(t->count > ConfigFileEntry.throttle_count)
435 {
436 if(t->count == ConfigFileEntry.throttle_count + 1)
437 {
438 rb_inet_ntop_sock(addr, sockhost, sizeof(sockhost));
439 sendto_realops_flags(UMODE_REJ, L_ALL, "Adding throttle for %s", sockhost);
440 }
441 t->count++;
442 ServerStats.is_thr++;
443 return 1;
444 }
445 /* Stop penalizing them after they've been throttled */
446 t->last = rb_current_time();
447 t->count++;
448 }
449 else
450 {
451 int bitlen = 32;
452 #ifdef RB_IPV6
453 if(GET_SS_FAMILY(addr) == AF_INET6)
454 bitlen = 128;
455 #endif
456 t = rb_malloc(sizeof(throttle_t));
457 t->last = rb_current_time();
458 t->count = 1;
459 pnode = make_and_lookup_ip(throttle_tree, addr, bitlen);
460 pnode->data = t;
461 rb_dlinkAdd(pnode, &t->node, &throttle_list);
462 }
463 return 0;
464 }
465
466 static void
throttle_expires(void * unused)467 throttle_expires(void *unused)
468 {
469 rb_dlink_node *ptr, *next;
470 rb_patricia_node_t *pnode;
471 throttle_t *t;
472
473 RB_DLINK_FOREACH_SAFE(ptr, next, throttle_list.head)
474 {
475 pnode = ptr->data;
476 t = pnode->data;
477
478 if(t->last + ConfigFileEntry.throttle_duration > rb_current_time())
479 continue;
480
481 rb_dlinkDelete(ptr, &throttle_list);
482 rb_free(t);
483 rb_patricia_remove(throttle_tree, pnode);
484 }
485 }
486
487 static int
get_global_count(struct sockaddr * addr)488 get_global_count(struct sockaddr *addr)
489 {
490 rb_patricia_node_t *pnode;
491 global_t *glb;
492
493 if((pnode = rb_match_ip(global_tree, addr)))
494 {
495 glb = pnode->data;
496 return glb->count;
497 }
498 return 0;
499 }
500
501 static int
inc_global_ip(struct sockaddr * addr,int bitlen)502 inc_global_ip(struct sockaddr *addr, int bitlen)
503 {
504 rb_patricia_node_t *pnode;
505 global_t *glb;
506
507
508 if((pnode = rb_match_ip(global_tree, addr)))
509 {
510 glb = pnode->data;
511 }
512 else
513 {
514 pnode = make_and_lookup_ip(global_tree, addr, bitlen);
515 glb = rb_malloc(sizeof(global_t));
516 pnode->data = glb;
517 }
518 glb->count++;
519 return glb->count;
520 }
521
522 static void
dec_global_ip(struct sockaddr * addr)523 dec_global_ip(struct sockaddr *addr)
524 {
525 rb_patricia_node_t *pnode;
526 global_t *glb;
527
528 if((pnode = rb_match_ip(global_tree, addr)))
529 {
530 glb = pnode->data;
531 glb->count--;
532 if(glb->count == 0)
533 {
534 rb_free(glb);
535 rb_patricia_remove(global_tree, pnode);
536 return;
537 }
538 }
539 }
540
541 int
inc_global_cidr_count(struct Client * client_p)542 inc_global_cidr_count(struct Client *client_p)
543 {
544 struct rb_sockaddr_storage ip;
545 struct sockaddr *addr;
546 int bitlen;
547
548 if(!MyClient(client_p))
549 {
550 if(EmptyString(client_p->sockhost) || !strcmp(client_p->sockhost, "0"))
551 return -1;
552 if(!rb_inet_pton_sock(client_p->sockhost, (struct sockaddr *)&ip))
553 return -1;
554 addr = (struct sockaddr *)&ip;
555 }
556 else
557 addr = (struct sockaddr *)&client_p->localClient->ip;
558 #ifdef RB_IPV6
559 if(GET_SS_FAMILY(addr) == AF_INET6)
560 {
561 bitlen = ConfigFileEntry.global_cidr_ipv6_bitlen;
562 }
563 else
564 #endif
565 bitlen = ConfigFileEntry.global_cidr_ipv4_bitlen;
566
567 return inc_global_ip(addr, bitlen);
568 }
569
570 void
dec_global_cidr_count(struct Client * client_p)571 dec_global_cidr_count(struct Client *client_p)
572 {
573 struct rb_sockaddr_storage ip;
574 struct sockaddr *addr;
575 if(!MyClient(client_p))
576 {
577 if(EmptyString(client_p->sockhost) || !strcmp(client_p->sockhost, "0"))
578 return;
579 if(!rb_inet_pton_sock(client_p->sockhost, (struct sockaddr *)&ip))
580 return;
581 addr = (struct sockaddr *)&ip;
582 }
583 else
584 addr = (struct sockaddr *)&client_p->localClient->ip;
585
586 dec_global_ip(addr);
587 }
588
589 int
check_global_cidr_count(struct Client * client_p)590 check_global_cidr_count(struct Client *client_p)
591 {
592 struct rb_sockaddr_storage ip;
593 struct sockaddr *addr;
594 int count, max;
595 if(!MyClient(client_p))
596 {
597 if(EmptyString(client_p->sockhost) || !strcmp(client_p->sockhost, "0"))
598 return -1;
599 if(!rb_inet_pton_sock(client_p->sockhost, (struct sockaddr *)&ip))
600 return -1;
601 addr = (struct sockaddr *)&ip;
602 }
603 else
604 addr = (struct sockaddr *)&client_p->localClient->ip;
605 count = get_global_count(addr);
606 #ifdef RB_IPV6
607 if(GET_SS_FAMILY(addr) == AF_INET6)
608 max = ConfigFileEntry.global_cidr_ipv6_count;
609 else
610 #endif
611 max = ConfigFileEntry.global_cidr_ipv4_count;
612 if(count >= max)
613 return 1;
614 return 0;
615 }
616
617 static void
clear_cidr_tree(void * data)618 clear_cidr_tree(void *data)
619 {
620 rb_free(data);
621 }
622
623 void
rehash_global_cidr_tree(void)624 rehash_global_cidr_tree(void)
625 {
626 struct Client *client_p;
627 rb_dlink_node *ptr;
628 rb_destroy_patricia(global_tree, clear_cidr_tree);
629 global_tree = rb_new_patricia(PATRICIA_BITS);
630 RB_DLINK_FOREACH(ptr, global_client_list.head)
631 {
632 client_p = ptr->data;
633 if(IsMe(client_p) && IsServer(client_p))
634 continue;
635 inc_global_cidr_count(client_p);
636 }
637 return;
638 }
639