This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
tango-maat/scanner/expr_matcher/adapter_hs/adapter_hs.cpp

876 lines
28 KiB
C++

/*
**********************************************************************************************
* File: adapter_hs.c
* Description:
* Authors: Liu wentan <liuwentan@geedgenetworks.com>
* Date: 2022-10-31
* Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved.
***********************************************************************************************
*/
#include <stdint.h>
#include <stdio.h>
#include <stddef.h>
#include <hs/hs.h>
#include <assert.h>
#include <unistd.h>
#include <sys/syscall.h>
#include "adapter_hs.h"
#include "uthash/utarray.h"
#include "uthash/uthash.h"
#include "maat_utils.h"
#include "../../bool_matcher/bool_matcher.h"
#define MAX_HIT_PATTERN_NUM 512
pid_t hs_gettid()
{
return syscall(SYS_gettid);
}
static const char *hs_module_name_str(const char *name)
{
static __thread char module[64];
snprintf(module, sizeof(module), "%s(%d)", name, hs_gettid());
return module;
}
#define MODULE_ADAPTER_HS hs_module_name_str("maat.adapter_hs")
struct adpt_hs_compile_data {
unsigned int *ids;
unsigned int *flags;
char **patterns;
size_t *pattern_lens;
unsigned int n_patterns;
};
struct adapter_hs_scratch {
hs_scratch_t **literal_scratches;
hs_scratch_t **regex_scratches;
struct bool_expr_match **bool_match_buffs;
};
struct adapter_hs_stream {
int thread_id;
hs_stream_t *literal_stream;
hs_stream_t *regex_stream;
struct adapter_hs_runtime *ref_hs_rt;
struct matched_pattern *matched_pat;
struct log_handle *logger;
};
/* adapter_hs runtime */
struct adapter_hs_runtime {
hs_database_t *literal_db;
hs_database_t *regex_db;
struct adapter_hs_scratch *scratch;
struct adapter_hs_stream **streams;
struct bool_matcher *bm;
};
/* adapter_hs instance */
struct adapter_hs {
size_t n_worker_thread;
size_t n_expr;
size_t n_patterns;
struct adapter_hs_runtime *hs_rt;
struct pattern_attribute *hs_attr;
struct log_handle *logger;
};
struct pattern_offset {
long long start;
long long end;
};
struct pattern_attribute {
long long pattern_id;
enum expr_match_mode match_mode;
struct pattern_offset offset;
};
struct matched_pattern {
UT_array *pattern_ids;
size_t n_patterns;
struct pattern_attribute *ref_hs_attr;
size_t scan_data_len;
};
static int _hs_alloc_scratch(hs_database_t *db, hs_scratch_t **scratches,
size_t n_worker_thread, struct log_handle *logger)
{
size_t scratch_size = 0;
if (hs_alloc_scratch(db, &scratches[0]) != HS_SUCCESS) {
log_error(logger, MODULE_ADAPTER_HS,
"[%s:%d] Unable to allocate scratch space. Exiting.",
__FUNCTION__, __LINE__);
return -1;
}
for (size_t i = 1; i < n_worker_thread; i++) {
hs_error_t err = hs_clone_scratch(scratches[0], &scratches[i]);
if (err != HS_SUCCESS) {
log_error(logger, MODULE_ADAPTER_HS,
"[%s:%d] Unable to clone scratch",
__FUNCTION__, __LINE__);
return -1;
}
err = hs_scratch_size(scratches[i], &scratch_size);
if (err != HS_SUCCESS) {
log_error(logger, MODULE_ADAPTER_HS,
"[%s:%d] Unable to query scratch size",
__FUNCTION__, __LINE__);
return -1;
}
}
return 0;
}
static int adpt_hs_alloc_scratch(struct adapter_hs_runtime *hs_rt,
size_t n_worker_thread,
enum expr_pattern_type pattern_type,
struct log_handle *logger)
{
int ret = 0;
if (pattern_type == EXPR_PATTERN_TYPE_STR) {
hs_rt->scratch->literal_scratches = ALLOC(hs_scratch_t *, n_worker_thread);
ret = _hs_alloc_scratch(hs_rt->literal_db, hs_rt->scratch->literal_scratches,
n_worker_thread, logger);
if (ret < 0) {
FREE(hs_rt->scratch->literal_scratches);
return -1;
}
} else {
hs_rt->scratch->regex_scratches = ALLOC(hs_scratch_t *, n_worker_thread);
ret = _hs_alloc_scratch(hs_rt->regex_db, hs_rt->scratch->regex_scratches,
n_worker_thread, logger);
if (ret < 0) {
FREE(hs_rt->scratch->regex_scratches);
return -1;
}
}
return 0;
}
/**
* @brief build hs block database for literal string and regex expression respectively
*
* @retval 0(success) -1(failed)
*/
static int adpt_hs_build_database(struct adapter_hs_runtime *hs_rt,
struct adpt_hs_compile_data *literal_cd,
struct adpt_hs_compile_data *regex_cd,
struct log_handle *logger)
{
hs_error_t err;
hs_compile_error_t *compile_err = NULL;
if (NULL == hs_rt || (NULL == literal_cd && NULL == regex_cd)) {
return -1;
}
if (literal_cd != NULL) {
err = hs_compile_lit_multi((const char *const *)literal_cd->patterns,
literal_cd->flags,literal_cd->ids,
literal_cd->pattern_lens, literal_cd->n_patterns,
HS_MODE_STREAM | HS_MODE_SOM_HORIZON_SMALL, NULL,
&hs_rt->literal_db, &compile_err);
if (err != HS_SUCCESS) {
if (compile_err) {
log_error(logger, MODULE_ADAPTER_HS, "[%s:%d] compile error: %s",
__FUNCTION__, __LINE__, compile_err->message);
}
hs_free_compile_error(compile_err);
return -1;
}
}
if (regex_cd != NULL) {
err = hs_compile_multi((const char *const *)regex_cd->patterns,
regex_cd->flags, regex_cd->ids, regex_cd->n_patterns,
HS_MODE_STREAM | HS_MODE_SOM_HORIZON_SMALL,
NULL, &hs_rt->regex_db, &compile_err);
if (err != HS_SUCCESS) {
if (compile_err) {
log_error(logger, MODULE_ADAPTER_HS, "[%s:%d] compile error: %s",
__FUNCTION__, __LINE__, compile_err->message);
}
hs_free_compile_error(compile_err);
return -1;
}
}
return 0;
}
static struct adpt_hs_compile_data *adpt_hs_compile_data_new(size_t n_patterns)
{
struct adpt_hs_compile_data *hs_cd = ALLOC(struct adpt_hs_compile_data, 1);
hs_cd->patterns = ALLOC(char *, n_patterns);
hs_cd->pattern_lens = ALLOC(size_t, n_patterns);
hs_cd->n_patterns = n_patterns;
hs_cd->ids = ALLOC(unsigned int, n_patterns);
hs_cd->flags = ALLOC(unsigned int, n_patterns);
return hs_cd;
}
static void adpt_hs_compile_data_free(struct adpt_hs_compile_data *hs_cd)
{
if (NULL == hs_cd) {
return;
}
if (hs_cd->patterns != NULL) {
for (size_t i = 0; i < hs_cd->n_patterns; i++) {
FREE(hs_cd->patterns[i]);
}
FREE(hs_cd->patterns);
}
if (hs_cd->pattern_lens != NULL) {
FREE(hs_cd->pattern_lens);
}
if (hs_cd->ids != NULL) {
FREE(hs_cd->ids);
}
if (hs_cd->flags != NULL) {
FREE(hs_cd->flags);
}
FREE(hs_cd);
}
static void populate_compile_data(struct adpt_hs_compile_data *compile_data,
int index, int pattern_id, char *pat,
size_t pat_len, int case_sensitive)
{
compile_data->ids[index] = pattern_id;
/* set flags */
compile_data->flags[index] |= HS_FLAG_SOM_LEFTMOST;
if (case_sensitive == EXPR_CASE_INSENSITIVE) {
compile_data->flags[index] |= HS_FLAG_CASELESS;
}
compile_data->pattern_lens[index] = pat_len;
compile_data->patterns[index] = ALLOC(char, pat_len + 1);
memcpy(compile_data->patterns[index], pat, pat_len);
}
static struct bool_expr *bool_exprs_new(struct expr_rule *rules, size_t n_rule,
struct pattern_attribute *pattern_attr,
struct adpt_hs_compile_data *literal_cd,
struct adpt_hs_compile_data *regex_cd,
size_t *n_pattern)
{
uint32_t pattern_index = 0;
uint32_t literal_index = 0;
uint32_t regex_index = 0;
struct bool_expr *bool_exprs = ALLOC(struct bool_expr, n_rule);
if (NULL == bool_exprs) {
return NULL;
}
/* populate adpt_hs_compile_data and bool_expr */
for (size_t i = 0; i < n_rule; i++) {
for (size_t j = 0; j < rules[i].n_patterns; j++) {
pattern_attr[pattern_index].pattern_id = pattern_index;
pattern_attr[pattern_index].match_mode = rules[i].patterns[j].match_mode;
if (pattern_attr[pattern_index].match_mode == EXPR_MATCH_MODE_SUB ||
pattern_attr[pattern_index].match_mode == EXPR_MATCH_MODE_EXACTLY) {
pattern_attr[pattern_index].offset.start = rules[i].patterns[j].start_offset;
pattern_attr[pattern_index].offset.end = rules[i].patterns[j].end_offset;
}
/* literal pattern */
if (rules[i].patterns[j].type == EXPR_PATTERN_TYPE_STR) {
populate_compile_data(literal_cd, literal_index, pattern_index,
rules[i].patterns[j].pat, rules[i].patterns[j].pat_len,
rules[i].patterns[j].case_sensitive);
literal_index++;
} else {
/* regex pattern */
populate_compile_data(regex_cd, regex_index, pattern_index,
rules[i].patterns[j].pat, rules[i].patterns[j].pat_len,
rules[i].patterns[j].case_sensitive);
regex_index++;
}
bool_exprs[i].items[j].item_id = pattern_index++;
bool_exprs[i].items[j].not_flag = 0;
}
bool_exprs[i].expr_id = rules[i].expr_id;
bool_exprs[i].item_num = rules[i].n_patterns;
bool_exprs[i].user_tag = rules[i].tag;
}
*n_pattern = pattern_index;
return bool_exprs;
}
static int verify_regex_expression(const char *regex_str, struct log_handle *logger)
{
hs_expr_info_t *info = NULL;
hs_compile_error_t *error = NULL;
hs_error_t err = hs_expression_info(regex_str, HS_FLAG_CASELESS, &info, &error);
if (err != HS_SUCCESS) {
// Expression will fail compilation and report error elsewhere.
if (logger != NULL) {
log_error(logger, MODULE_ADAPTER_HS,
"[%s:%d] illegal regex expression: \"%s\": %s",
__FUNCTION__, __LINE__, regex_str, error->message);
}
FREE(info);
hs_free_compile_error(error);
return 0;
}
if (info != NULL) {
FREE(info);
}
return 1;
}
int adapter_hs_verify_regex_expression(const char *regex_expr, struct log_handle *logger)
{
if (NULL == regex_expr) {
return 0;
}
return verify_regex_expression(regex_expr, logger);
}
void *adapter_hs_new(struct expr_rule *rules, size_t n_rule,
size_t n_literal_pattern, size_t n_regex_pattern,
size_t n_worker_thread, struct log_handle *logger)
{
/* get the sum of pattern */
size_t i = 0;
struct adpt_hs_compile_data *literal_cd = NULL;
struct adpt_hs_compile_data *regex_cd = NULL;
if (n_literal_pattern > 0) {
literal_cd = adpt_hs_compile_data_new(n_literal_pattern);
}
if (n_regex_pattern > 0) {
regex_cd = adpt_hs_compile_data_new(n_regex_pattern);
}
size_t pattern_cnt = n_literal_pattern + n_regex_pattern;
struct adapter_hs *hs_inst = ALLOC(struct adapter_hs, 1);
hs_inst->hs_attr = ALLOC(struct pattern_attribute, pattern_cnt);
hs_inst->logger = logger;
hs_inst->n_worker_thread = n_worker_thread;
hs_inst->n_expr = n_rule;
struct bool_expr *bool_exprs = bool_exprs_new(rules, n_rule, hs_inst->hs_attr,
literal_cd, regex_cd, &pattern_cnt);
if (NULL == bool_exprs) {
return NULL;
}
hs_inst->n_patterns = pattern_cnt;
/* create bool matcher */
size_t mem_size = 0;
int hs_ret = 0;
hs_inst->hs_rt = ALLOC(struct adapter_hs_runtime, 1);
//hs_rt->bm
hs_inst->hs_rt->bm = bool_matcher_new(bool_exprs, n_rule, &mem_size);
if (hs_inst->hs_rt->bm != NULL) {
log_info(logger, MODULE_ADAPTER_HS,
"Adapter_hs module: build bool matcher of %zu expressions"
" with %zu bytes memory", n_rule, mem_size);
} else {
log_error(logger, MODULE_ADAPTER_HS,
"[%s:%d] Adapter_hs module: build bool matcher failed",
__FUNCTION__, __LINE__);
hs_ret = -1;
}
FREE(bool_exprs);
/* build hs database hs_rt->literal_db & hs_rt->regex_db */
int ret = adpt_hs_build_database(hs_inst->hs_rt, literal_cd, regex_cd, logger);
if (ret < 0) {
hs_ret = -1;
}
if (literal_cd != NULL) {
adpt_hs_compile_data_free(literal_cd);
}
if (regex_cd != NULL) {
adpt_hs_compile_data_free(regex_cd);
}
if (hs_ret < 0) {
goto error;
}
/* alloc scratch */
hs_inst->hs_rt->scratch = ALLOC(struct adapter_hs_scratch, 1);
hs_inst->hs_rt->scratch->bool_match_buffs = ALLOC(struct bool_expr_match *,
n_worker_thread);
for (i = 0; i < n_worker_thread; i++) {
hs_inst->hs_rt->scratch->bool_match_buffs[i] = ALLOC(struct bool_expr_match,
MAX_HIT_EXPR_NUM);
}
/* literal and regex scratch can't reuse */
if (n_literal_pattern > 0) {
ret = adpt_hs_alloc_scratch(hs_inst->hs_rt, n_worker_thread,
EXPR_PATTERN_TYPE_STR, logger);
if (ret < 0) {
goto error;
}
}
if (n_regex_pattern > 0) {
ret = adpt_hs_alloc_scratch(hs_inst->hs_rt, n_worker_thread,
EXPR_PATTERN_TYPE_REG, logger);
if (ret < 0) {
goto error;
}
}
hs_inst->hs_rt->streams = ALLOC(struct adapter_hs_stream *, n_worker_thread);
for (i = 0; i < n_worker_thread; i++) {
hs_inst->hs_rt->streams[i] = (struct adapter_hs_stream *)adapter_hs_stream_open(hs_inst, i);
}
return hs_inst;
error:
adapter_hs_free(hs_inst);
return NULL;
}
void adapter_hs_free(void *hs_instance)
{
if (NULL == hs_instance) {
return;
}
struct adapter_hs *hs_inst = (struct adapter_hs *)hs_instance;
size_t i = 0;
if (hs_inst->hs_rt != NULL) {
if (hs_inst->hs_rt->literal_db != NULL) {
hs_free_database(hs_inst->hs_rt->literal_db);
hs_inst->hs_rt->literal_db = NULL;
}
if (hs_inst->hs_rt->regex_db != NULL) {
hs_free_database(hs_inst->hs_rt->regex_db);
hs_inst->hs_rt->regex_db = NULL;
}
if (hs_inst->hs_rt->scratch != NULL) {
if (hs_inst->hs_rt->scratch->literal_scratches != NULL) {
for (i = 0; i < hs_inst->n_worker_thread; i++) {
if (hs_inst->hs_rt->scratch->literal_scratches[i] != NULL) {
hs_free_scratch(hs_inst->hs_rt->scratch->literal_scratches[i]);
hs_inst->hs_rt->scratch->literal_scratches[i] = NULL;
}
}
FREE(hs_inst->hs_rt->scratch->literal_scratches);
}
if (hs_inst->hs_rt->scratch->regex_scratches != NULL) {
for (i = 0; i < hs_inst->n_worker_thread; i++) {
if (hs_inst->hs_rt->scratch->regex_scratches[i] != NULL) {
hs_free_scratch(hs_inst->hs_rt->scratch->regex_scratches[i]);
hs_inst->hs_rt->scratch->regex_scratches[i] = NULL;
}
}
FREE(hs_inst->hs_rt->scratch->regex_scratches);
}
if (hs_inst->hs_rt->scratch->bool_match_buffs != NULL) {
for (i = 0; i < hs_inst->n_worker_thread; i++) {
if (hs_inst->hs_rt->scratch->bool_match_buffs[i] != NULL) {
FREE(hs_inst->hs_rt->scratch->bool_match_buffs[i]);
}
}
FREE(hs_inst->hs_rt->scratch->bool_match_buffs);
}
FREE(hs_inst->hs_rt->scratch);
}
if (hs_inst->hs_rt->bm != NULL) {
bool_matcher_free(hs_inst->hs_rt->bm);
hs_inst->hs_rt->bm = NULL;
}
if (hs_inst->hs_rt->streams != NULL) {
for (i = 0; i < hs_inst->n_worker_thread; i++) {
if (hs_inst->hs_rt->streams[i] != NULL) {
adapter_hs_stream_close(hs_inst->hs_rt->streams[i]);
hs_inst->hs_rt->streams[i] = NULL;
}
}
FREE(hs_inst->hs_rt->streams);
}
FREE(hs_inst->hs_rt);
}
if (hs_inst->hs_attr != NULL) {
FREE(hs_inst->hs_attr);
}
FREE(hs_inst);
}
static inline int compare_pattern_id(const void *a, const void *b)
{
long long ret = *(const unsigned long long *)a - *(const unsigned long long *)b;
if (ret == 0) {
return 0;
} else if(ret < 0) {
return -1;
} else {
return 1;
}
}
/**
* @param id: pattern id
*/
static int matched_event_cb(unsigned int id, unsigned long long from,
unsigned long long to, unsigned int flags,
void *ctx)
{
// put id in set
unsigned long long pattern_id = id;
struct matched_pattern *matched_pat = (struct matched_pattern *)ctx;
if (id > matched_pat->n_patterns || id < 0) {
return 0;
}
if (utarray_len(matched_pat->pattern_ids) >= MAX_HIT_PATTERN_NUM) {
return 0;
}
// duplicate pattern_id
if (utarray_find(matched_pat->pattern_ids, &pattern_id, compare_pattern_id)) {
return 0;
}
int ret = 0;
struct pattern_attribute pat_attr = matched_pat->ref_hs_attr[id];
switch (pat_attr.match_mode) {
case EXPR_MATCH_MODE_EXACTLY:
if (0 == from && matched_pat->scan_data_len == to) {
ret = 1;
}
break;
case EXPR_MATCH_MODE_SUB:
if (pat_attr.offset.start == -1 &&
pat_attr.offset.end == -1) {
ret = 1;
break;
}
if (pat_attr.offset.start == -1) {
if ((long long)(to - 1) <= pat_attr.offset.end) {
ret = 1;
break;
}
}
if (pat_attr.offset.end == -1) {
if ((long long)from >= pat_attr.offset.start) {
ret = 1;
break;
}
}
if ((long long)from >= pat_attr.offset.start &&
(long long)(to - 1) <= pat_attr.offset.end) {
ret = 1;
}
break;
case EXPR_MATCH_MODE_PREFIX:
if (0 == from) {
ret = 1;
}
break;
case EXPR_MATCH_MODE_SUFFIX:
if (to == matched_pat->scan_data_len) {
ret = 1;
}
break;
default:
break;
}
if (1 == ret) {
utarray_push_back(matched_pat->pattern_ids, &pattern_id);
utarray_sort(matched_pat->pattern_ids, compare_pattern_id);
}
return 0;
}
UT_icd ut_hs_pattern_id_icd = {sizeof(unsigned long long), NULL, NULL, NULL};
void *adapter_hs_stream_open(void *hs_instance, int thread_id)
{
if (NULL == hs_instance || thread_id < 0) {
return NULL;
}
struct adapter_hs *hs_inst = (struct adapter_hs *)hs_instance;
struct adapter_hs_stream *hs_stream = ALLOC(struct adapter_hs_stream, 1);
hs_error_t err;
hs_stream->logger = hs_inst->logger;
hs_stream->thread_id = thread_id;
hs_stream->ref_hs_rt = hs_inst->hs_rt;
hs_stream->matched_pat = ALLOC(struct matched_pattern, 1);
hs_stream->matched_pat->ref_hs_attr = hs_inst->hs_attr;
hs_stream->matched_pat->n_patterns = hs_inst->n_patterns;
utarray_new(hs_stream->matched_pat->pattern_ids, &ut_hs_pattern_id_icd);
utarray_reserve(hs_stream->matched_pat->pattern_ids, MAX_HIT_PATTERN_NUM);
int err_count = 0;
if (hs_inst->hs_rt->literal_db != NULL) {
err = hs_open_stream(hs_inst->hs_rt->literal_db, 0,
&hs_stream->literal_stream);
if (err != HS_SUCCESS) {
log_error(hs_inst->logger, MODULE_ADAPTER_HS,
"hs_open_stream failed, hs err:%d", err);
err_count++;
}
}
if (hs_inst->hs_rt->regex_db != NULL) {
err = hs_open_stream(hs_inst->hs_rt->regex_db, 0,
&hs_stream->regex_stream);
if (err != HS_SUCCESS) {
log_error(hs_inst->logger, MODULE_ADAPTER_HS,
"hs_open_stream failed, hs err:%d", err);
err_count++;
}
}
if (err_count > 0) {
goto error;
}
return hs_stream;
error:
if (hs_stream->literal_stream != NULL) {
hs_close_stream(hs_stream->literal_stream, NULL, NULL, NULL);
hs_stream->literal_stream = NULL;
}
if (hs_stream->regex_stream != NULL) {
hs_close_stream(hs_stream->regex_stream, NULL, NULL, NULL);
hs_stream->regex_stream = NULL;
}
FREE(hs_stream);
return NULL;
}
void adapter_hs_stream_close(void *hs_stream)
{
if (NULL == hs_stream) {
return;
}
struct adapter_hs_stream *stream = (struct adapter_hs_stream *)hs_stream;
if (stream->ref_hs_rt != NULL) {
if (stream->literal_stream != NULL) {
hs_close_stream(stream->literal_stream, NULL, NULL, NULL);
stream->literal_stream = NULL;
}
if (stream->regex_stream != NULL) {
hs_close_stream(stream->regex_stream, NULL, NULL, NULL);
stream->regex_stream = NULL;
}
}
/* stream->hs_rt point to hs_instance->hs_rt which will call free
same as hs_attr */
stream->ref_hs_rt = NULL;
stream->matched_pat->ref_hs_attr = NULL;
if (stream->matched_pat->pattern_ids != NULL) {
utarray_free(stream->matched_pat->pattern_ids);
stream->matched_pat->pattern_ids = NULL;
}
FREE(stream->matched_pat);
FREE(stream);
}
static void adapter_hs_stream_reset(struct adapter_hs_stream *hs_stream)
{
if (NULL == hs_stream) {
return;
}
struct adapter_hs_scratch *scratch = hs_stream->ref_hs_rt->scratch;
if (hs_stream->literal_stream != NULL) {
hs_reset_stream(hs_stream->literal_stream, 0,
scratch->literal_scratches[hs_stream->thread_id],
matched_event_cb, hs_stream->matched_pat);
}
if (hs_stream->regex_stream != NULL) {
hs_reset_stream(hs_stream->regex_stream, 0,
scratch->regex_scratches[hs_stream->thread_id],
matched_event_cb, hs_stream->matched_pat);
}
utarray_clear(hs_stream->matched_pat->pattern_ids);
}
int adapter_hs_scan_stream(void *hs_stream, const char *data, size_t data_len,
struct expr_scan_result *results, size_t n_result,
size_t *n_hit_result)
{
hs_error_t err;
if (NULL == hs_stream || NULL == data || 0 == data_len ||
NULL == results || 0 == n_result || NULL == n_hit_result) {
return -1;
}
/*
In streaming mode, a non-zero return from the user-specified event-handler
function has consequences for the rest of that stream's lifetime: when a
non-zero return occurs, it signals that no more of the stream should be
scanned. Consequently if the user makes a subsequent call to
`hs_scan_stream` on a stream whose processing was terminated in this way,
hs_scan_stream will return `HS_SCAN_TERMINATED`. This case has not been
demonstrated in pcapscan, as its callback always returns 0.
*/
int err_count = 0;
struct adapter_hs_stream *stream = (struct adapter_hs_stream *)hs_stream;
int thread_id = stream->thread_id;
struct adapter_hs_scratch *scratch = stream->ref_hs_rt->scratch;
stream->matched_pat->scan_data_len = data_len;
int err_scratch_flag = 0;
if (stream->literal_stream != NULL) {
if (scratch->literal_scratches != NULL) {
err = hs_scan_stream(stream->literal_stream, data, data_len,
0, scratch->literal_scratches[thread_id],
matched_event_cb, stream->matched_pat);
if (err != HS_SUCCESS) {
err_count++;
}
} else {
log_error(stream->logger, MODULE_ADAPTER_HS,
"literal_scratches is null, thread_id:%d", thread_id);
err_scratch_flag++;
}
}
if (stream->regex_stream != NULL) {
if (scratch->regex_scratches != NULL) {
err = hs_scan_stream(stream->regex_stream, data, data_len,
0, scratch->regex_scratches[thread_id],
matched_event_cb, stream->matched_pat);
if (err != HS_SUCCESS) {
err_count++;
}
} else {
log_error(stream->logger, MODULE_ADAPTER_HS,
"regex_scratches is null, thread_id:%d", thread_id);
err_scratch_flag++;
}
}
if (err_count == 2) {
return -1;
}
if (err_scratch_flag != 0) {
return -1;
}
size_t n_pattern_id = utarray_len(stream->matched_pat->pattern_ids);
if (0 == n_pattern_id) {
*n_hit_result = 0;
return 0;
}
unsigned long long pattern_ids[n_pattern_id];
for (size_t i = 0; i < n_pattern_id; i++) {
pattern_ids[i] = *(unsigned long long *)utarray_eltptr(stream->matched_pat->pattern_ids, i);
}
int ret = 0;
struct bool_expr_match *bool_matcher_results = scratch->bool_match_buffs[thread_id];
int bool_matcher_ret = bool_matcher_match(stream->ref_hs_rt->bm, pattern_ids, n_pattern_id,
bool_matcher_results, MAX_HIT_EXPR_NUM);
if (bool_matcher_ret < 0) {
ret = -1;
goto next;
}
if (bool_matcher_ret > (int)n_result) {
bool_matcher_ret = n_result;
}
for (int index = 0; index < bool_matcher_ret; index++) {
results[index].rule_id = bool_matcher_results[index].expr_id;
results[index].user_tag = bool_matcher_results[index].user_tag;
}
*n_hit_result = bool_matcher_ret;
next:
utarray_clear(stream->matched_pat->pattern_ids);
return ret;
}
int adapter_hs_scan(void *hs_instance, int thread_id, const char *data, size_t data_len,
struct expr_scan_result *results, size_t n_result, size_t *n_hit_result)
{
if (NULL == hs_instance || NULL == data || (0 == data_len) ||
NULL == results || 0 == n_result || NULL == n_hit_result) {
return -1;
}
struct adapter_hs *hs_inst = (struct adapter_hs *)hs_instance;
struct adapter_hs_stream *hs_stream = hs_inst->hs_rt->streams[thread_id];
assert(hs_stream != NULL);
adapter_hs_stream_reset(hs_stream);
return adapter_hs_scan_stream(hs_stream, data, data_len, results, n_result, n_hit_result);
}