Suricata之源代码(一)

第一次系统性的写blog,写的不好,请大家多多包涵。

        在介绍Suricata源代码之前,大致介绍一下Suricata的工作流程。在suricata中主要使用了回调函数将所有的模块连接起来的。最后是通过DetectEngineCtx *global_de_ctx这个结构体启动起来的。整个的启动过程我用鞭炮来进行比喻,回调函数就好像鞭炮的引线一样,将所有的小的鞭炮连接起来,连接起来之后如果要放鞭炮就的要使用火柴将引线点燃。所以我将global_de_ctx比喻为火柴。在suricata中也是这样,最后通过global_de_ctx将suricata运行起来的。就好比是global_de_ctx打通了suricata的任督二脉。

DetectEngineCtx结构体在detect.h中。

typedef structDetectEngineCtx_ {

    uint8_t flags;

    int failure_fatal;

 

    Signature *sig_list;

    uint32_t sig_cnt;

 

    /* version of the srep data */

    uint32_t srep_version;

 

    Signature **sig_array;

    uint32_t sig_array_size; /* size in bytes*/

    uint32_t sig_array_len;  /* size in array members */

 

    uint32_t signum;

 

    /* used by the signature ordering module */

    struct SCSigOrderFunc_ *sc_sig_order_funcs;

    struct SCSigSignatureWrapper_*sc_sig_sig_wrapper;

 

    /*hash table used for holding the classification config info */

    HashTable *class_conf_ht;

    /* hash table used for holding thereference config info */

    HashTable *reference_conf_ht;

 

    /* main sigs */

    DetectEngineLookupFlowflow_gh[FLOW_STATES];

 

    uint32_t mpm_unique, mpm_reuse, mpm_none,

        mpm_uri_unique, mpm_uri_reuse,mpm_uri_none;

    uint32_t gh_unique, gh_reuse;

 

    uint32_t mpm_max_patcnt, mpm_min_patcnt,mpm_tot_patcnt,

        mpm_uri_max_patcnt, mpm_uri_min_patcnt,mpm_uri_tot_patcnt;

 

    /* init phase vars */

    HashListTable *sgh_hash_table;

 

    …….

}DetectEngineCtx;

下面还有很长没有贴出来,这个结构体非常的大。想想它确实是应该这么大的。毕竟它就是suricata的心脏嘛!

Suricata是c语言开发的,而c语言的起始点是从main()函数开始的,为了好找到入口点,所以在写代码的时候就规定了从main函数开始。而suricata的入口main函数是在suricata.c文件中。

int main(intargc, char **argv)

{

    int opt;

    char pcap_dev[128];

    char *sig_file = NULL;

    int sig_file_exclusive = FALSE;

    int conf_test = 0;

    char *pid_filename = NULL;

#ifdef UNITTESTS

    char *regex_arg = NULL;

#endif

…….

Suricata中的main函数接下来所做的事情是:

/* initializethe logging subsys */

    SCLogInitLogModule(NULL);//初始化日志系统

 

    if(SCSetThreadName("Suricata-Main") < 0) {//给主线程设置线程名称

        SCLogWarning(SC_ERR_THREAD_INIT,"Unable to set thread name");

    }

 

    RunModeRegisterRunModes();//设置运行模式

 

    /* By default use IDS mode, but if nfq oripfw

     * are specified, IPS mode will overwritethis */

    SET_ENGINE_MODE_IDS(engine_mode);//suricata默认情况下是运行IDS模式。而在RunModeRegisterRunModes()函数中,主要是在引擎中注册所有的运行模式。函数所在位置是在runmodes.c中。

/**

 * \brief Register all runmodes in the engine.

 */

voidRunModeRegisterRunModes(void)

{

    memset(runmodes, 0, sizeof(runmodes));

 

    RunModeIdsPcapRegister();

    RunModeFilePcapRegister();

    RunModeIdsPfringRegister();

    RunModeIpsNFQRegister();

    RunModeIpsIPFWRegister();

    RunModeErfFileRegister();

    RunModeErfDagRegister();

    RunModeNapatechRegister();

    RunModeIdsAFPRegister();

    RunModeUnixSocketRegister();

#ifdef UNITTESTS

    UtRunModeRegister();

#endif

    return;

}

其中我主要说RunModeIpsNFQRegister函数,因为这个模式下实现了IPS的功能。其中这个函数又是做了哪些事情呢?

voidRunModeIpsNFQRegister(void)

 57 {

 58    default_mode = "autofp";

 59    RunModeRegisterNewRunMode(RUNMODE_NFQ, "auto",                  

 60                               "Multithreaded NFQ IPS mode",        

 61                              RunModeIpsNFQAuto);

 62

 63    RunModeRegisterNewRunMode(RUNMODE_NFQ, "autofp",                

 64                               "Multithreaded NFQ IPS mode with respect to flow",

 65                              RunModeIpsNFQAutoFp);

 66

 67    RunModeRegisterNewRunMode(RUNMODE_NFQ, "workers",               

 68                               "Multiqueue NFQ IPS mode with one thread per queue",

 69                              RunModeIpsNFQWorker);                                                                                              

 70    return;

 71 }

里面注册了3个回调函数,这个3个回调函数主要针对的是auto模式、autofp模式和workers模式。

其中我要说的是workers模式下的情况,而在RunModeIpsNFQWorker(这个函数在runmode-nfq.c)这个函数中主要调用了函数RunModeSetIPSWorker。

ret =RunModeSetIPSWorker(de_ctx,

142             NFQGetThread,

143             "ReceiveNFQ",

144             "VerdictNFQ",

145             "DecodeNFQ");

在RunModeSetIPSWorker中就完成将所有的模块连接起来。包括了ReceiveNFQ模块(主要进行数据包的接受)、Decode模块(主要是对数据包的协议进行分析)、StreamTcp模块(主要是将对应的数据包组成stream的形式)、Detect模块(主要是使用DetectEngineCtx里面的特征对数据进行匹配)、Verdict模块以及RespondReject模块。


代码实现是:

int RunModeSetIPSWorker(DetectEngineCtx *de_ctx,

1150        ConfigIPSParserFunc ConfigParser,

1151         char*recv_mod_name,

1152         char*verdict_mod_name,

1153         char*decode_mod_name)

1154 {

1155     char tname[16];

1156     ThreadVars *tv =NULL;

1157     TmModule *tm_module =NULL;

1158     char *cur_queue =NULL;

1159

1160     int nqueue =LiveGetDeviceCount();

1161

1162     for (int i = 0; i< nqueue; i++) {

1163         /* create thethreads */

1164         cur_queue =LiveGetDeviceName(i);

1165         if (cur_queue ==NULL) {

1166            printf("ERROR: Invalid queue number\n");

1167            exit(EXIT_FAILURE);

1168         }

1169         memset(tname, 0,sizeof(tname));

1170         snprintf(tname,sizeof(tname), "Worker-Q%s", cur_queue);

1171

1172         char *thread_name= SCStrdup(tname);

1173         if(unlikely(thread_name == NULL)) {

1174            SCLogError(SC_ERR_RUNMODE, "Error allocating memory");

1175            exit(EXIT_FAILURE);

1176         }

1177         tv =TmThreadCreatePacketHandler(thread_name,

1178                "packetpool", "packetpool",

1179                "packetpool", "packetpool",

1180                "pktacqloop");

1181         if (tv == NULL) {

SCLogError(SC_ERR_THREAD_CREATE, "TmThreadsCreatefailed");

1183            exit(EXIT_FAILURE);

1184         }

1185

1186         tm_module =TmModuleGetByName(recv_mod_name);

1187         if (tm_module ==NULL) {

1188            SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName failed for%s", recv_mod_name);

1189            exit(EXIT_FAILURE);

1190         }

1191        TmSlotSetFuncAppend(tv, tm_module, (void *) ConfigParser(i));

1192

1193         tm_module =TmModuleGetByName(decode_mod_name);

1194         if (tm_module ==NULL) {

1195            SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName %sfailed", decode_mod_name);

1196            exit(EXIT_FAILURE);

1197         }

1198         TmSlotSetFuncAppend(tv,tm_module, NULL);

1199

1200         tm_module =TmModuleGetByName("StreamTcp");

1201         if (tm_module ==NULL) {

1202            SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcpfailed");

1203            exit(EXIT_FAILURE);

1204         }

1205        TmSlotSetFuncAppend(tv, tm_module, NULL);

1206

1207         tm_module =TmModuleGetByName("Detect");

1208         if (tm_module ==NULL) {

1209            SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed");

1210             exit(EXIT_FAILURE);

1211         }

1212        TmSlotSetFuncAppendDelayed(tv, tm_module,

1213                                    (void*)de_ctx, de_ctx->delayed_detect);

1214

1215         tm_module =TmModuleGetByName(verdict_mod_name);

1216         if (tm_module ==NULL) {

1217            SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName %s failed",verdict_mod_name);

                  exit(EXIT_FAILURE);

1219         }

1220

1221        TmSlotSetFuncAppend(tv, tm_module, (void *)de_ctx);

1222

1223         tm_module =TmModuleGetByName("RespondReject");

1224         if (tm_module ==NULL) {

1225            printf("ERROR: TmModuleGetByName for RespondReject failed\n");

1226            exit(EXIT_FAILURE);

1227         }

1228         TmSlotSetFuncAppend(tv,tm_module, NULL);

1229

1230         SetupOutputs(tv);

1231

1232        TmThreadSetCPU(tv, DETECT_CPU_SET);

1233

1234         if(TmThreadSpawn(tv) != TM_ECODE_OK) {

1235            SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed");

1236            exit(EXIT_FAILURE);

1237         }

1238     }

1239

1240     return 0;

1241 }

最后通过函数TmThreadSpawn(tv)创建线程。

如有错误请告诉我。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值