/*
* 基于snort-2.9.5的源码进行分析
* src/preprocessors/str_search.h|.c
*/
/*
* t_search 结构用于管理SearchAPI对象
*/
typedef struct tag_search
{
/*
* mpse 由mpseNew函数创建
*/
void *mpse;
/*
* 所有模式串中最长串的长度
*/
unsigned int max_len;
/*
* 该引擎在创建时就默认设置为1
*/
int in_use;
} t_search;
typedef struct _search_api
{
int (*search_init)(unsigned int);
int (*search_reinit)(unsigned int);
void (*search_free)(void);
void (*search_add)(unsigned int, const char *, unsigned int, int);
void (*search_prep)(unsigned int);
int (*search_find)(unsigned int, const char *, unsigned int, int, MatchFunction);
/* 6/1/06*/
void (*search_free_id)(unsigned id);
int (*search_get_handle)(void);
int (*search_put_handle)(unsigned int);
/*
* 创建多模式匹配引擎接口函数
*/
void * (*search_instance_new)(void);
/*
* 释放多模式匹配引擎接口函数
*/
void (*search_instance_free)(void * instance);
/*
* 增加模式串接口函数
*/
void (*search_instance_add) (void * instance, const char *s, unsigned int s_len, int s_id);
/*
* 模式串预处理接口函数 :比如 创建trie 和构建自动机
*/
void (*search_instance_prep)(void * instance );
/*
* 匹配函数 :MatchFunction:匹配成功后的回调函数,可执行一些相关操作
*/
int (*search_instance_find)(void * instance, const char *s, unsigned int s_len, int confine, MatchFunction);
} SearchAPI;
/* API exported by this module */
SearchAPI searchAPI =
{
SearchInit,
SearchReInit,
SearchFree,
SearchAdd,
SearchPrepPatterns,
SearchFindString,
SearchFreeId,
SearchGetHandle,
SearchPutHandle,
/*
* 创建引擎的函数
*/
SearchInstanceNew,
/*
* 释放引擎的函数
*/
SearchInstanceFree,
/*
* 增加模式串函数
*/
SearchInstanceAdd,
/*
* 引擎预处理函数:构建trie 自动机
*/
SearchInstancePrepPatterns,
/*
* 搜索函数
*/
SearchInstanceFindString,
};
SearchAPI *search_api = &searchAPI;
接下来分析上面提及的那几个函数的实现
1:创建对象
/*
* 创建mpse管理对象和mpse对象
*/
void * SearchInstanceNew(void)
{
/* 创建管理对象 */
t_search * search = malloc(sizeof(t_search));
if( !search )
return NULL;
/* 创建mpse对象, 通过MPSE_AC_BNFA宏设置,多模式匹配使用的算法*/
search->mpse = mpseNew(MPSE_AC_BNFA, MPSE_DONT_INCREMENT_GLOBAL_COUNT,
NULL, NULL, NULL);
if (search-> mpse == NULL )
{
free(search);
return NULL;
}
search->in_use=1;
search->max_len=0;
return search;
}
2:释放对象
void SearchInstanceFree( void * instance )
{
t_search * search = (t_search*)instance;
if( instance )
{
mpseFree( search->mpse );
free( instance );
}
}
3:增加模式串
/*
* instance : 管理对象
* pat : 模式串
* pat_len : 模式串长度
* id : 模式串所在模式串数组中的索引,例如 html_patterns
*/
void SearchInstanceAdd( void*instance, const char *pat, unsigned int pat_len, int id)
{
t_search * search = (t_search*)instance;
/* 添加模式串至mpse引擎中*/
if( search && search->mpse )
mpseAddPattern( search->mpse, (void *)pat, pat_len, 1, 0, 0, 0, (void *)(long) id, 0);
/* 更新模式串的最大长度*/
if ( search && pat_len > search->max_len )
search->max_len = pat_len;
}
4:预处理模式串(生成自动机)
/*
* instance : 管理对象
*/
void SearchInstancePrepPatterns(void * instance)
{
t_search * search = (t_search*)instance;
if( search && search->mpse )
{
/* 在调用完SearchInstanceAdd后,调用本函数进行模式预处理编译*/
mpsePrepPatterns( search->mpse, NULL, NULL);
}
}
5:搜索查找
/*
* 搜索函数
* instance : 管理对象
* str :源串
* str_len : 源串长度
* confine : 1 表示更新模式串的最大长度
* Match : 匹配成功后的回调函数
*/
int SearchInstanceFindString(void * instance,
const char *str,
unsigned int str_len,
int confine,
int (*Match) (void *, void *, int, void *, void *))
{
int num;
int start_state = 0;
t_search * search = (t_search*)instance;
if ( confine && (search->max_len > 0) )
{
if ( search->max_len < str_len )
{
str_len = search->max_len;
}
}
num = mpseSearch( search->mpse, (unsigned char*)str, str_len, Match, (void *) str,
&start_state);
return num;
}
以上介绍了模式匹配引擎接口的几个关键函数。接下来结合snort源代码分析如何使用这些接口
以html_patterns为例进行分析:
/*
* 结构定义
*/
typedef struct _HiSearchToken
{
/* 模式串*/
char *name;
/* 串长度*/
int name_len;
/* 串所在数组中的索引*/
int search_id;
} HiSearchToken;
a:创建管理对象,并添加串数组,编译
/* 管理对象*/
void *hi_htmltype_search_mpse = NULL;
...
void HI_SearchInit(void)
{
...
/* 创建 管理对象 实际调用SearchInstanceNew*/
hi_htmltype_search_mpse = search_api->search_instance_new();
if (hi_htmltype_search_mpse == NULL)
{
FatalError("%s(%d) Could not allocate memory for HTTP <script> type search.\n",
__FILE__, __LINE__);
}
/* 循环添加串 */
for (tmp = &html_patterns[0]; tmp->name != NULL; tmp++)
{
hi_html_search[tmp->search_id].name = tmp->name;
hi_html_search[tmp->search_id].name_len = tmp->name_len;
/* 添加串至 管理对象中*/
search_api->search_instance_add(hi_htmltype_search_mpse, tmp->name, tmp->name_len, tmp->search_id);
}
/* 编译 html_patterns串 所有初始化工作完成*/
search_api->search_instance_prep(hi_htmltype_search_mpse);
}
b:搜索
int hi_server_norm(HI_SESSION *Session, HttpSessionData *hsd)
{
...
/* 查找过程, 如果成功调用HI_SearchStrFound 善后处理*/
script_found = search_api->search_instance_find(hi_htmltype_search_mpse, (const char *)js_start, (angle_bracket-js_start), 0 , HI_SearchStrFound);
...
}
/* 返回1 表示 搜索成功*/
int HI_SearchStrFound(void *id, void *unused, int index, void *data, void *unused2)
{
int search_id = (int)(uintptr_t)id;
hi_search_info.id = search_id;
hi_search_info.index = index;
hi_search_info.length = hi_current_search[search_id].name_len;
/* Returning non-zero stops search, which is okay since we only look for one at a time */
return 1;
}
以上就分析完了snort的模式匹配引擎接口的使用
可以参考https://github.com/testwill/Multi-pattern-matching-engine中的mpse_test.c进行编写自己的测试程序进行使用