From 81650024ec40499e95c699987eebe9da32b7f9d4 Mon Sep 17 00:00:00 2001 From: pk910 Date: Thu, 20 Oct 2011 14:16:08 +0200 Subject: [PATCH] added spam/flood punishments --- src/bot_NeonSpam.c | 6 +- src/bot_NeonSpam.h | 2 +- src/cmd_neonspam_set.c | 2 + src/event_neonspam_chanmsg.c | 119 ++++++++++++++++++++++++++++++++--- 4 files changed, 119 insertions(+), 10 deletions(-) diff --git a/src/bot_NeonSpam.c b/src/bot_NeonSpam.c index 2263488..d4a10d4 100644 --- a/src/bot_NeonSpam.c +++ b/src/bot_NeonSpam.c @@ -118,6 +118,7 @@ static void start_bots() { } static int loadNeonSpamSettings(struct ChanNode *chan) { + if(chan->spam_settings) return 0; struct NeonSpamSettings *settings = malloc(sizeof(*settings)); if(!settings) { perror("malloc() failed"); @@ -125,11 +126,11 @@ static int loadNeonSpamSettings(struct ChanNode *chan) { } MYSQL_RES *res; MYSQL_ROW row, defaults = NULL; - printf_mysql_query("SELECT `channel_scanstate`, `channel_maxrepeat`, `channel_maxflood`, `channel_floodtime`, `channel_maxjoin`, `channel_jointime` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id); + printf_mysql_query("SELECT `channel_scanstate`, `channel_maxrepeat`, `channel_maxflood`, `channel_floodtime`, `channel_maxjoin`, `channel_jointime`, `channel_scanexcept` FROM `channels` WHERE `channel_id` = '%d'", chan->channel_id); res = mysql_use(); row = mysql_fetch_row(res); if(!row[0] || !row[1] || !row[2] || !row[3] || !row[4] || !row[5]) { - printf_mysql_query("SELECT `channel_scanstate`, `channel_maxrepeat`, `channel_maxflood`, `channel_floodtime`, `channel_maxjoin`, `channel_jointime` FROM `channels` WHERE `channel_name` = 'defaults'"); + printf_mysql_query("SELECT `channel_scanstate`, `channel_maxrepeat`, `channel_maxflood`, `channel_floodtime`, `channel_maxjoin`, `channel_jointime`, `channel_scanexcept` FROM `channels` WHERE `channel_name` = 'defaults'"); res = mysql_use(); defaults = mysql_fetch_row(res); } @@ -139,6 +140,7 @@ static int loadNeonSpamSettings(struct ChanNode *chan) { settings->flood_time = atoi(row[3] ? row[3] : defaults[3]); settings->join_amount = atoi(row[4] ? row[4] : defaults[4]); settings->join_time = atoi(row[5] ? row[5] : defaults[5]); + settings->exceptlevel = atoi(row[6] ? row[6] : defaults[6]); chan->spam_settings = settings; return 1; } diff --git a/src/bot_NeonSpam.h b/src/bot_NeonSpam.h index 0fb2af4..d318682 100644 --- a/src/bot_NeonSpam.h +++ b/src/bot_NeonSpam.h @@ -41,7 +41,7 @@ struct NeonSpamSettings { unsigned char flood_time; unsigned char join_amount; unsigned char join_time; - + unsigned int exceptlevel : 10; }; /* PENALTY SYSTEM * user gets MAX_FLOOD_TIME points per message diff --git a/src/cmd_neonspam_set.c b/src/cmd_neonspam_set.c index 228867a..7907dba 100644 --- a/src/cmd_neonspam_set.c +++ b/src/cmd_neonspam_set.c @@ -482,6 +482,8 @@ static char* neonspam_cmd_setexceptlevel(struct ClientSocket *client, struct Use //change value printf_mysql_query("UPDATE `channels` SET `channel_scanexcept` = '%d' WHERE `channel_id` = '%d' ", atoi(argument), chan->channel_id); sprintf(cvalue, "%d", atoi(argument)); + if(chan->spam_settings) + chan->spam_settings->exceptlevel = atoi(argument); } return cvalue; } diff --git a/src/event_neonspam_chanmsg.c b/src/event_neonspam_chanmsg.c index 87ecdc6..bb47344 100644 --- a/src/event_neonspam_chanmsg.c +++ b/src/event_neonspam_chanmsg.c @@ -19,9 +19,27 @@ #define SPAMSERV_CHECK_WARN 1 #define SPAMSERV_CHECK_PUNISH 2 +#define SPAMSERV_MSG_SPAM "Spamming" +#define SPAMSERV_MSG_FLOOD "Flooding the channel/network" +#define SPAMSERV_MSG_ADV "Advertising" +#define SPAMSERV_MSG_JOINFLOOD "Join flooding the channel" +#define SPAMSERV_MSG_WARNING "%s is against the network rules" + static int neonspam_spamscan(struct NeonSpamSettings *settings, struct ChanUser *chanuser, char *message); static int neonspam_floodscan(struct NeonSpamSettings *settings, struct ChanUser *chanuser); +static USERAUTH_CALLBACK(neonspam_event_chanmsg_nick_lookup); +static void neonspam_event_chanmsg_punish(struct ClientSocket *client, struct ChanUser *chanuser, struct NeonSpamSettings *settings, int action, char *reason, char *reaction); + +struct neonspam_event_chanmsg_cache { + struct ClientSocket *client; + struct ChanUser *chanuser; + struct NeonSpamSettings *settings; + int action; + char *reason; + char *reaction; +}; + static void neonspam_event_chanmsg(struct UserNode *user, struct ChanNode *chan, char *message) { struct ClientSocket *client = getChannelBot(chan, BOTID); if(!client) return; //we can't "see" this event @@ -33,36 +51,123 @@ static void neonspam_event_chanmsg(struct UserNode *user, struct ChanNode *chan, //ignore messages from ops/voices if we ignore them if(!(settings->flags & SPAMSETTINGS_SCANOPS) && (chanuser->flags & CHANUSERFLAG_OPPED)) return; if(!(settings->flags & SPAMSETTINGS_SCANVOICE) && (chanuser->flags & CHANUSERFLAG_VOICED)) return; - + if(settings->exceptlevel == 0) return; //scan the message int result = 0; - if(settings->flags & SPAMSETTINGS_SPAMSCAN) { + int action = SPAMSERV_CHECK_IGNORE; + char reason[MAXLEN]; + char *reaction = NULL; + if(action != SPAMSERV_CHECK_PUNISH && (settings->flags & SPAMSETTINGS_SPAMSCAN)) { result = neonspam_spamscan(settings, chanuser, message); switch(result) { case SPAMSERV_CHECK_IGNORE: break; case SPAMSERV_CHECK_WARN: - reply(client, user, "SPAM WARNING!"); + if(action == SPAMSERV_CHECK_IGNORE) { + action = result; + sprintf(reason, SPAMSERV_MSG_WARNING, SPAMSERV_MSG_SPAM); + } break; case SPAMSERV_CHECK_PUNISH: - reply(client, user, "SPAM PUNISHMENT!"); + if(action != SPAMSERV_CHECK_PUNISH) { + action = result; + sprintf(reason, SPAMSERV_MSG_WARNING, SPAMSERV_MSG_SPAM); + reaction = "channel_repeatreaction"; + } break; } } - if(settings->flags & SPAMSETTINGS_FLOODSCAN) { + if(action != SPAMSERV_CHECK_PUNISH && (settings->flags & SPAMSETTINGS_FLOODSCAN)) { result = neonspam_floodscan(settings, chanuser); switch(result) { case SPAMSERV_CHECK_IGNORE: break; case SPAMSERV_CHECK_WARN: - reply(client, user, "FLOOD WARNING!"); + if(action == SPAMSERV_CHECK_IGNORE) { + action = result; + sprintf(reason, SPAMSERV_MSG_WARNING, SPAMSERV_MSG_SPAM); + } break; case SPAMSERV_CHECK_PUNISH: - reply(client, user, "FLOOD PUNISHMENT!"); + if(action != SPAMSERV_CHECK_PUNISH) { + action = result; + sprintf(reason, SPAMSERV_MSG_WARNING, SPAMSERV_MSG_SPAM); + reaction = "channel_floodreaction"; + } break; } } + //some other checks? + if(action != SPAMSERV_CHECK_IGNORE) { + //whois the user to check against exceptlevel + if((user->flags & USERFLAG_ISAUTHED) || settings->exceptlevel == 501) { + neonspam_event_chanmsg_punish(client, chanuser, settings, action, reason, reaction); + } else { + struct neonspam_event_chanmsg_cache *cache = malloc(sizeof(*cache)); + if (!cache) { + perror("malloc() failed"); + return; + } + cache->client = client; + cache->chanuser = chanuser; + cache->settings = settings; + cache->action = action; + cache->reason = strdup(reason); + cache->reaction = reaction; + get_userauth(user, neonspam_event_chanmsg_nick_lookup, cache); + } + + } +} + +static USERAUTH_CALLBACK(neonspam_event_chanmsg_nick_lookup) { + struct neonspam_event_chanmsg_cache *cache = data; + neonspam_event_chanmsg_punish(cache->client, cache->chanuser, cache->settings, cache->action, cache->reason, cache->reaction); + free(cache->reason); + free(cache); +} + +static void neonspam_event_chanmsg_punish(struct ClientSocket *client, struct ChanUser *chanuser, struct NeonSpamSettings *settings, int action, char *reason, char *reaction) { + int uaccess = 0; + if(chanuser->user->flags & USERFLAG_ISAUTHED) + uaccess = getChannelAccess(chanuser->user, chanuser->chan, 0); + if(uaccess >= settings->exceptlevel) return; + if(action == SPAMSERV_CHECK_WARN) { + reply(client, chanuser->user, "%s", reason); + } else if(action == SPAMSERV_CHECK_PUNISH) { + MYSQL_RES *res; + MYSQL_ROW row; + loadChannelSettings(chanuser->chan); + printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_id` = '%d'", reaction, chanuser->chan->channel_id); + res = mysql_use(); + row = mysql_fetch_row(res); + int duration = 0; + char banmaskBuf[NICKLEN+USERLEN+HOSTLEN+3]; + char *banmask = NULL; + switch (atoi(row[0])) { + case 2: //TIMEBAN: 3min + duration = 180; + case 3: //TIMEBAN: 1h + if(!duration) + duration = 3600; + banmask = generate_banmask(chanuser->user, banmaskBuf); + printf_mysql_query("INSERT INTO `bans` (`ban_channel`, `ban_mask`, `ban_triggered`, `ban_timeout`, `ban_owner`, `ban_reason`) VALUES ('%d', '%s', UNIX_TIMESTAMP(), '%lu', '%d', '%s')", chanuser->chan->channel_id, escape_string(banmask), (unsigned long) (time(0) + duration), 0, escape_string(reason)); + int banid = (int) mysql_insert_id(mysql_conn); + char nameBuf[MAXLEN]; + char banidBuf[20]; + sprintf(nameBuf, "ban_%d", banid); + sprintf(banidBuf, "%d", banid); + timeq_add_name(nameBuf, duration, channel_ban_timeout, strdup(banidBuf)); + case 1: //KICKBAN + if(!banmask) + banmask = generate_banmask(chanuser->user, banmaskBuf); + putsock(client, "MODE %s +b %s", chanuser->chan->name, banmask); + case 0: //KICK + putsock(client, "KICK %s %s :%s", chanuser->chan->name, chanuser->user->nick, reason); + break; + } + } } static int neonspam_spamscan(struct NeonSpamSettings *settings, struct ChanUser *chanuser, char *message) { -- 2.20.1