zoukankan      html  css  js  c++  java
  • snort读取规则选项

    ***************************************************************/
    static const RuleOptFunc rule_options[] =
    {
        { RULE_OPT__ACTIVATED_BY,     1, 1, ParseOtnActivatedBy },
        { RULE_OPT__ACTIVATES,        1, 1, ParseOtnActivates },
        { RULE_OPT__CLASSTYPE,        1, 1, ParseOtnClassType },
        { RULE_OPT__COUNT,            1, 1, ParseOtnCount },
        { RULE_OPT__DETECTION_FILTER, 1, 1, ParseOtnDetectionFilter },
        { RULE_OPT__GID,              1, 1, ParseOtnGid },
        { RULE_OPT__LOGTO,            1, 1, ParseOtnLogTo },
        { RULE_OPT__METADATA,         1, 0, ParseOtnMetadata },
        { RULE_OPT__MSG,              1, 1, ParseOtnMessage },
        { RULE_OPT__PRIORITY,         1, 1, ParseOtnPriority },
        { RULE_OPT__REFERENCE,        1, 0, ParseOtnReference },
        { RULE_OPT__REVISION,         1, 1, ParseOtnRevision },
        { RULE_OPT__SID,              1, 1, ParseOtnSid },
        { RULE_OPT__TAG,              1, 1, ParseOtnTag },
        { RULE_OPT__THRESHOLD,        1, 1, ParseOtnThreshold },
     
        { NULL, 0, 0, NULL }   /* Marks end of array */
    };
     
    /* Rule options
     * Only the basic ones are here.  The detection options and preprocessor
     * detection options define their own */
    #define RULE_OPT__ACTIVATED_BY      "activated_by"
    #define RULE_OPT__ACTIVATES         "activates"
    #define RULE_OPT__CLASSTYPE         "classtype"
    #define RULE_OPT__COUNT             "count"
    #define RULE_OPT__DETECTION_FILTER  "detection_filter"
    #define RULE_OPT__GID               "gid"
    #define RULE_OPT__MSG               "msg"
    #define RULE_OPT__METADATA          "metadata"
    #define RULE_OPT__LOGTO             "logto"
    #define RULE_OPT__PRIORITY          "priority"
    #define RULE_OPT__REFERENCE         "reference"
    #define RULE_OPT__REVISION          "rev"
    #define RULE_OPT__SID               "sid"
    #define RULE_OPT__TAG               "tag"
    #define RULE_OPT__THRESHOLD         "threshold"
     
     
    /***************************************************************/
     
    typedef struct {
         unsigned gid;
         unsigned sid;
    }rule_number_t;
     
    typedef struct {
        int  max_rules;
        int  num_rules;
        rule_number_t * map;
    }rule_index_map_t;
     
    /****************************************************************************
     *
     * Function: ParseRuleOptions(char *, int)
     *
     * Purpose:  Process an individual rule's options and add it to the
     *           appropriate rule chain
     *
     * Arguments: rule => rule string
     *            rule_type => enumerated rule type (alert, pass, log)
     *            *conflicts => Identifies whether there was a conflict due to duplicate
     *                rule and whether existing otn was newer or not.
     *                0 - no conflict
     *                1 - existing otn is newer.
     *                -1 - existing otn is older.
     *
     * Returns:
     *  OptTreeNode *
     *      The new OptTreeNode on success or NULL on error.
     *
     ***************************************************************************/
    OptTreeNode * ParseRuleOptions(SnortConfig *sc, RuleTreeNode *rtn,
                                   char *rule_opts, RuleType rule_type, int protocol)
    {
        OptTreeNode *otn;
        RuleOptOtnHandler otn_handler = NULL;
        int num_detection_opts = 0;
        char *dopt_keyword = NULL;
        OptFpList *fpl = NULL;
        int got_sid = 0;
        /**申请一个规则选项对象*/
        otn = (OptTreeNode *)SnortAlloc(sizeof(OptTreeNode));
     
        /**为该规则选项设置一些基础属性*/
        otn->chain_node_number = otn_count;
        otn->proto = protocol;
        otn->event_data.sig_generator = GENERATOR_SNORT_ENGINE;
        otn->sigInfo.generator        = GENERATOR_SNORT_ENGINE;
        otn->sigInfo.rule_type        = SI_RULE_TYPE_DETECT; /* standard rule */
        otn->sigInfo.rule_flushing    = SI_RULE_FLUSHING_ON; /* usually just standard rules cause a flush*/
     
        /* Set the default rule state */
        /**设置默认状态*/
        otn->rule_state = ScDefaultRuleState();
        /**如果该规则没有规则选项*/
        if (rule_opts == NULL)
        {
            DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "No rule options.
    "););
            /**没有规则选项时但snort又需要规则选项中的sid时报错*/
            if (ScRequireRuleSid())
                ParseError("Each rule must contain a Rule-sid.");
            /**实际是规则选项保留指向规则头的指针,这样就构成了整个规则对象*/
            addRtnToOtn(otn, getParserPolicy(sc), rtn);
            /**将该规则的gid 和sid 构成一个id对象存放在ruleIndexMap的一个数组中,而存放位置下标作为返回值*/
            otn->ruleIndex = RuleIndexMapAdd(ruleIndexMap,
                                             otn->sigInfo.generator,
                                             otn->sigInfo.id);
        }
        else    /**有规则选项,解释规则选项*/
        {
            char **toks;
            int num_toks;
            /**字符数组大小为解析规则选项的预制回调函数个数*/
            char configured[sizeof(rule_options) / sizeof(RuleOptFunc)];
            int i;
            OptTreeNode *otn_dup;
            /**检查格式*/
            if ((rule_opts[0] != '(') || (rule_opts[strlen(rule_opts) - 1] != ')'))
            {
                ParseError("Rule options must be enclosed in '(' and ')'.");
            }
     
            /* Move past '(' and zero out ')' */
            /**去掉首尾括号*/
            rule_opts++;
            rule_opts[strlen(rule_opts) - 1] = '';
     
            /* Used to determine if a rule option has already been configured
             * in the rule.  Some can only be configured once */
            memset(configured, 0, sizeof(configured));
            /**提取规则选项条目*/
            toks = mSplit(rule_opts, ";", 0, &num_toks, '\');
     
            for (i = 0; i < num_toks; i++)
            {
                char **opts;
                int num_opts;
                char *option_args = NULL;
                int j;
     
                DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"   option: %s
    ", toks[i]););
                /**提取键值*/
                /* break out the option name from its data */
                opts = mSplit(toks[i], ":", 2, &num_opts, '\');
     
                DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"   option name: %s
    ", opts[0]););
     
                if (num_opts == 2)
                {
                    option_args = opts[1];
                    DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"   option args: %s
    ", option_args););
                }
     
                for (j = 0; rule_options[j].name != NULL; j++)
                {
                    /**检查该键对应的RuleOptFunc是哪一个*/
                    if (strcasecmp(opts[0], rule_options[j].name) == 0)
                    {
                        /**有的键值对应的数据只能获取一次,如果多次发现该键则报错*/
                        if (configured[j] && rule_options[j].only_once)
                        {
                            ParseError("Only one '%s' rule option per rule.",
                                       opts[0]);
                        }
                        /**若果键没有对应的值且该键需要参数则错误*/
                        if ((option_args == NULL) && rule_options[j].args_required)
                        {
                            ParseError("No argument passed to keyword "%s".  "
                                       "Make sure you didn't forget a ':' or the "
                                       "argument to this keyword.
    ", opts[0]);
                        }
                        /**调用键对应的回调函数进行处理*/
                        rule_options[j].parse_func(sc, rtn, otn, rule_type, option_args);
                        /**标记该键已获取过一次*/
                        configured[j] = 1;
                        break;
                    }
                }
     
                /* Because we actually allow an sid of 0 */
                if ((rule_options[j].name != NULL) &&
                    (strcasecmp(rule_options[j].name, RULE_OPT__SID) == 0))
                {
                    got_sid = 1;
                }
                /**解析规则选项的回调函数中,部分必要的基础数据解析使用的是
                 * rule_options中的单元,但更多的辅助单元是以插件方式注册的,
                 * 例如 SetupFlowBits等键值对解析。
                 *
                 **/
     
                 /**先检查是否是探测类型的插件*/
                /* It's possibly a detection option plugin */
                if (rule_options[j].name == NULL)
                {
                    RuleOptConfigFuncNode *dopt = rule_opt_config_funcs;
                    /**遍历所有规则选项解析插件*/
                    for (; dopt != NULL; dopt = dopt->next)
                    {
                        /**查找键值匹配的插件,如SetupTcpSeqCheck等*/
                        if (strcasecmp(opts[0], dopt->keyword) == 0)
                        {
                            /**调用该插件解析该单元*/
                            dopt->func(sc, option_args, otn, protocol);
     
                            /* If this option contains an OTN handler, save it for
                               use after the rule is done parsing. */
                            if (dopt->otn_handler != NULL)
                                otn_handler = dopt->otn_handler;
     
                            /* This is done so if we have a preprocessor/decoder
                             * rule, we can tell the user that detection options
                             * are not supported with those types of rules, and
                             * what the detection option is */
                             /**如果该插件试探查类插件将名字备份*/
                            if ((dopt_keyword == NULL) &&
                                (dopt->type == OPT_TYPE_DETECTION))
                            {
                                dopt_keyword = SnortStrdup(opts[0]);
                            }
     
                            break;
                        }
                    }
                    /**如果不是探测类型的插件,再来检测他是否是预处理的插件*/
                    if (dopt == NULL)
                    {
                        /* Maybe it's a preprocessor rule option */
                        PreprocOptionInit initFunc = NULL;
                        PreprocOptionEval evalFunc = NULL;
                        PreprocOptionFastPatternFunc fpFunc = NULL;
                        PreprocOptionOtnHandler preprocOtnHandler = NULL;
                        PreprocOptionCleanup cleanupFunc = NULL;
                        void *opt_data = NULL;
     
                        /**获取该关键字对应的预处理插件*/
                        int ret = GetPreprocessorRuleOptionFuncs
                            (sc, opts[0], &initFunc, &evalFunc,
                             &preprocOtnHandler, &fpFunc, &cleanupFunc);
     
                        if (ret && (initFunc != NULL))
                        {
                            /**初始化该插件*/
                            initFunc(sc, opts[0], option_args, &opt_data);
                            /**将该预处理处理报文的部分加入该规则选项实体持有的回调链中*/
                            AddPreprocessorRuleOption(sc, opts[0], otn, opt_data, evalFunc);
                            if (preprocOtnHandler != NULL)
                                otn_handler = (RuleOptOtnHandler)preprocOtnHandler;
     
                            DEBUG_WRAP(DebugMessage(DEBUG_INIT, "%s->", opts[0]););
                        }
                        else
                        {
                            /* Unrecognized rule option */
                            ParseError("Unknown rule option: '%s'.", opts[0]);
                        }
                    }
     
                    if (dopt_keyword == NULL)
                        dopt_keyword = SnortStrdup(opts[0]);
     
                    num_detection_opts++;
                }
     
                mSplitFree(&opts, num_opts);
            }
     
            /**这一部分代码是对自检和善后处理*/
            if ((dopt_keyword != NULL) &&
                (otn->sigInfo.rule_type != SI_RULE_TYPE_DETECT))
            {
                /* Preprocessor and decoder rules can not have
                 * detection options */
                ParseError("Preprocessor and decoder rules do not support "
                           "detection options: %s.", dopt_keyword);
            }
     
            if (dopt_keyword != NULL)
                free(dopt_keyword);
     
            if (!got_sid && !ScTestMode())
                ParseError("Each rule must contain a rule sid.");
     
            DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"OptListEnd
    "););
            /** 建立起规则选项实体到规则头部实体的映射*/
            addRtnToOtn(otn, getParserPolicy(sc), rtn);
     
            /* Check for duplicate SID */
            /** 检查sid 冲突*/
            otn_dup = OtnLookup(sc->otn_map, otn->sigInfo.generator, otn->sigInfo.id);
            if (otn_dup != NULL)
            {
                otn->ruleIndex = otn_dup->ruleIndex;
     
                if (mergeDuplicateOtn(sc, otn_dup, otn, rtn) == 0)
                {
                    /* We are keeping the old/dup OTN and trashing the new one
                     * we just created - it's free'd in the remove dup function */
                    mSplitFree(&toks, num_toks);
                    return NULL;
                }
            }
            else
            {
    /** 保存规则的gid 和 sid, 返回两个数据构成的对象在存放该对象集合的数组中的位置*/
                otn->ruleIndex = RuleIndexMapAdd(ruleIndexMap,
                                                 otn->sigInfo.generator,
                                                 otn->sigInfo.id);
            }
     
            mSplitFree(&toks, num_toks);
        }
        /**更新该规则选项所拥有的探测计数*/
        otn->num_detection_opts += num_detection_opts;
        /**更新总的规则选项计数*/
        otn_count++;
        /**如果该规则选项是探测型的,则增加探测规则计数*/
        if (otn->sigInfo.rule_type == SI_RULE_TYPE_DETECT)
        {
            detect_rule_count++;
        }
        else if (otn->sigInfo.rule_type == SI_RULE_TYPE_DECODE)
        {
        /**如果是设置decode的则反转指定sid的规则decode标识是否使能*/
            //Set the bit if the decoder rule is enabled in the policies
            UpdateDecodeRulesArray(otn->sigInfo.id, ENABLE_RULE, ENABLE_ONE_RULE);
            decode_rule_count++;
        }
        /**如果该规则选项是预处理类型的则增加预处理计数*/
        else if (otn->sigInfo.rule_type == SI_RULE_TYPE_PREPROC)
        {
            preproc_rule_count++;
        }
        /**向该选项节点的规则选项回调链表中追加一个尾部标志*/
        fpl = AddOptFuncToList(OptListEnd, otn);
        fpl->type = RULE_OPTION_TYPE_LEAF_NODE;
     
        if (otn_handler != NULL)
        {
            otn_handler(sc, otn);
        }
        /**这两个主要是针对字串的模式匹配,后续专门分析*/
        FinalizeContentUniqueness(sc, otn);
        ValidateFastPattern(otn);
     
        if ((thdx_tmp != NULL) && (otn->detection_filter != NULL))
        {
            ParseError("The "detection_filter" rule option and the "threshold" "
                       "rule option cannot be used in the same rule.
    ");
        }
        /**启用阀值时的一些检测不用太关注*/
        if (thdx_tmp != NULL)
        {
            int rstat;
     
            thdx_tmp->sig_id = otn->sigInfo.id;
            thdx_tmp->gen_id = otn->sigInfo.generator;
            rstat = sfthreshold_create(sc, sc->threshold_config, thdx_tmp);
     
            if (rstat)
            {
                if (rstat == THD_TOO_MANY_THDOBJ)
                {
                    ParseError("threshold (in rule): could not create threshold - "
                               "only one per sig_id=%u.", thdx_tmp->sig_id);
                }
                else
                {
                    ParseError("threshold (in rule): could not add threshold "
                               "for sig_id=%u!
    ", thdx_tmp->sig_id);
                }
            }
     
            thdx_tmp = NULL;
        }
     
        /* setup gid,sid->otn mapping */
        /**下面的两个函数都是将以otn中的sid 和 gid作为键将otn加入sfghash
         * 不同的是当发现其中有键完全相同的数据时的处理
         * 1.第一个函数会将该otn链接在sfgash查到的重复otn的一个专有链表中
         * 2.第二个则会直接报错
         */
        SoRuleOtnLookupAdd(sc->so_rule_otn_map, otn);
        OtnLookupAdd(sc->otn_map, otn);
     
        return otn;
    }
     
    /**根据关键字获取预处理插件*/
    int GetPreprocessorRuleOptionFuncs(
        SnortConfig *sc,
        char *optionName,
        PreprocOptionInit* initFunc,
        PreprocOptionEval* evalFunc,
        PreprocOptionOtnHandler* otnHandler,
        PreprocOptionFastPatternFunc* fpFunc,
        PreprocOptionCleanup* cleanupFunc
        )
    {
        /**因为预处理插件会注册多个函数,所以使用PreprocessorOptionInfo管理一个预处理插件的所有回调接口*/
        PreprocessorOptionInfo *optionInfo;
        SnortPolicy *p;
     
        if (sc == NULL)
        {
            FatalError("%s(%d) Snort conf for parsing is NULL.
    ",
                       __FILE__, __LINE__);
        }
     
        p = sc->targeted_policies[getParserPolicy(sc)];
        if (p == NULL)
            return 0;
     
        if (p->preproc_rule_options == NULL)
        {
            FatalError("Preprocessor Rule Option storage not initialized
    ");
        }
     
        /**为了快速查找使用sfhash管理PreprocessorOptionInfo,这里是从sfghash中获取预处理插件*/
        optionInfo = sfghash_find(p->preproc_rule_options, optionName);
        if (!optionInfo)
        {
            return 0;
        }
        /**从找到的PreprocessorOptionInfo中提取该预处理插件的回调函数*/
        *initFunc = (PreprocOptionInit)optionInfo->optionInit;  /**该回调主要是做初始化工作*/
        *evalFunc = (PreprocOptionEval)optionInfo->optionEval;  /**返回匹配等处理后获得的状态标志*/
        *fpFunc = (PreprocOptionFastPatternFunc)optionInfo->optionFpFunc;
        *otnHandler = (PreprocOptionOtnHandler)optionInfo->otnHandler;
        *cleanupFunc = (PreprocOptionCleanup)optionInfo->optionCleanup;
     
        return 1;
    }
    /***********************************************************************************************************************/
     
    /* same as the rule header FP list */
    typedef struct _OptFpList
    {
        /* context data for this test */
        void *context;
     
        int (*OptTestFunc)(void *option_data, Packet *p);
     
        struct _OptFpList *next;
     
        unsigned char isRelative;
        option_type_t type;
     
    } OptFpList;
     
     
    int AddPreprocessorRuleOption(SnortConfig *sc, char *optionName, OptTreeNode *otn, void *data, PreprocOptionEval evalFunc)
    {
        OptFpList *fpl;
        PreprocessorOptionInfo *optionInfo;
        PreprocessorOptionInfo *saveOptionInfo;
        /**这是用来获取数据的指针*/
        void *option_dup;
        SnortPolicy *p;
     
        if (sc == NULL)
        {
            FatalError("%s(%d) Snort conf for parsing is NULL.
    ",
                       __FILE__, __LINE__);
        }
     
        p = sc->targeted_policies[getParserPolicy(sc)];
        if (p == NULL)
            return 0;
        /**这里再次利用关键字获取到该预处理插件
         *
         */
        optionInfo = sfghash_find(p->preproc_rule_options, optionName);
     
        if (!optionInfo)
            return 0;
     
        saveOptionInfo = (PreprocessorOptionInfo *)SnortAlloc(sizeof(PreprocessorOptionInfo));
     
        memcpy(saveOptionInfo, optionInfo, sizeof(PreprocessorOptionInfo));
        /**注意, 在初始化该插件是允许返回一个数据,这里将该数据使用PreprocessorOptionInfo保存*/
        saveOptionInfo->data = data;
     
        /**将该插件的功能函数(该函数会解析报文数据)加入该规则选项的opt_func链表中*/
        //  Add to option chain with generic callback
        fpl = AddOptFuncToList(PreprocessorOptionFunc, otn);
     
        /*
         * attach custom info to the context node so that we can call each instance
         * individually
         */
         /**将fp1关联生成他的预处理器*/
        fpl->context = (void *) saveOptionInfo;
        /**这要是将初始化该插件时返回的数据保存在hash表中*/
        if (add_detection_option(sc, RULE_OPTION_TYPE_PREPROCESSOR,
                                 (void *)saveOptionInfo, &option_dup) == DETECTION_OPTION_EQUAL)
        {
            PreprocessorRuleOptionsFreeFunc(saveOptionInfo);
            fpl->context = saveOptionInfo = option_dup;
        }
        fpl->type = RULE_OPTION_TYPE_PREPROCESSOR;
     
        return 1;
    }
     
    /********************************************************************************/
    /****************************************************************************
     *
     * Function: AddOptFuncToList(int (*func)(), OptTreeNode *)
     *
     * Purpose: Links the option detection module to the OTN
     *
     * Arguments: (*func)() => function pointer to the detection module
     *            otn =>  pointer to the current OptTreeNode
     *
     * Returns: void function
     *
     ***************************************************************************/
    OptFpList * AddOptFuncToList(RuleOptEvalFunc ro_eval_func, OptTreeNode *otn)
    {
        OptFpList *ofp = (OptFpList *)SnortAlloc(sizeof(OptFpList));
     
        DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Adding new rule to list
    "););
        /**将插件的回调函数加入该规则选项的opt_func链表中*/
        /* if there are no nodes on the function list... */
        if (otn->opt_func == NULL)
        {
            otn->opt_func = ofp;
        }
        else
        {
            OptFpList *tmp = otn->opt_func;
     
            /* walk to the end of the list */
            while (tmp->next != NULL)
                tmp = tmp->next;
     
            tmp->next = ofp;
        }
     
        DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Set OptTestFunc to %p
    ", ro_eval_func););
        /**指向最后一个被加入的回调函数**/
        ofp->OptTestFunc = ro_eval_func;
     
        return ofp;
    }
     
    /****************************************************************************/
    /**Add RTN to OTN for a particular OTN.
     * @param otn pointer to structure OptTreeNode.
     * @param policyId policy id
     * @param rtn pointer to RuleTreeNode structure
     *
     * @return 0 if successful,
     *         -ve otherwise
     */
    int addRtnToOtn(
            OptTreeNode *otn,
            tSfPolicyId policyId,
            RuleTreeNode *rtn
            )
    {
        if (otn->proto_node_num <= policyId)
        {
            /* realloc the list, initialize missing elements to 0 and add
             * policyId */
            RuleTreeNode **tmpNodeArray;
            unsigned int numNodes = (policyId + 1);
     
            tmpNodeArray = SnortAlloc(sizeof(RuleTreeNode *) * numNodes);
     
            /* copy original contents, the remaining elements are already
             * zeroed out by snortAlloc */
            if (otn->proto_nodes)
            {
                memcpy(tmpNodeArray, otn->proto_nodes,
                    sizeof(RuleTreeNode *) * otn->proto_node_num);
                free(otn->proto_nodes);
            }
     
            otn->proto_node_num = numNodes;
            otn->proto_nodes = tmpNodeArray;
        }
     
        //add policyId
        if (otn->proto_nodes[policyId])
        {
            DestroyRuleTreeNode(rtn);
            return -1;
        }
        /**实际就这里最关键,这里建立起规则选项实体到规则头部实体的映射*/
        otn->proto_nodes[policyId] = rtn;
     
        return 0; //success
    }
  • 相关阅读:
    常见运算符_python
    hibernate中的二级缓存
    事务的隔离级别
    java hibernate 一对多和多对多映射关系总结
    hibernate中集合映射总结
    java中静态代码块之我的理解
    select下拉表达设置选中,获取选中项,change
    jquery checkbox设置选中,全选,反选,取值
    javaWeb建立一个简单三层项目具体步骤
    java 异步实现省市联动
  • 原文地址:https://www.cnblogs.com/sunyongjie1984/p/4375578.html
Copyright © 2011-2022 走看看