snort中較重要的一個環節就是配置文件的讀取。以snort-2.9.6.0爲示例
node
該過程完成如下幾件事
git
肯定被加載的模塊,並能爲部分模塊得到須要的配置參數app
獲取構建匹配結構須要的數據函數
內容較多,能夠下載snort 配置手冊oop
如下代碼是從幾個部分抽取關鍵片斷合併而成this
typedef struct _KeywordFunc { char *name; /**關鍵字名,用於匹配*/ KeywordType type; /**內型,是個枚舉值*/ int expand_vars; /**是否要擴展*/ int default_policy_only;/**是否只能默認配置策略*/ ParseFunc parse_func; /**解析該關鍵字的回調函數*/ } KeywordFunc; static const KeywordFunc snort_conf_keywords[] = { /* Rule keywords */ { SNORT_CONF_KEYWORD__ACTIVATE, KEYWORD_TYPE__RULE, 0, 0, ParseActivate }, { SNORT_CONF_KEYWORD__ALERT, KEYWORD_TYPE__RULE, 0, 0, ParseAlert }, { SNORT_CONF_KEYWORD__DROP, KEYWORD_TYPE__RULE, 0, 0, ParseDrop }, { SNORT_CONF_KEYWORD__BLOCK, KEYWORD_TYPE__RULE, 0, 0, ParseDrop }, { SNORT_CONF_KEYWORD__DYNAMIC, KEYWORD_TYPE__RULE, 0, 0, ParseDynamic }, { SNORT_CONF_KEYWORD__LOG, KEYWORD_TYPE__RULE, 0, 0, ParseLog }, { SNORT_CONF_KEYWORD__PASS, KEYWORD_TYPE__RULE, 0, 0, ParsePass }, { SNORT_CONF_KEYWORD__REJECT, KEYWORD_TYPE__RULE, 0, 0, ParseReject }, { SNORT_CONF_KEYWORD__SDROP, KEYWORD_TYPE__RULE, 0, 0, ParseSdrop }, { SNORT_CONF_KEYWORD__SBLOCK, KEYWORD_TYPE__RULE, 0, 0, ParseSdrop }, ..../** 後面有更多條目*/ }; static void ParseConfigFile(SnortConfig *sc, SnortPolicy *p, char *fname) { /* Used for line continuation */ int continuation = 0; char *saved_line = NULL; char *new_line = NULL; char *buf = (char *)SnortAlloc(MAX_LINE_LENGTH + 1); FILE *fp = fopen(fname, "r"); /** 打開文件*/ /* open the rules file */ if (fp == NULL) /** 打開失敗輸出信息*/ { ParseError("Unable to open rules file \"%s\": %s.\n", fname, strerror(errno)); } /* loop thru each file line and send it to the rule parser */ while ((fgets(buf, MAX_LINE_LENGTH, fp)) != NULL) /* 一次分析一行*/ { /* buffer indexing pointer */ char *index = buf; /* Increment the line counter so the error messages know which * line to bitch about */ file_line++; /** 增長行計數*/ /* fgets always appends a null, so doing a strlen should be safe */ if ((strlen(buf) + 1) == MAX_LINE_LENGTH) /** 檢查讀入的數據大小*/ { ParseError("Line greater than or equal to %u characters which is " "more than the parser is willing to handle. Try " "splitting it up on multiple lines if possible.", MAX_LINE_LENGTH); } DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Got line %s (%d): %s\n", fname, file_line, buf);); /* advance through any whitespace at the beginning of the line */ /** 去掉頭部的空格*/ while (isspace((int)*index)) index++; /* If it's an empty line or starts with a comment character */ /** ’#‘ ,‘,’ 開頭以及空串都將跳過*/ if ((strlen(index) == 0) || (*index == '#') || (*index == ';')) continue; /**有換行標誌,標識前面還有部分應該也屬於該行*/ if (continuation) { int new_line_len = strlen(saved_line) + strlen(index) + 1; /**長度校驗*/ if (new_line_len >= PARSERULE_SIZE) { ParseError("Rule greater than or equal to %u characters which " "is more than the parser is willing to handle. " "Submit a bug to bugs@snort.org if you legitimately " "feel like your rule or keyword configuration needs " "more than this amount of space.", PARSERULE_SIZE); } /**兩行合併*/ new_line = (char *)SnortAlloc(new_line_len); snprintf(new_line, new_line_len, "%s%s", saved_line, index); free(saved_line); saved_line = NULL; index = new_line; DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"concat rule: %s\n", new_line);); } /* check for a '\' continuation character at the end of the line * if it's there we need to get the next line in the file */ if (ContinuationCheck(index) == 0) /**檢查是否有換行符*/ { char **toks; int num_toks; char *keyword; char *args; int i; DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "[*] Processing keyword: %s\n", index);); /* Get the keyword and args */ /*提取關鍵字和參數*/ toks = mSplit(index, " \t", 2, &num_toks, 0); if (num_toks != 2) ParseError("Invalid configuration line: %s", index); keyword = SnortStrdup(ExpandVars(sc, toks[0])); args = toks[1]; for (i = 0; snort_conf_keywords[i].name != NULL; i++) { /**遍歷全部可用的關鍵字,找到匹配的關鍵字條目*/ if (strcasecmp(keyword, snort_conf_keywords[i].name) == 0) { /**只能默認配置的條目不處理*/ if ((getParserPolicy(sc) != getDefaultPolicy()) && snort_conf_keywords[i].default_policy_only) { /* Keyword only configurable in the default policy*/ DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Config option \"%s\" configurable only by default policy. Ignoring it", toks[0])); break; } if (((snort_conf_keywords[i].type == KEYWORD_TYPE__RULE) && !parse_rules) || ((snort_conf_keywords[i].type == KEYWORD_TYPE__MAIN) && parse_rules)) { break; } /** 該條目須要進行擴展,先擴展內容, TODO 後續關注*/ if (snort_conf_keywords[i].expand_vars) args = SnortStrdup(ExpandVars(sc, toks[1])); /* Special parsing case is ruletype. * Need to send the file pointer so it can parse what's * between '{' and '}' which can span multiple lines * without a line continuation character */ /**rule type 比較特殊是用來自定義動做的, 參見snort配置手冊*/ if (strcasecmp(keyword, SNORT_CONF_KEYWORD__RULE_TYPE) == 0) _ParseRuleTypeDeclaration(sc, fp, args, parse_rules); else snort_conf_keywords[i].parse_func(sc, p, args); /**調用匹配的回調函數處理規則*/ break; } } /* Didn't find any pre-defined snort_conf_keywords. Look for a user defined * rule type */ /** 檢查是否預約義的關鍵字所有未命中,使用用戶定義的關鍵字, * 用戶定義的關鍵字來自上面的ruleType */ if ((snort_conf_keywords[i].name == NULL) && parse_rules) { RuleListNode *node; DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES, "Unknown rule type, " "might be declared\n");); for (node = sc->rule_lists; node != NULL; node = node->next) { if (strcasecmp(node->name, keyword) == 0) break; } if (node == NULL) ParseError("Unknown rule type: %s.", toks[0]); if ( node->mode == RULE_TYPE__DROP ) { if ( ScTreatDropAsAlert() ) ParseRule(sc, p, args, RULE_TYPE__ALERT, node->RuleList); else if ( ScKeepDropRules() || ScLoadAsDropRules() ) ParseRule(sc, p, args, node->mode, node->RuleList); } else if ( node->mode == RULE_TYPE__SDROP ) { if ( ScKeepDropRules() && !ScTreatDropAsAlert() ) ParseRule(sc, p, args, node->mode, node->RuleList); else if ( ScLoadAsDropRules() ) ParseRule(sc, p, args, RULE_TYPE__DROP, node->RuleList); } else { ParseRule(sc, p, args, node->mode, node->RuleList); } } if (args != toks[1]) free(args); free(keyword); mSplitFree(&toks, num_toks); if(new_line != NULL) { free(new_line); new_line = NULL; continuation = 0; } } else /** 趕上換行符*/ { /* save the current line */ saved_line = SnortStrdup(index); /**保持該行,得到一個副本*/ /* current line was a continuation itself... */ if (new_line != NULL) /**釋放讀取的行*/ { free(new_line); new_line = NULL; } /* set the flag to let us know the next line is * a continuation line */ continuation = 1; /**標記換行標誌*/ } } fclose(fp); /**關閉文件*/ free(buf); /**釋放緩衝區*/ } /** 換行符的檢查以及處理*/ static int ContinuationCheck(char *rule) { char *idx; /* indexing var for moving around on the string */ idx = rule + strlen(rule) - 1; /**指向串尾*/ DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"initial idx set to \'%c\'\n", *idx);); while(isspace((int)*idx)) /** 去掉尾部的空格*/ { idx--; } if(*idx == '\\') /** 遇到換行符, snort規則支持換行符*/ { DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Got continuation char, " "clearing char and returning 1\n");); /* clear the '\' so there isn't a problem on the appended string */ *idx = '\x0'; /** 清除換行, 替換爲空字符*/ return 1; } return 0; }
snort規則支持換行符spa
不只'#',使用 ';'做爲行頭任然能達到註釋該行的效果code
以動做來分類系統預約義的規則優先於用戶自定義的規則ip