64 static int rule_warnings_only = 0;
120 { 0,
false,
false,
true,
"http_uri",
"http uri" },
121 { 0,
false,
false,
false,
"http_raw_uri",
"http raw uri" },
122 { 0,
false,
true,
false,
"http_method",
"http method" },
123 { 0,
false,
false,
false,
"http_request_line",
"http request line" },
124 { 0,
false,
false,
false,
"http_client_body",
"http client body" },
125 { 0,
false,
false,
true,
"http_header",
"http header" },
126 { 0,
false,
false,
false,
"http_raw_header",
"http raw header" },
127 { 0,
false,
false,
true,
"http_cookie",
"http cookie" },
128 { 0,
false,
false,
false,
"http_user_agent",
"http user agent" },
129 { 0,
false,
false,
false,
"http_host",
"http host" },
130 { 0,
false,
false,
false,
"http_raw_host",
"http raw host" },
131 { 0,
false,
false,
false,
"http_accept_enc",
"http accept enc" },
132 { 0,
false,
false,
false,
"http_referer",
"http referer" },
133 { 0,
false,
false,
false,
"http_content_type",
"http content type" },
134 { 0,
false,
false,
false,
"http_header_names",
"http header names" },
137 { 0,
false,
false,
false,
"http_stat_msg",
"http stat msg" },
138 { 0,
false,
false,
false,
"http_stat_code",
"http stat code" },
139 { 0,
false,
true,
false,
"file_data",
"http server body" },
142 { 0,
false,
false,
false,
"http_request_line",
"http request line" },
143 { 0,
false,
false,
false,
"http_accept",
"http accept" },
144 { 0,
false,
false,
false,
"http_accept_lang",
"http accept lang" },
145 { 0,
false,
false,
false,
"http_connection",
"http connection" },
146 { 0,
false,
false,
false,
"http_content_len",
"http content len" },
147 { 0,
false,
false,
false,
"http_protocol",
"http protocol" },
148 { 0,
false,
false,
false,
"http_start",
"http start" },
151 { 0,
false,
false,
false,
"http_response_line",
"http response line" },
152 { 0,
false,
false,
false,
"http.server",
"http server" },
153 { 0,
false,
false,
false,
"http.location",
"http location" },
156 static void FpPatternStatsAdd(
FpPatternStats *fp,
int list, uint16_t patlen)
165 else if (patlen < f->min)
177 int fast_pattern_set = 0;
178 int fast_pattern_only_set = 0;
179 int fast_pattern_chop_set = 0;
184 if (mpm_sm != NULL) {
187 fast_pattern_set = 1;
189 fast_pattern_only_set = 1;
191 fast_pattern_chop_set = 1;
197 fprintf(fp,
"== Sid: %u ==\n", s->
id);
198 fprintf(fp,
"%s\n", line);
200 fprintf(fp,
" Fast Pattern analysis:\n");
202 fprintf(fp,
" Prefilter on: %s\n",
209 fprintf(fp,
" No content present\n");
214 fprintf(fp,
" Fast pattern matcher: ");
215 int list_type = mpm_sm_list;
217 fprintf(fp,
"content\n");
222 fprintf(fp,
"%s (%s)\n", desc,
name);
227 fprintf(fp,
" Flags:");
229 fprintf(fp,
" Offset");
232 fprintf(fp,
" Depth");
236 fprintf(fp,
" Within");
240 fprintf(fp,
" Distance");
244 fprintf(fp,
" Nocase");
248 fprintf(fp,
" Negated");
252 fprintf(fp,
" None");
255 fprintf(fp,
" Fast pattern set: %s\n", fast_pattern_set ?
"yes" :
"no");
256 fprintf(fp,
" Fast pattern only set: %s\n", fast_pattern_only_set ?
"yes" :
"no");
257 fprintf(fp,
" Fast pattern chop set: %s\n", fast_pattern_chop_set ?
"yes" :
"no");
258 if (fast_pattern_chop_set) {
259 fprintf(fp,
" Fast pattern offset, length: %u, %u\n", fp_cd->
fp_chop_offset,
270 fprintf(fp,
" Original content: ");
274 if (fast_pattern_chop_set) {
283 fprintf(fp,
" Final content: ");
289 fprintf(fp,
" Final content: ");
318 char *log_path =
SCMalloc(PATH_MAX);
319 if (log_path == NULL) {
320 FatalError(
"Unable to allocate scratch memory for rule filename");
322 snprintf(log_path, PATH_MAX,
"%s/%s%s", log_dir,
325 FILE *fp = fopen(log_path,
"w");
327 SCLogError(
"failed to open %s: %s", log_path, strerror(errno));
334 SCLogInfo(
"Engine-Analysis for fast_pattern printed to file - %s",
339 gettimeofday(&tval, NULL);
341 struct tm *tms =
SCLocalTime(tval.tv_sec, &local_tm);
342 fprintf(fp,
"----------------------------------------------"
343 "---------------------\n");
345 "Date: %" PRId32
"/%" PRId32
"/%04d -- "
347 tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min,
349 fprintf(fp,
"----------------------------------------------"
350 "---------------------\n");
363 #define DETECT_PERCENT_ENCODING_REGEX "%[0-9|a-f|A-F]{2}"
369 PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
371 PCRE2_UCHAR errbuffer[256];
372 pcre2_get_error_message(en, errbuffer,
sizeof(errbuffer));
393 }
else if (value && strcasecmp(value,
"warnings-only") == 0) {
395 rule_warnings_only = 1;
400 char log_path[PATH_MAX];
401 snprintf(log_path,
sizeof(log_path),
"%s/%s%s", log_dir,
405 SCLogError(
"failed to open %s: %s", log_path, strerror(errno));
409 SCLogInfo(
"Engine-Analysis for rules printed to file - %s",
413 gettimeofday(&tval, NULL);
415 struct tm *tms =
SCLocalTime(tval.tv_sec, &local_tm);
417 "----------------------------------------------"
418 "---------------------\n");
420 "Date: %" PRId32
"/%" PRId32
"/%04d -- "
422 tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min,
425 "----------------------------------------------"
426 "---------------------\n");
429 if (!PerCentEncodingSetup(
de_ctx->
ea)) {
431 "Error compiling regex; can't check for percent encoding in normalized "
437 SCLogInfo(
"Conf parameter \"engine-analysis.rules\" not found. "
438 "Defaulting to not printing the rules analysis report.");
441 SCLogInfo(
"Engine-Analysis for rules disabled in conf file.");
450 fprintf(fp,
"============\n"
451 "Summary:\n============\n");
459 "%s, smallest pattern %u byte(s), longest pattern %u byte(s), number of patterns "
460 "%u, avg pattern len %.2f byte(s)\n",
462 (
float)((
double)f->
tot / (
float)f->
cnt));
482 *fp_analysis =
false;
483 *rule_analysis =
false;
487 FatalError(
"Unable to allocate per-engine analysis context");
492 if (cfg_prefix_len > 0) {
497 FatalError(
"Unable to allocate per-engine analysis context name buffer");
503 *fp_analysis = SetupFPAnalyzer(
de_ctx);
504 *rule_analysis = SetupRuleAnalyzer(
de_ctx);
506 if (!(*fp_analysis || *rule_analysis)) {
519 CleanupRuleAnalyzer(
de_ctx);
520 CleanupFPAnalyzer(
de_ctx);
537 static int PerCentEncodingMatch(
EngineAnalysisCtx *ea_ctx, uint8_t *content, uint16_t content_len)
541 pcre2_match_data *match = pcre2_match_data_create_from_pattern(ea_ctx->
percent_re, NULL);
542 ret = pcre2_match(ea_ctx->
percent_re, (PCRE2_SPTR8)content, content_len, 0, 0, match, NULL);
545 }
else if (ret < -1) {
546 SCLogError(
"Error parsing content - %s; error code is %d", content, ret);
549 pcre2_match_data_free(match);
559 if (mpm_sm != NULL) {
597 const int list_type = mpm_sm_list;
606 payload ? (stream ?
"payload and reassembled stream" :
"payload")
607 :
"reassembled stream");
614 }
else if (desc ||
name) {
634 fprintf(tmp_fp,
"== Sid: UNKNOWN ==\n");
635 fprintf(tmp_fp,
"%s\n", line);
636 fprintf(tmp_fp,
" FAILURE: invalid rule.\n");
637 fprintf(tmp_fp,
" File: %s.\n", file);
638 fprintf(tmp_fp,
" Line: %d.\n", lineno);
639 fprintf(tmp_fp,
"\n");
656 vsnprintf(
str,
sizeof(
str), fmt, ap);
660 ctx->js_notes = SCJbNewArray();
662 SCJbAppendString(
ctx->js_notes,
str);
671 vsnprintf(
str,
sizeof(
str), fmt, ap);
674 if (!
ctx->js_warnings)
675 ctx->js_warnings = SCJbNewArray();
676 if (
ctx->js_warnings)
677 SCJbAppendString(
ctx->js_warnings,
str);
680 #define CHECK(pat) if (strlen((pat)) <= len && memcmp((pat), buf, MIN(len, strlen((pat)))) == 0) return true;
682 static bool LooksLikeHTTPMethod(
const uint8_t *buf, uint16_t
len)
691 static bool LooksLikeHTTPUA(
const uint8_t *buf, uint16_t
len)
693 CHECK(
"User-Agent: ");
694 CHECK(
"\nUser-Agent: ");
700 char pattern_str[1024] =
"";
703 SCJbSetString(js,
"pattern", pattern_str);
712 SCJbSetUint(js,
"offset", cd->
offset);
715 SCJbSetUint(js,
"depth", cd->
depth);
718 SCJbSetInt(js,
"distance", cd->
distance);
721 SCJbSetInt(js,
"within", cd->
within);
740 SCJbOpenArray(js,
"matches");
744 SCJbSetString(js,
"name", mname);
750 SCJbOpenObject(js,
"content");
753 AnalyzerNote(
ctx, (
char *)
"'fast_pattern:only' option is silently ignored and "
754 "is interpreted as regular 'fast_pattern'");
758 (
char *)
"pattern looks like it inspects HTTP, use http.request_line or "
759 "http.method and http.uri instead for improved performance");
763 (
char *)
"pattern looks like it inspects HTTP, use http.user_agent "
764 "or http.header for improved performance");
767 AnalyzerNote(
ctx, (
char *)
"'within' option for pattern w/o previous content "
768 "was converted to 'depth'");
771 AnalyzerNote(
ctx, (
char *)
"'distance' option for pattern w/o previous content "
772 "was converted to 'offset'");
780 SCJbOpenObject(js,
"pcre");
785 (
char *)
"'/B' (rawbytes) option is a no-op and is silently ignored");
788 AnalyzerNote(
ctx, (
char *)
"pcre with \\X (Unicode extended grapheme cluster) "
796 SCJbOpenObject(js,
"byte_jump");
797 SCJbSetUint(js,
"nbytes", cd->
nbytes);
798 SCJbSetInt(js,
"offset", cd->
offset);
799 SCJbSetUint(js,
"multiplier", cd->
multiplier);
803 SCJbSetString(js,
"base",
"unset");
806 SCJbSetString(js,
"base",
"oct");
809 SCJbSetString(js,
"base",
"dec");
812 SCJbSetString(js,
"base",
"hex");
815 SCJbOpenArray(js,
"flags");
817 SCJbAppendString(js,
"from_beginning");
819 SCJbAppendString(js,
"little_endian");
821 SCJbAppendString(js,
"big_endian");
823 SCJbAppendString(js,
"string");
825 SCJbAppendString(js,
"relative");
827 SCJbAppendString(js,
"align");
829 SCJbAppendString(js,
"dce");
831 SCJbAppendString(js,
"offset_be");
833 SCJbAppendString(js,
"from_end");
841 SCJbOpenObject(js,
"byte_test");
842 SCJbSetUint(js,
"nbytes", cd->
nbytes);
843 SCJbSetInt(js,
"offset", cd->
offset);
846 SCJbSetString(js,
"base",
"unset");
849 SCJbSetString(js,
"base",
"oct");
852 SCJbSetString(js,
"base",
"dec");
855 SCJbSetString(js,
"base",
"hex");
858 SCJbOpenArray(js,
"flags");
860 SCJbAppendString(js,
"little_endian");
862 SCJbAppendString(js,
"big_endian");
864 SCJbAppendString(js,
"string");
866 SCJbAppendString(js,
"relative");
868 SCJbAppendString(js,
"dce");
875 SCJbOpenObject(js,
"absent");
876 SCJbSetBool(js,
"or_else", dad->
or_else);
884 SCJbOpenObject(js,
"ipopts");
886 SCJbSetString(js,
"option", flag);
893 SCJbOpenObject(js,
"flowbits");
896 SCJbSetString(js,
"cmd",
"isset");
899 SCJbSetString(js,
"cmd",
"isnotset");
902 SCJbSetString(js,
"cmd",
"set");
905 SCJbSetString(js,
"cmd",
"unset");
909 SCJbOpenArray(js,
"names");
915 const char *varname =
917 SCJbAppendString(js, varname);
922 SCJbSetString(js,
"operator",
"or");
930 SCJbOpenObject(js,
"xbits");
933 SCJbSetString(js,
"cmd",
"isset");
936 SCJbSetString(js,
"cmd",
"isnotset");
939 SCJbSetString(js,
"cmd",
"set");
942 SCJbSetString(js,
"cmd",
"unset");
945 SCJbSetString(js,
"cmd",
"toggle");
951 SCJbSetString(js,
"track",
"ip_src");
954 SCJbSetString(js,
"track",
"ip_dst");
957 SCJbSetString(js,
"track",
"ip_pair");
960 SCJbSetString(js,
"track",
"tx");
964 SCJbSetUint(js,
"expire", xd->
expire);
971 SCJbOpenObject(js,
"flowint");
974 SCJbSetString(js,
"cmd",
"set");
977 SCJbSetString(js,
"cmd",
"add");
980 SCJbSetString(js,
"cmd",
"sub");
983 SCJbSetString(js,
"cmd",
"lt");
986 SCJbSetString(js,
"cmd",
"lte");
989 SCJbSetString(js,
"cmd",
"eq");
992 SCJbSetString(js,
"cmd",
"ne");
995 SCJbSetString(js,
"cmd",
"gte");
998 SCJbSetString(js,
"cmd",
"gt");
1001 SCJbSetString(js,
"cmd",
"isset");
1004 SCJbSetString(js,
"cmd",
"isnotset");
1008 if (varname != NULL) {
1009 SCJbSetString(js,
"var", varname);
1023 SCJbOpenObject(js,
"ack");
1024 SCDetectU32ToJson(js, cd);
1030 SCJbOpenObject(js,
"seq");
1031 SCDetectU32ToJson(js, cd);
1037 SCJbOpenObject(js,
"tcp_mss");
1038 SCDetectU16ToJson(js, cd);
1044 SCJbOpenObject(js,
"dsize");
1045 SCDetectU16ToJson(js, cd);
1051 SCJbOpenObject(js,
"code");
1052 SCDetectU8ToJson(js, cd);
1058 SCJbOpenObject(js,
"ttl");
1059 SCDetectU8ToJson(js, cd);
1065 SCJbOpenObject(js,
"id");
1066 SCDetectU16ToJson(js, cd);
1072 SCJbOpenObject(js,
"window");
1073 SCDetectU16ToJson(js, cd);
1079 SCJbOpenObject(js,
"flow_age");
1080 SCDetectU32ToJson(js, cd);
1085 const uint8_t *dfd = (
const uint8_t *)smd->
ctx;
1086 SCJbOpenObject(js,
"flow_elephant");
1088 case DETECT_FLOW_TOSERVER:
1089 SCJbSetString(js,
"dir",
"toserver");
1091 case DETECT_FLOW_TOCLIENT:
1092 SCJbSetString(js,
"dir",
"toclient");
1094 case DETECT_FLOW_TOEITHER:
1095 SCJbSetString(js,
"dir",
"either");
1097 case DETECT_FLOW_TOBOTH:
1098 SCJbSetString(js,
"dir",
"both");
1106 SCJbOpenObject(js,
"app_layer_protocol");
1109 SCJbOpenArray(js,
"protocols");
1110 for (uint16_t i = 0; i < n; i++) {
1115 SCJbSetBool(js,
"negated", ad->
negated);
1121 SCJbOpenObject(js,
"tcp_session");
1122 SCJbOpenArray(js,
"phases");
1124 SCJbAppendString(js,
"setup");
1126 SCJbAppendString(js,
"established");
1128 SCJbAppendString(js,
"closing");
1150 ctx.js = SCJbNewObject();
1161 SCJbSetUint(
ctx.js,
"id", s->
id);
1162 SCJbSetUint(
ctx.js,
"gid", s->
gid);
1163 SCJbSetUint(
ctx.js,
"rev", s->
rev);
1164 SCJbSetString(
ctx.js,
"msg", s->
msg);
1167 SCJbSetString(
ctx.js,
"app_proto", alproto);
1169 SCJbOpenArray(
ctx.js,
"requirements");
1171 SCJbAppendString(
ctx.js,
"payload");
1174 SCJbAppendString(
ctx.js,
"no_payload");
1177 SCJbAppendString(
ctx.js,
"flow");
1180 SCJbAppendString(
ctx.js,
"tcp_flags_init_deinit");
1183 SCJbAppendString(
ctx.js,
"tcp_flags_unusual");
1186 SCJbAppendString(
ctx.js,
"engine_event");
1189 SCJbAppendString(
ctx.js,
"real_pkt");
1193 SCJbOpenObject(
ctx.js,
"match_policy");
1194 SCJbOpenArray(
ctx.js,
"actions");
1196 SCJbAppendString(
ctx.js,
"alert");
1199 SCJbAppendString(
ctx.js,
"drop");
1202 SCJbAppendString(
ctx.js,
"reject");
1205 SCJbAppendString(
ctx.js,
"reject_dst");
1208 SCJbAppendString(
ctx.js,
"reject_both");
1211 SCJbAppendString(
ctx.js,
"config");
1214 SCJbAppendString(
ctx.js,
"pass");
1217 SCJbAppendString(
ctx.js,
"accept");
1223 switch (flow_action) {
1225 SCJbSetString(
ctx.js,
"scope",
"packet");
1228 SCJbSetString(
ctx.js,
"scope",
"flow");
1231 SCJbSetString(
ctx.js,
"scope",
"flow_if_stateful");
1238 SCJbSetString(
ctx.js,
"scope",
"packet");
1241 SCJbSetString(
ctx.js,
"scope",
"flow");
1244 SCJbSetString(
ctx.js,
"scope",
"hook");
1247 SCJbSetString(
ctx.js,
"scope",
"tx");
1257 SCJbSetString(
ctx.js,
"type",
"unset");
1260 SCJbSetString(
ctx.js,
"type",
"ip_only");
1263 SCJbSetString(
ctx.js,
"type",
"like_ip_only");
1266 SCJbSetString(
ctx.js,
"type",
"pd_only");
1269 SCJbSetString(
ctx.js,
"type",
"de_only");
1272 SCJbSetString(
ctx.js,
"type",
"pkt");
1275 SCJbSetString(
ctx.js,
"type",
"pkt_stream");
1278 SCJbSetString(
ctx.js,
"type",
"stream");
1281 SCJbSetString(
ctx.js,
"type",
"app_layer");
1284 SCJbSetString(
ctx.js,
"type",
"app_tx");
1287 SCJbSetString(
ctx.js,
"type",
"error");
1293 SCJbOpenObject(
ctx.js,
"dependencies");
1294 SCJbOpenObject(
ctx.js,
"flowbits");
1295 SCJbOpenObject(
ctx.js,
"upstream");
1297 SCJbOpenObject(
ctx.js,
"state_modifying_rules");
1298 SCJbOpenArray(
ctx.js,
"sids");
1303 SCJbOpenArray(
ctx.js,
"names");
1306 SCJbAppendString(
ctx.js,
1319 SCJbOpenArray(
ctx.js,
"flags");
1321 SCJbAppendString(
ctx.js,
"src_any");
1324 SCJbAppendString(
ctx.js,
"dst_any");
1327 SCJbAppendString(
ctx.js,
"sp_any");
1330 SCJbAppendString(
ctx.js,
"dp_any");
1333 SCJbAppendString(
ctx.js,
"noalert");
1336 SCJbAppendString(
ctx.js,
"dsize");
1339 SCJbAppendString(
ctx.js,
"applayer");
1342 SCJbAppendString(
ctx.js,
"need_packet");
1345 SCJbAppendString(
ctx.js,
"need_stream");
1348 SCJbAppendString(
ctx.js,
"negated_mpm");
1351 SCJbAppendString(
ctx.js,
"flush");
1354 SCJbAppendString(
ctx.js,
"need_flowvar");
1357 SCJbAppendString(
ctx.js,
"filestore");
1360 SCJbAppendString(
ctx.js,
"toserver");
1363 SCJbAppendString(
ctx.js,
"toclient");
1366 SCJbAppendString(
ctx.js,
"tlsstore");
1369 SCJbAppendString(
ctx.js,
"bypass");
1372 SCJbAppendString(
ctx.js,
"prefilter");
1375 SCJbAppendString(
ctx.js,
"src_is_target");
1378 SCJbAppendString(
ctx.js,
"dst_is_target");
1385 SCJbOpenArray(
ctx.js,
"pkt_engines");
1387 for ( ; pkt != NULL; pkt = pkt->
next) {
1402 SCJbStartObject(
ctx.js);
1403 SCJbSetString(
ctx.js,
"name",
name);
1404 SCJbSetBool(
ctx.js,
"is_mpm", pkt->
mpm);
1406 SCJbOpenArray(
ctx.js,
"transforms");
1408 SCJbStartObject(
ctx.js);
1409 SCJbSetString(
ctx.js,
"name",
1422 SCJbOpenArray(
ctx.js,
"frame_engines");
1424 for (; frame != NULL; frame = frame->
next) {
1426 SCJbStartObject(
ctx.js);
1427 SCJbSetString(
ctx.js,
"name",
name);
1428 SCJbSetBool(
ctx.js,
"is_mpm", frame->
mpm);
1430 SCJbOpenArray(
ctx.js,
"transforms");
1432 SCJbStartObject(
ctx.js);
1433 SCJbSetString(
ctx.js,
"name",
1445 bool has_stream =
false;
1446 bool has_client_body_mpm =
false;
1447 bool has_file_data_mpm =
false;
1449 SCJbOpenArray(
ctx.js,
"engines");
1451 for ( ; app != NULL; app = app->
next) {
1466 }
else if (app->
mpm && strcmp(
name,
"http_client_body") == 0) {
1467 has_client_body_mpm =
true;
1468 }
else if (app->
mpm && strcmp(
name,
"file_data") == 0) {
1469 has_file_data_mpm =
true;
1472 SCJbStartObject(
ctx.js);
1473 SCJbSetString(
ctx.js,
"name",
name);
1474 const char *direction = app->
dir == 0 ?
"toserver" :
"toclient";
1475 SCJbSetString(
ctx.js,
"direction", direction);
1476 SCJbSetBool(
ctx.js,
"is_mpm", app->
mpm);
1480 SCJbSetString(
ctx.js,
"sub_state",
1484 SCJbOpenArray(
ctx.js,
"transforms");
1486 SCJbStartObject(
ctx.js);
1487 SCJbSetString(
ctx.js,
"name",
1501 if (has_stream && has_client_body_mpm)
1502 AnalyzerNote(&
ctx, (
char *)
"mpm in http_client_body combined with stream match leads to stream buffering");
1503 if (has_stream && has_file_data_mpm)
1504 AnalyzerNote(&
ctx, (
char *)
"mpm in file_data combined with stream match leads to stream buffering");
1507 SCJbOpenObject(
ctx.js,
"lists");
1517 if (pkt_mpm || app_mpm) {
1518 SCJbOpenObject(
ctx.js,
"mpm");
1526 SCJbSetString(
ctx.js,
"buffer",
name);
1534 switch (smd->
type) {
1538 DumpContent(
ctx.js, cd);
1550 SCJbOpenObject(
ctx.js,
"prefilter");
1557 SCJbSetString(
ctx.js,
"buffer",
name);
1559 SCJbSetString(
ctx.js,
"name", mname);
1563 if (
ctx.js_warnings) {
1564 SCJbClose(
ctx.js_warnings);
1565 SCJbSetObject(
ctx.js,
"warnings",
ctx.js_warnings);
1566 SCJbFree(
ctx.js_warnings);
1567 ctx.js_warnings = NULL;
1570 SCJbClose(
ctx.js_notes);
1571 SCJbSetObject(
ctx.js,
"notes",
ctx.js_notes);
1572 SCJbFree(
ctx.js_notes);
1573 ctx.js_notes = NULL;
1577 const char *filename =
"rules.json";
1579 char json_path[PATH_MAX] =
"";
1580 snprintf(json_path,
sizeof(json_path),
"%s/%s%s", log_dir,
1584 FILE *fp = fopen(json_path,
"a");
1586 fwrite(SCJbPtr(
ctx.js), SCJbLen(
ctx.js), 1, fp);
1600 SCJsonBuilder *root_jb = SCJbNewObject();
1601 if (root_jb == NULL) {
1605 if (arrays == NULL) {
1610 SCJbOpenArray(root_jb,
"buffers");
1614 char str[1024] =
"";
1618 SCJsonBuilder *jb = arrays[
p->sm_list];
1619 if (arrays[
p->sm_list] == NULL) {
1620 jb = arrays[
p->sm_list] = SCJbNewObject();
1626 SCJbSetString(jb,
"name",
name);
1627 SCJbSetUint(jb,
"list_id",
p->sm_list);
1629 SCJbOpenArray(jb,
"patterns");
1632 SCJbStartObject(jb);
1633 SCJbSetString(jb,
"pattern",
str);
1634 SCJbSetUint(jb,
"patlen",
p->cd->content_len);
1635 SCJbSetUint(jb,
"cnt",
p->cnt);
1636 SCJbSetUint(jb,
"mpm",
p->mpm);
1637 SCJbOpenObject(jb,
"flags");
1648 SCJsonBuilder *jb = arrays[i];
1655 SCJbAppendObject(root_jb, jb);
1661 const char *filename =
"patterns.json";
1663 char json_path[PATH_MAX] =
"";
1664 snprintf(json_path,
sizeof(json_path),
"%s/%s%s", log_dir,
1668 FILE *fp = fopen(json_path,
"a");
1670 fwrite(SCJbPtr(root_jb), SCJbLen(root_jb), 1, fp);
1692 EngineAnalysisItemsReset(ea_ctx);
1700 FatalError(
"Unable to allocate analysis scratch pad");
1710 analyzer_item->
item_id = (uint16_t)item_id;
1711 if (analyzer_item->
item_id == -1) {
1713 FatalError(
"unable to initialize engine-analysis table: detect buffer \"%s\" not "
1746 uint32_t rule_bidirectional = 0;
1747 uint32_t rule_pcre = 0;
1748 uint32_t rule_pcre_http = 0;
1749 uint32_t rule_content = 0;
1750 uint32_t rule_flow = 0;
1751 uint32_t rule_flags = 0;
1752 uint32_t rule_flow_toserver = 0;
1753 uint32_t rule_flow_toclient = 0;
1754 uint32_t rule_flow_nostream = 0;
1755 uint32_t rule_ipv4_only = 0;
1756 uint32_t rule_ipv6_only = 0;
1757 uint32_t rule_flowbits = 0;
1758 uint32_t rule_flowint = 0;
1759 uint32_t rule_content_http = 0;
1760 uint32_t rule_content_offset_depth = 0;
1761 int32_t list_id = 0;
1762 uint32_t rule_warning = 0;
1763 uint32_t stream_buf = 0;
1764 uint32_t packet_buf = 0;
1765 uint32_t file_store = 0;
1766 uint32_t warn_pcre_no_content = 0;
1767 uint32_t warn_pcre_http_content = 0;
1768 uint32_t warn_pcre_http = 0;
1769 uint32_t warn_content_http_content = 0;
1770 uint32_t warn_content_http = 0;
1771 uint32_t warn_tcp_no_flow = 0;
1772 uint32_t warn_client_ports = 0;
1773 uint32_t warn_direction = 0;
1774 uint32_t warn_method_toclient = 0;
1775 uint32_t warn_method_serverbody = 0;
1776 uint32_t warn_pcre_method = 0;
1777 uint32_t warn_encoding_norm_http_buf = 0;
1778 uint32_t warn_file_store_not_present = 0;
1779 uint32_t warn_offset_depth_pkt_stream = 0;
1780 uint32_t warn_offset_depth_alproto = 0;
1781 uint32_t warn_non_alproto_fp_for_alproto_sig = 0;
1782 uint32_t warn_no_direction = 0;
1783 uint32_t warn_both_direction = 0;
1785 EngineAnalysisItemsInit(
de_ctx->
ea);
1791 rule_bidirectional = 1;
1805 rule_ipv4_only += 1;
1808 rule_ipv6_only += 1;
1816 if (item_slot == -1) {
1824 if (item_slot == -1) {
1829 rule_content_offset_depth++;
1835 rule_content_http++;
1842 warn_encoding_norm_http_buf += 1;
1849 rule_flow_toserver = 1;
1852 rule_flow_toclient = 1;
1857 rule_flow_nostream = 1;
1871 if (sm->
ctx != NULL) {
1881 warn_file_store_not_present = 1;
1884 if (rule_pcre > 0 && rule_content == 0 && rule_content_http == 0) {
1886 warn_pcre_no_content = 1;
1889 if (rule_content_http > 0 && rule_pcre > 0 && rule_pcre_http == 0) {
1891 warn_pcre_http_content = 1;
1897 if (rule_content > 0 && rule_content_http > 0) {
1899 warn_content_http_content = 1;
1903 warn_content_http = 1;
1905 if (rule_content == 1) {
1910 (rule_content || rule_content_http || rule_pcre || rule_pcre_http || rule_flowbits ||
1913 warn_tcp_no_flow = 1;
1915 if (rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)
1920 warn_client_ports = 1;
1923 if (rule_flow && rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)) {
1928 if (*http_method_item_seen_ptr) {
1929 if (rule_flow && rule_flow_toclient) {
1931 warn_method_toclient = 1;
1933 if (*http_server_body_item_seen_ptr) {
1935 warn_method_serverbody = 1;
1937 if (rule_content == 0 && rule_content_http == 0 && (rule_pcre > 0 || rule_pcre_http > 0)) {
1939 warn_pcre_method = 1;
1942 if (rule_content_offset_depth > 0 && stream_buf && packet_buf) {
1944 warn_offset_depth_pkt_stream = 1;
1948 warn_offset_depth_alproto = 1;
1953 warn_non_alproto_fp_for_alproto_sig = 1;
1957 warn_no_direction += 1;
1965 warn_both_direction += 1;
1970 if (!rule_warnings_only || (rule_warnings_only && rule_warning > 0)) {
1972 fprintf(fp,
"== Sid: %u ==\n", s->
id);
1973 fprintf(fp,
"%s\n", line);
1979 fprintf(fp,
" Rule is ip only.\n");
1982 fprintf(fp,
" Rule is like ip only.\n");
1985 fprintf(fp,
" Rule is PD only.\n");
1988 fprintf(fp,
" Rule is DE only.\n");
1991 fprintf(fp,
" Rule is packet inspecting.\n");
1994 fprintf(fp,
" Rule is packet and stream inspecting.\n");
1997 fprintf(fp,
" Rule is stream inspecting.\n");
2000 fprintf(fp,
" Rule is app-layer inspecting.\n");
2003 fprintf(fp,
" Rule is App-layer TX inspecting.\n");
2009 fprintf(fp,
" Rule is IPv6 only.\n");
2011 fprintf(fp,
" Rule is IPv4 only.\n");
2013 fprintf(fp,
" Rule matches on packets.\n");
2014 if (!rule_flow_nostream && stream_buf &&
2015 (rule_flow || rule_flowbits || rule_flowint || rule_content || rule_pcre)) {
2016 fprintf(fp,
" Rule matches on reassembled stream.\n");
2021 fprintf(fp,
" Rule matches on %s buffer.\n", ai->
display_name);
2027 if (rule_content || rule_content_http || rule_pcre || rule_pcre_http) {
2029 " Rule contains %u content options, %u http content options, %u pcre "
2030 "options, and %u pcre options with http modifiers.\n",
2031 rule_content, rule_content_http, rule_pcre, rule_pcre_http);
2036 fprintf(fp,
" Prefilter on: %s.\n",
2039 EngineAnalysisRulesPrintFP(
de_ctx, s);
2043 if (warn_pcre_no_content ) {
2044 fprintf(fp,
" Warning: Rule uses pcre without a content option present.\n"
2045 " -Consider adding a content to improve performance of this "
2048 if (warn_pcre_http_content ) {
2049 fprintf(fp,
" Warning: Rule uses content options with http_* and pcre options "
2050 "without http modifiers.\n"
2051 " -Consider adding http pcre modifier.\n");
2053 else if (warn_pcre_http ) {
2054 fprintf(fp,
" Warning: Rule app layer protocol is http, but pcre options do not "
2055 "have http modifiers.\n"
2056 " -Consider adding http pcre modifiers.\n");
2058 if (warn_content_http_content ) {
2060 " Warning: Rule contains content with http_* and content without http_*.\n"
2061 " -Consider adding http content modifiers.\n");
2063 if (warn_content_http ) {
2064 fprintf(fp,
" Warning: Rule app layer protocol is http, but content options do not "
2065 "have http_* modifiers.\n"
2066 " -Consider adding http content modifiers.\n");
2068 if (rule_content == 1) {
2071 if (warn_encoding_norm_http_buf) {
2072 fprintf(fp,
" Warning: Rule may contain percent encoded content for a normalized "
2073 "http buffer match.\n");
2075 if (warn_tcp_no_flow
2077 fprintf(fp,
" Warning: TCP rule without a flow or flags option.\n"
2078 " -Consider adding flow or flags to improve performance of "
2081 if (warn_client_ports
2086 " Warning: Rule contains ports or port variables only on the client side.\n"
2087 " -Flow direction possibly inconsistent with rule.\n");
2089 if (warn_direction ) {
2090 fprintf(fp,
" Warning: Rule is bidirectional and has a flow option with a specific "
2093 if (warn_method_toclient ) {
2094 fprintf(fp,
" Warning: Rule uses content or pcre for http_method with "
2095 "flow:to_client or from_server\n");
2097 if (warn_method_serverbody ) {
2098 fprintf(fp,
" Warning: Rule uses content or pcre for http_method with content or "
2099 "pcre for http_server_body.\n");
2101 if (warn_pcre_method
2103 fprintf(fp,
" Warning: Rule uses pcre with only a http_method content; possible "
2104 "performance issue.\n");
2106 if (warn_offset_depth_pkt_stream) {
2107 fprintf(fp,
" Warning: Rule has depth"
2108 "/offset with raw content keywords. Please note the "
2109 "offset/depth will be checked against both packet "
2110 "payloads and stream. If you meant to have the offset/"
2111 "depth checked against just the payload, you can update "
2112 "the signature as \"alert tcp-pkt...\"\n");
2114 if (warn_offset_depth_alproto) {
2116 " Warning: Rule has "
2117 "offset/depth set along with a match on a specific "
2118 "app layer protocol - %d. This can lead to FNs if we "
2119 "have a offset/depth content match on a packet payload "
2120 "before we can detect the app layer protocol for the "
2124 if (warn_non_alproto_fp_for_alproto_sig) {
2125 fprintf(fp,
" Warning: Rule app layer "
2126 "protocol is http, but the fast_pattern is set on the raw "
2127 "stream. Consider adding fast_pattern over a http "
2128 "buffer for increased performance.");
2130 if (warn_no_direction) {
2131 fprintf(fp,
" Warning: Rule has no direction indicator.\n");
2133 if (warn_both_direction) {
2134 fprintf(fp,
" Warning: Rule is inspecting both the request and the response.\n");
2136 if (warn_file_store_not_present) {
2137 fprintf(fp,
" Warning: Rule requires file-store but the output file-store is not "
2140 if (rule_warning == 0) {
2141 fprintf(fp,
" No warnings for this rule.\n");
2150 const uint8_t sub_state,
const uint8_t state,
const uint8_t direction)
2152 char policy_string[64] =
"";
2169 snprintf(policy_string,
sizeof(policy_string),
"rejectdst:%s", as);
2171 snprintf(policy_string,
sizeof(policy_string),
"rejectboth:%s", as);
2173 snprintf(policy_string,
sizeof(policy_string),
"rejectsrc:%s", as);
2176 snprintf(policy_string,
sizeof(policy_string),
"drop:%s", as);
2178 snprintf(policy_string,
sizeof(policy_string),
"accept:%s", as);
2184 strlcat(policy_string,
",pass:flow",
sizeof(policy_string));
2189 SCJbSetString(
ctx->js,
"policy", policy_string);
2193 const uint8_t sub_state,
const uint8_t state,
const uint8_t direction,
RuleAnalyzer *
ctx)
2195 uint32_t accept_rules = 0;
2196 AddPolicy(
de_ctx,
ctx, a, sub_state, state, direction);
2197 SCJbOpenArray(
ctx->js,
"rules");
2206 if (direction == STREAM_TOSERVER) {
2221 bool skip_rule =
false;
2223 engine = engine->
next) {
2226 }
else if (engine->sub_state != sub_state) {
2247 if (accept_rules == 0) {
2248 AnalyzerWarning(
ctx, (
char *)
"no accept rules for state, default policy will be applied");
2255 ctx.js = SCJbNewObject();
2259 SCJbOpenObject(
ctx.js,
"tables");
2260 SCJbOpenObject(
ctx.js,
"packet:filter");
2261 SCJbSetString(
ctx.js,
"policy",
"drop:packet");
2262 SCJbOpenArray(
ctx.js,
"rules");
2263 uint32_t accept_rules = 0;
2264 uint32_t last_sid = 0;
2271 if (last_sid == s->
id)
2278 if (accept_rules == 0) {
2279 AnalyzerWarning(&
ctx,
2280 (
char *)
"no accept rules for \'packet:filter\', default policy will be applied");
2282 if (
ctx.js_warnings) {
2283 SCJbClose(
ctx.js_warnings);
2284 SCJbSetObject(
ctx.js,
"warnings",
ctx.js_warnings);
2285 SCJbFree(
ctx.js_warnings);
2286 ctx.js_warnings = NULL;
2291 if (!AppProtoIsValid(a))
2297 for (uint8_t sub_state = 1; sub_state <= max_sub_state; sub_state++) {
2300 for (uint8_t state = 0; state <= max_progress; state++) {
2302 a, sub_state, state, STREAM_TOSERVER);
2306 char table_name[256];
2307 snprintf(table_name,
sizeof(table_name),
"app:%s:%s:%s",
AppProtoToString(a),
2308 sub_state_name,
name);
2309 SCJbOpenObject(
ctx.js, table_name);
2310 FirewallAddRulesForState(
de_ctx, a, sub_state, state, STREAM_TOSERVER, &
ctx);
2311 if (
ctx.js_warnings) {
2312 SCJbClose(
ctx.js_warnings);
2313 SCJbSetObject(
ctx.js,
"warnings",
ctx.js_warnings);
2314 SCJbFree(
ctx.js_warnings);
2315 ctx.js_warnings = NULL;
2319 for (uint8_t state = 0; state <= max_progress; state++) {
2321 a, sub_state, state, STREAM_TOCLIENT);
2325 char table_name[256];
2326 snprintf(table_name,
sizeof(table_name),
"app:%s:%s:%s",
AppProtoToString(a),
2327 sub_state_name,
name);
2328 SCJbOpenObject(
ctx.js, table_name);
2329 FirewallAddRulesForState(
de_ctx, a, sub_state, state, STREAM_TOCLIENT, &
ctx);
2330 if (
ctx.js_warnings) {
2331 SCJbClose(
ctx.js_warnings);
2332 SCJbSetObject(
ctx.js,
"warnings",
ctx.js_warnings);
2333 SCJbFree(
ctx.js_warnings);
2334 ctx.js_warnings = NULL;
2345 const uint8_t complete_state_ts =
2348 for (uint8_t state = 0; state <= complete_state_ts; state++) {
2357 char table_name[128];
2359 SCJbOpenObject(
ctx.js, table_name);
2360 FirewallAddRulesForState(
de_ctx, a, 0, state, STREAM_TOSERVER, &
ctx);
2361 if (
ctx.js_warnings) {
2362 SCJbClose(
ctx.js_warnings);
2363 SCJbSetObject(
ctx.js,
"warnings",
ctx.js_warnings);
2364 SCJbFree(
ctx.js_warnings);
2365 ctx.js_warnings = NULL;
2369 const uint8_t complete_state_tc =
2371 for (uint8_t state = 0; state <= complete_state_tc; state++) {
2379 char table_name[128];
2381 SCJbOpenObject(
ctx.js, table_name);
2382 FirewallAddRulesForState(
de_ctx, a, 0, state, STREAM_TOCLIENT, &
ctx);
2383 if (
ctx.js_warnings) {
2384 SCJbClose(
ctx.js_warnings);
2385 SCJbSetObject(
ctx.js,
"warnings",
ctx.js_warnings);
2386 SCJbFree(
ctx.js_warnings);
2387 ctx.js_warnings = NULL;
2393 SCJbOpenObject(
ctx.js,
"packet:td");
2394 SCJbSetString(
ctx.js,
"policy",
"accept:hook");
2396 SCJbOpenArray(
ctx.js,
"rules");
2402 if (last_sid == s->
id)
2409 SCJbOpenObject(
ctx.js,
"app:td");
2410 SCJbSetString(
ctx.js,
"policy",
"accept:hook");
2412 SCJbOpenArray(
ctx.js,
"rules");
2418 if (last_sid == s->
id)
2427 SCJbOpenObject(
ctx.js,
"lists");
2428 SCJbOpenObject(
ctx.js,
"firewall");
2430 SCJbOpenArray(
ctx.js,
"rules");
2434 if (last_sid == s->
id)
2442 SCJbOpenObject(
ctx.js,
"td");
2444 SCJbOpenArray(
ctx.js,
"rules");
2448 if (last_sid == s->
id)
2456 SCJbOpenObject(
ctx.js,
"all");
2458 SCJbOpenArray(
ctx.js,
"rules");
2460 if (last_sid == s->
id)
2471 SCJbOpenObject(
ctx.js,
"keyword_info");
2481 snprintf(sid_key,
sizeof(sid_key),
"%u", s->
id);
2482 SCJbOpenObject(
ctx.js, sid_key);
2483 SCJbOpenArray(
ctx.js,
"tcp_session");
2485 SCJbAppendString(
ctx.js,
"setup");
2487 SCJbAppendString(
ctx.js,
"established");
2489 SCJbAppendString(
ctx.js,
"closing");
2504 const char *filename =
"firewall.json";
2506 char json_path[PATH_MAX] =
"";
2507 snprintf(json_path,
sizeof(json_path),
"%s/%s", log_dir, filename);
2510 FILE *fp = fopen(json_path,
"w");
2512 fwrite(SCJbPtr(
ctx.js), SCJbLen(
ctx.js), 1, fp);