Смекни!
smekni.com

Разработка и анализ эффективности средств отражения распределенных атак (стр. 12 из 13)

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&bsol;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&bsol;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 &bsol;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&bsol;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&bsol;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&bsol;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&bsol;n");

findNodeData->SeqAckNumber = p->tcph->th_ack-1;

break;

case PACKET_TYPE_SYN_ACK:

printf("processing RST from client&bsol;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&bsol;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&bsol;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&bsol;n");

}

if(_checkPeriod < 0)

{

FatalError("TcpConnectionEstimateTimeChecker:: _checkPeriod must be > 0&bsol;n");

}

if(_overdueUpperBound < 0)

{

FatalError("TcpConnectionEstimateTimeChecker:: _overdueUpperBound must be > 0&bsol;n");

}

if(_overdueUpperBoundDiviation < 0)

{

FatalError("TcpConnectionEstimateTimeChecker:: _overdueUpperBoundDiviation must be > 0&bsol;n");

}

if((_overdueUpperBound - _overdueUpperBoundDiviation) < 0)

{

FatalError("TcpConnectionEstimateTimeChecker:: (_overdueUpperBound - _overdueUpperBoundDiviation) must be > 0&bsol;n");

}

if((_overdueUpperBound + _overdueUpperBoundDiviation) > _serverTimeout)

{

FatalError("TcpConnectionEstimateTimeChecker:: (_overdueUpperBound + _overdueUpperBoundDiviation) must be < _serverTimeout&bsol;n");

}

if(_serverTimeout < 0)

{

FatalError("TcpConnectionEstimateTimeChecker:: _serverTimeout must be > 0&bsol;n");

}

if(_overdueTime > _serverTimeout)

{

FatalError("TcpConnectionEstimateTimeChecker:: overdue time can't be greater than server timeout&bsol;n");

}

if(_serverTimeout <= _checkPeriod)

{

FatalError("TcpConnectionEstimateTimeChecker:: _serverTimeout must be greater than _checkPeriod&bsol;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;