44 |
|
#include "log.h" |
45 |
|
#include "send.h" |
46 |
|
#include "memory.h" |
47 |
– |
#include "mempool.h" |
47 |
|
#include "res.h" |
48 |
|
#include "userhost.h" |
49 |
|
#include "user.h" |
53 |
|
#include "conf_db.h" |
54 |
|
#include "conf_class.h" |
55 |
|
#include "motd.h" |
56 |
+ |
#include "ipcache.h" |
57 |
|
|
58 |
|
|
59 |
|
/* general conf items link list root, other than k lines etc. */ |
75 |
|
static void read_conf(FILE *); |
76 |
|
static void clear_out_old_conf(void); |
77 |
|
static void expire_tklines(dlink_list *); |
78 |
– |
static void ipcache_remove_expired_entries(void *); |
79 |
– |
static uint32_t hash_ip(const struct irc_ssaddr *); |
78 |
|
static int verify_access(struct Client *); |
79 |
|
static int attach_iline(struct Client *, struct MaskItem *); |
82 |
– |
static struct ip_entry *find_or_add_ip(struct irc_ssaddr *); |
80 |
|
static dlink_list *map_to_list(enum maskitem_type); |
81 |
|
static int find_user_host(struct Client *, char *, char *, char *, unsigned int); |
82 |
|
|
83 |
|
|
87 |
– |
/* usually, with hash tables, you use a prime number... |
88 |
– |
* but in this case I am dealing with ip addresses, |
89 |
– |
* not ascii strings. |
90 |
– |
*/ |
91 |
– |
#define IP_HASH_SIZE 0x1000 |
92 |
– |
|
93 |
– |
struct ip_entry |
94 |
– |
{ |
95 |
– |
dlink_node node; /**< Doubly linked list node. */ |
96 |
– |
struct irc_ssaddr ip; |
97 |
– |
unsigned int count; /**< Number of registered users using this IP */ |
98 |
– |
unsigned int connection_count; /**< Number of connections from this IP in the last throttle_time duration */ |
99 |
– |
time_t last_attempt; /**< The last time someone connected from this IP */ |
100 |
– |
}; |
101 |
– |
|
102 |
– |
static dlink_list ip_hash_table[IP_HASH_SIZE]; |
103 |
– |
static mp_pool_t *ip_entry_pool = NULL; |
104 |
– |
|
105 |
– |
|
84 |
|
/* conf_dns_callback() |
85 |
|
* |
86 |
|
* inputs - pointer to struct MaskItem |
359 |
|
|
360 |
|
assert(conf->class); |
361 |
|
|
362 |
< |
ip_found = find_or_add_ip(&client_p->localClient->ip); |
362 |
> |
ip_found = ipcache_find_or_add_address(&client_p->localClient->ip); |
363 |
|
ip_found->count++; |
364 |
|
SetIpHash(client_p); |
365 |
|
|
396 |
|
return attach_conf(client_p, conf); |
397 |
|
} |
398 |
|
|
421 |
– |
/* init_ip_hash_table() |
422 |
– |
* |
423 |
– |
* inputs - NONE |
424 |
– |
* output - NONE |
425 |
– |
* side effects - allocate memory for ip_entry(s) |
426 |
– |
* - clear the ip hash table |
427 |
– |
*/ |
428 |
– |
void |
429 |
– |
ipcache_init(void) |
430 |
– |
{ |
431 |
– |
static struct event event_expire_ipcache = |
432 |
– |
{ |
433 |
– |
.name = "ipcache_remove_expired_entries", |
434 |
– |
.handler = ipcache_remove_expired_entries, |
435 |
– |
.when = 123 |
436 |
– |
}; |
437 |
– |
|
438 |
– |
event_add(&event_expire_ipcache, NULL); |
439 |
– |
ip_entry_pool = mp_pool_new(sizeof(struct ip_entry), MP_CHUNK_SIZE_IP_ENTRY); |
440 |
– |
} |
441 |
– |
|
442 |
– |
/* find_or_add_ip() |
443 |
– |
* |
444 |
– |
* inputs - pointer to struct irc_ssaddr |
445 |
– |
* output - pointer to a struct ip_entry |
446 |
– |
* side effects - |
447 |
– |
* |
448 |
– |
* If the ip # was not found, a new struct ip_entry is created, and the ip |
449 |
– |
* count set to 0. |
450 |
– |
*/ |
451 |
– |
static struct ip_entry * |
452 |
– |
find_or_add_ip(struct irc_ssaddr *addr) |
453 |
– |
{ |
454 |
– |
dlink_node *ptr = NULL; |
455 |
– |
struct ip_entry *iptr = NULL; |
456 |
– |
uint32_t hash_index = hash_ip(addr); |
457 |
– |
int res = 0; |
458 |
– |
struct sockaddr_in *v4 = (struct sockaddr_in *)addr, *ptr_v4; |
459 |
– |
#ifdef IPV6 |
460 |
– |
struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr, *ptr_v6; |
461 |
– |
#endif |
462 |
– |
|
463 |
– |
DLINK_FOREACH(ptr, ip_hash_table[hash_index].head) |
464 |
– |
{ |
465 |
– |
iptr = ptr->data; |
466 |
– |
#ifdef IPV6 |
467 |
– |
if (iptr->ip.ss.ss_family != addr->ss.ss_family) |
468 |
– |
continue; |
469 |
– |
|
470 |
– |
if (addr->ss.ss_family == AF_INET6) |
471 |
– |
{ |
472 |
– |
ptr_v6 = (struct sockaddr_in6 *)&iptr->ip; |
473 |
– |
res = memcmp(&v6->sin6_addr, &ptr_v6->sin6_addr, sizeof(struct in6_addr)); |
474 |
– |
} |
475 |
– |
else |
476 |
– |
#endif |
477 |
– |
{ |
478 |
– |
ptr_v4 = (struct sockaddr_in *)&iptr->ip; |
479 |
– |
res = memcmp(&v4->sin_addr, &ptr_v4->sin_addr, sizeof(struct in_addr)); |
480 |
– |
} |
481 |
– |
|
482 |
– |
if (res == 0) |
483 |
– |
return iptr; /* Found entry already in hash, return it. */ |
484 |
– |
} |
485 |
– |
|
486 |
– |
iptr = mp_pool_get(ip_entry_pool); |
487 |
– |
memcpy(&iptr->ip, addr, sizeof(struct irc_ssaddr)); |
488 |
– |
|
489 |
– |
dlinkAdd(iptr, &iptr->node, &atable[hash_index]); |
490 |
– |
|
491 |
– |
return iptr; |
492 |
– |
} |
493 |
– |
|
494 |
– |
/* remove_one_ip() |
495 |
– |
* |
496 |
– |
* inputs - unsigned long IP address value |
497 |
– |
* output - NONE |
498 |
– |
* side effects - The ip address given, is looked up in ip hash table |
499 |
– |
* and number of ip#'s for that ip decremented. |
500 |
– |
* If ip # count reaches 0 and has expired, |
501 |
– |
* the struct ip_entry is returned to the ip_entry_heap |
502 |
– |
*/ |
503 |
– |
void |
504 |
– |
remove_one_ip(struct irc_ssaddr *addr) |
505 |
– |
{ |
506 |
– |
dlink_node *ptr = NULL; |
507 |
– |
uint32_t hash_index = hash_ip(addr); |
508 |
– |
int res = 0; |
509 |
– |
struct sockaddr_in *v4 = (struct sockaddr_in *)addr, *ptr_v4; |
510 |
– |
#ifdef IPV6 |
511 |
– |
struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr, *ptr_v6; |
512 |
– |
#endif |
513 |
– |
|
514 |
– |
DLINK_FOREACH(ptr, ip_hash_table[hash_index].head) |
515 |
– |
{ |
516 |
– |
struct ip_entry *iptr = ptr->data; |
517 |
– |
#ifdef IPV6 |
518 |
– |
if (iptr->ip.ss.ss_family != addr->ss.ss_family) |
519 |
– |
continue; |
520 |
– |
if (addr->ss.ss_family == AF_INET6) |
521 |
– |
{ |
522 |
– |
ptr_v6 = (struct sockaddr_in6 *)&iptr->ip; |
523 |
– |
res = memcmp(&v6->sin6_addr, &ptr_v6->sin6_addr, sizeof(struct in6_addr)); |
524 |
– |
} |
525 |
– |
else |
526 |
– |
#endif |
527 |
– |
{ |
528 |
– |
ptr_v4 = (struct sockaddr_in *)&iptr->ip; |
529 |
– |
res = memcmp(&v4->sin_addr, &ptr_v4->sin_addr, sizeof(struct in_addr)); |
530 |
– |
} |
531 |
– |
|
532 |
– |
if (res) |
533 |
– |
continue; |
534 |
– |
assert(iptr->count > 0); |
535 |
– |
|
536 |
– |
if (--iptr->count == 0 && |
537 |
– |
(CurrentTime - iptr->last_attempt) >= ConfigFileEntry.throttle_time) |
538 |
– |
{ |
539 |
– |
dlinkDelete(&iptr->node, &ip_hash_table[hash_index]); |
540 |
– |
mp_pool_release(iptr); |
541 |
– |
return; |
542 |
– |
} |
543 |
– |
} |
544 |
– |
} |
545 |
– |
|
546 |
– |
/* hash_ip() |
547 |
– |
* |
548 |
– |
* input - pointer to an irc_inaddr |
549 |
– |
* output - integer value used as index into hash table |
550 |
– |
* side effects - hopefully, none |
551 |
– |
*/ |
552 |
– |
static uint32_t |
553 |
– |
hash_ip(const struct irc_ssaddr *addr) |
554 |
– |
{ |
555 |
– |
if (addr->ss.ss_family == AF_INET) |
556 |
– |
{ |
557 |
– |
const struct sockaddr_in *v4 = (const struct sockaddr_in *)addr; |
558 |
– |
uint32_t hash = 0, ip = ntohl(v4->sin_addr.s_addr); |
559 |
– |
|
560 |
– |
hash = ((ip >> 12) + ip) & (IP_HASH_SIZE - 1); |
561 |
– |
return hash; |
562 |
– |
} |
563 |
– |
#ifdef IPV6 |
564 |
– |
else |
565 |
– |
{ |
566 |
– |
const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)addr; |
567 |
– |
uint32_t hash = 0, *ip = (uint32_t *)&v6->sin6_addr.s6_addr; |
568 |
– |
|
569 |
– |
hash = ip[0] ^ ip[3]; |
570 |
– |
hash ^= hash >> 16; |
571 |
– |
hash ^= hash >> 8; |
572 |
– |
hash = hash & (IP_HASH_SIZE - 1); |
573 |
– |
return hash; |
574 |
– |
} |
575 |
– |
#else |
576 |
– |
return 0; |
577 |
– |
#endif |
578 |
– |
} |
579 |
– |
|
580 |
– |
/* count_ip_hash() |
581 |
– |
* |
582 |
– |
* inputs - pointer to counter of number of ips hashed |
583 |
– |
* - pointer to memory used for ip hash |
584 |
– |
* output - returned via pointers input |
585 |
– |
* side effects - NONE |
586 |
– |
* |
587 |
– |
* number of hashed ip #'s is counted up, plus the amount of memory |
588 |
– |
* used in the hash. |
589 |
– |
*/ |
590 |
– |
void |
591 |
– |
count_ip_hash(unsigned int *number_ips_stored, uint64_t *mem_ips_stored) |
592 |
– |
{ |
593 |
– |
*number_ips_stored = 0; |
594 |
– |
*mem_ips_stored = 0; |
595 |
– |
|
596 |
– |
for (unsigned int i = 0; i < IP_HASH_SIZE; ++i) |
597 |
– |
*number_ips_stored += dlink_list_length(&ip_hash_table[i]); |
598 |
– |
*mem_ips_stored = *number_ips_stored * sizeof(struct ip_entry); |
599 |
– |
} |
600 |
– |
|
601 |
– |
/* garbage_collect_ip_entries() |
602 |
– |
* |
603 |
– |
* input - NONE |
604 |
– |
* output - NONE |
605 |
– |
* side effects - free up all ip entries with no connections |
606 |
– |
*/ |
607 |
– |
static void |
608 |
– |
ipcache_remove_expired_entries(void *unused) |
609 |
– |
{ |
610 |
– |
dlink_node *ptr = NULL, *ptr_next = NULL; |
611 |
– |
|
612 |
– |
for (unsigned int i = 0; i < IP_HASH_SIZE; ++i) |
613 |
– |
{ |
614 |
– |
DLINK_FOREACH_SAFE(ptr, ptr_next, ip_hash_table[i].head) |
615 |
– |
{ |
616 |
– |
struct ip_entry *iptr = ptr->data; |
617 |
– |
|
618 |
– |
if (iptr->count == 0 && |
619 |
– |
(CurrentTime - iptr->last_attempt) >= ConfigFileEntry.throttle_time) |
620 |
– |
{ |
621 |
– |
dlinkDelete(&iptr->node, &ip_hash_table[i]); |
622 |
– |
mp_pool_release(iptr); |
623 |
– |
} |
624 |
– |
} |
625 |
– |
} |
626 |
– |
} |
627 |
– |
|
399 |
|
/* detach_conf() |
400 |
|
* |
401 |
|
* inputs - pointer to client to detach |
1016 |
|
if (conf) |
1017 |
|
return BANNED_CLIENT; |
1018 |
|
|
1019 |
< |
ip_found = find_or_add_ip(addr); |
1019 |
> |
ip_found = ipcache_find_or_add_address(addr); |
1020 |
|
|
1021 |
|
if ((CurrentTime - ip_found->last_attempt) < ConfigFileEntry.throttle_time) |
1022 |
|
{ |