A-A+

suricata 3.1 源码分析18 (模块注册及初始化)

2018年12月06日 suricata 暂无评论

|Suricata支持多种数据包源:pcap(实时/文件)、nfq、ipfw、mpipe、af-packet、pfring、dag(实时/文件)、napatech。
每种数据包源的支持都对应于一个线程模块(Thread Module),得益于这种其模块化的架构,增加一个新的数据源支持只需要添加一个新的线程模块即可。
这里,我将主要记录最常见的pcap实时数据源的实现细节,包括相关数据结构、运行流程,以及与主框架和其他模块的交互等。
模块注册
TmModuleReceivePcapRegister函数用于实现pcap实时数据源的线程模块的注册,该函数在系统初始化阶段由RegisterAllModules函数所调用。函数内部唯一的工作就是填充TmModule类型的结构体变量:tmm_modules[TMM_RECEIVEPCAP]。下面是各字段的填充内容:

字段 填充值 含义及用处
name “ReceivePcap” 线程名字:目前没有看到代码中有对这个变量的使用。
ThreadInit ReceivePcapThreadInit 初始化函数:在_TmSlotSetFuncAppend中被传递给其所嵌入的slot的SlotThreadInit函数,而该函数将在线程执行函数(如TmThreadsSlotVar)中被调用。
Func NULL 模块执行函数:对于数据源模块,其执行函数为下面的PktAcqLoop。
PktAcqLoop ReceivePcapLoop 数据包获取函数:在TmThreadsSlotPktAcqLoop中被调用。
ThreadExitPrintStats ReceivePcapThreadExitStats 退出打印函数:用于打印模块统计信息,同样被赋给slot对应函数,然后在线程执行函数的退出阶段被调用。
ThreadDeinit NULL 清理函数:这里设成NULL可能是个BUG,因为存在一个正好用于这个目的却没有被引用过的函数:ReceivePcapThreadDeinit,其中调用pcap_close进行了清理。
RegisterTests NULL 注册测试函数:用来注册模块内部所编写的单元测试,在单元测试模式下,运行所有测试前将调用TmModuleRegisterTests函数先注册所有线程模块的单元测试函数。
cap_flags SC_CAP_NET_RAW 能力标志(capability flags):标志这个线程模块所需要的能力,以确定能让整个系统正常运行所需要的最小权限。SC_CAP_NET_RAW应该是表示需要获取原始数据包的能力。
flags TM_FLAG_RECEIVE_TM 其他标志:TM_FLAG_RECEIVE_TM表示这个模块的用途是收包(其他还有解码、检测等)。

模块初始化
如上表所示,模块初始化由ReceivePcapThreadInit函数完成,其函数原型为:
TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data)
其中,tv参数对应该模块所嵌入的线程的ThreadVars,在使用某些与线程相关的函数时需要使用。
initdata参数是模块的初始化数据,在使用TmSlotSetFuncAppend向线程中嵌入模块时传入。对于这个模块,其初始数据是一个PcapIfaceConfig类型的结构体指针,而这个结构体是由运行模式(对应于这个模块的运行模式类型为RUNMODE_PCAP_DEV)初始化函数(例如如RunModeIdsPcapAutoFp)中的ParsePcapConfig通过查询配置节点树下的pcap节点信息所填充的。具体的一些重要配置信息包括:

字段 含义
threads 抓包线程数量,默认为1。
buffer_size 接收缓冲大小,通过pcap_set_buffer_size设置。
snaplen 抓取长度,通过pcap_set_snaplen设置。
promisc 是否开启混杂模式,通过pcap_set_promisc设置。注意:如果要打开混杂模式,那么网卡必须也要打开(ifconfig eth0 promisc)。
bpf_filter BPF过滤器表达式,通过pcap_compile编译成bpf_program后再通过pcap_setfilter设置。
checksum_mode 校验和验证模式,设置为auto表示使用统计方式确定当前是否有checksum off-loading,若有,则关闭后续的校验和验证。
ref, DerefFunc 实现对配置结构体的引用计数。ref初始为当前使用该接口的线程(threads),因为这些线程都会在ReceivePcapThreadInit中引用这个配置结构。当用完配置结构体后(或出错需要退出时),就调用DerefFunc(PcapDerefConfig)减少引用计数,并在引用计数值为0时调用SCFree回收内存。

最后一个data参数,是该初始化函数的结果输出。函数内部会新建一个PcapThreadVars结构体,作为本模块的内部上下文,其中部分字段是直接copy的PcapIfaceConfig,另一些重要字段包括:

字段 含义
livedev 当前设备结构体(LiveDevice类型),记录设备统计信息(收包、丢包、校验和验证失败的包),通过iface调用LiveGetDevice查找得到。
pcap_handle pcap句柄,通过pcap_open_live获得,后续使用pcap库函数时都会用到。
pcap_state pcap状态,UP或DOWN,在使用PcapTryReopen重新打开pcap时用到。

在初始化函数返回时,填充好的PcapThreadVars结构体便传递给了包含该模块的slot的slot_data字段,该字段将做为参数传入后续的模块函数。

标签:

给我留言

Copyright © 九毛的官方博客 保留所有权利.   Theme  Ality

用户登录