Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/VibeDevelopers/Comet.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478/* * 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; struct ConfItem *aconf; const char *reason; time_t time; unsigned int count; uint32_t mask_hashv;} reject_t;
typedef struct _delay_data{ rb_dlink_node node; rb_fde_t *F; struct ConfItem *aconf; const char *reason; bool ssl;} delay_t;
typedef struct _throttle{ rb_dlink_node node; time_t last; int count;} throttle_t;
unsigned longdelay_exit_length(void){ return rb_dlink_list_length(&delay_exit);}
static voidreject_free(reject_t *rdata){ struct ConfItem *aconf = rdata->aconf;
if (aconf) deref_conf(aconf);
rb_free(rdata);}
static voidreject_exit(void *unused){ static char dynamic_reason[BUFSIZE]; rb_dlink_node *ptr, *ptr_next; delay_t *ddata; static const char *errbuf = "ERROR :Closing Link: (*** Banned (cache))\r\n";
static const unsigned char ssldeniederrcode[] = { // SSLv3.0 Fatal Alert: Access Denied 0x15, 0x03, 0x00, 0x00, 0x02, 0x02, 0x31 };
RB_DLINK_FOREACH_SAFE(ptr, ptr_next, delay_exit.head) { ddata = ptr->data;
if (ddata->ssl) { rb_write(ddata->F, ssldeniederrcode, sizeof(ssldeniederrcode)); } else { *dynamic_reason = '\0';
if (ddata->aconf) snprintf(dynamic_reason, sizeof dynamic_reason, form_str(ERR_YOUREBANNEDCREEP) "\r\n", me.name, "*", get_user_ban_reason(ddata->aconf)); else if (ddata->reason) snprintf(dynamic_reason, sizeof dynamic_reason, ":%s 465 %s :%s\r\n", me.name, "*", ddata->reason);
if (*dynamic_reason) rb_write(ddata->F, dynamic_reason, strlen(dynamic_reason));
rb_write(ddata->F, errbuf, strlen(errbuf)); }
if (ddata->aconf) deref_conf(ddata->aconf);
rb_close(ddata->F); rb_free(ddata); }
delay_exit.head = delay_exit.tail = NULL; delay_exit.length = 0;}
static voidreject_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); reject_free(rdata); rb_patricia_remove(reject_tree, pnode); }}
voidinit_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 longthrottle_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;}
voidadd_reject(struct Client *client_p, const char *mask1, const char *mask2, struct ConfItem *aconf, const char *reason){ 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; if(GET_SS_FAMILY(&client_p->localClient->ip) == AF_INET6) bitlen = 128; 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->aconf = NULL; rdata->reason = NULL; } rdata->mask_hashv = hashv;
if (aconf != NULL && aconf != rdata->aconf && (aconf->status & CONF_KILL) && aconf->passwd) { if (rdata->aconf != NULL) deref_conf(rdata->aconf); aconf->clients++; rdata->aconf = aconf; } else if (reason != NULL) { if (rdata->aconf != NULL) deref_conf(rdata->aconf); rdata->aconf = NULL; rdata->reason = reason; }}
intcheck_reject(rb_fde_t *F, struct sockaddr *addr, bool ssl){ 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) return 0;
rdata = pnode->data; rdata->time = rb_current_time();
if (rdata->count <= (unsigned long)ConfigFileEntry.reject_after_count) return 0;
if (rdata->aconf != NULL && rdata->aconf->status & CONF_ILLEGAL) { rb_dlinkDelete(&rdata->rnode, &reject_list); reject_free(rdata); rb_patricia_remove(reject_tree, pnode); return 0; }
ddata = rb_malloc(sizeof(delay_t)); ServerStats.is_rej++; rb_setselect(F, RB_SELECT_WRITE | RB_SELECT_READ, NULL, NULL); if (rdata->aconf) { ddata->aconf = rdata->aconf; ddata->aconf->clients++; ddata->reason = NULL; } else if (rdata->reason) { ddata->reason = rdata->reason; ddata->aconf = NULL; } else { ddata->aconf = NULL; ddata->reason = NULL; } ddata->F = F; ddata->ssl = ssl; rb_dlinkAdd(ddata, &ddata->node, &delay_exit); return 1;}
intis_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;}
voidflush_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); reject_free(rdata); rb_patricia_remove(reject_tree, pnode); }}
intremove_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); reject_free(rdata); rb_patricia_remove(reject_tree, pnode); return 1; } return 0;}
intremove_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); reject_free(rdata); rb_patricia_remove(reject_tree, pnode); n++; } } return n;}
intthrottle_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; if(GET_SS_FAMILY(addr) == AF_INET6) bitlen = 128; 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;}
intis_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;}
voidflush_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 voidthrottle_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); }}