Suricata之源代碼(二)

     在前面的代碼主要是運行模式的一些初始化工作。接下來Suricata中的代碼主要是完成對命令行的命令

    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}
    };
ConfInit()的主要工作是初始化配置文件系統,主要是聲明並初始化root,root = ConfNodeNew()。代碼中使用了struct option結構體。該結構體主要是映射段命令和長命令的關係以及後面是否一定要跟參數。
#define no_argument        0
#define required_argument  1
#define optional_argument  2

struct option {
   const char *name;
   int has_arg;
   int *flag;
   int val;
};

const char *name是不帶短橫線的選項名,前面沒有短橫線。譬如“help”、“verbose”之類。

int has_arg描述了選項是否有選項參數。如果有,是哪種類型的參數,此時,它的值一定是下表中的一個。符號常量數值含義

no_argument 

0 選項沒有參數
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中出現的這個選項的參數相同。

接下來就是對命令的解析工作:

 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;
代碼中使用了getopt_long()函數解析了來自命令行的參數。

我們要看的部分也就是NFQ,看看NFQ在解析的時候主要是做了什麼事情。

#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':

run_mode = RUNMODE_NFQ;//設置運行模式

SET_ENGINE_MODE_IPS(engine_mode);//設置爲IPS

解析完這部分的代碼之後可要對全局的數據進行初始化:

 /* Initializations for global vars, queues, etc (memsets, mutex init..) */
    GlobalInits();
    TimeInit();
    SupportFastPatternForSigMatchTypes();
  /* load the pattern matchers */
    MpmTableSetup();

 SupportFastPatternForSigMatchTypes();//這裏是比較重要的一個部分,主要是針對快速匹配的。快速匹配的規則在rule中的體現是標記爲fast的。這個在後面講。反正這裏就是對各種快速匹配鏈表進行初始化

MpmTableSetup();//主要是對各種匹配算法進行註冊。也即裝載模式匹配

SupportFastPatternForSigMatchTypes函數的主要功能如下:

/**
 * \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;
}
MpmTableSetup函數功能主要是:
void MpmTableSetup(void) {
    memset(mpm_table, 0, sizeof(mpm_table));

    MpmWuManberRegister();
    MpmB2gRegister();
#ifdef __SC_CUDA_SUPPORT__
    MpmB2gCudaRegister();
#endif
    MpmB3gRegister();
    MpmB2gcRegister();
    MpmB2gmRegister();
    MpmACRegister();
    MpmACBSRegister();
    MpmACGfbsRegister();
}
接下來的工作就是對yaml文件的加載以及解析工作,這個我會在下個博客給出一定的分析,希望能夠達到拋磚引玉的功能。希望對看開源Suricata源代碼的人有一定的幫助。


發佈了28 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章