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