main:注册运行模式(添加到全局的运行模式数组runmodes中)
RunModeRegisterRunModes();
--------------------------
RunModeIdsPcapRegister();
{
RunModeRegisterNewRunMode(RUNMODE_PCAP_DEV, "workers",
"Workers pcap live mode, each thread does all"
" tasks from acquisition to logging",
RunModeIdsPcapWorkers);
}
--------------------------
void RunModeRegisterNewRunMode(int runmode, const char *name,
const char *description,
int (*RunModeFunc)(DetectEngineCtx *))
{
// 添加到全局的runmodes中
RunMode *mode = &runmodes[runmode].runmodes[runmodes[runmode].no_of_runmodes];
runmodes[runmode].no_of_runmodes++;
mode->runmode = runmode;
mode->name = SCStrdup(name);
mode->description = SCStrdup(description);
mode->RunModeFunc = RunModeFunc; // 执行函数:RunModeIdsPcapWorkers
}
====================================
main:注册模块(添加到全局的模块数组tmm_modules中)
TmModuleReceivePcapRegister();
TmModuleDecodePcapRegister();
TmModuleStreamTcpRegister();
TmModuleDetectRegister();
TmModuleRespondRejectRegister();
--------------------------------
// 添加到全局的模块数组中
void TmModuleReceivePcapRegister (void)
{
tmm_modules[TMM_RECEIVEPCAP].name = "ReceivePcap";
tmm_modules[TMM_RECEIVEPCAP].ThreadInit = ReceivePcapThreadInit;
tmm_modules[TMM_RECEIVEPCAP].Func = NULL;
tmm_modules[TMM_RECEIVEPCAP].PktAcqLoop = ReceivePcapLoop;
tmm_modules[TMM_RECEIVEPCAP].ThreadExitPrintStats = ReceivePcapThreadExitStats;
tmm_modules[TMM_RECEIVEPCAP].ThreadDeinit = NULL;
tmm_modules[TMM_RECEIVEPCAP].RegisterTests = NULL;
tmm_modules[TMM_RECEIVEPCAP].cap_flags = SC_CAP_NET_RAW;
tmm_modules[TMM_RECEIVEPCAP].flags = TM_FLAG_RECEIVE_TM;
}
======================================
main:运行模式调度
RunModeDispatch(run_mode, runmode_custom_mode, de_ctx);
{
mode->RunModeFunc(de_ctx); // workers模式调度RunModeIdsPcapWorkers函数
}
----------------------------------------------------
int RunModeIdsPcapWorkers(DetectEngineCtx *de_ctx)
{
int ret;
char *live_dev = NULL;
SCEnter();
RunModeInitialize();
TimeModeSetLive();
(void) ConfGet("pcap.single-pcap-dev", &live_dev);
ret = RunModeSetLiveCaptureWorkers(de_ctx,
ParsePcapConfig,
PcapConfigGeThreadsCount,
"ReceivePcap",
"DecodePcap", "RxPcap",
live_dev);
--------------
typedef定义函数指针类型:
typedef void *(*ConfigIfaceParserFunc) (const char *);
typedef void *(*ConfigIPSParserFunc) (int);
typedef int (*ConfigIfaceThreadsCountFunc) (void *);
--------------
int RunModeSetLiveCaptureWorkers(DetectEngineCtx *de_ctx,
ConfigIfaceParserFunc ConfigParser,
ConfigIfaceThreadsCountFunc ModThreadsCount,
char *recv_mod_name,
char *decode_mod_name, char *thread_name,
const char *live_dev)
{
live_dev_c = LiveGetDeviceName(ldev); // liev_dev_c = 'eth0'
aconf = ConfigParser(live_dev_c);
RunModeSetLiveCaptureWorkersForDevice( de_ctx,
ModThreadsCount,
recv_mod_name,
decode_mod_name,
thread_name,
live_dev_c,
aconf,
0);
}
--------------
static int RunModeSetLiveCaptureWorkersForDevice(DetectEngineCtx *de_ctx,
ConfigIfaceThreadsCountFunc ModThreadsCount,
char *recv_mod_name,
char *decode_mod_name, char *thread_name,
const char *live_dev, void *aconf,
unsigned char single_mode)
{
n_thread_name = 'RxPcapeth01'
// 创建tv实例
tv = TmThreadCreatePacketHandler(n_thread_name,
"packetpool", "packetpool",
"packetpool", "packetpool",
"pktacqloop");
回到这里继续:
创建tv实例,设置出入队列,设置tv->tm_func函数
// 收包模块插入槽
tm_module = TmModuleGetByName(recv_mod_name);
TmSlotSetFuncAppend(tv, tm_module, aconf);
// 解码模块插入槽
tm_module = TmModuleGetByName(decode_mod_name);
TmSlotSetFuncAppend(tv, tm_module, NULL);
// tcp流管理模块插入槽
tm_module = TmModuleGetByName("StreamTcp");
TmSlotSetFuncAppend(tv, tm_module, NULL);
// 检测模块插入槽(延迟作用是什么?)
tm_module = TmModuleGetByName("Detect");
TmSlotSetFuncAppendDelayed(tv, tm_module,
(void *)de_ctx, de_ctx->delayed_detect);
// 回应拒绝模块插入槽(啥意思?)
tm_module = TmModuleGetByName("RespondReject");
TmSlotSetFuncAppend(tv, tm_module, NULL);
// 真正创建线程
TmThreadSpawn(tv);
}
--------------------
模块插入槽函数:
static inline TmSlot * _TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void *data)
{
TmSlot *slot = SCMalloc(sizeof(TmSlot));
SC_ATOMIC_INIT(slot->slot_data);
slot->tv = tv;
slot->SlotThreadInit = tm->ThreadInit;
slot->slot_initdata = data;
SC_ATOMIC_INIT(slot->SlotFunc);
(void)SC_ATOMIC_SET(slot->SlotFunc, tm->Func);
slot->PktAcqLoop = tm->PktAcqLoop;
slot->SlotThreadExitPrintStats = tm->ThreadExitPrintStats;
slot->SlotThreadDeinit = tm->ThreadDeinit;
slot->tm_id = TmModuleGetIDForTM(tm);
tv->cap_flags |= tm->cap_flags;
if (tv->tm_slots == NULL) {
tv->tm_slots = slot;
slot->id = 0;
} else {
TmSlot *a = (TmSlot *)tv->tm_slots, *b = NULL;
for ( ; a != NULL; a = a->slot_next) {
b = a;
}
if (b != NULL) {
b->slot_next = slot;
slot->id = b->id + 1;
}
}
return slot;
}
---------------------
ThreadVars *TmThreadCreatePacketHandler(char *name, char *inq_name,
char *inqh_name, char *outq_name,
char *outqh_name, char *slots)
{
ThreadVars* tv = TmThreadCreate(name, inq_name, inqh_name, outq_name, outqh_name,
slots, NULL, 0);
returnt tv;
}
-------------
参数:name是tv实例的名称
inq_name是入队列名称
inqh_name是入队列处理名称(set by TmqhSetup())
outq_name是出队列名称
outqh_name是出队列处理名称(set by TmqhSetup())
slots是描述槽的作用
ThreadVars *TmThreadCreate(char *name, char *inq_name, char *inqh_name,
char *outq_name, char *outqh_name, char *slots,
void * (*fn_p)(void *), int mucond)
{
ThreadVars *tv = NULL;
tv = SCMalloc(sizeof(ThreadVars));
tv->name = name;
// 设置入队列
Tmq *tmq = NULL;
tmq = TmqGetQueueByName(inq_name);
tv->inq = tmq;
Tmqh *tmqh = NULL;
tmqh = TmqhGetQueueHandlerByName(inqh_name);
tv->tmqh_in = tmqh->InHandler;
tv->InShutdownHandler = tmqh->InShutdownHandler;
// 设置出队列
tmqh = TmqhGetQueueHandlerByName(outqh_name);
tv->tmqh_out = tmqh->OutHandler;
tv->outqh_name = tmqh->name;
// 设置槽函数
TmThreadSetSlots(tv, slots, fn_p)
}
-------------
TmEcode TmThreadSetSlots(ThreadVars *tv, char *name, void *(*fn_p)(void *))
{
// 这几个槽的名称区别
if (strcmp(name, "1slot") == 0) {
tv->tm_func = TmThreadsSlot1;
} else if (strcmp(name, "1slot_noout") == 0) {
tv->tm_func = TmThreadsSlot1NoOut;
} else if (strcmp(name, "1slot_noin") == 0) {
tv->tm_func = TmThreadsSlot1NoIn;
} else if (strcmp(name, "1slot_noinout") == 0) {
tv->tm_func = TmThreadsSlot1NoInOut;
} else if (strcmp(name, "varslot") == 0) {
tv->tm_func = TmThreadsSlotVar;
} else if (strcmp(name, "pktacqloop") == 0) { // 走到这里
tv->tm_func = TmThreadsSlotPktAcqLoop;
} else if (strcmp(name, "custom") == 0) {
if (fn_p == NULL)
goto error;
tv->tm_func = fn_p;
} else {
printf("Error: Slot "%s" not supported\n", name);
goto error;
}
}
------------
回到RunModeSetLiveCaptureWorkersForDevice函数
------------
真正创建线程:
TmEcode TmThreadSpawn(ThreadVars *tv)
{
// 创建线程,调用tv->tm_func函数: TmThreadsSlotPktAcqLoop
pthread_create(&tv->t, &attr, tv->tm_func, (void *)tv);
}
==================================================
void *TmThreadsSlotPktAcqLoop(void *td)
{
ThreadVars *tv = (ThreadVars *)td;
TmSlot *s = tv->tm_slots; // slot链表头
// 设置线程名称
SCSetThreadName(tv->name);
// 循环slot初始化
for (slot = s; slot != NULL; slot = slot->slot_next)
{
// slot中模块初始化Recive->Decode->StreamTcp->Detect->Alert ……
r = slot->SlotThreadInit(tv, slot->slot_initdata, &slot_data);
}
// 真正循环slot
while(run)
{
// 收包,执行 ReceivePcapLoop 函数,在注册模块时设置的
r = s->PktAcqLoop(tv, SC_ATOMIC_GET(s->slot_data), s);
}
// 销毁函数执行
for (slot = s; slot != NULL; slot = slot->slot_next)
{
slot->SlotThreadExitPrintStats(tv, SC_ATOMIC_GET(slot->slot_data));
r = slot->SlotThreadDeinit(tv, SC_ATOMIC_GET(slot->slot_data));
}
}
===============================
// data是初始化阶段生成的PcapThreadVars结构体
TmEcode ReceivePcapLoop(ThreadVars *tv, void *data, void *slot)
{
PcapThreadVars *ptv = (PcapThreadVars *)data;
TmSlot *s = (TmSlot *)slot;
ptv->slot = s->slot_next;// 第2个slot即Decode模块
while (1)
{ // 收包,每次收取一个数据包
r = pcap_dispatch(ptv->pcap_handle, (int)packet_q_len,
(pcap_handler)PcapCallbackLoop, (u_char *)ptv);
}
}
// 收包后回调函数
// 参数: user是ptv结构指针,h是pcap文件头,pkt是真正数据
void PcapCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt)
{
// 首先从packet pool中获取,如果失败。调用PacketGetFromAlloc新分配一个
// 注:与pool中取出的数据包最终可以回收不同,这种使用malloc动态分配的数据包最后需要free.
// 因此为了区分会在其flags中打上标记PKT_ALLOC。
Packet *p = PacketGetFromQueueOrAlloc();
// 数据包在callback中会送入outq中等待后续线程继续处理
// 调用TmThreadsSlotProcessPkt让本线程中包含的其他slot中的模块对数据包进行后续处理
TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p);
}
// 真正循环slot中模块执行函数
static inline TmEcode TmThreadsSlotProcessPkt(ThreadVars *tv, TmSlot *s, Packet *p)
{
TmThreadsSlotVarRun(tv, p, s);
// 线程创建时设置为与该线程绑定的outqh的处理函数OutHandler,
// 在这里默认为TmqhOutputFlowActivePackets,将数据包送到后续队列中去
tv->tmqh_out(tv, p);
// 注: slot_pre_pq vs. slot_post_pq:
// 某个slot在处理某个母数据包时新产生的子数据包,
// 若放入slot_pre_pq中,则这个数据包将在本个slot处理完母数据包后,
// 在后续slot处理母数据包之前,先将这些子数据包放到后续的slot去处理;
// 而如果是放如slot_post_pq,则需要等到母数据包被所有slot都处理完后,
// 在下一个数据包处理之前,再去集中处理,如上面所述。
处理slot->slot_post_pq队列
}
TmEcode TmThreadsSlotVarRun(ThreadVars *tv, Packet *p, TmSlot *slot)
{
循环调用Slot->SlotFun函数。
Decode->StreamTcp->Detect->RespondRejectFunc->AlertFastLog-> ……
处理 slot_pre_pq队列数据。
}