diff --git a/src/app-layer.c b/src/app-layer.c index ac432d622a..5a891d200f 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -115,6 +115,38 @@ void AppLayerIncTxCounter(ThreadVars *tv, Flow *f, uint64_t step) } } +/* 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 + * packet in the correct direction can be tagged. + * + * For IPS things are much simpler, and we don't use the flow + * flag. We just tag the packet directly. */ +static inline void FlagPacketFlow(Packet *p, Flow *f, uint8_t dir) +{ + if (EngineModeIsIPS()) { + if (dir == STREAM_TOSERVER) { + if (p->flowflags & FLOW_PKT_TOSERVER) { + p->flags |= PKT_PROTO_DETECT_TS_DONE; + } else { + f->flags |= FLOW_PROTO_DETECT_TS_DONE; + } + } else { + if (p->flowflags & FLOW_PKT_TOCLIENT) { + p->flags |= PKT_PROTO_DETECT_TC_DONE; + } else { + f->flags |= FLOW_PROTO_DETECT_TC_DONE; + } + } + } else { + if (dir == STREAM_TOSERVER) { + f->flags |= FLOW_PROTO_DETECT_TS_DONE; + } else { + f->flags |= FLOW_PROTO_DETECT_TC_DONE; + } + } +} + /* See if we're going to have to give up: * * If we're getting a lot of data in one direction and the @@ -150,24 +182,21 @@ static void TCPProtoDetectCheckBailConditions(Flow *f, TcpSession *ssn, Packet * if (ProtoDetectDone(f, ssn, STREAM_TOSERVER) && ProtoDetectDone(f, ssn, STREAM_TOCLIENT)) { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + goto failure; } else if (FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && size_ts > 100000 && size_tc == 0) { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); + goto failure; } else if (FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && size_tc > 100000 && size_ts == 0) { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); + goto failure; /* little data in ts direction, pp done, pm not done (max * depth not reached), ts direction done, lots of data in @@ -176,10 +205,9 @@ static void TCPProtoDetectCheckBailConditions(Flow *f, TcpSession *ssn, Packet * FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && !(FLOW_IS_PM_DONE(f, STREAM_TOSERVER)) && FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && FLOW_IS_PP_DONE(f, STREAM_TOCLIENT)) { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); + goto failure; /* little data in tc direction, pp done, pm not done (max * depth not reached), tc direction done, lots of data in @@ -188,10 +216,9 @@ static void TCPProtoDetectCheckBailConditions(Flow *f, TcpSession *ssn, Packet * FLOW_IS_PP_DONE(f, STREAM_TOCLIENT) && !(FLOW_IS_PM_DONE(f, STREAM_TOCLIENT)) && FLOW_IS_PM_DONE(f, STREAM_TOSERVER) && FLOW_IS_PP_DONE(f, STREAM_TOSERVER)) { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); + goto failure; /* in case of really low TS data (e.g. 4 bytes) we can have * the PP complete, PM not complete (depth not reached) and @@ -200,11 +227,20 @@ static void TCPProtoDetectCheckBailConditions(Flow *f, TcpSession *ssn, Packet * FLOW_IS_PP_DONE(f, STREAM_TOSERVER) && !(FLOW_IS_PM_DONE(f, STREAM_TOSERVER)) && (!FLOW_IS_PM_DONE(f, STREAM_TOCLIENT) && !FLOW_IS_PP_DONE(f, STREAM_TOCLIENT))) { - DisableAppLayer(f); - ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; AppLayerDecoderEventsSetEventRaw(&p->app_layer_events, APPLAYER_PROTO_DETECTION_SKIPPED); + goto failure; } + return; + +failure: + DisableAppLayer(f); + ssn->data_first_seen_dir = APP_LAYER_DATA_ALREADY_SENT_TO_APP_LAYER; + f->alproto = f->alproto_tc = f->alproto_ts = ALPROTO_FAILED; + + FlagPacketFlow(p, f, STREAM_TOSERVER); + FlagPacketFlow(p, f, STREAM_TOCLIENT); + return; } /** \todo modifying p this way seems too hacky */ @@ -315,6 +351,10 @@ static int TCPProtoDetect(ThreadVars *tv, StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); TcpSessionSetReassemblyDepth(ssn, AppLayerParserGetStreamDepth(f->proto, *alproto)); + if (flags & STREAM_TOCLIENT) + FlagPacketFlow(p, f, STREAM_TOCLIENT); + else + FlagPacketFlow(p, f, STREAM_TOSERVER); /* account flow if we have both sides */ if (*alproto_otherdir != ALPROTO_UNKNOWN) { @@ -469,6 +509,12 @@ static int TCPProtoDetect(ThreadVars *tv, StreamTcpSetStreamFlagAppProtoDetectionCompleted(stream); TcpSessionSetReassemblyDepth(ssn, AppLayerParserGetStreamDepth(f->proto, *alproto)); + + if (flags & STREAM_TOCLIENT) + FlagPacketFlow(p, f, STREAM_TOCLIENT); + else + FlagPacketFlow(p, f, STREAM_TOSERVER); + if (r < 0) goto failure; } diff --git a/src/decode.h b/src/decode.h index f760b17acb..deebbe8cdf 100644 --- a/src/decode.h +++ b/src/decode.h @@ -1096,6 +1096,10 @@ int DecoderParseDataFromFile(char *filename, DecoderFunc Decoder); * flow engine: Packet::flow_hash will be set */ #define PKT_WANTS_FLOW (1<<22) +/** protocol detection done */ +#define PKT_PROTO_DETECT_TS_DONE (1<<23) +#define PKT_PROTO_DETECT_TC_DONE (1<<24) + /** \brief return 1 if the packet is a pseudo packet */ #define PKT_IS_PSEUDOPKT(p) ((p)->flags & PKT_PSEUDO_STREAM_END) diff --git a/src/detect-app-layer-protocol.c b/src/detect-app-layer-protocol.c index 130789b34a..4694804b57 100644 --- a/src/detect-app-layer-protocol.c +++ b/src/detect-app-layer-protocol.c @@ -33,6 +33,41 @@ static void DetectAppLayerProtocolRegisterTests(void); +static int DetectAppLayerProtocolPacketMatch(ThreadVars *tv, + DetectEngineThreadCtx *det_ctx, + Packet *p, Signature *s, const SigMatchCtx *ctx) +{ + SCEnter(); + + int r = 0; + const DetectAppLayerProtocolData *data = (const DetectAppLayerProtocolData *)ctx; + + if ((p->flags & (PKT_PROTO_DETECT_TS_DONE|PKT_PROTO_DETECT_TC_DONE)) == 0) { + SCLogNotice("packet %u: flags not set", (uint)p->pcap_cnt); + SCReturnInt(0); + } + + const Flow *f = p->flow; + if (f == NULL) { + SCLogNotice("packet %u: no flow", (uint)p->pcap_cnt); + SCReturnInt(0); + } + + if ((p->flags & PKT_PROTO_DETECT_TS_DONE) && (p->flowflags & FLOW_PKT_TOSERVER)) { + SCLogNotice("toserver packet %u: looking for %u/neg %u, got %u", (uint)p->pcap_cnt, + data->alproto, data->negated, f->alproto_ts); + r = (data->negated) ? (f->alproto_ts != data->alproto) : + (f->alproto_ts == data->alproto); + } else if ((p->flags & PKT_PROTO_DETECT_TC_DONE) && (p->flowflags & FLOW_PKT_TOCLIENT)) { + SCLogNotice("toclient packet %u: looking for %u/neg %u, got %u", (uint)p->pcap_cnt, + data->alproto, data->negated, f->alproto_tc); + r = (data->negated) ? (f->alproto_tc != data->alproto) : + (f->alproto_tc == data->alproto); + } + + SCReturnInt(r); +} + static int DetectAppLayerProtocolMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, Signature *s, SigMatch *m) @@ -40,7 +75,7 @@ static int DetectAppLayerProtocolMatch(ThreadVars *t, DetectEngineThreadCtx *det SCEnter(); int r = 0; - DetectAppLayerProtocolData *data = (DetectAppLayerProtocolData *)m->ctx; + const DetectAppLayerProtocolData *data = (const DetectAppLayerProtocolData *)m->ctx; r = (data->negated) ? (f->alproto != data->alproto) : (f->alproto == data->alproto); @@ -72,11 +107,15 @@ static DetectAppLayerProtocolData *DetectAppLayerProtocolParse(const char *arg) while (*arg != '\0' && isspace((unsigned char)*arg)) arg++; - alproto = AppLayerGetProtoByName((char *)arg); - if (alproto == ALPROTO_UNKNOWN) { - SCLogError(SC_ERR_INVALID_SIGNATURE, "app-layer-protocol " - "keyword supplied with unknown protocol \"%s\"", arg); - return NULL; + if (strcmp(arg, "failed") == 0) { + alproto = ALPROTO_FAILED; + } else { + alproto = AppLayerGetProtoByName((char *)arg); + if (alproto == ALPROTO_UNKNOWN) { + SCLogError(SC_ERR_INVALID_SIGNATURE, "app-layer-protocol " + "keyword supplied with unknown protocol \"%s\"", arg); + return NULL; + } } data = SCMalloc(sizeof(DetectAppLayerProtocolData)); @@ -116,8 +155,14 @@ static int DetectAppLayerProtocolSetup(DetectEngineCtx *de_ctx, sm->type = DETECT_AL_APP_LAYER_PROTOCOL; sm->ctx = (void *)data; - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); - s->flags |= SIG_FLAG_APPLAYER; + if (data->negated || data->alproto == ALPROTO_FAILED) { + SCLogNotice("DETECT_SM_LIST_MATCH"); + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); + } else { + SCLogNotice("DETECT_SM_LIST_AMATCH"); + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); + s->flags |= SIG_FLAG_APPLAYER; + } return 0; @@ -136,7 +181,8 @@ static void DetectAppLayerProtocolFree(void *ptr) void DetectAppLayerProtocolRegister(void) { sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].name = "app-layer-protocol"; - sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Match = NULL; + sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Match = + DetectAppLayerProtocolPacketMatch; sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].AppLayerMatch = DetectAppLayerProtocolMatch; sigmatch_table[DETECT_AL_APP_LAYER_PROTOCOL].Setup = diff --git a/src/flow.c b/src/flow.c index f33c2bc5ba..be5ea03e30 100644 --- a/src/flow.c +++ b/src/flow.c @@ -248,6 +248,11 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p) p->flowflags |= FLOW_PKT_TOSERVER_FIRST; } } + /* xfer proto detect ts flag to first packet in ts dir */ + if (f->flags & FLOW_PROTO_DETECT_TS_DONE) { + f->flags &= ~FLOW_PROTO_DETECT_TS_DONE; + p->flags |= PKT_PROTO_DETECT_TS_DONE; + } } else { f->tosrcpktcnt++; f->tosrcbytecnt += GET_PKT_LEN(p); @@ -258,6 +263,11 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p) p->flowflags |= FLOW_PKT_TOCLIENT_FIRST; } } + /* xfer proto detect tc flag to first packet in tc dir */ + if (f->flags & FLOW_PROTO_DETECT_TC_DONE) { + f->flags &= ~FLOW_PROTO_DETECT_TC_DONE; + p->flags |= PKT_PROTO_DETECT_TC_DONE; + } } if ((f->flags & (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) == (FLOW_TO_DST_SEEN|FLOW_TO_SRC_SEEN)) { diff --git a/src/flow.h b/src/flow.h index 316d9ef807..a9d7c95d13 100644 --- a/src/flow.h +++ b/src/flow.h @@ -89,6 +89,9 @@ typedef struct AppLayerParserState_ AppLayerParserState; /** flow is ipv6 */ #define FLOW_IPV6 BIT_U32(19) +#define FLOW_PROTO_DETECT_TS_DONE BIT_U32(20) +#define FLOW_PROTO_DETECT_TC_DONE BIT_U32(21) + /* File flags */