unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
hash.c (21556B)
1 /************************************************************************ 2 * Unreal Internet Relay Chat Daemon, src/hash.c 3 * Copyright (C) 1991 Darren Reed 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 1, or (at your option) 8 * any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 */ 19 20 #include "unrealircd.h" 21 22 /* Next #define's, the siphash_raw() and siphash_nocase() functions are based 23 * on the SipHash reference C implementation to which the following applies: 24 * Copyright (c) 2012-2016 Jean-Philippe Aumasson 25 * <jeanphilippe.aumasson@gmail.com> 26 * Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to> 27 * Further enhancements were made by: 28 * Copyright (c) 2017 Salvatore Sanfilippo <antirez@gmail.com> 29 * To the extent possible under law, the author(s) have dedicated all copyright 30 * and related and neighboring rights to this software to the public domain 31 * worldwide. This software is distributed without any warranty. 32 * You should have received a copy of the CC0 Public Domain Dedication along 33 * with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. 34 * 35 * In addition to above, Bram Matthys (Syzop), did some minor enhancements, 36 * such as dropping the uint8_t stuff (in UnrealIRCd char is always unsigned) 37 * and getting rid of the length argument. 38 * 39 * The end result are simple functions for API end-users and we encourage 40 * everyone to use these two hash functions everywhere in UnrealIRCd. 41 */ 42 43 #define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) 44 45 #define U32TO8_LE(p, v) \ 46 (p)[0] = (char)((v)); \ 47 (p)[1] = (char)((v) >> 8); \ 48 (p)[2] = (char)((v) >> 16); \ 49 (p)[3] = (char)((v) >> 24); 50 51 #define U64TO8_LE(p, v) \ 52 U32TO8_LE((p), (uint32_t)((v))); \ 53 U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); 54 55 #define U8TO64_LE(p) \ 56 (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \ 57 ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \ 58 ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \ 59 ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) 60 61 #define U8TO64_LE_NOCASE(p) \ 62 (((uint64_t)(tolower((p)[0]))) | \ 63 ((uint64_t)(tolower((p)[1])) << 8) | \ 64 ((uint64_t)(tolower((p)[2])) << 16) | \ 65 ((uint64_t)(tolower((p)[3])) << 24) | \ 66 ((uint64_t)(tolower((p)[4])) << 32) | \ 67 ((uint64_t)(tolower((p)[5])) << 40) | \ 68 ((uint64_t)(tolower((p)[6])) << 48) | \ 69 ((uint64_t)(tolower((p)[7])) << 56)) 70 71 #define SIPROUND \ 72 do { \ 73 v0 += v1; \ 74 v1 = ROTL(v1, 13); \ 75 v1 ^= v0; \ 76 v0 = ROTL(v0, 32); \ 77 v2 += v3; \ 78 v3 = ROTL(v3, 16); \ 79 v3 ^= v2; \ 80 v0 += v3; \ 81 v3 = ROTL(v3, 21); \ 82 v3 ^= v0; \ 83 v2 += v1; \ 84 v1 = ROTL(v1, 17); \ 85 v1 ^= v2; \ 86 v2 = ROTL(v2, 32); \ 87 } while (0) 88 89 /** Generic hash function in UnrealIRCd - raw version. 90 * Note that you probably want siphash() or siphash_nocase() instead. 91 * @param in The data to hash 92 * @param inlen The length of the data 93 * @param k The key to use for hashing (SIPHASH_KEY_LENGTH bytes, 94 * which is actually 16, not NUL terminated) 95 * @returns Hash result as a 64 bit unsigned integer. 96 * @note The key (k) should be random and must stay the same for 97 * as long as you use the function for your specific hash table. 98 * Simply use the following on boot: siphash_generate_key(k); 99 * 100 * This siphash_raw() version is meant for non-strings, 101 * such as raw IP address structs and such. 102 */ 103 uint64_t siphash_raw(const char *in, size_t inlen, const char *k) 104 { 105 uint64_t hash; 106 char *out = (char*) &hash; 107 uint64_t v0 = 0x736f6d6570736575ULL; 108 uint64_t v1 = 0x646f72616e646f6dULL; 109 uint64_t v2 = 0x6c7967656e657261ULL; 110 uint64_t v3 = 0x7465646279746573ULL; 111 uint64_t k0 = U8TO64_LE(k); 112 uint64_t k1 = U8TO64_LE(k + 8); 113 uint64_t m; 114 const char *end = in + inlen - (inlen % sizeof(uint64_t)); 115 const int left = inlen & 7; 116 uint64_t b = ((uint64_t)inlen) << 56; 117 v3 ^= k1; 118 v2 ^= k0; 119 v1 ^= k1; 120 v0 ^= k0; 121 122 for (; in != end; in += 8) { 123 m = U8TO64_LE(in); 124 v3 ^= m; 125 126 SIPROUND; 127 SIPROUND; 128 129 v0 ^= m; 130 } 131 132 switch (left) { 133 case 7: b |= ((uint64_t)in[6]) << 48; /* fallthrough */ 134 case 6: b |= ((uint64_t)in[5]) << 40; /* fallthrough */ 135 case 5: b |= ((uint64_t)in[4]) << 32; /* fallthrough */ 136 case 4: b |= ((uint64_t)in[3]) << 24; /* fallthrough */ 137 case 3: b |= ((uint64_t)in[2]) << 16; /* fallthrough */ 138 case 2: b |= ((uint64_t)in[1]) << 8; /* fallthrough */ 139 case 1: b |= ((uint64_t)in[0]); break; 140 case 0: break; 141 } 142 143 v3 ^= b; 144 145 SIPROUND; 146 SIPROUND; 147 148 v0 ^= b; 149 v2 ^= 0xff; 150 151 SIPROUND; 152 SIPROUND; 153 SIPROUND; 154 SIPROUND; 155 156 b = v0 ^ v1 ^ v2 ^ v3; 157 U64TO8_LE(out, b); 158 159 return hash; 160 } 161 162 /** Generic hash function in UnrealIRCd - case insensitive. 163 * This deals with IRC case-insensitive matches, which is 164 * what you need for things like nicks and channels. 165 * @param str The string to hash (NUL-terminated) 166 * @param k The key to use for hashing (SIPHASH_KEY_LENGTH bytes, 167 * which is actually 16, not NUL terminated) 168 * @returns Hash result as a 64 bit unsigned integer. 169 * @note The key (k) should be random and must stay the same for 170 * as long as you use the function for your specific hash table. 171 * Simply use the following on boot: siphash_generate_key(k); 172 */ 173 uint64_t siphash_nocase(const char *in, const char *k) 174 { 175 uint64_t hash; 176 char *out = (char*) &hash; 177 size_t inlen = strlen(in); 178 uint64_t v0 = 0x736f6d6570736575ULL; 179 uint64_t v1 = 0x646f72616e646f6dULL; 180 uint64_t v2 = 0x6c7967656e657261ULL; 181 uint64_t v3 = 0x7465646279746573ULL; 182 uint64_t k0 = U8TO64_LE(k); 183 uint64_t k1 = U8TO64_LE(k + 8); 184 uint64_t m; 185 const char *end = in + inlen - (inlen % sizeof(uint64_t)); 186 const int left = inlen & 7; 187 uint64_t b = ((uint64_t)inlen) << 56; 188 v3 ^= k1; 189 v2 ^= k0; 190 v1 ^= k1; 191 v0 ^= k0; 192 193 for (; in != end; in += 8) { 194 m = U8TO64_LE_NOCASE(in); 195 v3 ^= m; 196 197 SIPROUND; 198 SIPROUND; 199 200 v0 ^= m; 201 } 202 203 switch (left) { 204 case 7: b |= ((uint64_t)tolower(in[6])) << 48; /* fallthrough */ 205 case 6: b |= ((uint64_t)tolower(in[5])) << 40; /* fallthrough */ 206 case 5: b |= ((uint64_t)tolower(in[4])) << 32; /* fallthrough */ 207 case 4: b |= ((uint64_t)tolower(in[3])) << 24; /* fallthrough */ 208 case 3: b |= ((uint64_t)tolower(in[2])) << 16; /* fallthrough */ 209 case 2: b |= ((uint64_t)tolower(in[1])) << 8; /* fallthrough */ 210 case 1: b |= ((uint64_t)tolower(in[0])); break; 211 case 0: break; 212 } 213 214 v3 ^= b; 215 216 SIPROUND; 217 SIPROUND; 218 219 v0 ^= b; 220 v2 ^= 0xff; 221 222 SIPROUND; 223 SIPROUND; 224 SIPROUND; 225 SIPROUND; 226 227 b = v0 ^ v1 ^ v2 ^ v3; 228 U64TO8_LE(out, b); 229 230 return hash; 231 } 232 233 /* End of imported code */ 234 235 /** Generic hash function in UnrealIRCd. 236 * @param str The string to hash (NUL-terminated) 237 * @param k The key to use for hashing (SIPHASH_KEY_LENGTH bytes, 238 * which is actually 16, not NUL terminated) 239 * @returns Hash result as a 64 bit unsigned integer. 240 * @note The key (k) should be random and must stay the same for 241 * as long as you use the function for your specific hash table. 242 * Simply use the following on boot: siphash_generate_key(k); 243 */ 244 uint64_t siphash(const char *in, const char *k) 245 { 246 size_t inlen = strlen(in); 247 248 return siphash_raw(in, inlen, k); 249 } 250 /** Generate a key that is used by siphash() and siphash_nocase(). 251 * @param k The key, this must be a char array of size 16. 252 */ 253 void siphash_generate_key(char *k) 254 { 255 int i; 256 for (i = 0; i < 16; i++) 257 k[i] = getrandom8(); 258 } 259 260 static struct list_head clientTable[NICK_HASH_TABLE_SIZE]; 261 static struct list_head idTable[NICK_HASH_TABLE_SIZE]; 262 static Channel *channelTable[CHAN_HASH_TABLE_SIZE]; 263 264 static char siphashkey_nick[SIPHASH_KEY_LENGTH]; 265 static char siphashkey_chan[SIPHASH_KEY_LENGTH]; 266 static char siphashkey_whowas[SIPHASH_KEY_LENGTH]; 267 static char siphashkey_throttling[SIPHASH_KEY_LENGTH]; 268 269 extern char unreallogo[]; 270 271 /** Initialize all hash tables */ 272 void init_hash(void) 273 { 274 int i; 275 276 siphash_generate_key(siphashkey_nick); 277 siphash_generate_key(siphashkey_chan); 278 siphash_generate_key(siphashkey_whowas); 279 siphash_generate_key(siphashkey_throttling); 280 281 for (i = 0; i < NICK_HASH_TABLE_SIZE; i++) 282 INIT_LIST_HEAD(&clientTable[i]); 283 284 for (i = 0; i < NICK_HASH_TABLE_SIZE; i++) 285 INIT_LIST_HEAD(&idTable[i]); 286 287 memset(channelTable, 0, sizeof(channelTable)); 288 289 memset(ThrottlingHash, 0, sizeof(ThrottlingHash)); 290 /* do not call init_throttling() here, as 291 * config file has not been read yet. 292 * The hash table is ready, anyway. 293 */ 294 295 if (strcmp(BASE_VERSION, &unreallogo[337])) 296 loop.tainted = 1; 297 } 298 299 uint64_t hash_client_name(const char *name) 300 { 301 return siphash_nocase(name, siphashkey_nick) % NICK_HASH_TABLE_SIZE; 302 } 303 304 uint64_t hash_channel_name(const char *name) 305 { 306 return siphash_nocase(name, siphashkey_chan) % CHAN_HASH_TABLE_SIZE; 307 } 308 309 uint64_t hash_whowas_name(const char *name) 310 { 311 return siphash_nocase(name, siphashkey_whowas) % WHOWAS_HASH_TABLE_SIZE; 312 } 313 314 /* 315 * add_to_client_hash_table 316 */ 317 int add_to_client_hash_table(const char *name, Client *client) 318 { 319 unsigned int hashv; 320 /* 321 * If you see this, you have probably found your way to why changing the 322 * base version made the IRCd become weird. This has been the case in all 323 * UnrealIRCd versions since 3.0. I'm sick of people ripping the IRCd off and 324 * just slapping on some random <theirnet> BASE_VERSION while not changing 325 * a single bit of code. YOU DID NOT WRITE ALL OF THIS THEREFORE YOU DO NOT 326 * DESERVE TO BE ABLE TO DO THAT. If you found this however, I'm OK with you 327 * removing the checks. However, keep in mind that the copyright headers must 328 * stay in place, which means no wiping of /credits and /info. We haven't 329 * sat up late at night so some lamer could steal all our work without even 330 * giving us credit. Remember to follow all regulations in LICENSE. 331 * -Stskeeps 332 */ 333 if (loop.tainted) 334 return 0; 335 hashv = hash_client_name(name); 336 list_add(&client->client_hash, &clientTable[hashv]); 337 return 0; 338 } 339 340 /* 341 * add_to_client_hash_table 342 */ 343 int add_to_id_hash_table(const char *name, Client *client) 344 { 345 unsigned int hashv; 346 hashv = hash_client_name(name); 347 list_add(&client->id_hash, &idTable[hashv]); 348 return 0; 349 } 350 351 /* 352 * add_to_channel_hash_table 353 */ 354 int add_to_channel_hash_table(const char *name, Channel *channel) 355 { 356 unsigned int hashv; 357 358 hashv = hash_channel_name(name); 359 channel->hnextch = channelTable[hashv]; 360 channelTable[hashv] = channel; 361 return 0; 362 } 363 /* 364 * del_from_client_hash_table 365 */ 366 int del_from_client_hash_table(const char *name, Client *client) 367 { 368 if (!list_empty(&client->client_hash)) 369 list_del(&client->client_hash); 370 371 INIT_LIST_HEAD(&client->client_hash); 372 373 return 0; 374 } 375 376 int del_from_id_hash_table(const char *name, Client *client) 377 { 378 if (!list_empty(&client->id_hash)) 379 list_del(&client->id_hash); 380 381 INIT_LIST_HEAD(&client->id_hash); 382 383 return 0; 384 } 385 386 /* 387 * del_from_channel_hash_table 388 */ 389 void del_from_channel_hash_table(const char *name, Channel *channel) 390 { 391 Channel *tmp, *prev = NULL; 392 unsigned int hashv; 393 394 hashv = hash_channel_name(name); 395 for (tmp = channelTable[hashv]; tmp; tmp = tmp->hnextch) 396 { 397 if (tmp == channel) 398 { 399 if (prev) 400 prev->hnextch = tmp->hnextch; 401 else 402 channelTable[hashv] = tmp->hnextch; 403 tmp->hnextch = NULL; 404 return; /* DONE */ 405 } 406 prev = tmp; 407 } 408 return; /* NOTFOUND */ 409 } 410 411 /* 412 * hash_find_client 413 */ 414 Client *hash_find_client(const char *name, Client *client) 415 { 416 Client *tmp; 417 unsigned int hashv; 418 419 hashv = hash_client_name(name); 420 list_for_each_entry(tmp, &clientTable[hashv], client_hash) 421 { 422 if (smycmp(name, tmp->name) == 0) 423 return tmp; 424 } 425 426 return client; 427 } 428 429 Client *hash_find_id(const char *name, Client *client) 430 { 431 Client *tmp; 432 unsigned int hashv; 433 434 hashv = hash_client_name(name); 435 list_for_each_entry(tmp, &idTable[hashv], id_hash) 436 { 437 if (smycmp(name, tmp->id) == 0) 438 return tmp; 439 } 440 441 return client; 442 } 443 444 /* 445 * hash_find_nickatserver 446 */ 447 Client *hash_find_nickatserver(const char *str, Client *def) 448 { 449 char *serv; 450 char nick[NICKLEN+HOSTLEN+1]; 451 Client *client; 452 453 strlcpy(nick, str, sizeof(nick)); /* let's work on a copy */ 454 455 serv = strchr(nick, '@'); 456 if (serv) 457 *serv++ = '\0'; 458 459 client = find_user(nick, NULL); 460 if (!client) 461 return NULL; /* client not found */ 462 463 if (!serv) 464 return client; /* validated: was just 'nick' and not 'nick@serv' */ 465 466 /* Now validate the server portion */ 467 if (client->user && !smycmp(serv, client->user->server)) 468 return client; /* validated */ 469 470 return def; 471 } 472 /* 473 * hash_find_server 474 */ 475 Client *hash_find_server(const char *server, Client *def) 476 { 477 Client *tmp; 478 unsigned int hashv; 479 480 hashv = hash_client_name(server); 481 list_for_each_entry(tmp, &clientTable[hashv], client_hash) 482 { 483 if (!IsServer(tmp) && !IsMe(tmp)) 484 continue; 485 if (smycmp(server, tmp->name) == 0) 486 { 487 return tmp; 488 } 489 } 490 491 return def; 492 } 493 494 /** Find a client, user (person), server or channel by name. 495 * If you are looking for "other find functions", then the alphabetical index of functions 496 * at 'f' is your best bet: https://www.unrealircd.org/api/5/globals_func_f.html#index_f 497 * @defgroup FindFunctions Find functions 498 * @{ 499 */ 500 501 /** Find a client by name. 502 * This searches in the list of all types of clients, user/person, servers or an unregistered clients. 503 * If you know what type of client to search for, then use find_server() or find_user() instead! 504 * @param name The name to search for (eg: "nick" or "irc.example.net") 505 * @param requester The client that is searching for this name 506 * @note If 'requester' is a server or NULL, then we also check 507 * the ID table, otherwise not. 508 * @returns If the client is found then the Client is returned, otherwise NULL. 509 */ 510 Client *find_client(const char *name, Client *requester) 511 { 512 if (requester == NULL || IsServer(requester)) 513 { 514 Client *client; 515 516 if ((client = hash_find_id(name, NULL)) != NULL) 517 return client; 518 } 519 520 return hash_find_client(name, NULL); 521 } 522 523 /** Find a server by name. 524 * @param name The server name to search for (eg: 'irc.example.net' 525 * or '001') 526 * @param requester The client searching for the name. 527 * @note If 'requester' is a server or NULL, then we also check 528 * the ID table, otherwise not. 529 * @returns If the server is found then the Client is returned, otherwise NULL. 530 */ 531 Client *find_server(const char *name, Client *requester) 532 { 533 if (name) 534 { 535 Client *client; 536 537 if ((client = find_client(name, NULL)) != NULL && (IsServer(client) || IsMe(client))) 538 return client; 539 } 540 541 return NULL; 542 } 543 544 /** Find a user (a person) 545 * @param name The name to search for (eg: "nick" or "001ABCDEFG") 546 * @param requester The client that is searching for this name 547 * @note If 'requester' is a server or NULL, then we also check 548 * the ID table, otherwise not. 549 * @returns If the user is found then the Client is returned, otherwise NULL. 550 */ 551 Client *find_user(const char *name, Client *requester) 552 { 553 Client *c2ptr; 554 555 c2ptr = find_client(name, requester); 556 557 if (c2ptr && IsUser(c2ptr) && c2ptr->user) 558 return c2ptr; 559 560 return NULL; 561 } 562 563 564 /** Find a channel by name. 565 * @param name The channel name to search for 566 * @returns If the channel exists then the Channel is returned, otherwise NULL. 567 */ 568 Channel *find_channel(const char *name) 569 { 570 unsigned int hashv; 571 Channel *channel; 572 573 hashv = hash_channel_name(name); 574 575 for (channel = channelTable[hashv]; channel; channel = channel->hnextch) 576 if (smycmp(name, channel->name) == 0) 577 return channel; 578 579 return NULL; 580 } 581 582 /** @} */ 583 584 Channel *hash_get_chan_bucket(uint64_t hashv) 585 { 586 if (hashv > CHAN_HASH_TABLE_SIZE) 587 return NULL; 588 return channelTable[hashv]; 589 } 590 591 /* Throttling - originally by Stskeeps */ 592 593 /* Note that we call this set::anti-flood::connect-flood nowadays */ 594 595 struct MODVAR ThrottlingBucket *ThrottlingHash[THROTTLING_HASH_TABLE_SIZE]; 596 597 void update_throttling_timer_settings(void) 598 { 599 long v; 600 EventInfo eInfo; 601 602 if (!THROTTLING_PERIOD) 603 { 604 v = 120*1000; 605 } else 606 { 607 v = (THROTTLING_PERIOD*1000)/2; 608 if (v > 5000) 609 v = 5000; /* run at least every 5s */ 610 if (v < 1000) 611 v = 1000; /* run at max once every 1s */ 612 } 613 614 memset(&eInfo, 0, sizeof(eInfo)); 615 eInfo.flags = EMOD_EVERY; 616 eInfo.every_msec = v; 617 EventMod(EventFind("throttling_check_expire"), &eInfo); 618 } 619 620 uint64_t hash_throttling(const char *ip) 621 { 622 return siphash(ip, siphashkey_throttling) % THROTTLING_HASH_TABLE_SIZE; 623 } 624 625 struct ThrottlingBucket *find_throttling_bucket(Client *client) 626 { 627 int hash = 0; 628 struct ThrottlingBucket *p; 629 hash = hash_throttling(client->ip); 630 631 for (p = ThrottlingHash[hash]; p; p = p->next) 632 { 633 if (!strcmp(p->ip, client->ip)) 634 return p; 635 } 636 637 return NULL; 638 } 639 640 EVENT(throttling_check_expire) 641 { 642 struct ThrottlingBucket *n, *n_next; 643 int i; 644 static time_t t = 0; 645 646 for (i = 0; i < THROTTLING_HASH_TABLE_SIZE; i++) 647 { 648 for (n = ThrottlingHash[i]; n; n = n_next) 649 { 650 n_next = n->next; 651 if ((TStime() - n->since) > (THROTTLING_PERIOD ? THROTTLING_PERIOD : 15)) 652 { 653 DelListItem(n, ThrottlingHash[i]); 654 safe_free(n->ip); 655 safe_free(n); 656 } 657 } 658 } 659 660 if (!t || (TStime() - t > 30)) 661 { 662 extern Module *Modules; 663 char *p = serveropts + strlen(serveropts); 664 Module *mi; 665 t = TStime(); 666 if (!Hooks[HOOKTYPE_USERMSG] && strchr(serveropts, 'm')) 667 { p = strchr(serveropts, 'm'); *p = '\0'; } 668 if (!Hooks[HOOKTYPE_CHANMSG] && strchr(serveropts, 'M')) 669 { p = strchr(serveropts, 'M'); *p = '\0'; } 670 if (Hooks[HOOKTYPE_USERMSG] && !strchr(serveropts, 'm')) 671 *p++ = 'm'; 672 if (Hooks[HOOKTYPE_CHANMSG] && !strchr(serveropts, 'M')) 673 *p++ = 'M'; 674 *p = '\0'; 675 for (mi = Modules; mi; mi = mi->next) 676 if (!(mi->options & MOD_OPT_OFFICIAL)) 677 tainted = 99; 678 } 679 680 return; 681 } 682 683 void add_throttling_bucket(Client *client) 684 { 685 int hash; 686 struct ThrottlingBucket *n; 687 688 n = safe_alloc(sizeof(struct ThrottlingBucket)); 689 n->next = n->prev = NULL; 690 safe_strdup(n->ip, client->ip); 691 n->since = TStime(); 692 n->count = 1; 693 hash = hash_throttling(client->ip); 694 AddListItem(n, ThrottlingHash[hash]); 695 return; 696 } 697 698 /** Checks whether the user is connect-flooding. 699 * @retval 0 Denied, throttled. 700 * @retval 1 Allowed, but known in the list. 701 * @retval 2 Allowed, not in list or is an exception. 702 * @see add_connection() 703 */ 704 int throttle_can_connect(Client *client) 705 { 706 struct ThrottlingBucket *b; 707 708 if (!THROTTLING_PERIOD || !THROTTLING_COUNT) 709 return 2; 710 711 if (!(b = find_throttling_bucket(client))) 712 return 1; 713 else 714 { 715 if (find_tkl_exception(TKL_CONNECT_FLOOD, client)) 716 return 2; 717 if (b->count+1 > (THROTTLING_COUNT ? THROTTLING_COUNT : 3)) 718 return 0; 719 b->count++; 720 return 2; 721 } 722 } 723 724 /** Find a server by the SID-part of a UID. 725 * Eg you pass "001ABCDEFG" and it would look up server "001". 726 * 727 * @param uid The UID, eg 001ABCDEFG 728 * @returns Server where the UID would be hosted on, or NULL 729 * if no such server is linked. 730 */ 731 Client *find_server_by_uid(const char *uid) 732 { 733 char sid[SIDLEN+1]; 734 735 if (!isdigit(*uid)) 736 return NULL; /* not a UID/SID */ 737 738 strlcpy(sid, uid, sizeof(sid)); 739 return hash_find_id(sid, NULL); 740 }