示例#1
0
/**
 * 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, &current_entry);

    if(ret == FLOW_NOTFOUND)
    {
        ret = flowps_add_entry(pstp,  tr_pos, address, &current_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(&current_entry->sliding_talker,
                          cur,
                          &pstp->config.limit_talker);

    flowps_fixed_winadj(&current_entry->fixed_talker,
                        cur,
                        &pstp->config.limit_talker);

    flowps_sliding_winadj(&current_entry->sliding_scanner,
                          cur,
                          &pstp->config.limit_scanner);

    flowps_fixed_winadj(&current_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);
}