예제 #1
0
int ruleMatch(void *p, Rule* rule)
{
    int retVal;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    /* Uh, stupid rule... Just checking IPs & Ports apparently */
    if (rule->numOptions == 0)
        return RULE_MATCH;

    retVal = ruleMatchInternal(sp, rule, 0, NULL);

    /* Special case for rules that just set a flowbit, but
     * don't alert.
     */

    if (rule->noAlert)
        return RULE_NOMATCH;

    return retVal;
}
예제 #2
0
/* Function to evaluate a loop (ie, a series of nested options) */
ENGINE_LINKAGE int loopEval(void *p, LoopInfo *loop, const u_int8_t **cursor)
{
    const u_int8_t *startingCursor;
    const u_int8_t *tmpCursor;
    int32_t i;
    int32_t startValue;
    int32_t endValue;
    int32_t incrementValue;
    int maxIterations, iterationCount = 0;
    int ret = RULE_NOMATCH;

    if (!cursor || !*cursor)
        return RULE_NOMATCH;

    /* Protect ourselves... */
    if (!loop->initialized)
        return RULE_NOMATCH;

    tmpCursor = startingCursor = *cursor;

    if (loop->start->dynamicType == DYNAMIC_TYPE_INT_STATIC)
        startValue = loop->start->data.staticInt;
    else
        startValue = *(loop->start->data.dynamicInt);
   
    if (loop->end->dynamicType == DYNAMIC_TYPE_INT_STATIC)
        endValue = loop->end->data.staticInt;
    else
        endValue = *(loop->end->data.dynamicInt);

    if (loop->increment->dynamicType == DYNAMIC_TYPE_INT_STATIC)
        incrementValue = loop->increment->data.staticInt;
    else
        incrementValue = *(loop->increment->data.dynamicInt);

    /* determine max iterations - based on current cursor position,
     * relative to the appropriate buffer */
    maxIterations = getLoopLimit(p, loop, startingCursor);

    for (i=startValue;
         checkLoopEnd(loop->op, i, endValue) && (iterationCount < maxIterations);
         i+= incrementValue)
    {
        /* Evaluate the options from the sub rule */
        ret = ruleMatchInternal(p, loop->subRule, 0, &tmpCursor);
        if (ret > RULE_NOMATCH)
        {
            *cursor = tmpCursor;
            return ret;
        }

        /* Adjust the starting cursor as specified... */
        tmpCursor = startingCursor;
        ret = setCursor(p, loop->cursorAdjust, &tmpCursor);
        if (ret != RULE_MATCH)
        {
            /* ie, cursor went out of bounds */
            return ret;
        }

        /* And save off the starting cursor */
        startingCursor = tmpCursor;

        iterationCount++;
    }

    return RULE_NOMATCH;
}
예제 #3
0
/* 
 *  ruleMatch
 * 
 *          p: packet data structure, same as the one found in snort.
 *    options: NULL terminated list of rule options
 *
 * Returns: 
 *    > 0 : match found
 *    = 0 : no match found
 *
 * Predefined constants: 
 *    (see sf_snort_plugin_api.h for more values)
 *    RULE_MATCH   -  if asn1 specifier is found within buffer 
 *    RULE_NOMATCH -  if asn1 specifier is not found within buffer 
 * 
 */
int ruleMatchInternal(SFSnortPacket *p, Rule* rule, u_int32_t optIndex, u_int8_t **cursor)
{
    u_int8_t *thisCursor = NULL, *startCursor = NULL;
    u_int8_t *tmpCursor = NULL;
    int retVal = RULE_NOMATCH;
    u_int32_t notFlag = 0;
    int thisType;
    ContentInfo *thisContentInfo = NULL;
    int startAdjust = 0;
    u_int32_t origFlags = 0;
    int32_t origOffset = 0;
    u_int32_t origDepth = 0;
    int continueLoop = 1;
    PCREInfo *thisPCREInfo = NULL;

    if (cursor)
        startCursor = thisCursor = *cursor;

    if (optIndex >= rule->numOptions || !rule->options[optIndex] )
        return RULE_NOMATCH;

    thisType = rule->options[optIndex]->optionType;

    /* Do some saving off of some info for recursion purposes */
    switch (thisType)
    {
        case OPTION_TYPE_CONTENT:
            thisContentInfo = rule->options[optIndex]->option_u.content;
            origFlags = thisContentInfo->flags;
            origDepth = thisContentInfo->depth;
            origOffset = thisContentInfo->offset;
            break;
        case OPTION_TYPE_PCRE:
            thisPCREInfo = rule->options[optIndex]->option_u.pcre;
            origFlags = thisPCREInfo->flags;
            break;
        default:
            /* Other checks should not need to check again like
             * PCRE & Content do.
             */
            break;
    }

    do
    {
        switch (thisType)
        {
        case OPTION_TYPE_CONTENT:
            retVal = contentMatch(p, rule->options[optIndex]->option_u.content, &thisCursor);
            notFlag = rule->options[optIndex]->option_u.content->flags & NOT_FLAG;
            break;
        case OPTION_TYPE_PCRE:
            retVal = pcreMatch(p, rule->options[optIndex]->option_u.pcre, &thisCursor);
            notFlag = rule->options[optIndex]->option_u.pcre->flags & NOT_FLAG;
            break;
        case OPTION_TYPE_FLOWBIT:
            retVal = processFlowbits(p, rule->options[optIndex]->option_u.flowBit);
            notFlag = rule->options[optIndex]->option_u.flowBit->flags & NOT_FLAG;
            break;
        case OPTION_TYPE_BYTE_TEST:
            retVal = byteTest(p, rule->options[optIndex]->option_u.byte, thisCursor);
            notFlag = rule->options[optIndex]->option_u.byte->flags & NOT_FLAG;
            break;
        case OPTION_TYPE_BYTE_JUMP:
            retVal = byteJump(p, rule->options[optIndex]->option_u.byte, &thisCursor);
            notFlag = rule->options[optIndex]->option_u.byte->flags & NOT_FLAG;
            break;
        case OPTION_TYPE_FLOWFLAGS:
            retVal = checkFlow(p, rule->options[optIndex]->option_u.flowFlags);
            notFlag = rule->options[optIndex]->option_u.flowFlags->flags & NOT_FLAG;
            break;
        case OPTION_TYPE_ASN1:
            retVal = detectAsn1(p, rule->options[optIndex]->option_u.asn1, thisCursor);
            notFlag = rule->options[optIndex]->option_u.asn1->flags & NOT_FLAG;
            break;
        case OPTION_TYPE_CURSOR:
            retVal = checkCursor(p, rule->options[optIndex]->option_u.cursor, thisCursor);
            notFlag = rule->options[optIndex]->option_u.cursor->flags & NOT_FLAG;
            break;
        case OPTION_TYPE_SET_CURSOR:
            retVal = setCursor(p, rule->options[optIndex]->option_u.cursor, &thisCursor);
            notFlag = rule->options[optIndex]->option_u.cursor->flags & NOT_FLAG;
            break;
        case OPTION_TYPE_HDR_CHECK:
            retVal = checkHdrOpt(p, rule->options[optIndex]->option_u.hdrData);
            notFlag = rule->options[optIndex]->option_u.hdrData->flags & NOT_FLAG;
            break;
        case OPTION_TYPE_BYTE_EXTRACT:
            retVal = extractValue(p, rule->options[optIndex]->option_u.byteExtract, thisCursor);
            notFlag = rule->options[optIndex]->option_u.byteExtract->flags & NOT_FLAG;
            break;
        case OPTION_TYPE_LOOP:
            retVal = loopEval(p, rule->options[optIndex]->option_u.loop, &thisCursor);
            notFlag = rule->options[optIndex]->option_u.loop->flags & NOT_FLAG;
            break;
        case OPTION_TYPE_PREPROCESSOR:
            retVal = preprocOptionEval(p, rule->options[optIndex]->option_u.preprocOpt, &thisCursor);
            notFlag = rule->options[optIndex]->option_u.preprocOpt->flags & NOT_FLAG;
            break;
        }

        if ( notFlag )
        {
            if ((retVal <= RULE_NOMATCH))
            {
                /* Set this as a positive match -- a ! was specified. */
                retVal = RULE_MATCH;
            }
            else  /* Match */
            {
                retVal = RULE_NOMATCH;
            }
        }

        if (retVal > RULE_NOMATCH)
        {
            /* This one matched.  Depending on type, check the next one
             * either in a loop, or not, saving cursor temporarily.
             */
            if (optIndex < rule->numOptions -1) /* hehe, optIndex is 0 based */
            {
                int nestedRetVal;
                /* Here's where it gets tricky... */
                if (thisType == OPTION_TYPE_CONTENT)
                {
                    /* If this is a content option, we've found a match.
                     * Save off the end-point of the current match.
                     * Less the length of current match plus 1.
                     *
                     * This gives us the starting point to check for this
                     * content again if subsequent options fail.  That starting
                     * point is the byte AFTER the beginning of the current
                     * match.
                     */
                    if ((origFlags & CONTENT_RELATIVE) && startCursor)
                    {
                        /* relative content.
                         * need to adjust offset/depth as well
                         */
                        tmpCursor = thisCursor -
                            thisContentInfo->patternByteFormLength + thisContentInfo->incrementLength;

                        /* Start Adjust is the difference between the old
                         * starting point and the 'next' starting point. */
                        startAdjust = tmpCursor - startCursor;
                    }
                    else
                    {
                        /* non-relative content */
                        tmpCursor = thisCursor -
                            thisContentInfo->patternByteFormLength + thisContentInfo->incrementLength;
                    }
                }
                else if (thisType == OPTION_TYPE_PCRE)
                {
                    /* Start next search at end of current pattern */
                    /* XXX: Could miss something here if part of pattern
                     * repeats but not easy to tell with PCRE.
                     */
                    tmpCursor = thisCursor;
                }

                nestedRetVal = ruleMatchInternal(p, rule, optIndex+1, &thisCursor);
                if (nestedRetVal == RULE_MATCH)
                {
                    /* Cool, everyone after us matched, we're done with a match */
                    if (cursor)
                        *cursor = thisCursor;
                    break;
                }

                /* If Content or PCRE, look farther into the packet
                 * for another match. */
                if (((thisType == OPTION_TYPE_CONTENT) ||
                     (thisType == OPTION_TYPE_PCRE))
                     && !notFlag)
                {
                    /* Only try to find this content again if it is a
                     * positive match.
                     */

                    /* And only if the next option is relative */
                    if (!isRelativeOption(rule->options[optIndex+1]))
                    {
                        /* Match failed, next option is not relative. 
                         * We're done. */
                        retVal = nestedRetVal;
                        break;
                    }

                    switch (thisType)
                    {
                    case OPTION_TYPE_CONTENT:
                        if (origFlags & CONTENT_RELATIVE)
                        {
                            if ((int32_t)(origDepth - startAdjust) < (int32_t)thisContentInfo->patternByteFormLength)
                            {
                                /* Adjusted depth would be less than the content we're searching for?
                                 * we're done. */
                                retVal = nestedRetVal;
                                continueLoop = 0;
                            }
                            else
                            {
                                /* For contents that were already relative, adjust the offset & depth fields
                                 * from their original values.  Makes it easy to determine when we'll be out
                                 * of the original bounds, relative to the original cursor. */
                                thisContentInfo->offset = origOffset + startAdjust;
                                thisContentInfo->depth = origDepth - startAdjust;

                                /* And use the original cursor that was passed in */
                                thisCursor = startCursor;
                            }
                        }
                        else
                        {
                            thisContentInfo->flags |= CONTENT_RELATIVE;
                            /* For contents that were not already relative, we simply use the adjusted
                             * cursor.  Set thisCursor to tmpCursor as calculated above */
                            thisCursor = tmpCursor;
                        }
                        break;
                    case OPTION_TYPE_PCRE:
                        /* Doesn't matter if it was already relative,
                         * just make it relative anyway.
                         */
                        thisPCREInfo->flags |= CONTENT_RELATIVE;
                        /* For PCREs that were not already relative, we use the cursor
                         * that was returned at the end of the pattern to start searching
                         * again. */
                        thisCursor = tmpCursor;
                        break;
                    }
                    continue;
                }


                /* Only need to search again when this is a
                 * content option.  If its not, we're done. */
                if (nestedRetVal <= RULE_NOMATCH)
                {
                    /* Handle the case when an error is propigated
                     * via nestedRetVal.
                     */
                    retVal = RULE_NOMATCH;
                }
                break;
            }
            else
            {
                /* Cool, nobody after us, we're done with a match */
                if (cursor)
                    *cursor = thisCursor;
                break;
            }
        }
        else
        {
            /* No match, get outta dodge */
            break;
        }
    } while (continueLoop);
    /* Keep looping until we break or serialized content checks returns no match. */

    /* Reset the flags for this content in case we added the
     * relative flag above.
     */
    if (thisContentInfo)
    {
        thisContentInfo->flags = origFlags;
        thisContentInfo->offset = origOffset;
        thisContentInfo->depth = origDepth;
    }
    if (thisPCREInfo)
    {
        thisPCREInfo->flags = origFlags;
    }

    return retVal;
}