]> jfr.im git - solanum.git/blame - src/reject.c
forward configure.ac changes
[solanum.git] / src / reject.c
CommitLineData
3c5a494d
VY
1/*\r
2 * ircd-ratbox: A slightly useful ircd\r
3 * reject.c: reject users with prejudice\r
4 *\r
5 * Copyright (C) 2003 Aaron Sethman <androsyn@ratbox.org>\r
6 * Copyright (C) 2003-2005 ircd-ratbox development team\r
7 *\r
8 * This program is free software; you can redistribute it and/or modify\r
9 * it under the terms of the GNU General Public License as published by\r
10 * the Free Software Foundation; either version 2 of the License, or\r
11 * (at your option) any later version.\r
12 *\r
13 * This program is distributed in the hope that it will be useful,\r
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
16 * GNU General Public License for more details.\r
17 *\r
18 * You should have received a copy of the GNU General Public License\r
19 * along with this program; if not, write to the Free Software\r
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301\r
21 * USA\r
22 *\r
23 * $Id: reject.c 25119 2008-03-13 16:57:05Z androsyn $\r
24 */\r
25\r
26#include "stdinc.h"\r
27#include "client.h"\r
28#include "s_conf.h"\r
29#include "reject.h"\r
30#include "s_stats.h"\r
31#include "ircd.h"\r
32#include "send.h"\r
33#include "numeric.h"\r
34#include "parse.h"\r
35#include "hostmask.h"\r
36\r
37static rb_patricia_tree_t *global_tree;\r
38static rb_patricia_tree_t *reject_tree;\r
39static rb_patricia_tree_t *dline_tree;\r
40static rb_patricia_tree_t *eline_tree;\r
41static rb_dlink_list delay_exit;\r
42static rb_dlink_list reject_list;\r
43static rb_dlink_list throttle_list;\r
44static rb_patricia_tree_t *throttle_tree;\r
45static void throttle_expires(void *unused);\r
46\r
47\r
48typedef struct _reject_data\r
49{\r
50 rb_dlink_node rnode;\r
51 time_t time;\r
52 unsigned int count;\r
53} reject_t;\r
54\r
55typedef struct _delay_data\r
56{\r
57 rb_dlink_node node;\r
58 rb_fde_t *F;\r
59} delay_t;\r
60\r
61typedef struct _throttle\r
62{\r
63 rb_dlink_node node;\r
64 time_t last;\r
65 int count;\r
66} throttle_t;\r
67\r
68typedef struct _global_data\r
69{\r
70 int count;\r
71} global_t;\r
72\r
73\r
74static rb_patricia_node_t *\r
75add_ipline(struct ConfItem *aconf, rb_patricia_tree_t *tree, struct sockaddr *addr, int cidr)\r
76{\r
77 rb_patricia_node_t *pnode;\r
78 pnode = make_and_lookup_ip(tree, addr, cidr);\r
79 if(pnode == NULL)\r
80 return NULL;\r
81 aconf->pnode = pnode;\r
82 pnode->data = aconf;\r
83 return (pnode);\r
84}\r
85\r
86int \r
87add_dline(struct ConfItem *aconf)\r
88{\r
89 struct rb_sockaddr_storage st;\r
90 int bitlen;\r
91 if(parse_netmask(aconf->host, (struct sockaddr *)&st, &bitlen) == HM_HOST)\r
92 return 0;\r
93\r
94 if(add_ipline(aconf, dline_tree, (struct sockaddr *)&st, bitlen) != NULL)\r
95 return 1;\r
96 return 0;\r
97}\r
98\r
99int\r
100add_eline(struct ConfItem *aconf)\r
101{\r
102 struct rb_sockaddr_storage st;\r
103 int bitlen;\r
104 if(parse_netmask(aconf->host, (struct sockaddr *)&st, &bitlen) == HM_HOST)\r
105 return 0;\r
106\r
107 if(add_ipline(aconf, eline_tree, (struct sockaddr *)&st, bitlen) != NULL)\r
108 return 1;\r
109 return 0;\r
110}\r
111\r
112unsigned long\r
113delay_exit_length(void)\r
114{\r
115 return rb_dlink_list_length(&delay_exit);\r
116}\r
117\r
118static void\r
119reject_exit(void *unused)\r
120{\r
121 rb_dlink_node *ptr, *ptr_next;\r
122 delay_t *ddata;\r
123 static const char *errbuf = "ERROR :Closing Link: (*** Banned (cache))\r\n";\r
124 \r
125 RB_DLINK_FOREACH_SAFE(ptr, ptr_next, delay_exit.head)\r
126 {\r
127 ddata = ptr->data;\r
128\r
129 rb_write(ddata->F, errbuf, strlen(errbuf)); \r
130 rb_close(ddata->F);\r
131 rb_free(ddata);\r
132 }\r
133\r
134 delay_exit.head = delay_exit.tail = NULL;\r
135 delay_exit.length = 0;\r
136}\r
137\r
138static void\r
139reject_expires(void *unused)\r
140{\r
141 rb_dlink_node *ptr, *next;\r
142 rb_patricia_node_t *pnode;\r
143 reject_t *rdata;\r
144 \r
145 RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)\r
146 {\r
147 pnode = ptr->data;\r
148 rdata = pnode->data; \r
149\r
150 if(rdata->time + ConfigFileEntry.reject_duration > rb_current_time())\r
151 continue;\r
152\r
153 rb_dlinkDelete(ptr, &reject_list);\r
154 rb_free(rdata);\r
155 rb_patricia_remove(reject_tree, pnode);\r
156 }\r
157}\r
158\r
159void\r
160init_reject(void)\r
161{\r
162 reject_tree = rb_new_patricia(PATRICIA_BITS);\r
163 dline_tree = rb_new_patricia(PATRICIA_BITS);\r
164 eline_tree = rb_new_patricia(PATRICIA_BITS);\r
165 throttle_tree = rb_new_patricia(PATRICIA_BITS);\r
166 global_tree = rb_new_patricia(PATRICIA_BITS);\r
167 rb_event_add("reject_exit", reject_exit, NULL, DELAYED_EXIT_TIME);\r
168 rb_event_add("reject_expires", reject_expires, NULL, 60);\r
169 rb_event_add("throttle_expires", throttle_expires, NULL, 10);\r
170}\r
171\r
172\r
173void\r
174add_reject(struct Client *client_p)\r
175{\r
176 rb_patricia_node_t *pnode;\r
177 reject_t *rdata;\r
178\r
179 /* Reject is disabled */\r
180 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)\r
181 return;\r
182\r
183 if((pnode = rb_match_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip)) != NULL)\r
184 {\r
185 rdata = pnode->data;\r
186 rdata->time = rb_current_time();\r
187 rdata->count++;\r
188 }\r
189 else\r
190 {\r
191 int bitlen = 32;\r
192#ifdef RB_IPV6\r
193 if(GET_SS_FAMILY(&client_p->localClient->ip) == AF_INET6)\r
194 bitlen = 128;\r
195#endif\r
196 pnode = make_and_lookup_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip, bitlen);\r
197 pnode->data = rdata = rb_malloc(sizeof(reject_t));\r
198 rb_dlinkAddTail(pnode, &rdata->rnode, &reject_list);\r
199 rdata->time = rb_current_time();\r
200 rdata->count = 1;\r
201 }\r
202}\r
203\r
204int\r
205check_reject(rb_fde_t *F, struct sockaddr *addr)\r
206{\r
207 rb_patricia_node_t *pnode;\r
208 reject_t *rdata;\r
209 delay_t *ddata;\r
210 /* Reject is disabled */\r
211 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)\r
212 return 0;\r
213 \r
214 pnode = rb_match_ip(reject_tree, addr);\r
215 if(pnode != NULL)\r
216 {\r
217 rdata = pnode->data;\r
218\r
219 rdata->time = rb_current_time();\r
220 if(rdata->count > (unsigned long)ConfigFileEntry.reject_after_count)\r
221 {\r
222 ddata = rb_malloc(sizeof(delay_t));\r
223 ServerStats.is_rej++;\r
224 rb_setselect(F, RB_SELECT_WRITE | RB_SELECT_READ, NULL, NULL);\r
225 ddata->F = F;\r
226 rb_dlinkAdd(ddata, &ddata->node, &delay_exit);\r
227 return 1;\r
228 }\r
229 } \r
230 /* Caller does what it wants */ \r
231 return 0;\r
232}\r
233\r
234void \r
235flush_reject(void)\r
236{\r
237 rb_dlink_node *ptr, *next;\r
238 rb_patricia_node_t *pnode;\r
239 reject_t *rdata;\r
240 \r
241 RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)\r
242 {\r
243 pnode = ptr->data;\r
244 rdata = pnode->data;\r
245 rb_dlinkDelete(ptr, &reject_list);\r
246 rb_free(rdata);\r
247 rb_patricia_remove(reject_tree, pnode);\r
248 }\r
249}\r
250\r
251int \r
252remove_reject(const char *ip)\r
253{\r
254 rb_patricia_node_t *pnode;\r
255 \r
256 /* Reject is disabled */\r
257 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)\r
258 return -1;\r
259\r
260 if((pnode = rb_match_string(reject_tree, ip)) != NULL)\r
261 {\r
262 reject_t *rdata = pnode->data;\r
263 rb_dlinkDelete(&rdata->rnode, &reject_list);\r
264 rb_free(rdata);\r
265 rb_patricia_remove(reject_tree, pnode);\r
266 return 1;\r
267 }\r
268 return 0;\r
269}\r
270\r
271static void\r
272delete_ipline(struct ConfItem *aconf, rb_patricia_tree_t *t)\r
273{\r
274 rb_patricia_remove(t, aconf->pnode);\r
275 if(!aconf->clients)\r
276 {\r
277 free_conf(aconf);\r
278 }\r
279}\r
280\r
281static struct ConfItem *\r
282find_ipline(rb_patricia_tree_t *t, struct sockaddr *addr)\r
283{\r
284 rb_patricia_node_t *pnode;\r
285 pnode = rb_match_ip(t, addr);\r
286 if(pnode != NULL)\r
287 return (struct ConfItem *) pnode->data;\r
288 return NULL;\r
289}\r
290\r
291static struct ConfItem *\r
292find_ipline_exact(rb_patricia_tree_t *t, struct sockaddr *addr, unsigned int bitlen)\r
293{\r
294 rb_patricia_node_t *pnode;\r
295 pnode = rb_match_ip_exact(t, addr, bitlen);\r
296 if(pnode != NULL)\r
297 return (struct ConfItem *) pnode->data;\r
298 return NULL;\r
299}\r
300\r
301\r
302struct ConfItem *\r
303find_dline(struct sockaddr *addr)\r
304{\r
305 struct ConfItem *aconf;\r
306 aconf = find_ipline(eline_tree, addr);\r
307 if(aconf != NULL)\r
308 {\r
309 return aconf;\r
310 }\r
311 return (find_ipline(dline_tree, addr));\r
312}\r
313\r
314struct ConfItem *\r
315find_dline_exact(struct sockaddr *addr, unsigned int bitlen)\r
316{\r
317 return find_ipline_exact(dline_tree, addr, bitlen);\r
318}\r
319\r
320void\r
321remove_dline(struct ConfItem *aconf)\r
322{\r
323 delete_ipline(aconf, dline_tree);\r
324}\r
325\r
326void\r
327report_dlines(struct Client *source_p)\r
328{\r
329 rb_patricia_node_t *pnode;\r
330 struct ConfItem *aconf;\r
331 const char *host, *pass, *user, *oper_reason;\r
332 RB_PATRICIA_WALK(dline_tree->head, pnode)\r
333 {\r
334 aconf = pnode->data;\r
335 if(aconf->flags & CONF_FLAGS_TEMPORARY)\r
336 RB_PATRICIA_WALK_BREAK;\r
337 get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason);\r
338 sendto_one_numeric(source_p, RPL_STATSDLINE,\r
339 form_str (RPL_STATSDLINE),\r
340 'D', host, pass,\r
341 oper_reason ? "|" : "",\r
342 oper_reason ? oper_reason : "");\r
343 }\r
344 RB_PATRICIA_WALK_END;\r
345}\r
346\r
347void\r
348report_tdlines(struct Client *source_p)\r
349{\r
350 rb_patricia_node_t *pnode;\r
351 struct ConfItem *aconf;\r
352 const char *host, *pass, *user, *oper_reason;\r
353 RB_PATRICIA_WALK(dline_tree->head, pnode)\r
354 {\r
355 aconf = pnode->data;\r
356 if(!(aconf->flags & CONF_FLAGS_TEMPORARY))\r
357 RB_PATRICIA_WALK_BREAK;\r
358 get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason);\r
359 sendto_one_numeric(source_p, RPL_STATSDLINE,\r
360 form_str (RPL_STATSDLINE),\r
361 'd', host, pass,\r
362 oper_reason ? "|" : "",\r
363 oper_reason ? oper_reason : "");\r
364 }\r
365 RB_PATRICIA_WALK_END;\r
366}\r
367\r
368void\r
369report_elines(struct Client *source_p)\r
370{\r
371 rb_patricia_node_t *pnode;\r
372 struct ConfItem *aconf;\r
373 int port;\r
374 const char *name, *host, *pass, *user, *classname;\r
375 RB_PATRICIA_WALK(eline_tree->head, pnode)\r
376 {\r
377 aconf = pnode->data;\r
378 get_printable_conf(aconf, &name, &host, &pass, &user, &port, &classname);\r
379 sendto_one_numeric(source_p, RPL_STATSDLINE,\r
380 form_str (RPL_STATSDLINE),\r
381 'e', host, pass,\r
382 "", "");\r
383 }\r
384 RB_PATRICIA_WALK_END;\r
385}\r
386\r
387\r
388\r
389int\r
390throttle_add(struct sockaddr *addr)\r
391{\r
392 throttle_t *t;\r
393 rb_patricia_node_t *pnode;\r
394\r
395 if((pnode = rb_match_ip(throttle_tree, addr)) != NULL)\r
396 {\r
397 t = pnode->data;\r
398\r
399 if(t->count > ConfigFileEntry.throttle_count)\r
400 return 1; \r
401\r
402 /* Stop penalizing them after they've been throttled */\r
403 t->last = rb_current_time();\r
404 t->count++;\r
405\r
406 } else {\r
407 int bitlen = 32;\r
408#ifdef RB_IPV6\r
409 if(GET_SS_FAMILY(addr) == AF_INET6)\r
410 bitlen = 128;\r
411#endif\r
412 t = rb_malloc(sizeof(throttle_t)); \r
413 t->last = rb_current_time();\r
414 t->count = 1;\r
415 pnode = make_and_lookup_ip(throttle_tree, addr, bitlen);\r
416 pnode->data = t;\r
417 rb_dlinkAdd(pnode, &t->node, &throttle_list); \r
418 } \r
419 return 0;\r
420}\r
421\r
422static void\r
423throttle_expires(void *unused)\r
424{\r
425 rb_dlink_node *ptr, *next;\r
426 rb_patricia_node_t *pnode;\r
427 throttle_t *t;\r
428 \r
429 RB_DLINK_FOREACH_SAFE(ptr, next, throttle_list.head)\r
430 {\r
431 pnode = ptr->data;\r
432 t = pnode->data; \r
433\r
434 if(t->last + ConfigFileEntry.throttle_duration > rb_current_time())\r
435 continue;\r
436\r
437 rb_dlinkDelete(ptr, &throttle_list);\r
438 rb_free(t);\r
439 rb_patricia_remove(throttle_tree, pnode);\r
440 }\r
441}\r
442\r
443static int \r
444get_global_count(struct sockaddr *addr)\r
445{\r
446 rb_patricia_node_t *pnode;\r
447 global_t *glb;\r
448 \r
449 if((pnode = rb_match_ip(global_tree, addr)))\r
450 {\r
451 glb = pnode->data;\r
452 return glb->count;\r
453 }\r
454 return 0; \r
455}\r
456\r
457static int\r
458inc_global_ip(struct sockaddr *addr, int bitlen)\r
459{\r
460 rb_patricia_node_t *pnode;\r
461 global_t *glb;\r
462\r
463\r
464 if((pnode = rb_match_ip(global_tree, addr)))\r
465 {\r
466 glb = pnode->data;\r
467 } \r
468 else\r
469 {\r
470 pnode = make_and_lookup_ip(global_tree, addr, bitlen);\r
471 glb = rb_malloc(sizeof(global_t));\r
472 pnode->data = glb;\r
473 }\r
474 glb->count++;\r
475 return glb->count;\r
476}\r
477\r
478static void\r
479dec_global_ip(struct sockaddr *addr)\r
480{\r
481 rb_patricia_node_t *pnode;\r
482 global_t *glb;\r
483 \r
484 if((pnode = rb_match_ip(global_tree, addr)))\r
485 {\r
486 glb = pnode->data;\r
487 glb->count--;\r
488 if(glb->count == 0)\r
489 {\r
490 rb_free(glb);\r
491 rb_patricia_remove(global_tree, pnode);\r
492 return;\r
493 }\r
494 }\r
495}\r
496\r
497int\r
498inc_global_cidr_count(struct Client *client_p)\r
499{\r
500 struct rb_sockaddr_storage ip;\r
501 struct sockaddr *addr;\r
502 int bitlen;\r
503\r
504 if(!MyClient(client_p))\r
505 {\r
506 if(EmptyString(client_p->sockhost) || !strcmp(client_p->sockhost, "0"))\r
507 return -1; \r
508 if(!rb_inet_pton_sock(client_p->sockhost, (struct sockaddr *)&ip))\r
509 return -1;\r
510 addr = (struct sockaddr *)&ip;\r
511 } else\r
512 addr = (struct sockaddr *)&client_p->localClient->ip;\r
513#ifdef RB_IPV6 \r
514 if(GET_SS_FAMILY(addr) == AF_INET6)\r
515 {\r
516 bitlen = ConfigFileEntry.global_cidr_ipv6_bitlen;\r
517 } else\r
518#endif\r
519 bitlen = ConfigFileEntry.global_cidr_ipv4_bitlen;\r
520\r
521 return inc_global_ip(addr, bitlen);\r
522}\r
523\r
524void\r
525dec_global_cidr_count(struct Client *client_p)\r
526{\r
527 struct rb_sockaddr_storage ip;\r
528 struct sockaddr *addr;\r
529 if(!MyClient(client_p))\r
530 {\r
531 if(EmptyString(client_p->sockhost) || !strcmp(client_p->sockhost, "0"))\r
532 return;\r
533 if(!rb_inet_pton_sock(client_p->sockhost, (struct sockaddr *)&ip))\r
534 return;\r
535 addr = (struct sockaddr *)&ip;\r
536 } else\r
537 addr = (struct sockaddr *)&client_p->localClient->ip;\r
538 \r
539 dec_global_ip(addr);\r
540}\r
541\r
542int\r
543check_global_cidr_count(struct Client *client_p)\r
544{\r
545 struct rb_sockaddr_storage ip;\r
546 struct sockaddr *addr;\r
547 int count, max;\r
548 if(!MyClient(client_p))\r
549 {\r
550 if(EmptyString(client_p->sockhost) || !strcmp(client_p->sockhost, "0"))\r
551 return -1;\r
552 if(!rb_inet_pton_sock(client_p->sockhost, (struct sockaddr *)&ip))\r
553 return -1;\r
554 addr = (struct sockaddr *)&ip;\r
555 } else \r
556 addr = (struct sockaddr *)&client_p->localClient->ip;\r
557 count = get_global_count(addr);\r
558#ifdef RB_IPV6\r
559 if(GET_SS_FAMILY(addr) == AF_INET6)\r
560 max = ConfigFileEntry.global_cidr_ipv6_count;\r
561 else\r
562#endif\r
563 max = ConfigFileEntry.global_cidr_ipv4_count;\r
564 if(count >= max)\r
565 return 1;\r
566 return 0;\r
567}\r
568\r
569static void\r
570clear_cidr_tree(void *data)\r
571{\r
572 rb_free(data); \r
573}\r
574\r
575void\r
576rehash_global_cidr_tree(void)\r
577{\r
578 struct Client *client_p;\r
579 rb_dlink_node *ptr;\r
580 rb_clear_patricia(global_tree, clear_cidr_tree);\r
581 RB_DLINK_FOREACH(ptr, global_client_list.head)\r
582 {\r
583 client_p = ptr->data;\r
584 if(IsMe(client_p) && IsServer(client_p))\r
585 continue;\r
586 inc_global_cidr_count(client_p); \r
587 }\r
588 return;\r
589}\r