]> jfr.im git - irc/rqf/shadowircd.git/blame - src/reject.c
Move to ratbox3 reject and throttle code.
[irc/rqf/shadowircd.git] / src / reject.c
CommitLineData
21c9d815
VY
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
d1275a8f 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21c9d815
VY
21 * USA
22 *
d1275a8f 23 * $Id: reject.c 25119 2008-03-13 16:57:05Z androsyn $
21c9d815
VY
24 */
25
26#include "stdinc.h"
21c9d815
VY
27#include "client.h"
28#include "s_conf.h"
29#include "reject.h"
30#include "s_stats.h"
d1275a8f
JT
31#include "ircd.h"
32#include "send.h"
33#include "numeric.h"
34#include "parse.h"
35#include "hostmask.h"
36#include "match.h"
21c9d815
VY
37#include "hash.h"
38
d1275a8f 39static rb_patricia_tree_t *global_tree;
07943cb5 40static rb_patricia_tree_t *reject_tree;
d1275a8f 41static rb_dlink_list delay_exit;
21c9d815 42static rb_dlink_list reject_list;
d1275a8f
JT
43static rb_dlink_list throttle_list;
44static rb_patricia_tree_t *throttle_tree;
45static void throttle_expires(void *unused);
21c9d815 46
21c9d815 47
d1275a8f 48typedef struct _reject_data
21c9d815
VY
49{
50 rb_dlink_node rnode;
51 time_t time;
52 unsigned int count;
53 uint32_t mask_hashv;
d1275a8f
JT
54} reject_t;
55
56typedef struct _delay_data
57{
58 rb_dlink_node node;
59 rb_fde_t *F;
60} delay_t;
61
62typedef struct _throttle
63{
64 rb_dlink_node node;
65 time_t last;
66 int count;
67} throttle_t;
68
69unsigned long
70delay_exit_length(void)
71{
72 return rb_dlink_list_length(&delay_exit);
73}
21c9d815 74
21c9d815
VY
75static void
76reject_exit(void *unused)
77{
21c9d815 78 rb_dlink_node *ptr, *ptr_next;
d1275a8f
JT
79 delay_t *ddata;
80 static const char *errbuf = "ERROR :Closing Link: (*** Banned (cache))\r\n";
81
21c9d815
VY
82 RB_DLINK_FOREACH_SAFE(ptr, ptr_next, delay_exit.head)
83 {
d1275a8f
JT
84 ddata = ptr->data;
85
86 rb_write(ddata->F, errbuf, strlen(errbuf));
87 rb_close(ddata->F);
88 rb_free(ddata);
21c9d815
VY
89 }
90
d1275a8f
JT
91 delay_exit.head = delay_exit.tail = NULL;
92 delay_exit.length = 0;
21c9d815
VY
93}
94
95static void
96reject_expires(void *unused)
97{
98 rb_dlink_node *ptr, *next;
07943cb5 99 rb_patricia_node_t *pnode;
d1275a8f 100 reject_t *rdata;
21c9d815
VY
101
102 RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
103 {
104 pnode = ptr->data;
105 rdata = pnode->data;
106
107 if(rdata->time + ConfigFileEntry.reject_duration > rb_current_time())
108 continue;
109
110 rb_dlinkDelete(ptr, &reject_list);
111 rb_free(rdata);
07943cb5 112 rb_patricia_remove(reject_tree, pnode);
21c9d815
VY
113 }
114}
115
116void
117init_reject(void)
118{
07943cb5 119 reject_tree = rb_new_patricia(PATRICIA_BITS);
d1275a8f 120 throttle_tree = rb_new_patricia(PATRICIA_BITS);
21c9d815
VY
121 rb_event_add("reject_exit", reject_exit, NULL, DELAYED_EXIT_TIME);
122 rb_event_add("reject_expires", reject_expires, NULL, 60);
d1275a8f 123 rb_event_add("throttle_expires", throttle_expires, NULL, 10);
21c9d815
VY
124}
125
126
127void
128add_reject(struct Client *client_p, const char *mask1, const char *mask2)
129{
07943cb5 130 rb_patricia_node_t *pnode;
d1275a8f 131 reject_t *rdata;
21c9d815
VY
132 uint32_t hashv;
133
134 /* Reject is disabled */
d1275a8f 135 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
21c9d815
VY
136 return;
137
138 hashv = 0;
139 if (mask1 != NULL)
d1275a8f 140 hashv ^= fnv_hash_upper((const unsigned char *)mask1, 32);
21c9d815 141 if (mask2 != NULL)
d1275a8f 142 hashv ^= fnv_hash_upper((const unsigned char *)mask2, 32);
21c9d815 143
07943cb5 144 if((pnode = rb_match_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip)) != NULL)
21c9d815
VY
145 {
146 rdata = pnode->data;
147 rdata->time = rb_current_time();
148 rdata->count++;
149 }
150 else
151 {
152 int bitlen = 32;
2c2e0aa9 153#ifdef RB_IPV6
d1275a8f 154 if(GET_SS_FAMILY(&client_p->localClient->ip) == AF_INET6)
21c9d815
VY
155 bitlen = 128;
156#endif
157 pnode = make_and_lookup_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip, bitlen);
d1275a8f 158 pnode->data = rdata = rb_malloc(sizeof(reject_t));
21c9d815
VY
159 rb_dlinkAddTail(pnode, &rdata->rnode, &reject_list);
160 rdata->time = rb_current_time();
161 rdata->count = 1;
162 }
163 rdata->mask_hashv = hashv;
164}
165
166int
d1275a8f 167check_reject(rb_fde_t *F, struct sockaddr *addr)
21c9d815 168{
07943cb5 169 rb_patricia_node_t *pnode;
d1275a8f
JT
170 reject_t *rdata;
171 delay_t *ddata;
21c9d815 172 /* Reject is disabled */
d1275a8f 173 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
21c9d815
VY
174 return 0;
175
d1275a8f 176 pnode = rb_match_ip(reject_tree, addr);
21c9d815
VY
177 if(pnode != NULL)
178 {
179 rdata = pnode->data;
180
181 rdata->time = rb_current_time();
d1275a8f 182 if(rdata->count > (unsigned long)ConfigFileEntry.reject_after_count)
21c9d815 183 {
d1275a8f 184 ddata = rb_malloc(sizeof(delay_t));
83251205 185 ServerStats.is_rej++;
d1275a8f
JT
186 rb_setselect(F, RB_SELECT_WRITE | RB_SELECT_READ, NULL, NULL);
187 ddata->F = F;
188 rb_dlinkAdd(ddata, &ddata->node, &delay_exit);
21c9d815
VY
189 return 1;
190 }
191 }
192 /* Caller does what it wants */
193 return 0;
194}
195
196void
197flush_reject(void)
198{
199 rb_dlink_node *ptr, *next;
07943cb5 200 rb_patricia_node_t *pnode;
d1275a8f 201 reject_t *rdata;
21c9d815
VY
202
203 RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
204 {
205 pnode = ptr->data;
206 rdata = pnode->data;
207 rb_dlinkDelete(ptr, &reject_list);
208 rb_free(rdata);
07943cb5 209 rb_patricia_remove(reject_tree, pnode);
21c9d815
VY
210 }
211}
212
213int
214remove_reject_ip(const char *ip)
215{
07943cb5 216 rb_patricia_node_t *pnode;
21c9d815
VY
217
218 /* Reject is disabled */
d1275a8f 219 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
21c9d815
VY
220 return -1;
221
07943cb5 222 if((pnode = rb_match_string(reject_tree, ip)) != NULL)
21c9d815 223 {
d1275a8f 224 reject_t *rdata = pnode->data;
21c9d815
VY
225 rb_dlinkDelete(&rdata->rnode, &reject_list);
226 rb_free(rdata);
07943cb5 227 rb_patricia_remove(reject_tree, pnode);
21c9d815
VY
228 return 1;
229 }
230 return 0;
231}
232
233int
234remove_reject_mask(const char *mask1, const char *mask2)
235{
236 rb_dlink_node *ptr, *next;
07943cb5 237 rb_patricia_node_t *pnode;
d1275a8f 238 reject_t *rdata;
21c9d815
VY
239 uint32_t hashv;
240 int n = 0;
241
242 hashv = 0;
243 if (mask1 != NULL)
d1275a8f 244 hashv ^= fnv_hash_upper((const unsigned char *)mask1, 32);
21c9d815 245 if (mask2 != NULL)
d1275a8f 246 hashv ^= fnv_hash_upper((const unsigned char *)mask2, 32);
21c9d815
VY
247 RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
248 {
249 pnode = ptr->data;
250 rdata = pnode->data;
251 if (rdata->mask_hashv == hashv)
252 {
253 rb_dlinkDelete(ptr, &reject_list);
254 rb_free(rdata);
07943cb5 255 rb_patricia_remove(reject_tree, pnode);
21c9d815
VY
256 n++;
257 }
258 }
259 return n;
260}
261
21c9d815 262int
d1275a8f 263throttle_add(struct sockaddr *addr)
21c9d815 264{
d1275a8f 265 throttle_t *t;
07943cb5 266 rb_patricia_node_t *pnode;
21c9d815 267
d1275a8f 268 if((pnode = rb_match_ip(throttle_tree, addr)) != NULL)
21c9d815 269 {
d1275a8f
JT
270 t = pnode->data;
271
272 if(t->count > ConfigFileEntry.throttle_count)
273 return 1;
274
275 /* Stop penalizing them after they've been throttled */
276 t->last = rb_current_time();
277 t->count++;
278
279 } else {
21c9d815 280 int bitlen = 32;
2c2e0aa9 281#ifdef RB_IPV6
d1275a8f 282 if(GET_SS_FAMILY(addr) == AF_INET6)
21c9d815
VY
283 bitlen = 128;
284#endif
d1275a8f
JT
285 t = rb_malloc(sizeof(throttle_t));
286 t->last = rb_current_time();
287 t->count = 1;
288 pnode = make_and_lookup_ip(throttle_tree, addr, bitlen);
289 pnode->data = t;
290 rb_dlinkAdd(pnode, &t->node, &throttle_list);
291 }
21c9d815
VY
292 return 0;
293}
294
d1275a8f
JT
295static void
296throttle_expires(void *unused)
21c9d815 297{
d1275a8f 298 rb_dlink_node *ptr, *next;
07943cb5 299 rb_patricia_node_t *pnode;
d1275a8f
JT
300 throttle_t *t;
301
302 RB_DLINK_FOREACH_SAFE(ptr, next, throttle_list.head)
21c9d815 303 {
d1275a8f
JT
304 pnode = ptr->data;
305 t = pnode->data;
306
307 if(t->last + ConfigFileEntry.throttle_duration > rb_current_time())
308 continue;
309
310 rb_dlinkDelete(ptr, &throttle_list);
311 rb_free(t);
312 rb_patricia_remove(throttle_tree, pnode);
21c9d815 313 }
21c9d815 314}
d1275a8f 315