snort的规则文件系统中包含很多配置,其中一些配置依赖于其他的配置项,使得snort规则解析分为两步,第一步解析配置的变量。
例如ipvar HOME_NET any 这是一个ip变量的设置,关键字ipvar 、HOME_NET :变量名、any :变量值;定义完之后,就可以在规则中使用,例如
alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"APP-DETECT Acunetix web vulnerability scan attempt"; flow:to_server,established; flowbits:set,acunetix-scan; content:"Acunetix-"; fast_pattern:only; http_header; metadata:service http; reference:url,www.acunetix.com; classtype:web-application-attack; sid:25358; rev:3;)
其中的红色部分就是使用的方式,在变量名中需要加上$。
下面以源码的形式进行分析解析变量的动作,snort中每个变量的关键字一般会在parser.h中以宏的方式定义,例如:
# define SNORT_CONF_KEYWORD__IPVAR "ipvar"
该关键字对应的解析函数会放置在一个叫snort_conf_keywords的数组中,在解析配置文件的时候,会遍历这个数组进行解析
typedef struct _KeywordFunc
{
char *name;/* 关键字 例如 ipvar*/
KeywordType type; /* 类型:规则配置、主配置、 所有*/
int expand_vars; /* */
int default_policy_only;
ParseFunc parse_func; /* 配置的解析函数类型*/
} KeywordFunc;
static const KeywordFunc snort_conf_keywords[] =
{
...
{ SNORT_CONF_KEYWORD__IPVAR, KEYWORD_TYPE__MAIN, 0, 0, ParseIpVar },
...
};
下面是解析ipvar的函数实现
/*
* sc : snort的配置对象
* p : snort 的策略,实际内容保存它的ip_vartable属性中
* args : 配置项内容(除关键字)
*/
static void ParseIpVar(SnortConfig *sc, SnortPolicy *p, char *args)
{
char **toks;
int num_toks;
int ret;
...
/* 通过上面的例子可以知道 ipvar的配置只有两项,所以如果切分的结果不等于二,说明有问题,报错退出程序,并在日志文件或者终端,显示错信息,具体到配置文件的名字和行号,方便调试*/
toks = mSplit(args, " \t", 0, &num_toks, 0);
if (num_toks != 2)
{
ParseError("Missing argument to %s", toks[0]);
}
/* Check command line variables to see if this has already
* been defined */
/* 检查命令行中是否已经定义该变量,如果已定义,抛弃配置文件的定义*/
if (cmd_line_var_list != NULL)
{
VarNode *tmp = cmd_line_var_list;
while (tmp != NULL)
{
/* Already defined this via command line */
if (strcasecmp(toks[0], tmp->name) == 0)
{
mSplitFree(&toks, num_toks);
return;
}
tmp = tmp->next;
}
}
DisallowCrossTableDuplicateVars(sc, toks[0], VAR_TYPE__IPVAR);
/* 检查是否定义过该变量,如果定义过,或者语法错误,报错退出,如果未定义,将该变量保存到策略p->ip_vartable属性的链表中*/
if((ret = sfvt_define(p->ip_vartable, toks[0], toks[1])) != SFIP_SUCCESS)
{
switch(ret) {
case SFIP_ARG_ERR:
ParseError("The following is not allowed: %s.", toks[1]);
break;
case SFIP_DUPLICATE:
ParseMessage("Var '%s' redefined.", toks[0]);
break;
case SFIP_CONFLICT:
ParseError("Negated IP ranges that are more general than "
"non-negated ranges are not allowed. Consider "
"inverting the logic in %s.", toks[0]);
break;
case SFIP_NOT_ANY:
ParseError("!any is not allowed in %s.", toks[0]);
break;
default:
ParseError("Failed to parse the IP address: %s.", toks[1]);
}
}
mSplitFree(&toks, num_toks);
}
这样ipvar的解析就算完成了。
接下来看一下规则中怎么使用的
/* 解析规则时,使用ProcessIP解析IP字段 */
static void ParseRule(SnortConfig *sc, SnortPolicy *p, char *args,
RuleType rule_type, ListHead *list)
{
...
ProcessIP(sc, toks[4], &test_rtn, DST, 0);
}
/* 在这个里面使用sfvt_lookup_var查询addr这个变量是否在ip_vartable是否存在,如果存在,规则头rtn->sip对变量内容进行深拷贝, 不存在,进行解析,并加入变量链表*/
static int ProcessIP(SnortConfig *sc, char *addr, RuleTreeNode *rtn, int mode, int neg_list)
{
vartable_t *ip_vartable = sc->targeted_policies[getParserPolicy(sc)]->ip_vartable;
...
if(mode == SRC)
{
int ret;
if (rtn->sip == NULL)
{
sfip_var_t *tmp = sfvt_lookup_var(ip_vartable, addr);
if (tmp != NULL)
{
rtn->sip = sfvar_create_alias(tmp, tmp->name);
if (rtn->sip == NULL)
ret = SFIP_FAILURE;
else
ret = SFIP_SUCCESS;
}
else
{
rtn->sip = (sfip_var_t *)SnortAlloc(sizeof(sfip_var_t));
ret = sfvt_add_to_var(ip_vartable, rtn->sip, addr);
}
}
...
}
/* mode == DST */
else
{
...
}
...
return 0;
}