/** * Print out the entirety of the server cache. * * @param ssp server stats pointer */ void server_stats_dump(SERVER_STATS *ssp) { SFXHASH_NODE *nodep; if(ssp && ssp->ipv4_table) { for( nodep = sfxhash_ghead(ssp->ipv4_table); nodep != NULL; nodep = sfxhash_gnext(nodep) ) { SERVER_KEY *kp = (SERVER_KEY *) nodep->key; u_int32_t count = *(u_int32_t *) nodep->data; flow_printf("hits: %u proto: %3u port: %5u ip: %s\n", count, kp->protocol, kp->port, inet_ntoa(*(struct in_addr *)&kp->address)); } } else { flow_printf("nothing to dump!\n"); } }
/** * print out a key to a file stream * * @param key what to print * * @return 0 on sucess */ int flowkey_print(FLOWKEY *key) { flow_printf(" Protocol : %d", key->protocol); flow_printf(" InitAddress: %s", inet_ntoa(*(struct in_addr *) &key->init_address)); flow_printf(" InitPort : %d", key->init_port); flow_printf(" RespAddress: %s", inet_ntoa(*(struct in_addr *) &key->resp_address)); flow_printf(" RespPort : %d", key->resp_port); return 0; }
int flow_init(FLOW *flow, char protocol, u_int32_t init_address, u_int16_t init_port, u_int32_t resp_address, u_int16_t resp_port) { if(flow == NULL) { return FLOW_ENULL; } flow->key.protocol = protocol; flow->key.init_address = init_address; flow->key.init_port = init_port; flow->key.resp_address = resp_address; flow->key.resp_port = resp_port; if(flowstat_clear(&flow->stats)) { flow_printf("unable to clear flow stats\n"); return FLOW_EINVALID; } /** have not done anything with the flow->data section yet */ return FLOW_SUCCESS; }
/** * 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 TMPSTART to not add to 'checks' */ PREPROC_PROFILE_TMPSTART(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_TMPEND(flowPerfStats); return FLOW_BADJUJU; } } } p->flow = NULL; PREPROC_PROFILE_TMPEND(flowPerfStats); return FLOW_SUCCESS; }
/** * Printout a score entry * * @param ps_score score entry to printf * * @return FLOW_SUCCESS on success */ int flowps_score_print(PS_SCORE *ps_score) { flow_printf(" score: %u start: %u end: %u", ps_score->score, (unsigned int) ps_score->start, (unsigned int) ps_score->ends); 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; }
void flowps_stats(PS_TRACKER *pstp) { int dumpall = pstp->config.dumpall; flow_printf("+---[ Flow-portscan Stats ]----------------+\n"); scoreboard_stats(&pstp->table_active, dumpall); scoreboard_stats(&pstp->table_scanner, dumpall); ut_stats(&pstp->unique_tracker, dumpall); server_stats(&pstp->server_stats, dumpall); }
void server_stats(SERVER_STATS *ssp, int dumpall) { unsigned total, fail, success, nodes, anr, overhead, memcap; memcap = overhead = nodes = anr = total = fail = success = 0; if(ssp && ssp->ipv4_table) { total = sfxhash_find_total(ssp->ipv4_table); fail = sfxhash_find_fail(ssp->ipv4_table); success = sfxhash_find_success(ssp->ipv4_table); nodes = sfxhash_count(ssp->ipv4_table); anr = sfxhash_anr_count(ssp->ipv4_table); memcap = server_stats_memcap(ssp); overhead = server_stats_overhead_bytes(ssp); } flow_printf(",-----[SERVER STATS]------------\n"); flow_printf(" Memcap: %u Overhead Bytes: %u\n", memcap, overhead); flow_printf(" Finds: %u (Sucessful: %u(%%%lf) Unsucessful: %u(%%%lf))\n", total, success, calc_percent(success,total), fail, calc_percent(fail,total)); flow_printf(" Nodes: %u\n", nodes); flow_printf(" Recovered Nodes: %u\n", anr); flow_printf("`-------------------------------\n"); if(dumpall) server_stats_dump(ssp); }
/** * Create a new scoreboard for tracking nodes. * * @param sbp scoreboard to initialize * @param at_thr active talker thresholds * @param sc_thr scanner thresholds (may not be needed) * @param kind tracker location for this table * @param description table description * @param rows number of rows to populate the initial HASHTABLE() with * @param memcap bytes we can spend on this scoreboard * * @return FLOW_SUCCESS on success, else failure */ int scoreboard_init(SCOREBOARD *sbp, char *description, TRACKER_POSITION kind, unsigned int rows, int memcap) { if(!sbp || !description) { return FLOW_ENULL; } if(rows < 1) return FLOW_EINVALID; if(memcap < (sizeof(SCORE_ENTRY) + sizeof(SFXHASH_NODE))) return FLOW_EINVALID; /* initialize s_init_entry*/ sb_init_entry(); memset(sbp, 0, sizeof(SCOREBOARD)); snprintf(sbp->description, SDESC_SIZE - 1, description); sbp->description[SDESC_SIZE - 1] = '\0'; /* what size should we do? */ sbp->ipv4_table = sfxhash_new(rows, /* # of rows in HT*/ sizeof(u_int32_t), /* size of the key */ sizeof(SCORE_ENTRY), /* data size */ memcap, /* how much memory is alloted */ 1, /* auto recover nodes */ scoreboard_anrfree, /* autorecovery function */ scoreboard_usrfree, /* free function for the data */ 1); /* recycle old nodes */ if(sbp->ipv4_table == NULL) { flow_printf("Unable to create scoreboard table!\n"); return FLOW_ENOMEM; } sbp->kind = kind; return FLOW_SUCCESS; }
/** * Print out the entirety of the scoreboard * * @param ssp unique tracker */ void scoreboard_dump(SCOREBOARD *ssp) { SFXHASH_NODE *nodep; if(ssp && ssp->ipv4_table) { for( nodep = sfxhash_ghead(ssp->ipv4_table); nodep != NULL; nodep = sfxhash_gnext(nodep) ) { u_int32_t *address = (u_int32_t *) nodep->key; SCORE_ENTRY *entry = (SCORE_ENTRY *) nodep->data; flowps_entry_print(entry, address); } } else { flow_printf("nothing to dump!\n"); } }
int scoreboard_add(SCOREBOARD *sbp, u_int32_t *address, SCORE_ENTRY **sepp) { int ret; int hash_add_ret; if(!sbp) { return FLOW_ENULL; } hash_add_ret = sfxhash_add(sbp->ipv4_table, address, &s_init_entry); switch(hash_add_ret) { case SFXHASH_OK: if(scoreboard_mru(sbp,sepp) != FLOW_SUCCESS) { /* something's wrong because we just added this thing!\n */ flow_printf("sba: Unable to find a key I just added!\n"); ret = FLOW_BADJUJU; } else { ret = FLOW_SUCCESS; } break; case SFXHASH_NOMEM: ret = FLOW_ENOMEM; break; case SFXHASH_INTABLE: default: ret = FLOW_EINVALID; break; } return ret; }
void scoreboard_stats(SCOREBOARD *sbp, int dumpall) { unsigned total = sfxhash_find_total(sbp->ipv4_table); unsigned fail = sfxhash_find_fail(sbp->ipv4_table); unsigned success = sfxhash_find_success(sbp->ipv4_table); flow_printf("SCOREBOARD_STATS: %s\n", (char *) sbp->description); flow_printf(" Memcap: %u Overhead Bytes: %u\n", sbp->ipv4_table->mc.memcap, sfxhash_overhead_bytes(sbp->ipv4_table)); flow_printf(" Finds: %u (Sucessful: %u(%%%f) Unsucessful: %u(%%%f))\n", total, success, calc_percent(success,total), fail, calc_percent(fail,total)); flow_printf(" Nodes: %u\n", sfxhash_count(sbp->ipv4_table)); flow_printf(" Recovered Nodes: %u\n", sfxhash_anr_count(sbp->ipv4_table)); flow_printf(" Score Entry Size:: %u\n", sizeof(SCORE_ENTRY)); if(dumpall) scoreboard_dump(sbp); }
int flowcache_newflow(FLOWCACHE *flowcachep, FLOWKEY *keyp, FLOW **flowpp) { static int run_once = 1; #ifdef FLOW_PERF_FIX FLOW *newflow = NULL; SFXHASH_NODE *new_node = NULL; #else static FLOW zeroflow; #endif static FLOWKEY searchkey; int ret; if(!flowcachep || !keyp || !flowpp) { return FLOW_ENULL; } FCS_new(flowcachep, keyp); if(run_once) { /* all the time that we're running this, we're actually going to be filling in the key, and having zero'd out counters */ #ifndef FLOW_PERF_FIX memset(&zeroflow, 0, sizeof(FLOW)); #endif memset(&searchkey, 0, sizeof(FLOWKEY)); run_once = 0; } flowkey_normalize(&searchkey, keyp); #ifdef FLOW_PERF_FIX /* This just eliminates a memcpy. */ /* Since we're using auto node recovery, we should get a node back * here that has a data pointer. */ /* flow_init resets the internal key & stats to zero. */ new_node = sfxhash_get_node(flowcachep->ipv4_table, &searchkey); if (new_node && new_node->data) { newflow = new_node->data; if(flow_init(newflow, keyp->protocol, keyp->init_address, keyp->init_port, keyp->resp_address, keyp->resp_port)) { return FLOW_ENULL; } ret = SFXHASH_OK; } else { ret = SFXHASH_NOMEM; } #else if(flow_init(&zeroflow, keyp->protocol, keyp->init_address, keyp->init_port, keyp->resp_address, keyp->resp_port)) { return FLOW_ENULL; } ret = sfxhash_add(flowcachep->ipv4_table, &searchkey, &zeroflow); #endif switch(ret) { case SFXHASH_OK: if(flowcache_mru(flowcachep,flowpp) != FLOW_SUCCESS) { /* something's wrong because we just added this thing!\n */ flow_printf("Unable to find a key I just added!\n"); return FLOW_BADJUJU; } if(init_flowdata(flowcachep, *flowpp)) { return FLOW_BADJUJU; } return FLOW_SUCCESS; case SFXHASH_NOMEM: return FLOW_ENOMEM; case SFXHASH_INTABLE: default: return FLOW_EINVALID; } }
/** * 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"); 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); }
static void FlowPSParseOption(PS_CONFIG *config, char *fname, int lineno, char *key, char *value) { int ivalue; if(!key || !value) { FatalError("%s:(%d) Invalid command line arguments!\n"); } if(s_debug > 1) flow_printf("key: %s value: %s\n", key, value); if(!strcasecmp(key, "scoreboard-memcap-talker")) { ivalue = atoi(value); config->sb_memcap_talker = ivalue; } else if(!strcasecmp(key, "scoreboard-memcap-scanner")) { ivalue = atoi(value); config->sb_memcap_scanner = ivalue; } else if(!strcasecmp(key,"unique-memcap")) { ivalue = atoi(value); config->ut_memcap = ivalue; } else if(!strcasecmp(key,"server-memcap")) { ivalue = atoi(value); config->server_memcap = ivalue; } else if(!strcasecmp(key, "scoreboard-rows-talker")) { ivalue = atoi(value); config->sb_rows_talker = ivalue; } else if(!strcasecmp(key, "scoreboard-rows-scanner")) { ivalue = atoi(value); config->sb_rows_scanner = ivalue; } else if(!strcasecmp(key,"unique-rows")) { ivalue = atoi(value); config->ut_rows = ivalue; } else if(!strcasecmp(key,"server-rows")) { ivalue = atoi(value); config->server_rows = ivalue; } else if(!strcasecmp(key, "server-watchnet")) { IPSET *ipset = ipset_new(IPV4_FAMILY); if(!ipset || ip4_setparse(ipset, value) !=0) { FatalError("%s(%d) Unable to create an IPSet from %s\n", file_name,file_line,value); } config->server_watchnet_ipv4 = ipset; } else if(!strcasecmp(key, "src-ignore-net")) { IPSET *ipset = ipset_new(IPV4_FAMILY); if(!ipset || ip4_setparse(ipset, value) !=0) { FatalError("%s(%d) Unable to create an IPSet from %s\n", file_name,file_line,value); } config->src_ignore_ipv4 = ipset; } else if(!strcasecmp(key, "dst-ignore-net")) { IPSET *ipset = ipset_new(IPV4_FAMILY); if(!ipset || ip4_setparse(ipset, value) !=0) { FatalError("%s(%d) Unable to create an IPSet from %s\n", file_name,file_line,value); } config->dst_ignore_ipv4 = ipset; } else if(!strcasecmp(key, "tcp-penalties")) { if(toggle_option(key, value, &config->tcp_penalties)) { FatalError("%s(%d) Error processing %s directive (value = %s)\n", file_name,file_line,key,value); } } else if(!strcasecmp(key, "server-learning-time")) { ivalue = atoi(value); config->server_learning_time = ivalue; } else if(!strcasecmp(key, "server-ignore-limit")) { ivalue = atoi(value); config->server_ignore_limit = ivalue; } else if(!strcasecmp(key, "server-scanner-limit")) { ivalue = atoi(value); config->server_scanner_limit = ivalue; } else if(!strcasecmp(key, "talker-fixed-threshold")) { ivalue = atoi(value); config->limit_talker.fixed = ivalue; } else if(!strcasecmp(key, "talker-sliding-threshold")) { ivalue = atoi(value); config->limit_talker.sliding = ivalue; } else if(!strcasecmp(key, "talker-fixed-window")) { ivalue = atoi(value); config->limit_talker.fixed_size = ivalue; } else if(!strcasecmp(key, "talker-sliding-window")) { ivalue = atoi(value); config->limit_talker.sliding_size = ivalue; } else if(!strcasecmp(key, "talker-sliding-scale-factor")) { config->limit_talker.window_scale = (float)strtod(value, NULL); } else if(!strcasecmp(key, "scanner-fixed-threshold")) { ivalue = atoi(value); config->limit_scanner.fixed = ivalue; } else if(!strcasecmp(key, "scanner-sliding-threshold")) { ivalue = atoi(value); config->limit_scanner.sliding = ivalue; } else if(!strcasecmp(key, "scanner-fixed-window")) { ivalue = atoi(value); config->limit_scanner.fixed_size = ivalue; } else if(!strcasecmp(key, "scanner-sliding-window")) { ivalue = atoi(value); config->limit_scanner.sliding_size = ivalue; } else if(!strcasecmp(key, "scanner-sliding-scale-factor")) { config->limit_scanner.window_scale = (float)strtod(value, NULL); } else if(!strcasecmp(key, "base-score")) { config->base_score = atoi(value); } else if(!strcasecmp(key, "dumpall")) { config->dumpall = atoi(value); } else if(!strcasecmp(key, "alert-mode")) { if(!strcasecmp(value, "once")) { config->alert_once = 1; } else if(!strcasecmp(value, "all")) { config->alert_once = 0; } else { FatalError("%s(%d) Bad option to %s => %s\n", file_name, file_line, key, value); } } else if(!strcasecmp(key, "output-mode")) { if(!strcasecmp(value, "msg")) { config->output_mode = VARIABLEMSG; } else if(!strcasecmp(value, "pktkludge")) { config->output_mode = PKTKLUDGE; } else { FatalError("%s(%d) Bad option to %s => %s\n", file_name, file_line, key, value); } } else { FatalError("%s(%d) Unknown Arguments: key(%s) value(%s)\n", fname, lineno, key, value); } }
void flowcache_stats(FILE *stream, FLOWCACHE *flowcachep) { int could_hold; int i; time_t low_time = 0, high_time = 0, diff_time = 0; int diff_hours = 0, diff_min = 0, diff_sec = 0; int diff_blocks = 0; FLOW *flow_mrup, *flow_lrup; #ifdef INDEPTH_DEBUG printf("table max depth: %u\n", sfxhash_maxdepth(flowcachep->ipv4_table)); #endif /* INDEPTH_DEBUG */ if((flowcache_mru(flowcachep, &flow_mrup) == FLOW_SUCCESS) && (flowcache_lru(flowcachep, &flow_lrup) == FLOW_SUCCESS)) { low_time = flow_lrup->stats.last_packet; high_time = flow_mrup->stats.last_packet; diff_time = high_time - low_time; diff_hours = diff_time / 3600; diff_min = (diff_time - (3600 * diff_hours)) / 60; diff_sec = diff_time % 60; } diff_blocks = flowcachep->ipv4_table->mc.nblocks - flowcache_overhead_blocks(flowcachep); //could_hold = flowcachep->ipv4_table->mc.memcap / // (sizeof(FLOW) + sizeof(FLOWKEY) + sizeof(SFXHASH_NODE)); /* this is a bad calculation -- should clean this up */ if(diff_blocks > 0) { could_hold = (flowcachep->ipv4_table->mc.memused - flowcache_overhead_bytes(flowcachep)) / diff_blocks; could_hold = flowcachep->ipv4_table->mc.memcap / could_hold; } else { could_hold = diff_blocks; } flow_printf(",----[ FLOWCACHE STATS ]----------\n"); flow_printf("Memcap: %u Overhead Bytes %u used(%%%f)/blocks (%u/%u)\nOverhead blocks: %u Could Hold: (%u)\n", flowcachep->ipv4_table->mc.memcap, flowcache_overhead_bytes(flowcachep), calc_percent(flowcachep->ipv4_table->mc.memused, flowcachep->ipv4_table->mc.memcap), flowcachep->ipv4_table->mc.memused, flowcachep->ipv4_table->mc.nblocks, flowcache_overhead_blocks(flowcachep), could_hold); flow_printf("IPV4 count: %u frees: %u\nlow_time: %u, high_time: %u," " diff: %dh:%02d:%02ds\n", sfxhash_count(flowcachep->ipv4_table), sfxhash_anr_count(flowcachep->ipv4_table), (unsigned) low_time, (unsigned) high_time, diff_hours,diff_min,diff_sec); flow_printf(" finds: " STDu64 " reversed: " STDu64 "(%%%f) \n find_success: " STDu64 " " "find_fail: " STDu64 "\npercent_success: (%%%f) new_flows: " STDu64 "\n", flowcachep->total.find_ops, flowcachep->total.reversed_ops, calc_percent64(flowcachep->total.reversed_ops, flowcachep->total.find_ops), flowcachep->total.find_success, flowcachep->total.find_fail, calc_percent64(flowcachep->total.find_success, flowcachep->total.find_ops), flowcachep->total.new_flows); for(i=0;i<256;i++) { if(flowcachep->per_proto[i].find_ops > 0) { flow_printf(" Protocol: %d (%%%f)\n" " finds: " STDu64 "\n" " reversed: " STDu64 "(%%%f)\n" " find_success: " STDu64 "\n" " find_fail: " STDu64 "\n" " percent_success: (%%%f)\n" " new_flows: " STDu64 "\n", i, calc_percent64(flowcachep->per_proto[i].find_ops, flowcachep->total.find_ops), flowcachep->per_proto[i].find_ops, flowcachep->per_proto[i].reversed_ops, calc_percent64(flowcachep->per_proto[i].reversed_ops, flowcachep->per_proto[i].find_ops), flowcachep->per_proto[i].find_success, flowcachep->per_proto[i].find_fail, calc_percent64(flowcachep->per_proto[i].find_success, flowcachep->per_proto[i].find_ops), flowcachep->per_proto[i].new_flows); } } }
int flowps_entry_print(SCORE_ENTRY *entry, u_int32_t *address) { char *c_position = "TRACKER_ACTIVE"; u_int32_t i; if(entry->position == TRACKER_SCANNER) c_position = "TRACKER_SCANNER"; flow_printf(",-----------------------------------------------------\n"); flow_printf("| Score entry for %s@%p Flags: %x\n", inet_ntoa(*(struct in_addr *) address), entry, entry->flags); flow_printf("| Alerts: FT: %u ST: %u FS: %u SS: %u", (entry->flags & ALERT_FIXED_TALKER), (entry->flags & ALERT_SLIDING_TALKER), (entry->flags & ALERT_FIXED_SCANNER), (entry->flags & ALERT_SLIDING_SCANNER)); flowps_score_print(&entry->fixed_talker); flow_printf("\n| Position: %s\n", c_position); flow_printf("| Fixed Talker:"); flowps_score_print(&entry->fixed_talker); flow_printf("\n| Sliding Talker:"); flowps_score_print(&entry->sliding_talker); flow_printf("\n| Fixed Scanner:"); flowps_score_print(&entry->fixed_scanner); flow_printf("\n| Sliding Scanner:"); flowps_score_print(&entry->sliding_scanner); flow_printf("\n| Connections Seen: %u", entry->connections_seen); /* as long as we have a postive # of connections, pump out the info */ for(i=0; i < entry->connections_seen && i < FLOWPS_HOSTS_SIZE; i++) { CONN_ENTRY *cp = &entry->last_hosts[i]; if(cp->protocol == 6) { flow_printf("\n| proto: %d %s:%d th_flags: %s", cp->protocol, inet_ntoa(*(struct in_addr*) &cp->ip), cp->port, mktcpflag_str(cp->cflags)); } else { flow_printf("\n| proto: %d %s:%d cflags: %d", cp->protocol, inet_ntoa(*(struct in_addr*) &cp->ip), cp->port, cp->cflags); } } flow_printf("\n`----------------------------------------------------\n"); return 0; }
/** * Display what the underlying tidbits think the config is * * @param trackerp grab the configuration info from the portscan tracker */ static void FlowPSOutputConfig(PS_TRACKER *trackerp) { if(pv.quiet_flag) return; flow_printf(",-----------[flow-portscan config]-------------\n"); flow_printf("| TCP Penalties: %s\n", trackerp->config.tcp_penalties ? "On": "Off"); flow_printf("| Ouput Mode: %s\n", (trackerp->config.output_mode == VARIABLEMSG) ? "msg" : "pktkludge"); flow_printf("| Base Score: %d\n", trackerp->config.base_score); flow_printf("+----------------------------------------------\n"); flow_printf("| Scoreboard: ACTIVE PORTSCANNER\n"); flow_printf("| memcap: %-8d %-8d\n", scoreboard_memcap(&trackerp->table_active), scoreboard_memcap(&trackerp->table_scanner)); flow_printf("| rows: %-8d %-8d\n", scoreboard_row_count(&trackerp->table_active), scoreboard_row_count(&trackerp->table_scanner)); flow_printf("| overhead: %-8d(%%%.02lf) %-8d(%%%.02lf)\n", scoreboard_overhead_bytes(&trackerp->table_active), calc_percent(scoreboard_overhead_bytes(&trackerp->table_active), scoreboard_memcap(&trackerp->table_active)), scoreboard_overhead_bytes(&trackerp->table_scanner), calc_percent(scoreboard_overhead_bytes(&trackerp->table_scanner), scoreboard_memcap(&trackerp->table_scanner))); flow_printf("| fixed-size: %-4ds %-4ds\n", trackerp->config.limit_talker.fixed_size, trackerp->config.limit_scanner.fixed_size); flow_printf("| sliding-size: %-4ds %-4ds\n", trackerp->config.limit_talker.sliding_size, trackerp->config.limit_scanner.sliding_size); flow_printf("| threshold-fixed: %-4u %-4u\n", trackerp->config.limit_talker.fixed, trackerp->config.limit_scanner.fixed); flow_printf("| threshold-sliding: %-4u %-4u\n", trackerp->config.limit_talker.sliding, trackerp->config.limit_scanner.sliding); flow_printf("| window scale: %-.2lf %-.2lf\n", trackerp->config.limit_talker.window_scale, trackerp->config.limit_scanner.window_scale); flow_printf("+----------------------------------------------\n"); flow_printf("| Uniqueness: memcap: %8d rows: %8d\n", ut_memcap(&trackerp->unique_tracker), ut_row_count(&trackerp->unique_tracker)); flow_printf("| overhead: %d (%%%.02lf)\n", ut_overhead_bytes(&trackerp->unique_tracker), calc_percent(ut_overhead_bytes(&trackerp->unique_tracker), ut_memcap(&trackerp->unique_tracker))); if(flowps_server_stats_enabled(trackerp) == FLOW_SUCCESS) { flow_printf("+----------------------------------------------\n"); flow_printf("| Server Stats: memcap: %8d rows: %8d\n", server_stats_memcap(&trackerp->server_stats), server_stats_row_count(&trackerp->server_stats)); flow_printf("| overhead: %d (%%%.02lf)\n", server_stats_overhead_bytes(&trackerp->server_stats), calc_percent(server_stats_overhead_bytes(&trackerp->server_stats), server_stats_memcap(&trackerp->server_stats))); flow_printf("| learning time: %d\n", trackerp->config.server_learning_time); flow_printf("| ignore limit: %u\n", trackerp->config.server_ignore_limit); flow_printf("| scanner limit: %u\n", trackerp->config.server_scanner_limit); } else { flow_printf("| Server Stats: Disabled\n"); } flow_printf("`----------------------------------------------\n"); }
/** * Get the score and the type of connection this is * * If the score is 0, this is an already existing connection and can * be successfully ignored. * * @param pstp portscan tracker * @param flowp flow to aquire a score for * * @param cur current time * @flags packet related flags that can be used to modify the score * @param score return value for the score * @param type return value for the type of connection * * @return FLOW_SUCCESS on success and sets the score and type */ int flowps_get_score(PS_TRACKER *pstp, FLOW *flowp, time_t cur, u_int32_t flags, int *score, TRACKER_POSITION *type) { UT_TYPE unique; u_int32_t hitcount = 1; int base_score; if(!flowp || !score || !type) { return FLOW_ENULL; } /* save off a default base score */ base_score = pstp->config.base_score; *score = pstp->config.base_score; /* run the uniqueness check * * This should be ABOVE the finding code since the unquieness * check is the key to determining if this should accrue more * points. If it's not unique, we can bail out instantly. * */ if(ut_check(&pstp->unique_tracker, &flowp->key, &unique) != FLOW_SUCCESS) { #ifndef WIN32 flow_printf("ut check failed in %s\n", __func__); #else flow_printf("ut check failed in %s(%d)\n", __FILE__, __LINE__); #endif return 0; } if(unique == UT_OLD) { /* bail out if we do not have a reason to further evaluate the * score. The score can only be changed if this flow is truely * a unique (dport+proto+address) */ *score = 0; return FLOW_SUCCESS; } else /* UT_NEW */ { if(flowps_server_watch(pstp,flowp->key.resp_address) == FLOW_SUCCESS) { /* perform the hitcount management */ if(cur < (packet_first_time() + pstp->config.server_learning_time)) { if(server_stats_add_ipv4(&pstp->server_stats, flowp->key.protocol, flowp->key.resp_address, flowp->key.resp_port, &hitcount) != FLOW_SUCCESS) { #ifdef DEBUG flow_printf("Unable to add ipv4 to server stats!\n"); #endif /* DEBUG */ } } else { hitcount = server_stats_hitcount_ipv4(&pstp->server_stats, flowp->key.protocol, flowp->key.resp_address, flowp->key.resp_port); if(pstp->config.server_scanner_limit && hitcount < pstp->config.server_scanner_limit) { *type = TRACKER_SCANNER; } } if(pstp->config.server_ignore_limit > 0 && hitcount > pstp->config.server_ignore_limit) { /* this must be a semi-active service -- it's not worth * anything */ if(s_debug > 5) { flow_printf("Happy Server hitcount: %d proto: %d %s:%d\n", hitcount, flowp->key.protocol, inet_ntoa(*(struct in_addr *) &flowp->key.resp_address), flowp->key.resp_port); } base_score = 0; } } /* this IP is not being watched or something like it */ else { hitcount = 1; } } /* * possibly assign penalty points for "bad session initiators */ if(pstp->config.tcp_penalties && flowp->key.protocol == 6) { flowps_tcp_penalty(flags, base_score, score); } else { *score = base_score; } /* @todo switch tables */ return FLOW_SUCCESS; }
/** * The callback for the flow-portscan module * * This function's purpose is to do about the same thing as a * traditional snort preprocessor. The only difference is that this * occurs only on a specific FLOW position. * * This individual callback position is only valid in the "NEW" flow * position. * * The operations are pretty much the same as laid out by * * Chris Green, Marc Norton, Dan Roelker * * Basic code flow: * * 1) Get the score and flag type * 2) return if the score is 0 * 3) Get the score entry node * 4) Perform time window maintence * - includes flushing the "scan data" out of the subsys * 5) Process the score data * 6) Generate alerts if necessary * * @param position where in the flow module this is being called from * @param flow the flow that the stats are kept for * @param direction the direction of the flow * @param cur the current time * @param p the current packet (may be NULL) * * @return TBD */ int flowps_newflow_callback(FLOW_POSITION position, FLOW *flowp, int direction, time_t cur, FLOWPACKET *p) { TRACKER_POSITION tr_pos = TRACKER_ACTIVE; /* where new nodes get inserted */ PS_TRACKER *pstp = &s_tracker; SCORE_ENTRY *current_entry = NULL; int ret, score; u_int32_t alert_flags; u_int8_t cflags; u_int32_t *address = &flowp->key.init_address; if(!flowps_enabled()) return 0; if(s_debug > 5) { printf("DEBUG: callback %s:%d -> %s:%d\n", inet_ntoax(p->iph->ip_src.s_addr), p->sp, inet_ntoax(p->iph->ip_dst.s_addr), p->dp); } if(position != FLOW_NEW) { #ifndef WIN32 flow_printf("Wrong callback position for %s\n", __func__); #else flow_printf("Wrong callback position for %s(%d)\n", __FILE__, __LINE__); #endif return 0; } if(flowps_is_ignored_ipv4(pstp, &flowp->key.init_address, &flowp->key.resp_address) == FLOW_SUCCESS) { return 0; } if(IsTcpPacket(p)) { /* allow radically different flags from SYN help score * differently */ cflags = GetTcpFlags(p); } else { cflags = 0; } /* * if we can't find the score for whatever reason, or the * resultant score is 0 (indicating that this a "normal" event), * just go ahead and return */ if(flowps_get_score(pstp, flowp, cur, cflags, &score, &tr_pos) != FLOW_SUCCESS) { return -1; } if(score == 0) { return 0; } else if(s_debug > 5) { flow_printf("new unique flow!\n"); flowkey_print(&flowp->key); flow_printf("\n"); } /* run the "score entry finder" or create a new node */ ret = flowps_find_entry(pstp, address, ¤t_entry); if(ret == FLOW_NOTFOUND) { ret = flowps_add_entry(pstp, tr_pos, address, ¤t_entry); if(ret != FLOW_SUCCESS) { /* tracker failed horribly */ #ifndef WIN32 flow_printf("flowps_add_entry check failed in %s\n", __func__); #else flow_printf("flowps_add_entry check failed in %s(%d)\n", __FILE__, __LINE__); #endif return 0; } } else if(ret != FLOW_SUCCESS) { #ifndef WIN32 flow_printf("bad return for finding the entry %s\n", __func__); #else flow_printf("bad return for finding the entry %s(%d)\n", __FILE__, __LINE__); #endif return 0; } flowps_sliding_winadj(¤t_entry->sliding_talker, cur, &pstp->config.limit_talker); flowps_fixed_winadj(¤t_entry->fixed_talker, cur, &pstp->config.limit_talker); flowps_sliding_winadj(¤t_entry->sliding_scanner, cur, &pstp->config.limit_scanner); flowps_fixed_winadj(¤t_entry->fixed_scanner, cur, &pstp->config.limit_scanner); /* maintain the list of recent connections */ flowps_set_last_address(current_entry, flowp, cflags); /* windows adjusted, lets get us some alerts */ if(s_debug > 5 && score > 1) { flow_printf("XXXX **** got a big old score(%d) because of [%s] -> %s\n", score, mktcpflag_str(cflags), inet_ntoa(*(struct in_addr *) (&flowp->key.resp_address))); flowps_entry_print(current_entry, address); flow_printf("\nXXXX ****\n"); } if(flowps_score_entry(pstp, current_entry, score, tr_pos, pstp->config.alert_once, &alert_flags) != FLOW_SUCCESS) { #ifndef WIN32 flow_printf("bad return for finding the entry %s\n", __func__); #else flow_printf("bad return for finding the entry %s(%d)\n", __FILE__, __LINE__); #endif return 0; } /* If someone generates an event * * */ if(current_entry->position == TRACKER_ACTIVE && tr_pos == TRACKER_SCANNER) { //flow_printf("moving this one! (cur %d) -> (new %d) %s\n", //current_entry->position, tr_pos, inet_ntoa(*(struct in_addr *) address)); /* move address TO scanner FROM active */ ret = scoreboard_move(&pstp->table_scanner, &pstp->table_active, address); if(ret != FLOW_SUCCESS) { flow_printf("Unable to move %s\n",inet_ntoa(*(struct in_addr *) address)); return -1; } else { /* @todo - move this into the scoreboard mv call */ current_entry->position = TRACKER_SCANNER; } } if(s_debug > 5) { if(tr_pos == TRACKER_SCANNER) { flow_printf("Found a tracker scanner!\n"); flowps_entry_print(current_entry, address); } } if(s_debug > 10) { flowps_entry_print(current_entry, address); } if(alert_flags) { /* ** We OR the alert_flags here because we only want to add ** new alerts and reset alerts that might not be set in ** alert_flags. This is for the case of alert_once being ** set. */ current_entry->flags |= alert_flags; /* push things through the output system */ flowps_generate_flow_event(current_entry, p, address, pstp->config.output_mode, cur); } return 0; }
int server_stats_save(SERVER_STATS *ssp, char *filename) { SFXHASH_NODE *nodep; unsigned char buf[STATSREC_SIZE]; int fd; if(!filename || !ssp) return FLOW_ENULL; #ifndef O_SYNC #define O_SYNC O_FSYNC #endif /* open this description, create it if necessary, always wait on * sync to disk w/ every write, only write */ fd = open(filename, O_CREAT|O_TRUNC|O_SYNC|O_WRONLY); if(fd < 0) { if(s_debug) { flow_printf("%s was not found\n", filename); } return FLOW_NOTFOUND; } /* this is a crappy parser... that's par for the course */ for( nodep = sfxhash_ghead(ssp->ipv4_table); nodep != NULL; nodep = sfxhash_gnext(nodep) ) { SERVER_KEY *kp = (SERVER_KEY *) nodep->key; u_int32_t count = *(u_int32_t *) nodep->data; u_int8_t family = '4'; u_int32_t ipv4_address; u_int16_t port; u_int8_t protocol; ssize_t wbytes = 0; ssize_t wsize; count = ntohl(count); ipv4_address = htonl(kp->address); port = htons(kp->port); protocol = kp->protocol; memcpy(buf + FAMILY_OFFSET, &family, FAMILY_SIZE); memcpy(buf + IPV4_OFFSET, &ipv4_address, IPV4_SIZE); memcpy(buf + PORT_OFFSET, &port, PORT_SIZE); memcpy(buf + IP_PROTO_OFFSET, &protocol, IP_PROTO_SIZE); memcpy(buf + COUNT_OFFSET, &count, COUNT_SIZE); /* now make sure we get a full record on disk */ while(wbytes < STATSREC_SIZE) { /* write the number of bytes we already have - the # * already written */ wsize = write(fd, buf, (STATSREC_SIZE - wbytes)); if(wsize < 0) { /* this record was truncated */ flow_printf("Truncated Server Record!\n"); return FLOW_EINVALID; } else { wbytes += wsize; } } } return FLOW_SUCCESS; }