TcpSynFloodPreventionProcessPacket(tcpSynFloodData->preventionModule, p, changeStat);
}
} // process SYN packet with prevetntion module
else if(packetType == PACKET_TYPE_SYN)
{
printf("processing SYN\n");
// check if atack is present
if(tcpSynFloodData->workingMode == TCP_SYN_FLOOD_PREVENTION)
{
printf("processing SYN while attack is present\n");
// get packet status
int packetStatus = TcpSynFloodPreventionProcessPacket(tcpSynFloodData->preventionModule, p, CHANGE_STAT_NO);
if(packetStatus == PREVENTION_PACKET_IS_BAD)
{
printf("Processing bas SYN\n");
if(InlineMode())
{
InlineDrop();
}
// else {} // Another type of ActiveReply should be implemented
// For example sending RST packets to server and client
return 0;
}
}
}
// process packet with time checker
int checkerResult = TcpConnEstTimeChecker_ProcessPacket(tcpSynFloodData->timeChecker, p, packetType);
if(checkerResult == SYN_ATACK_IS_PRESENT)
{
// Check if atack has been started now
if(tcpSynFloodData->workingMode == TCP_SYN_FLOOD_DETECTION)
{
// Generate log message 'Atack Started'
GenerateSnortEvent(NULL, GENERATOR_TCP_SYN_FLOOD, 0,0,0,3,SYNFLOOD_STARTED);
//change mode
tcpSynFloodData->workingMode = TCP_SYN_FLOOD_PREVENTION;
}
}
else
{
// Check if atack has been finished now
if(tcpSynFloodData->workingMode == TCP_SYN_FLOOD_PREVENTION)
{
// Generate event log "ATACK FINISHED"
GenerateSnortEvent(NULL, GENERATOR_TCP_SYN_FLOOD, 0,0,0,3,SYNFLOOD_FINISHED);
//change mode
tcpSynFloodData->workingMode = TCP_SYN_FLOOD_DETECTION;
}
}
}// PACKET IS SUPPORTED
return fp_list->next->OptTestFunc(p, otn, fp_list->next);
}
int ParseIntElement(char* token, char *name)
{
char * tail;
int value = (int) strtol(token, &tail, 10);
if(*tail)
{
FatalError("in TcpSynFlood rule: %s is invalid %s.\n", token, name);
}
return value;
}
inline int GetPacketType(TcpConnEstTimeChecker* checker, Packet* p, struct in_addr ipServer)
{
// check IP address
struct in_addr ipSrc = p->iph->ip_src;
struct in_addr ipDst = p->iph->ip_dst;
u_int8_t flags = p->tcph->th_flags;
if((ipDst.s_addr == ipServer.s_addr) && ((flags ^ R_SYN) == 0))
{
return PACKET_TYPE_SYN;
}
if((ipSrc.s_addr == ipServer.s_addr) && ((flags ^ R_SYN ^ R_ACK) == 0))
{
return PACKET_TYPE_SYN_ACK;
}
else if((ipDst.s_addr == ipServer.s_addr) && ((flags ^ R_ACK) == 0))
{
return PACKET_TYPE_ACK;
}
else if((ipSrc.s_addr == ipServer.s_addr) && ((flags ^ R_RST) == 0))
{
return PACKET_TYPE_RST_FROM_SERVER;
}
else if((ipDst.s_addr == ipServer.s_addr) && ((flags ^ R_RST) == 0))
{
return PACKET_TYPE_RST_FROM_CLIENT;
}
return PACKET_TYPE_UNSUPPORTED;
}
// файл tcp_conn_est_time_checker.h
#ifndef __TCP_CONN_EST_TIME_CHECKER_H__
#define __TCP_CONN_EST_TIME_CHECKER_H__
#include <time.h>
#include <sys/time.h>
#include "config.h"
#include "decode.h"
#include "ubi_SplayTree.h"
typedef struct _TcpConnEstTimeChecker
{
/*** Rule Options ***/
// time in seconds after which the half-open connection is overdue
long overdueTime;
// period in seconds to check the number of overdue half-open connections
long checkPeriod;
// the max allowed number of half-open connections
int overdueUpperBound;
// the diviation of overdueUpperBound
int overdueUpperBoundDiviation;
/*** Internal Data ***/
// the number of root nodes in the array
int rootNodesCount;
// the array of root nodes
ubi_btRoot* rootNodes;
// the index of the first node, which contains overdued connections
int firstOverduedNodeIndex;
// time when the last shift was made
struct timeval lastShiftTime;
// Indicates if Syn Flood atack presents
int atackState;
}
TcpConnEstTimeChecker;
/*** Inerface ***/
void InitTcpConnEstTimeChecker(TcpConnEstTimeChecker* checker, long _overdueTime,
long _checkPeriod, int _overdueUpperBound,
int _overdueUpperBoundDiviation, long _serverTimeout);
void DeInitTcpConnEstTimeChecker(TcpConnEstTimeChecker* checker);
int TcpConnEstTimeChecker_ProcessPacket(TcpConnEstTimeChecker* checker, Packet* p, int packetType);
int ShiftRootNodes(TcpConnEstTimeChecker* checker, int GenerationCount);
#endif /* __SP_TCP_SYN_FLOOD_H__ */
// файл tcp_conn_est_time_checker.c
#ifndef __TCP_CONN_EST_TIME_CHECKER_H__
#include "tcp_conn_est_time_checker.h"
#endif
#include "sp_tcp_syn_flood.h"
#include <memory.h>
#include <math.h>
#include <stdlib.h>
#include "rules.h"
#include "util.h"
/********* States of Timechecker Tree Node Data ********/
#define NODE_STATE_SYN_RECEIVED 1
#define NODE_STATE_SYN_ACK_RECEIVED 2
typedef struct _TimeCheckerTreeNodeData
{
ubi_trNode Node;
// state of the node
int NodeState;
// Sequence number for client SYN packet
u_int32_t ClientNumber;
// Sequence number for server SYN+ACK packet
u_int32_t ServerNumber;
}
TChTreeNodeData;
/*** TChTreeNodeData manipulation functions ***/
static int TChTreeNodeDataCompareFunc(ubi_trItemPtr ItemPtr, ubi_trNodePtr NodePtr);
static void TChTreeNodeDataDeleteNode(ubi_btNodePtr NodePtr);
/*** TcpConnEstTimeChecker manipulation functions ***/
void InitTcpConnEstTimeChecker(TcpConnEstTimeChecker* checker, long _overdueTime,
long _checkPeriod, int _overdueUpperBound,
int _overdueUpperBoundDiviation, long _serverTimeout)
{
CheckInitParams(_overdueTime, _checkPeriod, _overdueUpperBound, _overdueUpperBoundDiviation,_serverTimeout);
checker->overdueTime = _overdueTime;
checker->checkPeriod = _checkPeriod;
checker->overdueUpperBound = _overdueUpperBound;
checker->overdueUpperBoundDiviation = _overdueUpperBoundDiviation;
// Get rootNodes count
double serverTimeout = _serverTimeout;
int rootNodesCount = ceil(serverTimeout / _checkPeriod);
checker->rootNodesCount = rootNodesCount;
printf("NODES COUNT %d\n", rootNodesCount);
// init the array of root nodes
checker->rootNodes = (ubi_btRoot*)SnortAlloc(sizeof(ubi_btRoot) * rootNodesCount);
// the index of the first node with overdued connections
checker->firstOverduedNodeIndex = checker->overdueTime / checker->checkPeriod;
int i;
for(i = 0; i < rootNodesCount; i++)
{
ubi_trInitTree(checker->rootNodes + i,/* ptr to the tree head */
TChTreeNodeDataCompareFunc, /* comparison function */
ubi_trDUPKEY);
//0); /* do not allow nither OVERWRITE nor DUPLICATES */
}
// get current time
struct timezone tz;
gettimeofday(&checker->lastShiftTime, &tz);
//time(&checker->lastShiftTime);
checker->atackState = SYN_ATACK_IS_NOT_PRESENT;
}
void DeInitTcpConnEstTimeChecker(TcpConnEstTimeChecker* checker)
{
int rootNodesCount = checker->rootNodesCount;
// delete trees
int i;
for(i = 0; i < rootNodesCount; i++)
{
ubi_trKillTree(checker->rootNodes + i, TChTreeNodeDataDeleteNode);
}
// delete array
free(checker->rootNodes);
checker->rootNodes = NULL;
}
long GetTimeDifference(struct timeval* time1, struct timeval* time2)
{
long secDiff =time1->tv_sec - time2->tv_sec;
long micSecDiff = time1->tv_usec - time2->tv_usec;
return labs(secDiff)*1000000 + labs(micSecDiff);
}
int TcpConnEstTimeChecker_ProcessPacket(TcpConnEstTimeChecker* checker, Packet* p, int packetType)
{
int i;
/*
// get current time
time_t curTime;
time(&curTime);
//check the time
int diff = difftime(curTime, checker->lastShiftTime);
*/
struct timeval currTime;
struct timezone zone;
gettimeofday(&currTime, &zone);
long diff = GetTimeDifference(&currTime, &checker->lastShiftTime);
if(diff >= checker->checkPeriod)
{
// shift trees
printf("shifting trees\n");
int generationsCount = ((float)diff) / checker->checkPeriod;
ShiftRootNodes(checker, generationsCount);
}
// is used as item to search
TChTreeNodeData* findNodeData = NULL;
// flag which indicates if the node is inserted successfully
ubi_trBool insertResult;
// if Syn add node to the tree
if(packetType == PACKET_TYPE_SYN)
{
printf("processing SYN packet in time checker \n");
TChTreeNodeData* newNodeData = (TChTreeNodeData*)SnortAlloc(sizeof(TChTreeNodeData));
ubi_trNodePtr nodePtr = &newNodeData->Node;
ubi_btInitNode(nodePtr);
// save sequence number and set NODE_STATE_SYN_RECEIVED
newNodeData->ClientNumber = p->tcph->th_seq;
newNodeData->NodeState = NODE_STATE_SYN_RECEIVED;
// trying to insert the node to the 0-th tree
insertResult =
ubi_trInsert(checker->rootNodes, nodePtr, (ubi_trItemPtr)newNodeData, NULL);
if(insertResult != ubi_trTRUE)
{
printf("failed to add SYN to the tree\n");
// there is already the node with the same key in the tree
free(newNodeData);
}
}
// if Syn + Ack
else if(packetType == PACKET_TYPE_SYN_ACK)
{
printf("processing SYN + ACK in time checker\n" );
// find the node that is corresponded to received SYN
findNodeData = (TChTreeNodeData*)SnortAlloc(sizeof(TChTreeNodeData));
findNodeData->NodeState = NODE_STATE_SYN_RECEIVED;
findNodeData->ClientNumber = p->tcph->th_ack - 1;
// run over all trees and try to find the node
for(i = 0; i < checker->rootNodesCount; i++)
{
TChTreeNodeData* foundNodeData = (TChTreeNodeData*)ubi_trFind(checker->rootNodes + i, findNodeData);
if(foundNodeData != NULL)
{
// remove node from tree
ubi_trRemove(checker->rootNodes + i, foundNodeData);
// set Acknowledgement number and update node state to NODE_STATE_SYN_ACK_RECEIVED
foundNodeData->NodeState = NODE_STATE_SYN_ACK_RECEIVED;
foundNodeData->ServerNumber = p->tcph->th_seq;
// insert node again in the tree
insertResult =
ubi_trInsert(checker->rootNodes + i, foundNodeData, (ubi_trItemPtr)foundNodeData, NULL);
if(insertResult != ubi_trTRUE)
{
// there is already the node with the same key in the tree
free(foundNodeData);
}
break;
}
}
free(findNodeData);
}
// if Ack or Resets
else if ((packetType == PACKET_TYPE_ACK) ||
(packetType == PACKET_TYPE_RST_FROM_SERVER) ||
(packetType == PACKET_TYPE_SYN_ACK))
{
TChTreeNodeData* findNodeData = (TChTreeNodeData*)SnortAlloc(sizeof(TChTreeNodeData));
switch(packetType)
{
case PACKET_TYPE_ACK:
printf("processing ACK packet\n");
findNodeData->NodeState = NODE_STATE_SYN_ACK_RECEIVED;
findNodeData->ClientNumber = p->tcph->th_seq - 1;
findNodeData->ServerNumber = p->tcph->th_ack - 1;
break;
/*
case PACKET_TYPE_RST_FROM_SERVER:
printf("processing RST from server\n");
findNodeData->SeqAckNumber = p->tcph->th_ack-1;
break;
case PACKET_TYPE_SYN_ACK:
printf("processing RST from client\n");
findNodeData->SeqAckNumber = p->tcph->th_seq-1;
break;
*/
}
// run over all trees and try to Find and Delete node with the given key
for(i = 0; i < checker->rootNodesCount; i++)
{
ubi_trNodePtr nodePtr = ubi_trFind(checker->rootNodes + i, findNodeData);
if(nodePtr != NULL)
{
// delete
ubi_trRemove(checker->rootNodes + i, nodePtr);
free((TChTreeNodeData*)nodePtr);
break;
}
}
free(findNodeData);
}
// check overdue connections count
printf("chekcing\n");
return CheckOverdueConnectionsCount(checker);
}
int ShiftRootNodes(TcpConnEstTimeChecker* checker, int generationCount)
{
int i;
if(generationCount > checker->rootNodesCount)
{
generationCount = checker->rootNodesCount;
}
// free old trees
for( i = (checker->rootNodesCount - generationCount); i < checker->rootNodesCount; i++ )
{
ubi_trKillTree(checker->rootNodes + i, TChTreeNodeDataDeleteNode);
}
// shift
memmove(checker->rootNodes + generationCount,
checker->rootNodes, (checker->rootNodesCount - generationCount) * sizeof(ubi_btRoot));
// init new trees
for(i = 0; i < generationCount; i++)
{
ubi_trInitTree(&checker->rootNodes[i],/* ptr to the tree head */
TChTreeNodeDataCompareFunc, /* comparison function */
ubi_trDUPKEY); /* allow duplicates */
}
struct timezone zone;
gettimeofday(&checker->lastShiftTime, &zone);
return 0;
}
int CheckOverdueConnectionsCount(TcpConnEstTimeChecker* checker)
{
int resCount = 0;
int i;
for(i = checker->firstOverduedNodeIndex; i < checker->rootNodesCount; i++ )
{
resCount += ubi_trCount(checker->rootNodes + i);
}
int currentlyAllowedBound;
if(checker->atackState == SYN_ATACK_IS_PRESENT)
{
// subtract diviation from the bound
currentlyAllowedBound = checker->overdueUpperBound - checker->overdueUpperBoundDiviation;
}
else
{
// add diviation to the bound
currentlyAllowedBound = checker->overdueUpperBound + checker->overdueUpperBoundDiviation;
}
// save current atack state
checker->atackState = (resCount > currentlyAllowedBound )? SYN_ATACK_IS_PRESENT : SYN_ATACK_IS_NOT_PRESENT;
printf("check overdued: %d - %d\n", currentlyAllowedBound, resCount);
return checker->atackState;
}
void CheckInitParams(int _overdueTime,int _checkPeriod,
int _overdueUpperBound, int _overdueUpperBoundDiviation,
int _serverTimeout)
{
if(_overdueTime < 0)
{
FatalError("TcpConnectionEstimateTimeChecker:: _overdueTime must be > 0\n");
}
if(_checkPeriod < 0)
{
FatalError("TcpConnectionEstimateTimeChecker:: _checkPeriod must be > 0\n");
}
if(_overdueUpperBound < 0)
{
FatalError("TcpConnectionEstimateTimeChecker:: _overdueUpperBound must be > 0\n");
}
if(_overdueUpperBoundDiviation < 0)
{
FatalError("TcpConnectionEstimateTimeChecker:: _overdueUpperBoundDiviation must be > 0\n");
}
if((_overdueUpperBound - _overdueUpperBoundDiviation) < 0)
{
FatalError("TcpConnectionEstimateTimeChecker:: (_overdueUpperBound - _overdueUpperBoundDiviation) must be > 0\n");
}
if((_overdueUpperBound + _overdueUpperBoundDiviation) > _serverTimeout)
{
FatalError("TcpConnectionEstimateTimeChecker:: (_overdueUpperBound + _overdueUpperBoundDiviation) must be < _serverTimeout\n");
}
if(_serverTimeout < 0)
{
FatalError("TcpConnectionEstimateTimeChecker:: _serverTimeout must be > 0\n");
}
if(_overdueTime > _serverTimeout)
{
FatalError("TcpConnectionEstimateTimeChecker:: overdue time can't be greater than server timeout\n");
}
if(_serverTimeout <= _checkPeriod)
{
FatalError("TcpConnectionEstimateTimeChecker:: _serverTimeout must be greater than _checkPeriod\n");
}
}
/* Returns -1 if A < B
Returns 1 if A > B
Returns 0 if A = B
At first Client number is checked.
Than if neccessary Server nubmer is checked
*/
static int TChTreeNodeDataCompareFunc(ubi_trItemPtr ItemPtr, ubi_trNodePtr NodePtr)
{
TChTreeNodeData *A = (TChTreeNodeData *) ItemPtr;
TChTreeNodeData *B = (TChTreeNodeData *) NodePtr;
if(A->ClientNumber < B->ClientNumber)return -1;
if(A->ClientNumber == B->ClientNumber)return 0;
else // check curr node state
if(B->NodeState == NODE_STATE_SYN_ACK_RECEIVED)
{
if(A->ServerNumber < B->ServerNumber) return -1;
if(A->ServerNumber == B->ServerNumber) return 0;