Directorio de artículos
1. Descargue el código fuente de suricata
Vaya a https://github.com/OISF/suricata para descargar la versión de lanzamiento:
2. Instalar dependencias
1.libhtp
Debe descargar el código fuente de https://github.com/OISF/libhtp
, descomprimirlo, ingresar al directorio del código fuente libhtp-0.5.41
y ejecutar
./configure --prefix=/opt/libhtp-0.5.41-ubuntu-x64
make
make install
Luego configure las variables de entorno, edite /etc/profile
y agregue:
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. Otros
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 e instale
Después de descomprimir, ingrese al directorio del código fuente suricata-6.0.8
y ejecute:
./configure --prefix=/opt/suricata-6.0.8-ubuntu-x64
make
En este paso, se ha compilado suricata. Dado que suricata es un proceso independiente, si continúa ejecutando make install
el comando, el programa de software se instalará en el directorio especificado /opt/suricata-6.0.8-ubuntu-x64
. como:
4. Utilice suricata como componente.
En algunos casos, queremos que suricata no se ejecute como un proceso independiente, sino que lo use como un componente de módulo en un proceso. Luego necesitamos integrar el código fuente de suricata y sus archivos/bibliotecas de encabezado dependientes en el proceso principal.
Dado que suricata está escrito en C, si el proceso principal se implementa en C ++, la interfaz proporcionada por suricata no se puede llamar directamente. Para minimizar las modificaciones en el código fuente de suricata, se puede agregar un módulo proxy para la interfaz proxy y la interfaz Se puede hacer compatible con C++ en el módulo proxy, por ejemplo, agregue el módulo proxy:
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();
}
Si desea agregar monitoreo de eventos para información de alarma, puede hacer lo siguiente y suricata-6.0.8/src/
agregar un archivo en el directorio:
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
alerta-definir.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;
}
Modificar alert-fastlog.c
la interfaz del archivo 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;
}
En main.cpp
el archivo, agregue configuraciones de devolución de llamada de eventos de alarma, por ejemplo:
#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;
}
Después del paso anterior make
, se generarán automáticamente dos archivos de encabezado en el directorio src, que deberán integrarse en el proyecto en operaciones posteriores.
Dado que suricata usa rust
el módulo implementado, el directorio del código fuente es:
Por lo tanto, es necesario compilar el código fuente de Rust en .a
una biblioteca estática y proporcionarlo para llamadas en lenguaje C. Después de realizar la operación en el paso anterior make
, se generará automáticamente una biblioteca estática en el directorio de Rust, como por ejemplo:
Ahora escribimos CMake
el script de construcción del proyecto basado en él, como por ejemplo:
# 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)