suricata之linux编译

一、下载suricata源码

        到https://github.com/OISF/suricata下载发布版:
在这里插入图片描述

二、安装依赖

1、libhtp

        需要到https://github.com/OISF/libhtp下载源码
在这里插入图片描述
        解压后进入源码目录libhtp-0.5.41,执行

./configure --prefix=/opt/libhtp-0.5.41-ubuntu-x64
make
make install

        然后配置环境变量,编辑/etc/profile,添加:

export LIBHTP_ROOT=/opt/libhtp-0.5.41-ubuntu-x64
export LD_LIBRARY_PATH=$LIBHTP_ROOT/lib:$LD_LIBRARY_PATH
export CPATH=$LIBHTP_ROOT/include:$CPATH
export LIBRARY_PATH=$LIBHTP_ROOT/lib:$LIBRARY_PATH
export PKG_CONFIG_PATH=$LIBHTP_ROOT/lib/pkgconfig:$PKG_CONFIG_PATH

2、其他

apt-get install libpcre3-dev
apt-get install libjansson-dev
apt-get install libyaml-dev
apt-get install libmagic-dev
apt-get install libnss3-dev
apt-get install libcap-ng-dev
apt-get install liblz4-dev

三、编译安装

        解压后进入源码目录suricata-6.0.8,执行:

./configure --prefix=/opt/suricata-6.0.8-ubuntu-x64
make

        到此步骤,suricata已经编译完成,由于suricata是一个可独立运行的进程,如果继续执行make install命令,将会把软件程序安装到指定目录/opt/suricata-6.0.8-ubuntu-x64下。如:
在这里插入图片描述
在这里插入
图片描述在这里插入图片描述

四、把suricata作为组件

        在某些情况下,我们希望suricata不作为独立进程运行,而是希望把它当作某个进程中的一个模块组件,则需要把suricata的源码以及其依赖的头文件/库集成到主进程中。
        由于suricata是使用C编写,如果主进程使用C++实现,那么不能直接调用suricata提供的接口,为了最小化修改到suricata源码,可以增加代理模块进行接口代理,在代理模块中对接口进C++兼容,例如,增加代理模块:
proxy.h

#pragma once

#ifdef __cplusplus
extern "C"
{
    
    
#endif
    /** 
     * @brief 启动Suricata
     */
    void startSuricata(int argc, char** argv);

    /** 
     * @brief 停止Suricata
     */
    void stopSuricata();
#ifdef __cplusplus
}
#endif

proxy.c

#include "proxy.h"

#include <stdio.h>
#include <string.h>

#include "../suricata-6.0.8/src/suricata.h"

void startSuricata(int argc, char** argv)
{
    
    
    SuricataMain(argc, argv);
}

void stopSuricata()
{
    
    
    EngineStop();
}

        如果要增加对告警信息的事件监听,则可以如下操作,在suricata-6.0.8/src/目录下添加文件:
alert-define.h

#pragma once
#include <stdlib.h>

#ifdef __cplusplus
extern "C"
{
    
    
#endif
    /**
     * @brief 告警信息
     */
    typedef struct
    {
    
    
        char timebuf[64]; /* 时间, 格式: "10/16/2022-15:42:45.160103" */
        char protocol[32]; /* 协议 */
        char srcIp[46]; /* 源IP */
        int srcPort; /* 源端口 */
        char dstIp[46]; /* 目的IP */
        int dstPort; /* 目的端口 */
        int priority; /* 等级 */
        char classification[512]; /* 分类信息描述 */
        char msg[1024]; /* 消息 */
    } st_alert_info;

    /**
     * @brief 告警回调
     * @param info 告警信息
     * @return 0-不写日志, 1-写日志
     */
    typedef int (*alert_callback)(st_alert_info info);

    /**
     * @brief 设置告警回调
     * @param callback 回调
     */
    void setAlarmCallback(alert_callback callback);

    /**
     * @brief 响应告警回调
     * @param info 告警信息
     * @return 0-不写日志, 1-写日志
     */
    int onAlarmCallback(st_alert_info info);

#ifdef __cplusplus
}
#endif

alert-define.c

#include "alert-define.h"

static alert_callback s_alertCallback = NULL; /* 告警回调 */

void setAlarmCallback(alert_callback callback)
{
    
    
    s_alertCallback = callback;
}

int onAlarmCallback(st_alert_info info)
{
    
    
    if (s_alertCallback)
    {
    
    
        return s_alertCallback(info);
    }
    return 1;
}

        修改alert-fastlog.c文件接口int AlertFastLogger(ThreadVars *tv, void *data, const Packet *p)

#include "alert-define.h"

int AlertFastLogger(ThreadVars *tv, void *data, const Packet *p)
{
    
    
    AlertFastLogThread *aft = (AlertFastLogThread *)data;
    int i;
    char timebuf[64];
    int decoder_event = 0;

    CreateTimeString(&p->ts, timebuf, sizeof(timebuf));

    char srcip[46], dstip[46];
    if (PKT_IS_IPV4(p)) {
    
    
        PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip));
        PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip));
    } else if (PKT_IS_IPV6(p)) {
    
    
        PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip));
        PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip));
    } else {
    
    
        decoder_event = 1;
    }

    /* Buffer to store the generated alert strings. The buffer is
     * filled with alert strings until it doesn't have room to store
     * another full alert, only then is the buffer written.  This is
     * more efficient for multiple alerts and only slightly slower for
     * single alerts.
     */
    char alert_buffer[MAX_FASTLOG_BUFFER_SIZE];

    char proto[16] = "";
    const char *protoptr;
    if (SCProtoNameValid(IP_GET_IPPROTO(p))) {
    
    
        protoptr = known_proto[IP_GET_IPPROTO(p)];
    } else {
    
    
        snprintf(proto, sizeof(proto), "PROTO:%03" PRIu32, IP_GET_IPPROTO(p));
        protoptr = proto;
    }
    uint16_t src_port_or_icmp = p->sp;
    uint16_t dst_port_or_icmp = p->dp;
    if (IP_GET_IPPROTO(p) == IPPROTO_ICMP || IP_GET_IPPROTO(p) == IPPROTO_ICMPV6) {
    
    
        src_port_or_icmp = p->icmp_s.type;
        dst_port_or_icmp = p->icmp_s.code;
    }
    for (i = 0; i < p->alerts.cnt; i++) {
    
    
        const PacketAlert *pa = &p->alerts.alerts[i];
        if (unlikely(pa->s == NULL)) {
    
    
            continue;
        }

        const char *action = "";
        if ((pa->action & ACTION_DROP) && EngineModeIsIPS()) {
    
    
            action = "[Drop] ";
        } else if (pa->action & ACTION_DROP) {
    
    
            action = "[wDrop] ";
        }

        /* Create the alert string without locking. */
        int size = 0;
        if (likely(decoder_event == 0)) {
    
    
            PrintBufferData(alert_buffer, &size, MAX_FASTLOG_ALERT_SIZE,
                            "%s  %s[**] [%" PRIu32 ":%" PRIu32 ":%"
                            PRIu32 "] %s [**] [Classification: %s] [Priority: %"PRIu32"]"
                            " {%s} %s:%" PRIu32 " -> %s:%" PRIu32 "\n", timebuf, action,
                            pa->s->gid, pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio,
                            protoptr, srcip, src_port_or_icmp, dstip, dst_port_or_icmp);
        } else {
    
    
            PrintBufferData(alert_buffer, &size, MAX_FASTLOG_ALERT_SIZE, 
                            "%s  %s[**] [%" PRIu32 ":%" PRIu32
                            ":%" PRIu32 "] %s [**] [Classification: %s] [Priority: "
                            "%" PRIu32 "] [**] [Raw pkt: ", timebuf, action, pa->s->gid,
                            pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio);
            PrintBufferRawLineHex(alert_buffer, &size, MAX_FASTLOG_ALERT_SIZE,
                                  GET_PKT_DATA(p), GET_PKT_LEN(p) < 32 ? GET_PKT_LEN(p) : 32);
            if (p->pcap_cnt != 0) {
    
    
                PrintBufferData(alert_buffer, &size, MAX_FASTLOG_ALERT_SIZE, 
                                "] [pcap file packet: %"PRIu64"]\n", p->pcap_cnt);
            } else {
    
    
                PrintBufferData(alert_buffer, &size, MAX_FASTLOG_ALERT_SIZE, "]\n");
            }
        }

        /* 构造告警信息 */
        st_alert_info info;
        memset(&info, 0, sizeof(info));
        if (timebuf && strlen(timebuf) > 0)
        {
    
    
            memcpy(info.timebuf, timebuf, strlen(timebuf));
        }
        if (protoptr && strlen(protoptr) > 0)
        {
    
    
            memcpy(info.protocol, protoptr, strlen(protoptr));
        }
        if (strlen(srcip) > 0)
        {
    
    
            memcpy(info.srcIp, srcip, strlen(srcip));
        }
        info.srcPort = src_port_or_icmp;
        if (strlen(dstip) > 0)
        {
    
    
            memcpy(info.dstIp, dstip, strlen(dstip));
        }
        info.dstPort = dst_port_or_icmp;
        info.priority = pa->s->prio;
        if (pa->s->class_msg && strlen(pa->s->class_msg) > 0)
        {
    
    
            memcpy(info.classification, pa->s->class_msg, strlen(pa->s->class_msg));
        }
        if (pa->s->msg && strlen(pa->s->msg) > 0)
        {
    
    
            memcpy(info.msg, pa->s->msg, strlen(pa->s->msg));
        }
        /* 调用告警回调 */
        if (onAlarmCallback(info))
        {
    
    
            /* Write the alert to output file */
            AlertFastLogOutputAlert(aft, alert_buffer, size);
        }
    }

    return TM_ECODE_OK;
}

        在main.cpp文件中,增加告警事件回调设置,例如:

#include "../suricata-6.0.8/src/alert-define.h"
#include "proxy.h"

/**
 * @brief 响应告警回调
 * @param info 告警信息
 * @return 0-不写日志, 1-写日志
 */
int onAlertCallback(st_alert_info info)
{
    
    
    INFO_LOG(s_logger, "协议: {}, 源地址: {}:{}, 目的地址: {}:{}, 等级: {}, 类别: {}, 消息: {}", info.protocol, info.srcIp, info.srcPort,
             info.dstIp, info.dstPort, info.priority, info.classification, info.msg);
    return 1;
}

int main(int argc, char* argv[])
{
    
    
    setAlarmCallback(onAlertCallback); /* 设置告警回调 */
    /* 主循环 */
    while (1)
    {
    
    
        utility::PathInfo(Config::getValue(cfgkey::PathLog).toString() + "/suricata").create();
        /* 创建参数列表 */
        int argCount = 0;
        char** argList = NULL;
        {
    
    
            std::lock_guard<std::mutex> locker(s_mutexArgVec);
            s_argVec.clear();
            s_argVec.emplace_back(argv0);
            s_argVec.emplace_back("-c");
            s_argVec.emplace_back("/proc_test/suricata.yaml");
            s_argVec.emplace_back("-i");
            s_argVec.emplace_back("enp10");
            INFO_LOG(s_logger, "suricata模块启动参数: {}", utility::StrTool::join(s_argVec, " "));
            argList = utility::StrTool::convertToArgv(s_argVec, argCount);
        }
        /* 启动suricata */
        if (argCount > 0 && argList)
        {
    
    
            startSuricata(argCount, argList);
        }
        /* 销毁删除列表 */
        destroyArgv(argCount, argList);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    return 0;
}

        在上一步的make操作后,会在src目录下自动生成两个头文件,在后面的操作中需要集成到工程里
在这里插入图片描述

        由于suricata使用了rust实现的模块,源码目录为:
在这里插入图片描述

        因此,需要把rust的源码编译成.a静态库,提供给C语言调用。在上一步执行make操作后,会自动在rust目录下帮我们生成静态库,如:
在这里插入图片描述
在这里插入图片描述

        现在我们编写基于CMake的工程构建脚本,如:

# CMake版本
cmake_minimum_required(VERSION 3.18.0)

# `std::make_unique`要求最低C++14
set(CMAKE_CXX_STANDARD 14)

# 工程名
project(proc_intrusion)

####################################### 添加线程库 #######################################
find_package(Threads REQUIRED)
##########################################################################################

####################################### 添加libhtp库 #######################################
if ("$ENV{LIBHTP_ROOT}" STREQUAL "") # 自动查找
    find_path(LIBHTP_INCLUDE_DIR NAMES htp.h)
else () # 如果有手动配置LIBHTP环境变量LIBHTP_ROOT, 则从环境变量中获取
    set(LIBHTP_INCLUDE_DIR $ENV{
    
    LIBHTP_ROOT}/include/htp)
endif ()
find_library(LIBHTP_LIBRARIES NAMES htp HINTS ${LIBHTP_INCLUDE_DIR}/../../lib)
set(LIBHTP_ROOT_DIR ${LIBHTP_INCLUDE_DIR}/../../)
message(STATUS "libhtp root dir: ${LIBHTP_ROOT_DIR}")
message(STATUS "libhtp include path: ${LIBHTP_INCLUDE_DIR}")
message(STATUS "libhtp libraries: ${LIBHTP_LIBRARIES}")
if ("${LIBHTP_ROOT_DIR}" STREQUAL "LIBHTP_ROOT_DIR-NOTFOUND" OR
    "${LIBHTP_INCLUDE_DIR}" STREQUAL "LIBHTP_INCLUDE_DIR-NOTFOUND" OR
    "${LIBHTP_LIBRARIES}" STREQUAL "LIBHTP_LIBRARIES-NOTFOUND")
    message(WARNING "libhtp not found")
    return()
else ()
    include_directories(${LIBHTP_INCLUDE_DIR})
endif ()
##########################################################################################

# 添加宏定义
add_definitions(-DHAVE_CONFIG_H=1)
add_definitions(-DLOCAL_STATE_DIR="/home/proc_intrusion")

# 添加头文件包含目录
include_directories(/usr/include/nss)
include_directories(/usr/include/nspr)
include_directories(suricata-6.0.8/src)
include_directories(suricata-6.0.8/rust/dist)

# 添加suricata源文件
set(proc_files)
get_cxx_files(suricata-6.0.8/src src_list)
list(APPEND proc_files ${src_list})
list(REMOVE_ITEM proc_files ${CMAKE_CURRENT_SOURCE_DIR}/suricata-6.0.8/src/main.c) # 这里去除源码中的主文件

# 添加主进程源文件
get_cxx_files(src src_list)
list(APPEND proc_files ${src_list})

message("proc_files files:")
foreach(filename ${proc_files})
    message("    " ${filename})
endforeach()

# 构建可执行文件
add_executable(proc_intrusion ${proc_intrusion})

# 链接依赖库文件
target_link_libraries(proc_intrusion Threads::Threads
                                     ${LIBHTP_LIBRARIES}
                                     pcap
                                     dl
                                     rt
                                     m
                                     lz4
                                     magic
                                     cap-ng
                                     jansson
                                     yaml
                                     z
                                     pcre
                                     ssl3
                                     smime3
                                     nss3
                                     nssutil3
                                     plds4
                                     plc4
                                     nspr4
                                     /root/workspace/suricata-6.0.8/rust/target/release/libsuricata.a)

猜你喜欢

转载自blog.csdn.net/hezhanran/article/details/127530737