suricata 各个线程干的事情 -- 主线程

目录

线程类型

0. 主线程

注册runmodes

根据配置初始化 

注册应用协议检测器

注册应用层协议解析器

加载规则关键字

tag初始化

几种存储结构的初始化与注册

注册所有模块的函数

检测引擎初始化:

创建工作线程

创建非工作线程的子线程

主线程进入主循环:


线程类型

suricata 除了主线程外还有若干子线程,子线程类型见下表:

序号 线程类型 name 线程数量

tv->type

tv->tm_func()对应的函数 tv->tm_slots 对应的slot表(TmModule) 备注
1 worker threads W

suricata.yaml

threading配置

packetpool

TVT_PPT TmThreadsSlotPktAcqLoop

Receive

->Decode->FlowWorker
2 FlowManagerThread FM

suricata.yaml

flow.managers

management

TVT_MGMT

TmThreadsManagement FlowManager 默认为1个
3 FlowRecyclerThread FR

suricata.yaml

flow.recyclers

management

TVT_MGMT

TmThreadsManagement FlowRecycler 默认为1个
4 BypassedFlowManagerThread FB 1

management

TVT_MGMT

TmThreadsManagement BypassedFlowManager
5

StatsWakeupThread

CW 1

custom

TVT_MGMT

StatsWakeupThread

6

StatsMgmtThread

CS 1

custom

TVT_MGMT

StatsMgmtThread

7

UnixManagerThread

US

2 or 0

command

TVT_CMD

TmThreadsManagement

UnixManager

RUNMODE_UNIX_SOCKET

mode是才创建,否则没有

8

DetectLoaderThread

DL

suricata.yaml

multi-detect.loaders 

or 0

command

TVT_CMD

TmThreadsManagement

DetectLoader

MT(多租户)被启用才创建,默认的配置没有此项。

0. 主线程

主线程函数: int main(int argc, char **argv),可参见suricata 初始化做的那些事儿_xuwaiwai的博客-CSDN博客_suricata目录前言一、SuricataMain 程序入口1.在引擎中注册所有运行模式。2.解析执行命令3.初始化全局变量3.加载yaml配置文件4.初始化日志5.打印版本和CPUs/cores6.解析接口设置名称7.配置加载后的操作A. 设置多模和单模匹配模式B. 设置checksumC. 初始化存储模块D. 应用层协议设置E. 设置捕获参数F. 加载主机操作系统策略信息G. 初始化检测引擎H. 初始化queue handler(队列处理函数)https://blog.csdn.net/xuwaiwai/article/details/120045259?spm=1001.2014.3001.5501

注册runmodes

注册各种的运行模式到 runmodes 数据中(这里的运行模式是采集数据来源和IPS/IDS 的组合,比如 RUNMODE_PCAP_DEV,RUNMODE_NFQ,RUNMODE_AFP_DEV), 在每个运行模式具体的注册函数中,分别注册各自支持的工作模式("single","workers","autofp"),runmodes 结构如下。实际运行时会全部注册各种运行模式的工作模式,但是会根据运行命令和配置只会初始化并使用一种(运行模式 + 工作模式),如(RUNMODE_AFP_DEV+ "workers")。

typedef struct RunMode_ { //每种工作模式
    /* the runmode type */
    enum RunModes runmode; //运行模式 RUNMODE_AFP_DEV
    const char *name;      //工作模式名字 "workers"
    const char *description; //描述
    /* runmode function */
    int (*RunModeFunc)(void); //初始化的回调函数
} RunMode;

typedef struct RunModes_ {
    int cnt; 
    RunMode *runmodes; //容纳多个工作模式(single, workers, autofp)
} RunModes;

static RunModes runmodes[RUNMODE_USER_MAX]; //容纳多种运行模式


//eg. (RUNMODE_AFP_DEV+ "workers")将注册如下几种
void RunModeIdsAFPRegister(void)
{
    RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "single",
                              "Single threaded af-packet mode",
                              RunModeIdsAFPSingle);
    RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "workers",
                              "Workers af-packet mode, each thread does all"
                              " tasks from acquisition to logging",
                              RunModeIdsAFPWorkers);
    RunModeRegisterNewRunMode(RUNMODE_AFP_DEV, "autofp",
                              "Multi socket AF_PACKET mode.  Packets from "
                              "each flow are assigned to a single detect "
                              "thread.",
                              RunModeIdsAFPAutoFp);
    return;
}

根据配置初始化 

解析执行命令,记载 suricata.yaml配置文件,初始化日志系统。

注册应用协议检测器

:这个主要是根据相应的协议做对应的规则检测,初始化并保存在全局{static AppLayerProtoDetectCtx alpd_ctx}中。

        多模:放入 MpmTableElmt mpm_table[MPM_TABLE_SIZE] 中,总共有四种, 分别注册一些回调函数。实际使用时根据配置只用一种。

enum {
    MPM_NOTSET = 0,

    /* aho-corasick */
    MPM_AC,
    MPM_AC_BS,
    MPM_AC_KS,
    MPM_HS,
    /* table size */
    MPM_TABLE_SIZE,
};

typedef struct MpmTableElmt_ {
    const char *name;
    void (*InitCtx)(struct MpmCtx_ *);
    void (*InitThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *);
    void (*DestroyCtx)(struct MpmCtx_ *);
    void (*DestroyThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *);
    int  (*AddPattern)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t);
    int  (*AddPatternNocase)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t);
    int  (*Prepare)(struct MpmCtx_ *);
    uint32_t (*Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t);
    void (*PrintCtx)(struct MpmCtx_ *);
    void (*PrintThreadCtx)(struct MpmThreadCtx_ *);
    void (*RegisterUnittests)(void);
    uint8_t flags;
} MpmTableElmt;

MpmTableElmt mpm_table[MPM_TABLE_SIZE];

        单模:放入 SpmTableElmt spm_table[SPM_TABLE_SIZE] 中;总共有两种,分别注册一些回调函数。实际使用时根据配置只用一种。

enum {
    SPM_BM, /* Boyer-Moore */
    SPM_HS, /* Hyperscan */
    /* Other SPM matchers will go here. */
    SPM_TABLE_SIZE
};

typedef struct SpmTableElmt_ {
    const char *name;
    SpmGlobalThreadCtx *(*InitGlobalThreadCtx)(void);
    void (*DestroyGlobalThreadCtx)(SpmGlobalThreadCtx *g_thread_ctx);
    SpmThreadCtx *(*MakeThreadCtx)(const SpmGlobalThreadCtx *g_thread_ctx);
    void (*DestroyThreadCtx)(SpmThreadCtx *thread_ctx);
    SpmCtx *(*InitCtx)(const uint8_t *needle, uint16_t needle_len, int nocase,
                       SpmGlobalThreadCtx *g_thread_ctx);
    void (*DestroyCtx)(SpmCtx *);
    uint8_t *(*Scan)(const SpmCtx *ctx, SpmThreadCtx *thread_ctx,
                     const uint8_t *haystack, uint32_t haystack_len);
} SpmTableElmt;

extern SpmTableElmt spm_table[SPM_TABLE_SIZE];

根据配置中的匹配方式,初始化相应的单模和多模匹配,其中单模调用其中的 spm_table[matcher].InitGlobalThreadCtx() 回调函数来初始化,多模则会根据 三种协议(TCP,UDP,ICMP)和 两个方向(to_client, to_server)共六个组合分别初始化 mpm_table[matcher].InitCtx(mpm_ctx);

typedef struct AppLayerProtoDetectCtx_ {
    /* Context per ip_proto.
     * \todo Modify ctx_ipp to hold for only tcp and udp. The rest can be
     *       implemented if needed.  Waste of space otherwise. */
    AppLayerProtoDetectCtxIpproto ctx_ipp[FLOW_PROTO_DEFAULT]; //多模扫描

    /* Global SPM thread context prototype. */
    SpmGlobalThreadCtx *spm_global_thread_ctx; //单模扫描

    AppLayerProtoDetectProbingParser *ctx_pp;

    /* Indicates the protocols that have registered themselves
     * for protocol detection.  This table is independent of the
     * ipproto. */
    const char *alproto_names[ALPROTO_MAX];
} AppLayerProtoDetectCtx;

/* The global app layer proto detection context. */
static AppLayerProtoDetectCtx alpd_ctx;

注册应用层协议解析器

:主要是根据应用协议做协议解析,注册各种协议的回调函数,分配相应内存并保存在全局{static AppLayerParserCtx alp_ctx}中

void AppLayerParserRegisterProtocolParsers(void)
{
    SCEnter();

    RegisterHTPParsers();
    RegisterSSLParsers();

    ...

    RegisterRdpParsers();
    RegisterHTTP2Parsers();

    /** IMAP */
    AppLayerProtoDetectRegisterProtocol(ALPROTO_IMAP, "imap");
    if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", "imap")) {
        if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_IMAP,
                                  "1|20|capability", 12, 0, STREAM_TOSERVER) < 0)
        {
            SCLogInfo("imap proto registration failure");
            exit(EXIT_FAILURE);
        }
    } else {
        SCLogInfo("Protocol detection and parser disabled for %s protocol.",
                  "imap");
    }

    ValidateParsers();
    return;
}

加载规则关键字

:void SigTableSetup(void) 函数中执行,规则中各种关键字的注册,如sid, content, http.host 等。

void SigTableSetup(void)
{
    memset(sigmatch_table, 0, sizeof(sigmatch_table));

    DetectSidRegister();
   
    ...

    DetectContentRegister();
    DetectUricontentRegister();

    /* NOTE: the order of these currently affects inspect
     * engine registration order and ultimately the order
     * of inspect engines in the rule. Which in turn affects
     * state keeping */
    DetectHttpUriRegister();
    
    ...

    /* close keyword registration */
    DetectBufferTypeCloseRegistration();
}

/* Table with all SigMatch registrations */
SigTableElmt sigmatch_table[DETECT_TBLSIZE];

初始化queue handler(队列处理函数),这个是衔接线程模块和数据包队列之间的桥梁,目前共有3 类handler:simple,  packetpool, flow。每类handler内部都有一个InHandler和OutHandler,一个用于从上一级队列中获取数据包,另一个用于处理完毕后将数据包送入下一级队列。

enum {
    TMQH_NOT_SET,
    TMQH_SIMPLE,
    TMQH_PACKETPOOL,
    TMQH_FLOW,

    TMQH_SIZE,
};
Tmqh tmqh_table[TMQH_SIZE];

void TmqhSetup (void)
{
    memset(&tmqh_table, 0, sizeof(tmqh_table));

    TmqhSimpleRegister();
    TmqhPacketpoolRegister();
    TmqhFlowRegister();
}

tag初始化

tag作用:根据命中规则的tag信息分流或者是host记录前后的包数据,即标记规则命中之后的指定流量信息,用于指导日志对这些流量进行输出,方便分析(tag的作用和具体用法详情suricata源码之tag_村中少年的专栏-CSDN博客_suricata 源码分析)。

alter标记结构初始化:

/** tag signature we use for tag alerts */
static Signature g_tag_signature;
/** tag packet alert structure for tag alerts */
static PacketAlert g_tag_pa;

void PacketAlertTagInit(void)
{
    memset(&g_tag_signature, 0x00, sizeof(g_tag_signature));

    g_tag_signature.id = TAG_SIG_ID;
    g_tag_signature.gid = TAG_SIG_GEN;
    g_tag_signature.num = TAG_SIG_ID;
    g_tag_signature.rev = 1;
    g_tag_signature.prio = 2;

    memset(&g_tag_pa, 0x00, sizeof(g_tag_pa));

    g_tag_pa.action = ACTION_ALERT;
    g_tag_pa.s = &g_tag_signature;
}

几种存储结构的初始化与注册

StorageInit();TagInitCtx();ThresholdInit();HostBitInitCtx();IPPairBitInitCtx();这几个函数都在干这种事。

typedef enum StorageEnum_ {
    STORAGE_HOST,
    STORAGE_FLOW,
    STORAGE_IPPAIR,
    STORAGE_DEVICE,

    STORAGE_MAX,
} StorageEnum;

typedef struct StorageMapping_ {
    const char *name;
    StorageEnum type; // host, flow, tx, stream, ssn, etc
    unsigned int size;
    void *(*Alloc)(unsigned int);
    void (*Free)(void *);
} StorageMapping;

/** \brief list of StorageMapping used at registration time */
typedef struct StorageList_ {
    StorageMapping map;
    int id;
    struct StorageList_ *next;
} StorageList;

static StorageList *storage_list = NULL;

注册所有模块的函数

模块保存到TmModule tmm_modules[TMM_SIZE];实际线程中数据在一连串的模块中依次执行 slot。

typedef struct TmModule_ {
    const char *name;

    /** thread handling */
    TmEcode (*ThreadInit)(ThreadVars *, const void *, void **);
    void (*ThreadExitPrintStats)(ThreadVars *, void *);
    TmEcode (*ThreadDeinit)(ThreadVars *, void *);

    /** the packet processing function */
    TmEcode (*Func)(ThreadVars *, Packet *, void *);

    TmEcode (*PktAcqLoop)(ThreadVars *, void *, void *);

    /** terminates the capture loop in PktAcqLoop */
    TmEcode (*PktAcqBreakLoop)(ThreadVars *, void *);

    TmEcode (*Management)(ThreadVars *, void *);

    /** global Init/DeInit */
    TmEcode (*Init)(void);
    TmEcode (*DeInit)(void);
#ifdef UNITTESTS
    void (*RegisterTests)(void);
#endif
    uint8_t cap_flags;   /**< Flags to indicate the capability requierment of
                             the given TmModule */
    /* Other flags used by the module */
    uint8_t flags;
} TmModule;

TmModule tmm_modules[TMM_SIZE];

void RegisterAllModules(void)
{
    // zero all module storage
    memset(tmm_modules, 0, TMM_SIZE * sizeof(TmModule));

    /* commanders */
    TmModuleUnixManagerRegister();
    /* managers */
    TmModuleFlowManagerRegister();
    TmModuleFlowRecyclerRegister();
    TmModuleBypassedFlowManagerRegister();
   
    ...

    /* af-packet */
    TmModuleReceiveAFPRegister();
    TmModuleDecodeAFPRegister();
    
    ...

    TmModuleDebugList();
    /* nflog */
    TmModuleReceiveNFLOGRegister();
    TmModuleDecodeNFLOGRegister();

    /* windivert */
    TmModuleReceiveWinDivertRegister();
    TmModuleVerdictWinDivertRegister();
    TmModuleDecodeWinDivertRegister();
}

检测引擎初始化:

获取一个检测引擎实例: 初始化检测引擎,设置对应的单模和多模匹配, 根据suricara.yaml 中{detect:}节点设置相应配置, 初始化改引擎实例中保存SigGroupHeads 的哈希表, 初始化改引擎实例中保存MpmStore 的哈希表,初始化改引擎实例中用来剔除重复符号的哈希表,初始化用于存储解析器结果的字符串表示的哈希表等各种哈希表,初始化 IP Reputation,加载classification.config 配置文件中的classification 规则,加载reference.config 配置文件中的reference 规则。加载规则文件的签名规则

static int LoadSignatures(DetectEngineCtx *de_ctx, SCInstance *suri)
{
    if (SigLoadSignatures(de_ctx, suri->sig_file, suri->sig_file_exclusive) < 0) {
        SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed.");
        if (de_ctx->failure_fatal)
            return TM_ECODE_FAILED;
    }

    return TM_ECODE_OK;
}

 实例化的检测引擎 放入全局的 g_master_de_ctx 中

typedef struct DetectEngineMasterCtx_ {
    SCMutex lock;

    /** enable multi tenant mode */
    int multi_tenant_enabled;

    /** version, incremented after each 'apply to threads' */
    uint32_t version;

    /** list of active detection engines. This list is used to generate the
     *  threads det_ctx's */
    DetectEngineCtx *list;

    /** free list, containing detection engines that will be removed but may
     *  still be referenced by det_ctx's. Freed as soon as all references are
     *  gone. */
    DetectEngineCtx *free_list;

    enum DetectEngineTenantSelectors tenant_selector;

    /** list of tenant mappings. Updated under lock. Used to generate lookup
     *  structures. */
    DetectEngineTenantMapping *tenant_mapping_list;

    /** list of keywords that need thread local ctxs,
     *  only updated by keyword registration at start up. Not
     *  covered by the lock. */
    DetectEngineThreadKeywordCtxItem *keyword_list;
    int keyword_id;
} DetectEngineMasterCtx;

static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER,
    0, 99, NULL, NULL, TENANT_SELECTOR_UNKNOWN, NULL, NULL, 0};

创建工作线程

根据{ 运行模式 + 工作模式 } 获取对应的工作模式RunMode *mode = RunModeGetCustomMode(runmode, custom_mode); 同时mode->RunModeFunc();

执行之前注册数回调函数,例如,这里(RUNMODE_AFP_DEV+ "workers")这种模式将执行RunModeIdsAFPWorkers() 函数,在RunModeSetLiveCaptureWorkersForDevice函数中,根据配置创建多个worker threads。

static int RunModeSetLiveCaptureWorkersForDevice(ConfigIfaceThreadsCountFunc ModThreadsCount,
                              const char *recv_mod_name,
                              const char *decode_mod_name, const char *thread_name,
                              const char *live_dev, void *aconf,
                              unsigned char single_mode)
{
    ...

    /* create the threads */
    for (int thread = 0; thread < threads_count; thread++) {
        
        ...
        
        TmModule *tm_module = NULL;
        ThreadVars *tv = TmThreadCreatePacketHandler(tname,
                "packetpool", "packetpool",
                "packetpool", "packetpool",
                "pktacqloop");
        if (tv == NULL) {
            FatalError(SC_ERR_THREAD_CREATE, "TmThreadsCreate failed");
        }
        tv->printable_name = printable_threadname;

        tm_module = TmModuleGetByName(recv_mod_name);
        if (tm_module == NULL) {
            FatalError(SC_ERR_INVALID_VALUE, "TmModuleGetByName failed for %s", recv_mod_name);
        }
        TmSlotSetFuncAppend(tv, tm_module, aconf);

        tm_module = TmModuleGetByName(decode_mod_name);
        if (tm_module == NULL) {
            FatalError(SC_ERR_INVALID_VALUE, "TmModuleGetByName %s failed", decode_mod_name);
        }
        TmSlotSetFuncAppend(tv, tm_module, NULL);

        tm_module = TmModuleGetByName("FlowWorker");
        if (tm_module == NULL) {
            FatalError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed");
        }
        
        ...

        if (TmThreadSpawn(tv) != TM_ECODE_OK) {
            FatalError(SC_ERR_THREAD_SPAWN, "TmThreadSpawn failed");
        }
    }

    return 0;
}

首先创建在每个工作线程结构 ThreadVars *tv(创建是将线程tv->flags 设置为THV_PAUSE,目的是在后续的子线程创建完成后,在所有的初始完成才运行线程逻辑),在对应的tv 中添加一系列TmSlot。

 TmSlot的添加:根据 recv->decode->FlowWorker 相应的模块找到对饮的TmModule,在调用void TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, const void *data)函数添加:

void TmSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, const void *data)
{
    TmSlot *slot = SCMalloc(sizeof(TmSlot));
    if (unlikely(slot == NULL))
        return;
    memset(slot, 0, sizeof(TmSlot));
    SC_ATOMIC_INITPTR(slot->slot_data);
    slot->SlotThreadInit = tm->ThreadInit;
    slot->slot_initdata = data;
    if (tm->Func) {
        slot->SlotFunc = tm->Func;
    } else if (tm->PktAcqLoop) {
        slot->PktAcqLoop = tm->PktAcqLoop;
    } else if (tm->Management) {
        slot->Management = tm->Management;
    }
    slot->SlotThreadExitPrintStats = tm->ThreadExitPrintStats;
    slot->SlotThreadDeinit = tm->ThreadDeinit;
    /* we don't have to check for the return value "-1".  We wouldn't have
     * received a TM as arg, if it didn't exist */
    slot->tm_id = TmModuleGetIDForTM(tm);

    tv->tmm_flags |= tm->flags;
    tv->cap_flags |= tm->cap_flags;

    if (tv->tm_slots == NULL) {
        tv->tm_slots = slot;
    } else {
        TmSlot *a = (TmSlot *)tv->tm_slots, *b = NULL;

        /* get the last slot */
        for ( ; a != NULL; a = a->slot_next) {
             b = a;
        }
        /* append the new slot */
        if (b != NULL) {
            b->slot_next = slot;
        }
    }
    return;
}

新建一个 TmSlot *slot,将找到的TmModule 中的函数指针赋值给slot对应的函数指针,并把slot节点加入到tv->tm_slots队列中,这一个 slot 与 相应模块的 TmModule *tm是对应的。

在TmEcode TmThreadSpawn(ThreadVars *tv)函数中创建子线程线程(线程函数为tv->tm_func()绑定的回调函数,函数内部绑定cpu,初始化并等待tv->flags 取消THV_PAUSE), 同时将此线程结构tv 放入ThreadVars *tv_root[TVT_MAX] 中管理,worker threads的类型为TVT_PPT。

TmEcode TmThreadSpawn(ThreadVars *tv)
{
    pthread_attr_t attr;
    if (tv->tm_func == NULL) {
        printf("ERROR: no thread function set\n");
        return TM_ECODE_FAILED;
    }

    /* Initialize and set thread detached attribute */
    pthread_attr_init(&attr);

    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    int rc = pthread_create(&tv->t, &attr, tv->tm_func, (void *)tv);
    if (rc) {
        printf("ERROR; return code from pthread_create() is %" PRId32 "\n", rc);
        return TM_ECODE_FAILED;
    }

    TmThreadWaitForFlag(tv, THV_INIT_DONE | THV_RUNNING_DONE);

    TmThreadAppend(tv, tv->type);
    return TM_ECODE_OK;
}
enum {
    TVT_PPT,
    TVT_MGMT,
    TVT_CMD,
    TVT_MAX,
};
/* root of the threadvars list */
ThreadVars *tv_root[TVT_MAX] = { NULL };

创建非工作线程的子线程

 FlowManager线程,FlowRecycler线程, UnixManager线程,wakeup线程, management线程等,创建方法同worker threas的创建。子线程循环函数为tv->tm_func(),在此函数中完成线程的初始化,然后等待线程的 tv->flags 设置为非 THV_PAUSE状态后再执行线程逻辑。

    if (runmode != RUNMODE_UNIX_SOCKET) {
        /* spawn management threads */
        FlowManagerThreadSpawn();
        FlowRecyclerThreadSpawn();
        if (RunModeNeedsBypassManager()) {
            BypassedFlowManagerThreadSpawn();
        }
        StatsSpawnThreads();
    }

各子线程函数 tv->tm_func() 对应的回调函数:slot 中的回调函数取自之前注册的 TmModule,各线程的功能见下表:

序号 线程类型 name 线程数量

tv->type

tv->tm_func()对应的函数 tv->tm_slots 对应的slot表(TmModule) 备注
1 worker threads W

suricata.yaml

threading配置

packetpool

TVT_PPT TmThreadsSlotPktAcqLoop

Receive

->Decode->FlowWorker
2 FlowManagerThread FM

suricata.yaml

flow.managers

management

TVT_MGMT

TmThreadsManagement FlowManager 默认为1个
3 FlowRecyclerThread FR

suricata.yaml

flow.recyclers

management

TVT_MGMT

TmThreadsManagement FlowRecycler 默认为1个
4 BypassedFlowManagerThread FB 1

management

TVT_MGMT

TmThreadsManagement BypassedFlowManager
5

StatsWakeupThread

CW 1

custom

TVT_MGMT

StatsWakeupThread

6

StatsMgmtThread

CS 1

custom

TVT_MGMT

StatsMgmtThread

7

UnixManagerThread

US

2 or 0

command

TVT_CMD

TmThreadsManagement

UnixManager

RUNMODE_UNIX_SOCKET

mode是才创建,否则没有

8

DetectLoaderThread

DL

suricata.yaml

multi-detect.loaders 

or 0

command

TVT_CMD

TmThreadsManagement

DetectLoader

MT(多租户)被启用才创建,默认的配置没有此项。

所有子线程创建完成后,等待所有子线程初始化完成,设置max_pending_return_packets值  ,取消所有线程的暂停标志,这样所有线程都能愉快的玩耍了。

主线程进入主循环:

        主循环中处理SIGTERM(kill 不加参数)、SIGINT(ctrl + c)信号,当有这两个信号中的其中之一时,退出主循环,此时程序优雅的退出;

        检测 上面的各个子线程的状态,若有线程为 THV_FAILED状态(线程遇到错误并失败),这是退出程序,exit(0),不优雅;

        处理SIGHUP 信号

        处理SIGUSR2 信号,以用来动态加载规则,发送信号方式 { kill -USR2 $(pidof suricata) };

主循环退出后,关闭所有子线程,释放所有的资源,程序优雅的退出,至此,主线程完结!


  凡是过往,即为序章

你可能感兴趣的:(suricata,网络安全,suricata)