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

spp_portscan.c

Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
00003 ** Copyright (C) 1999,2000,2001 Patrick Mullen <p_mullen@linuxrc.net>
00004 **
00005 ** This program is free software; you can redistribute it and/or modify
00006 ** it under the terms of the GNU General Public License as published by
00007 ** the Free Software Foundation; either version 2 of the License, or
00008 ** (at your option) any later version.
00009 **
00010 ** This program is distributed in the hope that it will be useful,
00011 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 ** GNU General Public License for more details.
00014 **
00015 ** You should have received a copy of the GNU General Public License
00016 ** along with this program; if not, write to the Free Software
00017 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00018 */
00019 
00020 /* $Id$ */
00021 /* Snort Portscan Preprocessor Plugin
00022     by Patrick Mullen <p_mullen@linuxrc.net>
00023     Version 0.2.14
00024 */
00025 
00026 #include <sys/types.h>
00027 #include <string.h>
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <time.h>
00031 #ifndef WIN32
00032     #include <sys/time.h>
00033     #include <sys/socket.h>
00034     #include <netinet/in.h>
00035     #include <arpa/inet.h>
00036 #endif /* !WIN32 */
00037 #include <time.h>
00038 
00039 #include "rules.h"
00040 #include "log.h"
00041 #include "util.h"
00042 #include "debug.h"
00043 #include "generators.h"
00044 #include "detect.h"
00045 #include "log.h"
00046 #include "plugbase.h"
00047 #include "parser.h"
00048 #include "mstring.h"
00049 
00050 #include "snort.h"
00051 
00052 
00053 void PortscanInit(u_char *);
00054 void ParsePortscanArgs(u_char *);
00055 void PortscanPreprocFunction(Packet *, void *);
00056 void ExtractHeaderInfo(Packet*, struct in_addr*, struct in_addr*, u_short*, u_short*);
00057 
00058 void PortscanIgnoreHostsInit(u_char*);
00059 #define MODNAME "spp_portscan"
00060 /*
00061 BUGS:
00062 I dare say the connection information reported at the end of a scan is
00063    wildly inaccurate.  Search for "ZDNOTE CONNECTION INFORMATION" for
00064    more details.
00065 
00066 TODO:
00067 
00068 configuration file
00069 scans to multiple networks
00070 log scan packet contents
00071 - Once a host has been determined to be scanning, automatically log packets from
00072   that host to reduce memory requirements.
00073 documentation
00074 function descriptions
00075 distributed portscans
00076 
00077 */
00078 
00079 
00080 /* Definitions for scan types */
00081 struct spp_timeval
00082 {
00083     time_t tv_sec;
00084     time_t tv_usec;
00085 };
00086 
00087 typedef enum _scanType
00088 {
00089     sNONE = 0, sUDP = 1, sSYN = 2, sSYNFIN = 4, sFIN = 8, sNULL = 16,
00090     sXMAS = 32, sFULLXMAS = 64, sRESERVEDBITS = 128, sVECNA = 256, sNOACK = 512, sNMAPID = 1024,
00091     sSPAU = 2048, sINVALIDACK = 4096
00092 } ScanType;
00093 
00094 /* Definitions for log levels */
00095 typedef enum _logLevel
00096 {
00097     lNONE = 0, lFILE = 1, lEXTENDED = 2, lPACKET = 4
00098 } LogLevel;
00099 
00100 
00101 /* Structures for keeping track of connection information. */
00102 typedef struct _connectionInfo
00103 {
00104     ScanType scanType;
00105     u_short sport;
00106     u_short dport;
00107     struct spp_timeval timestamp;
00108     char tcpFlags[9];       /* Eight flags and a NULL */
00109     u_char *packetData;
00110     struct _connectionInfo *prevNode;
00111     struct _connectionInfo *nextNode;
00112 }               ConnectionInfo;
00113 
00114 typedef struct _destinationInfo
00115 {
00116     struct in_addr daddr;
00117     int numberOfConnections;
00118     ConnectionInfo *connectionsList;
00119     struct _destinationInfo *prevNode;
00120     struct _destinationInfo *nextNode;
00121 }                DestinationInfo;
00122 
00123 typedef struct _sourceInfo
00124 {
00125     struct in_addr saddr;
00126     int numberOfConnections;
00127     int numberOfDestinations;
00128     int numberOfTCPConnections;
00129     int numberOfUDPConnections;
00130 
00131     /*
00132      * ZDNOTE CONNECTION INFORMATION The totals statistics are generally
00133      * inaccurate and for general information of the severity of a scan,
00134      * rather than a hard and fast count of what was scanned. To provide 100%
00135      * accurate statistics, the architecture would have to be heavily
00136      * modified.  This should probably be done anyway, but not today.
00137      * 
00138      * Ways these counts will be inaccurate: 1) Hosts is incorrect if a host is
00139      * rescanned after all connection information is cleared 2) Connections
00140      * counts are incorrect if same ports are rescanned after they have
00141      * already been reported. 3) Probably more.  This is a little more
00142      * difficult to do reliably than I realized.  Ah, well.
00143      */
00144     int totalNumberOfTCPConnections;
00145     int totalNumberOfUDPConnections;
00146     int totalNumberOfDestinations;
00147 
00148     struct spp_timeval firstPacketTime;
00149     struct spp_timeval lastPacketTime;
00150     int reportStealth;
00151 
00152     int stealthScanUsed;
00153     int scanDetected;
00154     struct spp_timeval reportTime;  /* last time we reported on this
00155                      * source's activities */
00156     DestinationInfo *destinationsList;
00157     u_int32_t event_id;
00158     struct _sourceInfo *prevNode;
00159     struct _sourceInfo *nextNode;
00160 }           SourceInfo;
00161 
00162 typedef struct _scanList
00163 {
00164     SourceInfo *listHead;
00165     SourceInfo *lastSource;
00166     long numberOfSources;   /* must be as large as address space */
00167 }         ScanList;
00168 
00169 typedef struct _serverNode  /* for keeping track of our network's servers */
00170 {
00171     IpAddrSet *address;
00172     /*
00173      * u_long address; u_long netmask;
00174      */
00175     char ignoreFlags;
00176     struct _serverNode *nextNode;
00177 }           ServerNode;
00178 
00179 
00180 
00181 typedef struct _CPConfig
00182 {
00183     u_int32_t classification;
00184     u_int32_t priority;
00185 } CPConfig;
00186 
00187 
00188 /** FUNCTION PROTOTYPES **/
00189 /* Add connection information */
00190 int NewScan(ScanList *, Packet *, ScanType);
00191 ConnectionInfo *NewConnection(Packet *, ScanType);
00192 ConnectionInfo *AddConnection(ConnectionInfo *, Packet *, ScanType);
00193 DestinationInfo *NewDestination(Packet *, ScanType);
00194 DestinationInfo *AddDestination(DestinationInfo *, Packet *, ScanType);
00195 SourceInfo *NewSource(Packet *, ScanType);
00196 SourceInfo *AddSource(SourceInfo *, Packet *, ScanType);
00197 
00198 /* Remove connection information */
00199 void ExpireConnections(ScanList *, struct spp_timeval, struct spp_timeval);
00200 void RemoveConnection(ConnectionInfo *);
00201 void RemoveDestination(DestinationInfo *);
00202 void RemoveSource(SourceInfo *);
00203 void ClearConnectionInfoFromSource(SourceInfo *);
00204 
00205 /* Logging functions */
00206 void LogScanInfoToSeparateFile(SourceInfo *);
00207 void AlertIntermediateInfo(SourceInfo *);
00208 
00209 /* Miscellaneous functions */
00210 ScanList *CreateScanList(void);
00211 ScanType CheckTCPFlags(u_char);
00212 int IsServer(Packet *);
00213 
00214 /* For portscan-ignorehosts */
00215 IpAddrSet *PortscanAllocAddrNode();
00216 void PortscanParseIP(char *);
00217 void CreateServerList(u_char *);
00218 IpAddrSet *PortscanIgnoreAllocAddrNode(ServerNode *);
00219 void PortscanIgnoreParseIP(char *, ServerNode *);
00220 
00221 /* Global variables */
00222 ScanList *scanList;
00223 ServerNode *serverList;
00224 ScanType scansToWatch;
00225 CPConfig configdata;
00226 
00227 /*u_long homeNet, homeNetMask;*/
00228 IpAddrSet *homeAddr;
00229 char homeFlags;
00230 struct spp_timeval maxTime;
00231 long maxPorts;
00232 LogLevel logLevel;
00233 enum _timeFormat
00234 {
00235     tLOCAL, tGMT
00236 }           timeFormat;
00237 FILE *logFile;
00238 int packetLogSize;      /* Number of data bytes to log per scan
00239                  * packet */
00240 
00241 /* external globals from rules.c */
00242 extern u_int32_t event_id;
00243 
00244 
00245 ConnectionInfo *NewConnection(Packet * p, ScanType scanType)
00246 {
00247     ConnectionInfo *newConnection = (ConnectionInfo *) malloc(sizeof(ConnectionInfo));
00248 
00249     newConnection->prevNode = NULL;
00250     newConnection->nextNode = NULL;
00251 
00252     newConnection->scanType = scanType;
00253     /*
00254      * timestamp provided by libpcap.  This is available realtime and during
00255      * -r playback
00256      */
00257     newConnection->timestamp.tv_sec = p->pkth->ts.tv_sec;
00258     newConnection->timestamp.tv_usec = p->pkth->ts.tv_usec;
00259 
00260     /* The ports are already supposed to be in host order from decode.c */
00261     newConnection->sport = p->sp;
00262     newConnection->dport = p->dp;
00263 
00264     switch(p->iph->ip_proto)
00265     {
00266         case IPPROTO_TCP:
00267             CreateTCPFlagString(p, newConnection->tcpFlags);
00268 
00269             /* ZDNOTE PACKET LOGGING */
00270             if(logLevel & lPACKET)
00271             {
00272                 /*
00273                  * Determine buffer size = header size + lower(datasize,
00274                  * packetLogSize)
00275                  */
00276                 /* Allocate memory */
00277                 /* Copy data */
00278             }
00279             break;
00280 
00281         case IPPROTO_UDP:
00282             strncpy(newConnection->tcpFlags, "\0", 1);
00283 
00284             /* ZDNOTE PACKET LOGGING */
00285             if(logLevel & lPACKET)
00286             {
00287                 /*
00288                  * Determine buffer size = header size + lower(datasize,
00289                  * packetLogSize)
00290                  */
00291                 /* Allocate memory */
00292                 /* Copy data */
00293             }
00294             break;
00295 
00296         default:
00297             /* This should never happen because it's already filtered. */
00298             FatalError(MODNAME ": NewConnection(): Invalid protocol! (%d)\n", p->iph->ip_proto);
00299             break;
00300     }
00301 
00302     return(newConnection);
00303 }
00304 
00305 ConnectionInfo *AddConnection(ConnectionInfo * currentConnection, Packet * p, ScanType scanType)
00306 {
00307     if(currentConnection->nextNode)
00308         FatalError(MODNAME ":  AddConnection():  Not at end of connection list!");
00309 
00310     currentConnection->nextNode = NewConnection(p, scanType);
00311     currentConnection->nextNode->prevNode = currentConnection;
00312 
00313     return(currentConnection->nextNode);
00314 }
00315 
00316 
00317 DestinationInfo *NewDestination(Packet * p, ScanType scanType)
00318 {
00319     DestinationInfo *newDestination = (DestinationInfo *) malloc(sizeof(DestinationInfo));
00320 
00321     newDestination->prevNode = NULL;
00322     newDestination->nextNode = NULL;
00323     newDestination->daddr = p->iph->ip_dst;
00324     newDestination->connectionsList = NewConnection(p, scanType);
00325     newDestination->numberOfConnections = 1;
00326 
00327     return(newDestination);
00328 }
00329 
00330 
00331 DestinationInfo *AddDestination(DestinationInfo * currentDestination, Packet * p,
00332                                 ScanType scanType)
00333 {
00334     if(currentDestination->nextNode)
00335         FatalError(MODNAME ":  AddDestination():  Not at end of destination list!");
00336 
00337     currentDestination->nextNode = NewDestination(p, scanType);
00338     currentDestination->nextNode->prevNode = currentDestination;
00339     return(currentDestination->nextNode);
00340 }
00341 
00342 
00343 SourceInfo *NewSource(Packet * p, ScanType scanType)
00344 {
00345     SourceInfo *newSource = (SourceInfo *) malloc(sizeof(SourceInfo));
00346 
00347     newSource->prevNode = NULL;
00348     newSource->nextNode = NULL;
00349     newSource->saddr = p->iph->ip_src;
00350     newSource->numberOfConnections = 1;
00351 
00352     newSource->firstPacketTime.tv_sec = p->pkth->ts.tv_sec;
00353     newSource->firstPacketTime.tv_usec = p->pkth->ts.tv_usec;
00354     newSource->lastPacketTime.tv_sec = p->pkth->ts.tv_sec;
00355     newSource->lastPacketTime.tv_usec = p->pkth->ts.tv_usec;
00356 
00357     if(scanType == sUDP)
00358     {
00359         newSource->numberOfUDPConnections = 1;
00360         newSource->numberOfTCPConnections = 0;
00361 
00362         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, MODNAME
00363                                 ": NewSource(): %s->numberOfUDPConnections = 1, TCP = 0\n",
00364                                 inet_ntoa(newSource->saddr)););
00365     }
00366     else
00367     {
00368         newSource->numberOfTCPConnections = 1;
00369         newSource->numberOfUDPConnections = 0;
00370 
00371         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, MODNAME
00372                                 ": NewSource(): %s->numberOfTCPConnections = 1, UDP = 0\n",
00373                                 inet_ntoa(newSource->saddr)););
00374     }
00375 
00376     newSource->totalNumberOfTCPConnections = 0;
00377     newSource->totalNumberOfUDPConnections = 0;
00378     newSource->stealthScanUsed = 0; /* This needs to be set elsewhere */
00379     newSource->scanDetected = 0;
00380     newSource->destinationsList = NewDestination(p, scanType);
00381     newSource->numberOfDestinations = 1;
00382     newSource->totalNumberOfDestinations = 1;
00383     newSource->reportStealth = 0;   /* This needs to be set elsewhere */
00384 
00385     return(newSource);
00386 }
00387 
00388 
00389 SourceInfo *AddSource(SourceInfo * currentSource, Packet * p, ScanType scanType)
00390 {
00391     if(currentSource->nextNode)
00392         FatalError(MODNAME ":  AddSource():  Not at end of source list!");
00393 
00394     currentSource->nextNode = NewSource(p, scanType);
00395     currentSource->nextNode->prevNode = currentSource;
00396 
00397     return(currentSource->nextNode);
00398 }
00399 
00400 
00401 void RemoveConnection(ConnectionInfo * delConnection)
00402 {
00403     /*
00404      * If there is a prev and/or next node, make them point to the proper
00405      * places.  Otherwise, just delete this node.
00406      */
00407     if(delConnection->prevNode || delConnection->nextNode)
00408     {
00409         if(delConnection->prevNode)
00410         {
00411             delConnection->prevNode->nextNode = delConnection->nextNode;
00412         }
00413         else if(delConnection->nextNode)
00414         {
00415             delConnection->nextNode->prevNode = NULL;
00416         }
00417         if(delConnection->nextNode)
00418         {
00419             delConnection->nextNode->prevNode = delConnection->prevNode;
00420         }
00421         else if(delConnection->prevNode)
00422         {
00423             delConnection->prevNode->nextNode = NULL;
00424         }
00425     }
00426     free(delConnection);
00427 }
00428 
00429 
00430 void RemoveDestination(DestinationInfo * delDestination)
00431 {
00432     /*
00433      * If there is a prev and/or next node, make them point to the proper
00434      * places.  Otherwise, just delete this node.
00435      */
00436     if(delDestination->prevNode || delDestination->nextNode)
00437     {
00438         if(delDestination->prevNode)
00439         {
00440             delDestination->prevNode->nextNode = delDestination->nextNode;
00441         }
00442         else if(delDestination->nextNode)
00443         {
00444             delDestination->nextNode->prevNode = NULL;
00445         }
00446         if(delDestination->nextNode)
00447         {
00448             delDestination->nextNode->prevNode = delDestination->prevNode;
00449         }
00450         else if(delDestination->prevNode)
00451         {
00452             delDestination->prevNode->nextNode = NULL;
00453         }
00454     }
00455     free(delDestination);
00456 }
00457 
00458 
00459 void RemoveSource(SourceInfo * delSource)
00460 {
00461     /*
00462      * If there is a prev and/or next node, make them point to the proper
00463      * places.  Otherwise, just delete this node.
00464      */
00465     if(delSource->prevNode || delSource->nextNode)
00466     {
00467         if(delSource->prevNode)
00468         {
00469             delSource->prevNode->nextNode = delSource->nextNode;
00470         }
00471         else if(delSource->nextNode)
00472         {
00473             delSource->nextNode->prevNode = NULL;
00474         }
00475         if(delSource->nextNode)
00476         {
00477             delSource->nextNode->prevNode = delSource->prevNode;
00478         }
00479         else if(delSource->prevNode)
00480         {
00481             delSource->prevNode->nextNode = NULL;
00482         }
00483     }
00484     free(delSource);
00485 }
00486 
00487 
00488 /* Go through each connection and remove any connections that are old.  If
00489    the removal of a node makes a parent node empty, remove that node, all
00490    the way back to the root.
00491 */
00492 void ExpireConnections(ScanList * scanList, struct spp_timeval watchPeriod,
00493                        struct spp_timeval currentTime)
00494 {
00495     SourceInfo *currentSource = scanList->listHead, *tmpSource;
00496     DestinationInfo *currentDestination, *tmpDestination;
00497     ConnectionInfo *currentConnection, *tmpConnection;
00498 
00499     /* Empty list. Get out of here. */
00500     if(!scanList->listHead)
00501         return;
00502 
00503     while(currentSource)
00504     {
00505         /*
00506          * If this source host is scanning us, we don't want to lose any
00507          * connections so go back to top.
00508          */
00509         if(currentSource->scanDetected)
00510         {
00511             currentSource = currentSource->nextNode;
00512             continue;
00513         }
00514         currentDestination = currentSource->destinationsList;
00515 
00516         while(currentDestination)
00517         {
00518             currentConnection = currentDestination->connectionsList;
00519 
00520             while(currentConnection)
00521             {
00522                 if(currentConnection->timestamp.tv_sec + watchPeriod.tv_sec < currentTime.tv_sec)
00523                 {
00524                     /* Expire the connection */
00525                     tmpConnection = currentConnection;
00526                     currentConnection = currentConnection->nextNode;
00527 
00528                     /*
00529                      * If this is the first connection, we need to update
00530                      * connectionsList.
00531                      */
00532                     if(tmpConnection->prevNode == NULL)
00533                     {
00534                         currentDestination->connectionsList = tmpConnection->nextNode;
00535                     }
00536                     if(tmpConnection->scanType == sUDP)
00537                     {
00538                         currentSource->numberOfUDPConnections--;
00539 
00540                         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, MODNAME
00541                                                 ": ExpireConnections(): %s->numberOfUDPConnections-- (%d)\n",
00542                                                 inet_ntoa(currentSource->saddr),
00543                                                 currentSource->numberOfUDPConnections););
00544 
00545                     }
00546                     else
00547                     {
00548                         currentSource->numberOfTCPConnections--;
00549                         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, MODNAME
00550                                                 ": ExpireConnections(): %s->numberOfTCPConnections-- (%d)\n",
00551                                                 inet_ntoa(currentSource->saddr),
00552                                                 currentSource->numberOfTCPConnections););
00553 
00554                     }
00555 
00556                     RemoveConnection(tmpConnection);
00557                     currentSource->numberOfConnections--;
00558                     currentDestination->numberOfConnections--;
00559 
00560                 }
00561                 else
00562                 {
00563                     currentConnection = currentConnection->nextNode;
00564                 }
00565             }
00566 
00567             tmpDestination = currentDestination;
00568             currentDestination = currentDestination->nextNode;
00569 
00570             if(tmpDestination->numberOfConnections == 0)
00571             {
00572                 if(tmpDestination->prevNode == NULL)
00573                 {
00574                     currentSource->destinationsList = tmpDestination->nextNode;
00575                 }
00576                 RemoveDestination(tmpDestination);
00577                 currentSource->numberOfDestinations--;
00578             }
00579         }
00580 
00581         tmpSource = currentSource;
00582         currentSource = currentSource->nextNode;
00583 
00584         if(tmpSource->numberOfDestinations == 0)
00585         {
00586             /* If this is the first source, we need to update scanList. */
00587             if(tmpSource->prevNode == NULL)
00588             {
00589                 /* This is fine, even if tmpSource->nextNode is NULL */
00590                 scanList->listHead = tmpSource->nextNode;
00591             }
00592             RemoveSource(tmpSource);
00593             scanList->numberOfSources--;
00594         }
00595     }
00596 
00597     if(scanList->numberOfSources == 0)
00598     {
00599         scanList->listHead = NULL;
00600     }
00601 }
00602 
00603 
00604 /*
00605     Add the connection information and return the
00606     new number of connections for this host
00607 */
00608 int NewScan(ScanList * scanList, Packet * p, ScanType scanType)
00609 {
00610     SourceInfo *currentSource = scanList->listHead;
00611     DestinationInfo *currentDestination;
00612     ConnectionInfo *currentConnection;
00613     int matchFound = 0;
00614 
00615     struct in_addr saddr;
00616     struct in_addr daddr;
00617     u_short sport;
00618     u_short dport;
00619 
00620     /* If list is empty, create the list and add this entry. */
00621     if(!scanList->listHead)
00622     {
00623         scanList->listHead = NewSource(p, scanType);
00624         scanList->numberOfSources = 1;
00625         scanList->lastSource = scanList->listHead;
00626         return(scanList->listHead->numberOfConnections);
00627     }
00628     ExtractHeaderInfo(p, &saddr, &daddr, &sport, &dport);
00629 
00630     while(!matchFound)
00631     {
00632         if(currentSource->saddr.s_addr == saddr.s_addr)
00633         {
00634             currentDestination = currentSource->destinationsList;
00635 
00636             if(currentSource->destinationsList == NULL)
00637             {
00638                 currentSource->destinationsList = NewDestination(p, scanType);
00639                 currentSource->numberOfConnections++;
00640 
00641                 if(scanType == sUDP)
00642                 {
00643                     currentSource->numberOfUDPConnections++;
00644                     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, MODNAME
00645                                             ": NewScan(): %s->numberOfUDPConnections++ (%d)\n",
00646                                             inet_ntoa(currentSource->saddr),
00647                                             currentSource->numberOfUDPConnections););
00648                 }
00649                 else
00650                 {
00651                     currentSource->numberOfTCPConnections++;
00652                     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, MODNAME
00653                                             ": NewScan(): %s->numberOfTCPConnections++ (%d)\n",
00654                                             inet_ntoa(currentSource->saddr),
00655                                             currentSource->numberOfTCPConnections););
00656                 }
00657 
00658                 currentSource->numberOfDestinations++;
00659                 matchFound = 1;
00660             }
00661             currentDestination = currentSource->destinationsList;
00662 
00663             while(!matchFound)
00664             {
00665                 if(currentDestination->daddr.s_addr == daddr.s_addr)
00666                 {
00667                     currentConnection = currentDestination->connectionsList;
00668 
00669                     while(!matchFound)
00670                     {
00671                         /*
00672                          * There should be error checking for
00673                          * currentConnection == NULL, but that should never
00674                          * happen.
00675                          */
00676                         if(currentConnection == NULL)
00677                             FatalError(MODNAME ": currentConnection is NULL!!!??\n");
00678 
00679                         if((currentConnection->dport == dport) && (currentConnection->scanType == scanType))
00680                         {
00681                             /*
00682                              * If the same exact connection already exists,
00683                              * just update the timestamp.
00684                              */
00685                             currentConnection->timestamp.tv_sec = p->pkth->ts.tv_sec;
00686                             currentConnection->timestamp.tv_usec = p->pkth->ts.tv_usec;
00687                             currentConnection->sport = sport;
00688                             matchFound = 1;
00689                         }
00690                         else
00691                         {
00692                             /*
00693                              * If not at end of list, keep going, otherwise
00694                              * create a node.
00695                              */
00696                             if(!currentConnection->nextNode)
00697                             {
00698                                 currentConnection = AddConnection(currentConnection, p, scanType);
00699                                 currentSource->numberOfConnections++;
00700 
00701                                 if(scanType == sUDP)
00702                                 {
00703                                     currentSource->numberOfUDPConnections++;
00704                                     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, MODNAME
00705                                                             ": NewScan(): %s->numberOfUDPConnections++ (%d)\n",
00706                                                             inet_ntoa(currentSource->saddr),
00707                                                             currentSource->numberOfUDPConnections););
00708 
00709                                 }
00710                                 else
00711                                 {
00712                                     currentSource->numberOfTCPConnections++;
00713                                     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, MODNAME
00714                                                             ": NewScan(): %s->numberOfTCPConnections++ (%d)\n",
00715                                                             inet_ntoa(currentSource->saddr),
00716                                                             currentSource->numberOfTCPConnections););
00717                                 }
00718 
00719                                 currentDestination->numberOfConnections++;
00720                                 matchFound = 1;
00721                             }
00722                             else
00723                                 currentConnection = currentConnection->nextNode;
00724                         }
00725                     }
00726                 }
00727                 else
00728                 {
00729                     if(!currentDestination->nextNode)
00730                     {
00731                         currentDestination = AddDestination(currentDestination, p, scanType);
00732                         currentSource->numberOfConnections++;
00733 
00734                         if(scanType == sUDP)
00735                         {
00736                             currentSource->numberOfUDPConnections++;
00737                             DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, MODNAME
00738                                                     ": NewScan(): %s->numberOfUDPConnections++ (%d)\n",
00739                                                     inet_ntoa(currentSource->saddr),
00740                                                     currentSource->numberOfUDPConnections););
00741                         }
00742                         else
00743                         {
00744                             currentSource->numberOfTCPConnections++;
00745                             DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, MODNAME
00746                                                     ": NewScan(): %s->numberOfTCPConnections++ (%d)\n",
00747                                                     inet_ntoa(currentSource->saddr),
00748                                                     currentSource->numberOfTCPConnections););
00749 
00750                         }
00751 
00752                         currentSource->numberOfDestinations++;
00753                         currentSource->totalNumberOfDestinations++;
00754                         matchFound = 1;
00755                     }
00756                     else
00757                         currentDestination = currentDestination->nextNode;
00758                 }
00759             }
00760         }
00761         else
00762         {
00763             if(!currentSource->nextNode)
00764             {
00765                 currentSource = AddSource(currentSource, p, scanType);
00766                 currentSource->numberOfConnections = 1;
00767 
00768                 if(scanType == sUDP)
00769                 {
00770                     currentSource->numberOfUDPConnections = 1;
00771                     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
00772                                             MODNAME ": NewScan(): %s->numberOfUDPConnections = 1 \n",
00773                                             inet_ntoa(currentSource->saddr)););
00774                 }
00775                 else
00776                 {
00777                     currentSource->numberOfTCPConnections = 1;
00778                     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, MODNAME
00779                                             ": NewScan(): %s->numberOfTCPConnections = 1\n",
00780                                             inet_ntoa(currentSource->saddr)););
00781 
00782                 }
00783 
00784                 scanList->numberOfSources++;
00785                 matchFound = 1;
00786             }
00787             else
00788                 currentSource = currentSource->nextNode;
00789         }
00790     }
00791 
00792     scanList->lastSource = currentSource;
00793     return(currentSource->numberOfConnections);
00794 }
00795 
00796 
00797 ScanList *CreateScanList(void)
00798 {
00799     ScanList *newList = (ScanList *) malloc(sizeof(ScanList));
00800 
00801     newList->listHead = NULL;
00802     newList->lastSource = NULL;
00803     newList->numberOfSources = 0;
00804 
00805     return(newList);
00806 }
00807 
00808 
00809 
00810 void PortscanPreprocFunction(Packet * p, void *context)
00811 {
00812     /*
00813      * The main loop.  Whenever this is called, first we expire connections
00814      * so we don't get false positives from stale connections.  Then we add
00815      * the new connection information and check if the latest connection has
00816      * passed the threshold.  If it has or if a stealth technique was used,
00817      * we immediately report the scan.  Then we go through the list and any
00818      * host that has been flagged as doing a portscan and has passed the
00819      * necessary amount of time between reports and has connections stored
00820      * are reported and cleared.  Any host that has been flagged as doing a
00821      * portscan and has passed the necessary amount of time between reports
00822      * and does not have connections stored has the portscan flag cleared and
00823      * will automatically be flushed at next call.
00824      */
00825 
00826     SourceInfo *currentSource;
00827     ScanType scanType;
00828     struct spp_timeval currTime;
00829     char logMessage[180];
00830     int numPorts;
00831     Event event;
00832 
00833     if(!(p->preprocessors & PP_PORTSCAN))
00834     {
00835         return;
00836     }
00837 
00838     /* Only do processing on IP Packets */
00839     if(p->iph == NULL)
00840     {
00841         return;
00842     }
00843 
00844     if(p->packet_flags & PKT_REBUILT_STREAM)
00845     {
00846         return;
00847     }
00848 
00849     /*
00850      * Here we check if it is a protocol we are watching and if it is a
00851      * destination we are watching.  If either fails, we return abruptly.
00852      */
00853     switch(p->iph->ip_proto)
00854     {
00855         case IPPROTO_TCP:
00856             if(p->tcph == NULL)
00857             {
00858                 /*
00859                  * ZDNOTE Fragmented packets have IPH set to NULL so `nmap -f`
00860                  * defeats SPP, at least until reassembly or the header pointer
00861                  * is fixed.
00862                  */
00863                 return;
00864             }
00865             DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"spp_portscan: Got TCP pkt\n"););
00866             scanType = CheckTCPFlags(p->tcph->th_flags);
00867             break;
00868 
00869         case IPPROTO_UDP:
00870             /*
00871              * We no longer check for NULL UDP headers here, because it really
00872              * doesn't matter anymore.  We don't access it.  We just use p->[sd]p
00873              * instead.
00874              */
00875             scanType = sUDP;
00876             break;
00877 
00878         default:
00879             /* The packet isn't a protocol we watch, so get out of here. */
00880             return;         /*** RETURN ***/
00881             break;
00882     }
00883 
00884     /*
00885      * For speed, we're going to drop out right now if this packet is not any
00886      * type of scan.  My assumption is most packets on the network are not
00887      * going to be any type of scan packet (not even SYN or UDP), so this
00888      * extra check will be faster in the long run.
00889      */
00890     if(!scanType)
00891         return;
00892 
00893     /*
00894      * The checks above are faster, so now that we know this packet is
00895      * interesting we'll check the address.
00896      */
00897     if(!CheckAddrPort(homeAddr, 0, 0, p,
00898                 (ANY_DST_PORT | homeFlags), CHECK_DST))
00899     {
00900         return;
00901     }
00902     /*
00903      * If we ignore SYN and UDP scans from this host (presumably because it's
00904      * a server), clear out those flags so we don't get false alarms. If it's
00905      * a server, we also need to make sure there are no reserved bits set
00906      * because otherwise "2*S*****" shows as UNKNOWN instead of as SYN w/
00907      * RESERVEDBITS.  The beast below makes sure we are actually watching for
00908      * RB scans.  The previous version would have let servers be left as SYN
00909      * scans if a reserved bit was set.
00910      */
00911     if(IsServer(p) && !(scanType & sRESERVEDBITS & scansToWatch))
00912     {
00913         scanType &= ~(sSYN | sUDP);
00914     }
00915     if(scanType & scansToWatch)
00916     {
00917         currTime.tv_sec = p->pkth->ts.tv_sec;
00918         currTime.tv_usec = p->pkth->ts.tv_usec;
00919         ExpireConnections(scanList, maxTime, currTime);
00920 
00921         /*
00922          * If more than maxPorts connections made or if stealth scan
00923          * technique was used, mark this as a portscan.
00924          */
00925 
00926         numPorts = NewScan(scanList, p, scanType);
00927 
00928         /* Timestamp info for statistics */
00929         scanList->lastSource->lastPacketTime = currTime;
00930 
00931         if((numPorts > maxPorts) || (scanType & ~(sSYN | sUDP)))
00932         {
00933             if(scanType & ~(sSYN | sUDP))
00934             {
00935                 scanList->lastSource->stealthScanUsed = 1;
00936                 scanList->lastSource->reportStealth = 1;
00937             }
00938             if(!scanList->lastSource->scanDetected)
00939             {
00940                 if(scanList->lastSource->stealthScanUsed)
00941                 {
00942                     if(pv.alert_interface_flag)
00943                     {
00944                         sprintf(logMessage, 
00945                                 MODNAME ": PORTSCAN DETECTED on %s to port %d "
00946                                 "from %s (STEALTH)", 
00947                                 PRINT_INTERFACE(pv.interface), 
00948                                 p->dp,
00949                                 inet_ntoa(scanList->lastSource->saddr));
00950                     }
00951                     else
00952                     {
00953                         sprintf(logMessage, 
00954                                 MODNAME ": PORTSCAN DETECTED to port %d from "
00955                                 "%s (STEALTH)", 
00956                                 p->dp,
00957                                 inet_ntoa(scanList->lastSource->saddr));
00958                     }
00959                 }
00960                 else
00961                 {
00962                     if(pv.alert_interface_flag)
00963                     {
00964                         sprintf(logMessage, MODNAME 
00965                                 ": PORTSCAN DETECTED on %s from %s"
00966                                 " (THRESHOLD %ld connections exceeded in %ld seconds)",
00967                                 PRINT_INTERFACE(pv.interface), 
00968                                 inet_ntoa(scanList->lastSource->saddr), maxPorts,
00969                                 (long int) (currTime.tv_sec - 
00970                                             scanList->lastSource->firstPacketTime.tv_sec));
00971                     }
00972                     else
00973                     {
00974                         sprintf(logMessage, 
00975                                 MODNAME ": PORTSCAN DETECTED from %s"
00976                                 " (THRESHOLD %ld connections exceeded in %ld seconds)",
00977                                 inet_ntoa(scanList->lastSource->saddr), maxPorts,
00978                                 (long int) (currTime.tv_sec - 
00979                                             scanList->lastSource->firstPacketTime.tv_sec));
00980                     }
00981                 }
00982 
00983                 SetEvent(&event, GENERATOR_SPP_PORTSCAN, PORTSCAN_SCAN_DETECT, 
00984                         1, 0, 0, 0);
00985                 CallAlertFuncs(NULL , logMessage, NULL, &event);
00986                 scanList->lastSource->scanDetected = 1;
00987                 scanList->lastSource->reportTime = currTime;
00988                 scanList->lastSource->event_id = event_id;
00989             }
00990         }
00991         /* See if there's anyone we can snitch on.  ;)  */
00992         currentSource = scanList->listHead;
00993         while(currentSource)
00994         {
00995             if(currentSource->scanDetected)
00996             {
00997                 if(currentSource->reportTime.tv_sec + maxTime.tv_sec < currTime.tv_sec)
00998                 {
00999                     if(currentSource->numberOfConnections == 0)
01000                     {
01001                         /* Portscan stopped.  Clear flag. */
01002                         sprintf(logMessage, MODNAME ": End of portscan from %s: TOTAL time(%lds) hosts(%d) TCP(%d) UDP(%d)%s",
01003                                 inet_ntoa(currentSource->saddr),
01004                                 (long int) (currentSource->lastPacketTime.tv_sec - currentSource->firstPacketTime.tv_sec),
01005                                 currentSource->totalNumberOfDestinations,
01006                                 currentSource->totalNumberOfTCPConnections,
01007                                 currentSource->totalNumberOfUDPConnections,
01008                                 (currentSource->reportStealth) ? " STEALTH" : "");
01009                         SetEvent(&event, GENERATOR_SPP_PORTSCAN, 
01010                                 PORTSCAN_SCAN_END, 1, 0, 0, 
01011                                 currentSource->event_id);
01012                         CallAlertFuncs(NULL , logMessage, NULL, &event);
01013                         currentSource->scanDetected = 0;
01014                     }
01015                     else
01016                     {
01017                         /* This is where we do the real logging */
01018                         if(logLevel & lFILE)
01019                             LogScanInfoToSeparateFile(currentSource);
01020                         if(logLevel & lEXTENDED)
01021                             AlertIntermediateInfo(currentSource);
01022 
01023                         currentSource->totalNumberOfTCPConnections += 
01024                             currentSource->numberOfTCPConnections;
01025                         currentSource->totalNumberOfUDPConnections += 
01026                             currentSource->numberOfUDPConnections;
01027 
01028                         ClearConnectionInfoFromSource(currentSource);
01029                         currentSource->stealthScanUsed = 0;
01030                         currentSource->reportTime = currTime;
01031                     }
01032                 }
01033             }
01034             currentSource = currentSource->nextNode;
01035         }
01036     }
01037 }
01038 
01039 
01040 
01041 void ClearConnectionInfoFromSource(SourceInfo * currentSource)
01042 {
01043     DestinationInfo *currentDestination, *tmpDestination;
01044     ConnectionInfo *currentConnection, *tmpConnection;
01045 
01046     currentDestination = currentSource->destinationsList;
01047     while(currentDestination)
01048     {
01049         currentConnection = currentDestination->connectionsList;
01050         while(currentConnection)
01051         {
01052             tmpConnection = currentConnection;
01053             currentConnection = currentConnection->nextNode;
01054 
01055             if(tmpConnection->scanType == sUDP)
01056             {
01057                 currentSource->numberOfUDPConnections--;
01058                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, MODNAME
01059                                         ": ClearConnectionInfoFromSource(): %s->numberOfUDPConnections-- (%d)\n",
01060                                         inet_ntoa(currentSource->saddr), currentSource->numberOfUDPConnections););
01061 
01062             }
01063             else
01064             {
01065                 currentSource->numberOfTCPConnections--;
01066                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, MODNAME
01067                                         ": ClearConnectionInfoFromSource(): %s->numberOfTCPConnections-- (%d)\n",
01068                                         inet_ntoa(currentSource->saddr), currentSource->numberOfTCPConnections););
01069             }
01070 
01071             RemoveConnection(tmpConnection);
01072             currentDestination->numberOfConnections--;
01073             currentSource->numberOfConnections--;
01074         }
01075         tmpDestination = currentDestination;
01076         currentDestination = currentDestination->nextNode;
01077         RemoveDestination(tmpDestination);
01078         currentSource->numberOfDestinations--;
01079     }
01080     currentSource->destinationsList = NULL;
01081 }
01082 
01083 
01084 void SetupPortscan(void)
01085 {
01086     RegisterPreprocessor("portscan", PortscanInit);
01087 }
01088 
01089 
01090 void PortscanInit(u_char * args)
01091 {
01092     LogMessage("WARNING: the portscan preprocessor will be deprecated in "
01093             "the next release of snort.  Please switch to using SFPortscan.\n");
01094     ParsePortscanArgs(args);
01095     scanList = CreateScanList();
01096 
01097     /*
01098      * We set serverList to NULL here so if portscan-ignorehosts is used it
01099      * must be set after portscan.  This is necessary to make sure we don't
01100      * check an empty list.
01101      */
01102     serverList = NULL;
01103     AddFuncToPreprocList(PortscanPreprocFunction);
01104 }
01105 
01106 
01107 ScanType CheckTCPFlags(u_char th_flags)
01108 {
01109     u_char th_flags_cleaned;
01110     ScanType scan = sNONE;
01111 
01112     /*
01113      * Strip off the reserved bits for the testing, but flag that a scan is
01114      * being done.
01115      */
01116     th_flags_cleaned = th_flags & ~(R_RES1 | R_RES2);
01117 
01118     /* I'm disabling reserved bits scan detection until we can get a
01119      * handle on ECN, we're seeing far too many false positives with
01120      * this code right now -MFR
01121      */ 
01122     /*if(th_flags != th_flags_cleaned)
01123     {
01124         scan = sRESERVEDBITS;
01125     }*/
01126     /*
01127      * Most TCP packets will have the ACK bit set, so split that out quickly.
01128      * Any scans which use ACK (like Full-XMAS) must be added to this part.
01129      * Otherwise, it goes in the !ACK section. In addition, anything that is
01130      * !ACK && !SYN eventually gets flagged as something.  This is to
01131      * hopefully detect new stealth scan types.
01132      */
01133     if(th_flags_cleaned & R_ACK)
01134     {
01135 
01136         /*
01137          * This is from ipt_unclean.c from the netfilter package.  We are
01138          * allowing packets which are valid and flagging the rest as
01139          * INVALIDACK, if it's not already listed as some other scan.
01140          */
01141         switch(th_flags_cleaned)
01142         {
01143             case (R_ACK):
01144             case (R_SYN | R_ACK):
01145             case (R_FIN | R_ACK):
01146             case (R_RST | R_ACK):
01147             case (R_ACK | R_PSH):
01148             case (R_ACK | R_URG):
01149             case (R_ACK | R_URG | R_PSH):
01150             case (R_FIN | R_ACK | R_PSH):
01151             case (R_FIN | R_ACK | R_URG):
01152             case (R_FIN | R_ACK | R_URG | R_PSH):
01153             case (R_RST | R_ACK | R_PSH):   /* Found through numerous false
01154                              * alerts. */
01155                 /* Nothing.  This is legitimate traffic. */
01156                 break;
01157 
01158             case (R_SYN | R_RST | R_ACK | R_FIN | R_PSH | R_URG):
01159                 scan |= sFULLXMAS;
01160                 break;
01161 
01162             case (R_SYN | R_PSH | R_ACK | R_URG):
01163                 scan |= sSPAU;
01164                 break;
01165 
01166             default:
01167                 scan |= sINVALIDACK;
01168                 break;
01169         }
01170     }
01171     else
01172     {
01173         /*
01174          * ZDNOTE This could/should be optimized, but just by having the
01175          * check for SYN or RST being first makes this faster.  (Anything
01176          * else is a scan and shouldn't be hit often.
01177          */
01178         switch(th_flags_cleaned)
01179         {
01180             case R_SYN:
01181                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "spp_portscan: SYN packet\n"););
01182                 scan |= sSYN;
01183                 break;
01184 
01185             case R_RST:
01186                 /* Nothing.  This is legitimately tearing down a connection. */
01187                 break;
01188 
01189             case R_FIN:
01190                 scan |= sFIN;
01191                 break;
01192 
01193             case (R_SYN | R_FIN):
01194                 scan |= sSYNFIN;
01195                 break;
01196 
01197             case 0:
01198                 scan |= sNULL;
01199                 break;
01200 
01201             case (R_FIN | R_PSH | R_URG):
01202                 scan |= sXMAS;
01203                 break;
01204 
01205             case R_URG:
01206             case R_PSH:
01207             case (R_URG | R_FIN):
01208             case (R_PSH | R_FIN):
01209             case (R_URG | R_PSH):
01210                 scan |= sVECNA;
01211                 break;
01212 
01213             case (R_SYN | R_FIN | R_PSH | R_URG):
01214                 scan |= sNMAPID;
01215                 break;
01216 
01217             default:
01218                 /*
01219                  * We assume that anything down here w/out an ACK flag is some
01220                  * sort of a scan or something.  Anyway, we'll flag it because if
01221                  * it doesn't have an ACK it should have been only a SYN or RST
01222                  * and be detected above.
01223                  */
01224                 scan |= sNOACK;
01225                 break;
01226         }
01227     }
01228 
01229     return(scan);
01230 }
01231 
01232 
01233 void ParsePortscanArgs(u_char * args)
01234 {
01235     char **toks;
01236     int numToks;
01237 
01238     char *logFileName;
01239 
01240     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,MODNAME ": ParsePortscanArgs(): %s\n", args););
01241 
01242     logLevel = lNONE;
01243 
01244     if(!args)
01245     {
01246         FatalError(MODNAME ": %s (%d) => portscan configuration format:  address/mask ports seconds [logfile]\n", file_name, file_line);
01247     }
01248 
01249     /* the '\\' sets the string escape delimiter - MFR */
01250 #ifdef WIN32
01251     toks = mSplit(args, " ", 6, &numToks, 0);
01252 #else
01253     toks = mSplit(args, " ", 6, &numToks, '\\');    /* ZDNOTE What does the
01254                                                      * '\\' do? */
01255 #endif
01256 
01257     if((numToks < 3) || (numToks > 6))
01258     {
01259         FatalError(MODNAME "%s(%d) => portscan configuration format:  address/mask ports seconds [logfile]\n", file_name, file_line);
01260     }
01261 
01262     maxPorts = atoi(toks[1]);
01263     maxTime.tv_sec = atoi(toks[2]);
01264     maxTime.tv_usec = 0;
01265 
01266     PortscanParseIP(toks[0]);
01267     /* ParseIP(toks[0], homeAddr); */
01268 
01269     /*
01270      * Now we use the default log directory if provided from the command line
01271      * (-l).
01272      */
01273     if(numToks == 4)
01274     {
01275 #ifdef WIN32
01276         logFileName = (char *) calloc(strlen(toks[3]) + 1 + 1, 1);
01277         strncpy(logFileName, toks[3], strlen(toks[3]));
01278 #else
01279         if(pv.log_dir && (*toks[3] != '/'))
01280         {
01281             if(*(pv.log_dir + strlen(pv.log_dir) - 1) != '/')
01282             {
01283                 logFileName = (char *)calloc(strlen(pv.log_dir) 
01284                         + strlen(toks[3]) + 1 + 1, 1);
01285 
01286                 strncat(logFileName, pv.log_dir, strlen(pv.log_dir) + 1);
01287                 strncat(logFileName, "/", 1);
01288                 strncat(logFileName, toks[3], strlen(toks[3]));
01289             }
01290             else
01291             {
01292                 logFileName = (char *)calloc(strlen(pv.log_dir) 
01293                         + strlen(toks[3]) + 1, 1);
01294                    
01295                 strncat(logFileName, pv.log_dir, strlen(pv.log_dir) + 1);
01296                 strncat(logFileName, toks[3], strlen(toks[3]));
01297             }
01298         }
01299         else
01300         {
01301             logFileName = (char *)calloc(strlen(toks[3]) + 1, 1);
01302                
01303             strncat(logFileName, toks[3], strlen(toks[3]) + 1);
01304         }
01305 #endif  /* WIN32 */
01306 
01307         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,MODNAME ": logFileName = %s\n", logFileName););
01308 
01309         logFile = fopen(logFileName, "a+");
01310         if(!logFile)
01311         {
01312             perror("fopen");
01313             FatalError(MODNAME ": logfile open error (%s)\n", logFileName);
01314         }
01315 
01316         logLevel |= lFILE;
01317     }
01318 
01319     mSplitFree(&toks, numToks);
01320 
01321     /* How about some error detecting? :) */
01322     if(maxPorts == 0 || maxTime.tv_sec == 0)
01323     {
01324         FatalError(MODNAME ": %s (%d) => portscan configuration format:  address/mask ports seconds [logfile]\n", file_name, file_line);
01325     }
01326     /*
01327      * ZDNOTE Compile time settings.  Obviously needs to become runtime
01328      * settings.
01329      */
01330     /*
01331      * If you do not want every packet with reserved bits set (which
01332      * shouldn't happen), just remove the "| sRESERVEDBITS" from the end of
01333      * this line.  If you do that, you may wish to add a line to detect that
01334      * in the rules file(s).
01335      */
01336     /*
01337      * ZDNOTE If/when I add this to options, this would be "usfFnxXrvidI"
01338      * scan detection.
01339      */
01340     scansToWatch = ~(sRESERVEDBITS|sUDP);      /* Watch for ALL scans */
01341     /*
01342      * scansToWatch = sUDP | sSYN | sFIN | sSYNFIN | sNULL | sXMAS |
01343      * sFULLXMAS | sRESERVEDBITS | sVECNA | sNOACK | sNMAPID | sSPAU |
01344      * sINVALIDACK;
01345      */
01346     /* can watch all scans but disable some by doing the following */
01347     /* scansToWatch = ~(sRESERVEDBITS | sNMAPID ); */
01348 
01349     /*
01350      * ZDNOTE.  I'm a fascist and I want people to use my new feature, so I'm
01351      * forcing everyone to default to my extended logging.  Mwua-ha-ha-ha!!!
01352      */
01353     logLevel |= lEXTENDED;
01354 
01355     /* If you want to log packet contents, uncomment this line. */
01356     /* logLevel |= lPACKET; */
01357 
01358     /*
01359      * If you want to change the number of bytes of packet data stored,
01360      * change this value. This is the size of the payload and does not
01361      * include the packet header. Set the value to -1 to log the complete
01362      * packet contents.
01363      */
01364     packetLogSize = 100;
01365 
01366     if(pv.use_utc == 1)
01367     {
01368         timeFormat = tGMT;
01369         if(!pv.quiet_flag)
01370             printf("Using GMT time\n");
01371     }
01372     else
01373     {
01374         timeFormat = tLOCAL;
01375         if(!pv.quiet_flag)
01376             printf("Using LOCAL time\n");
01377     }
01378 }
01379 
01380 
01381 void LogScanInfoToSeparateFile(SourceInfo * currentSource)
01382 {
01383     DestinationInfo *currentDestination;
01384     ConnectionInfo *currentConnection;
01385     char *scanType;
01386     char *reservedBits;
01387     char *month;
01388     struct tm *time;
01389     char sourceAddress[16], destinationAddress[16];
01390     memset(sourceAddress, '\0', 16);
01391     memset(destinationAddress, '\0', 16);
01392 
01393     /*
01394      * Can't have two inet_ntoa() calls in a single printf because it uses a
01395      * static buffer.  It's also faster to only do it twice instead of twice
01396      * for each iteration.
01397      */
01398     strncpy(sourceAddress, inet_ntoa(currentSource->saddr), 15);
01399 
01400     for(currentDestination = currentSource->destinationsList; currentDestination;
01401        currentDestination = currentDestination->nextNode)
01402     {
01403         strncpy(destinationAddress, inet_ntoa(currentDestination->daddr), 15);
01404 
01405         for(currentConnection = currentDestination->connectionsList; currentConnection;
01406            currentConnection = currentConnection->nextNode)
01407         {
01408             /*
01409              * Apparently, through some stroke of genius and/or luck,
01410              * timeval.tv_sec can be used just like time_t.  Sweet.  And
01411              * stuff.
01412              */
01413             time = (timeFormat == tLOCAL) ? localtime((time_t *) & currentConnection->timestamp.tv_sec) : gmtime(&currentConnection->timestamp.tv_sec);
01414 
01415             switch(time->tm_mon)
01416             {
01417                 case 0:
01418                     month = "Jan";
01419                     break;
01420                 case 1:
01421                     month = "Feb";
01422                     break;
01423                 case 2:
01424                     month = "Mar";
01425                     break;
01426                 case 3:
01427                     month = "Apr";
01428                     break;
01429                 case 4:
01430                     month = "May";
01431                     break;
01432                 case 5:
01433                     month = "Jun";
01434                     break;
01435                 case 6:
01436                     month = "Jul";
01437                     break;
01438                 case 7:
01439                     month = "Aug";
01440                     break;
01441                 case 8:
01442                     month = "Sep";
01443                     break;
01444                 case 9:
01445                     month = "Oct";
01446                     break;
01447                 case 10:
01448                     month = "Nov";
01449                     break;
01450                 case 11:
01451                     month = "Dec";
01452                     break;
01453                 default:
01454                     month = "MONTH IS INVALID!!";
01455                     break;
01456             }
01457 
01458             reservedBits = (currentConnection->scanType & sRESERVEDBITS) ? "RESERVEDBITS" : "";
01459 
01460             DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"scanType = %x mask = %x result = (%x)\n", currentConnection->scanType, ~sRESERVEDBITS, currentConnection->scanType & ~sRESERVEDBITS););
01461 
01462             switch(currentConnection->scanType & ~sRESERVEDBITS)
01463             {
01464                 case sUDP:
01465                     scanType = "UDP";
01466                     break;
01467                 case sSYN:
01468                     scanType = "SYN";
01469                     break;
01470                 case sFIN:
01471                     scanType = "FIN";
01472                     break;
01473                 case sSYNFIN:
01474                     scanType = "SYNFIN";
01475                     break;
01476                 case sNULL:
01477                     scanType = "NULL";
01478                     break;
01479                 case sXMAS:
01480                     scanType = "XMAS";
01481                     break;
01482                 case sFULLXMAS:
01483                     scanType = "FULLXMAS";
01484                     break;
01485                 case sVECNA:
01486                     scanType = "VECNA";
01487                     break;
01488                 case sNOACK:
01489                     scanType = "NOACK";
01490                     break;
01491                 case sNMAPID:
01492                     scanType = "NMAPID";
01493                     break;
01494                 case sSPAU:
01495                     scanType = "SPAU";
01496                     break;
01497                 case sINVALIDACK:
01498                     scanType = "INVALIDACK";
01499                     break;
01500                 default:
01501                     /*
01502                      * This used to mean I screwed up, but now since any packet
01503                      * that has reserved bits set is set as a scan it looks bad
01504                      * if "ERROR" shows up when the packet really has something
01505                      * bizarre like "2****P**".
01506                      */
01507 
01508                     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"UNKNOWN: scanType = %x (%x)\n", currentConnection->scanType, currentConnection->scanType & ~sRESERVEDBITS););
01509 
01510                     scanType = "UNKNOWN";
01511                     break;
01512             }
01513 
01514             /* I have control of all data here, so this should be safe */
01515             fprintf(logFile, "%s %2d %.2d:%.2d:%.2d %s:%d -> %s:%d %s %s %s\n", month, time->tm_mday,
01516                     time->tm_hour, time->tm_min, time->tm_sec,
01517                     sourceAddress, currentConnection->sport, destinationAddress,
01518                     currentConnection->dport, scanType, currentConnection->tcpFlags, reservedBits);
01519         }
01520     }
01521 
01522     /* Now that we're done, flush the buffer to disk. */
01523     fflush(logFile);
01524 }
01525 
01526 
01527 /***** AlertIntermediateInfo() *****
01528   Log number of scan packets and types to standard alert mechanism.
01529 */
01530 void AlertIntermediateInfo(SourceInfo * currentSource)
01531 {
01532     char logMessage[160];
01533     Event event;
01534 
01535     sprintf(logMessage, 
01536             MODNAME ": portscan status from %s: %d connections "
01537             "across %d hosts: TCP(%d), UDP(%d)%s",
01538             inet_ntoa(currentSource->saddr), 
01539             currentSource->numberOfConnections, 
01540             currentSource->numberOfDestinations,
01541             currentSource->numberOfTCPConnections, 
01542             currentSource->numberOfUDPConnections,
01543             (currentSource->stealthScanUsed) ? " STEALTH" : "");
01544 
01545     SetEvent(&event, GENERATOR_SPP_PORTSCAN, 
01546             PORTSCAN_INTER_INFO, 1, 0, 0, currentSource->event_id);
01547     CallAlertFuncs(NULL, logMessage, NULL, &event);
01548 
01549     return;
01550 }
01551 
01552 
01553 void ExtractHeaderInfo(Packet * p, struct in_addr * saddr, 
01554                        struct in_addr * daddr, u_short * sport, 
01555                        u_short * dport)
01556 {
01557     /*
01558      * This function seems kinda silly now that I don't have to do protocol
01559      * checks to use the proper protocol headers to get the port, but I think
01560      * it still makes it easier and I don't have to worry about something
01561      * changing later.
01562      */
01563 
01564     *sport = p->sp;
01565     *dport = p->dp;
01566     *saddr = p->iph->ip_src;
01567     *daddr = p->iph->ip_dst;
01568 }
01569 
01570 
01571 /* Check if packet originated from a machine we have been told to ignore
01572    SYN and UDP "scans" from, presumably because it's a server.
01573 */
01574 int IsServer(Packet * p)
01575 {
01576     ServerNode *currentServer = serverList;
01577 
01578 #ifdef DEBUG
01579     char sourceIP[16], ruleIP[16], ruleNetMask[16];
01580 
01581 #endif
01582 
01583     while(currentServer)
01584     {
01585         /*
01586          * Return 1 if the source addr is in the serverlist, 0 if nothing is
01587          * found.
01588          */
01589         if(CheckAddrPort(currentServer->address, 0, 0, p,
01590                          (ANY_SRC_PORT | currentServer->ignoreFlags), CHECK_SRC))
01591         {
01592 
01593 #ifdef DEBUG
01594             memset(sourceIP, '\0', 16);
01595             memset(ruleIP, '\0', 16);
01596             memset(ruleNetMask, '\0', 16);
01597             strncpy(sourceIP, inet_ntoa(p->iph->ip_src), 15);
01598             strncpy(ruleIP, inet_ntoa(*(struct in_addr *) & (currentServer->address->ip_addr)), 14);
01599             strncpy(ruleNetMask, inet_ntoa(*(struct in_addr *) & (currentServer->address->netmask)), 15);
01600 
01601             printf(MODNAME ": IsServer():  Server %s found in %s/%s!\n", sourceIP, ruleIP, ruleNetMask);
01602 #endif
01603 
01604             return(1);
01605         }
01606         currentServer = currentServer->nextNode;
01607     }
01608 
01609     return(0);
01610 }
01611 
01612 
01613 void SetupPortscanIgnoreHosts(void)
01614 {
01615     RegisterPreprocessor("portscan-ignorehosts", PortscanIgnoreHostsInit);
01616 }
01617 
01618 
01619 void PortscanIgnoreHostsInit(u_char * args)
01620 {
01621     CreateServerList(args);
01622 }
01623 
01624 
01625 /* Well, it seems we are ignoring more than just servers now.  We're also
01626    ignoring SYN and UDP scans from our own networks.  I guess this is okay.
01627    Most networks have a soft, chewy center, anyway.  Besides, this
01628    makes the coding easier! ;)
01629 */
01630 void CreateServerList(u_char * servers)
01631 {
01632     char **toks;
01633     int num_toks;
01634     int num_servers = 0;
01635     ServerNode *currentServer;
01636 
01637 #ifdef DEBUG
01638     char ruleIP[16], ruleNetMask[16];
01639 #endif
01640 
01641     currentServer = NULL;
01642     serverList = NULL;
01643 
01644     if(servers == NULL)
01645     {
01646         FatalError(MODNAME ": %s (%d)=> No arguments to portscan-ignorehosts preprocessor!\n", file_name, file_line);
01647     }
01648     /* tokenize the argument list */
01649     toks = mSplit(servers, " ", 31, &num_toks, '\\');
01650 
01651     /* convert the tokens and place them into the server list */
01652     for(num_servers = 0; num_servers < num_toks; num_servers++)
01653     {
01654         if(currentServer != NULL)
01655         {
01656             currentServer->nextNode = (ServerNode *) calloc(sizeof(ServerNode), sizeof(char));
01657             currentServer = currentServer->nextNode;
01658         }
01659         else
01660         {
01661             currentServer = (ServerNode *) calloc(sizeof(ServerNode), sizeof(char));
01662             serverList = currentServer;
01663         }
01664 
01665         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,MODNAME ": CreateServerList(): Adding server %s\n", toks[num_servers]););
01666         /* currentServer->ignoreFlags = 0; */
01667 
01668         PortscanIgnoreParseIP(toks[num_servers], currentServer);
01669         /* ParseIP(toks[num_servers], &currentServer->address); */
01670 
01671 #ifdef DEBUG
01672         memset(ruleIP, '\0', 16);
01673         memset(ruleNetMask, '\0', 16);
01674         strncpy(ruleIP, inet_ntoa(*(struct in_addr *) & currentServer->address->ip_addr), 15);
01675         strncpy(ruleNetMask, inet_ntoa(*(struct in_addr *) & currentServer->address->netmask), 15);
01676         printf(MODNAME ": CreateServerList(): Added server %s/%s\n", ruleIP, ruleNetMask);
01677 #endif
01678 
01679         currentServer->nextNode = NULL;
01680     }
01681 
01682     mSplitFree(&toks, num_toks);
01683 }
01684 
01685 
01686 
01687 void PortscanParseIP(char *addr)
01688 {
01689     char **toks;
01690     int num_toks;
01691     int i;
01692     IpAddrSet *tmp_addr;
01693     char *tmp;
01694 
01695     if(*addr == '!')
01696     {
01697         homeFlags |= EXCEPT_DST_IP;
01698         addr++;
01699     }
01700 
01701     if(*addr == '$')
01702     {
01703         if((tmp = VarGet(addr + 1)) == NULL)
01704         {
01705             FatalError("%s(%d) => Undefined variable %s\n", file_name, 
01706                        file_line, addr);
01707         }
01708     }
01709     else
01710     {
01711         tmp = addr;
01712     }
01713 
01714     if (*tmp == '[')
01715     {
01716         *(strrchr(tmp, (int)']')) = 0; /* null out the en-bracket */
01717 
01718         toks = mSplit(tmp+1, ",", 128, &num_toks, 0);
01719 
01720         for(i = 0; i < num_toks; i++)
01721         {
01722             tmp_addr = PortscanAllocAddrNode();
01723 
01724             ParseIP(toks[i], tmp_addr);
01725         }
01726 
01727         mSplitFree(&toks, num_toks);
01728     } 
01729     else
01730     {
01731         tmp_addr = PortscanAllocAddrNode();
01732         ParseIP(tmp, tmp_addr);
01733     }
01734 }
01735 
01736 
01737 void PortscanIgnoreParseIP(char *addr, ServerNode* server)
01738 {
01739     char **toks;
01740     int num_toks;
01741     int i;
01742     IpAddrSet *tmp_addr;
01743     int global_negation_flag;
01744     char *tmp;
01745 
01746     if(addr == NULL)
01747     {
01748         FatalError("%s(%d) => Undefined address in portscan-ignorehosts directive\n",
01749                    file_name, file_line);
01750     }
01751 
01752     if(*addr == '!')
01753     {
01754         global_negation_flag = 1;
01755         addr++;
01756     }
01757 
01758     if(*addr == '$')
01759     {
01760         if((tmp = VarGet(addr + 1)) == NULL)
01761         {
01762             FatalError("%s (%d) => Undefined variable %s\n", file_name, 
01763                        file_line, addr);
01764         }
01765     }
01766     else
01767     {
01768         tmp = addr;
01769     }
01770 
01771     if (*tmp == '[')
01772     {
01773         *(strrchr(tmp, (int)']')) = 0; /* null out the en-bracket */
01774 
01775         toks = mSplit(tmp+1, ",", 128, &num_toks, 0);
01776 
01777         for(i = 0; i < num_toks; i++)
01778         {
01779             tmp_addr = PortscanIgnoreAllocAddrNode(server);
01780 
01781             ParseIP(toks[i], tmp_addr);
01782         }
01783 
01784         mSplitFree(&toks, num_toks);
01785     } 
01786     else
01787     {
01788         tmp_addr = PortscanIgnoreAllocAddrNode(server);
01789         
01790         ParseIP(tmp, tmp_addr);
01791     }
01792 }
01793 
01794 IpAddrSet *PortscanAllocAddrNode()
01795 {
01796     IpAddrSet *idx;     /* IP struct indexing pointer */
01797 
01798     if(homeAddr == NULL)
01799     {
01800         homeAddr = (IpAddrSet *) calloc(sizeof(IpAddrSet), sizeof(char));
01801 
01802         if(homeAddr == NULL)
01803         {
01804             FatalError("Unable to allocate space for portscan IP addr\n");
01805         }
01806 
01807         return homeAddr;
01808     }
01809 
01810     idx = homeAddr;
01811 
01812     while(idx->next != NULL)
01813     {
01814         idx = idx->next;
01815     }
01816 
01817     idx->next = (IpAddrSet *) calloc(sizeof(IpAddrSet), sizeof(char));
01818 
01819     idx = idx->next;
01820 
01821     if(idx == NULL)
01822     {
01823         FatalError("Unable to allocate space for portscan IP address\n");
01824     }
01825 
01826     return idx;
01827 }
01828 
01829 
01830 
01831 IpAddrSet *PortscanIgnoreAllocAddrNode(ServerNode * server)
01832 {
01833     IpAddrSet *idx;     /* IP struct indexing pointer */
01834 
01835     if(server->address == NULL)
01836     {
01837         server->address = (IpAddrSet *) calloc(sizeof(IpAddrSet), sizeof(char));
01838 
01839         if(server->address == NULL)
01840         {
01841             FatalError("Unable to allocate space for portscan IP addr\n");
01842         }
01843         return server->address;
01844     }
01845     idx = server->address;
01846 
01847     while(idx->next != NULL)
01848     {
01849         idx = idx->next;
01850     }
01851 
01852     idx->next = (IpAddrSet *) calloc(sizeof(IpAddrSet), sizeof(char));
01853 
01854     idx = idx->next;
01855 
01856     if(idx == NULL)
01857     {
01858         FatalError("Unable to allocate space for portscan IP address\n");
01859     }
01860     return idx;
01861 }

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