|
|
|
@ -608,28 +608,16 @@ static bool LooksLikeHTTPUA(const uint8_t *buf, uint16_t len)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DumpMatches(RuleAnalyzer *ctx, JsonBuilder *js, const SigMatchData *smd)
|
|
|
|
|
static void DumpContent(JsonBuilder *js, const DetectContentData *cd)
|
|
|
|
|
{
|
|
|
|
|
if (smd == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
jb_open_array(js, "matches");
|
|
|
|
|
do {
|
|
|
|
|
jb_start_object(js);
|
|
|
|
|
const char *mname = sigmatch_table[smd->type].name;
|
|
|
|
|
jb_set_string(js, "name", mname);
|
|
|
|
|
|
|
|
|
|
switch (smd->type) {
|
|
|
|
|
case DETECT_CONTENT: {
|
|
|
|
|
const DetectContentData *cd = (const DetectContentData *)smd->ctx;
|
|
|
|
|
|
|
|
|
|
jb_open_object(js, "content");
|
|
|
|
|
jb_set_string_from_bytes(js, "pattern", cd->content, cd->content_len);
|
|
|
|
|
jb_set_uint(js, "length", cd->content_len);
|
|
|
|
|
jb_set_bool(js, "nocase", cd->flags & DETECT_CONTENT_NOCASE);
|
|
|
|
|
jb_set_bool(js, "negated", cd->flags & DETECT_CONTENT_NEGATED);
|
|
|
|
|
jb_set_bool(js, "starts_with", cd->flags & DETECT_CONTENT_STARTS_WITH);
|
|
|
|
|
jb_set_bool(js, "ends_with", cd->flags & DETECT_CONTENT_ENDS_WITH);
|
|
|
|
|
jb_set_bool(js, "is_mpm", cd->flags & DETECT_CONTENT_MPM);
|
|
|
|
|
jb_set_bool(js, "no_double_inspect", cd->flags & DETECT_CONTENT_NO_DOUBLE_INSPECTION_REQUIRED);
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_OFFSET) {
|
|
|
|
|
jb_set_uint(js, "offset", cd->offset);
|
|
|
|
|
}
|
|
|
|
@ -643,6 +631,25 @@ static void DumpMatches(RuleAnalyzer *ctx, JsonBuilder *js, const SigMatchData *
|
|
|
|
|
jb_set_uint(js, "within", cd->within);
|
|
|
|
|
}
|
|
|
|
|
jb_set_bool(js, "fast_pattern", cd->flags & DETECT_CONTENT_FAST_PATTERN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void DumpMatches(RuleAnalyzer *ctx, JsonBuilder *js, const SigMatchData *smd)
|
|
|
|
|
{
|
|
|
|
|
if (smd == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
jb_open_array(js, "matches");
|
|
|
|
|
do {
|
|
|
|
|
jb_start_object(js);
|
|
|
|
|
const char *mname = sigmatch_table[smd->type].name;
|
|
|
|
|
jb_set_string(js, "name", mname);
|
|
|
|
|
|
|
|
|
|
switch (smd->type) {
|
|
|
|
|
case DETECT_CONTENT: {
|
|
|
|
|
const DetectContentData *cd = (const DetectContentData *)smd->ctx;
|
|
|
|
|
|
|
|
|
|
jb_open_object(js, "content");
|
|
|
|
|
DumpContent(js, cd);
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_FAST_PATTERN_ONLY) {
|
|
|
|
|
AnalyzerNote(ctx, (char *)"'fast_pattern:only' option is silently ignored and "
|
|
|
|
|
"is interpreted as regular 'fast_pattern'");
|
|
|
|
@ -783,6 +790,9 @@ void EngineAnalysisRules2(const DetectEngineCtx *de_ctx, const Signature *s)
|
|
|
|
|
}
|
|
|
|
|
jb_close(ctx.js);
|
|
|
|
|
|
|
|
|
|
const DetectEnginePktInspectionEngine *pkt_mpm = NULL;
|
|
|
|
|
const DetectEngineAppInspectionEngine *app_mpm = NULL;
|
|
|
|
|
|
|
|
|
|
jb_open_array(ctx.js, "pkt_engines");
|
|
|
|
|
const DetectEnginePktInspectionEngine *pkt = s->pkt_inspect;
|
|
|
|
|
for ( ; pkt != NULL; pkt = pkt->next) {
|
|
|
|
@ -805,6 +815,9 @@ void EngineAnalysisRules2(const DetectEngineCtx *de_ctx, const Signature *s)
|
|
|
|
|
jb_set_bool(ctx.js, "is_mpm", pkt->mpm);
|
|
|
|
|
DumpMatches(&ctx, ctx.js, pkt->smd);
|
|
|
|
|
jb_close(ctx.js);
|
|
|
|
|
if (pkt->mpm) {
|
|
|
|
|
pkt_mpm = pkt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
jb_close(ctx.js);
|
|
|
|
|
|
|
|
|
@ -845,6 +858,9 @@ void EngineAnalysisRules2(const DetectEngineCtx *de_ctx, const Signature *s)
|
|
|
|
|
jb_set_uint(ctx.js, "progress", app->progress);
|
|
|
|
|
DumpMatches(&ctx, ctx.js, app->smd);
|
|
|
|
|
jb_close(ctx.js);
|
|
|
|
|
if (app->mpm) {
|
|
|
|
|
app_mpm = app;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
jb_close(ctx.js);
|
|
|
|
|
|
|
|
|
@ -864,6 +880,39 @@ void EngineAnalysisRules2(const DetectEngineCtx *de_ctx, const Signature *s)
|
|
|
|
|
}
|
|
|
|
|
jb_close(ctx.js);
|
|
|
|
|
|
|
|
|
|
if (pkt_mpm || app_mpm) {
|
|
|
|
|
jb_open_object(ctx.js, "mpm");
|
|
|
|
|
|
|
|
|
|
int mpm_list = pkt_mpm ? DETECT_SM_LIST_PMATCH : app_mpm->sm_list;
|
|
|
|
|
const char *name;
|
|
|
|
|
if (mpm_list < DETECT_SM_LIST_DYNAMIC_START)
|
|
|
|
|
name = DetectListToHumanString(mpm_list);
|
|
|
|
|
else
|
|
|
|
|
name = DetectBufferTypeGetNameById(de_ctx, mpm_list);
|
|
|
|
|
jb_set_string(ctx.js, "buffer", name);
|
|
|
|
|
|
|
|
|
|
SigMatchData *smd = pkt_mpm ? pkt_mpm->smd : app_mpm->smd;
|
|
|
|
|
if (smd == NULL && mpm_list == DETECT_SM_LIST_PMATCH) {
|
|
|
|
|
smd = s->sm_arrays[mpm_list];
|
|
|
|
|
}
|
|
|
|
|
do {
|
|
|
|
|
switch (smd->type) {
|
|
|
|
|
case DETECT_CONTENT: {
|
|
|
|
|
const DetectContentData *cd = (const DetectContentData *)smd->ctx;
|
|
|
|
|
if (cd->flags & DETECT_CONTENT_MPM) {
|
|
|
|
|
DumpContent(ctx.js, cd);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (smd->is_last)
|
|
|
|
|
break;
|
|
|
|
|
smd++;
|
|
|
|
|
} while (1);
|
|
|
|
|
jb_close(ctx.js);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ctx.js_warnings) {
|
|
|
|
|
jb_close(ctx.js_warnings);
|
|
|
|
|
jb_set_object(ctx.js, "warnings", ctx.js_warnings);
|
|
|
|
|