snort中的规则解析框架(⼀)简介
snort中较重要的⼀个环节就是配置⽂件的读取。以snort-2.9.6.0为⽰例
该过程完成以下⼏件事
1. 确定被加载的模块,并能为部分模块获得需要的配置参数
2. 获取构建匹配结构需要的数据
规则⽂件范例
内容较多,可以下载snort 配置⼿册
代码分析
以下代码是从⼏个部分抽取关键⽚段合并⽽成
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 */
/* 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 "
error parse new"is more than the parser is willing to handle. "
"Submit a bug to 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;
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, "
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 */
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); /**关闭⽂件*/
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;
}
总结
1. snort规则⽀持换⾏符
2. 不仅'#',使⽤ ';'作为⾏头任然能达到注释该⾏的效果
3. 以动作来分类系统预定义的规则优先于⽤户⾃定义的规则
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论