您的位置:首页 > 编程语言

Suricata之源代码(一)

2016-03-08 11:45 246 查看
第一次系统性的写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)创建线程。

如有错误请告诉我。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: