Linux compilation of suricata

1. Download suricata source code

        Go to https://github.com/OISF/suricata to download the release version:
Insert image description here

2. Install dependencies

1、libhtp

        You need to download the source code from https://github.com/OISF/libhtp
Insert image description here
        , decompress it, enter the source code directory libhtp-0.5.41, and execute

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

        Then configure the environment variables, edit /etc/profile, and add:

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. Others

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

3. Compile and install

        After unzipping, enter the source code directory suricata-6.0.8and execute:

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

        At this step, suricata has been compiled. Since suricata is an independent process, if you continue to execute make installthe command, the software program will be installed in the specified directory /opt/suricata-6.0.8-ubuntu-x64. like:
Insert image description here
Insert image description hereInsert image description here

4. Use suricata as a component

        In some cases, we want suricata not to run as an independent process, but to use it as a module component in a process. Then we need to integrate suricata's source code and its dependent header files/libraries into the main process. .
        Since suricata is written in C, if the main process is implemented in C++, the interface provided by suricata cannot be directly called. In order to minimize modifications to the suricata source code, a proxy module can be added for interface proxy, and the interface can be made C++ compatible in the proxy module, for example , add proxy module:
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();
}

        If you want to add event monitoring for alarm information, you can do the following and suricata-6.0.8/src/add a file in the directory:
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;
}

        Modify alert-fastlog.cfile interface 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;
}

        In main.cppthe file, add alarm event callback settings, for example:

#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;
}

        After the previous step make, two header files will be automatically generated in the src directory, which need to be integrated into the project in subsequent operations.
Insert image description here

        Since suricata uses rustthe implemented module, the source code directory is:
Insert image description here

        Therefore, it is necessary to compile the rust source code into .aa static library and provide it for C language calling. After performing the operation in the previous step make, a static library will be automatically generated for us in the rust directory, such as:
Insert image description here
Insert image description here

        Now we write CMakethe project build script based on it, such as:

# 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)

Guess you like

Origin blog.csdn.net/hezhanran/article/details/127530737