]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
protodetect: use both directions over UDP
authorPhilippe Antoine <contact@catenacyber.fr>
Wed, 17 Jul 2019 13:21:13 +0000 (15:21 +0200)
committerVictor Julien <vjulien@oisf.net>
Tue, 17 May 2022 08:41:24 +0000 (10:41 +0200)
As is already done for TCP

Ticket: #2757

src/app-layer.c

index eb4ce8aca40eb14868034a4d754d4227a00ecf3f..87a2d12d5e2f24c8b2aa6687f592e92e2439b045 100644 (file)
@@ -685,8 +685,9 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
 
     /* if we don't know the proto yet and we have received a stream
      * initializer message, we run proto detection.
-     * We receive 2 stream init msgs (one for each direction) but we
-     * only run the proto detection once. */
+     * We receive 2 stream init msgs (one for each direction), we
+     * only run the proto detection for both and emit an event
+     * in the case protocols mismatch. */
     if (alproto == ALPROTO_UNKNOWN && (flags & STREAM_START)) {
         DEBUG_VALIDATE_BUG_ON(FlowChangeProto(f));
         /* run protocol detection */
@@ -785,8 +786,10 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
 int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow *f)
 {
     SCEnter();
+    AppProto *alproto;
+    AppProto *alproto_otherdir;
 
-    if (f->alproto == ALPROTO_FAILED) {
+    if (f->alproto_ts == ALPROTO_FAILED && f->alproto_tc == ALPROTO_FAILED) {
         SCReturnInt(0);
     }
 
@@ -794,33 +797,75 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow *
     uint8_t flags = 0;
     if (p->flowflags & FLOW_PKT_TOSERVER) {
         flags |= STREAM_TOSERVER;
+        alproto = &f->alproto_ts;
+        alproto_otherdir = &f->alproto_tc;
     } else {
         flags |= STREAM_TOCLIENT;
+        alproto = &f->alproto_tc;
+        alproto_otherdir = &f->alproto_ts;
     }
 
     AppLayerProfilingReset(tctx);
 
     /* if the protocol is still unknown, run detection */
-    if (f->alproto == ALPROTO_UNKNOWN) {
+    if (*alproto == ALPROTO_UNKNOWN) {
         SCLogDebug("Detecting AL proto on udp mesg (len %" PRIu32 ")",
                    p->payload_len);
 
         bool reverse_flow = false;
         PACKET_PROFILING_APP_PD_START(tctx);
-        f->alproto = AppLayerProtoDetectGetProto(tctx->alpd_tctx,
-                                  f, p->payload, p->payload_len,
-                                  IPPROTO_UDP, flags, &reverse_flow);
+        *alproto = AppLayerProtoDetectGetProto(
+                tctx->alpd_tctx, f, p->payload, p->payload_len, IPPROTO_UDP, flags, &reverse_flow);
         PACKET_PROFILING_APP_PD_END(tctx);
 
-        if (f->alproto != ALPROTO_UNKNOWN) {
-            AppLayerIncFlowCounter(tv, f);
-
-            if (p->flowflags & FLOW_PKT_TOSERVER) {
-                f->alproto_ts = f->alproto;
-            } else {
-                f->alproto_tc = f->alproto;
+        switch (*alproto) {
+            case ALPROTO_UNKNOWN:
+                if (*alproto_otherdir != ALPROTO_UNKNOWN) {
+                    // Use recognized side
+                    f->alproto = *alproto_otherdir;
+                    // do not keep ALPROTO_UNKNOWN for this side so as not to loop
+                    *alproto = *alproto_otherdir;
+                    if (*alproto_otherdir == ALPROTO_FAILED) {
+                        SCLogDebug("ALPROTO_UNKNOWN flow %p", f);
+                    }
+                } else {
+                    // First side of protocol is unknown
+                    *alproto = ALPROTO_FAILED;
+                }
+                break;
+            case ALPROTO_FAILED:
+                if (*alproto_otherdir != ALPROTO_UNKNOWN) {
+                    // Use recognized side
+                    f->alproto = *alproto_otherdir;
+                    if (*alproto_otherdir == ALPROTO_FAILED) {
+                        SCLogDebug("ALPROTO_UNKNOWN flow %p", f);
+                    }
+                }
+                // else wait for second side of protocol
+                break;
+            default:
+                if (*alproto_otherdir != ALPROTO_UNKNOWN && *alproto_otherdir != ALPROTO_FAILED) {
+                    if (*alproto_otherdir != *alproto) {
+                        AppLayerDecoderEventsSetEventRaw(
+                                &p->app_layer_events, APPLAYER_MISMATCH_PROTOCOL_BOTH_DIRECTIONS);
+                        // data already sent to parser, we cannot change the protocol to use the one
+                        // of the server
+                    }
+                } else {
+                    f->alproto = *alproto;
+                }
+        }
+        if (*alproto_otherdir == ALPROTO_UNKNOWN) {
+            if (f->alproto == ALPROTO_UNKNOWN) {
+                // so as to increase stat about .app_layer.flow.failed_udp
+                f->alproto = ALPROTO_FAILED;
             }
+            // If the other side is unknown, this is the first packet of the flow
+            AppLayerIncFlowCounter(tv, f);
+        }
 
+        // parse the data if we recognized one protocol
+        if (f->alproto != ALPROTO_UNKNOWN && f->alproto != ALPROTO_FAILED) {
             if (reverse_flow) {
                 SCLogDebug("reversing flow after proto detect told us so");
                 PacketSwap(p);
@@ -832,10 +877,6 @@ int AppLayerHandleUdp(ThreadVars *tv, AppLayerThreadCtx *tctx, Packet *p, Flow *
             r = AppLayerParserParse(tv, tctx->alp_tctx, f, f->alproto,
                                     flags, p->payload, p->payload_len);
             PACKET_PROFILING_APP_END(tctx, f->alproto);
-        } else {
-            f->alproto = ALPROTO_FAILED;
-            AppLayerIncFlowCounter(tv, f);
-            SCLogDebug("ALPROTO_UNKNOWN flow %p", f);
         }
         PACKET_PROFILING_APP_STORE(tctx, p);
         /* we do only inspection in one direction, so flag both