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 $
36 static patricia_tree_t
*reject_tree
;
37 rb_dlink_list delay_exit
;
38 static rb_dlink_list reject_list
;
40 static patricia_tree_t
*unknown_tree
;
50 static patricia_tree_t
*unknown_tree
;
53 reject_exit(void *unused
)
55 struct Client
*client_p
;
56 rb_dlink_node
*ptr
, *ptr_next
;
58 RB_DLINK_FOREACH_SAFE(ptr
, ptr_next
, delay_exit
.head
)
64 /* this MUST be here, to prevent the possibility
65 * sendto_one() generates a write error, and then a client
66 * ends up on the dead_list and the abort_list --fl
68 * new disconnect notice stolen from ircu --nenolod
69 * no, this only happens when someone's IP has some
70 * ban on it and rejects them rather longer than the
71 * ircu message suggests --jilles
73 if(!IsIOError(client_p
))
75 if(IsExUnknown(client_p
))
76 sendto_one(client_p
, "ERROR :Closing Link: %s (*** Too many unknown connections)", client_p
->host
);
78 sendto_one(client_p
, "ERROR :Closing Link: %s (*** Banned (cache))", client_p
->host
);
80 close_connection(client_p
);
82 rb_dlinkAddAlloc(client_p
, &dead_list
);
85 delay_exit
.head
= delay_exit
.tail
= NULL
;
86 delay_exit
.length
= 0;
90 reject_expires(void *unused
)
92 rb_dlink_node
*ptr
, *next
;
93 patricia_node_t
*pnode
;
94 struct reject_data
*rdata
;
96 RB_DLINK_FOREACH_SAFE(ptr
, next
, reject_list
.head
)
101 if(rdata
->time
+ ConfigFileEntry
.reject_duration
> rb_current_time())
104 rb_dlinkDelete(ptr
, &reject_list
);
106 patricia_remove(reject_tree
, pnode
);
113 reject_tree
= New_Patricia(PATRICIA_BITS
);
114 unknown_tree
= New_Patricia(PATRICIA_BITS
);
115 eventAdd("reject_exit", reject_exit
, NULL
, DELAYED_EXIT_TIME
);
116 eventAdd("reject_expires", reject_expires
, NULL
, 60);
121 add_reject(struct Client
*client_p
, const char *mask1
, const char *mask2
)
123 patricia_node_t
*pnode
;
124 struct reject_data
*rdata
;
127 /* Reject is disabled */
128 if(ConfigFileEntry
.reject_after_count
== 0 || ConfigFileEntry
.reject_ban_time
== 0)
133 hashv
^= fnv_hash_upper(mask1
, 32);
135 hashv
^= fnv_hash_upper(mask2
, 32);
137 if((pnode
= match_ip(reject_tree
, (struct sockaddr
*)&client_p
->localClient
->ip
)) != NULL
)
140 rdata
->time
= rb_current_time();
147 if(client_p
->localClient
->ip
.ss_family
== AF_INET6
)
150 pnode
= make_and_lookup_ip(reject_tree
, (struct sockaddr
*)&client_p
->localClient
->ip
, bitlen
);
151 pnode
->data
= rdata
= rb_malloc(sizeof(struct reject_data
));
152 rb_dlinkAddTail(pnode
, &rdata
->rnode
, &reject_list
);
153 rdata
->time
= rb_current_time();
156 rdata
->mask_hashv
= hashv
;
160 check_reject(struct Client
*client_p
)
162 patricia_node_t
*pnode
;
163 struct reject_data
*rdata
;
165 /* Reject is disabled */
166 if(ConfigFileEntry
.reject_after_count
== 0 || ConfigFileEntry
.reject_ban_time
== 0 ||
167 ConfigFileEntry
.reject_duration
== 0)
170 pnode
= match_ip(reject_tree
, (struct sockaddr
*)&client_p
->localClient
->ip
);
175 rdata
->time
= rb_current_time();
176 if(rdata
->count
> ConfigFileEntry
.reject_after_count
)
178 ServerStats
->is_rej
++;
180 rb_setselect(client_p
->localClient
->F
->fd
, FDLIST_NONE
, COMM_SELECT_WRITE
| COMM_SELECT_READ
, NULL
, NULL
, 0);
181 SetClosing(client_p
);
182 rb_dlinkMoveNode(&client_p
->localClient
->tnode
, &unknown_list
, &delay_exit
);
186 /* Caller does what it wants */
193 rb_dlink_node
*ptr
, *next
;
194 patricia_node_t
*pnode
;
195 struct reject_data
*rdata
;
197 RB_DLINK_FOREACH_SAFE(ptr
, next
, reject_list
.head
)
201 rb_dlinkDelete(ptr
, &reject_list
);
203 patricia_remove(reject_tree
, pnode
);
208 remove_reject_ip(const char *ip
)
210 patricia_node_t
*pnode
;
212 /* Reject is disabled */
213 if(ConfigFileEntry
.reject_after_count
== 0 || ConfigFileEntry
.reject_ban_time
== 0 ||
214 ConfigFileEntry
.reject_duration
== 0)
217 if((pnode
= match_string(reject_tree
, ip
)) != NULL
)
219 struct reject_data
*rdata
= pnode
->data
;
220 rb_dlinkDelete(&rdata
->rnode
, &reject_list
);
222 patricia_remove(reject_tree
, pnode
);
229 remove_reject_mask(const char *mask1
, const char *mask2
)
231 rb_dlink_node
*ptr
, *next
;
232 patricia_node_t
*pnode
;
233 struct reject_data
*rdata
;
239 hashv
^= fnv_hash_upper(mask1
, 32);
241 hashv
^= fnv_hash_upper(mask2
, 32);
242 RB_DLINK_FOREACH_SAFE(ptr
, next
, reject_list
.head
)
246 if (rdata
->mask_hashv
== hashv
)
248 rb_dlinkDelete(ptr
, &reject_list
);
250 patricia_remove(reject_tree
, pnode
);
259 add_unknown_ip(struct Client
*client_p
)
261 patricia_node_t
*pnode
;
263 if((pnode
= match_ip(unknown_tree
, (struct sockaddr
*)&client_p
->localClient
->ip
)) == NULL
)
267 if(client_p
->localClient
->ip
.ss_family
== AF_INET6
)
270 pnode
= make_and_lookup_ip(unknown_tree
, (struct sockaddr
*)&client_p
->localClient
->ip
, bitlen
);
271 pnode
->data
= (void *)0;
274 if((unsigned long)pnode
->data
>= ConfigFileEntry
.max_unknown_ip
)
276 SetExUnknown(client_p
);
278 rb_setselect(client_p
->localClient
->F
->fd
, FDLIST_NONE
, COMM_SELECT_WRITE
| COMM_SELECT_READ
, NULL
, NULL
, 0);
279 SetClosing(client_p
);
280 rb_dlinkMoveNode(&client_p
->localClient
->tnode
, &unknown_list
, &delay_exit
);
284 pnode
->data
= (void *)((unsigned long)pnode
->data
+ 1);
290 del_unknown_ip(struct Client
*client_p
)
292 patricia_node_t
*pnode
;
294 if((pnode
= match_ip(unknown_tree
, (struct sockaddr
*)&client_p
->localClient
->ip
)) != NULL
)
296 pnode
->data
= (void *)((unsigned long)pnode
->data
- 1);
297 if((unsigned long)pnode
->data
<= 0)
299 patricia_remove(unknown_tree
, pnode
);
302 /* this can happen due to m_webirc.c's manipulations, for example */