/** * 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; }
/** * 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); }