suricata 程序架构

Suricata是一款高性能网络入侵检测防御引擎。该引擎基于多线程,充分利用多核优势。它支持多种协议,如:ip4、ipv6、tcp、udp、http、smtp、pop3、imap、ftp等。可动态加载预设规则,支持多种文件格式统计数据输出,如pcap、json、unified2等,非常便于与Barnyard2等工具集成。

图1


图2

1.运行模式(runmode)

Suricata有多种运行模式,这些模式与抓包驱动和IDS/IPS选择相关联。抓包驱动如:pcap, pcap file, nfqueue,ipfw, dpdk或者一个特有的抓包驱动等。Suricata在启动时只能选择某个运行模式。如-i选项表示pcap, -r表示pcapfile,-q表示nfqueue等。

每一种运行模式都会初始化一些threads,queues等。模式的具体任务是由线程模块来完成。根据线程和线程模块的组织方式的不同,运行模式又细分为"autofp", "single","wokers".

图3

从上面的流程图可看出,“autofp”模式属于最高效的模式,但也是最复杂的模式。"worker“适中。

2.packet流水线

抓包模块收集packets并进行简单封装,再将其传递Decode模块,Decode模块根据packet的链路类型,解码出对应上层协议(IP,ICMP,TCP,UDP等),处理后的结果将被继续传递给下一个处理模块。

3.线程模块

线程模块是对packet处理任务的抽象。线程模块大概有以下几种:

        1.Receive模块:收集网络数据包,封装成Packet对象后将其传递给Decode线程模块

        2.Decode模块:对Packet按协议4层模型(数据链路层、网络层、传输层、应用层)进行解码,获取协议和负荷信息,解码完成后将Packet传递给FlowWorker线程模块。该模块主要是进行packet解码,不处理应用层。应用层由专门的应用层解码模块处理

        3.FlowWorker模块:对packets进行分配flow,Tcp会话管理,TCP重组,应用层数据解析处理,Detect规则检测

        4.Verdict模块:根据Detect模块检测的结果,对drop标记的包需要做丢弃处理

        5.RespondReject模块:根据detect检测后的结果,对于reject的包需要向双端发送reset包

        6.logs模块:将处理结果记录在日志中。

4.线程模块间的数据传递

同线程内的模块之间主要是以参数的形式进行数据传递,不同线程之间以共享队列的方式进行数据传递。

每个线程由ThreaVars结构体来抽象,ThreadVars对象指定线程输入数据队列inq和输出数据队列outq。

这些队列在多个线程之间进行共享,一个线程的输出队列可能是另一个线程的输入队列。

图4

绿色线条表示数据的走向。从输入队列获取数据包packet,经过slot函数(模块函数)的处理后,再将加工后的packet放到输出队列中。

在autofp模式下数据包的传递路径如下:

图5

蓝色线条表示packet的传递路径。

5.autofp模式研究

图6

5.1 RX thread

从上面"autofp"模式中可以看出RX thread所处的位置和包含的功能模块。它主要用于收集packets并对其进行解码,将处理后的packets放到pickup queue中,以供下个模块使用.

图7

RX thread的作用体现为线程函数-TmThreadsSlotPktAcqLoop,主要执行的任务为:

        1.给线程设置一个有意义的名称;

        2.将线程绑定到指定CPU核心;

        3.创建Packet对象池,用于快速存放网络数据包数据;

        4.初始化与该线程关联的线程模块;

        5.调用数据包收集模块,启动数据包收集,依次调用各模块处理packet,然后将packet放到输出队列中;

        6.如果接收到退出信号,则中止数据包收集,销毁Packet对象池,调用线程模块的退出清理函数;

        7.退出线程的执行。

5.2 W thread

从上面"autofp"模式中可以看出W thread所处的位置和包含的功能模块。它主要由FlowWorker模块和一些log模块组成, 主要完成数据检测和特定格式特定数据的日志输出。

图8

w thread的作用体现为线程函数-TmThreadsSlotVar,主要执行的任务为:

        1.给线程设置一个有意义的名称;

        2.将线程绑定到指定CPU核心;

        3.创建空Packet对象池;

        4.初始化与该线程关联的线程模块;

        5.从输入队列中获取packet,传递给线程模块依次处理后,放到输出队列中;

        6.如果接收到退出信号,则中止数据包收集,销毁Packet对象池,调用线程模块的退出清理函数;

        7.退出线程的执行。

你可能感兴趣的:(suricata 程序架构)