suricata 编译成动态库使用
项目中需求使用suricata 检测功能,只需要获取检测得到的 alert 结果, 需要将suricata的检测功能集成到我们的项目中,并提供接口动态加载规则。 源代码版本 6.0.4
源码 将suricata编译成动态库,使用suricata检测功能,只需要获取检测得到的alert。
目录
前提
接口
编译成动态库
初始化部分 suricataLibInit
初始化公共部分
RunModeLibraryRegister
TmModuleDecodeLibraryRegister 注册DecodeLibrary 的解析函数
初始化自有线程部分
检测接口 suricataLibProcessPacket
动态加载规则
前提
1、将 suricata 编译成动态库(以下简称为 libsuri_603.so),供我们的项目调用。
2、我们的项目已自己采集网卡数据,程序将调用 libsuri_603.so,将采集到的数据传入。
3、项目中调用的 libsuri_603.so 的也是一个动态库,并且只能在子线程(子线程名字为 Process 线程,和suricata中的worker线程一一对应)中,所有 libsuri_603.so 中的接口全部都在子线程中调用。
4、至少提供四个接口,分别为初始化,检测数据传入,动态规则加载接口,Destroy。
5、增加一个run_mode 为 RUNMODE_LIBRARY,在初始化中直接复制suricata.run_mode = RUNMODE_LIBRARY;
6、增加了三个文件分别为 libsuricata.h(接口头文件), source-library.c(主要负责调用工作线程),runmode-library.c(主要负责worker线程的处理化)
接口
/* libsuricata.h *///动态加载规则结束的回调
typedef void (*ReloadRuleRet)(int);/** \internal* \brief 初始化,每个 Process 线程都会调用这个 函数,但是只有其中一个线程取初始化suricata* 全局使用的数据,比如诸多回调函数的注册,管理线程的创建,规则文件的加载,检测引擎的加载。* 待全局数据初始完成后才会在每个 Process 线程中初始 worker线程独有的数据,* 注册工作流程的回调函数,初始化工作线程变量和存放数据包的内存池。* \param yamlFilePath suricata.yaml配置文件的路径* \param ips_ids 0:ips or 1:ids, 没有用到阻断功能,ips只是用以逐包检测* \param retFunc 动态加载规则结果的回调函数*/int suricataLibInit(const char* yamlFilePath, uint8_t ips_ids, ReloadRuleRet retFunc);/** \internal* \brief worker 我们项目会处理含有gtp层的码流,suricata不能解析这个,* 故这里会把含有gtp层的数据直接从内层ip开始,ipType=4 or 6; * 不含gtp的从Ethernet开始,ipType=0* \param pkt 一条码流包* \param caplen 长度* \param ipType 详见brief * \param lcapTime 包时间* \param outAlerts 传入alert,同步数据结构,事实上ids是逐流检测的,出结果可能会晚一些* 我们程序希望使用ips逐包检测,这样,出的检测结果即是当前传入的包触发的*/int suricataLibProcessPacket(const uint8_t* pkt, int caplen, uint8_t ipType, const struct timeval* lcapTime, PacketOutAlerts* outAlerts);/** \internal* \brief 动态加载规则 加载规则比较耗时,在此只是创建一个子线程,在子线程中加载规则*/
int suricataLibDynamicUpdateRules(void);/** \internal* \brief 释放资源*/
void suricataLibGlobalsDestroy(void);
编译成动态库
修改 src/Makefile.am 文件 ,将suricata编译成名字为 libsuri_603.so 的动态库
初始化部分 suricataLibInit
int suricataLibInit(const char *yamlFilePath, uint8_t ips_ids, ReloadRuleRet retFunc)
{//先初始化公共部分,保证只有一个线程初始化int retCode = suricataLibraryPublicInit(yamlFilePath, ips_ids, retFunc);if (0 != retCode){return retCode;}// 公共部分初始完成后再初始化自有线程的数据return suricataLibrarayThreadInit();
}
初始化公共部分
//初始化suricata 公共部分的部分代码
int suricataLibraryPublicInit(const char* yamlFilePath, uint8_t ips_ids, ReloadRuleRet retFunc)
{pthread_mutex_lock(&sg_initMutex);static int retCode = 1;do{if (0 == retCode){break;}//保存动态加载规则结果的回调函数reloadRuleRetFunc = retFunc;SC_ATOMIC_INIT(isReloading);SCInstanceInit(&suricata, "suricata_603_lib");if (InitGlobal() != 0) {retCode = -1;break;}//不读命令参数 直接设定为 RUNMODE_LIBRARYsuricata.run_mode = RUNMODE_LIBRARY;//保存suricata.yaml文件路径memcpy(yamlFilePathChar, yamlFilePath, pathLen);suricata.conf_filename = yamlFilePathChar;/** ... 此处省略1w行*/retCode = 0;} while (false);pthread_mutex_unlock(&sg_initMutex);return retCode;
}
suricataLibraryPublicInit 函数初始化的内容与 int SuricataMain(int argc, char **argv) 中初始的内容大致相同,不同点主要有三:
1、suricataLibraryPublicInit不初始worker线程的数据,这部分放在Process 线程调用suricataLibrarayThreadInit 函数实现。
2、suricataLibraryPublicInit 去掉了 SuricataMainLoop(&suricata)调用,因为libsuri_603.so不需要这个了,其动态加载规则放在另外的接口中处理 int suricataLibDynamicUpdateRules(void);
3、Destroy部分放在suricataLibGlobalsDestroy 接口中。
RunModeLibraryRegister
RunModeRegisterRunModes 函数中增加 RunModeLibraryRegister() 用以注册RUNMODE_LIBRARY 的回调函数 RunModeLibraryWorkers ,这个函数在各个线程在初始化自有线程的数据时调用。
void RunModeRegisterRunModes(void)
{/** ...*/RunModeLibraryRegister();return;
}void RunModeLibraryRegister(void)
{SCEnter();RunModeRegisterNewRunMode(RUNMODE_LIBRARY, "workers","Workers library mode, each thread does all"" tasks from acquisition to logging",RunModeLibraryWorkers);library_default_mode = "workers";return;
}
TmModuleDecodeLibraryRegister 注册DecodeLibrary 的解析函数
void RegisterAllModules(void)
{/***//* library */TmModuleDecodeLibraryRegister();
}void TmModuleDecodeLibraryRegister (void)
{SCEnter();SCLogDebug(" libraray support");tmm_modules[TMM_DECODELIBRARY].name = "DecodeLibrary";tmm_modules[TMM_DECODELIBRARY].ThreadInit = DecodeLibraryThreadInit;tmm_modules[TMM_DECODELIBRARY].Func = DecodeLibrary;tmm_modules[TMM_DECODELIBRARY].ThreadExitPrintStats = NULL;tmm_modules[TMM_DECODELIBRARY].ThreadDeinit = DecodeLibraryThreadDeinit;tmm_modules[TMM_DECODELIBRARY].cap_flags = 0;tmm_modules[TMM_DECODELIBRARY].flags = TM_FLAG_DECODE_TM;SCReturn;
}
初始化自有线程部分
int suricataLibrarayThreadInit(void)
{/** ... 此处省略1w行*///主要是这个函数 调用 RUNMODE_LIBRARY 模式的回调函数 //这里调用下面RunModeLibraryWorkers这个函数mode->RunModeFunc();/** ... 此处省略1w行*/return 0;
}static int RunModeLibraryWorkers(void)
{int ret = -1;char tname[50] = { "" };ThreadVars* tv_worker = NULL;TmModule* tm_module = NULL;pthread_t pthreadId = pthread_self();snprintf(tname, sizeof(tname), "LIBW-%lu", pthreadId);tv_worker = TmThreadCreatePacketHandler(tname,"packetpool", "packetpool","packetpool", "packetpool","pktacqloop");if (tv_worker == NULL) {SCLogError(SC_ERR_LIBRARY_CONFIG, " TmThreadsCreate failed for (%s)", tname);//exit(EXIT_FAILURE);return -1;}tv_worker->t = pthreadId;//注册解析流程 DecodeLibrary为新增的函数tm_module = TmModuleGetByName("DecodeLibrary");if (tm_module == NULL) {SCLogError(SC_ERR_LIBRARY_CONFIG, " TmModuleGetByName failed for DecodeLibrary");return -1;}TmSlotSetFuncAppend(tv_worker, tm_module, NULL);//注册检测流程 FlowWorker为原有的函数tm_module = TmModuleGetByName("FlowWorker");if (tm_module == NULL) {SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName for FlowWorker failed");return -1;}TmSlotSetFuncAppend(tv_worker, tm_module, NULL);//初始化worker线程的内存池(PacketPoolInit) 对流等TmThreadsSlotPktAcqInit(tv_worker);libraryThreadVarsPtr = tv_worker; //线程变量, 保存每个线的ThreadVars//不创建线程,只将这个线程变量加入 ThreadVars *tv_root[TVT_MAX] 中保存TmThreadAppend(tv_worker, tv_worker->type);return ret;
}
检测接口 suricataLibProcessPacket
这个就直接调用接口,然后顺着注册的回调函数依次运行即可 DecodeLibrary -> FlowWorker
int suricataLibProcessPacket(const uint8_t* pkt, int caplen, uint8_t ipType, const struct timeval* lcapTime, PacketOutAlerts* outAlerts)
{TmEcode code = suricataLibraryProcessPacket(pkt, caplen, ipType, lcapTime, outAlerts);SCReturnInt(code);
}
动态加载规则
创建子线程加载 加载函数为suricataLibraryAsyncUpdateRules
int suricataLibraryDynamicUpdateRules(void)
{if (unlikely(SC_ATOMIC_GET(isReloading) == true)){return -1;}SC_ATOMIC_SET(isReloading, true);pthread_t thread_id;pthread_attr_t attr;/* Initialize and set thread detached attribute */pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);int rc = pthread_create(&thread_id, &attr, suricataLibraryAsyncUpdateRules, NULL);if (rc) {printf("ERROR; return code from pthread_create() is %" PRId32 "\n", rc);SCLogError(SC_ERR_THREAD_DEINIT, "ERROR; return code from suricataLibraryDynamicUpdateRules pthread_create() is %" PRId32 "\n", rc);SC_ATOMIC_SET(isReloading, false);return -2;}return 0;
}
目前的问题
使用的同步接口检测并获取alter结果
1、ids模式下,因为是逐流检测,所以检测的结果相对于实际有alter的包有延后,这样对于pcap留存功能有影响;流超时检测会导致同步接口获取不到检测结果。
2、改成ips检测,这样有逐包检测,这样的话能够解决上面的问题,但是性能会下降,还会出现多的结果(比如存在这样一个http流,有两个事务,第一个事务只能被规则1命中,第二个事务只能被规则2命中。那么在ips模式下,第一个事务会检测出规则1,第二个事务会出规则2的同时多出一个规则1的结果)
3、同一个事务如果有多次多个结果,目前只取了第一个结果。这种在上面的ips模式下,可能取不到正确的结果(这个问题是dpi控制的)。
凡是过往,即为序章
suricata 编译成动态库使用相关推荐
- Android导入第三方静态库.a编译成动态库.so
http://ikinglai.blog.51cto.com/6220785/1324985 在Android开发的时候,经常会使用到用c或c++编写的第三方的静态库.如果有源码的话,可以直接跟你自己 ...
- android.bp编译生成so,Android导入第三方静态库.a编译成动态库.so
在Android开发的时候,经常会使用到用c或c++编写的第三方的静态库.如果有源码的话,可以直接跟你自己的代码一去编译成动态库so,但是如果没有源码的话,你就必须在自己的动态库so里面将别人生成好的 ...
- 属性浏览器控件QtTreePropertyBrowser编译成动态库(设计师插件)
文章目录 一.回顾 二.动态库编译 1.命令行编译动态库和测试程序 2.vs工具编译动态库和测试程序 3.安装文档 4.测试文档 三.设计师插件编译 1.重写QDesignerCustomWidget ...
- 算法开发:将合并后的模型编译成动态库(so文件)提供给qt调用
一 .说明: 模型:分类+分割模型,4个模型合并成一个大模型,参考我之前的博客介绍:算法开发:多模型合并,加快推理速度_喜欢天晴的博客-CSDN博客 环境:tensorrt8.2.3.0,cuda版o ...
- vs可以调用java接口吗_关于vs2010下编译dll动态库,JNA接口在java中调用的问题
最近在搞关于把vs2010中的project,使之能够在Java下面运行,有一个调用本地接口的问题,JNI那个涉及到复杂细节太多,就使用了最新的JNA(java native access) 网上也给 ...
- 【转】matlab与C/C++混合编程——在Windows/Linux上调用Matlab编译的动态库文件
转自:matlab与C/C++混合编程--在Windows/Linux上调用Matlab编译的动态库文件_sinat_18131557的博客-CSDN博客 date version comments ...
- android studio中把c/c++文件编译成.so库(一)
2019独角兽企业重金招聘Python工程师标准>>> 最近的项目涉及到JNI编程,经过一段时间的JNI编程之后,终于完美弄完了.所以,把在android studio中编译c/c+ ...
- gcc编译链接动态库
文章目录 前言 操作步骤 1.直接生成目标so文件 2.先生成.o中间文件再链接成目标so文件 总结 前言 以下内容主要作为学习记录,有不准确的地方希望帮忙指出来,谢谢 以下是本篇文章正文内容,下面示 ...
- 将RTKLIB编译成静态库
rtklib编译 在写自己的程序时,想要调用rtklib.h,和它的一些文件来进行运行,想要将rtklib编译成静态库安装在系统的目录下,这样基于rtklib的二次开发就不用再使用源码了,直接引用静态 ...
最新文章
- python 列表表达式 if_python中if else如何判断表达式成立?
- ant-design-pro Login 组件 实现 rules 验证
- lvs在linux系统下安装,Linux下安装lvs
- 如何判断UIWebView是否loading完全
- python six库_six库 解决python2的项目如何能够完全迁移到python3
- 地址已经被使用——Address already in use(来自《后台开发:核心技术于应用实践》)
- ASP.NET 2.0中控件的简单异步回调
- SNF快速开发平台MVC-各种级联绑定方式,演示样例程序(包含表单和表格控件)...
- 安徽省2012年下半年计算机水平考试(二级 c语言程序设计),安徽省计算机等级级考试真题C语言2012年12月.doc...
- ntp服务restrict_ntp服务器配置问题
- android关联发送程序,Android Handler机制之Message的发送与取出
- 为缺少调色板的png图片添加调色板
- expect巡检服务器_linux 巡检报告
- 生命在于学习——业务逻辑漏洞
- 湖北专升本MySQL复习(MySQL数据库实用教程)——MySQL数据表的操作
- 解决iPhone、iPad的home按键不灵敏
- B站纪录片发布会,发布的不只是纪录片
- 有度即时通统一工作门户助力政企单位开启数字化办公新模式
- postfix连接不上mysql_mysql – Postfix sasl登录失败没有找到机制
- php 获取百度权重,获取网站 百度权重 搜狗 谷歌PR