what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

spp_portscan-0.2.9.c

spp_portscan-0.2.9.c
Posted Mar 30, 2000
Site spyjurenet.com

spp_portscan.c - Snort Portscan Preprocessor logs port scans through snort.

tags | tool, sniffer
SHA-256 | 6e6b56d477c46c50eea6ac3e90210ceecbbe1546a20509aadd808e90cd37f46d

spp_portscan-0.2.9.c

Change Mirror Download
/*
** Copyright (C) 1998,1999,2000 Martin Roesch <roesch@clark.net>
** Copyright (C) 1999,2000 Patrick Mullen <p_mullen@linuxrc.net>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

/* $Id: spp_portscan.c,v 1.10 2000/02/10 21:50:24 fyodor Exp $ */
/* Snort Portscan Preprocessor Plugin
by Patrick Mullen <p_mullen@linuxrc.net>
*/

#define MODNAME "spp_portscan"

#include "spp_portscan.h"
#include "rules.h"
#include "log.h"

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/*
TODO:

function descriptions
distributed portscans

*/


/* Definitions for scan types */
typedef enum _scanType { sNONE=0, sUDP=1, sSYN=2, sSYNFIN=4, sFIN=8, sNULL=16,
sXMAS=32, sFULLXMAS=64, sRESERVEDBITS=128, sVECNA=256, sNOACK=512, sNMAPID=1024,
sSPAU=2048 } ScanType;

/* Definitions for log levels */
typedef enum _logLevel { lNONE=0, lFILE=1 } LogLevel;


/* Structures for keeping track of connection information. */
typedef struct _connectionInfo
{
ScanType scanType;
u_short sport;
u_short dport;
time_t timestamp;
char tcpFlags[9]; /* Eight flags and a NULL */
struct _connectionInfo *prevNode;
struct _connectionInfo *nextNode;
} ConnectionInfo;

typedef struct _destinationInfo
{
struct in_addr daddr;
int numberOfConnections;
ConnectionInfo *connectionsList;
struct _destinationInfo *prevNode;
struct _destinationInfo *nextNode;
} DestinationInfo;

typedef struct _sourceInfo
{
struct in_addr saddr;
int numberOfConnections;
long numberOfDestinations; /* must be as large as address space */
int scanDetected;
time_t reportTime; /* last time we reported on this source's activities */
DestinationInfo *destinationsList;
struct _sourceInfo *prevNode;
struct _sourceInfo *nextNode;
} SourceInfo;

typedef struct _scanList
{
SourceInfo *listHead;
SourceInfo *lastSource;
long numberOfSources; /* must be as large as address space */
} ScanList;

typedef struct _serverNode /* for keeping track of our network's servers */
{
u_long address;
u_long netmask;
struct _serverNode *nextNode;
} ServerNode;


/** FUNCTION PROTOTYPES **/
/* Add connection information */
int NewScan(ScanList*, Packet*, ScanType, time_t);
ConnectionInfo* NewConnection(Packet*, ScanType, time_t);
ConnectionInfo* AddConnection(ConnectionInfo*, Packet*, ScanType, time_t);
DestinationInfo* NewDestination(Packet*, ScanType, time_t);
DestinationInfo* AddDestination(DestinationInfo*, Packet*, ScanType, time_t);
SourceInfo* NewSource(Packet*, ScanType, time_t);
SourceInfo* AddSource(SourceInfo*, Packet*, ScanType, time_t);

/* Remove connection information */
void ExpireConnections(ScanList*, time_t, time_t);
void RemoveConnection(ConnectionInfo*);
void RemoveDestination(DestinationInfo*);
void RemoveSource(SourceInfo*);
void ClearConnectionInfoFromSource(SourceInfo*);

/* Logging functions */
void LogScanInfoToSeparateFile(SourceInfo*);

/* Miscellaneous functions */
ScanList* CreateScanList(void);
ScanType CheckTCPFlags(u_char);
int IsServer(Packet*);

/* For portscan-ignorehosts */
void CreateServerList(u_char*);

/* Global variables */
ScanList *scanList;
ServerNode *serverList;
ScanType scansToWatch;
u_long homeNet, homeNetMask;
time_t maxTime;
long maxPorts;
LogLevel logLevel;
enum _timeFormat { tLOCAL, tGMT } timeFormat;
FILE *logFile;

/* external globals from rules.c */
extern char *file_name;
extern int file_line;


ConnectionInfo* NewConnection(Packet *p, ScanType scanType, time_t timestamp)
{
ConnectionInfo *newConnection = (ConnectionInfo*)malloc(sizeof(ConnectionInfo));

newConnection->prevNode = NULL;
newConnection->nextNode = NULL;

newConnection->scanType = scanType;
newConnection->timestamp = timestamp;

/* The ports are already supposed to be in host order from decode.c */
newConnection->sport = p->sp;
newConnection->dport = p->dp;

switch(p->iph->ip_proto)
{
case IPPROTO_TCP:
CreateTCPFlagString(p, newConnection->tcpFlags);
break;

case IPPROTO_UDP:
strncpy(newConnection->tcpFlags, "\0", 1);
break;

default:
/* This should never happen because it's already filtered. */
FatalError(MODNAME": NewConnection(): Invalid protocol!\n");
break;
}

return(newConnection);
}

ConnectionInfo* AddConnection(ConnectionInfo *currentConnection, Packet *p, ScanType scanType, time_t timestamp)
{
if(currentConnection->nextNode)
FatalError(MODNAME": AddConnection(): Not at end of connection list!");

currentConnection->nextNode = NewConnection(p, scanType, timestamp);
currentConnection->nextNode->prevNode = currentConnection;

return(currentConnection->nextNode);
}


DestinationInfo* NewDestination(Packet *p, ScanType scanType, time_t timestamp)
{
DestinationInfo *newDestination = (DestinationInfo*)malloc(sizeof(DestinationInfo));

newDestination->prevNode = NULL;
newDestination->nextNode = NULL;
newDestination->daddr = p->iph->ip_dst;
newDestination->connectionsList = NewConnection(p, scanType, timestamp);
newDestination->numberOfConnections = 1;

return(newDestination);
}


DestinationInfo* AddDestination(DestinationInfo* currentDestination, Packet *p,
ScanType scanType, time_t timestamp)
{
if(currentDestination->nextNode)
FatalError(MODNAME": AddDestination(): Not at end of destination list!");

currentDestination->nextNode = NewDestination(p, scanType, timestamp);
currentDestination->nextNode->prevNode = currentDestination;
return(currentDestination->nextNode);
}


SourceInfo* NewSource(Packet *p, ScanType scanType, time_t timestamp)
{
SourceInfo *newSource = (SourceInfo*)malloc(sizeof(SourceInfo));

newSource->prevNode = NULL;
newSource->nextNode = NULL;
newSource->saddr = p->iph->ip_src;
newSource->numberOfConnections = 1;
newSource->scanDetected = 0;
newSource->destinationsList = NewDestination(p, scanType, timestamp);
newSource->numberOfDestinations = 1;

return(newSource);
}


SourceInfo* AddSource(SourceInfo *currentSource, Packet *p, ScanType scanType, time_t timestamp)
{
if(currentSource->nextNode)
FatalError(MODNAME": AddSource(): Not at end of source list!");

currentSource->nextNode = NewSource(p, scanType, timestamp);
currentSource->nextNode->prevNode = currentSource;

return(currentSource->nextNode);
}


void RemoveConnection(ConnectionInfo *delConnection)
{
/* If there is a prev and/or next node, make them point
to the proper places. Otherwise, just delete this node.
*/
if(delConnection->prevNode || delConnection->nextNode)
{
if(delConnection->prevNode)
{
delConnection->prevNode->nextNode = delConnection->nextNode;
}
else if(delConnection->nextNode)
{
delConnection->nextNode->prevNode = NULL;
}

if(delConnection->nextNode)
{
delConnection->nextNode->prevNode = delConnection->prevNode;
}
else if(delConnection->prevNode)
{
delConnection->prevNode->nextNode = NULL;
}
}

free(delConnection);
}


void RemoveDestination(DestinationInfo *delDestination)
{
/* If there is a prev and/or next node, make them point
to the proper places. Otherwise, just delete this node.
*/
if(delDestination->prevNode || delDestination->nextNode)
{
if(delDestination->prevNode)
{
delDestination->prevNode->nextNode = delDestination->nextNode;
}
else if(delDestination->nextNode)
{
delDestination->nextNode->prevNode = NULL;
}

if(delDestination->nextNode)
{
delDestination->nextNode->prevNode = delDestination->prevNode;
}
else if(delDestination->prevNode)
{
delDestination->prevNode->nextNode = NULL;
}
}

free(delDestination);
}


void RemoveSource(SourceInfo *delSource)
{
/* If there is a prev and/or next node, make them point
to the proper places. Otherwise, just delete this node.
*/
if(delSource->prevNode || delSource->nextNode)
{
if(delSource->prevNode)
{
delSource->prevNode->nextNode = delSource->nextNode;
}
else if(delSource->nextNode)
{
delSource->nextNode->prevNode = NULL;
}

if(delSource->nextNode)
{
delSource->nextNode->prevNode = delSource->prevNode;
}
else if(delSource->prevNode)
{
delSource->prevNode->nextNode = NULL;
}
}

free(delSource);
}


/* Go through each connection and remove any connections that are old. If
the removal of a node makes a parent node empty, remove that node, all
the way back to the root.
*/
void ExpireConnections(ScanList *scanList, time_t watchPeriod, time_t currentTime)
{
SourceInfo *currentSource = scanList->listHead, *tmpSource;
DestinationInfo *currentDestination, *tmpDestination;
ConnectionInfo *currentConnection, *tmpConnection;

/* Empty list. Get out of here. */
if(!scanList->listHead) return;

while(currentSource)
{
/* If this source host is scanning us, we don't want to lose any connections so go back to top. */
if(currentSource->scanDetected)
{
currentSource = currentSource->nextNode;
continue;
}

currentDestination = currentSource->destinationsList;

while(currentDestination)
{
currentConnection = currentDestination->connectionsList;
while(currentConnection)
{
if(currentConnection->timestamp + watchPeriod < currentTime)
{
/* Expire the connection */
tmpConnection = currentConnection;
currentConnection = currentConnection->nextNode;

/* If this is the first connection, we need to update connectionsList. */
if(tmpConnection->prevNode == NULL)
{
currentDestination->connectionsList = tmpConnection->nextNode;
}

RemoveConnection(tmpConnection);
currentSource->numberOfConnections--;
currentDestination->numberOfConnections--;
}
else
{
currentConnection = currentConnection->nextNode;
}
}
tmpDestination = currentDestination;
currentDestination = currentDestination->nextNode;
if(tmpDestination->numberOfConnections == 0)
{
if(tmpDestination->prevNode == NULL)
{
currentSource->destinationsList = tmpDestination->nextNode;
}

RemoveDestination(tmpDestination);
currentSource->numberOfDestinations--;
}
}
tmpSource = currentSource;
currentSource = currentSource->nextNode;
if(tmpSource->numberOfDestinations == 0)
{
/* If this is the first source, we need to update scanList. */
if(tmpSource->prevNode == NULL)
{
/* This is fine, even if tmpSource->nextNode is NULL */
scanList->listHead = tmpSource->nextNode;
}

RemoveSource(tmpSource);
scanList->numberOfSources--;
}
}
if(scanList->numberOfSources == 0)
{
scanList->listHead = NULL;
}
}


/*
Add the connection information and return the
new number of connections for this host
*/
int NewScan(ScanList *scanList, Packet *p, ScanType scanType, time_t timestamp)
{
SourceInfo *currentSource = scanList->listHead;
DestinationInfo *currentDestination;
ConnectionInfo *currentConnection;
int matchFound = 0;

struct in_addr saddr;
struct in_addr daddr;
u_short sport;
u_short dport;

/* If list is empty, create the list and add this entry. */
if(!scanList->listHead)
{
scanList->listHead = NewSource(p, scanType, timestamp);
scanList->numberOfSources = 1;
scanList->lastSource = scanList->listHead;
return(scanList->listHead->numberOfConnections);
}

ExtractHeaderInfo(p, &saddr, &daddr, &sport, &dport);

while(!matchFound)
{
if(currentSource->saddr.s_addr == saddr.s_addr)
{
currentDestination = currentSource->destinationsList;

if(currentSource->destinationsList == NULL)
{
currentSource->destinationsList = NewDestination(p, scanType, timestamp);
currentSource->numberOfConnections++;
currentSource->numberOfDestinations++;
matchFound = 1;
}

currentDestination = currentSource->destinationsList;

while(!matchFound)
{
if(currentDestination->daddr.s_addr == daddr.s_addr)
{
currentConnection = currentDestination->connectionsList;

while(!matchFound)
{
/* There should be error checking for currentConnection == NULL, but that
should never happen.
*/
if(currentConnection == NULL)
FatalError("currentConnection is NULL!!!??\n");

if((currentConnection->dport == dport) && (currentConnection->scanType == scanType))
{
currentConnection->timestamp = timestamp;
currentConnection->sport = sport;
matchFound = 1;
}
else
{
/* If not at end of list, keep going, otherwise create a node. */
if(!currentConnection->nextNode)
{
currentConnection = AddConnection(currentConnection, p, scanType, timestamp);
currentSource->numberOfConnections++;
currentDestination->numberOfConnections++;
matchFound = 1;
}
else currentConnection = currentConnection->nextNode;
}
}
}
else
{
if(!currentDestination->nextNode)
{
currentDestination = AddDestination(currentDestination, p, scanType, timestamp);
currentSource->numberOfConnections++;
currentSource->numberOfDestinations++;
matchFound = 1;
}
else currentDestination = currentDestination->nextNode;
}
}
}
else
{
if(!currentSource->nextNode)
{
currentSource = AddSource(currentSource, p, scanType, timestamp);
currentSource->numberOfConnections = 1;
scanList->numberOfSources++;
matchFound = 1;
}
else currentSource = currentSource->nextNode;
}
}

scanList->lastSource = currentSource;
return(currentSource->numberOfConnections);
}


ScanList* CreateScanList(void)
{
ScanList *newList = (ScanList*)malloc(sizeof(ScanList));
newList->listHead = NULL;
newList->lastSource = NULL;
newList->numberOfSources = 0;

return(newList);
}



void PortscanPreprocFunction(Packet *p)
{
/* The main loop. Whenever this is called, first we expire connections so we
don't get false positives from stale connections. Then we add the new
connection information and check if the latest connection has passed the
threshold. If it has or if a stealth technique was used, we immediately
report the scan. Then we go through the list and any host that has been
flagged as doing a portscan and has passed the necessary amount of time
between reports and has connections stored are reported and cleared. Any
host that has been flagged as doing a portscan and has passed the necessary
amount of time between reports and does not have connections stored has the
portscan flag cleared and will automatically be flushed at next call.
*/

SourceInfo *currentSource;
ScanType scanType;
time_t currTime;
char logMessage[80];

/* Only do processing on IP Packets */
if(p->iph == NULL)
{
return;
}

/* Here we check if it is a protocol we are watching and if it is
a destination we are watching. If either fails, we return abruptly.
*/
switch(p->iph->ip_proto)
{
case IPPROTO_TCP:
if(p->tcph == NULL)
{
/* ZDNOTE Fragmented packets have IPH set to NULL so `nmap -f` defeats
SPP, at least until reassembly or the header pointer is fixed.
*/
return;
}
scanType = CheckTCPFlags(p->tcph->th_flags);
break;

case IPPROTO_UDP:
/* We no longer check for NULL UDP headers here, because it really doesn't matter
anymore. We don't access it. We just use p->[sd]p instead.
*/
scanType = sUDP;
break;

default:
/* The packet isn't a protocol we watch, so get out of here. */
return; /*** RETURN ***/
break;
}

/* For speed, we're going to drop out right now if this packet is not any type of scan.
My assumption is most packets on the network are not going to be any type of scan
packet (not even SYN or UDP), so this extra check will be faster in the long run.
*/
if(!scanType) return;

/* The checks above are faster, so now that we know this packet is interesting we'll
check the address.
*/
if(!CheckAddrPort(homeNet, homeNetMask, 0, 0, p, ANY_DST_PORT, CHECK_DST)) return;


/* If we ignore SYN and UDP scans from this host (presumably because it's a server),
clear out those flags so we don't get false alarms.
If it's a server, we also need to make sure there are no reserved bits set
because otherwise "2*S*****" shows as UNKNOWN instead of as SYN w/ RESERVEDBITS.
The beast below makes sure we are actually watching for RB scans. The previous
version would have let servers be left as SYN scans if a reserved bit was set.
*/
if(IsServer(p) && !(scanType & sRESERVEDBITS & scansToWatch)) scanType &= ~(sSYN | sUDP);

if(scanType & scansToWatch)
{
currTime = time(NULL);
ExpireConnections(scanList, maxTime, currTime);

/* If more than maxPorts connections made or if stealth scan technique
was used, mark this as a portscan.
*/

if((NewScan(scanList, p, scanType, currTime) > maxPorts) ||
(scanType & ~(sSYN | sUDP)))
{
if(!scanList->lastSource->scanDetected)
{
sprintf(logMessage, MODNAME ": PORTSCAN DETECTED from %s", inet_ntoa(scanList->lastSource->saddr));
(*AlertFunc)(NULL, logMessage);
scanList->lastSource->scanDetected = 1;
scanList->lastSource->reportTime = currTime;
}
}

/* See if there's anyone we can snitch on. ;) */
currentSource = scanList->listHead;
while(currentSource)
{
if(currentSource->scanDetected)
{
if(currentSource->reportTime + maxTime < currTime)
{
if(currentSource->numberOfConnections == 0)
{
/* Portscan stopped. Clear flag. */
sprintf(logMessage, MODNAME ": End of portscan from %s", inet_ntoa(currentSource->saddr));
(*AlertFunc)(NULL, logMessage);
currentSource->scanDetected = 0;
}
else
{
/* This is where we do the real logging */
if(logLevel & lFILE) LogScanInfoToSeparateFile(currentSource);
ClearConnectionInfoFromSource(currentSource);
currentSource->reportTime = currTime;
}
}
}
currentSource = currentSource->nextNode;
}
}
}



void ClearConnectionInfoFromSource(SourceInfo *currentSource)
{
DestinationInfo *currentDestination, *tmpDestination;
ConnectionInfo *currentConnection, *tmpConnection;

currentDestination = currentSource->destinationsList;
while(currentDestination)
{
currentConnection = currentDestination->connectionsList;
while(currentConnection)
{
tmpConnection = currentConnection;
currentConnection = currentConnection->nextNode;
RemoveConnection(tmpConnection);
currentDestination->numberOfConnections--;
currentSource->numberOfConnections--;
}
tmpDestination = currentDestination;
currentDestination = currentDestination->nextNode;
RemoveDestination(tmpDestination);
currentSource->numberOfDestinations--;
}
currentSource->destinationsList = NULL;
}


void SetupPortscan(void)
{
RegisterPreprocessor("portscan", PortscanInit);
}


void PortscanInit(u_char *args)
{
ParsePortscanArgs(args);
scanList = CreateScanList();

/* We set serverList to NULL here so if portscan-ignorehosts is used it must be set
after portscan. This is necessary to make sure we don't check an empty list.
*/
serverList = NULL;
AddFuncToPreprocList(PortscanPreprocFunction);
}


ScanType CheckTCPFlags(u_char th_flags)
{
u_char th_flags_cleaned;
ScanType scan = sNONE;

/* Strip off the reserved bits for the testing, but flag
that a scan is being done.
*/
th_flags_cleaned = th_flags & ~(R_RES1 | R_RES2);

if(th_flags != th_flags_cleaned)
{
scan = sRESERVEDBITS;
}

/* Most TCP packets will have the ACK bit set, so split that out
quickly. Any scans which use ACK (like Full-XMAS) must be
added to this part. Otherwise, it goes in the !ACK section.
In addition, anything that is !ACK && !SYN eventually gets
flagged as something. This is to hopefully detect new stealth scan types.
*/
if(th_flags_cleaned & R_ACK)
{
if(th_flags_cleaned == (R_SYN | R_RST | R_ACK | R_FIN | R_PSH | R_URG))
scan |= sFULLXMAS;
if(th_flags_cleaned == (R_SYN | R_PSH | R_ACK | R_URG)) scan |= sSPAU;
}
else
{
/* ZDNOTE This could/should be optimized, but just by having the check
for SYN or RST being first makes this faster. (Anything else is a scan
and shouldn't be hit often.
*/
switch(th_flags_cleaned)
{
case R_SYN:
scan |= sSYN;
break;

case R_RST:
/* Nothing. This is legitimately tearing down a connection. */
break;

case R_FIN:
scan |= sFIN;
break;

case (R_SYN | R_FIN):
scan |= sSYNFIN;
break;

case 0:
scan |= sNULL;
break;

case (R_FIN | R_PSH | R_URG):
scan |= sXMAS;
break;

case R_URG:
case R_PSH:
case (R_URG | R_FIN):
case (R_PSH | R_FIN):
case (R_URG | R_PSH):
scan |= sVECNA;
break;

case (R_SYN | R_FIN | R_PSH | R_URG):
scan |= sNMAPID;
break;

default:
/* We assume that anything down here w/out an ACK flag is some sort of a
scan or something. Anyway, we'll flag it because if it doesn't have
an ACK it should have been only a SYN or RST and be detected above.
*/
scan |= sNOACK;
break;
}
}

return(scan);
}


void ParsePortscanArgs(u_char *args)
{
char **toks;
int numToks;

#ifdef DEBUG
printf(MODNAME": ParsePortscanArgs(): %s\n", args);
#endif

logLevel = lNONE;

if(!args)
{
FatalError( "ERROR %s (%d) => portscan configuration format: address/mask ports seconds [logfile]\n", file_name, file_lin
e);
}

toks = mSplit(args, " ", 4, &numToks, '\\'); /*ZDNOTE What does the '\\' do? */

if((numToks < 3) || (numToks > 4))
{
FatalError("ERROR: %s (%d) => portscan configuration format: address/mask ports seconds [logfile]\n", file_name, file_lin
e);
}

maxPorts = atoi(toks[1]);
maxTime = atoi(toks[2]);
ParseIP(toks[0], &homeNet, &homeNetMask);

if(numToks == 4)
{
logFile = fopen(toks[3], "a");
if(!logFile) FatalError(MODNAME": logfile open error");

logLevel |= lFILE;
}

/* How about some error detecting? :) */
if(maxPorts == 0 || maxTime == 0)
{
FatalError( "ERROR %s (%d) => portscan configuration format: address/mask ports seconds [logfile]\n", file_name, file_lin
e);
}


/*ZDNOTE Compile time settings. Obviously needs to become runtime settings. */
/* If you do not want every packet with reserved bits set (which shouldn't happen),
just remove the "| sRESERVEDBITS" from the end of this line. If you do that, you
may wish to add a line to detect that in the rules file(s).
*/
/*ZDNOTE If/when I add this to options, this would be "usfFnxXrvid" scan detection. */
scansToWatch = -1; /* Watch for ALL scans */
/*scansToWatch = sUDP | sSYN | sFIN | sSYNFIN | sNULL | sXMAS | sFULLXMAS | sRESERVEDBITS |
sVECNA | sNOACK | sNMAPID | sSPAU;*/
/* can watch all scans but disable some by doing the following*/
/*scansToWatch = ~(sRESERVEDBITS | sNMAPID );*/

timeFormat = tLOCAL; /* Alternatively, you can do tGMT (should be runtime setting) */
}


void LogScanInfoToSeparateFile(SourceInfo *currentSource)
{
DestinationInfo *currentDestination;
ConnectionInfo *currentConnection;
char *scanType;
char *reservedBits;
char *month;
struct tm *time;
char sourceAddress[16], destinationAddress[16];
char outBuf[160]; /* Don't need anywhere near this, but better safe than sorry. */

memset(sourceAddress, '\0', 16);
memset(destinationAddress, '\0', 16);

/* Can't have two inet_ntoa() calls in a single printf because it uses a static
buffer. It's also faster to only do it twice instead of twice for each iteration.
*/
strncpy(sourceAddress, inet_ntoa(currentSource->saddr), 15);

for(currentDestination = currentSource->destinationsList; currentDestination;
currentDestination = currentDestination->nextNode)
{
strncpy(destinationAddress, inet_ntoa(currentDestination->daddr), 15);

for(currentConnection = currentDestination->connectionsList; currentConnection;
currentConnection = currentConnection->nextNode)
{
time = (timeFormat == tLOCAL) ? localtime(&currentConnection->timestamp)
: gmtime(&currentConnection->timestamp);
switch(time->tm_mon)
{
case 0:
month = "Jan";
break;
case 1:
month = "Feb";
break;
case 2:
month = "Mar";
break;
case 3:
month = "Apr";
break;
case 4:
month = "May";
break;
case 5:
month = "Jun";
break;
case 6:
month = "Jul";
break;
case 7:
month = "Aug";
break;
case 8:
month = "Sep";
break;
case 9:
month = "Oct";
break;
case 10:
month = "Nov";
break;
case 11:
month = "Dec";
break;
default:
month = "MONTH IS INVALID!!";
break;
}

reservedBits = (currentConnection->scanType & sRESERVEDBITS) ? "RESERVEDBITS" : "";

#ifdef DEBUG
printf("scanType = %x mask = %x result = (%x)\n", currentConnection->scanType, ~sRESERVEDBITS, currentConnection->scanT
ype & ~sRESERVEDBITS);
#endif

switch(currentConnection->scanType & ~sRESERVEDBITS)
{
case sUDP:
scanType = "UDP";
break;
case sSYN:
scanType = "SYN";
break;
case sFIN:
scanType = "FIN";
break;
case sSYNFIN:
scanType = "SYNFIN";
break;
case sNULL:
scanType = "NULL";
break;
case sXMAS:
scanType = "XMAS";
break;
case sFULLXMAS:
scanType = "FULLXMAS";
break;
case sVECNA:
scanType = "VECNA";
break;
case sNOACK:
scanType = "NOACK";
break;
case sNMAPID:
scanType = "NMAPID";
break;
case sSPAU:
scanType = "SPAU";
break;
default:
/* This used to mean I screwed up, but now since any packet that has reserved bits set is
set as a scan it looks bad if "ERROR" shows up when the packet really has something
bizarre like "2****P**".
*/

#ifdef DEBUG
printf("UNKNOWN: scanType = %x (%x)\n", currentConnection->scanType, currentConnection->scanType & ~sRESERVEDBITS
);
#endif

scanType = "UNKNOWN";
break;
}

/* I have control of all data here, so this should be safe */
sprintf(outBuf, "%s %2d %.2d:%.2d:%.2d %s:%d -> %s:%d %s %s %s\n", month, time->tm_mday,
time->tm_hour, time->tm_min, time->tm_sec,
sourceAddress, currentConnection->sport, destinationAddress,
currentConnection->dport, scanType, currentConnection->tcpFlags, reservedBits);
fwrite(outBuf, strlen(outBuf), 1, logFile);
}
}

/* Now that we're done, flush the buffer to disk. */
fflush(logFile);
}


void ExtractHeaderInfo(Packet *p, struct in_addr *saddr, struct in_addr *daddr,
u_short *sport, u_short *dport)
{
/* This function seems kinda silly now that I don't have to do protocol checks
to use the proper protocol headers to get the port, but I think it still
makes it easier and I don't have to worry about something changing later.
*/

*sport = p->sp;
*dport = p->dp;
*saddr = p->iph->ip_src;
*daddr = p->iph->ip_dst;
}


/* Check if packet originated from a machine we have been told to ignore
SYN and UDP "scans" from, presumably because it's a server.
*/
int IsServer(Packet *p)
{
ServerNode *currentServer = serverList;

#ifdef DEBUG
char sourceIP[16], ruleIP[16], ruleNetMask[16];
#endif

while(currentServer)
{
/* Yo! If da current packet came from da current address in da server list,
we do a return here! Again wit' da multiple returns. I's a baaaad dooby!
*/
if(CheckAddrPort(currentServer->address, currentServer->netmask,
0, 0, p, ANY_SRC_PORT, CHECK_SRC))
{

#ifdef DEBUG
memset(sourceIP, '\0', 16);
memset(ruleIP, '\0', 16);
memset(ruleNetMask, '\0', 16);
strncpy(sourceIP, inet_ntoa(p->iph->ip_src), 15);
strncpy(ruleIP, inet_ntoa(*(struct in_addr*)&currentServer->address), 15);
strncpy(ruleNetMask, inet_ntoa(*(struct in_addr*)&currentServer->netmask), 15);

printf(MODNAME": IsServer(): Server %s found in %s/%s!\n", sourceIP, ruleIP, ruleNetMask);
#endif

return(1);
}

currentServer = currentServer->nextNode;
}

return(0);
}


void SetupPortscanIgnoreHosts(void)
{
RegisterPreprocessor("portscan-ignorehosts", PortscanIgnoreHostsInit);
}


void PortscanIgnoreHostsInit(u_char *args)
{
CreateServerList(args);
}


/* Well, it seems we are ignoring more than just servers now. We're also
ignoring SYN and UDP scans from our own networks. I guess this is okay.
Most networks have a soft, chewy center, anyway. Besides, this
makes the coding easier! ;)
*/
void CreateServerList(u_char *servers)
{
char **toks;
int num_toks;
int num_servers = 0;
ServerNode *currentServer;

#ifdef DEBUG
char ruleIP[16], ruleNetMask[16];
#endif

currentServer = NULL;
serverList = NULL;

if(servers == NULL)
{
FatalError( "ERROR %s (%d)=> No arguments to portscan-ignorehosts preprocessor!\n", file_name, file_line);
}

/* tokenize the argument list */
toks = mSplit(servers, " ", 31, &num_toks, '\\');

/* convert the tokens and place them into the server list */
for(num_servers = 0; num_servers < num_toks; num_servers++)
{
if(currentServer != NULL)
{
currentServer->nextNode = (ServerNode*)malloc(sizeof(ServerNode));
currentServer = currentServer->nextNode;
}
else
{
currentServer = (ServerNode*)malloc(sizeof(ServerNode));
serverList = currentServer;
}

#ifdef DEBUG
printf(MODNAME": CreateServerList(): Adding server %s\n", toks[num_servers]);
#endif

ParseIP(toks[num_servers], &currentServer->address, &currentServer->netmask);

#ifdef DEBUG
memset(ruleIP, '\0', 16);
memset(ruleNetMask, '\0', 16);
strncpy(ruleIP, inet_ntoa(*(struct in_addr*)&currentServer->address), 15);
strncpy(ruleNetMask, inet_ntoa(*(struct in_addr*)&currentServer->netmask), 15);
printf(MODNAME": CreateServerList(): Added server %s/%s\n", ruleIP, ruleNetMask);
#endif

currentServer->nextNode = NULL;
}

free(toks); /* ZDNOTE Does this really free the memory allocated to each token? */
}


Login or Register to add favorites

File Archive:

November 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Nov 1st
    30 Files
  • 2
    Nov 2nd
    0 Files
  • 3
    Nov 3rd
    0 Files
  • 4
    Nov 4th
    12 Files
  • 5
    Nov 5th
    44 Files
  • 6
    Nov 6th
    18 Files
  • 7
    Nov 7th
    9 Files
  • 8
    Nov 8th
    8 Files
  • 9
    Nov 9th
    3 Files
  • 10
    Nov 10th
    0 Files
  • 11
    Nov 11th
    14 Files
  • 12
    Nov 12th
    20 Files
  • 13
    Nov 13th
    63 Files
  • 14
    Nov 14th
    18 Files
  • 15
    Nov 15th
    8 Files
  • 16
    Nov 16th
    0 Files
  • 17
    Nov 17th
    0 Files
  • 18
    Nov 18th
    0 Files
  • 19
    Nov 19th
    0 Files
  • 20
    Nov 20th
    0 Files
  • 21
    Nov 21st
    0 Files
  • 22
    Nov 22nd
    0 Files
  • 23
    Nov 23rd
    0 Files
  • 24
    Nov 24th
    0 Files
  • 25
    Nov 25th
    0 Files
  • 26
    Nov 26th
    0 Files
  • 27
    Nov 27th
    0 Files
  • 28
    Nov 28th
    0 Files
  • 29
    Nov 29th
    0 Files
  • 30
    Nov 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2024 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close