573 lines
12 KiB
C
573 lines
12 KiB
C
/* @(#)$Id: ignore.c,v 1.19 2000/10/24 16:04:24 seks Exp $ */
|
|
|
|
/* Undernet Channel Service (X)
|
|
* Copyright (C) 1995-2002 Robin Thellend
|
|
*
|
|
* 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
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* 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 USA
|
|
*
|
|
* The author can be contact by email at <csfeedback@robin.pfft.net>
|
|
*
|
|
* Please note that this software is unsupported and mostly
|
|
* obsolete. It was replaced by GNUworld/CMaster. See
|
|
* http://gnuworld.sourceforge.net/ for more information.
|
|
*/
|
|
|
|
#include "h.h"
|
|
|
|
typedef struct aprivmsg
|
|
{
|
|
char user[200];
|
|
time_t time;
|
|
int length;
|
|
struct aprivmsg *next;
|
|
}
|
|
aprivmsg;
|
|
|
|
typedef struct aignore
|
|
{
|
|
char mask[200];
|
|
time_t time;
|
|
struct aignore *next;
|
|
}
|
|
aignore;
|
|
|
|
|
|
static aprivmsg *MessageList = NULL;
|
|
static aprivmsg *FloodList = NULL;
|
|
static aprivmsg *AddUserFloodList = NULL;
|
|
static aignore *IgnoreList = NULL;
|
|
|
|
void add_silence(char *, char *);
|
|
void rem_silence(char *);
|
|
|
|
int CheckPrivateFlood(char *source, int length, char *type)
|
|
{
|
|
char buffer[200];
|
|
char userhost[200];
|
|
char global[] = "*";
|
|
register aluser *user;
|
|
register aprivmsg *msg, *prev;
|
|
register int count, size;
|
|
|
|
if ((user = ToLuser(source)) == NULL)
|
|
{
|
|
sprintf(buffer, "ERROR! CheckPrivateFlood(): %s not found", source);
|
|
log(buffer);
|
|
return 1;
|
|
}
|
|
|
|
/* Don't check flood from admins */
|
|
if (IsValid(user, global) && Access(global, source) >= 1)
|
|
return 0;
|
|
|
|
if (!strcasecmp(user->username, DEFAULT_USERNAME) &&
|
|
!strcasecmp(user->site, DEFAULT_HOSTNAME))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* clean messages older than 30 seconds */
|
|
prev = NULL;
|
|
msg = MessageList;
|
|
while (msg != NULL)
|
|
{
|
|
if (msg->time < (now - 30))
|
|
{
|
|
if (prev)
|
|
{
|
|
prev->next = msg->next;
|
|
TTLALLOCMEM -= sizeof(aprivmsg);
|
|
free(msg);
|
|
msg = prev->next;
|
|
}
|
|
else
|
|
{
|
|
MessageList = msg->next;
|
|
TTLALLOCMEM -= sizeof(aprivmsg);
|
|
free(msg);
|
|
msg = MessageList;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
prev = msg;
|
|
msg = msg->next;
|
|
}
|
|
}
|
|
|
|
/* now add the current message in the list */
|
|
sprintf(userhost, "%s@%s", user->username, user->site);
|
|
msg = (aprivmsg *) MALLOC(sizeof(aprivmsg));
|
|
strcpy(msg->user, userhost);
|
|
msg->time = now;
|
|
msg->length = length;
|
|
msg->next = MessageList;
|
|
MessageList = msg;
|
|
|
|
/* count how many messages were received from that user
|
|
* and also how many bytes
|
|
*/
|
|
count = size = 0;
|
|
for (msg = MessageList; msg != NULL; msg = msg->next)
|
|
{
|
|
if (compare(userhost, msg->user))
|
|
{
|
|
count++;
|
|
size += msg->length;
|
|
}
|
|
}
|
|
|
|
if (count >= PRIVATE_FLOOD_RATE || size >= PRIVATE_FLOOD_SIZE)
|
|
{
|
|
#ifdef DEBUG
|
|
printf("FLOODED by %s!%s\n", user->nick, userhost);
|
|
#endif
|
|
if (!IsIgnored(source))
|
|
{
|
|
sprintf(buffer, "%sFLOOD from %s!%s", type, user->nick, userhost);
|
|
log(buffer);
|
|
|
|
sprintf(buffer, "%sFLOOD from %s!%s (%s)", type,
|
|
user->nick, userhost, user->server->name);
|
|
broadcast(buffer, 1);
|
|
}
|
|
MakeBanMask(user, buffer);
|
|
AddIgnore(source, buffer, IGNORE_TIME);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void AddIgnore(char *source, char *mask, int t)
|
|
{
|
|
char buffer[200];
|
|
char *site;
|
|
aignore *curr;
|
|
int count;
|
|
|
|
if (IsIgnored(source))
|
|
return;
|
|
|
|
/* count number of ignores from the same site */
|
|
site = strchr(mask, '@') + 1;
|
|
count = 0;
|
|
curr = IgnoreList;
|
|
while (curr)
|
|
{
|
|
if (!mycasecmp(strchr(curr->mask, '@') + 1, site))
|
|
count++;
|
|
curr = curr->next;
|
|
}
|
|
|
|
/* add the entry in the list */
|
|
curr = (aignore *) MALLOC(sizeof(aignore));
|
|
curr->time = now + t;
|
|
curr->next = IgnoreList;
|
|
IgnoreList = curr;
|
|
strcpy(curr->mask, mask);
|
|
|
|
add_silence(source, curr->mask);
|
|
notice(source, "I don't like being flooded! "
|
|
"I will ignore you from now on.");
|
|
|
|
/* schedule ignore removal */
|
|
AddEvent(EVENT_CLEAN_IGNORES, curr->time, "");
|
|
|
|
/* If there are already too many ignores from this site
|
|
* ignore the whole site
|
|
*/
|
|
if (count >= (MAX_IGNORE_PER_SITE - 1))
|
|
{
|
|
curr = (aignore *) MALLOC(sizeof(aignore));
|
|
curr->time = now + 300;
|
|
curr->next = IgnoreList;
|
|
IgnoreList = curr;
|
|
|
|
#ifdef DEBUG
|
|
printf("TOO MANY IGNORES FROM THE SAME SITE\n");
|
|
#endif
|
|
log("Too many ignores.. ignoring the whole site");
|
|
sprintf(curr->mask, "*!*@%s", site);
|
|
sprintf(buffer, "Ignoring the whole site! (%s)", site);
|
|
broadcast(buffer, 1);
|
|
add_silence(source, curr->mask);
|
|
AddEvent(EVENT_CLEAN_IGNORES, curr->time, "");
|
|
}
|
|
}
|
|
|
|
void CleanIgnores(void)
|
|
{
|
|
char buffer[200];
|
|
aignore *curr, *prev;
|
|
|
|
prev = NULL;
|
|
curr = IgnoreList;
|
|
while (curr != NULL)
|
|
{
|
|
if (curr->time <= now)
|
|
{
|
|
sprintf(buffer, "Removing ignore for %s", curr->mask);
|
|
log(buffer);
|
|
rem_silence(curr->mask);
|
|
if (prev != NULL)
|
|
{
|
|
prev->next = curr->next;
|
|
TTLALLOCMEM -= sizeof(aignore);
|
|
free(curr);
|
|
curr = prev->next;
|
|
}
|
|
else
|
|
{
|
|
IgnoreList = curr->next;
|
|
TTLALLOCMEM -= sizeof(aignore);
|
|
free(curr);
|
|
curr = IgnoreList;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
prev = curr;
|
|
curr = curr->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
int IsIgnored(char *nick)
|
|
{
|
|
char userhost[200];
|
|
register aignore *curr;
|
|
register aluser *user;
|
|
register int found = 0;
|
|
|
|
if ((user = ToLuser(nick)) == NULL)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
sprintf(userhost, "%s!%s@%s", user->nick, user->username, user->site);
|
|
|
|
curr = IgnoreList;
|
|
while (curr != NULL && !found)
|
|
{
|
|
if (compare(userhost, curr->mask))
|
|
{
|
|
add_silence(nick, curr->mask);
|
|
found++;
|
|
}
|
|
curr = curr->next;
|
|
}
|
|
|
|
return (found);
|
|
}
|
|
|
|
void ShowIgnoreList(char *source, char *channel, char *args)
|
|
{
|
|
char buffer[200];
|
|
aignore *curr = IgnoreList;
|
|
time_t m;
|
|
|
|
if (curr == NULL)
|
|
{
|
|
notice(source, "Ignore list is empty");
|
|
}
|
|
else
|
|
{
|
|
notice(source, "Ignore list:");
|
|
while (curr != NULL)
|
|
{
|
|
m = (curr->time - now) / 60 + 1;
|
|
sprintf(buffer, "%s for %ld minute%s",
|
|
curr->mask, m, (m > 1) ? "s" : "");
|
|
notice(source, buffer);
|
|
curr = curr->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
void add_silence(char *nick, char *mask)
|
|
{
|
|
char buffer[200];
|
|
|
|
sprintf(buffer, ":%s SILENCE %s :%s\n", mynick, nick, mask);
|
|
sendtoserv(buffer);
|
|
#ifdef FAKE_UWORLD
|
|
if (Uworld_status == 1)
|
|
{
|
|
sprintf(buffer, ":%s SILENCE %s :%s\n", UFAKE_NICK, nick, mask);
|
|
sendtoserv(buffer);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void rem_silence(char *mask)
|
|
{
|
|
char buffer[200];
|
|
|
|
sprintf(buffer, ":%s SILENCE * -%s\n", mynick, mask);
|
|
sendtoserv(buffer);
|
|
#ifdef FAKE_UWORLD
|
|
if (Uworld_status == 1)
|
|
{
|
|
sprintf(buffer, ":%s SILENCE * -%s\n", UFAKE_NICK, mask);
|
|
sendtoserv(buffer);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
int CheckFloodFlood(char *source, int length)
|
|
{
|
|
char buffer[200];
|
|
char userhost[200];
|
|
char global[] = "*";
|
|
register aluser *user;
|
|
register aprivmsg *msg, *prev;
|
|
register int count, size;
|
|
|
|
if ((user = ToLuser(source)) == NULL)
|
|
{
|
|
sprintf(buffer, "ERROR! CheckFloodFlood(): %s not found", source);
|
|
log(buffer);
|
|
return 1;
|
|
}
|
|
|
|
/* Don't check flood from admins */
|
|
if (IsValid(user, global) && Access(global, source) >= 1)
|
|
return 0;
|
|
|
|
if (!strcasecmp(user->username, DEFAULT_USERNAME) &&
|
|
!strcasecmp(user->site, DEFAULT_HOSTNAME))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* clean messages older than 30 seconds */
|
|
prev = NULL;
|
|
msg = FloodList;
|
|
while (msg != NULL)
|
|
{
|
|
if (msg->time < (now - 30))
|
|
{
|
|
if (prev)
|
|
{
|
|
prev->next = msg->next;
|
|
TTLALLOCMEM -= sizeof(aprivmsg);
|
|
free(msg);
|
|
msg = prev->next;
|
|
}
|
|
else
|
|
{
|
|
FloodList = msg->next;
|
|
TTLALLOCMEM -= sizeof(aprivmsg);
|
|
free(msg);
|
|
msg = FloodList;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
prev = msg;
|
|
msg = msg->next;
|
|
}
|
|
}
|
|
|
|
/* now add the current message in the list */
|
|
sprintf(userhost, "%s@%s", user->username, user->site);
|
|
msg = (aprivmsg *) MALLOC(sizeof(aprivmsg));
|
|
strcpy(msg->user, userhost);
|
|
msg->time = now;
|
|
msg->length = length;
|
|
msg->next = FloodList;
|
|
FloodList = msg;
|
|
|
|
/* count how many messages were received from that user
|
|
* and also how many bytes
|
|
*/
|
|
count = size = 0;
|
|
for (msg = FloodList; msg != NULL; msg = msg->next)
|
|
{
|
|
if (compare(userhost, msg->user))
|
|
{
|
|
count++;
|
|
size += msg->length;
|
|
}
|
|
}
|
|
|
|
if (count >= FLOOD_FLOOD_RATE || size >= FLOOD_FLOOD_SIZE)
|
|
{
|
|
if (!IsIgnored(source))
|
|
{
|
|
sprintf(buffer, "OUTPUT-FLOOD from %s!%s", user->nick, userhost);
|
|
log(buffer);
|
|
|
|
sprintf(buffer, "OUTPUT-FLOOD from %s!%s (%s)",
|
|
user->nick, userhost, user->server->name);
|
|
broadcast(buffer, 1);
|
|
}
|
|
MakeBanMask(user, buffer);
|
|
AddIgnore(source, buffer, FLOOD_FLOOD_IGNORE);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int CheckAdduserFlood(char *source, char *channel)
|
|
{
|
|
char buffer[200];
|
|
char userhost[200];
|
|
char global[] = "*";
|
|
register aluser *user;
|
|
register aprivmsg *msg, *prev;
|
|
register int count;
|
|
|
|
if ((user = ToLuser(source)) == NULL)
|
|
{
|
|
sprintf(buffer, "ERROR! CheckAdduserFlood(): %s not found", source);
|
|
log(buffer);
|
|
return 1;
|
|
}
|
|
|
|
/* Don't check flood from admins */
|
|
if (IsValid(user, global) && Access(global, source) >= 1)
|
|
return 0;
|
|
|
|
if (!strcasecmp(user->username, DEFAULT_USERNAME) &&
|
|
!strcasecmp(user->site, DEFAULT_HOSTNAME))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* clean messages older than 1 hour */
|
|
prev = NULL;
|
|
msg = AddUserFloodList;
|
|
while (msg != NULL)
|
|
{
|
|
if (msg->time < (now - 3600))
|
|
{
|
|
if (prev)
|
|
{
|
|
prev->next = msg->next;
|
|
TTLALLOCMEM -= sizeof(aprivmsg);
|
|
free(msg);
|
|
msg = prev->next;
|
|
}
|
|
else
|
|
{
|
|
AddUserFloodList = msg->next;
|
|
TTLALLOCMEM -= sizeof(aprivmsg);
|
|
free(msg);
|
|
msg = AddUserFloodList;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
prev = msg;
|
|
msg = msg->next;
|
|
}
|
|
}
|
|
|
|
sprintf(userhost, "%s@%s", user->username, user->site);
|
|
|
|
/* now add the current message in the list */
|
|
msg = (aprivmsg *) MALLOC(sizeof(aprivmsg));
|
|
strcpy(msg->user, channel);
|
|
msg->time = now;
|
|
msg->length = 0;
|
|
msg->next = AddUserFloodList;
|
|
AddUserFloodList = msg;
|
|
|
|
/* count how many messages were received from that user
|
|
* and also how many bytes
|
|
*/
|
|
count = 0;
|
|
for (msg = AddUserFloodList; msg != NULL; msg = msg->next)
|
|
{
|
|
if (!strcmp(channel, msg->user))
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if (count >= 20)
|
|
{
|
|
if (!IsIgnored(source))
|
|
{
|
|
sprintf(buffer, "ADDUSER-FLOOD from %s!%s [%s]", user->nick, userhost, channel);
|
|
log(buffer);
|
|
|
|
sprintf(buffer, "ADDUSER-FLOOD from %s!%s [%s] (%s)",
|
|
user->nick, userhost, channel, user->server->name);
|
|
broadcast(buffer, 1);
|
|
}
|
|
MakeBanMask(user, buffer);
|
|
AddIgnore(source, buffer, 120);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void AdminRemoveIgnore(char *source, char *ch, char *args)
|
|
{
|
|
char mask[200], global[] = "*";
|
|
char buffer[200];
|
|
aignore **curr, *tmp;
|
|
int change = 0;
|
|
|
|
if (Access(global, source) < XADMIN_LEVEL)
|
|
{
|
|
ReplyNotAccess(source, global);
|
|
return;
|
|
}
|
|
|
|
GetWord(0, args, mask);
|
|
|
|
if (!*mask)
|
|
{
|
|
notice(source, "SYNTAX: remignore <mask|all>");
|
|
return;
|
|
}
|
|
|
|
curr = &IgnoreList;
|
|
while (*curr != NULL)
|
|
{
|
|
if (!strcasecmp((*curr)->mask, mask) || !strcasecmp(mask, "all"))
|
|
{
|
|
change = 1;
|
|
sprintf(buffer, "removed %s", (*curr)->mask);
|
|
notice(source, buffer);
|
|
log(buffer);
|
|
rem_silence((*curr)->mask);
|
|
|
|
tmp = *curr;
|
|
*curr = tmp->next;
|
|
|
|
free(tmp);
|
|
TTLALLOCMEM -= sizeof(aignore);
|
|
}
|
|
else
|
|
{
|
|
curr = &(*curr)->next;
|
|
}
|
|
}
|
|
|
|
if (change)
|
|
{
|
|
sprintf(buffer, "%s removed ignore for [%s]", source, mask);
|
|
broadcast(buffer, 1);
|
|
}
|
|
}
|