added BotNet scanner to NeonSpam
authorpk910 <philipp@zoelle1.de>
Thu, 20 Oct 2011 23:19:14 +0000 (01:19 +0200)
committerpk910 <philipp@zoelle1.de>
Thu, 20 Oct 2011 23:19:14 +0000 (01:19 +0200)
src/bot_NeonSpam.c
src/bot_NeonSpam.h
src/cmd_neonspam_set.c
src/event_neonspam_chanmsg.c

index 5a200c1f3dd5ef7d8f1b93e787fe214bf93424dd..fdfd9147a7ab947742757cd755a42423f19ce52e 100644 (file)
@@ -52,12 +52,14 @@ static struct NeonSpamJoinNode *getNeonSpamJoinNode(struct ChanUser *chanuser);
 #define SPAMSERV_CHECK_IGNORE 0
 #define SPAMSERV_CHECK_WARN   1
 #define SPAMSERV_CHECK_PUNISH 2
+#define SPAMSERV_CHECK_DEAD   3 /* scanner has already killed the user */
 
 #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 channel rules"
+#define SPAMSERV_MSG_BOTNET     "BotNet detected."
 
 //EVENTS
 #include "event_neonspam_join.c"
@@ -155,6 +157,10 @@ static int loadNeonSpamSettings(struct ChanNode *chan) {
     settings->join_time = atoi(row[5] ? row[5] : defaults[5]);
     settings->exceptlevel = atoi(row[6] ? row[6] : defaults[6]);
     settings->join_nodes = NULL;
+    settings->lastmsg_time = 0;
+    int i;
+    for(i = 0; i < BOTNETSCAN_USERS; i++) 
+        settings->botnicks[i] = NULL;
     chan->spam_settings = settings;
     return 1;
 }
index 838a570a4dc6c5475328f3869beb7a3b5eb51c33..77fb4eefc07da03771581e14480a60fe7ab85be8 100644 (file)
 
 #include "main.h"
 
-#define SPAMSETTINGS_SPAMSCAN  0x01
-#define SPAMSETTINGS_FLOODSCAN 0x02
-#define SPAMSETTINGS_JOINSCAN  0x04
-#define SPAMSETTINGS_SCANOPS   0x08
-#define SPAMSETTINGS_SCANVOICE 0x10
+#define SPAMSETTINGS_SPAMSCAN       0x0001
+#define SPAMSETTINGS_FLOODSCAN      0x0002
+#define SPAMSETTINGS_JOINSCAN       0x0004
+#define SPAMSETTINGS_SCANOPS        0x0008
+#define SPAMSETTINGS_SCANVOICE      0x0010
+#define SPAMSETTINGS_BOTNETSCAN     0x0020
+#define SPAMSETTINGS_KICKEDBOTQUEUE 0x0040
 
 #define MAX_FLOOD_AMOUNT 300
 #define MIN_FLOOD_AMOUNT 2
@@ -34,6 +36,9 @@
 #define MIN_JOIN_AMOUNT 2
 #define MAX_JOIN_TIME   200
 
+#define BOTNETSCAN_USERS 4
+#define BOTNETSCAN_TIME 2
+
 struct NeonSpamSettings {
     unsigned int flags;
     unsigned char spam_amount;
@@ -42,7 +47,16 @@ struct NeonSpamSettings {
     unsigned char join_amount;
     unsigned char join_time;
     unsigned int exceptlevel : 10;
+    
+    //joinflood
     struct NeonSpamJoinNode *join_nodes;
+    
+    //botnet
+    unsigned long lastmsg; //crc32 hash
+    time_t lastmsg_time;
+    char *botnicks[BOTNETSCAN_USERS];
+    
+    
 };
 /* PENALTY SYSTEM
 * user gets MAX_FLOOD_TIME points per message
index 7907dba0e6f9a0c9fcbc7a2ee7e7cc80f5840b2d..41e78253c473421a2a52a2703fa9c5b8fa56ab99 100644 (file)
@@ -27,6 +27,7 @@ static char* neonspam_cmd_setjoinfloodreaction(struct ClientSocket *client, stru
 static char* neonspam_cmd_setspamscan(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *cvalue, char *argument);
 static char* neonspam_cmd_setfloodscan(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *cvalue, char *argument);
 static char* neonspam_cmd_setjoinfloodscan(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *cvalue, char *argument);
+static char* neonspam_cmd_setbotnetscan(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *cvalue, char *argument);
 static char* neonspam_cmd_setscanchanops(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *cvalue, char *argument);
 static char* neonspam_cmd_setscanvoiced(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *cvalue, char *argument);
 static char* neonspam_cmd_setexceptlevel(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *cvalue, char *argument);
@@ -63,6 +64,7 @@ static const struct {
     {"SpamScan",          NULL,  NS_VALID_BOOLEAN | NS_VALID_FUNCTION,              NULL, neonspam_cmd_setspamscan},
     {"FloodScan",         NULL,  NS_VALID_BOOLEAN | NS_VALID_FUNCTION,              NULL, neonspam_cmd_setfloodscan},
     {"JoinFloodScan",     NULL,  NS_VALID_BOOLEAN | NS_VALID_FUNCTION,              NULL, neonspam_cmd_setjoinfloodscan},
+    {"BotNetScan",        NULL,  NS_VALID_BOOLEAN | NS_VALID_FUNCTION,              NULL, neonspam_cmd_setbotnetscan},
     {"ScanChanOps",       NULL,  NS_VALID_BOOLEAN | NS_VALID_FUNCTION,              NULL, neonspam_cmd_setscanchanops},
     {"ScanVoiced",        NULL,  NS_VALID_BOOLEAN | NS_VALID_FUNCTION,              NULL, neonspam_cmd_setscanvoiced},
     {"ExceptLevel",       NULL,  NS_VALID_ACCESS | NS_VALID_FUNCTION,               NULL, neonspam_cmd_setexceptlevel},
@@ -433,6 +435,26 @@ static char* neonspam_cmd_setjoinfloodscan(struct ClientSocket *client, struct U
     return cvalue;
 }
 
+static char* neonspam_cmd_setbotnetscan(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *cvalue, char *argument) {
+    if(!cvalue) {
+        //get current value
+        cvalue = ((atoi(neonspam_settings_row[0] ? neonspam_settings_row[0] : neonspam_settings_defaults[0]) & SPAMSETTINGS_BOTNETSCAN) ? "1" : "0");
+    }
+    else if(argument) {
+        //change value
+        int cflags = atoi((neonspam_settings_row[0] ? neonspam_settings_row[0] : neonspam_settings_defaults[0]));
+        if(!strcmp(argument, "0"))
+            cflags &= ~SPAMSETTINGS_BOTNETSCAN;
+        else
+            cflags |= SPAMSETTINGS_BOTNETSCAN;
+        printf_mysql_query("UPDATE `channels` SET `channel_scanstate` = '%d' WHERE `channel_id` = '%d' ", cflags, chan->channel_id);
+        cvalue = argument;
+        if(chan->spam_settings)
+            chan->spam_settings->flags = cflags;
+    }
+    return cvalue;
+}
+
 static char* neonspam_cmd_setscanchanops(struct ClientSocket *client, struct UserNode *user, struct ChanNode *chan, struct Event *event, const char *setting, char *cvalue, char *argument) {
     if(!cvalue) {
         //get current value
index f55635a0e08b5c8608db34234db265345642a286..7bcd4b5016dcc6526cb31cee7f0d147c88791bed 100644 (file)
@@ -17,6 +17,7 @@
 
 static int neonspam_spamscan(struct NeonSpamSettings *settings, struct ChanUser *chanuser, char *message);
 static int neonspam_floodscan(struct NeonSpamSettings *settings, struct ChanUser *chanuser);
+static int neonspam_botnetscan(struct ClientSocket *client, struct NeonSpamSettings *settings, struct ChanUser *chanuser, char *message);
 
 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);
@@ -87,6 +88,15 @@ static void neonspam_event_chanmsg(struct UserNode *user, struct ChanNode *chan,
                 break;
         }
     }
+    if(action != SPAMSERV_CHECK_PUNISH && (settings->flags & SPAMSETTINGS_BOTNETSCAN)) {
+        result = neonspam_botnetscan(client, settings, chanuser, message);
+        switch(result) {
+            case SPAMSERV_CHECK_DEAD:
+                return;
+            case SPAMSERV_CHECK_IGNORE:
+                break;
+        }
+    }
     //some other checks?
     
     if(action != SPAMSERV_CHECK_IGNORE) {
@@ -126,21 +136,26 @@ static void neonspam_event_chanmsg_punish(struct ClientSocket *client, struct Ch
     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);
-        if(!row[0]) {
-            printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_name` = 'defaults'", reaction);
+        int reactionid;
+        if(!(reactionid = atoi(reaction))) {
+            MYSQL_RES *res;
+            MYSQL_ROW row;
+            printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_id` = '%d'", reaction, chanuser->chan->channel_id);
             res = mysql_use();
             row = mysql_fetch_row(res);
+            if(!row[0]) {
+                printf_mysql_query("SELECT `%s` FROM `channels` WHERE `channel_name` = 'defaults'", reaction);
+                res = mysql_use();
+                row = mysql_fetch_row(res);
+            }
+            reactionid = atoi(row[0]);
         }
+            
         int duration = 0;
         char banmaskBuf[NICKLEN+USERLEN+HOSTLEN+3];
         char *banmask = NULL;
-        switch (atoi(row[0])) {
+        switch (reactionid) {
             case 2: //TIMEBAN: 3min
                 duration = 180;
             case 3: //TIMEBAN: 1h
@@ -212,4 +227,41 @@ static int neonspam_floodscan(struct NeonSpamSettings *settings, struct ChanUser
         return SPAMSERV_CHECK_IGNORE;
 }
 
-
+static int neonspam_botnetscan(struct ClientSocket *client, struct NeonSpamSettings *settings, struct ChanUser *chanuser, char *message) {
+    //crc32 hash of the message
+    unsigned long msghash = crc32(message);
+    if((time(0) - settings->lastmsg_time) > BOTNETSCAN_TIME || settings->lastmsg != msghash) {
+        int i;
+        for(i = 0; i < BOTNETSCAN_USERS; i++) {
+            if(settings->botnicks[i]) {
+                free(settings->botnicks[i]);
+                settings->botnicks[i] = NULL;
+            }
+        }
+        settings->flags &= ~SPAMSETTINGS_KICKEDBOTQUEUE;
+        settings->lastmsg = msghash;
+    } else if(settings->lastmsg == msghash) {
+        int i;
+        for(i = 0; i < BOTNETSCAN_USERS; i++) {
+            if(!settings->botnicks[i]) {
+                settings->botnicks[i] = strdup(chanuser->user->nick);
+                break;
+            } else if(!stricmp(chanuser->user->nick, settings->botnicks[i])) {
+                return SPAMSERV_CHECK_IGNORE;
+            }
+        }
+        if(i == BOTNETSCAN_USERS) {
+            //BOTNETSCAN_USERS exceeded
+            if(!(settings->flags & SPAMSETTINGS_KICKEDBOTQUEUE)) {
+                for(i = 0; i < BOTNETSCAN_USERS; i++) {
+                    putsock(client, "KICK %s %s :%s", chanuser->chan->name, settings->botnicks[i], SPAMSERV_MSG_BOTNET);
+                }
+                settings->flags |= SPAMSETTINGS_KICKEDBOTQUEUE;
+            }
+            putsock(client, "KICK %s %s :%s", chanuser->chan->name, chanuser->user->nick, SPAMSERV_MSG_BOTNET);
+            return SPAMSERV_CHECK_DEAD;
+        }
+    }
+    settings->lastmsg_time = time(0);
+    return SPAMSERV_CHECK_IGNORE;
+}