#ifdef RCS
static char rcsid[]="$Id: flood.c,v 1.1.1.1 2000/11/13 02:42:41 holsta Exp $";
#endif
/******************************************************************************
* Internetting Cooperating Programmers
* ----------------------------------------------------------------------------
*
* ____ PROJECT
* | _ \ __ _ _ __ ___ ___ _ __
* | | | |/ _` | '_ \ / __/ _ \ '__|
* | |_| | (_| | | | | (_| __/ |
* |____/ \__,_|_| |_|\___\___|_| the IRC bot
*
* All files in this archive are subject to the GNU General Public License.
*
* $Source: /cvsroot/dancer/dancer/src/flood.c,v $
* $Revision: 1.1.1.1 $
* $Date: 2000/11/13 02:42:41 $
* $Author: holsta $
* $State: Exp $
* $Locker: $
*
* ---------------------------------------------------------------------------
*****************************************************************************/
#include "dancer.h"
#include "trio.h"
#include "strio.h"
#include "transfer.h"
#include "user.h"
#include "flood.h"
#include "bans.h"
extern time_t now;
extern bool uppercheck; /* check users for uppercase violations! */
extern bool beepcheck; /* check users for beep violations! */
extern bool colourcheck; /* check users for colourcode violations! */
extern bool ctcpmode; /* CTCP flood checks */
extern bool mute;
extern long levels[];
extern itemguest *guestHead;
int floodrate, floodtime; /* 'floodrate' messages within 'floodtime' secs */
int floodrepeatrate, floodrepeattime; /* 'floodrepeatrate' repetitions within 'floodrepeattime' secs */
int floodbeeps;
int floodjoins; /* max amount of joins from the same hostpattern */
/****************************************************************************
* _ _ _ __ __ _
* / \ | | ___ _ __| |_| \/ | ___ __| | ___
* / _ \ | |/ _ \ '__| __| |\/| |/ _ \ / _` |/ _ \
* / ___ \| | __/ | | |_| | | | (_) | (_| | __/
* /_/ \_\_|\___|_| \__|_| |_|\___/ \__,_|\___|
*
***************************************************************************/
#define ALERT_TIMEOUT (10*60) /* at least 10 minutes from the last
alert ON */
/* --- AlertMode -------------------------------------------------- */
int AlertMode(Alert what)
{
static time_t alerted = 0;
static int level = 0;
switch (what) {
case ALERT_ON:
alerted = now;
level++;
break;
case ALERT_RED:
level += 100;
alerted = now;
break;
case ALERT_OFF:
if (alerted && ((now - alerted) > ALERT_TIMEOUT)) {
Log(LOG, "Alert Mode OFF");
alerted = 0;
level = 0;
}
return 0;
default:
break;
}
if ((level > 0) && (level < 100))
Logf(LOG, "Alert Mode level %d", level);
else if ((level >= 100) && (level < 1000))
Logf(LOG, "Alert Mode *RED* level %d", level);
return level;
}
/* --- Warning ---------------------------------------------------- */
bool Warning(itemguest *g, char *msg, char *kickmsg)
{
int level;
level = g->ident->user ? g->ident->user->level : 0;
if (level < FLOODMIDHIGH) {
g->warnings++;
if (level < FLOODLOWMID) {
/* low -> mid */
if (g->warnings > WARNLOW) {
StickyKick(g, (g->warnings > 1) ? GetDefaultText(msg_no_more_mr_nice_bot) : kickmsg);
g->warnings = 0;
return TRUE; /* Kicked */
}
}
else if (g->warnings > WARNMID) {
/* mid -> high */
StickyKick(g, (g->warnings > 1) ? GetDefaultText(msg_no_more_mr_nice_bot) : kickmsg);
g->warnings = 0;
return TRUE; /* Kicked */
}
if (!mute)
Actionf(GetDefaultText(msg_usually_kicks_X), msg, g->warnings, g->ident->nick);
} /* high -> inf */
return FALSE;
}
/* --- FloodCheck ------------------------------------------------- */
void FloodCheck(itemguest *g)
{
if ((now - g->posttime) <= floodtime) {
g->postsame++;
if (g->postsame >= floodrate)
Warning(g, GetDefaultText(msg_flooders), GetDefaultText(msg_no_flooding));
}
else
g->postsame = 0;
}
/* --- Check ------------------------------------------------------ */
void Check(itemguest *g, char *line)
{
long uppers = 0, beeps = 0, colours = 0;
long length;
if (NULL == line)
return;
for (length = 0; line[length]; length++) {
if (beepcheck && ('\x07' == line[length]))
beeps++;
if (colourcheck && ('\x03' == line[length]) && isdigit(line[length + 1]))
colours++;
if (uppercheck && isupper(line[length]))
uppers++;
}
if (beeps) {
if (beeps <= floodbeeps)
Warning(g, GetDefaultText(msg_beepers), GetDefaultText(msg_kickmsg_no_beepers));
else
StickyKick(g, GetDefaultText(msg_kickmsg_no_beepers));
}
if (colours) {
Warning(g, GetDefaultText(msg_colour_users), GetDefaultText(msg_kickmsg_no_colours));
}
if (uppers && (length > 10)) {
if (uppers*1000/length > 750) /* This is a serious uppercase violation */
Warning(g, GetDefaultText(msg_shouters), GetDefaultText(msg_no_shouting));
}
}
/* --- RepeatCheck ------------------------------------------------ */
void RepeatCheck(itemguest *g, char *line)
{
unsigned long hash = 0;
if (NULL == line)
return;
while (*line)
hash = (hash<<1) + *line++;
if ((hash == g->hashpost) && ((now - g->hashtime) <= floodrepeattime)) {
g->hashsame++;
if (g->hashsame >= floodrepeatrate)
Warning(g, GetDefaultText(msg_repeaters), GetDefaultText(msg_no_repeaters));
}
else {
g->hashpost = hash;
g->hashtime = now;
g->hashsame = 1;
}
}
/* --- AvalanceCheck ---------------------------------------------- */
void AvalanceCheck(itemguest *g, char *param)
{
char c;
int cntone = 0, cntesc = 0, cntbeep = 0;
if (NULL == param)
return;
while (c = *param++) {
switch (c) {
case '\001':
cntone++;
break;
case '\x1b':
if ('\026' == *param)
cntesc++;
break;
case '\007':
cntbeep++;
break;
default:
break;
}
}
if (cntone > 5) { /* Kick without warning */
StickyKick(g, GetDefaultText(msg_ctcp_bomb_detected));
}
else if (cntesc > 4) {
StickyKick(g, GetDefaultText(msg_tsunami_detected));
}
else if (cntbeep > 5) {
StickyKick(g, GetDefaultText(msg_beep_flood_detected));
}
}
/* --- CTCPFloodCheck --------------------------------------------- */
/* Number of codes */
#define MAX_ACTION 6
#define MAX_CTCP 3
/* Shortest time interval the MAX number of codes are accepted to flood */
#define TIME_ACTION 4
#define TIME_CTCP 6
bool CTCPFloodCheck(itemguest *g, bool action)
{
bool flooding = FALSE;
static int actcp = 0;
static int nctcp = 0;
int compare = 999;
int tmp;
static time_t atime[MAX_ACTION];
static time_t ntime[MAX_CTCP];
if (action) {
tmp = actcp % MAX_ACTION;
atime[tmp] = now;
if (actcp < (MAX_ACTION - 1))
tmp = -1;
actcp++;
}
else {
tmp = nctcp % MAX_CTCP;
ntime[tmp] = now;
if (nctcp < (MAX_CTCP - 1))
tmp = -1;
nctcp++;
}
if (tmp >= 0) {
/* Compare to fetch a possible hit */
if (action) {
#if 0
int n;
for (n=0; n < MAX_ACTION; n++) {
fprintf(stderr, "(%d) %d ", n, now - atime[n]);
}
fprintf(stderr, "\nnow %d <-> %d\n",
tmp, (tmp + 1) % MAX_ACTION);
#endif
compare = now - atime[(tmp + 1) % MAX_ACTION];
}
else {
compare = now - ntime[(tmp + 1) % MAX_CTCP];
}
}
/* Now we have a time to compare with */
if (g) {
if (action) {
if (compare <= TIME_ACTION)
flooding = TRUE;
}
else {
if (compare <= TIME_CTCP)
flooding = TRUE;
}
if (flooding) {
#if 0
StrFormatMax(buf, sizeof(buf), "Flood: CTCP%s flood by %s!%s",
action ? " ACTION" : "", g->ident->nick,
g->ident->host);
Multicast(REPORTCAST, buf);
#endif
if (ctcpmode && !action) {
/* Don't do this on ACTION floods, but we can still report ACTION
floods to trigger ignore */
Warning(g, "CTCP flooders", "CTCP flood detected");
}
}
}
else /* A ctcp request from outside the channel */
flooding = TRUE; /* Not really flooding, but we ignore it */
return flooding;
}
/* --- MultiCheck ------------------------------------------------- */
/*
* This should kick users that try to join using the same user account
* for the Xth time.
*/
void MultiCheck(char *domain)
{
int count = 0; /* None so far */
itemguest *g;
if (domain) {
for (g = First(guestHead); g; g = Next(g)) {
if (StrEqual(g->ident->userdomain, domain) &&
((g->ident->level < LEVELEXPERT) || !g->flags.chanop))
count++; /* Count this */
}
if (count > floodjoins) {
AlertMode(ALERT_ON);
for (g = First(guestHead); g; g = Next(g)) {
if (StrEqual(g->ident->userdomain, domain) &&
((g->ident->level < LEVELEXPERT) || !g->flags.chanop))
StickyKick(g, "*bang* too many joined users");
}
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1