Suricata 源码阅读笔记:main ()
2023-1-4 00:4:58 Author: 每天一个入狱小技巧(查看原文) 阅读量:8 收藏

main () 函数位于 suricata.c 文件,其主要流程如下:

1. 定义并初始化程序的全局实例变量。

  • SCInstance 类型的 suri 变量用来保存程序当前的一些状态、标志等上下文环境,通常是用来作为参数传递给各个模块的子函数,因此为了更好的封装性而放到一个结构体变量中,而不是使用零散的长串参数或一堆全局变量。

  • SCInstanceInit 函数,顾名思义,即是对 suri 中各个字段进行初始化。注意,这里对所有字段都进行了显示初始化,因为虽然一个 memset 清零已经基本达到目的了,但显示地将各个成员设成 0/NULL/FALSE 对于可读性来说还是有好处的,可以明确地说明各个字段的初始值,且对扩展性也会有好处,例如若后续初始化需要设置一些非 0 值(如用 - 1 表示无效值),直接更改就好了。

2. 初始化 sc_set_caps 为 FALSE –> 标识是否对主线程进行特权去除(drop privilege),主要是出于安全性考虑。

3. 初始化原子变量 engine_stage –> 记录程序当前的运行阶段:SURICATA_INIT、SURICATA_RUNTIME、SURICATA_FINALIZE

4. 初始化日志模块,因为后续的执行流程中将使用日志输出,所以需要最先初始化该模块。

5. 设置当前主线程名字为 “Suricata-Main”。线程名字还是挺重要的,至少在 gdb 调试时 info threads 可以看到各个线程名,从而可以精确地找到想要查看的线程。另外,在 top -H 时,也能够显示出线程名字(然而 ps -efL 时貌似还是只是显示进程名)。

6. 初始化 ParserSize 模块 –> 使用正则表达式来解析类似 “10Mb” 这种大小参数,其中正则引擎用的是 pcre,因此初始化时就是调用 pcre_compile、pcre_study 对已经写好的正则表达式进行编译和预处理。

7. 注册各种运行模式。Suricata 对 “运行模式” 这个概念也进行了封装。运行模式存储在 runmodes 数组中,定义为 RunModes runmodes [RUNMODE_USER_MAX]。

  • 首先,数组中每一项(例如 runmodes [RUNMODE_PCAP_DEV]),对应一组运行模式,模式组包括(RunModes 类型):“IDS+Pcap” 模式组、“File+Pcap” 模式组、“UnixSocket” 模式组等(另外还有其他一些内部模式,如:“列出关键字” 模式、“打印版本号” 模式等,这些没有存储在 runmodes 数组中)。

  • 然后,每一个模式组,其中可以包含若干个运行模式(RunMode 类型),例如:single、auto、autofp、workers。

  • 运行模式的注册,则是为各个模式组(如 RunModeIdsPcapRegister)添加其所支持的运行模式(通过调用 RunModeRegisterNewRunMode),并定义改组的默认运行模式,以及非常重要的:注册各个模式下的初始化函数(如 RunModeIdsPcapSingle),等后续初始化阶段确定了具体的运行模式后,就会调用这里注册的对应的初始化函数,对该模式下的运行环境进行进一步配置。

8. 初始化引擎模式为 IDS 模式。引擎模式只有两种:IDS、IPS,初始默认为 IDS,而在 nfq 或 ipfw 启用时,就会切换成 IPS 模式,该模式下能够执行 “Drop” 操作,即拦截数据包。

9. 初始化配置模块,为配置节点树建立 root 节点。

10. 解析命令行参数。其中,与包捕获相关的选项(如 “-i”)都会调用 LiveRegisterDevice,以注册一个数据包捕获设备接口(如 eth0)。全局的所有已注册的设备接口存储在变量 live_devices 中,类型为 LiveDevice。注意,用多设备同时捕获数据包这个特性在 Suricata 中目前还只是实验性的。“-v” 选项可多次使用,每个 v 都能将当前日志等级提升一级。

11. 若运行模式为内部模式,则进入该模式执行,完毕后退出程序。

12. FinalizeRunMode,即为运行模式的处理划上句号。主要是设置 offline 标志、对 unknown 运行模式进行报错,以及设置全局的 run_mode 变量。

13. 若运行模式为单元测试模式,则跑(用户通过正则表达式指定的)单元测试,并输出测试结果。

14. 检查当前模式是否与 daemon 标志冲突。Pcap 文件模式及单元测试模式都不能在 daemon 开启下进行。

15. 初始化全局变量。包括:数据包队列 trans_q、数据队列 data_queues(干嘛的?)、对应的 mutex 和 cond、建立小写字母表。

16. 初始化时间。包括:获取当前时间所用的 spin lock,以及设置时区(调用 tzset () 即可)。

17. 为快速模式匹配注册关键字。调用 SupportFastPatternForSigMatchList 函数,按照优先级大小插入到 sm_fp_support_smlist_list 链表中。

18. 若用户未在输入参数中指定配置文件,则使用默认配置文件(/etc/suricata/suricata.yaml)。

19. 调用 LoadYamlConfig 读取 Yaml 格式配置文件。Yaml 格式解析是通过 libyaml 库来完成的,解析的结果存储在配置节点树(见 conf.c)中。对 include 机制的支持:在第一遍调用 ConfYamlLoadFile 载入主配置文件后,将在当前配置节点树中搜寻 “include” 节点,并对其每个子节点的值(即通过 include 语句所指定的子配置文件路径),同样调用 ConfYamlLoadFile 进行载入。

20. 再次初始化日志模块。这次,程序将会根据配置文件中日志输出配置(logging.outputs)填充 SCLogInitData 类型的结构体,调用 SCLogInitLogModule 重新初始化日志模块。

21. 打印版本信息。这是 Suricata 启动开始后第一条打印信息

22. 打印当前机器的 CPU / 核个数,这些信息是通过 sysconf 系统函数获取的。

23. 若运行模式为 DUMP_CONFIG,则调用 ConfDump 打印出当前的所有配置信息。ConfDump 通过递归调用 ConfNodeDump 函数实现对配置节点树的 DFS(深度优先遍历)。

24. 执行 PostConfLoadedSetup,即运行那些需要在配置载入完成后就立马执行的函数。这里面涉及的流程和函数非常多:

  • MpmTableSetup:设置多模式匹配表,该表中每一项就是一个实现了某种多模式匹配算法(如 WuManber、AC)的匹配器。以注册 AC 匹配器为例,MpmTableSetup 会调用 MpmACRegister 函数实现 AC 注册,函数内部其实只是填充 mpm_table 中对应 AC 的那一项(mpm_table [MPM_AC])的各个字段,如:匹配器名称("ac")、初始化函数(SCACInitCtx)、增加模式函数(SCACAddPatternCS)、实际的搜索执行函数(SCACSearch)。

  • 设置 rule_reload 标志。如果配置文件中对应选项打开,则会设置该标志,表示可以进行 “规则热重载”,即能够在程序运行时载入或替换规则集。

  • AppLayerDetectProtoThreadInit:初始化应用层协议检测模块。其中,AlpProtoInit 函数初始化该模块所用到的多模式匹配器,RegisterAppLayerParsers 函数注册各种应用层协议的解析器(如 RegisterHTPParsers 函数对应 HTTP 协议),而 AlpProtoFinalizeGlobal 函数完成一些收尾工作,包括调用匹配器的预处理(Prepare)函数、建立模式 ID 和规则签名之间的映射等。

  • AppLayerParsersInitPostProcess:这个函数内部建立了一个解析器之间的映射,还不太懂其用途。

  • 设置并验证日志存储目录是否存在。若配置文件中未指定,则使用默认目录,linux 下默认为 /var/log/suricata。

  • 获取与包捕获相关的一些配置参数,目前包括:max-pending-packets、default-packet-size。

  • 设置 host_mode(主机模式),两种模式:router 和 sniffer-only,而如果设置为 “auto”,则会进行自动选择:IPS 模式下运行为 router,否则为 sniffer-only。

  • SCHInfoLoadFromConfig:从配置文件中载入 host os policy (主机 OS 策略) 信息。网络入侵通常是针对某些特定 OS 的漏洞,因此如果能够获取部署环境中主机的 OS 信息,肯定对入侵检测大有裨益。具体这些信息是怎么使用的,暂时也还不清楚。

  • DefragInit:初始化 IP 分片重组模块。

  • SigTableSetup:初始化检测引擎,主要是注册检测引擎所支持的规则格式(跟 Snort 规则基本一致)中的关键字,比如 sid、priority、msg、within、distance 等等。

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

  • StorageInit:初始化存储模块,这个模块可以用来临时存储一些数据,数据类型目前有两种:host、flow。具体在何种场景下用,目前未知。

  • CIDRInit:初始化 CIDR 掩码数组,cidrs [i] 对应前 i 位为 1 的掩码。

  • SigParsePrepare:为规则签名解析器的正则表达式进行编译 (pcre_compile) 和预处理 (pcre_study)。

  • SCPerfInitCounterApi:初始化性能计数器模块。这个模块实现了累加计数器(例如统计收到的数据包个数、字节数)、平均值计数器(统计平均包长、处理时间)、最大计数器(最大包长、处理时间)、基于时间间隔的计数器(当前流量速率)等,默认输出到日志目录下的 stats.log 文件。

  • 几个 Profiling 模块的初始化函数。Profiling 模块提供内建的模块性能分析功能,可以用来分析模块性能、各种锁的实际使用情况(竞争时间)、规则的性能等。

  • SCReputationInitCtx:初始化 IP 声望模块。IP 声望数据在内部是以 Radix tree 的形式存储的,但目前还不知道数据源是从哪来的,而且也没看到这个模块的函数在哪调用。

  • SCProtoNameInit:读取 /etc/protocols 文件,建立 IP 层所承载的上层协议号和协议名的映射(如 6-> ”TCP”,17-> ”UDP“)。

  • TagInitCtx、ThresholdInit:与规则中的 tag、threshould 关键字的实现相关,这里用到了 Storage 模块,调用 HostStorageRegister 和 FlowStorageRegister 注册了几个(与流 / 主机绑定的?)存储区域。

  • DetectAddressTestConfVars、DetectPortTestConfVars:检查配置文件中 "vars" 选项下所预定义的一些 IP 地址(如局域网地址块)、端口变量(如 HTTP 端口号)是否符合格式要求。

  • RegisterAllModules:这是个非常重要的函数!里面注册了 Suricata 所支持的所有线程模块(Thread Module)。以 pcap 相关模块为例,TmModuleReceivePcapRegister 函数注册了 Pcap 捕获模块,而 TmModuleDecodePcapRegister 函数注册了 Pcap 数据包解码模块。所谓注册,就是在 tmm_modules 模块数组中对应的那项中填充 TmModule 结构的所有字段,这些字段包括:模块名字、线程初始化函数、包处理或包获取函数、线程退出清理函数、一些标志位等等。

  • AppLayerHtpNeedFileInspection:设置 suricata 内部模块与 libhtp(HTTP 处理库)对接关系的函数,具体细节暂时不管。

  • DetectEngineRegisterAppInspectionEngines:名字都这么长了,肯定很复杂。。。暂时不管。

  • 若设置了 rule_reload 标志,则注册相应的信号处理函数(目前设置的函数都是些提示函数,没有做实际重载)。这里用的是比较惯用的 SIGUSR2 信号来触发 rule reload。

  • StorageFinalize:关闭 storage 模块的注册,为已注册的 storage 实际分配存储空间。

  • TmModuleRunInit:调用之前注册的线程模块的初始化函数进行初始化。

25. 检查是否进入 Daemon 模式。若需要进入 Daemon 模式,则会检测 pidfile 是否已经存在(daemon 下只能有一个实例运行),然后进行 Daemonize,最后创建一个 pidfile。Daemonize 的主要思路是:fork-> 子进程调用 setsid 创建一个新的 session,关闭 stdin、stdout、stderr,并告诉父进程 –> 父进程等待子进程通知,然后退出 –> 子进程继续执行。

26. 初始化信号 handler。首先为 SIGINT(ctrl-c 触发)和 SIGTERM(不带参数 kill 时触发)这两个常规退出信号分别注册 handler,对 SIGINT 的处理是设置程序的状态标志为 STOP,即让程序优雅地退出;而对 SIGTERM 是设置为 KILL,即强杀。接着,程序会忽略 SIGPIPE(这个信号通常是在 Socket 通信时向已关闭的连接另一端发送数据时收到)和 SIGSYS(当进程尝试执行一个不存在的系统调用时收到)信号,以加强程序的容错性和健壮性。

27. 获取配置文件中指定的 Suricata 运行时的 user 和 group,如果命令行中没有指定的话。然后,将指定的 user 和 group 通过 getpwuid、getpwnam、getgrnam 等函数转换为 uid 和 gid,为后续的实际设置 uid 和 gid 做准备。注意,这段代码也是在 InitSignalHandler 中执行的,不知道为什么放这里,跟信号有关系么。。。

28. 初始化 Packet pool,即预分配一些 Packet 结构体,分配的数目由之前配置的 max_pending_packets 确定,而数据包的数据大小由 default_packet_size 确定(一个包的总占用空间为 default_packet_size+sizeof (Packet))。在调用 PacketGetFromAlloc 新建并初始化一个数据包后,再调用 PacketPoolStorePacket 将该数据包存入 ringbuffer。Suricata 中用于数据包池的 Ring Buffer 类型为 RingBuffer16,即容量为 2^16=65536(但为什么 max_pending_packets 的最大值被限定为 65534 呢?)。

29. 初始化 Host engine。这货好像跟之前的 host 类型的 storage 有关系,具体怎么用后面再看看吧。

30. 初始化 Flow engine。跟前面的 host 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 时间。

31. 初始化 Decect engine。若配置文件中未指定 mpm (多模式匹配器),则默认使用 AC,即使用 mpm_table 中 AC 那一项。SRepInit 函数(与前面的 SCReputationInitCtx 不同!)会初始化检测引擎中域 reputaion 相关信息,即从配置文件中指定的文件中读取声望数据。其余配置比较复杂,暂不关注。

32. 读取和解析 classification.config 和 reference.config,这两个文件用于支持规则格式中的 classification(规则分类)和 refercence(规则参考资料)字段。

33. 设置规则的动作优先级顺序,默认为 Pass->Drop->Reject->Alert。举例来说,若有一条 Pass 规则和 Drop 规则都匹配到了某个数据库,则会优先应用 Pass 规则。

34. 初始化 Magic 模块。Magic 模块只是对 libmagic 库进行了一层封装,通过文件中的 magic 字段来检测文件的类型(如”PDF-1.3“对应 PDF 文件)。

35. 设置是否延迟检测。若 delayed-detect 为 yes,则系统将在载入规则集之前就开始处理数据包,这样能够在 IPS 模式下将少系统的 down time(宕机时间)。

36. 如果没有设置延迟检测,就调用 LoadSignatures 载入规则集

37. 如果设置了 live_reload,则重新注册用于规则重载的 SIGUSR2 信号处理函数(这次是设置为真正的重载处理函数)。放在这里是为了防止在初次载入规则集时就被触发重载。

38. 初始化 ASN.1 解码模块。Wikipedia:ASN.1(Abstract Syntax Notation One) 是一套标准,是描述数据的示、编码、传输、解码的灵活的记法。应用层协议如 X.400(email)、X.500 和 LDAP(目录服务)、H.323(VoIP)和 SNMP 使用 ASN.1 描述它们交互的协议数据单元。

39. 处理 CoreDump 相关配置。Linux 下可用 prctl 函数获取和设置进程 dumpable 状态,设置 corefile 大小则是通过通用的 setrlimit 函数。

40. 调用 gettimeofday 保存当前时间,存储在 suri->start_time 中,作为系统的启动时间。

41. 去除主线程的权限。这个是通过 libcap-ng 实现的,首先调用 capng_clear 清空所有权限,然后根据运行模式添加一些必要权限(主要是为了抓包),最后调用 capng_change_id 设置新的 uid 和 gid。主线程的权限应该会被新建的子线程继承,因此只需要在主线程设置即可。

42. 初始化所有 Output 模块。这些模块之前在线程模块注册函数里已经都注册了,这里会根据配置文件再进行配置和初始化,最后把当前配置下启用了的 output 模块放到 RunModeOutputs 链表中。

43. 若当前抓包模式下未指定设备接口(通过 - i <dev> 或 --pcap=<dev > 等方式),则解析配置文件中指定的 Interface,并调用 LiveRegisterDevice 对其进行注册。

44. 若当前的模式为 CONF_TEST,即测试配置文件是否有效,则现在就可以退出了。这也说明,程序运行到这里,配置工作已经基本完成了。

45. 初始化运行模式。首先,根据配置文件和程序中的默认值来配置运行模式(single、auto 这些),而运行模式类型(PCAP_DEV、PCAPFILE 这些)也在之前已经确定了,因此运行模式已经固定下来,可以从 runmodes 表中获取到特定的 RunMode 了,接着就调用 RunMode 中的 RunModeFunc,进入当前运行模式的初始化函数。以 PCAP_DEV 类型下的 autofp 模式为例,该模式的初始化函数为:RunModeIdsPcapAutoFp。这个函数的执行流程为:

  • 调用 RunModeInitialize 进行通用的运行模式初始化,目前主要是设置 CPU affinity 和 threading_detect_ratio。

  • 调用 RunModeSetLiveCaptureAutoFp 设置该模式下的模块组合

    • 线程名字为 "Detect"+i,每个线程都有与一个输入队列绑定,即 inq 设置为 "pickup"+i 队列。

    • inqh 设置为 "flow",即使用 flow 类型(与前面的抓包线程相匹配)的 queue handler 作为线程的输入队列处理器。

    • outq、outqh 都设置为 "packetpool",表示这个线程的包处理完后会直接回收到 packet pool 中去。

    • slots 函数设置为 "varslot",表示这个线程的插槽类型为 varslot,对应的执行函数为 TmThreadsSlotVar。

    • 接着,跟上面类似,把 "StreamTcp"(用于 TCP 会话跟踪、重组等)、"Detect"(调用检测引擎进行实际的入侵检测)和 "RespondReject"(用于通过主动应答来拒绝连接)这三个线程模块嵌入进去。不过,这里在插入 “Detect” 模块时,调用的是 TmSlotSetFuncAppendDelayed,用于支持 delayed-detect 功能。

    • SetupOutputs:由于这组检测线程是处理数据包的完结之处,因此这里需要把输出模块也嵌入到这些线程中去,方式也是通过 TmSlotSetFuncAppend 函数,对象是 RunModeOutputs 中存储的输出模块。

    • TmThreadCreatePacketHandler 函数专门用于创建包处理线程,函数内部会调用通用的 TmThreadCreate 创建线程,并将线程类型设置为 TVT_PPT

    • 线程名字为 "RxPcap"+ 接口名 + i,如 “RxPcapeth01”。

    • inq、inqh 都设置为 "packetpool",表示将从数据包池(而不是某个数据包队列)中获取包。

    • outqh 设置为 "flow",表示使用之前注册的 flow 类型的 queue handler 作为线程的输出队列处理器,这个类型可以保证同一条 flow 的包都会输出给同一个 queue,具体的包调度策略取决于 autop-scheduler 指定的算法。

    • outq 设置为前面所设置的接收队列名字符串,而之前的 flow 类型 handler 的 TmqhOutputFlowSetupCtx 函数将会解析队列名字符串,并创建出相应个数(threads_max)的队列。

    • slots 函数设置为 "pktacqloop",表示这个线程的插槽类型为 pktacqloop,这样在 TmThreadSetSlots 函数中就会将线程执行函数(tm_func)设置为针对该插槽类型的 TmThreadsSlotPktAcqLoop 函数。最终线程在被 pthread_create 执行时传入的回调函数就是这个线程执行函数。

    • TmSlotSetFuncAppend:将 “ReceivePcap"和"DecodePcap" 这两个线程模块嵌入到前面创建的每个抓包线程的插槽中去。

    • TmThreadSetCPU:设置线程的 CPU 相关参数。

    • TmThreadSpawn:按照之前所填充好的 ThreadVars 生成实际的线程,并将该线程添加到全局线程数组 tv_root 中去。

    • 确实参数:接口个数 nlive、线程个数 thread_max(由用户指定,或 CPU 个数决定)。

    • RunmodeAutoFpCreatePickupQueuesString:创建一个包含 thread_max 个接收队列名字的字符串,如 "pickup1,pickup2,pickup3"。

    • ParsePcapConfig:解析 pcap 接口相关配置,如 buffer-size、bpf-filter、promisc 等。

    • PcapConfigGeThreadsCount:获取 pcap 接口配置中指定的 threads(抓包线程个数,默认为 1),保存到 threads_count 变量。

    • 创造 threads_count 个抓包线程

    • 创造 thread_max 个检测线程

46. 若 unix-command 为 enable 状态,则创建 Unix-socket 命令线程,可与 suricata 客户端使用 JSON 格式信息进行通信。命令线程的创建是通过 TmThreadCreateCmdThread 函数,创建的线程类型为 TVT_CMD。线程执行函数为 UnixManagerThread

47. 创建 Flow 管理线程,用于对流表进行超时删除处理。管理线程创建是通过 TmThreadCreateMgmtThread 函数,类型为 TVT_MGMT,执行函数为 FlowManagerThread

48. 初始化 Stream TCP 模块。其中调用了 StreamTcpReassembleInit 函数进行重组模块初始化。

49. 创建性能计数相关线程,包括一个定期对各计数器进行同步的唤醒线程(SCPerfWakeupThread),和一个定期输出计数值的管理线程(SCPerfMgmtThread)。

50. 检查数据包队列的状态是否有效:每个数据包队列都应该至少有一个 reader 和一个 writer。在前面线程绑定 inq 时会增加其 reader_cnt,绑定 outq 时会增加其 writer_cnt。

51. 等待子线程初始化完成。检查是否初始化完成的方式是遍历 tv_root,调用 TmThreadsCheckFlag 检查子线程的状态标志。

52. 更新 engine_stage 为 SURICATA_RUNTIME,即程序已经初始化完成,进入运转状态。这里的更新用的是原子 CAS 操作,防止并发更新导致状态不一致(但目前没在代码中只到到主线程有更新 engine_stage 操作,不存在并发更新)。

53. 让目前处于 paused 状态的线程继续执行。在 TmThreadCreate 中,线程的初始状态设置为了 PAUSE,因此初始化完成后就会等待主线程调用 TmThreadContinue 让其继续。从这以后,各线程就开始正式执行其主流程了。

54. 若设置了 delayed_detect,则现在开始调用 LoadSignatures 加载规则集,激活检测线程,并注册 rule_reload 信号处理函数。这里,激活检测线程是通过调用 TmThreadActivateDummySlot 函数,这个函数会将之前注册的 slot 中的 slotFunc 替换为实际操作函数,而不是原先在 delayed_detect 情况下设置的什么都不做的 TmDummyFunc。

55. 进入死循环。若受到引擎退出信号(SURICATA_KILL 或 SURICATA_STOP),则退出循环,执行后续退出操作,否则就调用 TmThreadCheckThreadState 检查各线程的状态,决定是否进行结束线程、重启线程、终止程序等操作,然后 usleep 一会儿(1s),继续循环。

56. 接着,程序就进入到了退出阶段,首先会更新 engine_stage 为 SURICATA_DEINIT,然后依次关闭 Unix-socket 线程、Flow 管理线程。

57. 停止包含抓包或解码线程模块的线程。这个是通过 TmThreadDisableThreadsWithTMS 实现,里面会检查每个线程的 slots 里嵌入的线程模块的 flags 中是否包含指定的 flag(这里是 TM_FLAG_RECEIVE_TM 或 TM_FLAG_DECODE_TM),一个线程模块的 flags 在注册时就已经指定了。关闭是通过向线程发送 KILL 信号(设置线程变量的 THV_KILL 标志)实现,收到该信号的线程会进入 RUNNING_DONE 状态,然后等待主线程下一步发出 DEINIT 信号。

58. 强制对仍有未处理的分段的流进行重组。

59. 打印进程运行的总时间(elapsed time)。

60. 在 rule_reload 开启下,首先同样调用 TmThreadDisableThreadsWithTMS 停止检测线程。特别地,该函数对于 inq 不为 "packetpool" 的线程(即该线程从一个 PakcetQueue 中获取数据包),会等到 inq 中的数据包都处理完毕再关闭这个线程。然后,检测是否 reload 正在进行,如果是则等待其完成,即不去打断它。

61. 杀死所有子线程。杀死线程的函数为 TmThreadKillThread,这个函数会同时向子线程发出 KILL 和 DEINIT 信号,然后等待子线程进入 CLOSED 状态,之后,再调用线程的清理函数(InShutdownHandler)以及其对应的 ouqh 的清理函数(OutHandlerCtxFree),最后调用 pthread_join 等待子线程退出。

62. 执行一大堆清理函数:清理性能计数模块、关闭 Flow engine、清理 StreamTCP、关闭 Host engine、清理 HTP 模块并打印状态、移除 PID 文件、关闭检测引擎、清理应用层识别模块、清理 Tag 环境、关闭所有输出模块,etc…

63. 调用 exit 以 engine_retval 为退出状态终止程序

转自:https://my.oschina.net/openadrian/blog/184621

    本公众号发布的靶场、文章项目中涉及的任何脚本工具,仅用于测试和学习研究,禁止用于商业用途不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断;

     本文章、项目内场所有资源文件,杜绝任何靶本公众号、自媒体进行形式的擅自转载、发布

    本公众号对任何脚本及工具问题概不负责,包括不限于由任何脚本错误导致的任何损失或损害及任何法律责任;

    直接使用本或公众发布的技术、靶场、文章项目中涉及的脚本工具,但在某些行为不符合任何国家/地区或相关地区的情况下进行传播时,引发的隐私或其他任何法律问题的后果概不负责;

    如果任何单位或个人认为项目或文章的内容可能侵犯其权利,则应及时通知并证明其身份,证明我们将在收到证明文件后删除相关内容;

    以任何方式查看或使用此项目的人或直接或间接使用项目的任何脚本的使用者都应仔细阅读此声明;

     本公众号保留更改或补充,免责随时声明的权利;

    一旦您访问或使用访问本公众号任何项目,则视为您已接受此免责声明。

     您在本声明未发出之时,使用或者访问了本公众号任何项目 ,则视为已接受此声明,请仔细阅读。

                                                                                         此致

    由于、利用的信息而造成的任何或直接的此文传播后果,均由用户本人负责,作者不承担任何直接责任。

一切法律后果均由攻击者承担!!!

日站不规范,亲人两行泪!!!

日站不规范,亲人两行泪!!!

日站不规范,亲人两行泪!!!

专注于信息安全方面分享,非营利性组织,不接任何商业广告

关注不迷,点赞!关注!转向!评论!!

要投稿的请留言或者加微信,会第一时间回复,谢谢


文章来源: http://mp.weixin.qq.com/s?__biz=Mzg2MzYzNjEyMg==&mid=2247487032&idx=1&sn=c38e254770bc5b14c5521cf50deec4e7&chksm=ce74d1cdf90358dbb897bbd9f0662dbf8b37cb6049ba65fca59444544f38fe0384038c51db84#rd
如有侵权请联系:admin#unsafe.sh