61 static int rule_warnings_only = 0;
117 { 0,
false,
false,
true,
"http_uri",
"http uri" },
118 { 0,
false,
false,
false,
"http_raw_uri",
"http raw uri" },
119 { 0,
false,
true,
false,
"http_method",
"http method" },
120 { 0,
false,
false,
false,
"http_request_line",
"http request line" },
121 { 0,
false,
false,
false,
"http_client_body",
"http client body" },
122 { 0,
false,
false,
true,
"http_header",
"http header" },
123 { 0,
false,
false,
false,
"http_raw_header",
"http raw header" },
124 { 0,
false,
false,
true,
"http_cookie",
"http cookie" },
125 { 0,
false,
false,
false,
"http_user_agent",
"http user agent" },
126 { 0,
false,
false,
false,
"http_host",
"http host" },
127 { 0,
false,
false,
false,
"http_raw_host",
"http raw host" },
128 { 0,
false,
false,
false,
"http_accept_enc",
"http accept enc" },
129 { 0,
false,
false,
false,
"http_referer",
"http referer" },
130 { 0,
false,
false,
false,
"http_content_type",
"http content type" },
131 { 0,
false,
false,
false,
"http_header_names",
"http header names" },
134 { 0,
false,
false,
false,
"http_stat_msg",
"http stat msg" },
135 { 0,
false,
false,
false,
"http_stat_code",
"http stat code" },
136 { 0,
false,
true,
false,
"file_data",
"http server body" },
139 { 0,
false,
false,
false,
"http_request_line",
"http request line" },
140 { 0,
false,
false,
false,
"http_accept",
"http accept" },
141 { 0,
false,
false,
false,
"http_accept_lang",
"http accept lang" },
142 { 0,
false,
false,
false,
"http_connection",
"http connection" },
143 { 0,
false,
false,
false,
"http_content_len",
"http content len" },
144 { 0,
false,
false,
false,
"http_protocol",
"http protocol" },
145 { 0,
false,
false,
false,
"http_start",
"http start" },
148 { 0,
false,
false,
false,
"http_response_line",
"http response line" },
149 { 0,
false,
false,
false,
"http.server",
"http server" },
150 { 0,
false,
false,
false,
"http.location",
"http location" },
153 static void FpPatternStatsAdd(
FpPatternStats *fp,
int list, uint16_t patlen)
162 else if (patlen < f->min)
174 int fast_pattern_set = 0;
175 int fast_pattern_only_set = 0;
176 int fast_pattern_chop_set = 0;
181 if (mpm_sm != NULL) {
184 fast_pattern_set = 1;
186 fast_pattern_only_set = 1;
188 fast_pattern_chop_set = 1;
194 fprintf(fp,
"== Sid: %u ==\n", s->
id);
195 fprintf(fp,
"%s\n", line);
197 fprintf(fp,
" Fast Pattern analysis:\n");
199 fprintf(fp,
" Prefilter on: %s\n",
206 fprintf(fp,
" No content present\n");
211 fprintf(fp,
" Fast pattern matcher: ");
212 int list_type = mpm_sm_list;
214 fprintf(fp,
"content\n");
219 fprintf(fp,
"%s (%s)\n", desc,
name);
224 fprintf(fp,
" Flags:");
226 fprintf(fp,
" Offset");
229 fprintf(fp,
" Depth");
233 fprintf(fp,
" Within");
237 fprintf(fp,
" Distance");
241 fprintf(fp,
" Nocase");
245 fprintf(fp,
" Negated");
249 fprintf(fp,
" None");
252 fprintf(fp,
" Fast pattern set: %s\n", fast_pattern_set ?
"yes" :
"no");
253 fprintf(fp,
" Fast pattern only set: %s\n", fast_pattern_only_set ?
"yes" :
"no");
254 fprintf(fp,
" Fast pattern chop set: %s\n", fast_pattern_chop_set ?
"yes" :
"no");
255 if (fast_pattern_chop_set) {
256 fprintf(fp,
" Fast pattern offset, length: %u, %u\n", fp_cd->
fp_chop_offset,
267 fprintf(fp,
" Original content: ");
271 if (fast_pattern_chop_set) {
280 fprintf(fp,
" Final content: ");
286 fprintf(fp,
" Final content: ");
315 char *log_path =
SCMalloc(PATH_MAX);
316 if (log_path == NULL) {
317 FatalError(
"Unable to allocate scratch memory for rule filename");
319 snprintf(log_path, PATH_MAX,
"%s/%s%s", log_dir,
322 FILE *fp = fopen(log_path,
"w");
324 SCLogError(
"failed to open %s: %s", log_path, strerror(errno));
331 SCLogInfo(
"Engine-Analysis for fast_pattern printed to file - %s",
336 gettimeofday(&tval, NULL);
338 struct tm *tms =
SCLocalTime(tval.tv_sec, &local_tm);
339 fprintf(fp,
"----------------------------------------------"
340 "---------------------\n");
342 "Date: %" PRId32
"/%" PRId32
"/%04d -- "
344 tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min,
346 fprintf(fp,
"----------------------------------------------"
347 "---------------------\n");
360 #define DETECT_PERCENT_ENCODING_REGEX "%[0-9|a-f|A-F]{2}"
366 PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
368 PCRE2_UCHAR errbuffer[256];
369 pcre2_get_error_message(en, errbuffer,
sizeof(errbuffer));
390 }
else if (value && strcasecmp(value,
"warnings-only") == 0) {
392 rule_warnings_only = 1;
397 char log_path[PATH_MAX];
398 snprintf(log_path,
sizeof(log_path),
"%s/%s%s", log_dir,
402 SCLogError(
"failed to open %s: %s", log_path, strerror(errno));
406 SCLogInfo(
"Engine-Analysis for rules printed to file - %s",
410 gettimeofday(&tval, NULL);
412 struct tm *tms =
SCLocalTime(tval.tv_sec, &local_tm);
414 "----------------------------------------------"
415 "---------------------\n");
417 "Date: %" PRId32
"/%" PRId32
"/%04d -- "
419 tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min,
422 "----------------------------------------------"
423 "---------------------\n");
426 if (!PerCentEncodingSetup(
de_ctx->
ea)) {
428 "Error compiling regex; can't check for percent encoding in normalized "
434 SCLogInfo(
"Conf parameter \"engine-analysis.rules\" not found. "
435 "Defaulting to not printing the rules analysis report.");
438 SCLogInfo(
"Engine-Analysis for rules disabled in conf file.");
447 fprintf(fp,
"============\n"
448 "Summary:\n============\n");
456 "%s, smallest pattern %u byte(s), longest pattern %u byte(s), number of patterns "
457 "%u, avg pattern len %.2f byte(s)\n",
459 (
float)((
double)f->
tot / (
float)f->
cnt));
479 *fp_analysis =
false;
480 *rule_analysis =
false;
484 FatalError(
"Unable to allocate per-engine analysis context");
489 if (cfg_prefix_len > 0) {
494 FatalError(
"Unable to allocate per-engine analysis context name buffer");
500 *fp_analysis = SetupFPAnalyzer(
de_ctx);
501 *rule_analysis = SetupRuleAnalyzer(
de_ctx);
503 if (!(*fp_analysis || *rule_analysis)) {
516 CleanupRuleAnalyzer(
de_ctx);
517 CleanupFPAnalyzer(
de_ctx);
534 static int PerCentEncodingMatch(
EngineAnalysisCtx *ea_ctx, uint8_t *content, uint16_t content_len)
538 pcre2_match_data *match = pcre2_match_data_create_from_pattern(ea_ctx->
percent_re, NULL);
539 ret = pcre2_match(ea_ctx->
percent_re, (PCRE2_SPTR8)content, content_len, 0, 0, match, NULL);
542 }
else if (ret < -1) {
543 SCLogError(
"Error parsing content - %s; error code is %d", content, ret);
546 pcre2_match_data_free(match);
556 if (mpm_sm != NULL) {
594 const int list_type = mpm_sm_list;
603 payload ? (stream ?
"payload and reassembled stream" :
"payload")
604 :
"reassembled stream");
611 }
else if (desc ||
name) {
631 fprintf(tmp_fp,
"== Sid: UNKNOWN ==\n");
632 fprintf(tmp_fp,
"%s\n", line);
633 fprintf(tmp_fp,
" FAILURE: invalid rule.\n");
634 fprintf(tmp_fp,
" File: %s.\n", file);
635 fprintf(tmp_fp,
" Line: %d.\n", lineno);
636 fprintf(tmp_fp,
"\n");
653 vsnprintf(
str,
sizeof(
str), fmt, ap);
657 ctx->js_notes = SCJbNewArray();
659 SCJbAppendString(
ctx->js_notes,
str);
668 vsnprintf(
str,
sizeof(
str), fmt, ap);
671 if (!
ctx->js_warnings)
672 ctx->js_warnings = SCJbNewArray();
673 if (
ctx->js_warnings)
674 SCJbAppendString(
ctx->js_warnings,
str);
677 #define CHECK(pat) if (strlen((pat)) <= len && memcmp((pat), buf, MIN(len, strlen((pat)))) == 0) return true;
679 static bool LooksLikeHTTPMethod(
const uint8_t *buf, uint16_t
len)
688 static bool LooksLikeHTTPUA(
const uint8_t *buf, uint16_t
len)
690 CHECK(
"User-Agent: ");
691 CHECK(
"\nUser-Agent: ");
697 char pattern_str[1024] =
"";
700 SCJbSetString(js,
"pattern", pattern_str);
709 SCJbSetUint(js,
"offset", cd->
offset);
712 SCJbSetUint(js,
"depth", cd->
depth);
715 SCJbSetInt(js,
"distance", cd->
distance);
718 SCJbSetInt(js,
"within", cd->
within);
737 SCJbOpenArray(js,
"matches");
741 SCJbSetString(js,
"name", mname);
747 SCJbOpenObject(js,
"content");
750 AnalyzerNote(
ctx, (
char *)
"'fast_pattern:only' option is silently ignored and "
751 "is interpreted as regular 'fast_pattern'");
755 (
char *)
"pattern looks like it inspects HTTP, use http.request_line or "
756 "http.method and http.uri instead for improved performance");
760 (
char *)
"pattern looks like it inspects HTTP, use http.user_agent "
761 "or http.header for improved performance");
764 AnalyzerNote(
ctx, (
char *)
"'within' option for pattern w/o previous content "
765 "was converted to 'depth'");
768 AnalyzerNote(
ctx, (
char *)
"'distance' option for pattern w/o previous content "
769 "was converted to 'offset'");
777 SCJbOpenObject(js,
"pcre");
782 (
char *)
"'/B' (rawbytes) option is a no-op and is silently ignored");
785 AnalyzerNote(
ctx, (
char *)
"pcre with \\X (Unicode extended grapheme cluster) "
793 SCJbOpenObject(js,
"byte_jump");
794 SCJbSetUint(js,
"nbytes", cd->
nbytes);
795 SCJbSetInt(js,
"offset", cd->
offset);
796 SCJbSetUint(js,
"multiplier", cd->
multiplier);
800 SCJbSetString(js,
"base",
"unset");
803 SCJbSetString(js,
"base",
"oct");
806 SCJbSetString(js,
"base",
"dec");
809 SCJbSetString(js,
"base",
"hex");
812 SCJbOpenArray(js,
"flags");
814 SCJbAppendString(js,
"from_beginning");
816 SCJbAppendString(js,
"little_endian");
818 SCJbAppendString(js,
"big_endian");
820 SCJbAppendString(js,
"string");
822 SCJbAppendString(js,
"relative");
824 SCJbAppendString(js,
"align");
826 SCJbAppendString(js,
"dce");
828 SCJbAppendString(js,
"offset_be");
830 SCJbAppendString(js,
"from_end");
838 SCJbOpenObject(js,
"byte_test");
839 SCJbSetUint(js,
"nbytes", cd->
nbytes);
840 SCJbSetInt(js,
"offset", cd->
offset);
843 SCJbSetString(js,
"base",
"unset");
846 SCJbSetString(js,
"base",
"oct");
849 SCJbSetString(js,
"base",
"dec");
852 SCJbSetString(js,
"base",
"hex");
855 SCJbOpenArray(js,
"flags");
857 SCJbAppendString(js,
"little_endian");
859 SCJbAppendString(js,
"big_endian");
861 SCJbAppendString(js,
"string");
863 SCJbAppendString(js,
"relative");
865 SCJbAppendString(js,
"dce");
872 SCJbOpenObject(js,
"absent");
873 SCJbSetBool(js,
"or_else", dad->
or_else);
881 SCJbOpenObject(js,
"ipopts");
883 SCJbSetString(js,
"option", flag);
890 SCJbOpenObject(js,
"flowbits");
893 SCJbSetString(js,
"cmd",
"isset");
896 SCJbSetString(js,
"cmd",
"isnotset");
899 SCJbSetString(js,
"cmd",
"set");
902 SCJbSetString(js,
"cmd",
"unset");
906 SCJbOpenArray(js,
"names");
912 const char *varname =
914 SCJbAppendString(js, varname);
919 SCJbSetString(js,
"operator",
"or");
927 SCJbOpenObject(js,
"xbits");
930 SCJbSetString(js,
"cmd",
"isset");
933 SCJbSetString(js,
"cmd",
"isnotset");
936 SCJbSetString(js,
"cmd",
"set");
939 SCJbSetString(js,
"cmd",
"unset");
942 SCJbSetString(js,
"cmd",
"toggle");
948 SCJbSetString(js,
"track",
"ip_src");
951 SCJbSetString(js,
"track",
"ip_dst");
954 SCJbSetString(js,
"track",
"ip_pair");
957 SCJbSetString(js,
"track",
"tx");
961 SCJbSetUint(js,
"expire", xd->
expire);
968 SCJbOpenObject(js,
"flowint");
971 SCJbSetString(js,
"cmd",
"set");
974 SCJbSetString(js,
"cmd",
"add");
977 SCJbSetString(js,
"cmd",
"sub");
980 SCJbSetString(js,
"cmd",
"lt");
983 SCJbSetString(js,
"cmd",
"lte");
986 SCJbSetString(js,
"cmd",
"eq");
989 SCJbSetString(js,
"cmd",
"ne");
992 SCJbSetString(js,
"cmd",
"gte");
995 SCJbSetString(js,
"cmd",
"gt");
998 SCJbSetString(js,
"cmd",
"isset");
1001 SCJbSetString(js,
"cmd",
"isnotset");
1005 if (varname != NULL) {
1006 SCJbSetString(js,
"var", varname);
1020 SCJbOpenObject(js,
"ack");
1021 SCDetectU32ToJson(js, cd);
1027 SCJbOpenObject(js,
"seq");
1028 SCDetectU32ToJson(js, cd);
1034 SCJbOpenObject(js,
"tcp_mss");
1035 SCDetectU16ToJson(js, cd);
1041 SCJbOpenObject(js,
"dsize");
1042 SCDetectU16ToJson(js, cd);
1048 SCJbOpenObject(js,
"code");
1049 SCDetectU8ToJson(js, cd);
1055 SCJbOpenObject(js,
"ttl");
1056 SCDetectU8ToJson(js, cd);
1062 SCJbOpenObject(js,
"id");
1063 SCDetectU16ToJson(js, cd);
1069 SCJbOpenObject(js,
"window");
1070 SCDetectU16ToJson(js, cd);
1076 SCJbOpenObject(js,
"flow_age");
1077 SCDetectU32ToJson(js, cd);
1082 const uint8_t *dfd = (
const uint8_t *)smd->
ctx;
1083 SCJbOpenObject(js,
"flow_elephant");
1085 case DETECT_FLOW_TOSERVER:
1086 SCJbSetString(js,
"dir",
"toserver");
1088 case DETECT_FLOW_TOCLIENT:
1089 SCJbSetString(js,
"dir",
"toclient");
1091 case DETECT_FLOW_TOEITHER:
1092 SCJbSetString(js,
"dir",
"either");
1094 case DETECT_FLOW_TOBOTH:
1095 SCJbSetString(js,
"dir",
"both");
1118 ctx.js = SCJbNewObject();
1129 SCJbSetUint(
ctx.js,
"id", s->
id);
1130 SCJbSetUint(
ctx.js,
"gid", s->
gid);
1131 SCJbSetUint(
ctx.js,
"rev", s->
rev);
1132 SCJbSetString(
ctx.js,
"msg", s->
msg);
1135 SCJbSetString(
ctx.js,
"app_proto", alproto);
1137 SCJbOpenArray(
ctx.js,
"requirements");
1139 SCJbAppendString(
ctx.js,
"payload");
1142 SCJbAppendString(
ctx.js,
"no_payload");
1145 SCJbAppendString(
ctx.js,
"flow");
1148 SCJbAppendString(
ctx.js,
"tcp_flags_init_deinit");
1151 SCJbAppendString(
ctx.js,
"tcp_flags_unusual");
1154 SCJbAppendString(
ctx.js,
"engine_event");
1157 SCJbAppendString(
ctx.js,
"real_pkt");
1161 SCJbOpenObject(
ctx.js,
"match_policy");
1162 SCJbOpenArray(
ctx.js,
"actions");
1164 SCJbAppendString(
ctx.js,
"alert");
1167 SCJbAppendString(
ctx.js,
"drop");
1170 SCJbAppendString(
ctx.js,
"reject");
1173 SCJbAppendString(
ctx.js,
"reject_dst");
1176 SCJbAppendString(
ctx.js,
"reject_both");
1179 SCJbAppendString(
ctx.js,
"config");
1182 SCJbAppendString(
ctx.js,
"pass");
1185 SCJbAppendString(
ctx.js,
"accept");
1191 switch (flow_action) {
1193 SCJbSetString(
ctx.js,
"scope",
"packet");
1196 SCJbSetString(
ctx.js,
"scope",
"flow");
1199 SCJbSetString(
ctx.js,
"scope",
"flow_if_stateful");
1206 SCJbSetString(
ctx.js,
"scope",
"packet");
1209 SCJbSetString(
ctx.js,
"scope",
"flow");
1212 SCJbSetString(
ctx.js,
"scope",
"hook");
1215 SCJbSetString(
ctx.js,
"scope",
"tx");
1225 SCJbSetString(
ctx.js,
"type",
"unset");
1228 SCJbSetString(
ctx.js,
"type",
"ip_only");
1231 SCJbSetString(
ctx.js,
"type",
"like_ip_only");
1234 SCJbSetString(
ctx.js,
"type",
"pd_only");
1237 SCJbSetString(
ctx.js,
"type",
"de_only");
1240 SCJbSetString(
ctx.js,
"type",
"pkt");
1243 SCJbSetString(
ctx.js,
"type",
"pkt_stream");
1246 SCJbSetString(
ctx.js,
"type",
"stream");
1249 SCJbSetString(
ctx.js,
"type",
"app_layer");
1252 SCJbSetString(
ctx.js,
"type",
"app_tx");
1255 SCJbSetString(
ctx.js,
"type",
"error");
1261 SCJbOpenObject(
ctx.js,
"dependencies");
1262 SCJbOpenObject(
ctx.js,
"flowbits");
1263 SCJbOpenObject(
ctx.js,
"upstream");
1265 SCJbOpenObject(
ctx.js,
"state_modifying_rules");
1266 SCJbOpenArray(
ctx.js,
"sids");
1271 SCJbOpenArray(
ctx.js,
"names");
1274 SCJbAppendString(
ctx.js,
1287 SCJbOpenArray(
ctx.js,
"flags");
1289 SCJbAppendString(
ctx.js,
"src_any");
1292 SCJbAppendString(
ctx.js,
"dst_any");
1295 SCJbAppendString(
ctx.js,
"sp_any");
1298 SCJbAppendString(
ctx.js,
"dp_any");
1301 SCJbAppendString(
ctx.js,
"noalert");
1304 SCJbAppendString(
ctx.js,
"dsize");
1307 SCJbAppendString(
ctx.js,
"applayer");
1310 SCJbAppendString(
ctx.js,
"need_packet");
1313 SCJbAppendString(
ctx.js,
"need_stream");
1316 SCJbAppendString(
ctx.js,
"negated_mpm");
1319 SCJbAppendString(
ctx.js,
"flush");
1322 SCJbAppendString(
ctx.js,
"need_flowvar");
1325 SCJbAppendString(
ctx.js,
"filestore");
1328 SCJbAppendString(
ctx.js,
"toserver");
1331 SCJbAppendString(
ctx.js,
"toclient");
1334 SCJbAppendString(
ctx.js,
"tlsstore");
1337 SCJbAppendString(
ctx.js,
"bypass");
1340 SCJbAppendString(
ctx.js,
"prefilter");
1343 SCJbAppendString(
ctx.js,
"src_is_target");
1346 SCJbAppendString(
ctx.js,
"dst_is_target");
1353 SCJbOpenArray(
ctx.js,
"pkt_engines");
1355 for ( ; pkt != NULL; pkt = pkt->
next) {
1370 SCJbStartObject(
ctx.js);
1371 SCJbSetString(
ctx.js,
"name",
name);
1372 SCJbSetBool(
ctx.js,
"is_mpm", pkt->
mpm);
1374 SCJbOpenArray(
ctx.js,
"transforms");
1376 SCJbStartObject(
ctx.js);
1377 SCJbSetString(
ctx.js,
"name",
1390 SCJbOpenArray(
ctx.js,
"frame_engines");
1392 for (; frame != NULL; frame = frame->
next) {
1394 SCJbStartObject(
ctx.js);
1395 SCJbSetString(
ctx.js,
"name",
name);
1396 SCJbSetBool(
ctx.js,
"is_mpm", frame->
mpm);
1398 SCJbOpenArray(
ctx.js,
"transforms");
1400 SCJbStartObject(
ctx.js);
1401 SCJbSetString(
ctx.js,
"name",
1413 bool has_stream =
false;
1414 bool has_client_body_mpm =
false;
1415 bool has_file_data_mpm =
false;
1417 SCJbOpenArray(
ctx.js,
"engines");
1419 for ( ; app != NULL; app = app->
next) {
1434 }
else if (app->
mpm && strcmp(
name,
"http_client_body") == 0) {
1435 has_client_body_mpm =
true;
1436 }
else if (app->
mpm && strcmp(
name,
"file_data") == 0) {
1437 has_file_data_mpm =
true;
1440 SCJbStartObject(
ctx.js);
1441 SCJbSetString(
ctx.js,
"name",
name);
1442 const char *direction = app->
dir == 0 ?
"toserver" :
"toclient";
1443 SCJbSetString(
ctx.js,
"direction", direction);
1444 SCJbSetBool(
ctx.js,
"is_mpm", app->
mpm);
1449 SCJbOpenArray(
ctx.js,
"transforms");
1451 SCJbStartObject(
ctx.js);
1452 SCJbSetString(
ctx.js,
"name",
1466 if (has_stream && has_client_body_mpm)
1467 AnalyzerNote(&
ctx, (
char *)
"mpm in http_client_body combined with stream match leads to stream buffering");
1468 if (has_stream && has_file_data_mpm)
1469 AnalyzerNote(&
ctx, (
char *)
"mpm in file_data combined with stream match leads to stream buffering");
1472 SCJbOpenObject(
ctx.js,
"lists");
1482 if (pkt_mpm || app_mpm) {
1483 SCJbOpenObject(
ctx.js,
"mpm");
1491 SCJbSetString(
ctx.js,
"buffer",
name);
1499 switch (smd->
type) {
1503 DumpContent(
ctx.js, cd);
1515 SCJbOpenObject(
ctx.js,
"prefilter");
1522 SCJbSetString(
ctx.js,
"buffer",
name);
1524 SCJbSetString(
ctx.js,
"name", mname);
1528 if (
ctx.js_warnings) {
1529 SCJbClose(
ctx.js_warnings);
1530 SCJbSetObject(
ctx.js,
"warnings",
ctx.js_warnings);
1531 SCJbFree(
ctx.js_warnings);
1532 ctx.js_warnings = NULL;
1535 SCJbClose(
ctx.js_notes);
1536 SCJbSetObject(
ctx.js,
"notes",
ctx.js_notes);
1537 SCJbFree(
ctx.js_notes);
1538 ctx.js_notes = NULL;
1542 const char *filename =
"rules.json";
1544 char json_path[PATH_MAX] =
"";
1545 snprintf(json_path,
sizeof(json_path),
"%s/%s%s", log_dir,
1549 FILE *fp = fopen(json_path,
"a");
1551 fwrite(SCJbPtr(
ctx.js), SCJbLen(
ctx.js), 1, fp);
1565 SCJsonBuilder *root_jb = SCJbNewObject();
1566 if (root_jb == NULL) {
1570 if (arrays == NULL) {
1575 SCJbOpenArray(root_jb,
"buffers");
1579 char str[1024] =
"";
1583 SCJsonBuilder *jb = arrays[
p->sm_list];
1584 if (arrays[
p->sm_list] == NULL) {
1585 jb = arrays[
p->sm_list] = SCJbNewObject();
1591 SCJbSetString(jb,
"name",
name);
1592 SCJbSetUint(jb,
"list_id",
p->sm_list);
1594 SCJbOpenArray(jb,
"patterns");
1597 SCJbStartObject(jb);
1598 SCJbSetString(jb,
"pattern",
str);
1599 SCJbSetUint(jb,
"patlen",
p->cd->content_len);
1600 SCJbSetUint(jb,
"cnt",
p->cnt);
1601 SCJbSetUint(jb,
"mpm",
p->mpm);
1602 SCJbOpenObject(jb,
"flags");
1613 SCJsonBuilder *jb = arrays[i];
1620 SCJbAppendObject(root_jb, jb);
1626 const char *filename =
"patterns.json";
1628 char json_path[PATH_MAX] =
"";
1629 snprintf(json_path,
sizeof(json_path),
"%s/%s%s", log_dir,
1633 FILE *fp = fopen(json_path,
"a");
1635 fwrite(SCJbPtr(root_jb), SCJbLen(root_jb), 1, fp);
1657 EngineAnalysisItemsReset(ea_ctx);
1665 FatalError(
"Unable to allocate analysis scratch pad");
1675 analyzer_item->
item_id = (uint16_t)item_id;
1676 if (analyzer_item->
item_id == -1) {
1678 FatalError(
"unable to initialize engine-analysis table: detect buffer \"%s\" not "
1711 uint32_t rule_bidirectional = 0;
1712 uint32_t rule_pcre = 0;
1713 uint32_t rule_pcre_http = 0;
1714 uint32_t rule_content = 0;
1715 uint32_t rule_flow = 0;
1716 uint32_t rule_flags = 0;
1717 uint32_t rule_flow_toserver = 0;
1718 uint32_t rule_flow_toclient = 0;
1719 uint32_t rule_flow_nostream = 0;
1720 uint32_t rule_ipv4_only = 0;
1721 uint32_t rule_ipv6_only = 0;
1722 uint32_t rule_flowbits = 0;
1723 uint32_t rule_flowint = 0;
1724 uint32_t rule_content_http = 0;
1725 uint32_t rule_content_offset_depth = 0;
1726 int32_t list_id = 0;
1727 uint32_t rule_warning = 0;
1728 uint32_t stream_buf = 0;
1729 uint32_t packet_buf = 0;
1730 uint32_t file_store = 0;
1731 uint32_t warn_pcre_no_content = 0;
1732 uint32_t warn_pcre_http_content = 0;
1733 uint32_t warn_pcre_http = 0;
1734 uint32_t warn_content_http_content = 0;
1735 uint32_t warn_content_http = 0;
1736 uint32_t warn_tcp_no_flow = 0;
1737 uint32_t warn_client_ports = 0;
1738 uint32_t warn_direction = 0;
1739 uint32_t warn_method_toclient = 0;
1740 uint32_t warn_method_serverbody = 0;
1741 uint32_t warn_pcre_method = 0;
1742 uint32_t warn_encoding_norm_http_buf = 0;
1743 uint32_t warn_file_store_not_present = 0;
1744 uint32_t warn_offset_depth_pkt_stream = 0;
1745 uint32_t warn_offset_depth_alproto = 0;
1746 uint32_t warn_non_alproto_fp_for_alproto_sig = 0;
1747 uint32_t warn_no_direction = 0;
1748 uint32_t warn_both_direction = 0;
1750 EngineAnalysisItemsInit(
de_ctx->
ea);
1756 rule_bidirectional = 1;
1770 rule_ipv4_only += 1;
1773 rule_ipv6_only += 1;
1781 if (item_slot == -1) {
1789 if (item_slot == -1) {
1794 rule_content_offset_depth++;
1800 rule_content_http++;
1807 warn_encoding_norm_http_buf += 1;
1814 rule_flow_toserver = 1;
1817 rule_flow_toclient = 1;
1822 rule_flow_nostream = 1;
1836 if (sm->
ctx != NULL) {
1846 warn_file_store_not_present = 1;
1849 if (rule_pcre > 0 && rule_content == 0 && rule_content_http == 0) {
1851 warn_pcre_no_content = 1;
1854 if (rule_content_http > 0 && rule_pcre > 0 && rule_pcre_http == 0) {
1856 warn_pcre_http_content = 1;
1862 if (rule_content > 0 && rule_content_http > 0) {
1864 warn_content_http_content = 1;
1868 warn_content_http = 1;
1870 if (rule_content == 1) {
1875 (rule_content || rule_content_http || rule_pcre || rule_pcre_http || rule_flowbits ||
1878 warn_tcp_no_flow = 1;
1880 if (rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)
1885 warn_client_ports = 1;
1888 if (rule_flow && rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)) {
1893 if (*http_method_item_seen_ptr) {
1894 if (rule_flow && rule_flow_toclient) {
1896 warn_method_toclient = 1;
1898 if (*http_server_body_item_seen_ptr) {
1900 warn_method_serverbody = 1;
1902 if (rule_content == 0 && rule_content_http == 0 && (rule_pcre > 0 || rule_pcre_http > 0)) {
1904 warn_pcre_method = 1;
1907 if (rule_content_offset_depth > 0 && stream_buf && packet_buf) {
1909 warn_offset_depth_pkt_stream = 1;
1913 warn_offset_depth_alproto = 1;
1918 warn_non_alproto_fp_for_alproto_sig = 1;
1922 warn_no_direction += 1;
1930 warn_both_direction += 1;
1935 if (!rule_warnings_only || (rule_warnings_only && rule_warning > 0)) {
1937 fprintf(fp,
"== Sid: %u ==\n", s->
id);
1938 fprintf(fp,
"%s\n", line);
1944 fprintf(fp,
" Rule is ip only.\n");
1947 fprintf(fp,
" Rule is like ip only.\n");
1950 fprintf(fp,
" Rule is PD only.\n");
1953 fprintf(fp,
" Rule is DE only.\n");
1956 fprintf(fp,
" Rule is packet inspecting.\n");
1959 fprintf(fp,
" Rule is packet and stream inspecting.\n");
1962 fprintf(fp,
" Rule is stream inspecting.\n");
1965 fprintf(fp,
" Rule is app-layer inspecting.\n");
1968 fprintf(fp,
" Rule is App-layer TX inspecting.\n");
1974 fprintf(fp,
" Rule is IPv6 only.\n");
1976 fprintf(fp,
" Rule is IPv4 only.\n");
1978 fprintf(fp,
" Rule matches on packets.\n");
1979 if (!rule_flow_nostream && stream_buf &&
1980 (rule_flow || rule_flowbits || rule_flowint || rule_content || rule_pcre)) {
1981 fprintf(fp,
" Rule matches on reassembled stream.\n");
1986 fprintf(fp,
" Rule matches on %s buffer.\n", ai->
display_name);
1992 if (rule_content || rule_content_http || rule_pcre || rule_pcre_http) {
1994 " Rule contains %u content options, %u http content options, %u pcre "
1995 "options, and %u pcre options with http modifiers.\n",
1996 rule_content, rule_content_http, rule_pcre, rule_pcre_http);
2001 fprintf(fp,
" Prefilter on: %s.\n",
2004 EngineAnalysisRulesPrintFP(
de_ctx, s);
2008 if (warn_pcre_no_content ) {
2009 fprintf(fp,
" Warning: Rule uses pcre without a content option present.\n"
2010 " -Consider adding a content to improve performance of this "
2013 if (warn_pcre_http_content ) {
2014 fprintf(fp,
" Warning: Rule uses content options with http_* and pcre options "
2015 "without http modifiers.\n"
2016 " -Consider adding http pcre modifier.\n");
2018 else if (warn_pcre_http ) {
2019 fprintf(fp,
" Warning: Rule app layer protocol is http, but pcre options do not "
2020 "have http modifiers.\n"
2021 " -Consider adding http pcre modifiers.\n");
2023 if (warn_content_http_content ) {
2025 " Warning: Rule contains content with http_* and content without http_*.\n"
2026 " -Consider adding http content modifiers.\n");
2028 if (warn_content_http ) {
2029 fprintf(fp,
" Warning: Rule app layer protocol is http, but content options do not "
2030 "have http_* modifiers.\n"
2031 " -Consider adding http content modifiers.\n");
2033 if (rule_content == 1) {
2036 if (warn_encoding_norm_http_buf) {
2037 fprintf(fp,
" Warning: Rule may contain percent encoded content for a normalized "
2038 "http buffer match.\n");
2040 if (warn_tcp_no_flow
2042 fprintf(fp,
" Warning: TCP rule without a flow or flags option.\n"
2043 " -Consider adding flow or flags to improve performance of "
2046 if (warn_client_ports
2051 " Warning: Rule contains ports or port variables only on the client side.\n"
2052 " -Flow direction possibly inconsistent with rule.\n");
2054 if (warn_direction ) {
2055 fprintf(fp,
" Warning: Rule is bidirectional and has a flow option with a specific "
2058 if (warn_method_toclient ) {
2059 fprintf(fp,
" Warning: Rule uses content or pcre for http_method with "
2060 "flow:to_client or from_server\n");
2062 if (warn_method_serverbody ) {
2063 fprintf(fp,
" Warning: Rule uses content or pcre for http_method with content or "
2064 "pcre for http_server_body.\n");
2066 if (warn_pcre_method
2068 fprintf(fp,
" Warning: Rule uses pcre with only a http_method content; possible "
2069 "performance issue.\n");
2071 if (warn_offset_depth_pkt_stream) {
2072 fprintf(fp,
" Warning: Rule has depth"
2073 "/offset with raw content keywords. Please note the "
2074 "offset/depth will be checked against both packet "
2075 "payloads and stream. If you meant to have the offset/"
2076 "depth checked against just the payload, you can update "
2077 "the signature as \"alert tcp-pkt...\"\n");
2079 if (warn_offset_depth_alproto) {
2081 " Warning: Rule has "
2082 "offset/depth set along with a match on a specific "
2083 "app layer protocol - %d. This can lead to FNs if we "
2084 "have a offset/depth content match on a packet payload "
2085 "before we can detect the app layer protocol for the "
2089 if (warn_non_alproto_fp_for_alproto_sig) {
2090 fprintf(fp,
" Warning: Rule app layer "
2091 "protocol is http, but the fast_pattern is set on the raw "
2092 "stream. Consider adding fast_pattern over a http "
2093 "buffer for increased performance.");
2095 if (warn_no_direction) {
2096 fprintf(fp,
" Warning: Rule has no direction indicator.\n");
2098 if (warn_both_direction) {
2099 fprintf(fp,
" Warning: Rule is inspecting both the request and the response.\n");
2101 if (warn_file_store_not_present) {
2102 fprintf(fp,
" Warning: Rule requires file-store but the output file-store is not "
2105 if (rule_warning == 0) {
2106 fprintf(fp,
" No warnings for this rule.\n");
2115 const uint8_t state,
const uint8_t direction)
2117 char policy_string[64] =
"";
2120 if (direction == STREAM_TOSERVER) {
2121 p = &fw_policies->
app[a].
ts[state];
2123 p = &fw_policies->
app[a].
tc[state];
2131 snprintf(policy_string,
sizeof(policy_string),
"rejectdst:%s", as);
2133 snprintf(policy_string,
sizeof(policy_string),
"rejectboth:%s", as);
2135 snprintf(policy_string,
sizeof(policy_string),
"rejectsrc:%s", as);
2138 snprintf(policy_string,
sizeof(policy_string),
"drop:%s", as);
2140 snprintf(policy_string,
sizeof(policy_string),
"accept:%s", as);
2146 strlcat(policy_string,
",pass:flow",
sizeof(policy_string));
2151 SCJbSetString(
ctx->js,
"policy", policy_string);
2157 uint32_t accept_rules = 0;
2158 AddPolicy(
de_ctx,
ctx, a, state, direction);
2159 SCJbOpenArray(
ctx->js,
"rules");
2168 if (direction == STREAM_TOSERVER) {
2190 if (accept_rules == 0) {
2191 AnalyzerWarning(
ctx, (
char *)
"no accept rules for state, default policy will be applied");
2198 ctx.js = SCJbNewObject();
2202 SCJbOpenObject(
ctx.js,
"tables");
2203 SCJbOpenObject(
ctx.js,
"packet:filter");
2204 SCJbSetString(
ctx.js,
"policy",
"drop:packet");
2205 SCJbOpenArray(
ctx.js,
"rules");
2206 uint32_t accept_rules = 0;
2207 uint32_t last_sid = 0;
2214 if (last_sid == s->
id)
2221 if (accept_rules == 0) {
2222 AnalyzerWarning(&
ctx,
2223 (
char *)
"no accept rules for \'packet:filter\', default policy will be applied");
2225 if (
ctx.js_warnings) {
2226 SCJbClose(
ctx.js_warnings);
2227 SCJbSetObject(
ctx.js,
"warnings",
ctx.js_warnings);
2228 SCJbFree(
ctx.js_warnings);
2229 ctx.js_warnings = NULL;
2234 if (!AppProtoIsValid(a))
2237 const uint8_t complete_state_ts =
2240 for (uint8_t state = 0; state <= complete_state_ts; state++) {
2245 name =
"request-started";
2246 else if (state == complete_state_ts)
2247 name =
"request-complete";
2252 char table_name[128];
2254 SCJbOpenObject(
ctx.js, table_name);
2255 FirewallAddRulesForState(
de_ctx, a, state, STREAM_TOSERVER, &
ctx);
2256 if (
ctx.js_warnings) {
2257 SCJbClose(
ctx.js_warnings);
2258 SCJbSetObject(
ctx.js,
"warnings",
ctx.js_warnings);
2259 SCJbFree(
ctx.js_warnings);
2260 ctx.js_warnings = NULL;
2264 const uint8_t complete_state_tc =
2266 for (uint8_t state = 0; state <= complete_state_tc; state++) {
2271 name =
"response-started";
2272 else if (state == complete_state_tc)
2273 name =
"response-complete";
2277 char table_name[128];
2279 SCJbOpenObject(
ctx.js, table_name);
2280 FirewallAddRulesForState(
de_ctx, a, state, STREAM_TOCLIENT, &
ctx);
2281 if (
ctx.js_warnings) {
2282 SCJbClose(
ctx.js_warnings);
2283 SCJbSetObject(
ctx.js,
"warnings",
ctx.js_warnings);
2284 SCJbFree(
ctx.js_warnings);
2285 ctx.js_warnings = NULL;
2291 SCJbOpenObject(
ctx.js,
"packet:td");
2292 SCJbSetString(
ctx.js,
"policy",
"accept:hook");
2294 SCJbOpenArray(
ctx.js,
"rules");
2300 if (last_sid == s->
id)
2307 SCJbOpenObject(
ctx.js,
"app:td");
2308 SCJbSetString(
ctx.js,
"policy",
"accept:hook");
2310 SCJbOpenArray(
ctx.js,
"rules");
2316 if (last_sid == s->
id)
2325 SCJbOpenObject(
ctx.js,
"lists");
2326 SCJbOpenObject(
ctx.js,
"firewall");
2328 SCJbOpenArray(
ctx.js,
"rules");
2332 if (last_sid == s->
id)
2340 SCJbOpenObject(
ctx.js,
"td");
2342 SCJbOpenArray(
ctx.js,
"rules");
2346 if (last_sid == s->
id)
2354 SCJbOpenObject(
ctx.js,
"all");
2356 SCJbOpenArray(
ctx.js,
"rules");
2358 if (last_sid == s->
id)
2370 const char *filename =
"firewall.json";
2372 char json_path[PATH_MAX] =
"";
2373 snprintf(json_path,
sizeof(json_path),
"%s/%s", log_dir, filename);
2376 FILE *fp = fopen(json_path,
"w");
2378 fwrite(SCJbPtr(
ctx.js), SCJbLen(
ctx.js), 1, fp);