]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
app-layer: error counters
authorVictor Julien <victor@inliniac.net>
Tue, 9 Nov 2021 12:45:54 +0000 (13:45 +0100)
committerVictor Julien <vjulien@oisf.net>
Thu, 3 Feb 2022 19:12:05 +0000 (20:12 +0100)
Per app-layer error counters for:
gap, parser, internal (AppLayerResult issues), alloc

src/app-layer-parser.c
src/app-layer.c
src/app-layer.h

index 884f1d7deae5aab9d940bd7a7e25e952f0c1ac98..9ba84e0e265d124925004a6163df5026e6b2e297 100644 (file)
@@ -1269,6 +1269,7 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow
                 AppLayerParserStreamTruncated(f->proto, alproto, f->alstate,
                         flags);
             }
+            AppLayerIncGapErrorCounter(tv, f);
             goto error;
         }
     }
@@ -1276,8 +1277,10 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow
     /* Get the parser state (if any) */
     if (pstate == NULL) {
         f->alparser = pstate = AppLayerParserStateAlloc();
-        if (pstate == NULL)
+        if (pstate == NULL) {
+            AppLayerIncAllocErrorCounter(tv, f);
             goto error;
+        }
     }
 
     SetEOFFlags(pstate, flags);
@@ -1285,8 +1288,10 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow
     alstate = f->alstate;
     if (alstate == NULL || FlowChangeProto(f)) {
         f->alstate = alstate = p->StateAlloc(alstate, f->alproto_orig);
-        if (alstate == NULL)
+        if (alstate == NULL) {
+            AppLayerIncAllocErrorCounter(tv, f);
             goto error;
+        }
         SCLogDebug("alloced new app layer state %p (name %s)",
                    alstate, AppLayerGetProtoName(f->alproto));
     } else {
@@ -1304,6 +1309,7 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow
         AppLayerResult res = p->Parser[direction](f, alstate, pstate, stream_slice,
                 alp_tctx->alproto_local_storage[f->protomap][alproto]);
         if (res.status < 0) {
+            AppLayerIncParserErrorCounter(tv, f);
             goto error;
         } else if (res.status > 0) {
             DEBUG_VALIDATE_BUG_ON(res.consumed > input_len);
@@ -1315,6 +1321,7 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow
             /* put protocol in error state on improper use of the
              * return codes. */
             if (res.consumed > input_len || res.needed + res.consumed < input_len) {
+                AppLayerIncInternalErrorCounter(tv, f);
                 goto error;
             }
 
index 530d5f8b15f712eb9d1c992f5909d31860091f92..149936b1a1237e78ae84cbe3a82036c9c4886f88 100644 (file)
@@ -77,11 +77,19 @@ struct AppLayerThreadCtx_ {
 typedef struct AppLayerCounterNames_ {
     char name[MAX_COUNTER_SIZE];
     char tx_name[MAX_COUNTER_SIZE];
+    char gap_error[MAX_COUNTER_SIZE];
+    char parser_error[MAX_COUNTER_SIZE];
+    char internal_error[MAX_COUNTER_SIZE];
+    char alloc_error[MAX_COUNTER_SIZE];
 } AppLayerCounterNames;
 
 typedef struct AppLayerCounters_ {
     uint16_t counter_id;
     uint16_t counter_tx_id;
+    uint16_t gap_error_id;
+    uint16_t parser_error_id;
+    uint16_t internal_error_id;
+    uint16_t alloc_error_id;
 } AppLayerCounters;
 
 /* counter names. Only used at init. */
@@ -120,6 +128,38 @@ void AppLayerIncTxCounter(ThreadVars *tv, Flow *f, uint64_t step)
     }
 }
 
+void AppLayerIncGapErrorCounter(ThreadVars *tv, Flow *f)
+{
+    const uint16_t id = applayer_counters[f->protomap][f->alproto].gap_error_id;
+    if (likely(tv && id > 0)) {
+        StatsIncr(tv, id);
+    }
+}
+
+void AppLayerIncAllocErrorCounter(ThreadVars *tv, Flow *f)
+{
+    const uint16_t id = applayer_counters[f->protomap][f->alproto].alloc_error_id;
+    if (likely(tv && id > 0)) {
+        StatsIncr(tv, id);
+    }
+}
+
+void AppLayerIncParserErrorCounter(ThreadVars *tv, Flow *f)
+{
+    const uint16_t id = applayer_counters[f->protomap][f->alproto].parser_error_id;
+    if (likely(tv && id > 0)) {
+        StatsIncr(tv, id);
+    }
+}
+
+void AppLayerIncInternalErrorCounter(ThreadVars *tv, Flow *f)
+{
+    const uint16_t id = applayer_counters[f->protomap][f->alproto].internal_error_id;
+    if (likely(tv && id > 0)) {
+        StatsIncr(tv, id);
+    }
+}
+
 /* in IDS mode protocol detection is done in reverse order:
  * when TCP data is ack'd. We want to flag the correct packet,
  * so in this case we set a flag in the flow so that the first
@@ -942,6 +982,7 @@ void AppLayerSetupCounters()
     AppProto alproto;
     AppProto alprotos[ALPROTO_MAX];
     const char *str = "app_layer.flow.";
+    const char *estr = "app_layer.error.";
 
     AppLayerProtoDetectSupportedAppProtocols(alprotos);
 
@@ -964,6 +1005,21 @@ void AppLayerSetupCounters()
                     snprintf(applayer_counter_names[ipproto_map][alproto].tx_name,
                             sizeof(applayer_counter_names[ipproto_map][alproto].tx_name),
                             "%s%s%s", tx_str, alproto_str, ipproto_suffix);
+
+                    if (ipproto == IPPROTO_TCP) {
+                        snprintf(applayer_counter_names[ipproto_map][alproto].gap_error,
+                                sizeof(applayer_counter_names[ipproto_map][alproto].gap_error),
+                                "%s%s%s.gap", estr, alproto_str, ipproto_suffix);
+                    }
+                    snprintf(applayer_counter_names[ipproto_map][alproto].alloc_error,
+                            sizeof(applayer_counter_names[ipproto_map][alproto].alloc_error),
+                            "%s%s%s.alloc", estr, alproto_str, ipproto_suffix);
+                    snprintf(applayer_counter_names[ipproto_map][alproto].parser_error,
+                            sizeof(applayer_counter_names[ipproto_map][alproto].parser_error),
+                            "%s%s%s.parser", estr, alproto_str, ipproto_suffix);
+                    snprintf(applayer_counter_names[ipproto_map][alproto].internal_error,
+                            sizeof(applayer_counter_names[ipproto_map][alproto].internal_error),
+                            "%s%s%s.internal", estr, alproto_str, ipproto_suffix);
                 } else {
                     snprintf(applayer_counter_names[ipproto_map][alproto].name,
                             sizeof(applayer_counter_names[ipproto_map][alproto].name),
@@ -971,11 +1027,31 @@ void AppLayerSetupCounters()
                     snprintf(applayer_counter_names[ipproto_map][alproto].tx_name,
                             sizeof(applayer_counter_names[ipproto_map][alproto].tx_name),
                             "%s%s", tx_str, alproto_str);
+
+                    if (ipproto == IPPROTO_TCP) {
+                        snprintf(applayer_counter_names[ipproto_map][alproto].gap_error,
+                                sizeof(applayer_counter_names[ipproto_map][alproto].gap_error),
+                                "%s%s.gap", estr, alproto_str);
+                    }
+                    snprintf(applayer_counter_names[ipproto_map][alproto].alloc_error,
+                            sizeof(applayer_counter_names[ipproto_map][alproto].alloc_error),
+                            "%s%s.alloc", estr, alproto_str);
+                    snprintf(applayer_counter_names[ipproto_map][alproto].parser_error,
+                            sizeof(applayer_counter_names[ipproto_map][alproto].parser_error),
+                            "%s%s.parser", estr, alproto_str);
+                    snprintf(applayer_counter_names[ipproto_map][alproto].internal_error,
+                            sizeof(applayer_counter_names[ipproto_map][alproto].internal_error),
+                            "%s%s.internal", estr, alproto_str);
                 }
             } else if (alproto == ALPROTO_FAILED) {
                 snprintf(applayer_counter_names[ipproto_map][alproto].name,
                         sizeof(applayer_counter_names[ipproto_map][alproto].name),
                         "%s%s%s", str, "failed", ipproto_suffix);
+                if (ipproto == IPPROTO_TCP) {
+                    snprintf(applayer_counter_names[ipproto_map][alproto].gap_error,
+                            sizeof(applayer_counter_names[ipproto_map][alproto].gap_error),
+                            "%sfailed%s.gap", estr, ipproto_suffix);
+                }
             }
         }
     }
@@ -1000,9 +1076,25 @@ void AppLayerRegisterThreadCounters(ThreadVars *tv)
 
                 applayer_counters[ipproto_map][alproto].counter_tx_id =
                     StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].tx_name, tv);
+
+                if (ipproto == IPPROTO_TCP) {
+                    applayer_counters[ipproto_map][alproto].gap_error_id = StatsRegisterCounter(
+                            applayer_counter_names[ipproto_map][alproto].gap_error, tv);
+                }
+                applayer_counters[ipproto_map][alproto].alloc_error_id = StatsRegisterCounter(
+                        applayer_counter_names[ipproto_map][alproto].alloc_error, tv);
+                applayer_counters[ipproto_map][alproto].parser_error_id = StatsRegisterCounter(
+                        applayer_counter_names[ipproto_map][alproto].parser_error, tv);
+                applayer_counters[ipproto_map][alproto].internal_error_id = StatsRegisterCounter(
+                        applayer_counter_names[ipproto_map][alproto].internal_error, tv);
             } else if (alproto == ALPROTO_FAILED) {
                 applayer_counters[ipproto_map][alproto].counter_id =
                     StatsRegisterCounter(applayer_counter_names[ipproto_map][alproto].name, tv);
+
+                if (ipproto == IPPROTO_TCP) {
+                    applayer_counters[ipproto_map][alproto].gap_error_id = StatsRegisterCounter(
+                            applayer_counter_names[ipproto_map][alproto].gap_error, tv);
+                }
             }
         }
     }
index 76b40cf9c1d171c0567071799606512e8e6ed738..b220092a5ca00105d0ddcf8b396dbb6a74cb476a 100644 (file)
@@ -146,6 +146,10 @@ void AppLayerUnittestsRegister(void);
 #endif
 
 void AppLayerIncTxCounter(ThreadVars *tv, Flow *f, uint64_t step);
+void AppLayerIncGapErrorCounter(ThreadVars *tv, Flow *f);
+void AppLayerIncAllocErrorCounter(ThreadVars *tv, Flow *f);
+void AppLayerIncParserErrorCounter(ThreadVars *tv, Flow *f);
+void AppLayerIncInternalErrorCounter(ThreadVars *tv, Flow *f);
 
 static inline uint8_t StreamSliceGetFlags(const StreamSlice *stream_slice)
 {