fprintf(fp, "\n");
}
}
+
+#include "app-layer-parser.h"
+
+static void FirewallAddRulesForState(const DetectEngineCtx *de_ctx, const AppProto a,
+ const uint8_t state, const uint8_t direction, RuleAnalyzer *ctx)
+{
+ uint32_t accept_rules = 0;
+ SCJbSetString(ctx->js, "policy", "drop:flow");
+ SCJbOpenArray(ctx->js, "rules");
+ for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
+ if ((s->flags & SIG_FLAG_FIREWALL) == 0)
+ break;
+ if (s->type != SIG_TYPE_APP_TX)
+ continue;
+ if (s->alproto != a)
+ continue;
+
+ if (direction == STREAM_TOSERVER) {
+ if (s->flags & SIG_FLAG_TOCLIENT) {
+ continue;
+ }
+ } else {
+ if (s->flags & SIG_FLAG_TOSERVER) {
+ continue;
+ }
+ }
+
+ if (s->app_progress_hook == state) {
+ SCJbAppendString(ctx->js, s->sig_str);
+ accept_rules += ((s->action & ACTION_ACCEPT) != 0);
+ }
+ }
+ SCJbClose(ctx->js);
+
+ if (accept_rules == 0) {
+ AnalyzerWarning(ctx, (char *)"no accept rules for state, default policy will be applied");
+ }
+}
+
+int FirewallAnalyzer(const DetectEngineCtx *de_ctx)
+{
+ RuleAnalyzer ctx = { NULL, NULL, NULL };
+ ctx.js = SCJbNewObject();
+ if (ctx.js == NULL)
+ return -1;
+
+ SCJbOpenObject(ctx.js, "tables");
+ SCJbOpenObject(ctx.js, "packet:filter");
+ SCJbSetString(ctx.js, "policy", "drop:packet");
+ SCJbOpenArray(ctx.js, "rules");
+ uint32_t accept_rules = 0;
+ uint32_t last_sid = 0;
+ for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
+ if ((s->flags & SIG_FLAG_FIREWALL) == 0)
+ break;
+ if (s->type != SIG_TYPE_PKT)
+ continue;
+ /* don't double list <> sigs */
+ if (last_sid == s->id)
+ continue;
+ last_sid = s->id;
+ SCJbAppendString(ctx.js, s->sig_str);
+ accept_rules += ((s->action & ACTION_ACCEPT) != 0);
+ }
+ SCJbClose(ctx.js);
+ if (accept_rules == 0) {
+ AnalyzerWarning(&ctx,
+ (char *)"no accept rules for \'packet:filter\', default policy will be applied");
+ }
+ if (ctx.js_warnings) {
+ SCJbClose(ctx.js_warnings);
+ SCJbSetObject(ctx.js, "warnings", ctx.js_warnings);
+ SCJbFree(ctx.js_warnings);
+ ctx.js_warnings = NULL;
+ }
+ SCJbClose(ctx.js); // packet_filter
+
+ for (AppProto a = 0; a < g_alproto_max; a++) {
+ if (!AppProtoIsValid(a))
+ continue;
+
+ // HACK not all protocols have named states yet
+ const char *hack = AppLayerParserGetStateNameById(IPPROTO_TCP, a, 0, STREAM_TOSERVER);
+ if (!hack)
+ continue;
+
+ SCJbOpenObject(ctx.js, AppProtoToString(a));
+ const uint8_t complete_state_ts =
+ (const uint8_t)AppLayerParserGetStateProgressCompletionStatus(a, STREAM_TOSERVER);
+ for (uint8_t state = 0; state < complete_state_ts; state++) {
+ const char *name =
+ AppLayerParserGetStateNameById(IPPROTO_TCP, a, state, STREAM_TOSERVER);
+ char table_name[128];
+ snprintf(table_name, sizeof(table_name), "app:%s:%s", AppProtoToString(a), name);
+ SCJbOpenObject(ctx.js, table_name);
+ FirewallAddRulesForState(de_ctx, a, state, STREAM_TOSERVER, &ctx);
+ if (ctx.js_warnings) {
+ SCJbClose(ctx.js_warnings);
+ SCJbSetObject(ctx.js, "warnings", ctx.js_warnings);
+ SCJbFree(ctx.js_warnings);
+ ctx.js_warnings = NULL;
+ }
+ SCJbClose(ctx.js);
+ }
+ const uint8_t complete_state_tc =
+ (const uint8_t)AppLayerParserGetStateProgressCompletionStatus(a, STREAM_TOCLIENT);
+ for (uint8_t state = 0; state < complete_state_tc; state++) {
+ const char *name =
+ AppLayerParserGetStateNameById(IPPROTO_TCP, a, state, STREAM_TOCLIENT);
+ char table_name[128];
+ snprintf(table_name, sizeof(table_name), "app:%s:%s", AppProtoToString(a), name);
+ SCJbOpenObject(ctx.js, table_name);
+ FirewallAddRulesForState(de_ctx, a, state, STREAM_TOCLIENT, &ctx);
+ if (ctx.js_warnings) {
+ SCJbClose(ctx.js_warnings);
+ SCJbSetObject(ctx.js, "warnings", ctx.js_warnings);
+ SCJbFree(ctx.js_warnings);
+ ctx.js_warnings = NULL;
+ }
+ SCJbClose(ctx.js);
+ }
+ SCJbClose(ctx.js); // app layer
+ }
+ SCJbOpenObject(ctx.js, "packet:td");
+ SCJbSetString(ctx.js, "policy", "accept:hook");
+ last_sid = 0;
+ SCJbOpenArray(ctx.js, "rules");
+ for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
+ if ((s->flags & SIG_FLAG_FIREWALL) != 0)
+ continue;
+ if (s->type == SIG_TYPE_APP_TX)
+ continue;
+ if (last_sid == s->id)
+ continue;
+ last_sid = s->id;
+ SCJbAppendString(ctx.js, s->sig_str);
+ }
+ SCJbClose(ctx.js); // rules
+ SCJbClose(ctx.js); // packet:td
+ SCJbOpenObject(ctx.js, "app:td");
+ SCJbSetString(ctx.js, "policy", "accept:hook");
+ last_sid = 0;
+ SCJbOpenArray(ctx.js, "rules");
+ for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
+ if ((s->flags & SIG_FLAG_FIREWALL) != 0)
+ continue;
+ if (s->type != SIG_TYPE_APP_TX)
+ continue;
+ if (last_sid == s->id)
+ continue;
+ last_sid = s->id;
+ SCJbAppendString(ctx.js, s->sig_str);
+ }
+ SCJbClose(ctx.js); // rules
+ SCJbClose(ctx.js); // app:td
+ SCJbClose(ctx.js); // tables
+
+ SCJbOpenObject(ctx.js, "lists");
+ SCJbOpenObject(ctx.js, "firewall");
+ last_sid = 0;
+ SCJbOpenArray(ctx.js, "rules");
+ for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
+ if ((s->flags & SIG_FLAG_FIREWALL) == 0)
+ continue;
+ if (last_sid == s->id)
+ continue;
+ last_sid = s->id;
+ SCJbAppendString(ctx.js, s->sig_str);
+ }
+ SCJbClose(ctx.js); // rules
+ SCJbClose(ctx.js); // firewall
+
+ SCJbOpenObject(ctx.js, "td");
+ last_sid = 0;
+ SCJbOpenArray(ctx.js, "rules");
+ for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
+ if ((s->flags & SIG_FLAG_FIREWALL) != 0)
+ continue;
+ if (last_sid == s->id)
+ continue;
+ last_sid = s->id;
+ SCJbAppendString(ctx.js, s->sig_str);
+ }
+ SCJbClose(ctx.js); // rules
+ SCJbClose(ctx.js); // td
+
+ SCJbOpenObject(ctx.js, "all");
+ last_sid = 0;
+ SCJbOpenArray(ctx.js, "rules");
+ for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
+ if (last_sid == s->id)
+ continue;
+ last_sid = s->id;
+ SCJbAppendString(ctx.js, s->sig_str);
+ }
+ SCJbClose(ctx.js); // rules
+ SCJbClose(ctx.js); // all
+
+ SCJbClose(ctx.js); // lists
+
+ SCJbClose(ctx.js); // top level object
+
+ const char *filename = "firewall.json";
+ const char *log_dir = SCConfigGetLogDirectory();
+ char json_path[PATH_MAX] = "";
+ snprintf(json_path, sizeof(json_path), "%s/%s", log_dir, filename);
+
+ SCMutexLock(&g_rules_analyzer_write_m);
+ FILE *fp = fopen(json_path, "w");
+ if (fp != NULL) {
+ fwrite(SCJbPtr(ctx.js), SCJbLen(ctx.js), 1, fp);
+ fprintf(fp, "\n");
+ fclose(fp);
+ }
+ SCMutexUnlock(&g_rules_analyzer_write_m);
+ SCJbFree(ctx.js);
+ return 0;
+}