-/*\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 "struct.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
-#include "match.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
+ *
+ * $Id: reject.c 25119 2008-03-13 16:57:05Z androsyn $
+ */
+
+#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;
+}
+
+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);
+ }
+}
+