L.检查配置文件中”vars”选项 IP、port是否符合格式要求
此处只讨论 IDS模式, af-packet采集,workers工作模式下。
代码如下:
if (InitGlobal() != 0) {
exit(EXIT_FAILURE);
}
int InitGlobal(void) {
...
RunModeRegisterRunModes();
...
}
//主要是完成运行模式的注册,添加的所有运行模式都要通过这个函数注册
void RunModeRegisterRunModes(void)
{
memset(runmodes, 0, sizeof(runmodes));
RunModeIdsPcapRegister();
RunModeFilePcapRegister();
RunModeIdsPfringRegister();
RunModeIpsNFQRegister();
RunModeIpsIPFWRegister();
RunModeErfFileRegister();
RunModeErfDagRegister();
RunModeNapatechRegister();
RunModeIdsAFPRegister();
RunModeIdsNetmapRegister();
RunModeIdsNflogRegister();
RunModeUnixSocketRegister();
RunModeIpsWinDivertRegister();
#ifdef UNITTESTS
UtRunModeRegister();
#endif
return;
}
// IDS workers af-packet 模式下注册函数
void RunModeIdsAFPRegister(void)
{
RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "workers",
"Workers af-packet mode, each thread does all"
" tasks from acquisition to logging",
RunModeIdsAFPWorkers);
return;
}
void RunModeRegisterNewRunMode(enum RunModes runmode,
const char *name,
const char *description,
int (*RunModeFunc)(void))
{
//注册一个相应的模式及回调函数到全局 static RunModes runmodes[RUNMODE_USER_MAX];
//对应的回调函数
mode->RunModeFunc = RunModeFunc; //即为int RunModeIdsAFPWorkers(void)函数
//这个函数将在创建线程时调用
}
//创建相应的工作线程,同时工作线程处理流程
//(ReceiveAFP --> DecodeAFP --> FlowWorker --> RespondReject)
int RunModeIdsAFPWorkers(void)
{
SCEnter();
#ifdef HAVE_AF_PACKET
int ret;
const char *live_dev = NULL;
RunModeInitialize();
TimeModeSetLive();
(void)ConfGet("af-packet.live-interface", &live_dev);
if (AFPPeersListInit() != TM_ECODE_OK) {
FatalError(SC_ERR_FATAL, "Unable to init peers list.");
}
ret = RunModeSetLiveCaptureWorkers(ParseAFPConfig,
AFPConfigGeThreadsCount,
"ReceiveAFP",
"DecodeAFP", thread_name_workers,
live_dev);
if (ret != 0) {
FatalError(SC_ERR_FATAL, "Unable to start runmode");
}
/* In IPS mode each threads must have a peer */
if (AFPPeersListCheck() != TM_ECODE_OK) {
FatalError(SC_ERR_FATAL, "Some IPS capture threads did not peer.");
}
SCLogDebug("RunModeIdsAFPWorkers initialised");
#endif /* HAVE_AF_PACKET */
SCReturnInt(0);
}
if (ParseCommandLine(argc, argv, &suricata) != TM_ECODE_OK) {
exit(EXIT_FAILURE);
}
/* Initializations for global vars, queues, etc (memsets, mutex init..) 数据包队列trans_q、数据队列data_queues(干嘛的?)、对应的mutex和cond、建立小写字母表。*/
GlobalsInitPreConfig();
void GlobalsInitPreConfig(void)
{
TimeInit();
SupportFastPatternForSigMatchTypes();
SCThresholdConfGlobalInit();
}
TimeInit() 初始化时间。包括:获取当前时间所用的spin lock,以及设置时区(调用tzset()即可)。
SupportFastPatternForSigMatchTypes() 为快速模式匹配注册关键字。调用SupportFastPatternForSigMatchList函数,按照优先级大小插入到sm_fp_support_smlist_list链表中。
SCThresholdConfGlobalInit() 初始化阈值正则系统
if (LoadYamlConfig(&suricata) != TM_ECODE_OK) {
exit(EXIT_FAILURE);
}
调用LoadYamlConfig读取Yaml格式配置文件。若用户未在输入参数(-c)中指定配置文件,则使用默认配置文件(/etc/suricata/suricata.yaml)。Yaml格式解析是通过libyaml库来完成的,解析的结果存储在配置节点树(见conf.c)中。对include机制的支持:在第一遍调用ConfYamlLoadFile载入主配置文件后,将在当前配置节点树中搜寻“include”节点,并对其每个子节点的值(即通过include语句所指定的子配置文件路径),同样调用ConfYamlLoadFile进行载入。
/* Since our config is now loaded we can finish configurating the
* logging module. */
SCLogLoadConfig(suricata.daemon, suricata.verbose);
再次初始化日志模块。这次,程序将会根据配置文件中日志输出配置(logging.outputs)填充SCLogInitData类型的结构体,调用SCLogInitLogModule重新初始化日志模块。
LogVersion(&suricata); //打印版本信息。这是Suricata启动开始后第一条打印信息。
UtilCpuPrintSummary(); //打印当前机器的CPU/核个数,这些信息是通过sysconf系统函数获取的。
if (ParseInterfacesList(suricata.aux_run_mode, suricata.pcap_dev) != TM_ECODE_OK) {
exit(EXIT_FAILURE);
}
解析接口设置名称(网络设备,如eth0,eth1等)。 如果suri.pcap_dev为NULL,则从配置文件获取设备名称。 如果suri.pcap_dev不为NULL,则将读入的配置结点的设备名称改为suri.pcap_dev。
if (PostConfLoadedSetup(&suricata) != TM_ECODE_OK) {
exit(EXIT_FAILURE);
}
这个函数包含在配置加载后需要运行操作,操作很多。
MpmTableSetup();
SpmTableSetup();
//多模匹配模式种类
enum {
MPM_NOTSET = 0,
/* aho-corasick */
MPM_AC,
MPM_AC_BS,
MPM_AC_KS,
MPM_HS,
/* table size */
MPM_TABLE_SIZE,
};
//单模匹配模式种类
enum {
SPM_BM, /* Boyer-Moore */
SPM_HS, /* Hyperscan */
/* Other SPM matchers will go here. */
SPM_TABLE_SIZE
};
设置多模式匹配表,
设置单模式匹配表,基本和上面的多模式匹配相同,有两个匹配项BM和HS(HYPERSCAN)。
已多模注册AC匹配器为例,MpmTableSetup()会调用MpmACRegister(void) 函数实现AC注册,函数内部其实只是填充mpm_table中对应 AC的那一项(mpm_table[MPM_AC])的各个字段,如:匹配器名称(”ac”)、初始化函数(SCACInitCtx)、增加模式函数 (SCACAddPatternCS)、实际的搜索执行函数(SCACSearch), 注册了一些列的回调函数。
if (suri->checksum_validation == -1) {
const char *cv = NULL;
if (ConfGetValue("capture.checksum-validation", &cv) == 1) {
if (strcmp(cv, "none") == 0) {
suri->checksum_validation = 0;
} else if (strcmp(cv, "all") == 0) {
suri->checksum_validation = 1;
}
}
}
switch (suri->checksum_validation) {
case 0:
ConfSet("stream.checksum-validation", "0");
break;
case 1:
ConfSet("stream.checksum-validation", "1");
break;
}
StorageInit();
StorageInit:初始化存储模块,这个模块可以用来临时存储一些数据,数据类型目前有四种:host、flow、ippair、livedevice。具体在何种场景下用,目前未知。
AppLayerSetup();
int AppLayerSetup(void)
{
SCEnter();
AppLayerProtoDetectSetup();
AppLayerParserSetup();
AppLayerParserRegisterProtocolParsers();
AppLayerProtoDetectPrepareState();
AppLayerSetupCounters();
SCReturnInt(0);
}
AppLayerProtoDetectSetup() 函数初始化该模块所用到的多模式匹配器;
AppLayerParserSetup() 函数通过传输层和应用层协议号构建了一个二维数组,并在该数组中为相应的流重组深度赋值;
AppLayerParserRegisterProtocolParsers() 函数注册各种应用层协议的解析器 (如RegisterHTPParsers函数对应HTTP协议,这个后面会详细分析);
AppLayerProtoDetectPrepareState() 函数的功能暂时也没弄明白。
AppLayerSetupCounters() 函数设置Counter name
if (ConfigGetCaptureValue(suri) != TM_ECODE_OK) {
SCReturnInt(TM_ECODE_FAILED);
}
获取与包捕获相关的一些配置参数,目前包括:max-pending-packets、default-packet-size。
/* Load the Host-OS lookup. */
SCHInfoLoadFromConfig();
针对碎片整理和TCP流重组的主机特定策略。主机操作系统查找是使用基数树完成的,就像路由表一样,以便匹配最特定的条目。
if (suri->run_mode == RUNMODE_ENGINE_ANALYSIS) {
SCLogInfo("== Carrying out Engine Analysis ==");
const char *temp = NULL;
if (ConfGet("engine-analysis", &temp) == 0) {
SCLogInfo("no engine-analysis parameter(s) defined in conf file. "
"Please define/enable them in the conf to use this "
"feature.");
SCReturnInt(TM_ECODE_FAILED);
}
}
/* hardcoded initialization code */
SigTableSetup(); /* load the rule keywords */
SigTableApplyStrictCommandlineOption(suri->strict_rule_parsing_string);
SigTableSetup:初始化检测引擎,主要是注册检测引擎所支持的规则格式(跟Snort规则基本一致)中的关键字,比如sid、priority、msg、within、distance等等。
SigTableApplyStrictCommandlineOption(suri->strict_rule_parsing_string) 为指定的检测关键字设置严格匹配。
TmqhSetup();
初始化queue handler(队列处理函数),这个是衔接线程模块和数据包队列之间的桥梁,目前共有3 类handler:simple, packetpool, flow。每类handler内部都有一个InHandler和OutHandler,一个用于从上一级队列中获取数据包,另一个用于处理完毕后将数据包送入下一级队列。
CIDRInit();
CIDRInit:初始化CIDR掩码数组,cidrs[i]对应前i位为1的掩码。
SCProtoNameInit();
读取/etc/protocols文件,建立IP层所承载的上层协议号和协议名的映射(如6-> ”TCP”,17-> ”UDP“)。
TagInitCtx();
PacketAlertTagInit();
ThresholdInit();
HostBitInitCtx();
IPPairBitInitCtx();
TagInitCtx、ThresholdInit:与规则中的tag、threshould关键字的实现相关,这里用到了Storage模块,调用 HostStorageRegister和FlowStorageRegister注册了几个(与流/主机绑定的?)存储区域。
if (DetectAddressTestConfVars() < 0) {
SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY,
"basic address vars test failed. Please check %s for errors",
suri->conf_filename);
SCReturnInt(TM_ECODE_FAILED);
}
if (DetectPortTestConfVars() < 0) {
SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY,
"basic port vars test failed. Please check %s for errors",
suri->conf_filename);
SCReturnInt(TM_ECODE_FAILED);
}
DetectAddressTestConfVars、DetectPortTestConfVars:检查配置文件中”vars”选项下所预定义的一些IP地址(如局域网地址块)、端口变量(如HTTP端口号)是否符合格式要求。
FeatureTrackingRegister(); /* must occur prior to output mod registration */
FeatureTrackingRegister:注册特征比较函数。
RegisterAllModules();
void RegisterAllModules(void)
{
// zero all module storage
memset(tmm_modules, 0, TMM_SIZE * sizeof(TmModule));
...
/* af-packet */
TmModuleReceiveAFPRegister();
TmModuleDecodeAFPRegister();
...
/* flow worker */
TmModuleFlowWorkerRegister();
/* respond-reject */
TmModuleRespondRejectRegister();
/* log api */
TmModuleLoggerRegister();
TmModuleStatsLoggerRegister();
...
/* nflog */
TmModuleReceiveNFLOGRegister();
TmModuleDecodeNFLOGRegister();
...
}
以IDS模式, af-packet采集,workers 为例,所谓注册,就是在tmm_modules模块数组中对应的那项 中填充TmModule结构的所有字段,这些字段包括:模块名字、线程初始化函数、包处理或包获取函数、线程退出清理函数、一些标志位等等。
AppLayerHtpNeedFileInspection();
AppLayerHtpNeedFileInspection:设置suricata内部模块与libhtp(HTTP处理库)对接关系的函数。
StorageFinalize();
StorageFinalize:关闭storage模块的注册,为已注册的storage实际分配存储空间。
if (MayDaemonize(suri) != TM_ECODE_OK)
SCReturnInt(TM_ECODE_FAILED);
检查是否进入Daemon模式。若需要进入Daemon模式,则会检测pidfile是否已经存在(daemon下只 能有一个实例运行),然后进行Daemonize,最后创建一个pidfile。Daemonize的主要思路是:fork->子进程调用 setsid创建一个新的session,关闭stdin、stdout、stderr,并告诉父进程 –> 父进程等待子进程通知,然后退出 –> 子进程继续执行。
if (InitSignalHandler(suri) != TM_ECODE_OK)
SCReturnInt(TM_ECODE_FAILED);
初始化信号handler。首先为SIGINT(ctrl-c触发)和SIGTERM(不带参数kill时触发)这两个常规退出信号分别注册handler,对SIGINT的处理是设置程序的状态标志为STOP,即让程序优雅地退出;而对SIGTERM是设置为KILL,即强杀。接着,程序会忽略SIGPIPE(这个信号通常是在Socket通信时向已关闭的连接另一端发送数据时收到)和SIGSYS(当进程尝试执行一个不存在的系统调用时收到)信号,以加强程序的容错性和健壮性。
/* Check for the existance of the default logging directory which we pick
* from suricata.yaml. If not found, shut the engine down */
suri->log_dir = ConfigGetLogDirectory();
设置并验证日志存储目录是否存在。若配置文件中未指定,则使用默认目录,linux下默认为/var/log/suricata。
/* Check for the existance of the default logging directory which we pick
* from suricata.yaml. If not found, shut the engine down */
suri->log_dir = ConfigGetLogDirectory();
if (ConfigCheckLogDirectoryExists(suri->log_dir) != TM_ECODE_OK) {
SCLogError(SC_ERR_LOGDIR_CONFIG, "The logging directory \"%s\" "
"supplied by %s (default-log-dir) doesn't exist. "
"Shutting down the engine", suri->log_dir, suri->conf_filename);
SCReturnInt(TM_ECODE_FAILED);
}
if (!IsLogDirectoryWritable(suri->log_dir)) {
SCLogError(SC_ERR_LOGDIR_CONFIG, "The logging directory \"%s\" "
"supplied by %s (default-log-dir) is not writable. "
"Shutting down the engine", suri->log_dir, suri->conf_filename);
SCReturnInt(TM_ECODE_FAILED);
}
设置并验证日志存储目录是否存在。若配置文件中未指定,则使用默认目录,linux下默认为/var/log/suricata。
#ifdef HAVE_NSS
if (suri->run_mode != RUNMODE_CONF_TEST) {
/* init NSS for hashing */
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
NSS_NoDB_Init(NULL);
}
#endif
if (suri->disabled_detect) {
SCLogConfig("detection engine disabled");
/* disable raw reassembly */
(void)ConfSetFinal("stream.reassembly.raw", "false");
}
若detect未开启,则设置tcp流重组为false。
HostInitConfig(HOST_VERBOSE);
初始化Host engine。具体到配置文件中只有3项:hash-size, prealloc, memcap。
CoredumpLoadConfig();
处理CoreDump相关配置。Linux下可用prctl函数获取和设置进程dumpable状态,设置corefile大小则是通过通用的setrlimit函数。
DecodeGlobalConfig();
译码器的设置, teredo,vxlan,vntag,geneve,max-layers
LiveDeviceFinalize();
创建注册设备 ,这个函数创建所有需要的LiveDevice,通过LiveRegisterDevice()创建的LiveDeviceName列表
PreRunInit(suri->run_mode);
/* initialization code for both the main modes and for
* unix socket mode.
*
* Will be run once per pcap in unix-socket mode */
void PreRunInit(const int runmode)
{
/* Initialize Datasets to be able to use them with unix socket */
DatasetsInit();
if (runmode == RUNMODE_UNIX_SOCKET)
return;
StatsInit();
#ifdef PROFILING
SCProfilingRulesGlobalInit();
SCProfilingKeywordsGlobalInit();
SCProfilingPrefilterGlobalInit();
SCProfilingSghsGlobalInit();
SCProfilingInit();
#endif /* PROFILING */
DefragInit();
FlowInitConfig(FLOW_QUIET);
IPPairInitConfig(FLOW_QUIET);
StreamTcpInitConfig(STREAM_VERBOSE);
AppLayerParserPostStreamSetup();
AppLayerRegisterGlobalCounters();
OutputFilestoreRegisterGlobalCounters();
}
若运行模式不为RUNMODE_UNIX_SOCKET调用StatsInit()初始化全局变量stats_ctx。
DefragInit() 初始化IP分片重组模块。
FlowInitConfig(FLOW_QUIET) 初始化Flow engine。用来表示一条TCP/UDP/ICMP/SCTP流的,程序当前所记录的所有流便组成了流表,在flow引擎中,流表为flow_hash这个全局变量,其类型为FlowBucket *,而FlowBucket中则能够存储一个Flow链表,典型的一张chained hash Table。在初始化函数FlowInitConfig中,首先会使用配置文件信息填充flow_config,然后会按照配置中的hash_size为流表实际分配内存,接着按照prealloc进行流的预分配(FlowAlloc->FlowEnqueue,存储在flow_spare_q这个FlowQueue类型的队列中),最后调用FlowInitFlowProto为流表所用于的各种流协议进行配置,主要是设置timeout时间。
IPPairInitConfig(FLOW_QUIET) 初始化ippair engine,默认不开启。
StreamTcpInitConfig(STREAM_VERBOSE) 初始化Stream TCP模块。其中调用了StreamTcpReassembleInit函数进行重组模块初始化。
AppLayerParserPostStreamSetup() 为流深度设置一个默认值
AppLayerRegisterGlobalCounters() 注册应用层全局计数器
“http.memuse”,”http.memcap”,”ftp.memuse”,”ftp.memcap”,”app_layer.expectations”到stats_ctx中。
SCDropMainThreadCaps(suricata.userid, suricata.groupid);
去除主线程的权限。这个是通过libcap-ng实现的,首先调用capng_clear清空所有权限,然后根据运行模式添加一些必要权限(主要是为了抓包),最后调用capng_change_id设置新的uid和gid。主线程的权限应该会被新建的子线程继承,因此只需要在主线程设置即可。
PreRunPostPrivsDropInit(suricata.run_mode);
/* tasks we need to run before packets start flowing,
* but after we dropped privs */
void PreRunPostPrivsDropInit(const int runmode)
{
StatsSetupPostConfigPreOutput();
RunModeInitializeOutputs();
if (runmode == RUNMODE_UNIX_SOCKET) {
/* As the above did some necessary startup initialization, it
* also setup some outputs where only one is allowed, so
* deinitialize to the state that unix-mode does after every
* pcap. */
PostRunDeinit(RUNMODE_PCAP_FILE, NULL);
return;
}
StatsSetupPostConfigPostOutput();
}
在数据包开始流动之前我们需要运行的任务,但在我们丢弃了privs之后
RunModeInitializeOutputs() 初始化所有Output模块。这些模块之前在线程模块注册函数里已经都注册了,这里会根据配置文件再进行配置和初始化,最后把当前配置下启用了的output模块放到RunModeOutputs链表中。目前我了解到的全部的log都是在这里初始化的,包括自己扩展的log模块也在这里。
PostConfLoadedDetectSetup(&suricata);
void PostConfLoadedDetectSetup(SCInstance *suri)
{
DetectEngineCtx *de_ctx = NULL;
if (!suri->disabled_detect) {
SCClassConfInit();
SCReferenceConfInit();
SetupDelayedDetect(suri);
int mt_enabled = 0;
(void)ConfGetBool("multi-detect.enabled", &mt_enabled);
int default_tenant = 0;
if (mt_enabled)
(void)ConfGetBool("multi-detect.default", &default_tenant);
if (DetectEngineMultiTenantSetup() == -1) {
FatalError(SC_ERR_FATAL, "initializing multi-detect "
"detection engine contexts failed.");
}
if (suri->delayed_detect && suri->run_mode != RUNMODE_CONF_TEST) {
de_ctx = DetectEngineCtxInitStubForDD();
} else if (mt_enabled && !default_tenant && suri->run_mode != RUNMODE_CONF_TEST) {
de_ctx = DetectEngineCtxInitStubForMT();
} else {
de_ctx = DetectEngineCtxInit();
}
if (de_ctx == NULL) {
FatalError(SC_ERR_FATAL, "initializing detection engine "
"context failed.");
}
if (de_ctx->type == DETECT_ENGINE_TYPE_NORMAL) {
if (LoadSignatures(de_ctx, suri) != TM_ECODE_OK)
exit(EXIT_FAILURE);
}
gettimeofday(&de_ctx->last_reload, NULL);
DetectEngineAddToMaster(de_ctx);
DetectEngineBumpVersion();
}
}
detect设为启用时,
SCClassConfInit() 解析Class相关正则
SCReferenceConfInit() 解析Refference相关正则
SetupDelayedDetect(&suri) 设置是否延迟检测。若delayed-detect为yes,则系统将在载入规则集之前就开始处理数据包,这样能够在IPS模式下减少系统的down time(宕机时间)
初始化Decect engine。若配置文件中未指定mpm(多模式匹配器),则默认使用AC,即使用 mpm_table中AC那一项。SRepInit函数(与前面的SCReputationInitCtx不同!)会初始化检测引擎中域 reputaion相关信息,即从配置文件中指定的文件中读取声望数据
SCSetStartTime(&suricata);
设置记录开始时间。
RunModeDispatch(suricata.run_mode, suricata.runmode_custom_mode,
suricata.capture_plugin_name, suricata.capture_plugin_args);
mode->RunModeFunc();
if (local_custom_mode != NULL)
SCFree(local_custom_mode);
/* Check if the alloted queues have at least 1 reader and writer */
TmValidateQueueState();
if (runmode != RUNMODE_UNIX_SOCKET) {
/* spawn management threads */
FlowManagerThreadSpawn();
FlowRecyclerThreadSpawn();
if (RunModeNeedsBypassManager()) {
BypassedFlowManagerThreadSpawn();
}
StatsSpawnThreads();
}
初始化运行模式。首先,根据配置文件和程序中的默认值来配置运行模式(single、auto这些),而运行模式类 型(PCAP_DEV、PCAPFILE这些)也在之前已经确定了,因此运行模式已经固定下来,可以从runmodes表中获取到特定的RunMode 了,接着就调用RunMode中的RunModeFunc,进入当前运行模式的初始化函数(mode->RunModeFunc())。以 AFP 类型下的workers模式为例,该模式的初 始化函数为:RunModeIdsAFPWorkers。
FlowManagerThreadSpawn() : 创建Flow管理线程,用于对流表进行超时删除处理。管理线程创建是通过TmThreadCreateMgmtThread函数,类型为TVT_MGMT,执行函数为FlowManager。
FlowRecyclerThreadSpawn(): 同样是对流超时进行处理,执行函数为FlowRecycler。
StatsSpawnThreads() : 创建性能计数相关线程,包括一个定期对各计数器进行同步的唤醒线程(StatsWakeupThread),和一个定期输出计数值的管理线程(StatsMgmtThread)。
/* Wait till all the threads have been initialized */
if (TmThreadWaitOnThreadInit() == TM_ECODE_FAILED) {
FatalError(SC_ERR_FATAL, "Engine initialization failed, "
"aborting...");
}
等待子线程初始化完成。检查是否初始化完成的方式是遍历tv_root,调用TmThreadsCheckFlag检查子线程的状态标志。
SC_ATOMIC_SET(engine_stage, SURICATA_RUNTIME);
PacketPoolPostRunmodes();
/* Un-pause all the paused threads */
TmThreadContinueThreads();
继续运行暂停的线程
PostRunStartedDetectSetup(&suricata);
static void PostRunStartedDetectSetup(const SCInstance *suri)
{
#ifndef OS_WIN32
/* registering signal handlers we use. We setup usr2 here, so that one
* can't call it during the first sig load phase or while threads are still
* starting up. */
if (DetectEngineEnabled() && suri->delayed_detect == 0) {
UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2);
UtilSignalUnblock(SIGUSR2);
}
#endif
if (suri->delayed_detect) {
/* force 'reload', this will load the rules and swap engines */
DetectEngineReload(suri);
SCLogNotice("Signature(s) loaded, Detect thread(s) activated.");
#ifndef OS_WIN32
UtilSignalHandlerSetup(SIGUSR2, SignalHandlerSigusr2);
UtilSignalUnblock(SIGUSR2);
#endif
}
}
设置Sigusr2信号的处理函数
DetectEngineReload(&suri) 重新加载detect engine
SuricataMainLoop(&suricata);
static void SuricataMainLoop(SCInstance *suri)
{
while(1) {
if (sigterm_count || sigint_count) {
suricata_ctl_flags |= SURICATA_STOP;
}
if (suricata_ctl_flags & SURICATA_STOP) {
SCLogNotice("Signal Received. Stopping engine.");
break;
}
TmThreadCheckThreadState();
if (sighup_count > 0) {
OutputNotifyFileRotation();
sighup_count--;
}
if (sigusr2_count > 0) {
if (!(DetectEngineReloadIsStart())) {
DetectEngineReloadStart();
DetectEngineReload(suri);
DetectEngineReloadSetIdle();
sigusr2_count--;
}
} else if (DetectEngineReloadIsStart()) {
DetectEngineReload(suri);
DetectEngineReloadSetIdle();
}
usleep(10* 1000);
}
}
若收到引擎退出信号(SURICATA_KILL或SURICATA_STOP),则退出循环,执行后续退出操作
TmThreadCheckThreadState() 检查各线程的状态,决定是否进行结束线程、重启线程、终止程序等操作
OutputNotifyFileRotation() 循环设置注册文件的flags。
凡是过往,即为序章