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