📄 spp_portscan.c
字号:
/*
** 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.19 2000/07/07 12:00:25 fyodor Exp $ */
/* Snort Portscan Preprocessor Plugin
by Patrick Mullen <p_mullen@linuxrc.net>
Version 0.2.14
*/
#define MODNAME "spp_portscan"
#include "spp_portscan.h"
#include "rules.h"
#include "log.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
/*
BUGS:
I dare say the connection information reported at the end of a scan is
wildly inaccurate. Search for "ZDNOTE CONNECTION INFORMATION" for
more details.
TODO:
configuration file
scans to multiple networks
log scan packet contents
- Once a host has been determined to be scanning, automatically log packets from
that host to reduce memory requirements.
documentation
function descriptions
distributed portscans
*/
struct spp_timeval
{
time_t tv_sec;
time_t tv_usec;
};
/* 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, sINVALIDACK=4096
} ScanType;
/* Definitions for log levels */
typedef enum _logLevel
{
lNONE=0, lFILE=1, lEXTENDED=2, lPACKET=4
} LogLevel;
/* Structures for keeping track of connection information. */
typedef struct _connectionInfo
{
ScanType scanType;
u_short sport;
u_short dport;
struct spp_timeval timestamp;
char tcpFlags[9]; /* Eight flags and a NULL */
u_char *packetData;
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;
int numberOfDestinations;
int numberOfTCPConnections;
int numberOfUDPConnections;
/* ZDNOTE CONNECTION INFORMATION
The totals statistics are generally inaccurate and for general information
of the severity of a scan, rather than a hard and fast count of what was scanned.
To provide 100% accurate statistics, the architecture would have to be heavily
modified. This should probably be done anyway, but not today.
Ways these counts will be inaccurate:
1) Hosts is incorrect if a host is rescanned after all connection information is cleared
2) Connections counts are incorrect if same ports are rescanned after they
have already been reported.
3) Probably more. This is a little more difficult to do reliably
than I realized. Ah, well.
*/
int totalNumberOfTCPConnections;
int totalNumberOfUDPConnections;
int totalNumberOfDestinations;
struct spp_timeval firstPacketTime;
struct spp_timeval lastPacketTime;
int reportStealth;
int stealthScanUsed;
int scanDetected;
struct spp_timeval 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);
ConnectionInfo* NewConnection(Packet*, ScanType);
ConnectionInfo* AddConnection(ConnectionInfo*, Packet*, ScanType);
DestinationInfo* NewDestination(Packet*, ScanType);
DestinationInfo* AddDestination(DestinationInfo*, Packet*, ScanType);
SourceInfo* NewSource(Packet*, ScanType);
SourceInfo* AddSource(SourceInfo*, Packet*, ScanType);
/* Remove connection information */
void ExpireConnections(ScanList*, struct spp_timeval, struct spp_timeval);
void RemoveConnection(ConnectionInfo*);
void RemoveDestination(DestinationInfo*);
void RemoveSource(SourceInfo*);
void ClearConnectionInfoFromSource(SourceInfo*);
/* Logging functions */
void LogScanInfoToSeparateFile(SourceInfo*);
void AlertIntermediateInfo(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;
struct spp_timeval maxTime;
long maxPorts;
LogLevel logLevel;
enum _timeFormat
{
tLOCAL, tGMT
} timeFormat;
FILE *logFile;
int packetLogSize; /* Number of data bytes to log per scan packet */
/* external globals from rules.c */
extern char *file_name;
extern int file_line;
ConnectionInfo* NewConnection(Packet *p, ScanType scanType)
{
ConnectionInfo *newConnection = (ConnectionInfo*)malloc(sizeof(ConnectionInfo));
newConnection->prevNode = NULL;
newConnection->nextNode = NULL;
newConnection->scanType = scanType;
/* timestamp provided by libpcap. This is
available realtime and during -r playback */
newConnection->timestamp.tv_sec = p->pkth->ts.tv_sec;
newConnection->timestamp.tv_usec = p->pkth->ts.tv_usec;
/* 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);
/* ZDNOTE PACKET LOGGING */
if (logLevel & lPACKET)
{
/* Determine buffer size = header size + lower(datasize, packetLogSize) */
/* Allocate memory */
/* Copy data */
}
break;
case IPPROTO_UDP:
strncpy(newConnection->tcpFlags, "\0", 1);
/* ZDNOTE PACKET LOGGING */
if (logLevel & lPACKET)
{
/* Determine buffer size = header size + lower(datasize, packetLogSize) */
/* Allocate memory */
/* Copy data */
}
break;
default:
/* This should never happen because it's already filtered. */
FatalError(MODNAME": NewConnection(): Invalid protocol! (%d)\n", p->iph->ip_proto);
break;
}
return(newConnection);
}
ConnectionInfo* AddConnection(ConnectionInfo *currentConnection, Packet *p, ScanType scanType)
{
if (currentConnection->nextNode)
FatalError(MODNAME": AddConnection(): Not at end of connection list!");
currentConnection->nextNode = NewConnection(p, scanType);
currentConnection->nextNode->prevNode = currentConnection;
return(currentConnection->nextNode);
}
DestinationInfo* NewDestination(Packet *p, ScanType scanType)
{
DestinationInfo *newDestination = (DestinationInfo*)malloc(sizeof(DestinationInfo));
newDestination->prevNode = NULL;
newDestination->nextNode = NULL;
newDestination->daddr = p->iph->ip_dst;
newDestination->connectionsList = NewConnection(p, scanType);
newDestination->numberOfConnections = 1;
return(newDestination);
}
DestinationInfo* AddDestination(DestinationInfo* currentDestination, Packet *p,
ScanType scanType)
{
if (currentDestination->nextNode)
FatalError(MODNAME": AddDestination(): Not at end of destination list!");
currentDestination->nextNode = NewDestination(p, scanType);
currentDestination->nextNode->prevNode = currentDestination;
return(currentDestination->nextNode);
}
SourceInfo* NewSource(Packet *p, ScanType scanType)
{
SourceInfo *newSource = (SourceInfo*)malloc(sizeof(SourceInfo));
newSource->prevNode = NULL;
newSource->nextNode = NULL;
newSource->saddr = p->iph->ip_src;
newSource->numberOfConnections = 1;
newSource->firstPacketTime.tv_sec = p->pkth->ts.tv_sec;
newSource->firstPacketTime.tv_usec = p->pkth->ts.tv_usec;
newSource->lastPacketTime.tv_sec =p->pkth->ts.tv_sec;
newSource->lastPacketTime.tv_usec =p->pkth->ts.tv_usec;
if (scanType == sUDP)
{
newSource->numberOfUDPConnections = 1;
newSource->numberOfTCPConnections = 0;
#ifdef DEBUG
printf(MODNAME": NewSource(): %s->numberOfUDPConnections = 1, TCP = 0\n", inet_ntoa(newSource->saddr));
#endif
}
else
{
newSource->numberOfTCPConnections = 1;
newSource->numberOfUDPConnections = 0;
#ifdef DEBUG
printf(MODNAME": NewSource(): %s->numberOfTCPConnections = 1, UDP = 0\n", inet_ntoa(newSource->saddr));
#endif
}
newSource->totalNumberOfTCPConnections = 0;
newSource->totalNumberOfUDPConnections = 0;
newSource->stealthScanUsed = 0; /* This needs to be set elsewhere */
newSource->scanDetected = 0;
newSource->destinationsList = NewDestination(p, scanType);
newSource->numberOfDestinations = 1;
newSource->totalNumberOfDestinations = 1;
newSource->reportStealth = 0; /* This needs to be set elsewhere */
return(newSource);
}
SourceInfo* AddSource(SourceInfo *currentSource, Packet *p, ScanType scanType)
{
if (currentSource->nextNode)
FatalError(MODNAME": AddSource(): Not at end of source list!");
currentSource->nextNode = NewSource(p, scanType);
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)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -