ircd: import modified version of ratbox 3.1 whowas code

This commit is contained in:
William Pitcock 2016-01-23 11:16:34 -05:00
parent 3de2266243
commit b47f8a4fda
12 changed files with 205 additions and 195 deletions

View file

@ -117,7 +117,8 @@ struct Client
struct Client *servptr; /* Points to server this Client is on */
struct Client *from; /* == self, if Local Client, *NEVER* NULL! */
struct Whowas *whowas; /* Pointers to whowas structs */
rb_dlink_list whowas_clist;
time_t tsinfo; /* TS on the nick, SVINFO on server */
unsigned int umodes; /* opers, normal users subset */
unsigned int flags; /* client flags */

View file

@ -131,7 +131,7 @@
#define NUMERIC_STR_366 ":%s 366 %s %s :End of /NAMES list."
#define NUMERIC_STR_367 ":%s 367 %s %s %s %s %lu"
#define NUMERIC_STR_368 ":%s 368 %s %s :End of Channel Ban List"
#define NUMERIC_STR_369 ":%s 369 %s %s :End of WHOWAS"
#define NUMERIC_STR_369 "%s :End of WHOWAS"
#define NUMERIC_STR_371 ":%s"
#define NUMERIC_STR_372 ":%s 372 %s :- %s"
#define NUMERIC_STR_374 ":End of /INFO list."
@ -147,7 +147,7 @@
#define NUMERIC_STR_403 "%s :No such channel"
#define NUMERIC_STR_404 "%s :Cannot send to channel"
#define NUMERIC_STR_405 ":%s 405 %s %s :You have joined too many channels"
#define NUMERIC_STR_406 ":%s 406 %s %s :There was no such nickname"
#define NUMERIC_STR_406 ":%s :There was no such nickname"
#define NUMERIC_STR_407 ":%s 407 %s %s :Too many recipients."
#define NUMERIC_STR_409 ":%s 409 %s :No origin specified"
#define NUMERIC_STR_410 ":%s 410 %s %s :Invalid CAP subcommand"

View file

@ -31,13 +31,6 @@
#include "setup.h"
/*
* Whowas hash table size
*
*/
#define WW_MAX_BITS 16
#define WW_MAX 65536
struct User;
struct Client;
@ -48,7 +41,10 @@ struct Client;
*/
struct Whowas
{
int hashv;
struct whowas_top *wtop;
rb_dlink_node wnode; /* for the wtop linked list */
rb_dlink_node cnode; /* node for online clients */
rb_dlink_node whowas_node; /* node for the whowas linked list */
char name[NICKLEN + 1];
char username[USERLEN + 1];
char hostname[HOSTLEN + 1];
@ -59,10 +55,6 @@ struct Whowas
const char *servername;
time_t logoff;
struct Client *online; /* Pointer to new nickname for chasing or NULL */
struct Whowas *next; /* for hash table... */
struct Whowas *prev; /* for hash table... */
struct Whowas *cnext; /* for client struct linked list */
struct Whowas *cprev; /* for client struct linked list */
};
/* Flags */
@ -72,7 +64,7 @@ struct Whowas
/*
** initwhowas
*/
extern void initwhowas(void);
extern void whowas_init(void);
/*
** add_history
@ -81,7 +73,7 @@ extern void initwhowas(void);
** Client must be a fully registered user (specifically,
** the user structure must have been allocated).
*/
void add_history(struct Client *, int);
void whowas_add_history(struct Client *, int);
/*
** off_history
@ -90,7 +82,7 @@ void add_history(struct Client *, int);
** structures and it must know when they cease to exist. This
** also implicitly calls AddHistory.
*/
void off_history(struct Client *);
void whowas_off_history(struct Client *);
/*
** get_history
@ -98,18 +90,12 @@ void off_history(struct Client *);
** nickname within the timelimit. Returns NULL, if no
** one found...
*/
struct Client *get_history(const char *, time_t);
struct Client *whowas_get_history(const char *, time_t);
/* Nick name */
/* Time limit in seconds */
/*
** for debugging...counts related structures stored in whowas array.
*/
void count_whowas_memory(size_t *, size_t *);
/* XXX m_whowas.c in modules needs these */
extern struct Whowas WHOWAS[];
extern struct Whowas *WHOWASHASH[];
extern unsigned int hash_whowas_name(const char *name);
rb_dlink_list *whowas_get_list(const char *name);
void whowas_set_size(int whowas_length);
void whowas_memory_usage(size_t *count, size_t *memused);
#endif /* INCLUDED_whowas_h */

View file

@ -672,7 +672,7 @@ resv_nick_fnc(const char *mask, const char *reason, int temp_time)
/* Do all of the nick-changing gymnastics. */
client_p->tsinfo = rb_current_time();
add_history(client_p, 1);
whowas_add_history(client_p, 1);
monitor_signoff(client_p);
@ -872,7 +872,7 @@ find_chasing(struct Client *source_p, const char *user, int *chasing)
if(who || IsDigit(*user))
return who;
if(!(who = get_history(user, (long) KILLCHASETIMELIMIT)))
if(!(who = whowas_get_history(user, (long) KILLCHASETIMELIMIT)))
{
sendto_one_numeric(source_p, ERR_NOSUCHNICK,
form_str(ERR_NOSUCHNICK), user);
@ -1247,8 +1247,8 @@ exit_generic_client(struct Client *client_p, struct Client *source_p, struct Cli
/* Clean up allow lists */
del_all_accepts(source_p);
add_history(source_p, 0);
off_history(source_p);
whowas_add_history(source_p, 0);
whowas_off_history(source_p);
monitor_signoff(source_p);

View file

@ -653,7 +653,7 @@ charybdis_main(int argc, char *argv[])
init_hook();
init_channels();
initclass();
initwhowas();
whowas_init();
init_reject();
init_cache();
init_monitor();

View file

@ -1513,7 +1513,7 @@ change_nick_user_host(struct Client *target_p, const char *nick, const char *use
rb_strlcpy(target_p->host, host, sizeof target_p->host);
if (changed)
add_history(target_p, 1);
whowas_add_history(target_p, 1);
del_from_client_hash(target_p->name, target_p);
rb_strlcpy(target_p->name, nick, NICKLEN);

View file

@ -4,7 +4,8 @@
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2005 ircd-ratbox development team
* Copyright (C) 2002-2012 ircd-ratbox development team
* Copyright (C) 2016 William Pitcock <nenolod@dereferenced.org>
*
* 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
@ -18,178 +19,203 @@
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*
* $Id: whowas.c 1717 2006-07-04 14:41:11Z jilles $
*/
#include "stdinc.h"
#include "whowas.h"
#include "client.h"
#include "common.h"
#include "hash.h"
#include "whowas.h"
#include "match.h"
#include "ircd.h"
#include "ircd_defs.h"
#include "numeric.h"
#include "s_assert.h"
#include "s_serv.h"
#include "s_user.h"
#include "send.h"
#include "s_conf.h"
#include "client.h"
#include "send.h"
#include "logger.h"
#include "scache.h"
#include "s_assert.h"
#include "irc_radixtree.h"
/* internally defined function */
static void add_whowas_to_clist(struct Whowas **, struct Whowas *);
static void del_whowas_from_clist(struct Whowas **, struct Whowas *);
static void add_whowas_to_list(struct Whowas **, struct Whowas *);
static void del_whowas_from_list(struct Whowas **, struct Whowas *);
struct Whowas WHOWAS[NICKNAMEHISTORYLENGTH];
struct Whowas *WHOWASHASH[WW_MAX];
static int whowas_next = 0;
unsigned int hash_whowas_name(const char *name)
struct whowas_top
{
return fnv_hash_upper((const unsigned char *) name, WW_MAX_BITS);
char *name;
rb_dlink_list wwlist;
};
static struct irc_radixtree *whowas_tree = NULL;
static rb_dlink_list whowas_list = {NULL, NULL, 0};
static unsigned int whowas_list_length = NICKNAMEHISTORYLENGTH;
static void whowas_trim(void *unused);
static void
whowas_free_wtop(struct whowas_top *wtop)
{
if(rb_dlink_list_length(&wtop->wwlist) == 0)
{
irc_radixtree_delete(whowas_tree, wtop->name);
rb_free(wtop->name);
rb_free(wtop);
}
}
void add_history(struct Client *client_p, int online)
static struct whowas_top *
whowas_get_top(const char *name)
{
struct Whowas *who = &WHOWAS[whowas_next];
struct whowas_top *wtop;
wtop = irc_radixtree_retrieve(whowas_tree, name);
if (wtop != NULL)
return wtop;
wtop = rb_malloc(sizeof(struct whowas_top));
wtop->name = rb_strdup(name);
irc_radixtree_add(whowas_tree, wtop->name, wtop);
return wtop;
}
rb_dlink_list *
whowas_get_list(const char *name)
{
struct whowas_top *wtop;
wtop = irc_radixtree_retrieve(whowas_tree, name);
if(wtop == NULL)
return NULL;
return &wtop->wwlist;
}
void
whowas_add_history(struct Client *client_p, int online)
{
struct whowas_top *wtop;
struct Whowas *who;
s_assert(NULL != client_p);
if(client_p == NULL)
return;
if(who->hashv != -1)
{
if(who->online)
del_whowas_from_clist(&(who->online->whowas), who);
del_whowas_from_list(&WHOWASHASH[who->hashv], who);
}
who->hashv = hash_whowas_name(client_p->name);
/* trim some of the entries if we're getting well over our history length */
if(rb_dlink_list_length(&whowas_list) > whowas_list_length + 100)
whowas_trim(NULL);
wtop = whowas_get_top(client_p->name);
who = rb_malloc(sizeof(struct Whowas));
who->wtop = wtop;
who->logoff = rb_current_time();
/*
* NOTE: strcpy ok here, the sizes in the client struct MUST
* match the sizes in the whowas struct
*/
rb_strlcpy(who->name, client_p->name, sizeof(who->name));
strcpy(who->username, client_p->username);
strcpy(who->hostname, client_p->host);
strcpy(who->realname, client_p->info);
strcpy(who->suser, client_p->user->suser);
strcpy(who->sockhost, client_p->sockhost);
rb_strlcpy(who->username, client_p->username, sizeof(who->username));
rb_strlcpy(who->hostname, client_p->host, sizeof(who->hostname));
rb_strlcpy(who->realname, client_p->info, sizeof(who->realname));
rb_strlcpy(who->sockhost, client_p->sockhost, sizeof(who->sockhost));
who->flags = (IsIPSpoof(client_p) ? WHOWAS_IP_SPOOFING : 0) |
(IsDynSpoof(client_p) ? WHOWAS_DYNSPOOF : 0);
/* this is safe do to with the servername cache */
who->servername = scache_get_name(client_p->servptr->serv->nameinfo);
if(online)
{
who->online = client_p;
add_whowas_to_clist(&(client_p->whowas), who);
rb_dlinkAdd(who, &who->cnode, &client_p->whowas_clist);
}
else
who->online = NULL;
add_whowas_to_list(&WHOWASHASH[who->hashv], who);
whowas_next++;
if(whowas_next == NICKNAMEHISTORYLENGTH)
whowas_next = 0;
rb_dlinkAdd(who, &who->wnode, &wtop->wwlist);
rb_dlinkAdd(who, &who->whowas_node, &whowas_list);
}
void off_history(struct Client *client_p)
{
struct Whowas *temp, *next;
for (temp = client_p->whowas; temp; temp = next)
void
whowas_off_history(struct Client *client_p)
{
rb_dlink_node *ptr, *next;
RB_DLINK_FOREACH_SAFE(ptr, next, client_p->whowas_clist.head)
{
next = temp->cnext;
temp->online = NULL;
del_whowas_from_clist(&(client_p->whowas), temp);
struct Whowas *who = ptr->data;
who->online = NULL;
rb_dlinkDelete(&who->cnode, &client_p->whowas_clist);
}
}
struct Client *get_history(const char *nick, time_t timelimit)
struct Client *
whowas_get_history(const char *nick, time_t timelimit)
{
struct Whowas *temp;
int blah;
struct whowas_top *wtop;
rb_dlink_node *ptr;
wtop = irc_radixtree_retrieve(whowas_tree, nick);
if(wtop == NULL)
return NULL;
timelimit = rb_current_time() - timelimit;
blah = hash_whowas_name(nick);
temp = WHOWASHASH[blah];
for (; temp; temp = temp->next)
RB_DLINK_FOREACH_PREV(ptr, wtop->wwlist.tail)
{
if(irccmp(nick, temp->name))
continue;
if(temp->logoff < timelimit)
continue;
return temp->online;
struct Whowas *who = ptr->data;
if(who->logoff >= timelimit)
{
return who->online;
}
}
return NULL;
}
void count_whowas_memory(size_t * wwu, size_t * wwum)
static void
whowas_trim(void *unused)
{
*wwu = NICKNAMEHISTORYLENGTH;
*wwum = NICKNAMEHISTORYLENGTH * sizeof(struct Whowas);
long over;
if(rb_dlink_list_length(&whowas_list) < whowas_list_length)
return;
over = rb_dlink_list_length(&whowas_list) - whowas_list_length;
/* remove whowas entries over the configured length */
for(long i = 0; i < over; i++)
{
if(whowas_list.tail != NULL && whowas_list.tail->data != NULL)
{
struct Whowas *twho = whowas_list.tail->data;
if(twho->online != NULL)
rb_dlinkDelete(&twho->cnode, &twho->online->whowas_clist);
rb_dlinkDelete(&twho->wnode, &twho->wtop->wwlist);
rb_dlinkDelete(&twho->whowas_node, &whowas_list);
whowas_free_wtop(twho->wtop);
rb_free(twho);
}
}
}
void
initwhowas()
whowas_init(void)
{
int i;
for (i = 0; i < NICKNAMEHISTORYLENGTH; i++)
whowas_tree = irc_radixtree_create("whowas", irc_radixtree_irccasecanon);
if(whowas_list_length == 0)
{
memset((void *) &WHOWAS[i], 0, sizeof(struct Whowas));
WHOWAS[i].hashv = -1;
whowas_list_length = NICKNAMEHISTORYLENGTH;
}
for (i = 0; i < WW_MAX; i++)
WHOWASHASH[i] = NULL;
rb_event_add("whowas_trim", whowas_trim, NULL, 10);
}
static void
add_whowas_to_clist(struct Whowas **bucket, struct Whowas *whowas)
void
whowas_set_size(int len)
{
whowas->cprev = NULL;
if((whowas->cnext = *bucket) != NULL)
whowas->cnext->cprev = whowas;
*bucket = whowas;
whowas_list_length = len;
whowas_trim(NULL);
}
static void
del_whowas_from_clist(struct Whowas **bucket, struct Whowas *whowas)
void
whowas_memory_usage(size_t * count, size_t * memused)
{
if(whowas->cprev)
whowas->cprev->cnext = whowas->cnext;
else
*bucket = whowas->cnext;
if(whowas->cnext)
whowas->cnext->cprev = whowas->cprev;
}
static void
add_whowas_to_list(struct Whowas **bucket, struct Whowas *whowas)
{
whowas->prev = NULL;
if((whowas->next = *bucket) != NULL)
whowas->next->prev = whowas;
*bucket = whowas;
}
static void
del_whowas_from_list(struct Whowas **bucket, struct Whowas *whowas)
{
if(whowas->prev)
whowas->prev->next = whowas->next;
else
*bucket = whowas->next;
if(whowas->next)
whowas->next->prev = whowas->prev;
*count = rb_dlink_list_length(&whowas_list);
*memused += *count * sizeof(struct Whowas);
*memused += sizeof(struct whowas_top) * irc_radixtree_size(whowas_tree);
}

View file

@ -102,7 +102,7 @@ mo_kill(struct Client *client_p, struct Client *source_p, int parc, const char *
** rewrite the KILL for this new nickname--this keeps
** servers in synch when nick change and kill collide
*/
if((target_p = get_history(user, (long) KILLCHASETIMELIMIT)) == NULL)
if((target_p = whowas_get_history(user, (long) KILLCHASETIMELIMIT)) == NULL)
{
if (strchr(user, '.'))
sendto_one_numeric(source_p, ERR_CANTKILLSERVER, form_str(ERR_CANTKILLSERVER));
@ -221,7 +221,7 @@ ms_kill(struct Client *client_p, struct Client *source_p, int parc, const char *
* not an uid, automatically rewrite the KILL for this new nickname.
* --this keeps servers in synch when nick change and kill collide
*/
if(IsDigit(*user) || (!(target_p = get_history(user, (long) KILLCHASETIMELIMIT))))
if(IsDigit(*user) || (!(target_p = whowas_get_history(user, (long) KILLCHASETIMELIMIT))))
{
sendto_one_numeric(source_p, ERR_NOSUCHNICK,
form_str(ERR_NOSUCHNICK), IsDigit(*user) ? "*" : user);

View file

@ -685,7 +685,7 @@ change_local_nick(struct Client *client_p, struct Client *source_p,
/* send the nick change to servers.. */
if(source_p->user)
{
add_history(source_p, 1);
whowas_add_history(source_p, 1);
if (dosend)
{
@ -745,7 +745,7 @@ change_remote_nick(struct Client *client_p, struct Client *source_p,
if(source_p->user)
{
add_history(source_p, 1);
whowas_add_history(source_p, 1);
if (dosend)
{
sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld",

View file

@ -244,7 +244,7 @@ doit:
target_p->name, target_p->username,
target_p->host, parv[2]);
add_history(target_p, 1);
whowas_add_history(target_p, 1);
sendto_server(NULL, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld",
use_id(target_p), parv[2], (long) target_p->tsinfo);

View file

@ -1267,7 +1267,7 @@ stats_memory (struct Client *source_p)
size_t total_memory = 0;
count_whowas_memory(&ww, &wwm);
whowas_memory_usage(&ww, &wwm);
RB_DLINK_FOREACH(ptr, global_client_list.head)
{

View file

@ -58,9 +58,10 @@ DECLARE_MODULE_AV1(whowas, NULL, NULL, whowas_clist, NULL, NULL, "$Revision: 171
static int
m_whowas(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
{
struct Whowas *temp;
rb_dlink_list *whowas_list;
rb_dlink_node *ptr;
int cur = 0;
int max = -1, found = 0;
int max = -1;
char *p;
const char *nick;
char tbuf[26];
@ -76,8 +77,8 @@ m_whowas(struct Client *client_p, struct Client *source_p, int parc, const char
{
sendto_one(source_p, form_str(RPL_LOAD2HI),
me.name, source_p->name, "WHOWAS");
sendto_one(source_p, form_str(RPL_ENDOFWHOWAS),
me.name, source_p->name, parv[1]);
sendto_one_numeric(source_p, RPL_ENDOFWHOWAS, form_str(RPL_ENDOFWHOWAS),
parv[1]);
return 0;
}
else
@ -101,54 +102,50 @@ m_whowas(struct Client *client_p, struct Client *source_p, int parc, const char
nick = parv[1];
sendq_limit = get_sendq(client_p) * 9 / 10;
whowas_list = whowas_get_list(nick);
temp = WHOWASHASH[hash_whowas_name(nick)];
found = 0;
for (; temp; temp = temp->next)
if(whowas_list == NULL)
{
if(!irccmp(nick, temp->name))
sendto_one_numeric(source_p, ERR_WASNOSUCHNICK, form_str(ERR_WASNOSUCHNICK), nick);
sendto_one_numeric(source_p, RPL_ENDOFWHOWAS, form_str(RPL_ENDOFWHOWAS), parv[1]);
return 0;
}
RB_DLINK_FOREACH(ptr, whowas_list->head)
{
struct Whowas *temp = ptr->data;
if(cur > 0 && rb_linebuf_len(&client_p->localClient->buf_sendq) > sendq_limit)
{
sendto_one(source_p, form_str(ERR_TOOMANYMATCHES),
me.name, source_p->name, "WHOWAS");
break;
}
sendto_one(source_p, form_str(RPL_WHOWASUSER),
me.name, source_p->name, temp->name,
temp->username, temp->hostname, temp->realname);
if (!EmptyString(temp->sockhost) &&
strcmp(temp->sockhost, "0") &&
show_ip_whowas(temp, source_p))
#if 0
sendto_one(source_p, form_str(RPL_WHOWASREAL),
me.name, source_p->name, temp->name,
"<untracked>", temp->sockhost);
#else
sendto_one_numeric(source_p, RPL_WHOISACTUALLY,
form_str(RPL_WHOISACTUALLY),
temp->name, temp->sockhost);
#endif
if (!EmptyString(temp->suser))
sendto_one_numeric(source_p, RPL_WHOISLOGGEDIN,
"%s %s :was logged in as",
temp->name, temp->suser);
sendto_one_numeric(source_p, RPL_WHOISSERVER,
form_str(RPL_WHOISSERVER),
temp->name, temp->servername,
rb_ctime(temp->logoff, tbuf, sizeof(tbuf)));
cur++;
found++;
}
if(max > 0 && cur >= max)
break;
}
if(!found)
sendto_one(source_p, form_str(ERR_WASNOSUCHNICK),
me.name, source_p->name, nick);
sendto_one(source_p, form_str(RPL_ENDOFWHOWAS),
me.name, source_p->name, parv[1]);
sendto_one_numeric(source_p, RPL_ENDOFWHOWAS, form_str(RPL_ENDOFWHOWAS), parv[1]);
return 0;
}