2 * ircd-ratbox: A slightly useful ircd
3 * reject.c: reject users with prejudice
5 * Copyright (C) 2003 Aaron Sethman <androsyn@ratbox.org>
6 * Copyright (C) 2003-2005 ircd-ratbox development team
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.
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.
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
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
);
45 typedef struct _reject_data
48 struct ConfItem
*aconf
;
55 typedef struct _delay_data
59 struct ConfItem
*aconf
;
63 typedef struct _throttle
71 delay_exit_length(void)
73 return rb_dlink_list_length(&delay_exit
);
77 reject_free(reject_t
*rdata
)
79 struct ConfItem
*aconf
= rdata
->aconf
;
88 reject_exit(void *unused
)
90 static char dynamic_reason
[BUFSIZE
];
91 rb_dlink_node
*ptr
, *ptr_next
;
93 static const char *errbuf
= "ERROR :Closing Link: (*** Banned (cache))\r\n";
95 RB_DLINK_FOREACH_SAFE(ptr
, ptr_next
, delay_exit
.head
)
99 *dynamic_reason
= '\0';
103 snprintf(dynamic_reason
, BUFSIZE
, form_str(ERR_YOUREBANNEDCREEP
) "\r\n",
104 me
.name
, "*", get_user_ban_reason(ddata
->aconf
));
105 rb_write(ddata
->F
, dynamic_reason
, strlen(dynamic_reason
));
107 deref_conf(ddata
->aconf
);
109 else if (ddata
->reason
)
111 snprintf(dynamic_reason
, BUFSIZE
, ":%s 465 %s :%s\r\n",
112 me
.name
, "*", ddata
->reason
);
113 rb_write(ddata
->F
, dynamic_reason
, strlen(dynamic_reason
));
116 rb_write(ddata
->F
, errbuf
, strlen(errbuf
));
121 delay_exit
.head
= delay_exit
.tail
= NULL
;
122 delay_exit
.length
= 0;
126 reject_expires(void *unused
)
128 rb_dlink_node
*ptr
, *next
;
129 rb_patricia_node_t
*pnode
;
132 RB_DLINK_FOREACH_SAFE(ptr
, next
, reject_list
.head
)
137 if(rdata
->time
+ ConfigFileEntry
.reject_duration
> rb_current_time())
140 rb_dlinkDelete(ptr
, &reject_list
);
142 rb_patricia_remove(reject_tree
, pnode
);
149 reject_tree
= rb_new_patricia(PATRICIA_BITS
);
150 throttle_tree
= rb_new_patricia(PATRICIA_BITS
);
151 rb_event_add("reject_exit", reject_exit
, NULL
, DELAYED_EXIT_TIME
);
152 rb_event_add("reject_expires", reject_expires
, NULL
, 60);
153 rb_event_add("throttle_expires", throttle_expires
, NULL
, 10);
161 rb_patricia_node_t
*pnode
;
165 RB_DLINK_FOREACH(ptr
, throttle_list
.head
)
169 if (t
->count
> ConfigFileEntry
.throttle_count
)
177 add_reject(struct Client
*client_p
, const char *mask1
, const char *mask2
, struct ConfItem
*aconf
, const char *reason
)
179 rb_patricia_node_t
*pnode
;
183 /* Reject is disabled */
184 if(ConfigFileEntry
.reject_after_count
== 0 || ConfigFileEntry
.reject_duration
== 0)
189 hashv
^= fnv_hash_upper((const unsigned char *)mask1
, 32);
191 hashv
^= fnv_hash_upper((const unsigned char *)mask2
, 32);
193 if((pnode
= rb_match_ip(reject_tree
, (struct sockaddr
*)&client_p
->localClient
->ip
)) != NULL
)
196 rdata
->time
= rb_current_time();
202 if(GET_SS_FAMILY(&client_p
->localClient
->ip
) == AF_INET6
)
204 pnode
= make_and_lookup_ip(reject_tree
, (struct sockaddr
*)&client_p
->localClient
->ip
, bitlen
);
205 pnode
->data
= rdata
= rb_malloc(sizeof(reject_t
));
206 rb_dlinkAddTail(pnode
, &rdata
->rnode
, &reject_list
);
207 rdata
->time
= rb_current_time();
210 rdata
->reason
= NULL
;
212 rdata
->mask_hashv
= hashv
;
214 if (aconf
!= NULL
&& aconf
!= rdata
->aconf
&& (aconf
->status
& CONF_KILL
) && aconf
->passwd
)
216 if (rdata
->aconf
!= NULL
)
217 deref_conf(rdata
->aconf
);
219 rdata
->aconf
= aconf
;
221 else if (reason
!= NULL
)
223 if (rdata
->aconf
!= NULL
)
224 deref_conf(rdata
->aconf
);
226 rdata
->reason
= reason
;
231 check_reject(rb_fde_t
*F
, struct sockaddr
*addr
)
233 rb_patricia_node_t
*pnode
;
237 /* Reject is disabled */
238 if (ConfigFileEntry
.reject_after_count
== 0 || ConfigFileEntry
.reject_duration
== 0)
241 pnode
= rb_match_ip(reject_tree
, addr
);
246 rdata
->time
= rb_current_time();
248 if (rdata
->count
<= (unsigned long)ConfigFileEntry
.reject_after_count
)
251 if (rdata
->aconf
!= NULL
&& rdata
->aconf
->status
& CONF_ILLEGAL
)
253 rb_dlinkDelete(&rdata
->rnode
, &reject_list
);
255 rb_patricia_remove(reject_tree
, pnode
);
259 ddata
= rb_malloc(sizeof(delay_t
));
260 ServerStats
.is_rej
++;
261 rb_setselect(F
, RB_SELECT_WRITE
| RB_SELECT_READ
, NULL
, NULL
);
264 ddata
->aconf
= rdata
->aconf
;
265 ddata
->aconf
->clients
++;
266 ddata
->reason
= NULL
;
268 else if (rdata
->reason
)
270 ddata
->reason
= rdata
->reason
;
276 ddata
->reason
= NULL
;
279 rb_dlinkAdd(ddata
, &ddata
->node
, &delay_exit
);
284 is_reject_ip(struct sockaddr
*addr
)
286 rb_patricia_node_t
*pnode
;
290 /* Reject is disabled */
291 if(ConfigFileEntry
.reject_after_count
== 0 || ConfigFileEntry
.reject_duration
== 0)
294 pnode
= rb_match_ip(reject_tree
, addr
);
299 if(rdata
->count
> (unsigned long)ConfigFileEntry
.reject_after_count
)
301 duration
= rdata
->time
+ ConfigFileEntry
.reject_duration
- rb_current_time();
302 return duration
> 0 ? duration
: 1;
311 rb_dlink_node
*ptr
, *next
;
312 rb_patricia_node_t
*pnode
;
315 RB_DLINK_FOREACH_SAFE(ptr
, next
, reject_list
.head
)
319 rb_dlinkDelete(ptr
, &reject_list
);
321 rb_patricia_remove(reject_tree
, pnode
);
326 remove_reject_ip(const char *ip
)
328 rb_patricia_node_t
*pnode
;
330 /* Reject is disabled */
331 if(ConfigFileEntry
.reject_after_count
== 0 || ConfigFileEntry
.reject_duration
== 0)
334 if((pnode
= rb_match_string(reject_tree
, ip
)) != NULL
)
336 reject_t
*rdata
= pnode
->data
;
337 rb_dlinkDelete(&rdata
->rnode
, &reject_list
);
339 rb_patricia_remove(reject_tree
, pnode
);
346 remove_reject_mask(const char *mask1
, const char *mask2
)
348 rb_dlink_node
*ptr
, *next
;
349 rb_patricia_node_t
*pnode
;
356 hashv
^= fnv_hash_upper((const unsigned char *)mask1
, 32);
358 hashv
^= fnv_hash_upper((const unsigned char *)mask2
, 32);
359 RB_DLINK_FOREACH_SAFE(ptr
, next
, reject_list
.head
)
363 if (rdata
->mask_hashv
== hashv
)
365 rb_dlinkDelete(ptr
, &reject_list
);
367 rb_patricia_remove(reject_tree
, pnode
);
375 throttle_add(struct sockaddr
*addr
)
378 rb_patricia_node_t
*pnode
;
380 if((pnode
= rb_match_ip(throttle_tree
, addr
)) != NULL
)
384 if(t
->count
> ConfigFileEntry
.throttle_count
)
386 ServerStats
.is_thr
++;
389 /* Stop penalizing them after they've been throttled */
390 t
->last
= rb_current_time();
395 if(GET_SS_FAMILY(addr
) == AF_INET6
)
397 t
= rb_malloc(sizeof(throttle_t
));
398 t
->last
= rb_current_time();
400 pnode
= make_and_lookup_ip(throttle_tree
, addr
, bitlen
);
402 rb_dlinkAdd(pnode
, &t
->node
, &throttle_list
);
408 is_throttle_ip(struct sockaddr
*addr
)
411 rb_patricia_node_t
*pnode
;
414 if((pnode
= rb_match_ip(throttle_tree
, addr
)) != NULL
)
417 if(t
->count
> ConfigFileEntry
.throttle_count
)
419 duration
= t
->last
+ ConfigFileEntry
.throttle_duration
- rb_current_time();
420 return duration
> 0 ? duration
: 1;
429 rb_dlink_node
*ptr
, *next
;
430 rb_patricia_node_t
*pnode
;
433 RB_DLINK_FOREACH_SAFE(ptr
, next
, throttle_list
.head
)
438 rb_dlinkDelete(ptr
, &throttle_list
);
440 rb_patricia_remove(throttle_tree
, pnode
);
445 throttle_expires(void *unused
)
447 rb_dlink_node
*ptr
, *next
;
448 rb_patricia_node_t
*pnode
;
451 RB_DLINK_FOREACH_SAFE(ptr
, next
, throttle_list
.head
)
456 if(t
->last
+ ConfigFileEntry
.throttle_duration
> rb_current_time())
459 rb_dlinkDelete(ptr
, &throttle_list
);
461 rb_patricia_remove(throttle_tree
, pnode
);