From 3051f7f23f245fc2029a7c61df89bb8d12f9a2ae Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Wed, 17 Jul 2019 15:21:13 +0200 Subject: [PATCH] protodetect: use both directions over UDP As is already done for TCP Ticket: #2757 --- src/app-layer.c | 77 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 18 deletions(-) diff --git a/src/app-layer.c b/src/app-layer.c index eb4ce8aca4..87a2d12d5e 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -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