项目中需求使用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 编译成动态库使用相关推荐

  1. Android导入第三方静态库.a编译成动态库.so

    http://ikinglai.blog.51cto.com/6220785/1324985 在Android开发的时候,经常会使用到用c或c++编写的第三方的静态库.如果有源码的话,可以直接跟你自己 ...

  2. android.bp编译生成so,Android导入第三方静态库.a编译成动态库.so

    在Android开发的时候,经常会使用到用c或c++编写的第三方的静态库.如果有源码的话,可以直接跟你自己的代码一去编译成动态库so,但是如果没有源码的话,你就必须在自己的动态库so里面将别人生成好的 ...

  3. 属性浏览器控件QtTreePropertyBrowser编译成动态库(设计师插件)

    文章目录 一.回顾 二.动态库编译 1.命令行编译动态库和测试程序 2.vs工具编译动态库和测试程序 3.安装文档 4.测试文档 三.设计师插件编译 1.重写QDesignerCustomWidget ...

  4. 算法开发:将合并后的模型编译成动态库(so文件)提供给qt调用

    一 .说明: 模型:分类+分割模型,4个模型合并成一个大模型,参考我之前的博客介绍:算法开发:多模型合并,加快推理速度_喜欢天晴的博客-CSDN博客 环境:tensorrt8.2.3.0,cuda版o ...

  5. vs可以调用java接口吗_关于vs2010下编译dll动态库,JNA接口在java中调用的问题

    最近在搞关于把vs2010中的project,使之能够在Java下面运行,有一个调用本地接口的问题,JNI那个涉及到复杂细节太多,就使用了最新的JNA(java native access) 网上也给 ...

  6. 【转】matlab与C/C++混合编程——在Windows/Linux上调用Matlab编译的动态库文件

    转自:matlab与C/C++混合编程--在Windows/Linux上调用Matlab编译的动态库文件_sinat_18131557的博客-CSDN博客 date version comments ...

  7. android studio中把c/c++文件编译成.so库(一)

    2019独角兽企业重金招聘Python工程师标准>>> 最近的项目涉及到JNI编程,经过一段时间的JNI编程之后,终于完美弄完了.所以,把在android studio中编译c/c+ ...

  8. gcc编译链接动态库

    文章目录 前言 操作步骤 1.直接生成目标so文件 2.先生成.o中间文件再链接成目标so文件 总结 前言 以下内容主要作为学习记录,有不准确的地方希望帮忙指出来,谢谢 以下是本篇文章正文内容,下面示 ...

  9. 将RTKLIB编译成静态库

    rtklib编译 在写自己的程序时,想要调用rtklib.h,和它的一些文件来进行运行,想要将rtklib编译成静态库安装在系统的目录下,这样基于rtklib的二次开发就不用再使用源码了,直接引用静态 ...

最新文章

  1. python 列表表达式 if_python中if else如何判断表达式成立?
  2. ant-design-pro Login 组件 实现 rules 验证
  3. lvs在linux系统下安装,Linux下安装lvs
  4. 如何判断UIWebView是否loading完全
  5. python six库_six库 解决python2的项目如何能够完全迁移到python3
  6. 地址已经被使用——Address already in use(来自《后台开发:核心技术于应用实践》)
  7. ASP.NET 2.0中控件的简单异步回调
  8. SNF快速开发平台MVC-各种级联绑定方式,演示样例程序(包含表单和表格控件)...
  9. 安徽省2012年下半年计算机水平考试(二级 c语言程序设计),安徽省计算机等级级考试真题C语言2012年12月.doc...
  10. ntp服务restrict_ntp服务器配置问题
  11. android关联发送程序,Android Handler机制之Message的发送与取出
  12. 为缺少调色板的png图片添加调色板
  13. expect巡检服务器_linux 巡检报告
  14. 生命在于学习——业务逻辑漏洞
  15. 湖北专升本MySQL复习(MySQL数据库实用教程)——MySQL数据表的操作
  16. 解决iPhone、iPad的home按键不灵敏
  17. B站纪录片发布会,发布的不只是纪录片
  18. 有度即时通统一工作门户助力政企单位开启数字化办公新模式
  19. postfix连接不上mysql_mysql – Postfix sasl登录失败没有找到机制
  20. php 获取百度权重,获取网站 百度权重 搜狗 谷歌PR

热门文章

  1. VC++如何利用Matlab2014b的图形引擎进行绘图
  2. js实现数据量换算问题
  3. 【定量分析、量化金融与统计学】统计推断基础(3)---点估计、区间估计
  4. SIMD补充 指令集架构类型 指令集介绍
  5. bzoj4569【SCOI2016】萌萌哒
  6. 日语助词と的所有的语法点,赶快记起来
  7. (十一)Canny 边缘检测算法
  8. 如何彻底关闭:Windows Defender Service
  9. a到z的ascii码值是多少_a的ascii码值十六进制是多少
  10. BackgroundMattingV2 百度网盘 模型文件