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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * $Id: reject.c 3456 2007-05-18 19:14:18Z jilles $
35 static rb_patricia_tree_t
*reject_tree
;
36 rb_dlink_list delay_exit
;
37 static rb_dlink_list reject_list
;
39 static rb_patricia_tree_t
*unknown_tree
;
50 reject_exit(void *unused
)
52 struct Client
*client_p
;
53 rb_dlink_node
*ptr
, *ptr_next
;
55 RB_DLINK_FOREACH_SAFE(ptr
, ptr_next
, delay_exit
.head
)
61 /* this MUST be here, to prevent the possibility
62 * sendto_one() generates a write error, and then a client
63 * ends up on the dead_list and the abort_list --fl
65 * new disconnect notice stolen from ircu --nenolod
66 * no, this only happens when someone's IP has some
67 * ban on it and rejects them rather longer than the
68 * ircu message suggests --jilles
70 if(!IsIOError(client_p
))
72 if(IsExUnknown(client_p
))
73 sendto_one(client_p
, "ERROR :Closing Link: %s (*** Too many unknown connections)", client_p
->host
);
75 sendto_one(client_p
, "ERROR :Closing Link: %s (*** Banned (cache))", client_p
->host
);
77 close_connection(client_p
);
79 rb_dlinkAddAlloc(client_p
, &dead_list
);
82 delay_exit
.head
= delay_exit
.tail
= NULL
;
83 delay_exit
.length
= 0;
87 reject_expires(void *unused
)
89 rb_dlink_node
*ptr
, *next
;
90 rb_patricia_node_t
*pnode
;
91 struct reject_data
*rdata
;
93 RB_DLINK_FOREACH_SAFE(ptr
, next
, reject_list
.head
)
98 if(rdata
->time
+ ConfigFileEntry
.reject_duration
> rb_current_time())
101 rb_dlinkDelete(ptr
, &reject_list
);
103 rb_patricia_remove(reject_tree
, pnode
);
110 reject_tree
= rb_new_patricia(PATRICIA_BITS
);
111 unknown_tree
= rb_new_patricia(PATRICIA_BITS
);
112 rb_event_add("reject_exit", reject_exit
, NULL
, DELAYED_EXIT_TIME
);
113 rb_event_add("reject_expires", reject_expires
, NULL
, 60);
118 add_reject(struct Client
*client_p
, const char *mask1
, const char *mask2
)
120 rb_patricia_node_t
*pnode
;
121 struct reject_data
*rdata
;
124 /* Reject is disabled */
125 if(ConfigFileEntry
.reject_after_count
== 0 || ConfigFileEntry
.reject_ban_time
== 0)
130 hashv
^= fnv_hash_upper(mask1
, 32);
132 hashv
^= fnv_hash_upper(mask2
, 32);
134 if((pnode
= rb_match_ip(reject_tree
, (struct sockaddr
*)&client_p
->localClient
->ip
)) != NULL
)
137 rdata
->time
= rb_current_time();
144 if(client_p
->localClient
->ip
.ss_family
== AF_INET6
)
147 pnode
= make_and_lookup_ip(reject_tree
, (struct sockaddr
*)&client_p
->localClient
->ip
, bitlen
);
148 pnode
->data
= rdata
= rb_malloc(sizeof(struct reject_data
));
149 rb_dlinkAddTail(pnode
, &rdata
->rnode
, &reject_list
);
150 rdata
->time
= rb_current_time();
153 rdata
->mask_hashv
= hashv
;
157 check_reject(struct Client
*client_p
)
159 rb_patricia_node_t
*pnode
;
160 struct reject_data
*rdata
;
162 /* Reject is disabled */
163 if(ConfigFileEntry
.reject_after_count
== 0 || ConfigFileEntry
.reject_ban_time
== 0 ||
164 ConfigFileEntry
.reject_duration
== 0)
167 pnode
= rb_match_ip(reject_tree
, (struct sockaddr
*)&client_p
->localClient
->ip
);
172 rdata
->time
= rb_current_time();
173 if(rdata
->count
> ConfigFileEntry
.reject_after_count
)
175 ServerStats
.is_rej
++;
177 rb_setselect(client_p
->localClient
->F
, RB_SELECT_WRITE
| RB_SELECT_READ
, NULL
, NULL
);
178 SetClosing(client_p
);
179 rb_dlinkMoveNode(&client_p
->localClient
->tnode
, &unknown_list
, &delay_exit
);
183 /* Caller does what it wants */
190 rb_dlink_node
*ptr
, *next
;
191 rb_patricia_node_t
*pnode
;
192 struct reject_data
*rdata
;
194 RB_DLINK_FOREACH_SAFE(ptr
, next
, reject_list
.head
)
198 rb_dlinkDelete(ptr
, &reject_list
);
200 rb_patricia_remove(reject_tree
, pnode
);
205 remove_reject_ip(const char *ip
)
207 rb_patricia_node_t
*pnode
;
209 /* Reject is disabled */
210 if(ConfigFileEntry
.reject_after_count
== 0 || ConfigFileEntry
.reject_ban_time
== 0 ||
211 ConfigFileEntry
.reject_duration
== 0)
214 if((pnode
= rb_match_string(reject_tree
, ip
)) != NULL
)
216 struct reject_data
*rdata
= pnode
->data
;
217 rb_dlinkDelete(&rdata
->rnode
, &reject_list
);
219 rb_patricia_remove(reject_tree
, pnode
);
226 remove_reject_mask(const char *mask1
, const char *mask2
)
228 rb_dlink_node
*ptr
, *next
;
229 rb_patricia_node_t
*pnode
;
230 struct reject_data
*rdata
;
236 hashv
^= fnv_hash_upper(mask1
, 32);
238 hashv
^= fnv_hash_upper(mask2
, 32);
239 RB_DLINK_FOREACH_SAFE(ptr
, next
, reject_list
.head
)
243 if (rdata
->mask_hashv
== hashv
)
245 rb_dlinkDelete(ptr
, &reject_list
);
247 rb_patricia_remove(reject_tree
, pnode
);
256 add_unknown_ip(struct Client
*client_p
)
258 rb_patricia_node_t
*pnode
;
260 if((pnode
= rb_match_ip(unknown_tree
, (struct sockaddr
*)&client_p
->localClient
->ip
)) == NULL
)
264 if(client_p
->localClient
->ip
.ss_family
== AF_INET6
)
267 pnode
= make_and_lookup_ip(unknown_tree
, (struct sockaddr
*)&client_p
->localClient
->ip
, bitlen
);
268 pnode
->data
= (void *)0;
271 if((unsigned long)pnode
->data
>= ConfigFileEntry
.max_unknown_ip
)
273 SetExUnknown(client_p
);
275 rb_setselect(client_p
->localClient
->F
, RB_SELECT_WRITE
| RB_SELECT_READ
, NULL
, NULL
);
276 SetClosing(client_p
);
277 rb_dlinkMoveNode(&client_p
->localClient
->tnode
, &unknown_list
, &delay_exit
);
281 pnode
->data
= (void *)((unsigned long)pnode
->data
+ 1);
287 del_unknown_ip(struct Client
*client_p
)
289 rb_patricia_node_t
*pnode
;
291 if((pnode
= rb_match_ip(unknown_tree
, (struct sockaddr
*)&client_p
->localClient
->ip
)) != NULL
)
293 pnode
->data
= (void *)((unsigned long)pnode
->data
- 1);
294 if((unsigned long)pnode
->data
<= 0)
296 rb_patricia_remove(unknown_tree
, pnode
);
299 /* this can happen due to m_webirc.c's manipulations, for example */