58 static int rule_warnings_only = 0;
114 { 0,
false,
false,
true,
"http_uri",
"http uri" },
115 { 0,
false,
false,
false,
"http_raw_uri",
"http raw uri" },
116 { 0,
false,
true,
false,
"http_method",
"http method" },
117 { 0,
false,
false,
false,
"http_request_line",
"http request line" },
118 { 0,
false,
false,
false,
"http_client_body",
"http client body" },
119 { 0,
false,
false,
true,
"http_header",
"http header" },
120 { 0,
false,
false,
false,
"http_raw_header",
"http raw header" },
121 { 0,
false,
false,
true,
"http_cookie",
"http cookie" },
122 { 0,
false,
false,
false,
"http_user_agent",
"http user agent" },
123 { 0,
false,
false,
false,
"http_host",
"http host" },
124 { 0,
false,
false,
false,
"http_raw_host",
"http raw host" },
125 { 0,
false,
false,
false,
"http_accept_enc",
"http accept enc" },
126 { 0,
false,
false,
false,
"http_referer",
"http referer" },
127 { 0,
false,
false,
false,
"http_content_type",
"http content type" },
128 { 0,
false,
false,
false,
"http_header_names",
"http header names" },
131 { 0,
false,
false,
false,
"http_stat_msg",
"http stat msg" },
132 { 0,
false,
false,
false,
"http_stat_code",
"http stat code" },
133 { 0,
false,
true,
false,
"file_data",
"http server body" },
136 { 0,
false,
false,
false,
"http_request_line",
"http request line" },
137 { 0,
false,
false,
false,
"http_accept",
"http accept" },
138 { 0,
false,
false,
false,
"http_accept_lang",
"http accept lang" },
139 { 0,
false,
false,
false,
"http_connection",
"http connection" },
140 { 0,
false,
false,
false,
"http_content_len",
"http content len" },
141 { 0,
false,
false,
false,
"http_protocol",
"http protocol" },
142 { 0,
false,
false,
false,
"http_start",
"http start" },
145 { 0,
false,
false,
false,
"http_response_line",
"http response line" },
146 { 0,
false,
false,
false,
"http.server",
"http server" },
147 { 0,
false,
false,
false,
"http.location",
"http location" },
150 static void FpPatternStatsAdd(
FpPatternStats *fp,
int list, uint16_t patlen)
159 else if (patlen < f->min)
171 int fast_pattern_set = 0;
172 int fast_pattern_only_set = 0;
173 int fast_pattern_chop_set = 0;
178 if (mpm_sm != NULL) {
181 fast_pattern_set = 1;
183 fast_pattern_only_set = 1;
185 fast_pattern_chop_set = 1;
191 fprintf(fp,
"== Sid: %u ==\n", s->
id);
192 fprintf(fp,
"%s\n", line);
194 fprintf(fp,
" Fast Pattern analysis:\n");
196 fprintf(fp,
" Prefilter on: %s\n",
203 fprintf(fp,
" No content present\n");
208 fprintf(fp,
" Fast pattern matcher: ");
209 int list_type = mpm_sm_list;
211 fprintf(fp,
"content\n");
216 fprintf(fp,
"%s (%s)\n", desc,
name);
221 fprintf(fp,
" Flags:");
223 fprintf(fp,
" Offset");
226 fprintf(fp,
" Depth");
230 fprintf(fp,
" Within");
234 fprintf(fp,
" Distance");
238 fprintf(fp,
" Nocase");
242 fprintf(fp,
" Negated");
246 fprintf(fp,
" None");
249 fprintf(fp,
" Fast pattern set: %s\n", fast_pattern_set ?
"yes" :
"no");
250 fprintf(fp,
" Fast pattern only set: %s\n", fast_pattern_only_set ?
"yes" :
"no");
251 fprintf(fp,
" Fast pattern chop set: %s\n", fast_pattern_chop_set ?
"yes" :
"no");
252 if (fast_pattern_chop_set) {
253 fprintf(fp,
" Fast pattern offset, length: %u, %u\n", fp_cd->
fp_chop_offset,
264 fprintf(fp,
" Original content: ");
268 if (fast_pattern_chop_set) {
277 fprintf(fp,
" Final content: ");
283 fprintf(fp,
" Final content: ");
302 int fp_engine_analysis_set = 0;
304 if ((
SCConfGetBool(
"engine-analysis.rules-fast-pattern", &fp_engine_analysis_set)) == 0) {
308 if (fp_engine_analysis_set == 0)
312 char *log_path =
SCMalloc(PATH_MAX);
313 if (log_path == NULL) {
314 FatalError(
"Unable to allocate scratch memory for rule filename");
316 snprintf(log_path, PATH_MAX,
"%s/%s%s", log_dir,
319 FILE *fp = fopen(log_path,
"w");
321 SCLogError(
"failed to open %s: %s", log_path, strerror(errno));
328 SCLogInfo(
"Engine-Analysis for fast_pattern printed to file - %s",
333 gettimeofday(&tval, NULL);
335 struct tm *tms =
SCLocalTime(tval.tv_sec, &local_tm);
336 fprintf(fp,
"----------------------------------------------"
337 "---------------------\n");
339 "Date: %" PRId32
"/%" PRId32
"/%04d -- "
341 tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min,
343 fprintf(fp,
"----------------------------------------------"
344 "---------------------\n");
357 #define DETECT_PERCENT_ENCODING_REGEX "%[0-9|a-f|A-F]{2}"
363 PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
365 PCRE2_UCHAR errbuffer[256];
366 pcre2_get_error_message(en, errbuffer,
sizeof(errbuffer));
387 }
else if (value && strcasecmp(value,
"warnings-only") == 0) {
389 rule_warnings_only = 1;
394 char log_path[PATH_MAX];
395 snprintf(log_path,
sizeof(log_path),
"%s/%s%s", log_dir,
399 SCLogError(
"failed to open %s: %s", log_path, strerror(errno));
403 SCLogInfo(
"Engine-Analysis for rules printed to file - %s",
407 gettimeofday(&tval, NULL);
409 struct tm *tms =
SCLocalTime(tval.tv_sec, &local_tm);
411 "----------------------------------------------"
412 "---------------------\n");
414 "Date: %" PRId32
"/%" PRId32
"/%04d -- "
416 tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min,
419 "----------------------------------------------"
420 "---------------------\n");
423 if (!PerCentEncodingSetup(
de_ctx->
ea)) {
425 "Error compiling regex; can't check for percent encoding in normalized "
431 SCLogInfo(
"Conf parameter \"engine-analysis.rules\" not found. "
432 "Defaulting to not printing the rules analysis report.");
435 SCLogInfo(
"Engine-Analysis for rules disabled in conf file.");
444 fprintf(fp,
"============\n"
445 "Summary:\n============\n");
453 "%s, smallest pattern %u byte(s), longest pattern %u byte(s), number of patterns "
454 "%u, avg pattern len %.2f byte(s)\n",
456 (
float)((
double)f->
tot / (
float)f->
cnt));
476 *fp_analysis =
false;
477 *rule_analysis =
false;
481 FatalError(
"Unable to allocate per-engine analysis context");
486 if (cfg_prefix_len > 0) {
490 FatalError(
"Unable to allocate per-engine analysis context name buffer");
498 *fp_analysis = SetupFPAnalyzer(
de_ctx);
499 *rule_analysis = SetupRuleAnalyzer(
de_ctx);
501 if (!(*fp_analysis || *rule_analysis)) {
513 CleanupRuleAnalyzer(
de_ctx);
514 CleanupFPAnalyzer(
de_ctx);
531 static int PerCentEncodingMatch(
EngineAnalysisCtx *ea_ctx, uint8_t *content, uint16_t content_len)
535 pcre2_match_data *match = pcre2_match_data_create_from_pattern(ea_ctx->
percent_re, NULL);
536 ret = pcre2_match(ea_ctx->
percent_re, (PCRE2_SPTR8)content, content_len, 0, 0, match, NULL);
539 }
else if (ret < -1) {
540 SCLogError(
"Error parsing content - %s; error code is %d", content, ret);
543 pcre2_match_data_free(match);
553 if (mpm_sm != NULL) {
591 const int list_type = mpm_sm_list;
600 payload ? (stream ?
"payload and reassembled stream" :
"payload")
601 :
"reassembled stream");
608 }
else if (desc ||
name) {
646 vsnprintf(
str,
sizeof(
str), fmt, ap);
650 ctx->js_notes = SCJbNewArray();
652 SCJbAppendString(
ctx->js_notes,
str);
661 vsnprintf(
str,
sizeof(
str), fmt, ap);
664 if (!
ctx->js_warnings)
665 ctx->js_warnings = SCJbNewArray();
666 if (
ctx->js_warnings)
667 SCJbAppendString(
ctx->js_warnings,
str);
670 #define CHECK(pat) if (strlen((pat)) <= len && memcmp((pat), buf, MIN(len, strlen((pat)))) == 0) return true;
672 static bool LooksLikeHTTPMethod(
const uint8_t *buf, uint16_t
len)
681 static bool LooksLikeHTTPUA(
const uint8_t *buf, uint16_t
len)
683 CHECK(
"User-Agent: ");
684 CHECK(
"\nUser-Agent: ");
690 char pattern_str[1024] =
"";
693 SCJbSetString(js,
"pattern", pattern_str);
702 SCJbSetUint(js,
"offset", cd->
offset);
705 SCJbSetUint(js,
"depth", cd->
depth);
708 SCJbSetInt(js,
"distance", cd->
distance);
711 SCJbSetInt(js,
"within", cd->
within);
730 SCJbOpenArray(js,
"matches");
734 SCJbSetString(js,
"name", mname);
740 SCJbOpenObject(js,
"content");
743 AnalyzerNote(
ctx, (
char *)
"'fast_pattern:only' option is silently ignored and "
744 "is interpreted as regular 'fast_pattern'");
748 (
char *)
"pattern looks like it inspects HTTP, use http.request_line or "
749 "http.method and http.uri instead for improved performance");
753 (
char *)
"pattern looks like it inspects HTTP, use http.user_agent "
754 "or http.header for improved performance");
757 AnalyzerNote(
ctx, (
char *)
"'within' option for pattern w/o previous content "
758 "was converted to 'depth'");
761 AnalyzerNote(
ctx, (
char *)
"'distance' option for pattern w/o previous content "
762 "was converted to 'offset'");
770 SCJbOpenObject(js,
"pcre");
775 (
char *)
"'/B' (rawbytes) option is a no-op and is silently ignored");
782 SCJbOpenObject(js,
"byte_jump");
783 SCJbSetUint(js,
"nbytes", cd->
nbytes);
784 SCJbSetInt(js,
"offset", cd->
offset);
785 SCJbSetUint(js,
"multiplier", cd->
multiplier);
789 SCJbSetString(js,
"base",
"unset");
792 SCJbSetString(js,
"base",
"oct");
795 SCJbSetString(js,
"base",
"dec");
798 SCJbSetString(js,
"base",
"hex");
801 SCJbOpenArray(js,
"flags");
803 SCJbAppendString(js,
"from_beginning");
805 SCJbAppendString(js,
"little_endian");
807 SCJbAppendString(js,
"big_endian");
809 SCJbAppendString(js,
"string");
811 SCJbAppendString(js,
"relative");
813 SCJbAppendString(js,
"align");
815 SCJbAppendString(js,
"dce");
817 SCJbAppendString(js,
"offset_be");
819 SCJbAppendString(js,
"from_end");
827 SCJbOpenObject(js,
"byte_test");
828 SCJbSetUint(js,
"nbytes", cd->
nbytes);
829 SCJbSetInt(js,
"offset", cd->
offset);
832 SCJbSetString(js,
"base",
"unset");
835 SCJbSetString(js,
"base",
"oct");
838 SCJbSetString(js,
"base",
"dec");
841 SCJbSetString(js,
"base",
"hex");
844 SCJbOpenArray(js,
"flags");
846 SCJbAppendString(js,
"little_endian");
848 SCJbAppendString(js,
"big_endian");
850 SCJbAppendString(js,
"string");
852 SCJbAppendString(js,
"relative");
854 SCJbAppendString(js,
"dce");
861 SCJbOpenObject(js,
"absent");
862 SCJbSetBool(js,
"or_else", dad->
or_else);
870 SCJbOpenObject(js,
"ipopts");
872 SCJbSetString(js,
"option", flag);
879 SCJbOpenObject(js,
"flowbits");
882 SCJbSetString(js,
"cmd",
"isset");
885 SCJbSetString(js,
"cmd",
"isnotset");
888 SCJbSetString(js,
"cmd",
"set");
891 SCJbSetString(js,
"cmd",
"unset");
894 SCJbSetString(js,
"cmd",
"toggle");
898 SCJbOpenArray(js,
"names");
904 const char *varname =
906 SCJbAppendString(js, varname);
911 SCJbSetString(js,
"operator",
"or");
919 SCJbOpenObject(js,
"ack");
920 SCJbSetUint(js,
"number", cd->
ack);
926 SCJbOpenObject(js,
"seq");
927 SCJbSetUint(js,
"number", cd->
seq);
933 SCJbOpenObject(js,
"tcp_mss");
934 SCDetectU16ToJson(js, cd);
940 SCJbOpenObject(js,
"dsize");
941 SCDetectU16ToJson(js, cd);
947 SCJbOpenObject(js,
"code");
948 SCDetectU8ToJson(js, cd);
954 SCJbOpenObject(js,
"id");
955 SCJbSetUint(js,
"number",
SCNtohs(cd->
id));
961 SCJbOpenObject(js,
"window");
962 SCJbSetUint(js,
"size", wd->
size);
963 SCJbSetBool(js,
"negated", wd->
negated);
969 SCJbOpenObject(js,
"flow_age");
970 SCDetectU32ToJson(js, cd);
991 ctx.js = SCJbNewObject();
1002 SCJbSetUint(
ctx.js,
"id", s->
id);
1003 SCJbSetUint(
ctx.js,
"gid", s->
gid);
1004 SCJbSetUint(
ctx.js,
"rev", s->
rev);
1005 SCJbSetString(
ctx.js,
"msg", s->
msg);
1008 SCJbSetString(
ctx.js,
"app_proto", alproto);
1010 SCJbOpenArray(
ctx.js,
"requirements");
1012 SCJbAppendString(
ctx.js,
"payload");
1015 SCJbAppendString(
ctx.js,
"no_payload");
1018 SCJbAppendString(
ctx.js,
"flow");
1021 SCJbAppendString(
ctx.js,
"tcp_flags_init_deinit");
1024 SCJbAppendString(
ctx.js,
"tcp_flags_unusual");
1027 SCJbAppendString(
ctx.js,
"engine_event");
1030 SCJbAppendString(
ctx.js,
"real_pkt");
1034 SCJbOpenObject(
ctx.js,
"match_policy");
1035 SCJbOpenArray(
ctx.js,
"actions");
1037 SCJbAppendString(
ctx.js,
"alert");
1040 SCJbAppendString(
ctx.js,
"drop");
1043 SCJbAppendString(
ctx.js,
"reject");
1046 SCJbAppendString(
ctx.js,
"reject_dst");
1049 SCJbAppendString(
ctx.js,
"reject_both");
1052 SCJbAppendString(
ctx.js,
"config");
1055 SCJbAppendString(
ctx.js,
"pass");
1058 SCJbAppendString(
ctx.js,
"accept");
1064 switch (flow_action) {
1066 SCJbSetString(
ctx.js,
"scope",
"packet");
1069 SCJbSetString(
ctx.js,
"scope",
"flow");
1072 SCJbSetString(
ctx.js,
"scope",
"flow_if_stateful");
1079 SCJbSetString(
ctx.js,
"scope",
"packet");
1082 SCJbSetString(
ctx.js,
"scope",
"flow");
1085 SCJbSetString(
ctx.js,
"scope",
"hook");
1088 SCJbSetString(
ctx.js,
"scope",
"tx");
1098 SCJbSetString(
ctx.js,
"type",
"unset");
1101 SCJbSetString(
ctx.js,
"type",
"ip_only");
1104 SCJbSetString(
ctx.js,
"type",
"like_ip_only");
1107 SCJbSetString(
ctx.js,
"type",
"pd_only");
1110 SCJbSetString(
ctx.js,
"type",
"de_only");
1113 SCJbSetString(
ctx.js,
"type",
"pkt");
1116 SCJbSetString(
ctx.js,
"type",
"pkt_stream");
1119 SCJbSetString(
ctx.js,
"type",
"stream");
1122 SCJbSetString(
ctx.js,
"type",
"app_layer");
1125 SCJbSetString(
ctx.js,
"type",
"app_tx");
1128 SCJbSetString(
ctx.js,
"type",
"error");
1134 SCJbOpenObject(
ctx.js,
"dependencies");
1135 SCJbOpenObject(
ctx.js,
"flowbits");
1136 SCJbOpenObject(
ctx.js,
"upstream");
1138 SCJbOpenObject(
ctx.js,
"state_modifying_rules");
1139 SCJbOpenArray(
ctx.js,
"sids");
1144 SCJbOpenArray(
ctx.js,
"names");
1147 SCJbAppendString(
ctx.js,
1160 SCJbOpenArray(
ctx.js,
"flags");
1162 SCJbAppendString(
ctx.js,
"src_any");
1165 SCJbAppendString(
ctx.js,
"dst_any");
1168 SCJbAppendString(
ctx.js,
"sp_any");
1171 SCJbAppendString(
ctx.js,
"dp_any");
1174 SCJbAppendString(
ctx.js,
"noalert");
1177 SCJbAppendString(
ctx.js,
"dsize");
1180 SCJbAppendString(
ctx.js,
"applayer");
1183 SCJbAppendString(
ctx.js,
"need_packet");
1186 SCJbAppendString(
ctx.js,
"need_stream");
1189 SCJbAppendString(
ctx.js,
"negated_mpm");
1192 SCJbAppendString(
ctx.js,
"flush");
1195 SCJbAppendString(
ctx.js,
"need_flowvar");
1198 SCJbAppendString(
ctx.js,
"filestore");
1201 SCJbAppendString(
ctx.js,
"toserver");
1204 SCJbAppendString(
ctx.js,
"toclient");
1207 SCJbAppendString(
ctx.js,
"tlsstore");
1210 SCJbAppendString(
ctx.js,
"bypass");
1213 SCJbAppendString(
ctx.js,
"prefilter");
1216 SCJbAppendString(
ctx.js,
"src_is_target");
1219 SCJbAppendString(
ctx.js,
"dst_is_target");
1226 SCJbOpenArray(
ctx.js,
"pkt_engines");
1228 for ( ; pkt != NULL; pkt = pkt->
next) {
1243 SCJbStartObject(
ctx.js);
1244 SCJbSetString(
ctx.js,
"name",
name);
1245 SCJbSetBool(
ctx.js,
"is_mpm", pkt->
mpm);
1247 SCJbOpenArray(
ctx.js,
"transforms");
1249 SCJbStartObject(
ctx.js);
1250 SCJbSetString(
ctx.js,
"name",
1263 SCJbOpenArray(
ctx.js,
"frame_engines");
1265 for (; frame != NULL; frame = frame->
next) {
1267 SCJbStartObject(
ctx.js);
1268 SCJbSetString(
ctx.js,
"name",
name);
1269 SCJbSetBool(
ctx.js,
"is_mpm", frame->
mpm);
1271 SCJbOpenArray(
ctx.js,
"transforms");
1273 SCJbStartObject(
ctx.js);
1274 SCJbSetString(
ctx.js,
"name",
1286 bool has_stream =
false;
1287 bool has_client_body_mpm =
false;
1288 bool has_file_data_mpm =
false;
1290 SCJbOpenArray(
ctx.js,
"engines");
1292 for ( ; app != NULL; app = app->
next) {
1307 }
else if (app->
mpm && strcmp(
name,
"http_client_body") == 0) {
1308 has_client_body_mpm =
true;
1309 }
else if (app->
mpm && strcmp(
name,
"file_data") == 0) {
1310 has_file_data_mpm =
true;
1313 SCJbStartObject(
ctx.js);
1314 SCJbSetString(
ctx.js,
"name",
name);
1315 const char *direction = app->
dir == 0 ?
"toserver" :
"toclient";
1316 SCJbSetString(
ctx.js,
"direction", direction);
1317 SCJbSetBool(
ctx.js,
"is_mpm", app->
mpm);
1322 SCJbOpenArray(
ctx.js,
"transforms");
1324 SCJbStartObject(
ctx.js);
1325 SCJbSetString(
ctx.js,
"name",
1339 if (has_stream && has_client_body_mpm)
1340 AnalyzerNote(&
ctx, (
char *)
"mpm in http_client_body combined with stream match leads to stream buffering");
1341 if (has_stream && has_file_data_mpm)
1342 AnalyzerNote(&
ctx, (
char *)
"mpm in file_data combined with stream match leads to stream buffering");
1345 SCJbOpenObject(
ctx.js,
"lists");
1355 if (pkt_mpm || app_mpm) {
1356 SCJbOpenObject(
ctx.js,
"mpm");
1364 SCJbSetString(
ctx.js,
"buffer",
name);
1371 switch (smd->
type) {
1375 DumpContent(
ctx.js, cd);
1387 SCJbOpenObject(
ctx.js,
"prefilter");
1394 SCJbSetString(
ctx.js,
"buffer",
name);
1396 SCJbSetString(
ctx.js,
"name", mname);
1400 if (
ctx.js_warnings) {
1401 SCJbClose(
ctx.js_warnings);
1402 SCJbSetObject(
ctx.js,
"warnings",
ctx.js_warnings);
1403 SCJbFree(
ctx.js_warnings);
1404 ctx.js_warnings = NULL;
1407 SCJbClose(
ctx.js_notes);
1408 SCJbSetObject(
ctx.js,
"notes",
ctx.js_notes);
1409 SCJbFree(
ctx.js_notes);
1410 ctx.js_notes = NULL;
1414 const char *filename =
"rules.json";
1416 char json_path[PATH_MAX] =
"";
1417 snprintf(json_path,
sizeof(json_path),
"%s/%s%s", log_dir,
1421 FILE *fp = fopen(json_path,
"a");
1423 fwrite(SCJbPtr(
ctx.js), SCJbLen(
ctx.js), 1, fp);
1437 SCJsonBuilder *root_jb = SCJbNewObject();
1441 SCJbOpenArray(root_jb,
"buffers");
1445 char str[1024] =
"";
1449 SCJsonBuilder *jb = arrays[p->
sm_list];
1450 if (arrays[p->
sm_list] == NULL) {
1451 jb = arrays[p->
sm_list] = SCJbNewObject();
1457 SCJbSetString(jb,
"name",
name);
1458 SCJbSetUint(jb,
"list_id", p->
sm_list);
1460 SCJbOpenArray(jb,
"patterns");
1463 SCJbStartObject(jb);
1464 SCJbSetString(jb,
"pattern",
str);
1466 SCJbSetUint(jb,
"cnt", p->
cnt);
1467 SCJbSetUint(jb,
"mpm", p->
mpm);
1468 SCJbOpenObject(jb,
"flags");
1479 SCJsonBuilder *jb = arrays[i];
1486 SCJbAppendObject(root_jb, jb);
1492 const char *filename =
"patterns.json";
1494 char json_path[PATH_MAX] =
"";
1495 snprintf(json_path,
sizeof(json_path),
"%s/%s%s", log_dir,
1499 FILE *fp = fopen(json_path,
"a");
1501 fwrite(SCJbPtr(root_jb), SCJbLen(root_jb), 1, fp);
1522 EngineAnalysisItemsReset(ea_ctx);
1530 FatalError(
"Unable to allocate analysis scratch pad");
1540 analyzer_item->
item_id = (uint16_t)item_id;
1541 if (analyzer_item->
item_id == -1) {
1543 FatalError(
"unable to initialize engine-analysis table: detect buffer \"%s\" not "
1576 uint32_t rule_bidirectional = 0;
1577 uint32_t rule_pcre = 0;
1578 uint32_t rule_pcre_http = 0;
1579 uint32_t rule_content = 0;
1580 uint32_t rule_flow = 0;
1581 uint32_t rule_flags = 0;
1582 uint32_t rule_flow_toserver = 0;
1583 uint32_t rule_flow_toclient = 0;
1584 uint32_t rule_flow_nostream = 0;
1585 uint32_t rule_ipv4_only = 0;
1586 uint32_t rule_ipv6_only = 0;
1587 uint32_t rule_flowbits = 0;
1588 uint32_t rule_flowint = 0;
1589 uint32_t rule_content_http = 0;
1590 uint32_t rule_content_offset_depth = 0;
1591 int32_t list_id = 0;
1592 uint32_t rule_warning = 0;
1593 uint32_t stream_buf = 0;
1594 uint32_t packet_buf = 0;
1595 uint32_t file_store = 0;
1596 uint32_t warn_pcre_no_content = 0;
1597 uint32_t warn_pcre_http_content = 0;
1598 uint32_t warn_pcre_http = 0;
1599 uint32_t warn_content_http_content = 0;
1600 uint32_t warn_content_http = 0;
1601 uint32_t warn_tcp_no_flow = 0;
1602 uint32_t warn_client_ports = 0;
1603 uint32_t warn_direction = 0;
1604 uint32_t warn_method_toclient = 0;
1605 uint32_t warn_method_serverbody = 0;
1606 uint32_t warn_pcre_method = 0;
1607 uint32_t warn_encoding_norm_http_buf = 0;
1608 uint32_t warn_file_store_not_present = 0;
1609 uint32_t warn_offset_depth_pkt_stream = 0;
1610 uint32_t warn_offset_depth_alproto = 0;
1611 uint32_t warn_non_alproto_fp_for_alproto_sig = 0;
1612 uint32_t warn_no_direction = 0;
1613 uint32_t warn_both_direction = 0;
1615 EngineAnalysisItemsInit(
de_ctx->
ea);
1621 rule_bidirectional = 1;
1635 rule_ipv4_only += 1;
1638 rule_ipv6_only += 1;
1646 if (item_slot == -1) {
1654 if (item_slot == -1) {
1659 rule_content_offset_depth++;
1665 rule_content_http++;
1672 warn_encoding_norm_http_buf += 1;
1679 rule_flow_toserver = 1;
1682 rule_flow_toclient = 1;
1687 rule_flow_nostream = 1;
1712 warn_file_store_not_present = 1;
1715 if (rule_pcre > 0 && rule_content == 0 && rule_content_http == 0) {
1717 warn_pcre_no_content = 1;
1720 if (rule_content_http > 0 && rule_pcre > 0 && rule_pcre_http == 0) {
1722 warn_pcre_http_content = 1;
1728 if (rule_content > 0 && rule_content_http > 0) {
1730 warn_content_http_content = 1;
1734 warn_content_http = 1;
1736 if (rule_content == 1) {
1741 (rule_content || rule_content_http || rule_pcre || rule_pcre_http || rule_flowbits ||
1744 warn_tcp_no_flow = 1;
1746 if (rule_flow && !rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)
1751 warn_client_ports = 1;
1754 if (rule_flow && rule_bidirectional && (rule_flow_toserver || rule_flow_toclient)) {
1759 if (*http_method_item_seen_ptr) {
1760 if (rule_flow && rule_flow_toclient) {
1762 warn_method_toclient = 1;
1764 if (*http_server_body_item_seen_ptr) {
1766 warn_method_serverbody = 1;
1768 if (rule_content == 0 && rule_content_http == 0 && (rule_pcre > 0 || rule_pcre_http > 0)) {
1770 warn_pcre_method = 1;
1773 if (rule_content_offset_depth > 0 && stream_buf && packet_buf) {
1775 warn_offset_depth_pkt_stream = 1;
1779 warn_offset_depth_alproto = 1;
1784 warn_non_alproto_fp_for_alproto_sig = 1;
1788 warn_no_direction += 1;
1795 warn_both_direction += 1;
1800 if (!rule_warnings_only || (rule_warnings_only && rule_warning > 0)) {
1802 fprintf(fp,
"== Sid: %u ==\n", s->
id);
1803 fprintf(fp,
"%s\n", line);
1809 fprintf(fp,
" Rule is ip only.\n");
1812 fprintf(fp,
" Rule is like ip only.\n");
1815 fprintf(fp,
" Rule is PD only.\n");
1818 fprintf(fp,
" Rule is DE only.\n");
1821 fprintf(fp,
" Rule is packet inspecting.\n");
1824 fprintf(fp,
" Rule is packet and stream inspecting.\n");
1827 fprintf(fp,
" Rule is stream inspecting.\n");
1830 fprintf(fp,
" Rule is app-layer inspecting.\n");
1833 fprintf(fp,
" Rule is App-layer TX inspecting.\n");
1839 fprintf(fp,
" Rule is IPv6 only.\n");
1841 fprintf(fp,
" Rule is IPv4 only.\n");
1843 fprintf(fp,
" Rule matches on packets.\n");
1844 if (!rule_flow_nostream && stream_buf &&
1845 (rule_flow || rule_flowbits || rule_flowint || rule_content || rule_pcre)) {
1846 fprintf(fp,
" Rule matches on reassembled stream.\n");
1851 fprintf(fp,
" Rule matches on %s buffer.\n", ai->
display_name);
1857 if (rule_content || rule_content_http || rule_pcre || rule_pcre_http) {
1859 " Rule contains %u content options, %u http content options, %u pcre "
1860 "options, and %u pcre options with http modifiers.\n",
1861 rule_content, rule_content_http, rule_pcre, rule_pcre_http);
1866 fprintf(fp,
" Prefilter on: %s.\n",
1869 EngineAnalysisRulesPrintFP(
de_ctx, s);
1873 if (warn_pcre_no_content ) {
1874 fprintf(fp,
" Warning: Rule uses pcre without a content option present.\n"
1875 " -Consider adding a content to improve performance of this "
1878 if (warn_pcre_http_content ) {
1879 fprintf(fp,
" Warning: Rule uses content options with http_* and pcre options "
1880 "without http modifiers.\n"
1881 " -Consider adding http pcre modifier.\n");
1883 else if (warn_pcre_http ) {
1884 fprintf(fp,
" Warning: Rule app layer protocol is http, but pcre options do not "
1885 "have http modifiers.\n"
1886 " -Consider adding http pcre modifiers.\n");
1888 if (warn_content_http_content ) {
1890 " Warning: Rule contains content with http_* and content without http_*.\n"
1891 " -Consider adding http content modifiers.\n");
1893 if (warn_content_http ) {
1894 fprintf(fp,
" Warning: Rule app layer protocol is http, but content options do not "
1895 "have http_* modifiers.\n"
1896 " -Consider adding http content modifiers.\n");
1898 if (rule_content == 1) {
1901 if (warn_encoding_norm_http_buf) {
1902 fprintf(fp,
" Warning: Rule may contain percent encoded content for a normalized "
1903 "http buffer match.\n");
1905 if (warn_tcp_no_flow
1907 fprintf(fp,
" Warning: TCP rule without a flow or flags option.\n"
1908 " -Consider adding flow or flags to improve performance of "
1911 if (warn_client_ports
1916 " Warning: Rule contains ports or port variables only on the client side.\n"
1917 " -Flow direction possibly inconsistent with rule.\n");
1919 if (warn_direction ) {
1920 fprintf(fp,
" Warning: Rule is bidirectional and has a flow option with a specific "
1923 if (warn_method_toclient ) {
1924 fprintf(fp,
" Warning: Rule uses content or pcre for http_method with "
1925 "flow:to_client or from_server\n");
1927 if (warn_method_serverbody ) {
1928 fprintf(fp,
" Warning: Rule uses content or pcre for http_method with content or "
1929 "pcre for http_server_body.\n");
1931 if (warn_pcre_method
1933 fprintf(fp,
" Warning: Rule uses pcre with only a http_method content; possible "
1934 "performance issue.\n");
1936 if (warn_offset_depth_pkt_stream) {
1937 fprintf(fp,
" Warning: Rule has depth"
1938 "/offset with raw content keywords. Please note the "
1939 "offset/depth will be checked against both packet "
1940 "payloads and stream. If you meant to have the offset/"
1941 "depth checked against just the payload, you can update "
1942 "the signature as \"alert tcp-pkt...\"\n");
1944 if (warn_offset_depth_alproto) {
1946 " Warning: Rule has "
1947 "offset/depth set along with a match on a specific "
1948 "app layer protocol - %d. This can lead to FNs if we "
1949 "have a offset/depth content match on a packet payload "
1950 "before we can detect the app layer protocol for the "
1954 if (warn_non_alproto_fp_for_alproto_sig) {
1955 fprintf(fp,
" Warning: Rule app layer "
1956 "protocol is http, but the fast_pattern is set on the raw "
1957 "stream. Consider adding fast_pattern over a http "
1958 "buffer for increased performance.");
1960 if (warn_no_direction) {
1961 fprintf(fp,
" Warning: Rule has no direction indicator.\n");
1963 if (warn_both_direction) {
1964 fprintf(fp,
" Warning: Rule is inspecting both the request and the response.\n");
1966 if (warn_file_store_not_present) {
1967 fprintf(fp,
" Warning: Rule requires file-store but the output file-store is not "
1970 if (rule_warning == 0) {
1971 fprintf(fp,
" No warnings for this rule.\n");
1982 uint32_t accept_rules = 0;
1983 SCJbSetString(
ctx->js,
"policy",
"drop:flow");
1984 SCJbOpenArray(
ctx->js,
"rules");
1993 if (direction == STREAM_TOSERVER) {
2010 if (accept_rules == 0) {
2011 AnalyzerWarning(
ctx, (
char *)
"no accept rules for state, default policy will be applied");
2018 ctx.js = SCJbNewObject();
2022 SCJbOpenObject(
ctx.js,
"tables");
2023 SCJbOpenObject(
ctx.js,
"packet:filter");
2024 SCJbSetString(
ctx.js,
"policy",
"drop:packet");
2025 SCJbOpenArray(
ctx.js,
"rules");
2026 uint32_t accept_rules = 0;
2027 uint32_t last_sid = 0;
2034 if (last_sid == s->
id)
2041 if (accept_rules == 0) {
2042 AnalyzerWarning(&
ctx,
2043 (
char *)
"no accept rules for \'packet:filter\', default policy will be applied");
2045 if (
ctx.js_warnings) {
2046 SCJbClose(
ctx.js_warnings);
2047 SCJbSetObject(
ctx.js,
"warnings",
ctx.js_warnings);
2048 SCJbFree(
ctx.js_warnings);
2049 ctx.js_warnings = NULL;
2054 if (!AppProtoIsValid(a))
2063 const uint8_t complete_state_ts =
2065 for (uint8_t state = 0; state < complete_state_ts; state++) {
2068 char table_name[128];
2070 SCJbOpenObject(
ctx.js, table_name);
2071 FirewallAddRulesForState(
de_ctx, a, state, STREAM_TOSERVER, &
ctx);
2072 if (
ctx.js_warnings) {
2073 SCJbClose(
ctx.js_warnings);
2074 SCJbSetObject(
ctx.js,
"warnings",
ctx.js_warnings);
2075 SCJbFree(
ctx.js_warnings);
2076 ctx.js_warnings = NULL;
2080 const uint8_t complete_state_tc =
2082 for (uint8_t state = 0; state < complete_state_tc; state++) {
2085 char table_name[128];
2087 SCJbOpenObject(
ctx.js, table_name);
2088 FirewallAddRulesForState(
de_ctx, a, state, STREAM_TOCLIENT, &
ctx);
2089 if (
ctx.js_warnings) {
2090 SCJbClose(
ctx.js_warnings);
2091 SCJbSetObject(
ctx.js,
"warnings",
ctx.js_warnings);
2092 SCJbFree(
ctx.js_warnings);
2093 ctx.js_warnings = NULL;
2099 SCJbOpenObject(
ctx.js,
"packet:td");
2100 SCJbSetString(
ctx.js,
"policy",
"accept:hook");
2102 SCJbOpenArray(
ctx.js,
"rules");
2108 if (last_sid == s->
id)
2115 SCJbOpenObject(
ctx.js,
"app:td");
2116 SCJbSetString(
ctx.js,
"policy",
"accept:hook");
2118 SCJbOpenArray(
ctx.js,
"rules");
2124 if (last_sid == s->
id)
2133 SCJbOpenObject(
ctx.js,
"lists");
2134 SCJbOpenObject(
ctx.js,
"firewall");
2136 SCJbOpenArray(
ctx.js,
"rules");
2140 if (last_sid == s->
id)
2148 SCJbOpenObject(
ctx.js,
"td");
2150 SCJbOpenArray(
ctx.js,
"rules");
2154 if (last_sid == s->
id)
2162 SCJbOpenObject(
ctx.js,
"all");
2164 SCJbOpenArray(
ctx.js,
"rules");
2166 if (last_sid == s->
id)
2178 const char *filename =
"firewall.json";
2180 char json_path[PATH_MAX] =
"";
2181 snprintf(json_path,
sizeof(json_path),
"%s/%s", log_dir, filename);
2184 FILE *fp = fopen(json_path,
"w");
2186 fwrite(SCJbPtr(
ctx.js), SCJbLen(
ctx.js), 1, fp);