]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
app-layer/probing-parser: implement reverse flow
authorVictor Julien <victor@inliniac.net>
Mon, 1 Apr 2019 20:20:53 +0000 (22:20 +0200)
committerVictor Julien <victor@inliniac.net>
Tue, 2 Apr 2019 13:05:30 +0000 (15:05 +0200)
Implement midstream support for the pure probing parsers. These
need to look up the appropriate parsers based on the reverse
tuple.

src/app-layer-detect-proto.c

index 84b671ce4ad7ecbffb3c7e8b0bc2a1164d52196c..3e75482ee21540490de6c19884e889c5cf3d296b 100644 (file)
@@ -444,6 +444,39 @@ static AppProto AppLayerProtoDetectPEGetProto(Flow *f, uint8_t ipproto,
     return alproto;
 }
 
+static inline AppProto PPGetProto(
+        const AppLayerProtoDetectProbingParserElement *pe,
+        Flow *f, uint8_t direction,
+        uint8_t *buf, uint32_t buflen,
+        uint32_t *alproto_masks, uint8_t *rdir
+)
+{
+    while (pe != NULL) {
+        if ((buflen < pe->min_depth)  ||
+            (alproto_masks[0] & pe->alproto_mask)) {
+            pe = pe->next;
+            continue;
+        }
+
+        AppProto alproto = ALPROTO_UNKNOWN;
+        if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) {
+            alproto = pe->ProbingParserTs(f, direction, buf, buflen, rdir);
+        } else if (pe->ProbingParserTc != NULL) {
+            alproto = pe->ProbingParserTc(f, direction, buf, buflen, rdir);
+        }
+        if (AppProtoIsValid(alproto)) {
+            SCReturnUInt(alproto);
+        }
+        if (alproto == ALPROTO_FAILED ||
+            (pe->max_depth != 0 && buflen > pe->max_depth)) {
+            alproto_masks[0] |= pe->alproto_mask;
+        }
+        pe = pe->next;
+    }
+
+    SCReturnUInt(ALPROTO_UNKNOWN);
+}
+
 /**
  * \brief Call the probing parser if it exists for this flow.
  *
@@ -453,22 +486,28 @@ static AppProto AppLayerProtoDetectPEGetProto(Flow *f, uint8_t ipproto,
  */
 static AppProto AppLayerProtoDetectPPGetProto(Flow *f,
         uint8_t *buf, uint32_t buflen,
-        uint8_t ipproto, uint8_t direction,
+        uint8_t ipproto, const uint8_t idir,
         bool *reverse_flow)
 {
     const AppLayerProtoDetectProbingParserPort *pp_port_dp = NULL;
     const AppLayerProtoDetectProbingParserPort *pp_port_sp = NULL;
-    const AppLayerProtoDetectProbingParserElement *pe = NULL;
     const AppLayerProtoDetectProbingParserElement *pe1 = NULL;
     const AppLayerProtoDetectProbingParserElement *pe2 = NULL;
     AppProto alproto = ALPROTO_UNKNOWN;
     uint32_t *alproto_masks;
     uint32_t mask = 0;
+    uint8_t dir = idir;
+    uint16_t dp = f->protodetect_dp ? f->protodetect_dp : FLOW_GET_DP(f);
+    uint16_t sp = FLOW_GET_SP(f);
 
-    const uint16_t dp = f->protodetect_dp ? f->protodetect_dp : f->dp;
-    const uint16_t sp = f->sp;
+again_midstream:
+    if (idir != dir) {
+        SWAP_VARS(uint16_t, dp, sp); /* look up parsers in rev dir */
+    }
+    SCLogDebug("%u->%u %s", sp, dp,
+            (dir == STREAM_TOSERVER) ? "toserver" : "toclient");
 
-    if (direction & STREAM_TOSERVER) {
+    if (dir == STREAM_TOSERVER) {
         /* first try the destination port */
         pp_port_dp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, dp);
         alproto_masks = &f->probing_parser_toserver_alproto_masks;
@@ -515,82 +554,62 @@ static AppProto AppLayerProtoDetectPPGetProto(Flow *f,
 
     if (pe1 == NULL && pe2 == NULL) {
         SCLogDebug("%s - No probing parsers found for either port",
-                (direction & STREAM_TOSERVER) ? "toserver":"toclient");
-        FLOW_SET_PP_DONE(f, direction);
-        goto end;
+                (dir == STREAM_TOSERVER) ? "toserver":"toclient");
+        if (dir == idir)
+            FLOW_SET_PP_DONE(f, dir);
+        goto noparsers;
     }
 
-    /* run the parser(s) */
+    /* run the parser(s): always call with original direction */
     uint8_t rdir = 0;
-    pe = pe1;
-    while (pe != NULL) {
-        if ((buflen < pe->min_depth)  ||
-            (alproto_masks[0] & pe->alproto_mask)) {
-            pe = pe->next;
-            continue;
-        }
+    alproto = PPGetProto(pe1, f, idir, buf, buflen, alproto_masks, &rdir);
+    if (AppProtoIsValid(alproto))
+        goto end;
+    alproto = PPGetProto(pe2, f, idir, buf, buflen, alproto_masks, &rdir);
+    if (AppProtoIsValid(alproto))
+        goto end;
 
-        if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) {
-            alproto = pe->ProbingParserTs(f, direction, buf, buflen, &rdir);
-        } else if (pe->ProbingParserTc != NULL) {
-            alproto = pe->ProbingParserTc(f, direction, buf, buflen, &rdir);
-        }
-        if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED)
-            goto end;
-        if (alproto == ALPROTO_FAILED ||
-            (pe->max_depth != 0 && buflen > pe->max_depth)) {
-            alproto_masks[0] |= pe->alproto_mask;
+    /* get the mask we need for this direction */
+    if (dir == idir) {
+        if (pp_port_dp && pp_port_sp)
+            mask = pp_port_dp->alproto_mask|pp_port_sp->alproto_mask;
+        else if (pp_port_dp)
+            mask = pp_port_dp->alproto_mask;
+        else if (pp_port_sp)
+            mask = pp_port_sp->alproto_mask;
+
+        if (alproto_masks[0] == mask) {
+            FLOW_SET_PP_DONE(f, dir);
+            SCLogDebug("%s, mask is now %08x, needed %08x, so done",
+                    (dir == STREAM_TOSERVER) ? "toserver":"toclient",
+                    alproto_masks[0], mask);
+        } else {
+            SCLogDebug("%s, mask is now %08x, need %08x",
+                    (dir == STREAM_TOSERVER) ? "toserver":"toclient",
+                    alproto_masks[0], mask);
         }
-        pe = pe->next;
     }
-    pe = pe2;
-    while (pe != NULL) {
-        if ((buflen < pe->min_depth)  ||
-            (alproto_masks[0] & pe->alproto_mask)) {
-            pe = pe->next;
-            continue;
-        }
 
-        if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) {
-            alproto = pe->ProbingParserTs(f, direction, buf, buflen, &rdir);
-        } else if (pe->ProbingParserTc != NULL) {
-            alproto = pe->ProbingParserTc(f, direction, buf, buflen, &rdir);
-        }
-        if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED)
-            goto end;
-        if (alproto == ALPROTO_FAILED ||
-            (pe->max_depth != 0 && buflen > pe->max_depth)) {
-            alproto_masks[0] |= pe->alproto_mask;
+ noparsers:
+    if (stream_config.midstream == true && idir == dir) {
+        if (idir == STREAM_TOSERVER) {
+            dir = STREAM_TOCLIENT;
+        } else {
+            dir = STREAM_TOSERVER;
         }
-        pe = pe->next;
-    }
-
-    /* get the mask we need for this direction */
-    if (pp_port_dp && pp_port_sp)
-        mask = pp_port_dp->alproto_mask|pp_port_sp->alproto_mask;
-    else if (pp_port_dp)
-        mask = pp_port_dp->alproto_mask;
-    else if (pp_port_sp)
-        mask = pp_port_sp->alproto_mask;
-
-    if (alproto_masks[0] == mask) {
-        FLOW_SET_PP_DONE(f, direction);
-        SCLogDebug("%s, mask is now %08x, needed %08x, so done",
-                (direction & STREAM_TOSERVER) ? "toserver":"toclient", alproto_masks[0], mask);
-    } else {
-        SCLogDebug("%s, mask is now %08x, need %08x",
-                (direction & STREAM_TOSERVER) ? "toserver":"toclient", alproto_masks[0], mask);
+        SCLogDebug("no match + midstream, retry the other direction %s",
+                (dir == STREAM_TOSERVER) ? "toserver" : "toclient");
+        goto again_midstream;
     }
 
  end:
-    if (alproto != ALPROTO_FAILED && alproto != ALPROTO_UNKNOWN &&
-        rdir == (direction & (STREAM_TOSERVER|STREAM_TOCLIENT))) {
+    if (AppProtoIsValid(alproto) && rdir != 0 && rdir != idir) {
         SCLogDebug("PP found %u, is reverse flow", alproto);
         *reverse_flow = true;
     }
 
     SCLogDebug("%s, mask is now %08x",
-            (direction & STREAM_TOSERVER) ? "toserver":"toclient", alproto_masks[0]);
+            (idir == STREAM_TOSERVER) ? "toserver":"toclient", alproto_masks[0]);
     SCReturnUInt(alproto);
 }
 
@@ -1482,8 +1501,7 @@ AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx,
     if (!FLOW_IS_PM_DONE(f, direction)) {
         AppProto pm_results[ALPROTO_MAX];
         uint16_t pm_matches = AppLayerProtoDetectPMGetProto(tctx, f,
-                buf, buflen, direction,
-                pm_results, reverse_flow);
+                buf, buflen, direction, pm_results, reverse_flow);
         if (pm_matches > 0) {
             alproto = pm_results[0];
 
@@ -1500,13 +1518,13 @@ AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx,
 
     if (!FLOW_IS_PP_DONE(f, direction)) {
         bool rflow = false;
-        alproto = AppLayerProtoDetectPPGetProto(f, buf, buflen,
-                                                ipproto, direction,
-                                                &rflow);
-        if (alproto != ALPROTO_UNKNOWN)
+        alproto = AppLayerProtoDetectPPGetProto(f, buf, buflen, ipproto,
+                direction & (STREAM_TOSERVER|STREAM_TOCLIENT), &rflow);
+        if (AppProtoIsValid(alproto)) {
+            if (rflow) {
+                *reverse_flow = true;
+            }
             goto end;
-        if (rflow) {
-            *reverse_flow = true;
         }
     }
 
@@ -1516,7 +1534,7 @@ AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx,
     }
 
  end:
-    if (alproto == ALPROTO_UNKNOWN)
+    if (!AppProtoIsValid(alproto))
         alproto = pm_alproto;
 
     SCReturnUInt(alproto);