📄 spp_flow.c
字号:
/** * Copyright (C) 2003 Sourcefire, Inc. * * @file spp_flow.c * @author Chris Green <cmg@sourcefire.com> * @date Thu May 29 11:27:17 2003 * * @brief flow integration with snort * * The purpose of this module is to have an abstract way of detecting * significant events to various modules so that everything higher * layers see as a session can be tracked in a single spot. * * This module completely replaces spp_conversation. */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * 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. */#include <time.h>#include "snort.h"#include "decode.h" /* Packet */#include "debug.h" /* DEBUG_WRAP */#include "plugbase.h" /* RegisterPreprocesor */#include "util.h" /* FatalError */#include "parser.h" /* file_name, file_line */#include "stream_api.h"#include "spp_flow.h"#include "flow/flow.h"#include "flow/flow_cache.h"#include "flow/flow_callback.h"#include "flow/flow_class.h"#include "flow/flow_print.h"#include "flow/portscan/flowps_snort.h"#include "profiler.h"#define DEFAULT_MEMCAP (1024 * 1024 * 10)#define DEFAULT_ROWS (1024 * 4)#define DEFAULT_STAT_INTERVAL 0typedef struct _SPPFLOW_CONFIG{ int stats_interval; int memcap; int rows; FLOWHASHID hashid;} SPPFLOW_CONFIG;static int s_flow_running = 0; /**< is flow turned on? */static FLOWCACHE s_fcache;static SPPFLOW_CONFIG s_config;static int FlowParseArgs(SPPFLOW_CONFIG *config, char *args);static INLINE int FlowPacket(Packet *p);static void FlowPreprocessor(Packet *p, void *);static void FlowInit(char *args);static void FlowCleanExit(int signal, void *data);static void FlowRestart(int signal, void *data);static void FlowParseOption(SPPFLOW_CONFIG *config, char *fname, int lineno, char *key, char *value);static void DisplayFlowConfig(void);static void FlowPrintStats(int exiting);static void FlowVerifyConfig(void);static int s_debug = 0;unsigned int giFlowbitSize = 64;#ifdef PERF_PROFILINGPreprocStats flowPerfStats;#endif/** * Add the Flow Preprocessor to the list of things that snort can * configure. * */void SetupFlow(void){ /* we should really create some set of structure's that we can go * register as config editors */ RegisterPreprocessor("flow", FlowInit); /* setup the portscan preprocessor */ SetupFlowPS(); }/** * Condense all the checks into one places * * Must be IP * Must not be a fragment * Must not be a rebuild stream * * @param p packet to inspect * * @return 1 if this packet is for flow module, 0 otherwise */static INLINE int FlowPacket(Packet *p){ if(!p->iph) return 0; if(p->frag_flag) return 0; /* if(p->packet_flags & PKT_REBUILT_STREAM) return 0; */ return 1;}/** * Initialize the configuration of the flow preprocessor * * @param args command line arguments from snort.conf */static void FlowInit(char *args){ static int init_once = 0; int ret; static SPPFLOW_CONFIG *config = &s_config; #ifdef SUP_IP6 FatalError("The flow preprocessor is now part of Stream5. This version of" " flow is not supported when IPv6 support is compiled into Snort.");#endif if(init_once) FatalError("%s(%d) Unable to reinitialize flow!\n", file_name, file_line); else init_once = 1; /* setup the defaults */ config->stats_interval = DEFAULT_STAT_INTERVAL; config->memcap = DEFAULT_MEMCAP; config->rows = DEFAULT_ROWS; config->hashid = HASH2; /* use the quickest hash by default */ FlowParseArgs(config, args); if((ret = flowcache_init(&s_fcache, config->rows, config->memcap, giFlowbitSize, config->hashid)) != FLOW_SUCCESS) { FatalError("Unable to initialize the flow cache!" "-- try more memory (current memcap is %d)\n", config->memcap); } DisplayFlowConfig(); s_flow_running = 1; AddFuncToPreprocList(FlowPreprocessor, PRIORITY_NETWORK, PP_FLOW); RegisterPreprocStats("flow", FlowPrintStats); AddFuncToPreprocCleanExitList(FlowCleanExit, NULL, PRIORITY_LAST, PP_FLOW); AddFuncToPreprocRestartList(FlowRestart, NULL, PRIORITY_LAST, PP_FLOW); AddFuncToConfigCheckList(FlowVerifyConfig);#ifdef PERF_PROFILING RegisterPreprocessorProfile("flow", &flowPerfStats, 0, &totalPerfStats);#endif}static void FlowRestart(int signal, void *data){ return;}static void FlowPrintStats(int exiting){ fflush(stdout); flowcache_stats(stdout, &s_fcache); fflush(stdout); if (exiting) { flowcache_destroy(&s_fcache); }}static void FlowCleanExit(int signal, void *data){ return;}/** * The runtime entry point for the flow module from snort * * 1) Assign each packet a flow * 2) Perform various callbacks based on the parameters for the flow * * @param p packet to process */static void FlowPreprocessor(Packet *p, void *context){ int flow_class; /**< addressing scheme to use */ int direction; /**< which way does the flow go */ static time_t last_output = 0; FLOWKEY search_key; FLOW *fp; FLOWCACHE *fcache = &s_fcache; FLOWPACKET *pkt = (FLOWPACKET *) p; PROFILE_VARS; if(!FlowPacket(p)) { return; } PREPROC_PROFILE_START(flowPerfStats); /* first find the addressing schema */ if(flow_classifier(pkt, &flow_class) != FLOW_SUCCESS) { //LogMessage("Error classifying packet\n"); PREPROC_PROFILE_END(flowPerfStats); return; } switch(flow_class) { case FLOW_IPV4: if(flowkey_make(&search_key, pkt) != FLOW_SUCCESS) { ErrorMessage("Unable to make a search key\n"); PREPROC_PROFILE_END(flowPerfStats); return; } break; default: ErrorMessage("Unknown Flow Type: %d\n", flow_class); PREPROC_PROFILE_END(flowPerfStats); return; } /** this should return a direction too for the key */ //printf("flowkey: "); flowkey_fprint(stdout, &search_key); printf("\n"); if(flowcache_find(fcache, &search_key, &fp, &direction) == FLOW_SUCCESS) { /* ** We set flows for rebuilt pkts if there is one, otherwise ** we just bail. */ if(p->packet_flags & PKT_REBUILT_STREAM) { p->flow = fp; PREPROC_PROFILE_END(flowPerfStats); return; } if(direction == FROM_RESPONDER && fp->stats.packets_recv == 0) { /* this is the first packet back from the guy */ flow_callbacks(FLOW_FIRST_BIDIRECTIONAL, fp, direction, p); } flow_callbacks(FLOW_ADDITIONAL, fp, direction, pkt); } else { /* ** If there's no flow for a rebuilt stream, then we don't ** care because something is screwed up. */ if(p->packet_flags & PKT_REBUILT_STREAM) { PREPROC_PROFILE_END(flowPerfStats); return; } if(flowcache_newflow(fcache, &search_key, &fp) != FLOW_SUCCESS) { flow_printf("***ERROR: "); flowkey_print(&search_key); flow_printf("\n"); } direction = FROM_INITIATOR; flow_callbacks(FLOW_NEW, fp, FROM_INITIATOR, pkt); } fp->stats.direction = direction; /* printout some verbose statistics */ if(s_config.stats_interval && ((last_output + s_config.stats_interval) <= p->pkth->ts.tv_sec)) { last_output = p->pkth->ts.tv_sec; if(!pv.quiet_flag) flowcache_stats(stdout, fcache); } p->flow = fp; PREPROC_PROFILE_END(flowPerfStats);}/** * See if the flow needs to be shutdown and remove it from the * cache. This function should be placed AFTER all detection type * components. * * @param p packet * * @return 0 on success */int CheckFlowShutdown(Packet *p){ FLOWCACHE *fcache = &s_fcache; FLOW *flowp = (FLOW *) p->flow; PROFILE_VARS; /* Use REENTER_START to not add to 'checks' */ PREPROC_PROFILE_REENTER_START(flowPerfStats); if(flowp != NULL) { if(flow_checkflag(flowp, FLOW_CLOSEME)) { /* allow all the submodules to trigger their final stand */ flow_callbacks(FLOW_SHUTDOWN, flowp, FROM_INITIATOR, p); if(flowcache_releaseflow(fcache, &flowp) != FLOW_SUCCESS) { flow_printf("Can't release flow %p\n", p->flow); PREPROC_PROFILE_REENTER_END(flowPerfStats); return FLOW_BADJUJU; } } } p->flow = NULL; PREPROC_PROFILE_REENTER_END(flowPerfStats); return FLOW_SUCCESS;}static int FlowParseArgs(SPPFLOW_CONFIG *config, char *args){ char *key, *value; char *myargs = NULL; const char *delim = " \t"; if(args) { if(s_debug > 5) flow_printf("I'm parsing %s!\n", args); myargs = strdup(args); if(myargs == NULL) FatalError("Out of memory parsing flow arguments\n"); } else { if(s_debug > 5) flow_printf("nothing to parse for this flow!\n"); return 0; } key = strtok(myargs, delim); while(key != NULL) { value = strtok(NULL, delim); if(!value) { FatalError("%s(%d) key %s has no value\n", file_name, file_line, key); } FlowParseOption(config, file_name, file_line, key, value); key = strtok(NULL, delim); } if(myargs) free(myargs); return 0;}static void FlowParseOption(SPPFLOW_CONFIG *config, char *fname, int lineno, char *key, char *value){ if(!strcasecmp(key, "memcap")) { config->memcap = atoi(value); } else if(!strcasecmp(key, "rows")) { config->rows = atoi(value); } else if(!strcasecmp(key, "stats_interval")) { config->stats_interval = atoi(value); } else if(!strcasecmp(key, "hash")) { switch(atoi(value)) { case 1: config->hashid = HASH1; break; case 2: config->hashid = HASH2; break; default: FatalError("%s(%d) Unknown Hash Type: key(%s) value(%s)\n", fname, lineno, key, value); } } else { FatalError("%s(%d) Unknown Arguments: key(%s) value(%s)\n", fname, lineno, key, value); } }/** * Print out some of the common information about the Flow Processor * configuration * */static void DisplayFlowConfig(void){ SPPFLOW_CONFIG *cp = &s_config; FLOWCACHE *fcp = &s_fcache; LogMessage(",-----------[Flow Config]----------------------\n"); LogMessage("| Stats Interval: %d\n", cp->stats_interval); LogMessage("| Hash Method: %d\n", cp->hashid); LogMessage("| Memcap: %d\n", cp->memcap); LogMessage("| Rows : %d\n", flowcache_row_count(fcp)); LogMessage("| Overhead Bytes: %d(%%%.2f)\n", flowcache_overhead_bytes(fcp), calc_percent(flowcache_overhead_bytes(fcp),cp->memcap)); LogMessage("`----------------------------------------------\n");}/** * Return 1 if spp_flow has been configured * * * @return 1 if spp_flow is enabled */int SppFlowIsRunning(void){ return s_flow_running;}void FlowVerifyConfig(void){ if (stream_api != NULL) { if (stream_api->version >= STREAM_API_VERSION5) { FatalError("Stream5 and flow cannot be used at the same time, as " "Stream5 provides the same functionality as flow. It " "would result in a performance degradation to use both, " "as the information gathered from flow would be duplicated " "by Stream5. Please change your 'snort.conf' to use " "either only stream5 (with tcp & udp tracking) or stream4 " "and flow. See the Snort manual for more details.\n"); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -