]> jfr.im git - solanum.git/blob - ircd/reject.c
Remove unused kline_delay config option
[solanum.git] / ircd / reject.c
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
24 #include "stdinc.h"
25 #include "client.h"
26 #include "s_conf.h"
27 #include "reject.h"
28 #include "s_stats.h"
29 #include "ircd.h"
30 #include "send.h"
31 #include "numeric.h"
32 #include "parse.h"
33 #include "hostmask.h"
34 #include "match.h"
35 #include "hash.h"
36
37 static rb_patricia_tree_t *reject_tree;
38 static rb_dlink_list delay_exit;
39 static rb_dlink_list reject_list;
40 static rb_dlink_list throttle_list;
41 static rb_patricia_tree_t *throttle_tree;
42 static void throttle_expires(void *unused);
43
44
45 typedef struct _reject_data
46 {
47 rb_dlink_node rnode;
48 time_t time;
49 unsigned int count;
50 uint32_t mask_hashv;
51 } reject_t;
52
53 typedef struct _delay_data
54 {
55 rb_dlink_node node;
56 rb_fde_t *F;
57 } delay_t;
58
59 typedef struct _throttle
60 {
61 rb_dlink_node node;
62 time_t last;
63 int count;
64 } throttle_t;
65
66 unsigned long
67 delay_exit_length(void)
68 {
69 return rb_dlink_list_length(&delay_exit);
70 }
71
72 static void
73 reject_exit(void *unused)
74 {
75 rb_dlink_node *ptr, *ptr_next;
76 delay_t *ddata;
77 static const char *errbuf = "ERROR :Closing Link: (*** Banned (cache))\r\n";
78
79 RB_DLINK_FOREACH_SAFE(ptr, ptr_next, delay_exit.head)
80 {
81 ddata = ptr->data;
82
83 rb_write(ddata->F, errbuf, strlen(errbuf));
84 rb_close(ddata->F);
85 rb_free(ddata);
86 }
87
88 delay_exit.head = delay_exit.tail = NULL;
89 delay_exit.length = 0;
90 }
91
92 static void
93 reject_expires(void *unused)
94 {
95 rb_dlink_node *ptr, *next;
96 rb_patricia_node_t *pnode;
97 reject_t *rdata;
98
99 RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
100 {
101 pnode = ptr->data;
102 rdata = pnode->data;
103
104 if(rdata->time + ConfigFileEntry.reject_duration > rb_current_time())
105 continue;
106
107 rb_dlinkDelete(ptr, &reject_list);
108 rb_free(rdata);
109 rb_patricia_remove(reject_tree, pnode);
110 }
111 }
112
113 void
114 init_reject(void)
115 {
116 reject_tree = rb_new_patricia(PATRICIA_BITS);
117 throttle_tree = rb_new_patricia(PATRICIA_BITS);
118 rb_event_add("reject_exit", reject_exit, NULL, DELAYED_EXIT_TIME);
119 rb_event_add("reject_expires", reject_expires, NULL, 60);
120 rb_event_add("throttle_expires", throttle_expires, NULL, 10);
121 }
122
123 unsigned long
124 throttle_size(void)
125 {
126 unsigned long count;
127 rb_dlink_node *ptr;
128 rb_patricia_node_t *pnode;
129 throttle_t *t;
130
131 count = 0;
132 RB_DLINK_FOREACH(ptr, throttle_list.head)
133 {
134 pnode = ptr->data;
135 t = pnode->data;
136 if (t->count > ConfigFileEntry.throttle_count)
137 count++;
138 }
139
140 return count;
141 }
142
143 void
144 add_reject(struct Client *client_p, const char *mask1, const char *mask2)
145 {
146 rb_patricia_node_t *pnode;
147 reject_t *rdata;
148 uint32_t hashv;
149
150 /* Reject is disabled */
151 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
152 return;
153
154 hashv = 0;
155 if (mask1 != NULL)
156 hashv ^= fnv_hash_upper((const unsigned char *)mask1, 32);
157 if (mask2 != NULL)
158 hashv ^= fnv_hash_upper((const unsigned char *)mask2, 32);
159
160 if((pnode = rb_match_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip)) != NULL)
161 {
162 rdata = pnode->data;
163 rdata->time = rb_current_time();
164 rdata->count++;
165 }
166 else
167 {
168 int bitlen = 32;
169 if(GET_SS_FAMILY(&client_p->localClient->ip) == AF_INET6)
170 bitlen = 128;
171 pnode = make_and_lookup_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip, bitlen);
172 pnode->data = rdata = rb_malloc(sizeof(reject_t));
173 rb_dlinkAddTail(pnode, &rdata->rnode, &reject_list);
174 rdata->time = rb_current_time();
175 rdata->count = 1;
176 }
177 rdata->mask_hashv = hashv;
178 }
179
180 int
181 check_reject(rb_fde_t *F, struct sockaddr *addr)
182 {
183 rb_patricia_node_t *pnode;
184 reject_t *rdata;
185 delay_t *ddata;
186 /* Reject is disabled */
187 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
188 return 0;
189
190 pnode = rb_match_ip(reject_tree, addr);
191 if(pnode != NULL)
192 {
193 rdata = pnode->data;
194
195 rdata->time = rb_current_time();
196 if(rdata->count > (unsigned long)ConfigFileEntry.reject_after_count)
197 {
198 ddata = rb_malloc(sizeof(delay_t));
199 ServerStats.is_rej++;
200 rb_setselect(F, RB_SELECT_WRITE | RB_SELECT_READ, NULL, NULL);
201 ddata->F = F;
202 rb_dlinkAdd(ddata, &ddata->node, &delay_exit);
203 return 1;
204 }
205 }
206 /* Caller does what it wants */
207 return 0;
208 }
209
210 int
211 is_reject_ip(struct sockaddr *addr)
212 {
213 rb_patricia_node_t *pnode;
214 reject_t *rdata;
215 int duration;
216
217 /* Reject is disabled */
218 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
219 return 0;
220
221 pnode = rb_match_ip(reject_tree, addr);
222 if(pnode != NULL)
223 {
224 rdata = pnode->data;
225
226 if(rdata->count > (unsigned long)ConfigFileEntry.reject_after_count)
227 {
228 duration = rdata->time + ConfigFileEntry.reject_duration - rb_current_time();
229 return duration > 0 ? duration : 1;
230 }
231 }
232 return 0;
233 }
234
235 void
236 flush_reject(void)
237 {
238 rb_dlink_node *ptr, *next;
239 rb_patricia_node_t *pnode;
240 reject_t *rdata;
241
242 RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
243 {
244 pnode = ptr->data;
245 rdata = pnode->data;
246 rb_dlinkDelete(ptr, &reject_list);
247 rb_free(rdata);
248 rb_patricia_remove(reject_tree, pnode);
249 }
250 }
251
252 int
253 remove_reject_ip(const char *ip)
254 {
255 rb_patricia_node_t *pnode;
256
257 /* Reject is disabled */
258 if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
259 return -1;
260
261 if((pnode = rb_match_string(reject_tree, ip)) != NULL)
262 {
263 reject_t *rdata = pnode->data;
264 rb_dlinkDelete(&rdata->rnode, &reject_list);
265 rb_free(rdata);
266 rb_patricia_remove(reject_tree, pnode);
267 return 1;
268 }
269 return 0;
270 }
271
272 int
273 remove_reject_mask(const char *mask1, const char *mask2)
274 {
275 rb_dlink_node *ptr, *next;
276 rb_patricia_node_t *pnode;
277 reject_t *rdata;
278 uint32_t hashv;
279 int n = 0;
280
281 hashv = 0;
282 if (mask1 != NULL)
283 hashv ^= fnv_hash_upper((const unsigned char *)mask1, 32);
284 if (mask2 != NULL)
285 hashv ^= fnv_hash_upper((const unsigned char *)mask2, 32);
286 RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
287 {
288 pnode = ptr->data;
289 rdata = pnode->data;
290 if (rdata->mask_hashv == hashv)
291 {
292 rb_dlinkDelete(ptr, &reject_list);
293 rb_free(rdata);
294 rb_patricia_remove(reject_tree, pnode);
295 n++;
296 }
297 }
298 return n;
299 }
300
301 int
302 throttle_add(struct sockaddr *addr)
303 {
304 throttle_t *t;
305 rb_patricia_node_t *pnode;
306
307 if((pnode = rb_match_ip(throttle_tree, addr)) != NULL)
308 {
309 t = pnode->data;
310
311 if(t->count > ConfigFileEntry.throttle_count)
312 {
313 ServerStats.is_thr++;
314 return 1;
315 }
316 /* Stop penalizing them after they've been throttled */
317 t->last = rb_current_time();
318 t->count++;
319
320 } else {
321 int bitlen = 32;
322 if(GET_SS_FAMILY(addr) == AF_INET6)
323 bitlen = 128;
324 t = rb_malloc(sizeof(throttle_t));
325 t->last = rb_current_time();
326 t->count = 1;
327 pnode = make_and_lookup_ip(throttle_tree, addr, bitlen);
328 pnode->data = t;
329 rb_dlinkAdd(pnode, &t->node, &throttle_list);
330 }
331 return 0;
332 }
333
334 int
335 is_throttle_ip(struct sockaddr *addr)
336 {
337 throttle_t *t;
338 rb_patricia_node_t *pnode;
339 int duration;
340
341 if((pnode = rb_match_ip(throttle_tree, addr)) != NULL)
342 {
343 t = pnode->data;
344 if(t->count > ConfigFileEntry.throttle_count)
345 {
346 duration = t->last + ConfigFileEntry.throttle_duration - rb_current_time();
347 return duration > 0 ? duration : 1;
348 }
349 }
350 return 0;
351 }
352
353 void
354 flush_throttle(void)
355 {
356 rb_dlink_node *ptr, *next;
357 rb_patricia_node_t *pnode;
358 throttle_t *t;
359
360 RB_DLINK_FOREACH_SAFE(ptr, next, throttle_list.head)
361 {
362 pnode = ptr->data;
363 t = pnode->data;
364
365 rb_dlinkDelete(ptr, &throttle_list);
366 rb_free(t);
367 rb_patricia_remove(throttle_tree, pnode);
368 }
369 }
370
371 static void
372 throttle_expires(void *unused)
373 {
374 rb_dlink_node *ptr, *next;
375 rb_patricia_node_t *pnode;
376 throttle_t *t;
377
378 RB_DLINK_FOREACH_SAFE(ptr, next, throttle_list.head)
379 {
380 pnode = ptr->data;
381 t = pnode->data;
382
383 if(t->last + ConfigFileEntry.throttle_duration > rb_current_time())
384 continue;
385
386 rb_dlinkDelete(ptr, &throttle_list);
387 rb_free(t);
388 rb_patricia_remove(throttle_tree, pnode);
389 }
390 }
391