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