Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

spp_bait_and_switch.c

Go to the documentation of this file.
00001 /* $Id: spp_template.c,v 1.5 2004/02/13 16:19:03 roesch Exp $ */
00002 /* Snort Preprocessor Plugin Source File Template */
00003 
00004 /* spp_bait_and_switch 
00005  * 
00006  * Purpose:
00007  *
00008  * Based on Sticky-Drop the original Bait-and-switch project, and Snortsam, we want to really fuck with our attackers.  
00009  *
00010  * Arguments:
00011  *   
00012  *
00013  *
00014  */
00015 
00016 
00017 /* bait_and_switch is for inline */
00018 #ifdef GIDS
00019 #ifndef IPFW
00020 
00021 #include <sys/types.h>
00022 #include <stdlib.h>
00023 #include <ctype.h>
00024 #include <rpc/types.h>
00025 #include <string.h>
00026 #include <stdio.h>
00027 #include "generators.h"
00028 #include "event_wrapper.h"
00029 #include "assert.h"
00030 #include "util.h"
00031 #include "plugbase.h"
00032 #include "parser.h"
00033 #include "mempool.h"
00034 #include "plugbase.h"
00035 #include "mstring.h"
00036 #include "util.h"
00037 #include "log.h"
00038 #include "parser.h"
00039 #include "detect.h"
00040 #include "rules.h"
00041 #include "decode.h"
00042 #include "debug.h"
00043 #include "ubi_SplayTree.h"
00044 #include "ubi_BinTree.h"
00045 
00046 #ifndef WIN32
00047 #include <sys/socket.h>
00048 #include <netinet/in.h>
00049 #include <arpa/inet.h>
00050 #endif /* WIN32 */
00051 
00052 #include "spp_bait_and_switch.h"
00053 #include "inline.h"
00054 
00055 #define MAX_PORTS               64
00056 #define MEM_CHUNK               32
00057 #define DIRECTION_SOURCE        0
00058 #define DIRECTION_DST           1
00059 
00060 /* Data Used for Bait-and-Switch */
00061 typedef struct _BandS
00062 {
00063     ubi_trRoot attackerRoot;  /* this tree is for the reroute info */
00064     ubi_trRootPtr attackerRootPtr;
00065     MemPool AttackerPool;
00066     u_int32_t max_reroute_entries;
00067     char log;
00068     FILE *logfile;
00069     char *logpath;
00070     char iptpath[255];
00071     char iptcmd[255];
00072     char *insertmode;   
00073 } BandS;
00074 
00075 BandS bands;
00076 
00077 
00078 typedef struct _Attacker
00079 {
00080     ubi_trNode Node;             /* for the splay tree */
00081     MemBucket *bucket;
00082     u_int32_t attackerip;
00083     u_int32_t honeypotip;
00084     u_int32_t attackedip;
00085     u_int32_t timeout;
00086     struct timeval ruleaddtime;
00087     struct timeval ruledeletetime;
00088     char iptdnatcmd[255];
00089     char iptsnatcmd[255];
00090     char iptundnatcmd[255];
00091     char iptunsnatcmd[255];
00092 } Attacker;
00093 
00094 Attacker attacker;
00095 
00096 typedef struct _bashostNode
00097 {
00098     IpAddrSet *address;
00099     u_short hsp;         /* hi src port */
00100     u_short lsp;         /* lo src port */
00101     u_int32_t flags;     /* control flags */
00102     struct _bashostNode *nextNode;
00103 
00104 } basHostNode;
00105 
00106 basHostNode *basignoreList; /* for ignore-hosts */
00107 int num_ports_from;
00108 int num_ports_to;
00109 u_int32_t *basignorePortFrom;
00110 u_int32_t *basignorePortTo;
00111 
00112 static void BaitandSwitchInit(u_char *);
00113 static void ParseBaitandSwitchArgs(char *);
00114 void BaitAndSwitch(Packet *, void *);
00115 void BASLog(Packet *);
00116 
00117 static int IpAddressCompareFunction(ubi_trItemPtr, ubi_trNodePtr);
00118 static int PruneAttackers(u_int32_t now, int tokill, Attacker *saveme);
00119 static void BaitAndSwitchCleanExitFunction(int, void *);
00120 static void BaitAndSwitchRestartFunction(int, void *);
00121 
00122 /* For ignore hosts */
00123 void basInitIgnoreHosts(u_char *);
00124 IpAddrSet* basIgnoreAllocAddrNode(basHostNode *);
00125 void basScanParseIp(char *, basHostNode *);
00126 
00127 /* For ignore ports */
00128 void basInitIgnoreFrom(u_char *);
00129 void basInitIgnoreTo(u_char *);
00130 void basInitIgnorePorts(u_char *, u_int32_t **, int *);
00131 u_int32_t basScanParsePort(char *);
00132 
00133 int basIsIgnored(Packet *, char);
00134 int basAttackerSearch(Packet *, char);
00135 
00136 static int s_bas_running = 0;
00137  
00138 extern int do_detect;
00139 
00140 
00141 /*
00142  * Function: ()
00143  *
00144  * Purpose: Registers the preprocessor keyword and initialization 
00145  *          function into the preprocessor list.  This is the function that
00146  *          gets called from InitPreprocessors() in plugbase.c.
00147  *
00148  * Arguments: None.
00149  *
00150  * Returns: void function
00151  *
00152  */
00153 void SetupBaitAndSwitch()
00154 {
00155     /* 
00156      * link the preprocessor keyword to the init function in 
00157      * the preproc list 
00158      */
00159     RegisterPreprocessor("bait-and-switch", BaitandSwitchInit);
00160     RegisterPreprocessor("bait-and-switch-ignorehosts", basInitIgnoreHosts);
00161     RegisterPreprocessor("bait-and-switch-ignoreports-from", basInitIgnoreFrom);
00162     RegisterPreprocessor("bait-and-switch-ignoreports-to", basInitIgnoreTo);
00163     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Preprocessor: BaitAndSwitch is setup...\n"););
00164 }
00165 
00166 
00167 /*
00168  * Function: BaitAndSwitchInit(u_char *)
00169  *
00170  * Purpose: Calls the argument parsing function, performs final setup on data
00171  *          structs, links the preproc function into the function list.
00172  *
00173  * Arguments: args => ptr to argument string
00174  *
00175  * Returns: void function
00176  *
00177  */
00178 static void BaitandSwitchInit(u_char *args)
00179 {
00180     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Preprocessor: BaitAndSwitch Initialized\n"););
00181 
00182     memset(&bands, 0, sizeof(BandS));
00183     ParseBaitandSwitchArgs(args);
00184     bands.attackerRootPtr = &bands.attackerRoot;
00185 
00186     ubi_trInitTree(bands.attackerRootPtr, IpAddressCompareFunction, 0);
00187     if(mempool_init(&bands.AttackerPool , bands.max_reroute_entries, sizeof(Attacker)))
00188     {
00189       FatalError("ERROR: Could not alloc memory for baitandswitch entries\n");
00190     }
00191     else if(!InlineMode()) 
00192     {
00193       FatalError("ERROR: We have to be in InlineMode() to use baitandswitch\n"); 
00194     }
00195     
00196     s_bas_running = 1;
00197     if (system(savecmd) != 0) 
00198     {
00199         FatalError("ERROR: failed to save iptables state before Bait-And-Switch bailing\n");
00200     }
00201 
00202     AddFuncToPreprocList(BaitAndSwitch);
00203     AddFuncToCleanExitList(BaitAndSwitchCleanExitFunction, NULL);
00204     AddFuncToRestartList(BaitAndSwitchRestartFunction, NULL);
00205 }
00206 
00207 
00208 /*
00209  * Function: ParseBaitAndSwitchArgs(char *)
00210  *
00211  * Purpose: Process the preprocessor arguements from the rules file and 
00212  *          initialize the preprocessor's data struct.  This function doesn't
00213  *          have to exist if it makes sense to parse the args in the init 
00214  *          function.
00215  *
00216  * Arguments: args => argument list
00217  *
00218  * Returns: void function
00219  *
00220  */
00221 static void ParseBaitandSwitchArgs(char *args)
00222 {
00223     int num_toks, s_toks;
00224     char **toks = NULL;
00225     char **stoks;
00226     char **iptdirtoks;
00227     int num_iptdirtoks = 0;
00228     int i;
00229     char* index;
00230     char logpath[STD_BUF], tmp[STD_BUF];
00231     bands.insertmode="A";
00232     /* setup the defaults */
00233     strlcpy(logpath, pv.log_dir, STD_BUF);
00234     strlcpy(tmp, "/bands.log", STD_BUF);
00235     strlcat(logpath, tmp, STD_BUF);
00236  
00237     strlcpy(bands.iptpath,"/sbin",STD_BUF);
00238    
00239     if(snprintf(bands.iptcmd,sizeof(bands.iptcmd) -1,"%s/iptables",bands.iptpath) >= sizeof(bands.iptcmd))
00240     {
00241         FatalError("The iptcmd supplied is too long\n");
00242     }
00243     else if(snprintf(savecmd,sizeof(savecmd) -1,"%s/iptables-save > %s/iptables-rules",bands.iptpath,pv.log_dir) >= sizeof(savecmd))
00244     {
00245         FatalError("The iptsavecmd is too long\n");
00246     }
00247     else if(snprintf(restorecmd,sizeof(restorecmd) -1,"%s/iptables-restore < %s/iptables-rules",bands.iptpath,pv.log_dir) >= sizeof(restorecmd))
00248     {
00249         FatalError("The iptrestorecmd is too long\n");
00250     }
00251     else
00252     {
00253         LogMessage("default iptcmd is %s\n",bands.iptcmd);
00254         LogMessage("default iptsave is %s\n",savecmd);
00255         LogMessage("default iptrestore is %s\n",restorecmd);
00256     } 
00257     bands.max_reroute_entries = 100;
00258     bands.log = 0;
00259     if (args)
00260     {
00261 
00262         toks = mSplit(args, ",", 7, &num_toks, 0);
00263 
00264         i=0;
00265 
00266         while (i < num_toks)
00267         {
00268             index = toks[i];
00269 
00270             while(isspace((int)*index)) index++;
00271 
00272             stoks = mSplit(index, " ", 5, &s_toks, 0);
00273             if(!strcasecmp(stoks[0], "max_entries"))
00274             {
00275                 if(isdigit((int)(stoks[1][0])))
00276                 {
00277                     /* number of tgtnodes */
00278                     bands.max_reroute_entries = atoi(stoks[1]);
00279                     i++;
00280                 }
00281                 else
00282                 {
00283                     FatalError("Bad BaitAndSwitch Max Entries Arg",file_name,file_line);
00284                 }
00285     
00286             }
00287             else if(!strcasecmp(stoks[0], "log"))
00288             {
00289                 bands.log = 1;
00290                 i++;
00291             } 
00292             else if(!strcasecmp(stoks[0], "log-file"))
00293             {
00294                 if(isascii((int)(stoks[1][0])))
00295                 {
00296                     if (stoks[1][0] == '/')
00297                         strlcpy (logpath, stoks[1], STD_BUF);
00298                     else
00299                     {
00300                         strlcpy(logpath, pv.log_dir, STD_BUF);
00301                         strlcat(logpath, "/", STD_BUF);
00302                         strlcat(logpath, stoks[1], STD_BUF);
00303                     }
00304                     i++;
00305                 }
00306             }
00307             else if(!strcasecmp(stoks[0],"insert_before"))
00308             {
00309                 bands.insertmode = "I";
00310                 i++;
00311             }           
00312             else if(!strncasecmp(index, "iptpath", 7))
00313             {
00314                 /* get the argument for the option */
00315                 iptdirtoks = mSplit(index, " ", 1, &num_iptdirtoks, 0);
00316 
00317                 /* copy it to the clamcnf */
00318                 if(strlcpy(bands.iptpath, iptdirtoks[1], sizeof(bands.iptpath)) >= sizeof(bands.iptpath))
00319                 {
00320                     FatalError("The iptpath supplied in the config is too long\n");
00321                 }
00322                 else if(snprintf(bands.iptcmd,sizeof(bands.iptcmd) -1,"%s/iptables",bands.iptpath) >= sizeof(bands.iptcmd))
00323                 {
00324                    FatalError("The iptcmd supplied is too long\n");
00325                 }
00326                 else if(snprintf(savecmd,sizeof(savecmd) -1,"%s/iptables-save > %s/iptables-rules",bands.iptpath,pv.log_dir) >= sizeof(savecmd))
00327                 {
00328                    FatalError("The iptsavecmd is too long\n");
00329                 }
00330                 else if(snprintf(restorecmd,sizeof(restorecmd) -1,"%s/iptables-restore < %s/iptables-rules",bands.iptpath,pv.log_dir) >= sizeof(restorecmd))
00331                 {
00332                    FatalError("The iptrestorecmd is too long\n");
00333                 }
00334                 else
00335                 {
00336                    mSplitFree(&iptdirtoks, num_iptdirtoks);
00337                    LogMessage("iptcmd command is now %s\n",bands.iptcmd);
00338                    LogMessage("iptsave command is now %s\n",savecmd);
00339                    LogMessage("iptrestore command is now %s\n",restorecmd);
00340                    i++;
00341                 }
00342 
00343             }
00344             else
00345             {
00346                 FatalError("%s(%d) => option '%s' is undefined. ",
00347                             file_name, file_line, stoks[0]);
00348             }
00349 
00350             mSplitFree(&stoks, s_toks);
00351        }
00352             mSplitFree(&toks, num_toks);
00353     }
00354     if(bands.log)
00355     {
00356         bands.logfile = fopen(logpath, "a+");
00357 
00358         if(bands.logfile == NULL)
00359         {
00360             FatalError("Can't open logfile: %s", bands.logpath);
00361         }
00362     }
00363 }
00364 void basInitIgnoreHosts(u_char *hosts)
00365 {
00366     char **toks;
00367     int num_toks;
00368     int num_hosts = 0;
00369     basHostNode *bascurrentHost;
00370     /*int i;*/
00371 
00372     bascurrentHost = NULL;
00373     basignoreList = NULL;
00374 
00375     if(hosts == NULL)
00376     {
00377         ErrorMessage(" ERROR: %s(%d)=> No arguments to "
00378                      "bait-and-switch-ignorehosts, ignoring.\n",
00379                      file_name, file_line);
00380         return;
00381     }
00382 
00383     toks = mSplit(hosts, " ", 127, &num_toks, '\\');
00384 
00385     for(num_hosts = 0; num_hosts < num_toks; num_hosts++)
00386     {
00387         if((bascurrentHost = (basHostNode *) calloc(1, sizeof(basHostNode))) == NULL)
00388         {
00389             FatalError("[!] ERROR: Unable to allocate space for "
00390                        "bait-and-switch IgnoreHost");
00391         }
00392         bascurrentHost->address = NULL; /* be paranoid */
00393         bascurrentHost->nextNode = basignoreList;
00394         basignoreList = bascurrentHost;
00395 
00396 
00397         basScanParseIp(toks[num_hosts], bascurrentHost);
00398     }
00399 
00400     mSplitFree(&toks, num_toks);
00401 }
00402 
00403 
00404 IpAddrSet* basIgnoreAllocAddrNode(basHostNode *host)
00405 {
00406     IpAddrSet *idx;
00407 
00408     if((idx = (IpAddrSet *) calloc(1, sizeof(IpAddrSet))) == NULL)
00409       {
00410         FatalError("[!] ERROR: Unable to allocate space for "
00411                        "BaitAndSwitch IP addr\n");
00412       }
00413 
00414     idx->next = host->address;
00415     host->address = idx;
00416 
00417     return idx;
00418 }
00419 
00420 
00421 void basScanParseIp(char *addr, basHostNode *host)
00422 {
00423     char **toks;
00424     int num_toks;
00425     int i, not_flag;
00426     IpAddrSet *tmp_addr;
00427     char *enbracket, *ports;
00428     char *tmp;
00429 
00430     if(addr == NULL)
00431     {
00432         ErrorMessage("ERROR %s(%d) => Undefine address in "
00433                      "bait-and-switch-ignorehosts directive, igoring.\n", file_name,
00434                      file_line);
00435 
00436         return;
00437     }
00438 
00439     if(*addr == '!')
00440     {
00441         host->flags |= EXCEPT_SRC_IP;
00442         addr++;
00443     }
00444 
00445     if(*addr == '$')
00446     {
00447         if((tmp = VarGet(addr + 1)) == NULL)
00448         {
00449             ErrorMessage("ERROR %s (%d) => Undefined variable \"%s\", "
00450                          "ignoring\n", file_name, file_line, addr);
00451 
00452             return;
00453         }
00454     }
00455     else
00456     {
00457         tmp = addr;
00458     }
00459 
00460     ports = strrchr(tmp, (int)'@');
00461 
00462     if (*tmp == '[')
00463     {
00464         enbracket = strrchr(tmp, (int)']');
00465         if (enbracket) *enbracket = '\x0'; /* null out the en-bracket */
00466 
00467         if (ports && enbracket && (ports < enbracket))
00468         {
00469           FatalError("[!] ERROR %s(%d) => syntax error in"
00470                      "bait-and-switch-ignorehosts \"%s\"\n",
00471                      file_name, file_line, tmp);
00472         }
00473         toks = mSplit(tmp+1, ",", 128, &num_toks, 0);
00474 
00475         for(i = 0; i < num_toks; i++)
00476         {
00477             tmp_addr = basIgnoreAllocAddrNode(host);
00478 
00479             ParseIP(toks[i], tmp_addr);
00480         }
00481 
00482         mSplitFree(&toks, num_toks);
00483     }
00484     else
00485     {
00486         if (ports) *ports = '\x0'; /* null out the at */
00487 
00488         tmp_addr = basIgnoreAllocAddrNode(host);
00489         ParseIP(tmp, tmp_addr);
00490     }
00491 
00492     if (ports)
00493     {
00494       ports++;
00495       if (ParsePort(ports, &(host->hsp), &(host->lsp), "ip", &not_flag))
00496         host->flags |= ANY_SRC_PORT;
00497       if (not_flag)
00498         host->flags |= EXCEPT_SRC_PORT;
00499     } else {
00500         host->flags |= ANY_SRC_PORT;
00501     }
00502 
00503 }
00504 
00505 
00506 void basInitIgnoreFrom(u_char *args)
00507 {
00508   basInitIgnorePorts(args, &basignorePortFrom, &num_ports_from);
00509 }
00510 
00511 
00512 void basInitIgnoreTo(u_char *args)
00513 {
00514   basInitIgnorePorts(args, &basignorePortTo, &num_ports_to);
00515 }
00516 
00517 
00518 void basInitIgnorePorts(u_char *list, u_int32_t **ports, int *num)
00519 {
00520     int new_ports, max_ports;
00521     u_int32_t *pool;
00522     char **toks;
00523     int num_toks;
00524 
00525     *ports = NULL;
00526     *num = 0;
00527     max_ports = 0;
00528 
00529     if(list == NULL)
00530     {
00531         ErrorMessage(" ERROR: %s(%d)=> No arguments to "
00532                      "bait-and-switch-ignoreports, ignoring.\n",
00533                      file_name, file_line);
00534         return;
00535     }
00536 
00537     toks = mSplit(list, " ", MAX_PORTS, &num_toks, '\\');
00538 
00539     for(;*num < num_toks; (*num)++)
00540     {
00541       if(*num >= max_ports)
00542       {
00543         new_ports = max_ports + MEM_CHUNK;
00544         if((pool = (u_int32_t *) calloc(new_ports, sizeof(u_int32_t))) == NULL)
00545         {
00546           FatalError("[!] ERROR: Unable to allocate space for "
00547                      "bait-and-switch-ignoreports");
00548         }
00549         if (*ports != NULL)
00550         {
00551           memcpy(pool, *ports, max_ports * sizeof(u_int32_t));
00552           free(*ports);
00553         }
00554         max_ports = new_ports;
00555         *ports = pool;
00556       }
00557       (*ports)[*num] = basScanParsePort(toks[*num]);
00558     }
00559 
00560     mSplitFree(&toks, num_toks);
00561 
00562 }
00563 
00564 
00565 u_int32_t basScanParsePort(char *port)
00566 {
00567     char *tmp;
00568 
00569     if(port == NULL)
00570     {
00571       FatalError("ERROR %s(%d) => Undefined ports in "
00572                  "bait-and-switch-ignoreports directive\n",
00573                  file_name, file_line);
00574     }
00575 
00576     if(*port == '$')
00577     {
00578       if((tmp = VarGet(port + 1)) == NULL)
00579         {
00580           FatalError("ERROR %s (%d) => Undefined variable \"%s\"\n",
00581                      file_name, file_line, port);
00582 
00583         }
00584     }
00585     else
00586     {
00587         tmp = port;
00588     }
00589 
00590     if(!isdigit((int)tmp[0]))
00591     {
00592       FatalError("ERROR %s(%d) => Bad port list to "
00593                  "bait-and-switch-ignoreports\n", file_name, file_line);
00594     }
00595 
00596     return((u_int32_t)atol(tmp));
00597 }
00598 
00599 int basAttackerSearch(Packet *p, char direction)
00600 {
00601     Attacker *searchval;
00602     Attacker tmp;
00603     char pattacker[STD_BUF];
00604     char phoneypot[STD_BUF];
00605 
00606     if(direction == DIRECTION_SOURCE)
00607     {
00608         tmp.attackerip = (u_int32_t)p->iph->ip_src.s_addr;
00609         tmp.honeypotip = (u_int32_t)p->iph->ip_dst.s_addr;
00610         snprintf(pattacker,sizeof(pattacker) -1,"%s",(char *)inet_ntoa(p->iph->ip_src));
00611         snprintf(phoneypot,sizeof(phoneypot) -1,"%s",(char *)inet_ntoa(p->iph->ip_dst));
00612 
00613     }
00614     if(direction == DIRECTION_DST)
00615     {
00616         tmp.attackerip = (u_int32_t)p->iph->ip_dst.s_addr;
00617         tmp.honeypotip = (u_int32_t)p->iph->ip_src.s_addr;
00618         snprintf(pattacker,sizeof(pattacker) -1,"%s",(char *)inet_ntoa(p->iph->ip_src));    
00619         snprintf(phoneypot,sizeof(phoneypot) -1,"%s",(char *)inet_ntoa(p->iph->ip_dst));  
00620     }
00621     if(ubi_trCount(bands.attackerRootPtr) == 0)
00622     {
00623         DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00624                    "we don't have any entries in the attacker table running through normal snort preprocessors and detection engine\n"););
00625         return 0;
00626     }
00627     
00628         searchval = (Attacker *) ubi_btFirst((ubi_btNodePtr)bands.attackerRootPtr->root);
00629 
00630         if(searchval == NULL)               
00631         {
00632             return 0;
00633         }
00634 
00635         do
00636         {
00637 
00638 
00639             if((searchval->attackerip == tmp.attackerip) && (searchval->honeypotip == tmp.honeypotip))
00640             {              
00641 
00642                 if(p->pkth->ts.tv_sec >= (searchval->ruledeletetime.tv_sec))         
00643                 {
00644                     DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00645                                             "Pruning out Attacker entry %s due to timeout\n",pattacker););
00646 
00647                      PruneAttackers(p->pkth->ts.tv_sec, 1, NULL);
00648 
00649                      return(0);
00650                 }
00651 
00652                 else
00653                 {
00654                      DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00655                                             "Attacker/Honeypot attacker:%s honeypot:%s pair found in tree\n",pattacker,phoneypot););
00656                      return(1);
00657                 }
00658             }
00659             else if((searchval->attackerip == tmp.attackerip) && (searchval->attackedip == tmp.honeypotip))
00660             {
00661            
00662                 /*either this connection is left over from before we added our DNAT/SNAT rules or something is fucked in iptables*/
00663                 DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00664                                         "assuming stale iptables connection tearing down session attacker:%s attackedip:%s\n",pattacker,phoneypot););
00665                 InlineReject(p);
00666                 return(1);
00667             }
00668             else
00669             {
00670                 if(searchval != NULL && ubi_trCount(bands.attackerRootPtr))
00671                 {
00672                     searchval = (Attacker *) ubi_btNext((ubi_btNodePtr)searchval);
00673                 }
00674                 else
00675                 {
00676                     DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00677                                "attacker not found src %s dst %s\n",pattacker,phoneypot););
00678                     return (0);
00679                 }
00680             }
00681         } while(searchval != NULL);
00682 
00683         return (0);
00684 }
00685 int basIsIgnored(Packet *p, char dir)
00686 {                 
00687     basHostNode *bascurrentHost = basignoreList;
00688     int i;                
00689 
00690     for(i = 0; i < num_ports_from; i++)
00691     {
00692       if (p->sp == basignorePortFrom[i])   
00693       {
00694         return(1);               
00695       }      
00696     }
00697 
00698     for(i = 0; i < num_ports_to; i++)
00699     {            
00700       if (p->dp == basignorePortTo[i])
00701       {
00702         return(1);
00703       }
00704     }
00705 
00706     while(bascurrentHost)
00707     {
00708         /*
00709          * Return 1 if the source addr is in the serverlist, 0 if nothing is
00710          * found.
00711          */
00712         if(dir == DIRECTION_SOURCE)
00713         {
00714             if(CheckAddrPort(bascurrentHost->address, bascurrentHost->hsp,
00715                              bascurrentHost->lsp, p, bascurrentHost->flags, CHECK_SRC))
00716             {
00717                 return(1);
00718             }
00719         }
00720         else if(dir == DIRECTION_DST)
00721         {
00722             if(CheckAddrPort(bascurrentHost->address, bascurrentHost->hsp,
00723                              bascurrentHost->lsp, p, bascurrentHost->flags, INVERSE))
00724             {
00725                 return(1);
00726             }
00727         }
00728         bascurrentHost = bascurrentHost->nextNode;
00729     }
00730     return(0);
00731 }
00732 
00733 
00734 /*
00735  * Function: AddIpToBlockTree(Packet *p, char bdirection, u_int32_timeout) 
00736  *
00737  * Purpose: Add source ip addy's into the splay tree 
00738  *         
00739  * Returns: void function
00740  *
00741  */
00742 void AddIpToRerouteTree(Packet *p, char bdirection, u_int32_t timeout, u_int32_t hpotip)
00743 {
00744     
00745     if((bdirection == DIRECTION_SOURCE) && (basIsIgnored(p, DIRECTION_SOURCE)))
00746     {
00747         DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,"Host %s  matched ignore list, not adding to reroute tree.\n",inet_ntoa(p->iph->ip_src)););
00748         return;
00749     }
00750     else if((bdirection == DIRECTION_DST) && (basIsIgnored(p, DIRECTION_DST)))
00751     {
00752         DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,"Host %s  matched ignore list, not adding to reroute tree.\n",inet_ntoa(p->iph->ip_dst)););
00753         return;
00754     }
00755     
00756     else
00757     {
00758         Attacker *a = NULL;
00759         MemBucket *mb = NULL;
00760         char fattacker[STD_BUF];
00761         char fattacked[STD_BUF];
00762         char fhoneypot[STD_BUF];
00763         struct in_addr hpot; 
00764         /* borrow a attacker node from the attacker node pool */
00765         mb = mempool_alloc(&bands.AttackerPool);
00766 
00767         if(mb == NULL)
00768         {
00769             /* Nuke 5 nodes we are out of memory */
00770             PruneAttackers(p->pkth->ts.tv_sec, 5, NULL);    
00771         }
00772         a = (Attacker *) mb->data;
00773         a->bucket = mb;
00774         hpot.s_addr=(ulong)hpotip; 
00775         /* fill in the attacker struct */
00776         if(bdirection == DIRECTION_SOURCE)
00777         {
00778             a->attackerip = (u_int32_t)p->iph->ip_src.s_addr;
00779             a->attackedip = (u_int32_t)p->iph->ip_dst.s_addr;
00780             a->honeypotip = (u_int32_t)hpot.s_addr;
00781             snprintf(fattacker,sizeof(fattacker) -1,"%s",(char *)inet_ntoa(p->iph->ip_src));
00782             snprintf(fattacked,sizeof(fattacked) -1,"%s",(char *)inet_ntoa(p->iph->ip_dst));
00783             snprintf(fhoneypot,sizeof(fhoneypot) -1,"%s",(char *)inet_ntoa(hpot));
00784         }
00785         else if(bdirection == DIRECTION_DST)
00786         {
00787             a->attackerip = (u_int32_t)p->iph->ip_dst.s_addr;
00788             a->attackedip = (u_int32_t)p->iph->ip_src.s_addr;
00789             a->honeypotip = (u_int32_t)hpot.s_addr;
00790             snprintf(fattacker,sizeof(fattacker) -1,"%s",(char *)inet_ntoa(p->iph->ip_dst));
00791             snprintf(fattacked,sizeof(fattacked) -1,"%s",(char *)inet_ntoa(p->iph->ip_src));
00792             snprintf(fhoneypot,sizeof(fhoneypot) -1,"%s",(char *)inet_ntoa(hpot));
00793         }
00794         else
00795         {
00796             DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00797                        "not inserting into tree we need src or dst\n"););
00798             mempool_free(&bands.AttackerPool,a->bucket);
00799             return;
00800 
00801         }
00802 
00803   
00804         if(a->attackedip == a->honeypotip)
00805         {  
00806             DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH, 
00807                        "attackedip %s is equal to the honeypot ip address %s\n",fattacked,fhoneypot););
00808            mempool_free(&bands.AttackerPool,a->bucket);
00809            return;
00810         }
00811             DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00812                        "attacker %s attacked %s hpot %s\n",fattacker,fattacked,fhoneypot););
00813 
00814         if(snprintf(a->iptdnatcmd,sizeof(a->iptdnatcmd) -1,"%s -t nat -%s PREROUTING -s %s -d %s -j DNAT --to-destination %s",bands.iptcmd,bands.insertmode,fattacker,fattacked,fhoneypot) >= sizeof(a->iptdnatcmd))
00815         {
00816            DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00817                       "could not add PREROUTING -A rule it was to long\n"););
00818            return;
00819         }
00820         if(snprintf(a->iptsnatcmd,sizeof(a->iptsnatcmd) -1,"%s -t nat -%s POSTROUTING -s %s -d %s -j SNAT --to-source %s",bands.iptcmd,bands.insertmode,fhoneypot, fattacker, fattacked) >= sizeof(a->iptsnatcmd))
00821         {
00822            DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00823                       "could not add POSTROUTING -A rule it was to long\n"););
00824            return;
00825         }
00826         if(snprintf(a->iptundnatcmd,sizeof(a->iptundnatcmd) -1,"%s -t nat -D PREROUTING -s %s -d %s -j DNAT --to-destination %s",bands.iptcmd,fattacker, fattacked, fhoneypot) >= sizeof(a->iptundnatcmd))
00827         {
00828            DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00829                       "could not add PREROUTING -D rule it was to long\n"););
00830            return;
00831         }
00832         if(snprintf(a->iptunsnatcmd,sizeof(a->iptunsnatcmd) -1,"%s -t nat -D POSTROUTING -s %s -d %s -j SNAT --to-source %s",bands.iptcmd,fhoneypot, fattacker, fattacked) >= sizeof(a->iptunsnatcmd))
00833         {
00834            DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00835                       "could not add POSTROUTING -D rule it was to long\n"););
00836            return;
00837         }
00838  
00839         a->ruleaddtime.tv_sec = p->pkth->ts.tv_sec;
00840         a->ruledeletetime.tv_sec = a->ruleaddtime.tv_sec + timeout;
00841         if(ubi_sptInsert(bands.attackerRootPtr,
00842                          (ubi_btNodePtr)a,
00843                          (ubi_btNodePtr)a, NULL) == ubi_trFALSE)
00844         {
00845             DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00846                        "Entry already exists, or something has gone terribly wrong\n"););
00847             /* We allocated memory let's clean it up */
00848              mempool_free(&bands.AttackerPool,a->bucket);
00849         }
00850         else
00851         {
00852             DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00853                        "Insert into reroute tree was successful\n"););
00854             if(system(a->iptdnatcmd) !=0)
00855             {
00856                DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00857                           "failed to add iptables DNAT rule"););
00858             }
00859             else
00860             {
00861                DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00862                           "added iptables DNAT rule\n"););
00863                if(bands.log)
00864                {
00865                    fprintf(bands.logfile,"DNATing all traffic from attackerip: %s bound for ip address: %s to honeypotip of %s\n",fattacker, fattacked, fhoneypot);
00866                }    
00867             }
00868 
00869             if(system(a->iptsnatcmd) != 0)
00870             {
00871                DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00872                           "failed to add iptables SNAT rule\n"););
00873             }
00874             else
00875             {
00876                DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00877                           "added iptables SNAT rule\n"););
00878                 if(bands.log)
00879                 {
00880                     fprintf(bands.logfile,"SNATing all traffic from honeypot ip: %s bound for attackerip: %s to source of attacked ip: %s\n",fhoneypot, fattacker, fattacked);
00881                 }
00882             }
00883             do_detect = 0;
00884             p->preprocessors = 0;
00885             InlineReject(p);
00886         }
00887     }
00888 }
00889 
00890 
00891 void BASLog(Packet *p)
00892 {
00893     char src[STD_BUF];
00894     char dst[STD_BUF];
00895     char timestamp[TIMEBUF_SIZE];
00896     char flagString[9]; 
00897    
00898     strlcpy(src, (char *)inet_ntoa(p->iph->ip_src), sizeof(src));
00899     strlcpy(dst, (char *)inet_ntoa(p->iph->ip_dst), sizeof(dst));
00900     ts_print((struct timeval *) &p->pkth->ts, timestamp);         
00901 
00902     if(p->tcph)
00903     {
00904         CreateTCPFlagString(p, flagString);
00905         fprintf(bands.logfile,"Rerouted Packet %s TCP %s:%u->%s:%u %s\n", timestamp, src, p->sp, dst, p->dp, flagString);
00906                 
00907     }
00908     else if(p->udph)
00909     {
00910         fprintf(bands.logfile,"Rerouted Packet %s UDP %s:%u->%s:%u\n", timestamp, src, p->sp, dst, p->dp); 
00911 
00912     }
00913     else if(p->icmph)      
00914     {
00915         fprintf(bands.logfile, "Rerouted Packet %s ICMP %s->%s type: %u code: %u \n", timestamp, src, dst, p->icmph->type, p->icmph->code);
00916 
00917     }             
00918 
00919     fflush(bands.logfile);
00920 }
00921 
00922 
00923 /*
00924  * Function: PreprocFunction(Packet *)
00925  *
00926  * Purpose: Perform the preprocessor's intended function.  This can be
00927  *          simple (statistics collection) or complex (IP defragmentation)
00928  *          as you like.  Try not to destroy the performance of the whole
00929  *          system by trying to do too much....
00930  *
00931  * Arguments: p => pointer to the current packet data struct 
00932  *
00933  * Returns: void function
00934  *
00935  */
00936 void BaitAndSwitch(Packet *p, void *context)
00937 {
00938     if(basAttackerSearch(p, DIRECTION_SOURCE))
00939     {
00940        DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00941                                "Attacker was found, lets log if specified and set do_detect = 0 and p->processors =0; the packet\n"););
00942        if(bands.log)
00943        {
00944            /* Log the packet */
00945            BASLog(p);
00946        }
00947            
00948        /* Disable Detection to save resources and Drop The Packet */
00949 
00950        do_detect = 0;
00951        p->preprocessors = 0; 
00952            
00953     }
00954     if(basAttackerSearch(p, DIRECTION_DST))
00955     {
00956        DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00957                                "Attacker was found, lets log if specified and set do_detect = 0 and p->processors =0; the packet\n"););
00958        if(bands.log)
00959        {
00960            /* Log the packet */
00961            BASLog(p);
00962        }
00963 
00964        /* Disable Detection to save resources and Drop The Packet */
00965 
00966        do_detect = 0;
00967        p->preprocessors = 0;
00968 
00969     }
00970     else
00971     {
00972          DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
00973                                  "ip address not found in drop list passing\n"););
00974     }
00975     DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,   
00976                             "Calling Global Prune Check \n"););                         
00977 
00978     PruneAttackers(p->pkth->ts.tv_sec,0,NULL);
00979 }
00980 
00981 
00982 static int IpAddressCompareFunction(ubi_trItemPtr ItemPtr, ubi_trNodePtr NodePtr)
00983 {            
00984     Attacker *A = (Attacker *) NodePtr;     
00985     Attacker *B = (Attacker *) ItemPtr;
00986 
00987     if(A->attackerip < B->attackerip)
00988     {               
00989         return 1;   
00990     }         
00991     else if(A->attackerip > B->attackerip)
00992     {
00993         return -1;
00994     }         
00995     if(A->attackedip < B->attackedip)
00996     {
00997         return 1;
00998     }
00999     else if(A->attackedip > B->attackedip) 
01000     {
01001         return -1;
01002     }
01003     if(A->honeypotip < B->honeypotip)
01004     {
01005         return 1;
01006     }
01007     else if(A->honeypotip > B->honeypotip)
01008     {
01009         return -1;
01010     }                   
01011     return 0;
01012 }
01013 
01014 
01015 static void DeleteAttacker(Attacker *a)
01016 {               
01017     Attacker *olda;
01018 
01019     DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH, "Deleteing Attacker %p\n", a);
01020                DebugMessage(DEBUG_BAITANDSWITCH,
01021                             "a->ip: %X\n", a->attackerip);
01022                DebugMessage(DEBUG_BAITANDSWITCH,
01023                             "a->ruleaddtime: %u\n", a->ruleaddtime.tv_sec);
01024                DebugMessage(DEBUG_BAITANDSWITCH,
01025                             "a->ruledeletetime: %u\n", a->ruledeletetime.tv_sec);
01026 
01027                );
01028 
01029    if(system(a->iptundnatcmd) !=0)
01030    {
01031        DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
01032                   "failed to delete iptables DNAT rule\n"););
01033    }
01034    else
01035    {
01036        DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH, 
01037                   "deleted iptables DNAT rule\n"););
01038    }
01039 
01040    if(system(a->iptunsnatcmd) != 0)
01041    {
01042        DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH, 
01043                   "failed to delete iptables SNAT rule\n"););
01044    }
01045    else
01046    {
01047        DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH, 
01048                   "deleted iptables SNAT rule\n"););
01049    }
01050         
01051     olda = (Attacker *) ubi_sptRemove(bands.attackerRootPtr,
01052                                           (ubi_btNodePtr) a);
01053 
01054     mempool_free(&bands.AttackerPool,a->bucket);
01055 }    
01056 
01057 
01058 static int PruneAttackers(u_int32_t now, int tokill, Attacker *saveme)
01059 {
01060     Attacker *idx;
01061     u_int32_t pruned = 0;
01062 
01063     DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
01064                             "PruneAttackers called now: "
01065                             " %u tokill: %d: saveme: %p, count: %u\n",
01066                             now, tokill, saveme,
01067                             ubi_trCount(bands.attackerRootPtr)););
01068 
01069     if(ubi_trCount(bands.attackerRootPtr) == 0)
01070     {
01071         return 0;
01072     }
01073 
01074     if(tokill == 0)
01075     {
01076         DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,  
01077                                 "Running Through Global Prune Check Loop\n"););
01078 
01079         idx = (Attacker *) ubi_btFirst((ubi_btNodePtr)bands.attackerRootPtr->root);
01080 
01081         if(idx == NULL)
01082         {
01083             return 0;
01084         }
01085 
01086         do
01087         {
01088             if(idx == saveme)
01089             {
01090                 idx = (Attacker *) ubi_btNext((ubi_btNodePtr)idx);
01091                 continue;
01092             }
01093 
01094             if((idx->ruledeletetime.tv_sec) <  now)
01095             {
01096                 Attacker *savidx = idx;
01097 
01098                 if(ubi_trCount(bands.attackerRootPtr) > 1)
01099                 {
01100                     idx = (Attacker *) ubi_btNext((ubi_btNodePtr)idx);
01101                     DEBUG_WRAP(DebugMessage(DEBUG_BAITANDSWITCH,
01102                                             "pruning stale BAITANDSWITCH entry\n"););
01103                     DeleteAttacker(savidx);
01104                     pruned++;
01105                 }
01106                 else
01107                 {
01108                     DeleteAttacker(savidx); 
01109                     pruned++;
01110                     return pruned;
01111                 }
01112             }
01113             else
01114             {
01115                 if(idx != NULL && ubi_trCount(bands.attackerRootPtr) > 1)
01116                 {
01117                     idx = (Attacker *) ubi_btNext((ubi_btNodePtr)idx);
01118                 }
01119                 else
01120                 {
01121                     return pruned;
01122                 }
01123             }
01124         } while(idx != NULL);
01125 
01126         return pruned;
01127     }
01128     else
01129     {
01130         while(tokill-- &&  ubi_trCount(bands.attackerRootPtr) > 0) 
01131         {
01132             idx = (Attacker *) ubi_btLeafNode((ubi_btNodePtr)bands.attackerRootPtr);
01133             DeleteAttacker(idx);
01134             return 0;
01135         }
01136     }
01137        return 0;
01138 }
01139 
01140 
01141 int BaitAndSwitchIsRunning(void)
01142 {                
01143     return s_bas_running;
01144 }     
01145 
01146 
01147 /* 
01148  * Function: PreprocCleanExitFunction(int, void *)
01149  *
01150  * Purpose: This function gets called when Snort is exiting, if there's
01151  *          any cleanup that needs to be performed (e.g. closing files)
01152  *          it should be done here.
01153  *
01154  * Arguments: signal => the code of the signal that was issued to Snort
01155  *            data => any arguments or data structs linked to this 
01156  *                    functioin when it was registered, may be
01157  *                    needed to properly exit
01158  *       
01159  * Returns: void function
01160  */                   
01161 static void BaitAndSwitchCleanExitFunction(int signal, void *data)
01162 {
01163 
01164 }
01165 
01166 
01167 
01168 /* 
01169  * Function: PreprocRestartFunction(int, void *)
01170  *
01171  * Purpose: This function gets called when Snort is restarting on a SIGHUP,
01172  *          if there's any initialization or cleanup that needs to happen
01173  *          it should be done here.
01174  *
01175  * Arguments: signal => the code of the signal that was issued to Snort
01176  *            data => any arguments or data structs linked to this 
01177  *                    functioin when it was registered, may be
01178  *                    needed to properly exit
01179  *       
01180  * Returns: void function
01181  */                   
01182 static void BaitAndSwitchRestartFunction(int signal, void *foo)
01183 {
01184 
01185 }
01186 
01187 #endif /* IPFW */
01188 #endif /* GIDS */

Generated on Sun May 14 14:51:16 2006 by  doxygen 1.4.2