在前面的代码主要是运行模式的一些初始化工作。接下来Suricata中的代码主要是完成对命令行的命令
0 选项没有参数
- <span style="font-size:18px;"> ConfInit();
- struct option long_opts[] = {
- {"dump-config", 0, &dump_config, 1},
- {"pfring", optional_argument, 0, 0},
- {"pfring-int", required_argument, 0, 0},
- {"pfring-cluster-id", required_argument, 0, 0},
- {"pfring-cluster-type", required_argument, 0, 0},
- {"af-packet", optional_argument, 0, 0},
- {"pcap", optional_argument, 0, 0},
- #ifdef BUILD_UNIX_SOCKET
- {"unix-socket", optional_argument, 0, 0},
- #endif
- {"pcap-buffer-size", required_argument, 0, 0},
- {"unittest-filter", required_argument, 0, 'U'},
- {"list-app-layer-protos", 0, &list_app_layer_protocols, 1},
- {"list-unittests", 0, &list_unittests, 1},
- {"list-cuda-cards", 0, &list_cuda_cards, 1},
- {"list-runmodes", 0, &list_runmodes, 1},
- {"list-keywords", optional_argument, &list_keywords, 1},
- {"runmode", required_argument, NULL, 0},
- {"engine-analysis", 0, &engine_analysis, 1},
- #ifdef OS_WIN32
- {"service-install", 0, 0, 0},
- {"service-remove", 0, 0, 0},
- {"service-change-params", 0, 0, 0},
- #endif /* OS_WIN32 */
- {"pidfile", required_argument, 0, 0},
- {"init-errors-fatal", 0, 0, 0},
- {"fatal-unittests", 0, 0, 0},
- {"user", required_argument, 0, 0},
- {"group", required_argument, 0, 0},
- {"erf-in", required_argument, 0, 0},
- {"dag", required_argument, 0, 0},
- {"napatech", 0, 0, 0},
- {"build-info", 0, &build_info, 1},
- {NULL, 0, NULL, 0}
- };
- </span>
<span style="font-size:18px;"> ConfInit();
struct option long_opts[] = {
{"dump-config", 0, &dump_config, 1},
{"pfring", optional_argument, 0, 0},
{"pfring-int", required_argument, 0, 0},
{"pfring-cluster-id", required_argument, 0, 0},
{"pfring-cluster-type", required_argument, 0, 0},
{"af-packet", optional_argument, 0, 0},
{"pcap", optional_argument, 0, 0},
#ifdef BUILD_UNIX_SOCKET
{"unix-socket", optional_argument, 0, 0},
#endif
{"pcap-buffer-size", required_argument, 0, 0},
{"unittest-filter", required_argument, 0, 'U'},
{"list-app-layer-protos", 0, &list_app_layer_protocols, 1},
{"list-unittests", 0, &list_unittests, 1},
{"list-cuda-cards", 0, &list_cuda_cards, 1},
{"list-runmodes", 0, &list_runmodes, 1},
{"list-keywords", optional_argument, &list_keywords, 1},
{"runmode", required_argument, NULL, 0},
{"engine-analysis", 0, &engine_analysis, 1},
#ifdef OS_WIN32
{"service-install", 0, 0, 0},
{"service-remove", 0, 0, 0},
{"service-change-params", 0, 0, 0},
#endif /* OS_WIN32 */
{"pidfile", required_argument, 0, 0},
{"init-errors-fatal", 0, 0, 0},
{"fatal-unittests", 0, 0, 0},
{"user", required_argument, 0, 0},
{"group", required_argument, 0, 0},
{"erf-in", required_argument, 0, 0},
{"dag", required_argument, 0, 0},
{"napatech", 0, 0, 0},
{"build-info", 0, &build_info, 1},
{NULL, 0, NULL, 0}
};
</span>
ConfInit()的主要工作是初始化配置文件系统,主要是声明并初始化root,root = ConfNodeNew()。代码中使用了struct option结构体。该结构体主要是映射段命令和长命令的关系以及后面是否一定要跟参数。
- <span style="font-size:18px;">#define no_argument 0
- #define required_argument 1
- #define optional_argument 2
- struct option {
- const char *name;
- int has_arg;
- int *flag;
- int val;
- };</span>
<span style="font-size:18px;">#define no_argument 0
#define required_argument 1
#define optional_argument 2
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};</span>
const char *name是不带短横线的选项名,前面没有短横线。譬如“help”、“verbose”之类。
int has_arg描述了选项是否有选项参数。如果有,是哪种类型的参数,此时,它的值一定是下表中的一个。符号常量数值含义
no_argument
required_argument
1 选项需要参数
optional_argument
2 选项参数可选
int *flag
如果这个指针为NULL,那么getopt_long()返回该结构val字段中的数值。如果该指针不为NULL,getopt_long()会使得它所指向的变量中填入val字段中的数值,并且getopt_long()返回0。如果flag不是NULL,但未发现长选项,那么它所指向的变量的数值不变。
int val 这个值是发现了长选项时的返回值,或者flag不是NULL时载入*flag中的值。典型情况下,若flag不是NULL,那么val是个真/假值,譬如1或0;另一方面,如果flag是NULL,那么val通常是字符常量,若长选项与短选项一致,那么该字符常量应该与optstring中出现的这个选项的参数相同。
接下来就是对命令的解析工作:
- <span style="font-size:18px;"> int option_index = 0;
- char short_opts[] = "c:TDhi:l:q:d:r:us:S:U:VF:";
- while ((opt = getopt_long(argc, argv, short_opts, long_opts, &option_index)) != -1) {
- switch (opt) {
- case 0:
- if (strcmp((long_opts[option_index]).name , "pfring") == 0 ||
- strcmp((long_opts[option_index]).name , "pfring-int") == 0) {
- #ifdef HAVE_PFRING
- run_mode = RUNMODE_PFRING;</span>
<span style="font-size:18px;"> int option_index = 0;
char short_opts[] = "c:TDhi:l:q:d:r:us:S:U:VF:";
while ((opt = getopt_long(argc, argv, short_opts, long_opts, &option_index)) != -1) {
switch (opt) {
case 0:
if (strcmp((long_opts[option_index]).name , "pfring") == 0 ||
strcmp((long_opts[option_index]).name , "pfring-int") == 0) {
#ifdef HAVE_PFRING
run_mode = RUNMODE_PFRING;</span>
代码中使用了getopt_long()函数解析了来自命令行的参数。
我们要看的部分也就是NFQ,看看NFQ在解析的时候主要是做了什么事情。
- <span style="font-size:18px;">#ifdef NFQ
- if (run_mode == RUNMODE_UNKNOWN) {
- run_mode = RUNMODE_NFQ;
- SET_ENGINE_MODE_IPS(engine_mode);
- if (NFQRegisterQueue(optarg) == -1)
- exit(EXIT_FAILURE);
- } else if (run_mode == RUNMODE_NFQ) {
- if (NFQRegisterQueue(optarg) == -1)
- exit(EXIT_FAILURE);
- } else {
- SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode "
- "has been specified");
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- #else
- SCLogError(SC_ERR_NFQ_NOSUPPORT,"NFQUEUE not enabled. Make sure to pass --enable-nfqueue to configure when building.");
- exit(EXIT_FAILURE);
- #endif /* NFQ */
- break;
- case 'd':</span>
<span style="font-size:18px;">#ifdef NFQ
if (run_mode == RUNMODE_UNKNOWN) {
run_mode = RUNMODE_NFQ;
SET_ENGINE_MODE_IPS(engine_mode);
if (NFQRegisterQueue(optarg) == -1)
exit(EXIT_FAILURE);
} else if (run_mode == RUNMODE_NFQ) {
if (NFQRegisterQueue(optarg) == -1)
exit(EXIT_FAILURE);
} else {
SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode "
"has been specified");
usage(argv[0]);
exit(EXIT_FAILURE);
}
#else
SCLogError(SC_ERR_NFQ_NOSUPPORT,"NFQUEUE not enabled. Make sure to pass --enable-nfqueue to configure when building.");
exit(EXIT_FAILURE);
#endif /* NFQ */
break;
case 'd':</span>
run_mode = RUNMODE_NFQ;//设置运行模式
SET_ENGINE_MODE_IPS(engine_mode);//设置为IPS
解析完这部分的代码之后可要对全局的数据进行初始化:
- <span style="font-size:18px;"> /* Initializations for global vars, queues, etc (memsets, mutex init..) */
- GlobalInits();
- TimeInit();
- SupportFastPatternForSigMatchTypes();<span style="font-family:Microsoft YaHei;">
- </span> /* load the pattern matchers */
- MpmTableSetup();</span>
<span style="font-size:18px;"> /* Initializations for global vars, queues, etc (memsets, mutex init..) */
GlobalInits();
TimeInit();
SupportFastPatternForSigMatchTypes();<span style="font-family:Microsoft YaHei;">
</span> /* load the pattern matchers */
MpmTableSetup();</span>
SupportFastPatternForSigMatchTypes();//这里是比较重要的一个部分,主要是针对快速匹配的。快速匹配的规则在rule中的体现是标记为fast的。这个在后面讲。反正这里就是对各种快速匹配链表进行初始化
MpmTableSetup();//主要是对各种匹配算法进行注册。也即装载模式匹配
SupportFastPatternForSigMatchTypes函数的主要功能如下:
- <span style="font-size:18px;">/**
- * \brief Registers the keywords(SMs) that should be given fp support.
- */
- void SupportFastPatternForSigMatchTypes(void)
- {
- SupportFastPatternForSigMatchList(DETECT_SM_LIST_PMATCH);
- SupportFastPatternForSigMatchList(DETECT_SM_LIST_UMATCH);
- SupportFastPatternForSigMatchList(DETECT_SM_LIST_HCBDMATCH);
- SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSBDMATCH);
- SupportFastPatternForSigMatchList(DETECT_SM_LIST_HHDMATCH);
- SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRHDMATCH);
- SupportFastPatternForSigMatchList(DETECT_SM_LIST_HMDMATCH);
- SupportFastPatternForSigMatchList(DETECT_SM_LIST_HCDMATCH);
- SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRUDMATCH);
- SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSMDMATCH);
- SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSCDMATCH);
- SupportFastPatternForSigMatchList(DETECT_SM_LIST_HUADMATCH);
- SupportFastPatternForSigMatchList(DETECT_SM_LIST_HHHDMATCH);
- SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRHHDMATCH);
- return;
- }
- </span>
<span style="font-size:18px;">/**
* \brief Registers the keywords(SMs) that should be given fp support.
*/
void SupportFastPatternForSigMatchTypes(void)
{
SupportFastPatternForSigMatchList(DETECT_SM_LIST_PMATCH);
SupportFastPatternForSigMatchList(DETECT_SM_LIST_UMATCH);
SupportFastPatternForSigMatchList(DETECT_SM_LIST_HCBDMATCH);
SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSBDMATCH);
SupportFastPatternForSigMatchList(DETECT_SM_LIST_HHDMATCH);
SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRHDMATCH);
SupportFastPatternForSigMatchList(DETECT_SM_LIST_HMDMATCH);
SupportFastPatternForSigMatchList(DETECT_SM_LIST_HCDMATCH);
SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRUDMATCH);
SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSMDMATCH);
SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSCDMATCH);
SupportFastPatternForSigMatchList(DETECT_SM_LIST_HUADMATCH);
SupportFastPatternForSigMatchList(DETECT_SM_LIST_HHHDMATCH);
SupportFastPatternForSigMatchList(DETECT_SM_LIST_HRHHDMATCH);
return;
}
</span>
MpmTableSetup函数功能主要是:
- <span style="font-size:18px;">void MpmTableSetup(void) {
- memset(mpm_table, 0, sizeof(mpm_table));
- MpmWuManberRegister();
- MpmB2gRegister();
- #ifdef __SC_CUDA_SUPPORT__
- MpmB2gCudaRegister();
- #endif
- MpmB3gRegister();
- MpmB2gcRegister();
- MpmB2gmRegister();
- MpmACRegister();
- MpmACBSRegister();
- MpmACGfbsRegister();
- }</span>
<span style="font-size:18px;">void MpmTableSetup(void) {
memset(mpm_table, 0, sizeof(mpm_table));
MpmWuManberRegister();
MpmB2gRegister();
#ifdef __SC_CUDA_SUPPORT__
MpmB2gCudaRegister();
#endif
MpmB3gRegister();
MpmB2gcRegister();
MpmB2gmRegister();
MpmACRegister();
MpmACBSRegister();
MpmACGfbsRegister();
}</span>
接下来的工作就是对yaml文件的加载以及解析工作,这个我会在下个博客给出一定的分析,希望能够达到抛砖引玉的功能。希望对看开源Suricata源代码的人有一定的帮助。