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-2012 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 29215 2015-12-10 13:57:05Z 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 void
remove_exempts(void)307 remove_exempts(void)
308 {
309 	rb_patricia_node_t *pnode;
310 	rb_dlink_list list;
311 	rb_dlink_node *ptr, *next;
312 
313 	memset(&list, 0, sizeof(list));
314 
315 	RB_PATRICIA_WALK(eline_tree->head, pnode)
316 	{
317 		rb_dlinkAddAlloc(pnode->data, &list);
318 	}
319 	RB_PATRICIA_WALK_END;
320 
321 
322 	RB_DLINK_FOREACH_SAFE(ptr, next, list.head)
323 	{
324 		delete_ipline((struct ConfItem *)ptr->data, eline_tree);
325 		rb_free_rb_dlink_node(ptr); /* no need to use rb_dlinkDestroy */
326 	}
327 }
328 
329 
330 struct ConfItem *
find_dline(struct sockaddr * addr)331 find_dline(struct sockaddr *addr)
332 {
333 	struct ConfItem *aconf;
334 	aconf = find_ipline(eline_tree, addr);
335 	if(aconf != NULL)
336 	{
337 		return aconf;
338 	}
339 	return (find_ipline(dline_tree, addr));
340 }
341 
342 struct ConfItem *
find_dline_exact(struct sockaddr * addr,unsigned int bitlen)343 find_dline_exact(struct sockaddr *addr, unsigned int bitlen)
344 {
345 	return find_ipline_exact(dline_tree, addr, bitlen);
346 }
347 
348 void
remove_dline(struct ConfItem * aconf)349 remove_dline(struct ConfItem *aconf)
350 {
351 	delete_ipline(aconf, dline_tree);
352 }
353 
354 void
remove_perm_dlines(void)355 remove_perm_dlines(void)
356 {
357 	rb_patricia_node_t *pnode;
358 	rb_dlink_list list;
359 	rb_dlink_node *ptr, *next;
360 	struct ConfItem *aconf;
361 
362 	memset(&list, 0, sizeof(list));
363 
364 	RB_PATRICIA_WALK(dline_tree->head, pnode)
365 	{
366 		aconf = pnode->data;
367 		if(!(aconf->flags & CONF_FLAGS_TEMPORARY))
368 		{
369 			rb_dlinkAddAlloc(aconf, &list);
370 		}
371 	}
372         RB_PATRICIA_WALK_END;
373 
374 	RB_DLINK_FOREACH_SAFE(ptr, next, list.head)
375 	{
376 		aconf = ptr->data;
377 		remove_dline(aconf);
378 		rb_free_rb_dlink_node(ptr);
379 	}
380 }
381 
382 void
report_dlines(struct Client * source_p)383 report_dlines(struct Client *source_p)
384 {
385 	rb_patricia_node_t *pnode;
386 	struct ConfItem *aconf;
387 	const char *host, *pass, *user, *oper_reason;
388 	RB_PATRICIA_WALK(dline_tree->head, pnode)
389 	{
390 		aconf = pnode->data;
391 		if(aconf->flags & CONF_FLAGS_TEMPORARY)
392 			RB_PATRICIA_WALK_BREAK;
393 		get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason);
394 		sendto_one_numeric(source_p, RPL_STATSDLINE,
395 				   form_str(RPL_STATSDLINE),
396 				   'D', host, pass,
397 				   oper_reason ? "|" : "", oper_reason ? oper_reason : "");
398 	}
399 	RB_PATRICIA_WALK_END;
400 }
401 
402 void
report_tdlines(struct Client * source_p)403 report_tdlines(struct Client *source_p)
404 {
405 	rb_patricia_node_t *pnode;
406 	struct ConfItem *aconf;
407 	const char *host, *pass, *user, *oper_reason;
408 	RB_PATRICIA_WALK(dline_tree->head, pnode)
409 	{
410 		aconf = pnode->data;
411 		if(!(aconf->flags & CONF_FLAGS_TEMPORARY))
412 			RB_PATRICIA_WALK_BREAK;
413 		get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason);
414 		sendto_one_numeric(source_p, RPL_STATSDLINE,
415 				   form_str(RPL_STATSDLINE),
416 				   'd', host, pass,
417 				   oper_reason ? "|" : "", oper_reason ? oper_reason : "");
418 	}
419 	RB_PATRICIA_WALK_END;
420 }
421 
422 void
report_elines(struct Client * source_p)423 report_elines(struct Client *source_p)
424 {
425 	rb_patricia_node_t *pnode;
426 	struct ConfItem *aconf;
427 	int port;
428 	const char *name, *host, *pass, *user, *classname;
429 	RB_PATRICIA_WALK(eline_tree->head, pnode)
430 	{
431 		aconf = pnode->data;
432 		get_printable_conf(aconf, &name, &host, &pass, &user, &port, &classname);
433 		sendto_one_numeric(source_p, RPL_STATSDLINE,
434 				   form_str(RPL_STATSDLINE), 'e', host, pass, "", "");
435 	}
436 	RB_PATRICIA_WALK_END;
437 }
438 
439 
440 unsigned long
throttle_size(void)441 throttle_size(void)
442 {
443 	unsigned long count;
444 	rb_dlink_node *ptr;
445 	rb_patricia_node_t *pnode;
446 	throttle_t *t;
447 
448 	count = 0;
449 	RB_DLINK_FOREACH(ptr, throttle_list.head)
450 	{
451 		pnode = ptr->data;
452 		t = pnode->data;
453 		if (t->count > ConfigFileEntry.throttle_count)
454 			count++;
455 	}
456 
457 	return count;
458 }
459 
460 int
throttle_add(struct sockaddr * addr)461 throttle_add(struct sockaddr *addr)
462 {
463 	throttle_t *t;
464 	rb_patricia_node_t *pnode;
465 	char sockhost[HOSTIPLEN+1];
466 	if((pnode = rb_match_ip(throttle_tree, addr)) != NULL)
467 	{
468 		t = pnode->data;
469 
470 		if(t->count > ConfigFileEntry.throttle_count)
471 		{
472 			if(t->count == ConfigFileEntry.throttle_count + 1)
473 			{
474 				rb_inet_ntop_sock(addr, sockhost, sizeof(sockhost));
475 				sendto_realops_flags(UMODE_REJ, L_ALL, "Adding throttle for %s", sockhost);
476 			}
477 			t->count++;
478 			ServerStats.is_thr++;
479 			return 1;
480 		}
481 		/* Stop penalizing them after they've been throttled */
482 		t->last = rb_current_time();
483 		t->count++;
484 	}
485 	else
486 	{
487 		int bitlen = 32;
488 #ifdef RB_IPV6
489 		if(GET_SS_FAMILY(addr) == AF_INET6)
490 			bitlen = 128;
491 #endif
492 		t = rb_malloc(sizeof(throttle_t));
493 		t->last = rb_current_time();
494 		t->count = 1;
495 		pnode = make_and_lookup_ip(throttle_tree, addr, bitlen);
496 		pnode->data = t;
497 		rb_dlinkAdd(pnode, &t->node, &throttle_list);
498 	}
499 	return 0;
500 }
501 
502 static void
throttle_expires(void * unused)503 throttle_expires(void *unused)
504 {
505 	rb_dlink_node *ptr, *next;
506 	rb_patricia_node_t *pnode;
507 	throttle_t *t;
508 
509 	RB_DLINK_FOREACH_SAFE(ptr, next, throttle_list.head)
510 	{
511 		pnode = ptr->data;
512 		t = pnode->data;
513 
514 		if(t->last + ConfigFileEntry.throttle_duration > rb_current_time())
515 			continue;
516 
517 		rb_dlinkDelete(ptr, &throttle_list);
518 		rb_free(t);
519 		rb_patricia_remove(throttle_tree, pnode);
520 	}
521 }
522 
523 static int
get_global_count(struct sockaddr * addr)524 get_global_count(struct sockaddr *addr)
525 {
526 	rb_patricia_node_t *pnode;
527 	global_t *glb;
528 
529 	if((pnode = rb_match_ip(global_tree, addr)))
530 	{
531 		glb = pnode->data;
532 		return glb->count;
533 	}
534 	return 0;
535 }
536 
537 static int
inc_global_ip(struct sockaddr * addr,int bitlen)538 inc_global_ip(struct sockaddr *addr, int bitlen)
539 {
540 	rb_patricia_node_t *pnode;
541 	global_t *glb;
542 
543 
544 	if((pnode = rb_match_ip(global_tree, addr)))
545 	{
546 		glb = pnode->data;
547 	}
548 	else
549 	{
550 		pnode = make_and_lookup_ip(global_tree, addr, bitlen);
551 		glb = rb_malloc(sizeof(global_t));
552 		pnode->data = glb;
553 	}
554 	glb->count++;
555 	return glb->count;
556 }
557 
558 static void
dec_global_ip(struct sockaddr * addr)559 dec_global_ip(struct sockaddr *addr)
560 {
561 	rb_patricia_node_t *pnode;
562 	global_t *glb;
563 
564 	if((pnode = rb_match_ip(global_tree, addr)))
565 	{
566 		glb = pnode->data;
567 		glb->count--;
568 		if(glb->count == 0)
569 		{
570 			rb_free(glb);
571 			rb_patricia_remove(global_tree, pnode);
572 			return;
573 		}
574 	}
575 }
576 
577 int
inc_global_cidr_count(struct Client * client_p)578 inc_global_cidr_count(struct Client *client_p)
579 {
580 	struct rb_sockaddr_storage ip;
581 	struct sockaddr *addr;
582 	int bitlen;
583 
584 	if(!MyClient(client_p))
585 	{
586 		if(EmptyString(client_p->sockhost) || !strcmp(client_p->sockhost, "0"))
587 			return -1;
588 		if(!rb_inet_pton_sock(client_p->sockhost, (struct sockaddr *)&ip))
589 			return -1;
590 		addr = (struct sockaddr *)&ip;
591 	}
592 	else
593 		addr = (struct sockaddr *)&client_p->localClient->ip;
594 #ifdef RB_IPV6
595 	if(GET_SS_FAMILY(addr) == AF_INET6)
596 	{
597 		bitlen = ConfigFileEntry.global_cidr_ipv6_bitlen;
598 	}
599 	else
600 #endif
601 		bitlen = ConfigFileEntry.global_cidr_ipv4_bitlen;
602 
603 	return inc_global_ip(addr, bitlen);
604 }
605 
606 void
dec_global_cidr_count(struct Client * client_p)607 dec_global_cidr_count(struct Client *client_p)
608 {
609 	struct rb_sockaddr_storage ip;
610 	struct sockaddr *addr;
611 	if(!MyClient(client_p))
612 	{
613 		if(EmptyString(client_p->sockhost) || !strcmp(client_p->sockhost, "0"))
614 			return;
615 		if(!rb_inet_pton_sock(client_p->sockhost, (struct sockaddr *)&ip))
616 			return;
617 		addr = (struct sockaddr *)&ip;
618 	}
619 	else
620 		addr = (struct sockaddr *)&client_p->localClient->ip;
621 
622 	dec_global_ip(addr);
623 }
624 
625 int
check_global_cidr_count(struct Client * client_p)626 check_global_cidr_count(struct Client *client_p)
627 {
628 	struct rb_sockaddr_storage ip;
629 	struct sockaddr *addr;
630 	int count, max;
631 	if(!MyClient(client_p))
632 	{
633 		if(EmptyString(client_p->sockhost) || !strcmp(client_p->sockhost, "0"))
634 			return -1;
635 		if(!rb_inet_pton_sock(client_p->sockhost, (struct sockaddr *)&ip))
636 			return -1;
637 		addr = (struct sockaddr *)&ip;
638 	}
639 	else
640 		addr = (struct sockaddr *)&client_p->localClient->ip;
641 	count = get_global_count(addr);
642 #ifdef RB_IPV6
643 	if(GET_SS_FAMILY(addr) == AF_INET6)
644 		max = ConfigFileEntry.global_cidr_ipv6_count;
645 	else
646 #endif
647 		max = ConfigFileEntry.global_cidr_ipv4_count;
648 	if(count >= max)
649 		return 1;
650 	return 0;
651 }
652 
653 static void
clear_cidr_tree(void * data)654 clear_cidr_tree(void *data)
655 {
656 	rb_free(data);
657 }
658 
659 void
rehash_global_cidr_tree(void)660 rehash_global_cidr_tree(void)
661 {
662 	struct Client *client_p;
663 	rb_dlink_node *ptr;
664 	rb_destroy_patricia(global_tree, clear_cidr_tree);
665 	global_tree = rb_new_patricia(PATRICIA_BITS);
666 	RB_DLINK_FOREACH(ptr, global_client_list.head)
667 	{
668 		client_p = ptr->data;
669 		if(IsMe(client_p) && IsServer(client_p))
670 			continue;
671 		inc_global_cidr_count(client_p);
672 	}
673 	return;
674 }
675