]> jfr.im git - irc/rqf/shadowircd.git/blobdiff - src/reject.c
Removal of ancient SVN ID's part one
[irc/rqf/shadowircd.git] / src / reject.c
index a076fc9f12481cd029f59581144260bd2cc086c4..ab9163b2ede9ae05005556cfccae4d35eb23e8a2 100644 (file)
-/*\r
- *  ircd-ratbox: A slightly useful ircd\r
- *  reject.c: reject users with prejudice\r
- *\r
- *  Copyright (C) 2003 Aaron Sethman <androsyn@ratbox.org>\r
- *  Copyright (C) 2003-2005 ircd-ratbox development team\r
- *\r
- *  This program is free software; you can redistribute it and/or modify\r
- *  it under the terms of the GNU General Public License as published by\r
- *  the Free Software Foundation; either version 2 of the License, or\r
- *  (at your option) any later version.\r
- *\r
- *  This program is distributed in the hope that it will be useful,\r
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- *  GNU General Public License for more details.\r
- *\r
- *  You should have received a copy of the GNU General Public License\r
- *  along with this program; if not, write to the Free Software\r
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301\r
- *  USA\r
- *\r
- *  $Id: reject.c 25119 2008-03-13 16:57:05Z androsyn $\r
- */\r
-\r
-#include "stdinc.h"\r
-#include "client.h"\r
-#include "s_conf.h"\r
-#include "reject.h"\r
-#include "s_stats.h"\r
-#include "ircd.h"\r
-#include "send.h"\r
-#include "numeric.h"\r
-#include "parse.h"\r
-#include "hostmask.h"\r
-\r
-static rb_patricia_tree_t *global_tree;\r
-static rb_patricia_tree_t *reject_tree;\r
-static rb_patricia_tree_t *dline_tree;\r
-static rb_patricia_tree_t *eline_tree;\r
-static rb_dlink_list delay_exit;\r
-static rb_dlink_list reject_list;\r
-static rb_dlink_list throttle_list;\r
-static rb_patricia_tree_t *throttle_tree;\r
-static void throttle_expires(void *unused);\r
-\r
-\r
-typedef struct _reject_data\r
-{\r
-       rb_dlink_node rnode;\r
-       time_t time;\r
-       unsigned int count;\r
-} reject_t;\r
-\r
-typedef struct _delay_data\r
-{\r
-       rb_dlink_node node;\r
-       rb_fde_t *F;\r
-} delay_t;\r
-\r
-typedef struct _throttle\r
-{\r
-       rb_dlink_node node;\r
-       time_t last;\r
-       int count;\r
-} throttle_t;\r
-\r
-typedef struct _global_data\r
-{\r
-       int count;\r
-} global_t;\r
-\r
-\r
-static rb_patricia_node_t *\r
-add_ipline(struct ConfItem *aconf, rb_patricia_tree_t *tree, struct sockaddr *addr, int cidr)\r
-{\r
-       rb_patricia_node_t *pnode;\r
-       pnode = make_and_lookup_ip(tree, addr, cidr);\r
-       if(pnode == NULL)\r
-               return NULL;\r
-       aconf->pnode = pnode;\r
-       pnode->data = aconf;\r
-       return (pnode);\r
-}\r
-\r
-int \r
-add_dline(struct ConfItem *aconf)\r
-{\r
-       struct rb_sockaddr_storage st;\r
-       int bitlen;\r
-       if(parse_netmask(aconf->host, (struct sockaddr *)&st, &bitlen) == HM_HOST)\r
-               return 0;\r
-\r
-       if(add_ipline(aconf, dline_tree, (struct sockaddr *)&st, bitlen) != NULL)\r
-               return 1;\r
-       return 0;\r
-}\r
-\r
-int\r
-add_eline(struct ConfItem *aconf)\r
-{\r
-       struct rb_sockaddr_storage st;\r
-       int bitlen;\r
-       if(parse_netmask(aconf->host, (struct sockaddr *)&st, &bitlen) == HM_HOST)\r
-               return 0;\r
-\r
-       if(add_ipline(aconf, eline_tree, (struct sockaddr *)&st, bitlen) != NULL)\r
-               return 1;\r
-       return 0;\r
-}\r
-\r
-unsigned long\r
-delay_exit_length(void)\r
-{\r
-       return rb_dlink_list_length(&delay_exit);\r
-}\r
-\r
-static void\r
-reject_exit(void *unused)\r
-{\r
-       rb_dlink_node *ptr, *ptr_next;\r
-       delay_t *ddata;\r
-       static const char *errbuf = "ERROR :Closing Link: (*** Banned (cache))\r\n";\r
-       \r
-       RB_DLINK_FOREACH_SAFE(ptr, ptr_next, delay_exit.head)\r
-       {\r
-               ddata = ptr->data;\r
-\r
-               rb_write(ddata->F, errbuf, strlen(errbuf));             \r
-               rb_close(ddata->F);\r
-               rb_free(ddata);\r
-       }\r
-\r
-       delay_exit.head = delay_exit.tail = NULL;\r
-       delay_exit.length = 0;\r
-}\r
-\r
-static void\r
-reject_expires(void *unused)\r
-{\r
-       rb_dlink_node *ptr, *next;\r
-       rb_patricia_node_t *pnode;\r
-       reject_t *rdata;\r
-       \r
-       RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)\r
-       {\r
-               pnode = ptr->data;\r
-               rdata = pnode->data;            \r
-\r
-               if(rdata->time + ConfigFileEntry.reject_duration > rb_current_time())\r
-                       continue;\r
-\r
-               rb_dlinkDelete(ptr, &reject_list);\r
-               rb_free(rdata);\r
-               rb_patricia_remove(reject_tree, pnode);\r
-       }\r
-}\r
-\r
-void\r
-init_reject(void)\r
-{\r
-       reject_tree = rb_new_patricia(PATRICIA_BITS);\r
-       dline_tree = rb_new_patricia(PATRICIA_BITS);\r
-       eline_tree = rb_new_patricia(PATRICIA_BITS);\r
-       throttle_tree = rb_new_patricia(PATRICIA_BITS);\r
-       global_tree =  rb_new_patricia(PATRICIA_BITS);\r
-       rb_event_add("reject_exit", reject_exit, NULL, DELAYED_EXIT_TIME);\r
-       rb_event_add("reject_expires", reject_expires, NULL, 60);\r
-       rb_event_add("throttle_expires", throttle_expires, NULL, 10);\r
-}\r
-\r
-\r
-void\r
-add_reject(struct Client *client_p)\r
-{\r
-       rb_patricia_node_t *pnode;\r
-       reject_t *rdata;\r
-\r
-       /* Reject is disabled */\r
-       if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)\r
-               return;\r
-\r
-       if((pnode = rb_match_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip)) != NULL)\r
-       {\r
-               rdata = pnode->data;\r
-               rdata->time = rb_current_time();\r
-               rdata->count++;\r
-       }\r
-       else\r
-       {\r
-               int bitlen = 32;\r
-#ifdef RB_IPV6\r
-               if(GET_SS_FAMILY(&client_p->localClient->ip) == AF_INET6)\r
-                       bitlen = 128;\r
-#endif\r
-               pnode = make_and_lookup_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip, bitlen);\r
-               pnode->data = rdata = rb_malloc(sizeof(reject_t));\r
-               rb_dlinkAddTail(pnode, &rdata->rnode, &reject_list);\r
-               rdata->time = rb_current_time();\r
-               rdata->count = 1;\r
-       }\r
-}\r
-\r
-int\r
-check_reject(rb_fde_t *F, struct sockaddr *addr)\r
-{\r
-       rb_patricia_node_t *pnode;\r
-       reject_t *rdata;\r
-       delay_t *ddata;\r
-       /* Reject is disabled */\r
-       if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)\r
-               return 0;\r
-               \r
-       pnode = rb_match_ip(reject_tree, addr);\r
-       if(pnode != NULL)\r
-       {\r
-               rdata = pnode->data;\r
-\r
-               rdata->time = rb_current_time();\r
-               if(rdata->count > (unsigned long)ConfigFileEntry.reject_after_count)\r
-               {\r
-                       ddata = rb_malloc(sizeof(delay_t));\r
-                       ServerStats.is_rej++;\r
-                       rb_setselect(F, RB_SELECT_WRITE | RB_SELECT_READ, NULL, NULL);\r
-                       ddata->F = F;\r
-                       rb_dlinkAdd(ddata, &ddata->node, &delay_exit);\r
-                       return 1;\r
-               }\r
-       }       \r
-       /* Caller does what it wants */ \r
-       return 0;\r
-}\r
-\r
-void \r
-flush_reject(void)\r
-{\r
-       rb_dlink_node *ptr, *next;\r
-       rb_patricia_node_t *pnode;\r
-       reject_t *rdata;\r
-       \r
-       RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)\r
-       {\r
-               pnode = ptr->data;\r
-               rdata = pnode->data;\r
-               rb_dlinkDelete(ptr, &reject_list);\r
-               rb_free(rdata);\r
-               rb_patricia_remove(reject_tree, pnode);\r
-       }\r
-}\r
-\r
-int \r
-remove_reject(const char *ip)\r
-{\r
-       rb_patricia_node_t *pnode;\r
-       \r
-       /* Reject is disabled */\r
-       if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)\r
-               return -1;\r
-\r
-       if((pnode = rb_match_string(reject_tree, ip)) != NULL)\r
-       {\r
-               reject_t *rdata = pnode->data;\r
-               rb_dlinkDelete(&rdata->rnode, &reject_list);\r
-               rb_free(rdata);\r
-               rb_patricia_remove(reject_tree, pnode);\r
-               return 1;\r
-       }\r
-       return 0;\r
-}\r
-\r
-static void\r
-delete_ipline(struct ConfItem *aconf, rb_patricia_tree_t *t)\r
-{\r
-       rb_patricia_remove(t, aconf->pnode);\r
-       if(!aconf->clients)\r
-       {\r
-               free_conf(aconf);\r
-       }\r
-}\r
-\r
-static struct ConfItem *\r
-find_ipline(rb_patricia_tree_t *t, struct sockaddr *addr)\r
-{\r
-       rb_patricia_node_t *pnode;\r
-       pnode = rb_match_ip(t, addr);\r
-       if(pnode != NULL)\r
-               return (struct ConfItem *) pnode->data;\r
-       return NULL;\r
-}\r
-\r
-static struct ConfItem *\r
-find_ipline_exact(rb_patricia_tree_t *t, struct sockaddr *addr, unsigned int bitlen)\r
-{\r
-       rb_patricia_node_t *pnode;\r
-       pnode = rb_match_ip_exact(t, addr, bitlen);\r
-       if(pnode != NULL)\r
-               return (struct ConfItem *) pnode->data;\r
-       return NULL;\r
-}\r
-\r
-\r
-struct ConfItem *\r
-find_dline(struct sockaddr *addr)\r
-{\r
-       struct ConfItem *aconf;\r
-       aconf = find_ipline(eline_tree, addr);\r
-       if(aconf != NULL)\r
-       {\r
-               return aconf;\r
-       }\r
-       return (find_ipline(dline_tree, addr));\r
-}\r
-\r
-struct ConfItem *\r
-find_dline_exact(struct sockaddr *addr, unsigned int bitlen)\r
-{\r
-       return find_ipline_exact(dline_tree, addr, bitlen);\r
-}\r
-\r
-void\r
-remove_dline(struct ConfItem *aconf)\r
-{\r
-       delete_ipline(aconf, dline_tree);\r
-}\r
-\r
-void\r
-report_dlines(struct Client *source_p)\r
-{\r
-       rb_patricia_node_t *pnode;\r
-       struct ConfItem *aconf;\r
-       const char *host, *pass, *user, *oper_reason;\r
-       RB_PATRICIA_WALK(dline_tree->head, pnode)\r
-       {\r
-               aconf = pnode->data;\r
-               if(aconf->flags & CONF_FLAGS_TEMPORARY)\r
-                       RB_PATRICIA_WALK_BREAK;\r
-               get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason);\r
-               sendto_one_numeric(source_p, RPL_STATSDLINE,\r
-                                            form_str (RPL_STATSDLINE),\r
-                                             'D', host, pass,\r
-                                             oper_reason ? "|" : "",\r
-                                             oper_reason ? oper_reason : "");\r
-       }\r
-       RB_PATRICIA_WALK_END;\r
-}\r
-\r
-void\r
-report_tdlines(struct Client *source_p)\r
-{\r
-       rb_patricia_node_t *pnode;\r
-       struct ConfItem *aconf;\r
-       const char *host, *pass, *user, *oper_reason;\r
-       RB_PATRICIA_WALK(dline_tree->head, pnode)\r
-       {\r
-               aconf = pnode->data;\r
-               if(!(aconf->flags & CONF_FLAGS_TEMPORARY))\r
-                       RB_PATRICIA_WALK_BREAK;\r
-               get_printable_kline(source_p, aconf, &host, &pass, &user, &oper_reason);\r
-               sendto_one_numeric(source_p, RPL_STATSDLINE,\r
-                                            form_str (RPL_STATSDLINE),\r
-                                             'd', host, pass,\r
-                                             oper_reason ? "|" : "",\r
-                                             oper_reason ? oper_reason : "");\r
-       }\r
-       RB_PATRICIA_WALK_END;\r
-}\r
-\r
-void\r
-report_elines(struct Client *source_p)\r
-{\r
-       rb_patricia_node_t *pnode;\r
-       struct ConfItem *aconf;\r
-       int port;\r
-       const char *name, *host, *pass, *user, *classname;\r
-       RB_PATRICIA_WALK(eline_tree->head, pnode)\r
-       {\r
-               aconf = pnode->data;\r
-               get_printable_conf(aconf, &name, &host, &pass, &user, &port, &classname);\r
-               sendto_one_numeric(source_p, RPL_STATSDLINE,\r
-                                            form_str (RPL_STATSDLINE),\r
-                                             'e', host, pass,\r
-                                             "", "");\r
-       }\r
-       RB_PATRICIA_WALK_END;\r
-}\r
-\r
-\r
-\r
-int\r
-throttle_add(struct sockaddr *addr)\r
-{\r
-       throttle_t *t;\r
-       rb_patricia_node_t *pnode;\r
-\r
-       if((pnode = rb_match_ip(throttle_tree, addr)) != NULL)\r
-       {\r
-               t = pnode->data;\r
-\r
-               if(t->count > ConfigFileEntry.throttle_count)\r
-                       return 1;                       \r
-\r
-               /* Stop penalizing them after they've been throttled */\r
-               t->last = rb_current_time();\r
-               t->count++;\r
-\r
-       } else {\r
-               int bitlen = 32;\r
-#ifdef RB_IPV6\r
-               if(GET_SS_FAMILY(addr) == AF_INET6)\r
-                       bitlen = 128;\r
-#endif\r
-               t = rb_malloc(sizeof(throttle_t));      \r
-               t->last = rb_current_time();\r
-               t->count = 1;\r
-               pnode = make_and_lookup_ip(throttle_tree, addr, bitlen);\r
-               pnode->data = t;\r
-               rb_dlinkAdd(pnode, &t->node, &throttle_list); \r
-       }       \r
-       return 0;\r
-}\r
-\r
-static void\r
-throttle_expires(void *unused)\r
-{\r
-       rb_dlink_node *ptr, *next;\r
-       rb_patricia_node_t *pnode;\r
-       throttle_t *t;\r
-       \r
-       RB_DLINK_FOREACH_SAFE(ptr, next, throttle_list.head)\r
-       {\r
-               pnode = ptr->data;\r
-               t = pnode->data;                \r
-\r
-               if(t->last + ConfigFileEntry.throttle_duration > rb_current_time())\r
-                       continue;\r
-\r
-               rb_dlinkDelete(ptr, &throttle_list);\r
-               rb_free(t);\r
-               rb_patricia_remove(throttle_tree, pnode);\r
-       }\r
-}\r
-\r
-static int \r
-get_global_count(struct sockaddr *addr)\r
-{\r
-       rb_patricia_node_t *pnode;\r
-       global_t *glb;\r
-       \r
-       if((pnode = rb_match_ip(global_tree, addr)))\r
-       {\r
-               glb = pnode->data;\r
-               return glb->count;\r
-       }\r
-       return 0;               \r
-}\r
-\r
-static int\r
-inc_global_ip(struct sockaddr *addr, int bitlen)\r
-{\r
-       rb_patricia_node_t *pnode;\r
-       global_t *glb;\r
-\r
-\r
-       if((pnode = rb_match_ip(global_tree, addr)))\r
-       {\r
-               glb = pnode->data;\r
-       } \r
-       else\r
-       {\r
-               pnode = make_and_lookup_ip(global_tree, addr, bitlen);\r
-               glb = rb_malloc(sizeof(global_t));\r
-               pnode->data = glb;\r
-       }\r
-       glb->count++;\r
-       return glb->count;\r
-}\r
-\r
-static void\r
-dec_global_ip(struct sockaddr *addr)\r
-{\r
-       rb_patricia_node_t *pnode;\r
-       global_t *glb;\r
-       \r
-       if((pnode = rb_match_ip(global_tree, addr)))\r
-       {\r
-               glb = pnode->data;\r
-               glb->count--;\r
-               if(glb->count == 0)\r
-               {\r
-                       rb_free(glb);\r
-                       rb_patricia_remove(global_tree, pnode);\r
-                       return;\r
-               }\r
-       }\r
-}\r
-\r
-int\r
-inc_global_cidr_count(struct Client *client_p)\r
-{\r
-       struct rb_sockaddr_storage ip;\r
-       struct sockaddr *addr;\r
-       int bitlen;\r
-\r
-       if(!MyClient(client_p))\r
-       {\r
-               if(EmptyString(client_p->sockhost) || !strcmp(client_p->sockhost, "0"))\r
-                       return -1; \r
-               if(!rb_inet_pton_sock(client_p->sockhost, (struct sockaddr *)&ip))\r
-                       return -1;\r
-               addr = (struct sockaddr *)&ip;\r
-       } else\r
-               addr = (struct sockaddr *)&client_p->localClient->ip;\r
-#ifdef RB_IPV6 \r
-       if(GET_SS_FAMILY(addr) == AF_INET6)\r
-       {\r
-               bitlen = ConfigFileEntry.global_cidr_ipv6_bitlen;\r
-       } else\r
-#endif\r
-               bitlen = ConfigFileEntry.global_cidr_ipv4_bitlen;\r
-\r
-       return inc_global_ip(addr, bitlen);\r
-}\r
-\r
-void\r
-dec_global_cidr_count(struct Client *client_p)\r
-{\r
-       struct rb_sockaddr_storage ip;\r
-       struct sockaddr *addr;\r
-       if(!MyClient(client_p))\r
-       {\r
-               if(EmptyString(client_p->sockhost) || !strcmp(client_p->sockhost, "0"))\r
-                       return;\r
-               if(!rb_inet_pton_sock(client_p->sockhost, (struct sockaddr *)&ip))\r
-                       return;\r
-               addr = (struct sockaddr *)&ip;\r
-       } else\r
-               addr = (struct sockaddr *)&client_p->localClient->ip;\r
-       \r
-       dec_global_ip(addr);\r
-}\r
-\r
-int\r
-check_global_cidr_count(struct Client *client_p)\r
-{\r
-       struct rb_sockaddr_storage ip;\r
-       struct sockaddr *addr;\r
-       int count, max;\r
-       if(!MyClient(client_p))\r
-       {\r
-               if(EmptyString(client_p->sockhost) || !strcmp(client_p->sockhost, "0"))\r
-                       return -1;\r
-               if(!rb_inet_pton_sock(client_p->sockhost, (struct sockaddr *)&ip))\r
-                       return -1;\r
-               addr = (struct sockaddr *)&ip;\r
-       } else \r
-               addr = (struct sockaddr *)&client_p->localClient->ip;\r
-       count = get_global_count(addr);\r
-#ifdef RB_IPV6\r
-       if(GET_SS_FAMILY(addr) == AF_INET6)\r
-               max = ConfigFileEntry.global_cidr_ipv6_count;\r
-       else\r
-#endif\r
-               max = ConfigFileEntry.global_cidr_ipv4_count;\r
-       if(count >= max)\r
-               return 1;\r
-       return 0;\r
-}\r
-\r
-static void\r
-clear_cidr_tree(void *data)\r
-{\r
-       rb_free(data);  \r
-}\r
-\r
-void\r
-rehash_global_cidr_tree(void)\r
-{\r
-       struct Client *client_p;\r
-       rb_dlink_node *ptr;\r
-       rb_clear_patricia(global_tree, clear_cidr_tree);\r
-       RB_DLINK_FOREACH(ptr, global_client_list.head)\r
-       {\r
-               client_p = ptr->data;\r
-               if(IsMe(client_p) && IsServer(client_p))\r
-                       continue;\r
-               inc_global_cidr_count(client_p);        \r
-       }\r
-       return;\r
-}\r
+/*
+ *  ircd-ratbox: A slightly useful ircd
+ *  reject.c: reject users with prejudice
+ *
+ *  Copyright (C) 2003 Aaron Sethman <androsyn@ratbox.org>
+ *  Copyright (C) 2003-2005 ircd-ratbox development team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ *  USA
+ *
+ */
+
+#include "stdinc.h"
+#include "client.h"
+#include "s_conf.h"
+#include "reject.h"
+#include "s_stats.h"
+#include "ircd.h"
+#include "send.h"
+#include "numeric.h"
+#include "parse.h"
+#include "hostmask.h"
+#include "match.h"
+#include "hash.h"
+
+static rb_patricia_tree_t *reject_tree;
+static rb_dlink_list delay_exit;
+static rb_dlink_list reject_list;
+static rb_dlink_list throttle_list;
+static rb_patricia_tree_t *throttle_tree;
+static void throttle_expires(void *unused);
+
+
+typedef struct _reject_data
+{
+       rb_dlink_node rnode;
+       time_t time;
+       unsigned int count;
+       uint32_t mask_hashv;
+} reject_t;
+
+typedef struct _delay_data
+{
+       rb_dlink_node node;
+       rb_fde_t *F;
+} delay_t;
+
+typedef struct _throttle
+{
+       rb_dlink_node node;
+       time_t last;
+       int count;
+} throttle_t;
+
+unsigned long
+delay_exit_length(void)
+{
+       return rb_dlink_list_length(&delay_exit);
+}
+
+static void
+reject_exit(void *unused)
+{
+       rb_dlink_node *ptr, *ptr_next;
+       delay_t *ddata;
+       static const char *errbuf = "ERROR :Closing Link: (*** Banned (cache))\r\n";
+       
+       RB_DLINK_FOREACH_SAFE(ptr, ptr_next, delay_exit.head)
+       {
+               ddata = ptr->data;
+
+               rb_write(ddata->F, errbuf, strlen(errbuf));             
+               rb_close(ddata->F);
+               rb_free(ddata);
+       }
+
+       delay_exit.head = delay_exit.tail = NULL;
+       delay_exit.length = 0;
+}
+
+static void
+reject_expires(void *unused)
+{
+       rb_dlink_node *ptr, *next;
+       rb_patricia_node_t *pnode;
+       reject_t *rdata;
+       
+       RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
+       {
+               pnode = ptr->data;
+               rdata = pnode->data;            
+
+               if(rdata->time + ConfigFileEntry.reject_duration > rb_current_time())
+                       continue;
+
+               rb_dlinkDelete(ptr, &reject_list);
+               rb_free(rdata);
+               rb_patricia_remove(reject_tree, pnode);
+       }
+}
+
+void
+init_reject(void)
+{
+       reject_tree = rb_new_patricia(PATRICIA_BITS);
+       throttle_tree = rb_new_patricia(PATRICIA_BITS);
+       rb_event_add("reject_exit", reject_exit, NULL, DELAYED_EXIT_TIME);
+       rb_event_add("reject_expires", reject_expires, NULL, 60);
+       rb_event_add("throttle_expires", throttle_expires, NULL, 10);
+}
+
+unsigned long
+throttle_size(void)
+{
+       unsigned long count;
+       rb_dlink_node *ptr;
+       rb_patricia_node_t *pnode;
+       throttle_t *t;
+
+       count = 0;
+       RB_DLINK_FOREACH(ptr, throttle_list.head)
+       {
+               pnode = ptr->data;
+               t = pnode->data;
+               if (t->count > ConfigFileEntry.throttle_count)
+                       count++;
+       }
+
+       return count;
+}
+
+void
+add_reject(struct Client *client_p, const char *mask1, const char *mask2)
+{
+       rb_patricia_node_t *pnode;
+       reject_t *rdata;
+       uint32_t hashv;
+
+       /* Reject is disabled */
+       if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
+               return;
+
+       hashv = 0;
+       if (mask1 != NULL)
+               hashv ^= fnv_hash_upper((const unsigned char *)mask1, 32);
+       if (mask2 != NULL)
+               hashv ^= fnv_hash_upper((const unsigned char *)mask2, 32);
+
+       if((pnode = rb_match_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip)) != NULL)
+       {
+               rdata = pnode->data;
+               rdata->time = rb_current_time();
+               rdata->count++;
+       }
+       else
+       {
+               int bitlen = 32;
+#ifdef RB_IPV6
+               if(GET_SS_FAMILY(&client_p->localClient->ip) == AF_INET6)
+                       bitlen = 128;
+#endif
+               pnode = make_and_lookup_ip(reject_tree, (struct sockaddr *)&client_p->localClient->ip, bitlen);
+               pnode->data = rdata = rb_malloc(sizeof(reject_t));
+               rb_dlinkAddTail(pnode, &rdata->rnode, &reject_list);
+               rdata->time = rb_current_time();
+               rdata->count = 1;
+       }
+       rdata->mask_hashv = hashv;
+}
+
+int
+check_reject(rb_fde_t *F, struct sockaddr *addr)
+{
+       rb_patricia_node_t *pnode;
+       reject_t *rdata;
+       delay_t *ddata;
+       /* Reject is disabled */
+       if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
+               return 0;
+               
+       pnode = rb_match_ip(reject_tree, addr);
+       if(pnode != NULL)
+       {
+               rdata = pnode->data;
+
+               rdata->time = rb_current_time();
+               if(rdata->count > (unsigned long)ConfigFileEntry.reject_after_count)
+               {
+                       ddata = rb_malloc(sizeof(delay_t));
+                       ServerStats.is_rej++;
+                       rb_setselect(F, RB_SELECT_WRITE | RB_SELECT_READ, NULL, NULL);
+                       ddata->F = F;
+                       rb_dlinkAdd(ddata, &ddata->node, &delay_exit);
+                       return 1;
+               }
+       }       
+       /* Caller does what it wants */ 
+       return 0;
+}
+
+int
+is_reject_ip(struct sockaddr *addr)
+{
+       rb_patricia_node_t *pnode;
+       reject_t *rdata;
+       int duration;
+
+       /* Reject is disabled */
+       if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
+               return 0;
+               
+       pnode = rb_match_ip(reject_tree, addr);
+       if(pnode != NULL)
+       {
+               rdata = pnode->data;
+
+               if(rdata->count > (unsigned long)ConfigFileEntry.reject_after_count)
+               {
+                       duration = rdata->time + ConfigFileEntry.reject_duration - rb_current_time();
+                       return duration > 0 ? duration : 1;
+               }
+       }       
+       return 0;
+}
+
+void 
+flush_reject(void)
+{
+       rb_dlink_node *ptr, *next;
+       rb_patricia_node_t *pnode;
+       reject_t *rdata;
+       
+       RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
+       {
+               pnode = ptr->data;
+               rdata = pnode->data;
+               rb_dlinkDelete(ptr, &reject_list);
+               rb_free(rdata);
+               rb_patricia_remove(reject_tree, pnode);
+       }
+}
+
+int 
+remove_reject_ip(const char *ip)
+{
+       rb_patricia_node_t *pnode;
+       
+       /* Reject is disabled */
+       if(ConfigFileEntry.reject_after_count == 0 || ConfigFileEntry.reject_duration == 0)
+               return -1;
+
+       if((pnode = rb_match_string(reject_tree, ip)) != NULL)
+       {
+               reject_t *rdata = pnode->data;
+               rb_dlinkDelete(&rdata->rnode, &reject_list);
+               rb_free(rdata);
+               rb_patricia_remove(reject_tree, pnode);
+               return 1;
+       }
+       return 0;
+}
+
+int
+remove_reject_mask(const char *mask1, const char *mask2)
+{
+       rb_dlink_node *ptr, *next;
+       rb_patricia_node_t *pnode;
+       reject_t *rdata;
+       uint32_t hashv;
+       int n = 0;
+       
+       hashv = 0;
+       if (mask1 != NULL)
+               hashv ^= fnv_hash_upper((const unsigned char *)mask1, 32);
+       if (mask2 != NULL)
+               hashv ^= fnv_hash_upper((const unsigned char *)mask2, 32);
+       RB_DLINK_FOREACH_SAFE(ptr, next, reject_list.head)
+       {
+               pnode = ptr->data;
+               rdata = pnode->data;
+               if (rdata->mask_hashv == hashv)
+               {
+                       rb_dlinkDelete(ptr, &reject_list);
+                       rb_free(rdata);
+                       rb_patricia_remove(reject_tree, pnode);
+                       n++;
+               }
+       }
+       return n;
+}
+
+int
+throttle_add(struct sockaddr *addr)
+{
+       throttle_t *t;
+       rb_patricia_node_t *pnode;
+
+       if((pnode = rb_match_ip(throttle_tree, addr)) != NULL)
+       {
+               t = pnode->data;
+
+               if(t->count > ConfigFileEntry.throttle_count)
+               {
+                       ServerStats.is_thr++;
+                       return 1;
+               }
+               /* Stop penalizing them after they've been throttled */
+               t->last = rb_current_time();
+               t->count++;
+
+       } else {
+               int bitlen = 32;
+#ifdef RB_IPV6
+               if(GET_SS_FAMILY(addr) == AF_INET6)
+                       bitlen = 128;
+#endif
+               t = rb_malloc(sizeof(throttle_t));      
+               t->last = rb_current_time();
+               t->count = 1;
+               pnode = make_and_lookup_ip(throttle_tree, addr, bitlen);
+               pnode->data = t;
+               rb_dlinkAdd(pnode, &t->node, &throttle_list); 
+       }       
+       return 0;
+}
+
+int
+is_throttle_ip(struct sockaddr *addr)
+{
+       throttle_t *t;
+       rb_patricia_node_t *pnode;
+       int duration;
+
+       if((pnode = rb_match_ip(throttle_tree, addr)) != NULL)
+       {
+               t = pnode->data;
+               if(t->count > ConfigFileEntry.throttle_count)
+               {
+                       duration = t->last + ConfigFileEntry.throttle_duration - rb_current_time();
+                       return duration > 0 ? duration : 1;
+               }
+       }
+       return 0;
+}
+
+void 
+flush_throttle(void)
+{
+       rb_dlink_node *ptr, *next;
+       rb_patricia_node_t *pnode;
+       throttle_t *t;
+       
+       RB_DLINK_FOREACH_SAFE(ptr, next, throttle_list.head)
+       {
+               pnode = ptr->data;
+               t = pnode->data;                
+
+               rb_dlinkDelete(ptr, &throttle_list);
+               rb_free(t);
+               rb_patricia_remove(throttle_tree, pnode);
+       }
+}
+
+static void
+throttle_expires(void *unused)
+{
+       rb_dlink_node *ptr, *next;
+       rb_patricia_node_t *pnode;
+       throttle_t *t;
+       
+       RB_DLINK_FOREACH_SAFE(ptr, next, throttle_list.head)
+       {
+               pnode = ptr->data;
+               t = pnode->data;                
+
+               if(t->last + ConfigFileEntry.throttle_duration > rb_current_time())
+                       continue;
+
+               rb_dlinkDelete(ptr, &throttle_list);
+               rb_free(t);
+               rb_patricia_remove(throttle_tree, pnode);
+       }
+}
+