diff --git a/include/h.h b/include/h.h index 4a2a1f5ce..020643ffd 100644 --- a/include/h.h +++ b/include/h.h @@ -369,6 +369,7 @@ extern time_t expire_cache(time_t); extern void del_queries(char *); extern uint64_t siphash(const char *in, const char *k); +extern uint64_t siphash_raw(const char *in, size_t len, const char *k); extern uint64_t siphash_nocase(const char *in, const char *k); extern void siphash_generate_key(char *k); extern void init_hash(void); @@ -390,6 +391,7 @@ extern aClient *hash_find_client(const char *, aClient *); extern aClient *hash_find_id(const char *, aClient *); extern aClient *hash_find_nickatserver(const char *, aClient *); extern aClient *hash_find_server(const char *, aClient *); +extern struct MODVAR ThrottlingBucket *ThrottlingHash[THROTTLING_HASH_TABLE_SIZE]; extern char *find_by_aln(char *); extern char *convert2aln(int); extern int convertfromaln(char *); diff --git a/include/hash.h b/include/hash.h index b58a07d6e..0d43a99f3 100644 --- a/include/hash.h +++ b/include/hash.h @@ -26,6 +26,7 @@ #define CHAN_HASH_TABLE_SIZE 32768 #define WATCH_HASH_TABLE_SIZE 32768 #define WHOWAS_HASH_TABLE_SIZE 32768 +#define THROTTLING_HASH_TABLE_SIZE 8192 typedef struct hashentry { int hits; @@ -33,11 +34,6 @@ typedef struct hashentry { void *list; } aHashEntry; -/* - * Throttling -*/ -#define THROTTLING_HASH_SIZE 1019 /* prime number */ - #define NullChn ((aChannel *)0) #define find_channel hash_find_channel diff --git a/include/struct.h b/include/struct.h index 69425e737..6022a295a 100644 --- a/include/struct.h +++ b/include/struct.h @@ -1852,10 +1852,10 @@ struct PendingNet { aPendingServer *servers; /**< The list of servers connected to the client */ }; -void init_throttling_hash(); -struct ThrottlingBucket *find_throttling_bucket(aClient *); -void add_throttling_bucket(aClient *); -int throttle_can_connect(aClient *); +extern void init_throttling(); +extern struct ThrottlingBucket *find_throttling_bucket(aClient *); +extern void add_throttling_bucket(aClient *); +extern int throttle_can_connect(aClient *); typedef struct _maxtargets MaxTarget; struct _maxtargets { diff --git a/src/hash.c b/src/hash.c index 0c54e3b85..f837e84c9 100644 --- a/src/hash.c +++ b/src/hash.c @@ -19,7 +19,7 @@ #include "unrealircd.h" -/* Next #define's, the siphash() and siphash_nocase() functions are based +/* Next #define's, the siphash_raw() and siphash_nocase() functions are based * on the SipHash reference C implementation to which the following applies: * Copyright (c) 2012-2016 Jean-Philippe Aumasson * @@ -86,19 +86,23 @@ v2 = ROTL(v2, 32); \ } while (0) -/** Generic hash function in UnrealIRCd. - * @param str The string to hash (NUL-terminated) +/** Generic hash function in UnrealIRCd - raw version. + * Note that you probably want siphash() or siphash_nocase() instead. + * @param in The data to hash + * @param inlen The length of the data * @param k The key to use for hashing (16 bytes, not NUL terminated) * @returns Hash result as a 64 bit unsigned integer. * @notes The key (k) should be random and must stay the same for * as long as you use the function for your specific hash table. * Simply use the following on boot: siphash_generate_key(k); + * + * This siphash_raw() version is meant for non-strings, + * such as raw IP address structs and such. */ -uint64_t siphash(const char *in, const char *k) +uint64_t siphash_raw(const char *in, size_t inlen, const char *k) { uint64_t hash; char *out = (char*) &hash; - size_t inlen = strlen(in); uint64_t v0 = 0x736f6d6570736575ULL; uint64_t v1 = 0x646f72616e646f6dULL; uint64_t v2 = 0x6c7967656e657261ULL; @@ -224,6 +228,22 @@ uint64_t siphash_nocase(const char *in, const char *k) return hash; } +/* End of imported code */ + +/** Generic hash function in UnrealIRCd. + * @param str The string to hash (NUL-terminated) + * @param k The key to use for hashing (16 bytes, not NUL terminated) + * @returns Hash result as a 64 bit unsigned integer. + * @notes The key (k) should be random and must stay the same for + * as long as you use the function for your specific hash table. + * Simply use the following on boot: siphash_generate_key(k); + */ +uint64_t siphash(const char *in, const char *k) +{ + size_t inlen = strlen(in); + + return siphash_raw(in, inlen, k); +} /** Generate a key that is used by siphash() and siphash_nocase(). * @param k The key, this must be a char array of size 16. */ @@ -243,6 +263,7 @@ static char siphashkey_nick[16]; static char siphashkey_chan[16]; static char siphashkey_watch[16]; static char siphashkey_whowas[16]; +static char siphashkey_throttling[16]; extern char unreallogo[]; @@ -255,6 +276,7 @@ void init_hash(void) siphash_generate_key(siphashkey_chan); siphash_generate_key(siphashkey_watch); siphash_generate_key(siphashkey_whowas); + siphash_generate_key(siphashkey_throttling); for (i = 0; i < NICK_HASH_TABLE_SIZE; i++) INIT_LIST_HEAD(&clientTable[i]); @@ -265,6 +287,12 @@ void init_hash(void) memset(channelTable, 0, sizeof(channelTable)); memset(watchTable, 0, sizeof(watchTable)); + bzero(ThrottlingHash, sizeof(ThrottlingHash)); + /* do not call init_throttling() here, as + * config file has not been read yet. + * The hash table is ready, anyway. + */ + if (strcmp(BASE_VERSION, &unreallogo[337])) loop.tainted = 1; } @@ -861,20 +889,20 @@ int hash_del_watch_list(aClient *cptr) return 0; } -/* - * Throttling - * -by Stskeeps -*/ +/* Throttling - originally by Stskeeps */ -struct MODVAR ThrottlingBucket *ThrottlingHash[THROTTLING_HASH_SIZE+1]; +/* Note that we call this set::anti-flood::connect-flood nowadays */ -void init_throttling_hash() +struct MODVAR ThrottlingBucket *ThrottlingHash[THROTTLING_HASH_TABLE_SIZE]; + +void init_throttling() { -long v; - bzero(ThrottlingHash, sizeof(ThrottlingHash)); + long v; + if (!THROTTLING_PERIOD) + { v = 120; - else + } else { v = THROTTLING_PERIOD/2; if (v > 5) @@ -883,12 +911,12 @@ long v; EventAdd(NULL, "bucketcleaning", v, 0, e_clean_out_throttling_buckets, NULL); } -int hash_throttling(char *ip) +u_int64_t hash_throttling(char *ip) { - return hash_client_name(ip) %THROTTLING_HASH_SIZE; // TODO: improve/fix ;) + return siphash(ip, siphashkey_throttling) % THROTTLING_HASH_TABLE_SIZE; } -struct ThrottlingBucket *find_throttling_bucket(aClient *acptr) +struct ThrottlingBucket *find_throttling_bucket(aClient *acptr) { int hash = 0; struct ThrottlingBucket *p; @@ -909,7 +937,7 @@ EVENT(e_clean_out_throttling_buckets) int i; static time_t t = 0; - for (i = 0; i < THROTTLING_HASH_SIZE; i++) + for (i = 0; i < THROTTLING_HASH_TABLE_SIZE; i++) { for (n = ThrottlingHash[i]; n; n = n_next) { @@ -952,9 +980,9 @@ EVENT(e_clean_out_throttling_buckets) void add_throttling_bucket(aClient *acptr) { - int hash; - struct ThrottlingBucket *n; - + int hash; + struct ThrottlingBucket *n; + n = MyMallocEx(sizeof(struct ThrottlingBucket)); n->next = n->prev = NULL; n->ip = strdup(acptr->ip); @@ -965,13 +993,13 @@ void add_throttling_bucket(aClient *acptr) return; } -/** Checks wether the user is connect-flooding. +/** Checks whether the user is connect-flooding. * @retval 0 Denied, throttled. * @retval 1 Allowed, but known in the list. * @retval 2 Allowed, not in list or is an exception. * @see add_connection() */ -int throttle_can_connect(aClient *sptr) +int throttle_can_connect(aClient *sptr) { struct ThrottlingBucket *b; diff --git a/src/ircd.c b/src/ircd.c index b48909361..44ad63e62 100644 --- a/src/ircd.c +++ b/src/ircd.c @@ -743,7 +743,6 @@ static void do_version_check() extern void applymeblock(void); extern MODVAR Event *events; -extern struct MODVAR ThrottlingBucket *ThrottlingHash[THROTTLING_HASH_SIZE+1]; /** This functions resets a couple of timers and does other things that * are absolutely cruicial when the clock is adjusted - particularly @@ -815,7 +814,7 @@ void fix_timers(void) * sonner than we should. */ cnt = 0; - for (i = 0; i < THROTTLING_HASH_SIZE; i++) + for (i = 0; i < THROTTLING_HASH_TABLE_SIZE; i++) { for (thr = ThrottlingHash[i]; thr; thr = thr->next) { @@ -1383,7 +1382,7 @@ int InitUnrealIRCd(int argc, char *argv[]) fix_timers(); write_pidfile(); Debug((DEBUG_NOTICE, "Server ready...")); - init_throttling_hash(); + init_throttling(); loop.ircd_booted = 1; #if defined(HAVE_SETPROCTITLE) setproctitle("%s", me.name);