From b8d13f354b0b17fbd6fff5db5b1b81d3e10c4dea Mon Sep 17 00:00:00 2001 From: Mats Klepsland Date: Tue, 31 Jan 2017 14:34:30 +0100 Subject: [PATCH] app-layer: support changing flow alproto Support changing the application level protocol for a flow. This is needed by STARTTLS and HTTP CONNECT to switch from the original alproto to tls. This commit allows a flag to be set 'FLOW_CHANGE_PROTO', which triggers a new protocol detection on the next packet for a flow. --- src/app-layer-detect-proto.c | 18 ++++++++++++++++++ src/app-layer-detect-proto.h | 5 +++++ src/app-layer.c | 8 ++++++++ src/flow.c | 32 ++++++++++++++++++++++++++++++++ src/flow.h | 9 +++++++++ 5 files changed, 72 insertions(+) diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c index 9a2460bce6..209c266e56 100644 --- a/src/app-layer-detect-proto.c +++ b/src/app-layer-detect-proto.c @@ -1614,6 +1614,24 @@ void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_n SCReturn; } +void AppLayerProtoDetectReset(Flow *f) +{ + FlowUnsetChangeProtoFlag(f); + FLOW_RESET_PM_DONE(f, STREAM_TOSERVER); + FLOW_RESET_PM_DONE(f, STREAM_TOCLIENT); + FLOW_RESET_PP_DONE(f, STREAM_TOSERVER); + FLOW_RESET_PP_DONE(f, STREAM_TOCLIENT); + f->probing_parser_toserver_alproto_masks = 0; + f->probing_parser_toclient_alproto_masks = 0; + + AppLayerParserStateCleanup(f->proto, f->alproto, f->alstate, f->alparser); + f->alstate = NULL; + f->alparser = NULL; + f->alproto = ALPROTO_UNKNOWN; + f->alproto_ts = ALPROTO_UNKNOWN; + f->alproto_tc = ALPROTO_UNKNOWN; +} + int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto) { diff --git a/src/app-layer-detect-proto.h b/src/app-layer-detect-proto.h index f9a02236ec..6b68fe4c3b 100644 --- a/src/app-layer-detect-proto.h +++ b/src/app-layer-detect-proto.h @@ -106,6 +106,11 @@ int AppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, */ int AppLayerProtoDetectSetup(void); +/** + * \brief Reset proto detect for flow + */ +void AppLayerProtoDetectReset(Flow *); + /** * \brief Cleans up the app layer protocol detection phase. */ diff --git a/src/app-layer.c b/src/app-layer.c index 737b1861c9..73d74167c2 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -562,6 +562,14 @@ int AppLayerHandleTCPData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, data, data_len, flags) != 0) { goto failure; } + } else if (alproto != ALPROTO_UNKNOWN && FlowChangeProto(f)) { + f->alproto_orig = f->alproto; + AppLayerProtoDetectReset(f); + /* rerun protocol detection */ + if (TCPProtoDetect(tv, ra_ctx, app_tctx, p, f, ssn, stream, + data, data_len, flags) != 0) { + goto failure; + } } else { SCLogDebug("stream data (len %" PRIu32 " alproto " "%"PRIu16" (flow %p)", data_len, f->alproto, f); diff --git a/src/flow.c b/src/flow.c index 589f733ee9..50075d975f 100644 --- a/src/flow.c +++ b/src/flow.c @@ -181,6 +181,38 @@ int FlowHasAlerts(const Flow *f) return 0; } +/** \brief Set flag to indicate to change proto for the flow + * + * \param f flow + */ +void FlowSetChangeProtoFlag(Flow *f) +{ + f->flags |= FLOW_CHANGE_PROTO; +} + +/** \brief Unset flag to indicate to change proto for the flow + * + * \param f flow + */ +void FlowUnsetChangeProtoFlag(Flow *f) +{ + f->flags &= ~FLOW_CHANGE_PROTO; +} + +/** \brief Check if change proto flag is set for flow + * \param f flow + * \retval 1 change proto flag is set + * \retval 0 change proto flag is not set + */ +int FlowChangeProto(Flow *f) +{ + if (f->flags & FLOW_CHANGE_PROTO) { + return 1; + } + + return 0; +} + /** * \brief determine the direction of the packet compared to the flow * \retval 0 to_server diff --git a/src/flow.h b/src/flow.h index a490a82427..5224defd68 100644 --- a/src/flow.h +++ b/src/flow.h @@ -93,6 +93,8 @@ typedef struct AppLayerParserState_ AppLayerParserState; #define FLOW_PROTO_DETECT_TS_DONE BIT_U32(20) #define FLOW_PROTO_DETECT_TC_DONE BIT_U32(21) +/** Indicate that alproto detection for flow should be done again */ +#define FLOW_CHANGE_PROTO BIT_U32(22) /* File flags */ @@ -384,6 +386,10 @@ typedef struct Flow_ AppProto alproto_ts; AppProto alproto_tc; + /** original application level protocol. Used to indicate the previous + protocol when changing to another protocol , e.g. with STARTTLS. */ + AppProto alproto_orig; + /** detection engine ctx version used to inspect this flow. Set at initial * inspection. If it doesn't match the currently in use de_ctx, the * stored sgh ptrs are reset. */ @@ -455,6 +461,9 @@ void FlowShutdown(void); void FlowSetIPOnlyFlag(Flow *, int); void FlowSetHasAlertsFlag(Flow *); int FlowHasAlerts(const Flow *); +void FlowSetChangeProtoFlag(Flow *); +void FlowUnsetChangeProtoFlag(Flow *); +int FlowChangeProto(Flow *); void FlowRegisterTests (void); int FlowSetProtoTimeout(uint8_t ,uint32_t ,uint32_t ,uint32_t); -- 2.47.2