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