summaryrefslogtreecommitdiffstats
path: root/src/app-layer-detect-proto.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/app-layer-detect-proto.c')
-rw-r--r--src/app-layer-detect-proto.c3688
1 files changed, 3688 insertions, 0 deletions
diff --git a/src/app-layer-detect-proto.c b/src/app-layer-detect-proto.c
new file mode 100644
index 0000000..c7f902e
--- /dev/null
+++ b/src/app-layer-detect-proto.c
@@ -0,0 +1,3688 @@
+/* Copyright (C) 2007-2022 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Victor Julien <victor@inliniac.net>
+ * \author Anoop Saldanha <anoopsaldanha@gmail.com>
+ */
+
+#include "suricata-common.h"
+#include "decode.h"
+#include "threads.h"
+#include "threadvars.h"
+#include "tm-threads.h"
+
+#include "detect.h"
+#include "detect-engine-port.h"
+#include "detect-engine-build.h"
+#include "detect-parse.h"
+#include "detect-engine.h"
+#include "detect-content.h"
+#include "detect-engine-mpm.h"
+#include "detect-engine-state.h"
+
+#include "util-print.h"
+#include "util-pool.h"
+#include "util-unittest.h"
+#include "util-unittest-helper.h"
+#include "util-validate.h"
+
+#include "flow.h"
+#include "flow-util.h"
+#include "flow-private.h"
+
+#include "stream-tcp-private.h"
+#include "stream-tcp-reassemble.h"
+#include "stream-tcp.h"
+#include "stream.h"
+
+#include "app-layer.h"
+#include "app-layer-protos.h"
+#include "app-layer-parser.h"
+#include "app-layer-detect-proto.h"
+#include "app-layer-expectation.h"
+
+#include "conf.h"
+#include "util-memcmp.h"
+#include "util-spm.h"
+#include "util-debug.h"
+
+#include "runmodes.h"
+
+typedef struct AppLayerProtoDetectProbingParserElement_ {
+ AppProto alproto;
+ /* \todo don't really need it. See if you can get rid of it */
+ uint16_t port;
+ /* \todo calculate at runtime and get rid of this var */
+ uint32_t alproto_mask;
+ /* the min length of data that has to be supplied to invoke the parser */
+ uint16_t min_depth;
+ /* the max length of data after which this parser won't be invoked */
+ uint16_t max_depth;
+
+ /* the to_server probing parser function */
+ ProbingParserFPtr ProbingParserTs;
+
+ /* the to_client probing parser function */
+ ProbingParserFPtr ProbingParserTc;
+
+ struct AppLayerProtoDetectProbingParserElement_ *next;
+} AppLayerProtoDetectProbingParserElement;
+
+typedef struct AppLayerProtoDetectProbingParserPort_ {
+ /* the port no for which probing parser(s) are invoked */
+ uint16_t port;
+
+ uint32_t alproto_mask;
+
+ /* the max depth for all the probing parsers registered for this port */
+ uint16_t dp_max_depth;
+ uint16_t sp_max_depth;
+
+ AppLayerProtoDetectProbingParserElement *dp;
+ AppLayerProtoDetectProbingParserElement *sp;
+
+ struct AppLayerProtoDetectProbingParserPort_ *next;
+} AppLayerProtoDetectProbingParserPort;
+
+typedef struct AppLayerProtoDetectProbingParser_ {
+ uint8_t ipproto;
+ AppLayerProtoDetectProbingParserPort *port;
+
+ struct AppLayerProtoDetectProbingParser_ *next;
+} AppLayerProtoDetectProbingParser;
+
+typedef struct AppLayerProtoDetectPMSignature_ {
+ AppProto alproto;
+ uint8_t direction; /**< direction for midstream */
+ SigIntId id;
+ /* \todo Change this into a non-pointer */
+ DetectContentData *cd;
+ uint16_t pp_min_depth;
+ uint16_t pp_max_depth;
+ ProbingParserFPtr PPFunc;
+ struct AppLayerProtoDetectPMSignature_ *next;
+} AppLayerProtoDetectPMSignature;
+
+typedef struct AppLayerProtoDetectPMCtx_ {
+ uint16_t pp_max_len;
+ uint16_t min_len;
+ MpmCtx mpm_ctx;
+
+ /** Mapping between pattern id and signature. As each signature has a
+ * unique pattern with a unique id, we can lookup the signature by
+ * the pattern id. */
+ AppLayerProtoDetectPMSignature **map;
+ AppLayerProtoDetectPMSignature *head;
+
+ /* \todo we don't need this except at setup time. Get rid of it. */
+ PatIntId max_pat_id;
+ SigIntId max_sig_id;
+} AppLayerProtoDetectPMCtx;
+
+typedef struct AppLayerProtoDetectCtxIpproto_ {
+ /* 0 - toserver, 1 - toclient */
+ AppLayerProtoDetectPMCtx ctx_pm[2];
+} AppLayerProtoDetectCtxIpproto;
+
+/**
+ * \brief The app layer protocol detection context.
+ */
+typedef struct AppLayerProtoDetectCtx_ {
+ /* Context per ip_proto.
+ * \todo Modify ctx_ipp to hold for only tcp and udp. The rest can be
+ * implemented if needed. Waste of space otherwise. */
+ AppLayerProtoDetectCtxIpproto ctx_ipp[FLOW_PROTO_DEFAULT];
+
+ /* Global SPM thread context prototype. */
+ SpmGlobalThreadCtx *spm_global_thread_ctx;
+
+ AppLayerProtoDetectProbingParser *ctx_pp;
+
+ /* Indicates the protocols that have registered themselves
+ * for protocol detection. This table is independent of the
+ * ipproto. */
+ const char *alproto_names[ALPROTO_MAX];
+} AppLayerProtoDetectCtx;
+
+typedef struct AppLayerProtoDetectAliases_ {
+ const char *proto_name;
+ const char *proto_alias;
+ struct AppLayerProtoDetectAliases_ *next;
+} AppLayerProtoDetectAliases;
+
+/**
+ * \brief The app layer protocol detection thread context.
+ */
+struct AppLayerProtoDetectThreadCtx_ {
+ PrefilterRuleStore pmq;
+ /* The value 2 is for direction(0 - toserver, 1 - toclient). */
+ MpmThreadCtx mpm_tctx[FLOW_PROTO_DEFAULT][2];
+ SpmThreadCtx *spm_thread_ctx;
+};
+
+/* The global app layer proto detection context. */
+static AppLayerProtoDetectCtx alpd_ctx;
+static AppLayerProtoDetectAliases *alpda_ctx = NULL;
+
+static void AppLayerProtoDetectPEGetIpprotos(AppProto alproto,
+ uint8_t *ipprotos);
+
+/***** Static Internal Calls: Protocol Retrieval *****/
+
+/** \internal
+ * \brief Handle SPM search for Signature
+ * \param buflen full size of the input buffer
+ * \param searchlen pattern matching portion of buffer */
+static AppProto AppLayerProtoDetectPMMatchSignature(const AppLayerProtoDetectPMSignature *s,
+ AppLayerProtoDetectThreadCtx *tctx, Flow *f, uint8_t flags, const uint8_t *buf,
+ uint32_t buflen, uint16_t searchlen, bool *rflow)
+{
+ SCEnter();
+
+ if (s->cd->offset > searchlen) {
+ SCLogDebug("s->co->offset (%"PRIu16") > searchlen (%"PRIu16")",
+ s->cd->offset, searchlen);
+ SCReturnUInt(ALPROTO_UNKNOWN);
+ }
+ if (s->cd->depth > searchlen) {
+ SCLogDebug("s->co->depth (%"PRIu16") > searchlen (%"PRIu16")",
+ s->cd->depth, searchlen);
+ SCReturnUInt(ALPROTO_UNKNOWN);
+ }
+
+ const uint8_t *sbuf = buf + s->cd->offset;
+ uint16_t ssearchlen = s->cd->depth - s->cd->offset;
+ SCLogDebug("s->co->offset (%"PRIu16") s->cd->depth (%"PRIu16")",
+ s->cd->offset, s->cd->depth);
+
+ uint8_t *found = SpmScan(s->cd->spm_ctx, tctx->spm_thread_ctx,
+ sbuf, ssearchlen);
+ if (found == NULL) {
+ SCReturnUInt(ALPROTO_UNKNOWN);
+ }
+
+ uint8_t direction = (flags & (STREAM_TOSERVER | STREAM_TOCLIENT));
+ SCLogDebug("matching, s->direction %s, our dir %s",
+ (s->direction & STREAM_TOSERVER) ? "toserver" : "toclient",
+ (flags & STREAM_TOSERVER) ? "toserver" : "toclient");
+ if (s->PPFunc == NULL) {
+ if (direction == s->direction) {
+ SCLogDebug("direction is correct");
+ } else {
+ SCLogDebug("direction is wrong, rflow = true");
+ *rflow = true;
+ }
+ /* validate using Probing Parser */
+ } else {
+ if (s->pp_min_depth > buflen) {
+ SCLogDebug("PP can't be run yet as pp_min_depth %u > buflen %u",
+ s->pp_min_depth, buflen);
+ SCReturnInt(ALPROTO_UNKNOWN);
+ }
+
+ uint8_t rdir = 0;
+ AppProto r = s->PPFunc(f, flags, buf, buflen, &rdir);
+ if (r == s->alproto) {
+ SCLogDebug("found %s/%u, rdir %02x reverse_flow? %s",
+ AppProtoToString(r), r, rdir,
+ (rdir && direction != rdir) ? "true" : "false");
+ *rflow = (rdir && direction != rdir);
+ SCReturnUInt(s->alproto);
+ } else if (r == ALPROTO_FAILED) {
+ SCReturnUInt(ALPROTO_FAILED);
+ } else {
+ /* unknown: lets see if we will try again later */
+ if (s->pp_max_depth < buflen) {
+ SCLogDebug("depth reached and answer inconclusive: fail");
+ SCReturnUInt(ALPROTO_FAILED);
+ }
+ SCReturnUInt(ALPROTO_UNKNOWN);
+ }
+ }
+ SCReturnUInt(s->alproto);
+}
+
+/**
+ * \retval 0 no matches
+ * \retval -1 no matches, mpm depth reached
+ */
+static inline int PMGetProtoInspect(AppLayerProtoDetectThreadCtx *tctx,
+ AppLayerProtoDetectPMCtx *pm_ctx, MpmThreadCtx *mpm_tctx, Flow *f, const uint8_t *buf,
+ uint32_t buflen, uint8_t flags, AppProto *pm_results, bool *rflow)
+{
+ int pm_matches = 0;
+
+ // maxdepth is u16, so minimum is u16
+ uint16_t searchlen = (uint16_t)MIN(buflen, pm_ctx->mpm_ctx.maxdepth);
+ SCLogDebug("searchlen %u buflen %u", searchlen, buflen);
+
+ /* do the mpm search */
+ uint32_t search_cnt = mpm_table[pm_ctx->mpm_ctx.mpm_type].Search(
+ &pm_ctx->mpm_ctx, mpm_tctx, &tctx->pmq,
+ buf, searchlen);
+ if (search_cnt == 0) {
+ if (buflen >= pm_ctx->mpm_ctx.maxdepth)
+ return -1;
+ return 0;
+ }
+
+ /* alproto bit field */
+ uint8_t pm_results_bf[(ALPROTO_MAX / 8) + 1];
+ memset(pm_results_bf, 0, sizeof(pm_results_bf));
+
+ /* loop through unique pattern id's. Can't use search_cnt here,
+ * as that contains all matches, tctx->pmq.pattern_id_array_cnt
+ * contains only *unique* matches. */
+ for (uint32_t cnt = 0; cnt < tctx->pmq.rule_id_array_cnt; cnt++) {
+ const AppLayerProtoDetectPMSignature *s = pm_ctx->map[tctx->pmq.rule_id_array[cnt]];
+ while (s != NULL) {
+ AppProto proto = AppLayerProtoDetectPMMatchSignature(
+ s, tctx, f, flags, buf, buflen, searchlen, rflow);
+
+ /* store each unique proto once */
+ if (AppProtoIsValid(proto) &&
+ !(pm_results_bf[proto / 8] & (1 << (proto % 8))) )
+ {
+ pm_results[pm_matches++] = proto;
+ pm_results_bf[proto / 8] |= 1 << (proto % 8);
+ }
+ s = s->next;
+ }
+ }
+ if (pm_matches == 0 && buflen >= pm_ctx->pp_max_len) {
+ pm_matches = -2;
+ }
+ PmqReset(&tctx->pmq);
+ return pm_matches;
+}
+
+/** \internal
+ * \brief Run Pattern Sigs against buffer
+ * \param direction direction for the patterns
+ * \param pm_results[out] AppProto array of size ALPROTO_MAX */
+static AppProto AppLayerProtoDetectPMGetProto(AppLayerProtoDetectThreadCtx *tctx, Flow *f,
+ const uint8_t *buf, uint32_t buflen, uint8_t flags, AppProto *pm_results, bool *rflow)
+{
+ SCEnter();
+
+ pm_results[0] = ALPROTO_UNKNOWN;
+
+ AppLayerProtoDetectPMCtx *pm_ctx;
+ MpmThreadCtx *mpm_tctx;
+ int m = -1;
+
+ if (f->protomap >= FLOW_PROTO_DEFAULT) {
+ pm_results[0] = ALPROTO_FAILED;
+ SCReturnUInt(1);
+ }
+
+ if (flags & STREAM_TOSERVER) {
+ pm_ctx = &alpd_ctx.ctx_ipp[f->protomap].ctx_pm[0];
+ mpm_tctx = &tctx->mpm_tctx[f->protomap][0];
+ } else {
+ pm_ctx = &alpd_ctx.ctx_ipp[f->protomap].ctx_pm[1];
+ mpm_tctx = &tctx->mpm_tctx[f->protomap][1];
+ }
+ if (likely(pm_ctx->mpm_ctx.pattern_cnt > 0)) {
+ m = PMGetProtoInspect(tctx, pm_ctx, mpm_tctx, f, buf, buflen, flags, pm_results, rflow);
+ }
+ /* pattern found, yay */
+ if (m > 0) {
+ FLOW_SET_PM_DONE(f, flags);
+ SCReturnUInt((uint16_t)m);
+
+ /* handle non-found in non-midstream case */
+ } else if (!stream_config.midstream) {
+ /* we can give up if mpm gave no results and its search depth
+ * was reached. */
+ if (m < 0) {
+ FLOW_SET_PM_DONE(f, flags);
+ SCReturnUInt(0);
+ } else if (m == 0) {
+ SCReturnUInt(0);
+ }
+ SCReturnUInt((uint16_t)m);
+
+ /* handle non-found in midstream case */
+ } else if (m <= 0) {
+ if (flags & STREAM_TOSERVER) {
+ pm_ctx = &alpd_ctx.ctx_ipp[f->protomap].ctx_pm[1];
+ mpm_tctx = &tctx->mpm_tctx[f->protomap][1];
+ } else {
+ pm_ctx = &alpd_ctx.ctx_ipp[f->protomap].ctx_pm[0];
+ mpm_tctx = &tctx->mpm_tctx[f->protomap][0];
+ }
+ SCLogDebug("no matches and in midstream mode, lets try the "
+ "*patterns for the other side");
+
+ int om = -1;
+ if (likely(pm_ctx->mpm_ctx.pattern_cnt > 0)) {
+ om = PMGetProtoInspect(
+ tctx, pm_ctx, mpm_tctx, f, buf, buflen, flags, pm_results, rflow);
+ }
+ /* found! */
+ if (om > 0) {
+ FLOW_SET_PM_DONE(f, flags);
+ SCReturnUInt((uint16_t)om);
+
+ /* both sides failed */
+ } else if (om < 0 && m && m < 0) {
+ FLOW_SET_PM_DONE(f, flags);
+ SCReturnUInt(0);
+
+ /* one side still uncertain */
+ } else if (om == 0 || m == 0) {
+ SCReturnUInt(0);
+ }
+ }
+ SCReturnUInt(0);
+}
+
+static AppLayerProtoDetectProbingParserElement *AppLayerProtoDetectGetProbingParser(
+ AppLayerProtoDetectProbingParser *pp, uint8_t ipproto, AppProto alproto)
+{
+ AppLayerProtoDetectProbingParserElement *pp_elem = NULL;
+ AppLayerProtoDetectProbingParserPort *pp_port = NULL;
+
+ while (pp != NULL) {
+ if (pp->ipproto == ipproto)
+ break;
+ pp = pp->next;
+ }
+ if (pp == NULL)
+ return NULL;
+
+ pp_port = pp->port;
+ while (pp_port != NULL) {
+ if (pp_port->dp != NULL && pp_port->dp->alproto == alproto) {
+ pp_elem = pp_port->dp;
+ break;
+ }
+ if (pp_port->sp != NULL && pp_port->sp->alproto == alproto) {
+ pp_elem = pp_port->sp;
+ break;
+ }
+ pp_port = pp_port->next;
+ }
+
+ SCReturnPtr(pp_elem, "AppLayerProtoDetectProbingParserElement *");
+}
+
+static AppLayerProtoDetectProbingParserPort *AppLayerProtoDetectGetProbingParsers(AppLayerProtoDetectProbingParser *pp,
+ uint8_t ipproto,
+ uint16_t port)
+{
+ AppLayerProtoDetectProbingParserPort *pp_port = NULL;
+
+ while (pp != NULL) {
+ if (pp->ipproto == ipproto)
+ break;
+
+ pp = pp->next;
+ }
+
+ if (pp == NULL)
+ goto end;
+
+ pp_port = pp->port;
+ while (pp_port != NULL) {
+ if (pp_port->port == port || pp_port->port == 0) {
+ break;
+ }
+ pp_port = pp_port->next;
+ }
+
+ end:
+ SCReturnPtr(pp_port, "AppLayerProtoDetectProbingParserPort *");
+}
+
+
+/**
+ * \brief Call the probing expectation to see if there is some for this flow.
+ *
+ */
+static AppProto AppLayerProtoDetectPEGetProto(Flow *f, uint8_t ipproto, uint8_t flags)
+{
+ AppProto alproto = ALPROTO_UNKNOWN;
+
+ SCLogDebug("expectation check for %p (dir %d)", f, flags);
+ FLOW_SET_PE_DONE(f, flags);
+
+ alproto = AppLayerExpectationHandle(f, flags);
+
+ return alproto;
+}
+
+static inline AppProto PPGetProto(const AppLayerProtoDetectProbingParserElement *pe, Flow *f,
+ uint8_t flags, const 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 (flags & STREAM_TOSERVER && pe->ProbingParserTs != NULL) {
+ alproto = pe->ProbingParserTs(f, flags, buf, buflen, rdir);
+ } else if (flags & STREAM_TOCLIENT && pe->ProbingParserTc != NULL) {
+ alproto = pe->ProbingParserTc(f, flags, 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.
+ *
+ * First we check the flow's dp as it's most likely to match. If that didn't
+ * lead to a PP, we try the sp.
+ *
+ */
+static AppProto AppLayerProtoDetectPPGetProto(Flow *f, const uint8_t *buf, uint32_t buflen,
+ uint8_t ipproto, const uint8_t flags, bool *reverse_flow)
+{
+ const AppLayerProtoDetectProbingParserPort *pp_port_dp = NULL;
+ const AppLayerProtoDetectProbingParserPort *pp_port_sp = NULL;
+ const AppLayerProtoDetectProbingParserElement *pe0 = NULL;
+ const AppLayerProtoDetectProbingParserElement *pe1 = NULL;
+ const AppLayerProtoDetectProbingParserElement *pe2 = NULL;
+ AppProto alproto = ALPROTO_UNKNOWN;
+ uint32_t *alproto_masks = NULL;
+ uint32_t mask = 0;
+ uint8_t idir = (flags & (STREAM_TOSERVER | STREAM_TOCLIENT));
+ uint8_t dir = idir;
+ uint16_t dp = f->protodetect_dp ? f->protodetect_dp : FLOW_GET_DP(f);
+ uint16_t sp = FLOW_GET_SP(f);
+ bool probe_is_found = false;
+
+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 (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;
+ if (pp_port_dp != NULL) {
+ SCLogDebug("toserver - Probing parser found for destination port %"PRIu16, dp);
+
+ /* found based on destination port, so use dp registration */
+ pe1 = pp_port_dp->dp;
+ } else {
+ SCLogDebug("toserver - No probing parser registered for dest port %"PRIu16, dp);
+ }
+
+ pp_port_sp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, sp);
+ if (pp_port_sp != NULL) {
+ SCLogDebug("toserver - Probing parser found for source port %"PRIu16, sp);
+
+ /* found based on source port, so use sp registration */
+ pe2 = pp_port_sp->sp;
+ } else {
+ SCLogDebug("toserver - No probing parser registered for source port %"PRIu16, sp);
+ }
+ } else {
+ /* first try the destination port */
+ pp_port_dp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, dp);
+ if (dir == idir) {
+ // do not update alproto_masks to let a chance to second packet
+ // for instance when sending a junk packet to a DNS server
+ alproto_masks = &f->probing_parser_toclient_alproto_masks;
+ }
+ if (pp_port_dp != NULL) {
+ SCLogDebug("toclient - Probing parser found for destination port %"PRIu16, dp);
+
+ /* found based on destination port, so use dp registration */
+ pe1 = pp_port_dp->dp;
+ } else {
+ SCLogDebug("toclient - No probing parser registered for dest port %"PRIu16, dp);
+ }
+
+ pp_port_sp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, sp);
+ if (pp_port_sp != NULL) {
+ SCLogDebug("toclient - Probing parser found for source port %"PRIu16, sp);
+
+ pe2 = pp_port_sp->sp;
+ } else {
+ SCLogDebug("toclient - No probing parser registered for source port %"PRIu16, sp);
+ }
+ }
+
+ if (dir == STREAM_TOSERVER && f->alproto_tc != ALPROTO_UNKNOWN) {
+ pe0 = AppLayerProtoDetectGetProbingParser(alpd_ctx.ctx_pp, ipproto, f->alproto_tc);
+ } else if (dir == STREAM_TOCLIENT && f->alproto_ts != ALPROTO_UNKNOWN) {
+ pe0 = AppLayerProtoDetectGetProbingParser(alpd_ctx.ctx_pp, ipproto, f->alproto_ts);
+ }
+
+ if (pe1 == NULL && pe2 == NULL && pe0 == NULL) {
+ SCLogDebug("%s - No probing parsers found for either port",
+ (dir == STREAM_TOSERVER) ? "toserver":"toclient");
+ goto noparsers;
+ } else {
+ probe_is_found = true;
+ }
+
+ /* run the parser(s): always call with original direction */
+ uint8_t rdir = 0;
+ alproto = PPGetProto(pe0, f, flags, buf, buflen, alproto_masks, &rdir);
+ if (AppProtoIsValid(alproto))
+ goto end;
+ alproto = PPGetProto(pe1, f, flags, buf, buflen, alproto_masks, &rdir);
+ if (AppProtoIsValid(alproto))
+ goto end;
+ alproto = PPGetProto(pe2, f, flags, buf, buflen, alproto_masks, &rdir);
+ if (AppProtoIsValid(alproto))
+ goto end;
+
+ /* 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);
+ }
+ }
+
+noparsers:
+ if (stream_config.midstream && idir == dir) {
+ if (idir == STREAM_TOSERVER) {
+ dir = STREAM_TOCLIENT;
+ } else {
+ dir = STREAM_TOSERVER;
+ }
+ SCLogDebug("no match + midstream, retry the other direction %s",
+ (dir == STREAM_TOSERVER) ? "toserver" : "toclient");
+ goto again_midstream;
+ } else if (!probe_is_found) {
+ FLOW_SET_PP_DONE(f, idir);
+ }
+
+ end:
+ if (AppProtoIsValid(alproto) && rdir != 0 && rdir != idir) {
+ SCLogDebug("PP found %u, is reverse flow", alproto);
+ *reverse_flow = true;
+ }
+
+ SCLogDebug("%s, mask is now %08x",
+ (idir == STREAM_TOSERVER) ? "toserver":"toclient", alproto_masks[0]);
+ SCReturnUInt(alproto);
+}
+
+/***** Static Internal Calls: PP registration *****/
+
+static void AppLayerProtoDetectPPGetIpprotos(AppProto alproto,
+ uint8_t *ipprotos)
+{
+ SCEnter();
+
+ const AppLayerProtoDetectProbingParser *pp;
+ const AppLayerProtoDetectProbingParserPort *pp_port;
+ const AppLayerProtoDetectProbingParserElement *pp_pe;
+
+ for (pp = alpd_ctx.ctx_pp; pp != NULL; pp = pp->next) {
+ for (pp_port = pp->port; pp_port != NULL; pp_port = pp_port->next) {
+ for (pp_pe = pp_port->dp; pp_pe != NULL; pp_pe = pp_pe->next) {
+ if (alproto == pp_pe->alproto)
+ ipprotos[pp->ipproto / 8] |= 1 << (pp->ipproto % 8);
+ }
+ for (pp_pe = pp_port->sp; pp_pe != NULL; pp_pe = pp_pe->next) {
+ if (alproto == pp_pe->alproto)
+ ipprotos[pp->ipproto / 8] |= 1 << (pp->ipproto % 8);
+ }
+ }
+ }
+
+ SCReturn;
+}
+
+static uint32_t AppLayerProtoDetectProbingParserGetMask(AppProto alproto)
+{
+ SCEnter();
+
+ if (!(alproto > ALPROTO_UNKNOWN && alproto < ALPROTO_FAILED)) {
+ FatalError("Unknown protocol detected - %u", alproto);
+ }
+
+ SCReturnUInt(1UL << (uint32_t)alproto);
+}
+
+static AppLayerProtoDetectProbingParserElement *AppLayerProtoDetectProbingParserElementAlloc(void)
+{
+ SCEnter();
+
+ AppLayerProtoDetectProbingParserElement *p = SCMalloc(sizeof(AppLayerProtoDetectProbingParserElement));
+ if (unlikely(p == NULL)) {
+ exit(EXIT_FAILURE);
+ }
+ memset(p, 0, sizeof(AppLayerProtoDetectProbingParserElement));
+
+ SCReturnPtr(p, "AppLayerProtoDetectProbingParserElement");
+}
+
+
+static void AppLayerProtoDetectProbingParserElementFree(AppLayerProtoDetectProbingParserElement *p)
+{
+ SCEnter();
+ SCFree(p);
+ SCReturn;
+}
+
+static AppLayerProtoDetectProbingParserPort *AppLayerProtoDetectProbingParserPortAlloc(void)
+{
+ SCEnter();
+
+ AppLayerProtoDetectProbingParserPort *p = SCMalloc(sizeof(AppLayerProtoDetectProbingParserPort));
+ if (unlikely(p == NULL)) {
+ exit(EXIT_FAILURE);
+ }
+ memset(p, 0, sizeof(AppLayerProtoDetectProbingParserPort));
+
+ SCReturnPtr(p, "AppLayerProtoDetectProbingParserPort");
+}
+
+static void AppLayerProtoDetectProbingParserPortFree(AppLayerProtoDetectProbingParserPort *p)
+{
+ SCEnter();
+
+ AppLayerProtoDetectProbingParserElement *e;
+
+ e = p->dp;
+ while (e != NULL) {
+ AppLayerProtoDetectProbingParserElement *e_next = e->next;
+ AppLayerProtoDetectProbingParserElementFree(e);
+ e = e_next;
+ }
+
+ e = p->sp;
+ while (e != NULL) {
+ AppLayerProtoDetectProbingParserElement *e_next = e->next;
+ AppLayerProtoDetectProbingParserElementFree(e);
+ e = e_next;
+ }
+
+ SCFree(p);
+
+ SCReturn;
+}
+
+static AppLayerProtoDetectProbingParser *AppLayerProtoDetectProbingParserAlloc(void)
+{
+ SCEnter();
+
+ AppLayerProtoDetectProbingParser *p = SCMalloc(sizeof(AppLayerProtoDetectProbingParser));
+ if (unlikely(p == NULL)) {
+ exit(EXIT_FAILURE);
+ }
+ memset(p, 0, sizeof(AppLayerProtoDetectProbingParser));
+
+ SCReturnPtr(p, "AppLayerProtoDetectProbingParser");
+}
+
+static void AppLayerProtoDetectProbingParserFree(AppLayerProtoDetectProbingParser *p)
+{
+ SCEnter();
+
+ AppLayerProtoDetectProbingParserPort *pt = p->port;
+ while (pt != NULL) {
+ AppLayerProtoDetectProbingParserPort *pt_next = pt->next;
+ AppLayerProtoDetectProbingParserPortFree(pt);
+ pt = pt_next;
+ }
+
+ SCFree(p);
+
+ SCReturn;
+}
+
+static AppLayerProtoDetectProbingParserElement *
+AppLayerProtoDetectProbingParserElementCreate(AppProto alproto,
+ uint16_t port,
+ uint16_t min_depth,
+ uint16_t max_depth)
+{
+ AppLayerProtoDetectProbingParserElement *pe = AppLayerProtoDetectProbingParserElementAlloc();
+
+ pe->alproto = alproto;
+ pe->port = port;
+ pe->alproto_mask = AppLayerProtoDetectProbingParserGetMask(alproto);
+ pe->min_depth = min_depth;
+ pe->max_depth = max_depth;
+ pe->next = NULL;
+
+ if (max_depth != 0 && min_depth >= max_depth) {
+ SCLogError("Invalid arguments sent to "
+ "register the probing parser. min_depth >= max_depth");
+ goto error;
+ }
+ if (alproto <= ALPROTO_UNKNOWN || alproto >= ALPROTO_MAX) {
+ SCLogError("Invalid arguments sent to register "
+ "the probing parser. Invalid alproto - %d",
+ alproto);
+ goto error;
+ }
+
+ SCReturnPtr(pe, "AppLayerProtoDetectProbingParserElement");
+ error:
+ AppLayerProtoDetectProbingParserElementFree(pe);
+ SCReturnPtr(NULL, "AppLayerProtoDetectProbingParserElement");
+}
+
+static AppLayerProtoDetectProbingParserElement *
+AppLayerProtoDetectProbingParserElementDuplicate(AppLayerProtoDetectProbingParserElement *pe)
+{
+ SCEnter();
+
+ AppLayerProtoDetectProbingParserElement *new_pe = AppLayerProtoDetectProbingParserElementAlloc();
+
+ new_pe->alproto = pe->alproto;
+ new_pe->port = pe->port;
+ new_pe->alproto_mask = pe->alproto_mask;
+ new_pe->min_depth = pe->min_depth;
+ new_pe->max_depth = pe->max_depth;
+ new_pe->ProbingParserTs = pe->ProbingParserTs;
+ new_pe->ProbingParserTc = pe->ProbingParserTc;
+ new_pe->next = NULL;
+
+ SCReturnPtr(new_pe, "AppLayerProtoDetectProbingParserElement");
+}
+
+#ifdef DEBUG
+static void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingParser *pp)
+{
+ SCEnter();
+
+ AppLayerProtoDetectProbingParserPort *pp_port = NULL;
+ AppLayerProtoDetectProbingParserElement *pp_pe = NULL;
+
+ printf("\nProtocol Detection Configuration\n");
+
+ for ( ; pp != NULL; pp = pp->next) {
+ /* print ip protocol */
+ if (pp->ipproto == IPPROTO_TCP)
+ printf("IPProto: TCP\n");
+ else if (pp->ipproto == IPPROTO_UDP)
+ printf("IPProto: UDP\n");
+ else
+ printf("IPProto: %"PRIu8"\n", pp->ipproto);
+
+ pp_port = pp->port;
+ for ( ; pp_port != NULL; pp_port = pp_port->next) {
+ if (pp_port->dp != NULL) {
+ printf(" Port: %"PRIu16 "\n", pp_port->port);
+
+ printf(" Destination port: (max-depth: %"PRIu16 ", "
+ "mask - %"PRIu32")\n",
+ pp_port->dp_max_depth,
+ pp_port->alproto_mask);
+ pp_pe = pp_port->dp;
+ for ( ; pp_pe != NULL; pp_pe = pp_pe->next) {
+
+ printf(" alproto: %s\n", AppProtoToString(pp_pe->alproto));
+ printf(" port: %"PRIu16 "\n", pp_pe->port);
+ printf(" mask: %"PRIu32 "\n", pp_pe->alproto_mask);
+ printf(" min_depth: %"PRIu32 "\n", pp_pe->min_depth);
+ printf(" max_depth: %"PRIu32 "\n", pp_pe->max_depth);
+
+ printf("\n");
+ }
+ }
+
+ if (pp_port->sp == NULL) {
+ continue;
+ }
+
+ printf(" Source port: (max-depth: %"PRIu16 ", "
+ "mask - %"PRIu32")\n",
+ pp_port->sp_max_depth,
+ pp_port->alproto_mask);
+ pp_pe = pp_port->sp;
+ for ( ; pp_pe != NULL; pp_pe = pp_pe->next) {
+
+ printf(" alproto: %s\n", AppProtoToString(pp_pe->alproto));
+ printf(" port: %"PRIu16 "\n", pp_pe->port);
+ printf(" mask: %"PRIu32 "\n", pp_pe->alproto_mask);
+ printf(" min_depth: %"PRIu32 "\n", pp_pe->min_depth);
+ printf(" max_depth: %"PRIu32 "\n", pp_pe->max_depth);
+
+ printf("\n");
+ }
+ }
+ }
+
+ SCReturn;
+}
+#endif
+
+static void AppLayerProtoDetectProbingParserElementAppend(AppLayerProtoDetectProbingParserElement **head_pe,
+ AppLayerProtoDetectProbingParserElement *new_pe)
+{
+ SCEnter();
+
+ if (*head_pe == NULL) {
+ *head_pe = new_pe;
+ goto end;
+ }
+
+ if ((*head_pe)->port == 0) {
+ if (new_pe->port != 0) {
+ new_pe->next = *head_pe;
+ *head_pe = new_pe;
+ } else {
+ AppLayerProtoDetectProbingParserElement *temp_pe = *head_pe;
+ while (temp_pe->next != NULL)
+ temp_pe = temp_pe->next;
+ temp_pe->next = new_pe;
+ }
+ } else {
+ AppLayerProtoDetectProbingParserElement *temp_pe = *head_pe;
+ if (new_pe->port == 0) {
+ while (temp_pe->next != NULL)
+ temp_pe = temp_pe->next;
+ temp_pe->next = new_pe;
+ } else {
+ while (temp_pe->next != NULL && temp_pe->next->port != 0)
+ temp_pe = temp_pe->next;
+ new_pe->next = temp_pe->next;
+ temp_pe->next = new_pe;
+
+ }
+ }
+
+ end:
+ SCReturn;
+}
+
+static void AppLayerProtoDetectProbingParserAppend(AppLayerProtoDetectProbingParser **head_pp,
+ AppLayerProtoDetectProbingParser *new_pp)
+{
+ SCEnter();
+
+ if (*head_pp == NULL) {
+ *head_pp = new_pp;
+ goto end;
+ }
+
+ AppLayerProtoDetectProbingParser *temp_pp = *head_pp;
+ while (temp_pp->next != NULL)
+ temp_pp = temp_pp->next;
+ temp_pp->next = new_pp;
+
+ end:
+ SCReturn;
+}
+
+static void AppLayerProtoDetectProbingParserPortAppend(AppLayerProtoDetectProbingParserPort **head_port,
+ AppLayerProtoDetectProbingParserPort *new_port)
+{
+ SCEnter();
+
+ if (*head_port == NULL) {
+ *head_port = new_port;
+ goto end;
+ }
+
+ if ((*head_port)->port == 0) {
+ new_port->next = *head_port;
+ *head_port = new_port;
+ } else {
+ AppLayerProtoDetectProbingParserPort *temp_port = *head_port;
+ while (temp_port->next != NULL && temp_port->next->port != 0) {
+ temp_port = temp_port->next;
+ }
+ new_port->next = temp_port->next;
+ temp_port->next = new_port;
+ }
+
+ end:
+ SCReturn;
+}
+
+static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbingParser **pp,
+ uint8_t ipproto,
+ uint16_t port,
+ AppProto alproto,
+ uint16_t min_depth, uint16_t max_depth,
+ uint8_t direction,
+ ProbingParserFPtr ProbingParser1,
+ ProbingParserFPtr ProbingParser2)
+{
+ SCEnter();
+
+ /* get the top level ipproto pp */
+ AppLayerProtoDetectProbingParser *curr_pp = *pp;
+ while (curr_pp != NULL) {
+ if (curr_pp->ipproto == ipproto)
+ break;
+ curr_pp = curr_pp->next;
+ }
+ if (curr_pp == NULL) {
+ AppLayerProtoDetectProbingParser *new_pp = AppLayerProtoDetectProbingParserAlloc();
+ new_pp->ipproto = ipproto;
+ AppLayerProtoDetectProbingParserAppend(pp, new_pp);
+ curr_pp = new_pp;
+ }
+
+ /* get the top level port pp */
+ AppLayerProtoDetectProbingParserPort *curr_port = curr_pp->port;
+ while (curr_port != NULL) {
+ if (curr_port->port == port)
+ break;
+ curr_port = curr_port->next;
+ }
+ if (curr_port == NULL) {
+ AppLayerProtoDetectProbingParserPort *new_port = AppLayerProtoDetectProbingParserPortAlloc();
+ new_port->port = port;
+ AppLayerProtoDetectProbingParserPortAppend(&curr_pp->port, new_port);
+ curr_port = new_port;
+ if (direction & STREAM_TOSERVER) {
+ curr_port->dp_max_depth = max_depth;
+ } else {
+ curr_port->sp_max_depth = max_depth;
+ }
+
+ AppLayerProtoDetectProbingParserPort *zero_port;
+
+ zero_port = curr_pp->port;
+ while (zero_port != NULL && zero_port->port != 0) {
+ zero_port = zero_port->next;
+ }
+ if (zero_port != NULL) {
+ AppLayerProtoDetectProbingParserElement *zero_pe;
+
+ zero_pe = zero_port->dp;
+ for ( ; zero_pe != NULL; zero_pe = zero_pe->next) {
+ if (curr_port->dp == NULL)
+ curr_port->dp_max_depth = zero_pe->max_depth;
+ if (zero_pe->max_depth == 0)
+ curr_port->dp_max_depth = zero_pe->max_depth;
+ if (curr_port->dp_max_depth != 0 &&
+ curr_port->dp_max_depth < zero_pe->max_depth) {
+ curr_port->dp_max_depth = zero_pe->max_depth;
+ }
+
+ AppLayerProtoDetectProbingParserElement *dup_pe =
+ AppLayerProtoDetectProbingParserElementDuplicate(zero_pe);
+ AppLayerProtoDetectProbingParserElementAppend(&curr_port->dp, dup_pe);
+ curr_port->alproto_mask |= dup_pe->alproto_mask;
+ }
+
+ zero_pe = zero_port->sp;
+ for ( ; zero_pe != NULL; zero_pe = zero_pe->next) {
+ if (curr_port->sp == NULL)
+ curr_port->sp_max_depth = zero_pe->max_depth;
+ if (zero_pe->max_depth == 0)
+ curr_port->sp_max_depth = zero_pe->max_depth;
+ if (curr_port->sp_max_depth != 0 &&
+ curr_port->sp_max_depth < zero_pe->max_depth) {
+ curr_port->sp_max_depth = zero_pe->max_depth;
+ }
+
+ AppLayerProtoDetectProbingParserElement *dup_pe =
+ AppLayerProtoDetectProbingParserElementDuplicate(zero_pe);
+ AppLayerProtoDetectProbingParserElementAppend(&curr_port->sp, dup_pe);
+ curr_port->alproto_mask |= dup_pe->alproto_mask;
+ }
+ } /* if (zero_port != NULL) */
+ } /* if (curr_port == NULL) */
+
+ /* insert the pe_pp */
+ AppLayerProtoDetectProbingParserElement *curr_pe;
+ if (direction & STREAM_TOSERVER)
+ curr_pe = curr_port->dp;
+ else
+ curr_pe = curr_port->sp;
+ while (curr_pe != NULL) {
+ if (curr_pe->alproto == alproto) {
+ SCLogError("Duplicate pp registered - "
+ "ipproto - %" PRIu8 " Port - %" PRIu16 " "
+ "App Protocol - NULL, App Protocol(ID) - "
+ "%" PRIu16 " min_depth - %" PRIu16 " "
+ "max_dept - %" PRIu16 ".",
+ ipproto, port, alproto, min_depth, max_depth);
+ goto error;
+ }
+ curr_pe = curr_pe->next;
+ }
+ /* Get a new parser element */
+ AppLayerProtoDetectProbingParserElement *new_pe =
+ AppLayerProtoDetectProbingParserElementCreate(alproto,
+ curr_port->port,
+ min_depth, max_depth);
+ if (new_pe == NULL)
+ goto error;
+ curr_pe = new_pe;
+ AppLayerProtoDetectProbingParserElement **head_pe;
+ if (direction & STREAM_TOSERVER) {
+ curr_pe->ProbingParserTs = ProbingParser1;
+ curr_pe->ProbingParserTc = ProbingParser2;
+ if (curr_port->dp == NULL)
+ curr_port->dp_max_depth = new_pe->max_depth;
+ if (new_pe->max_depth == 0)
+ curr_port->dp_max_depth = new_pe->max_depth;
+ if (curr_port->dp_max_depth != 0 &&
+ curr_port->dp_max_depth < new_pe->max_depth) {
+ curr_port->dp_max_depth = new_pe->max_depth;
+ }
+ curr_port->alproto_mask |= new_pe->alproto_mask;
+ head_pe = &curr_port->dp;
+ } else {
+ curr_pe->ProbingParserTs = ProbingParser2;
+ curr_pe->ProbingParserTc = ProbingParser1;
+ if (curr_port->sp == NULL)
+ curr_port->sp_max_depth = new_pe->max_depth;
+ if (new_pe->max_depth == 0)
+ curr_port->sp_max_depth = new_pe->max_depth;
+ if (curr_port->sp_max_depth != 0 &&
+ curr_port->sp_max_depth < new_pe->max_depth) {
+ curr_port->sp_max_depth = new_pe->max_depth;
+ }
+ curr_port->alproto_mask |= new_pe->alproto_mask;
+ head_pe = &curr_port->sp;
+ }
+ AppLayerProtoDetectProbingParserElementAppend(head_pe, new_pe);
+
+ if (curr_port->port == 0) {
+ AppLayerProtoDetectProbingParserPort *temp_port = curr_pp->port;
+ while (temp_port != NULL && temp_port->port != 0) {
+ if (direction & STREAM_TOSERVER) {
+ if (temp_port->dp == NULL)
+ temp_port->dp_max_depth = curr_pe->max_depth;
+ if (curr_pe->max_depth == 0)
+ temp_port->dp_max_depth = curr_pe->max_depth;
+ if (temp_port->dp_max_depth != 0 &&
+ temp_port->dp_max_depth < curr_pe->max_depth) {
+ temp_port->dp_max_depth = curr_pe->max_depth;
+ }
+ AppLayerProtoDetectProbingParserElementAppend(&temp_port->dp,
+ AppLayerProtoDetectProbingParserElementDuplicate(curr_pe));
+ temp_port->alproto_mask |= curr_pe->alproto_mask;
+ } else {
+ if (temp_port->sp == NULL)
+ temp_port->sp_max_depth = curr_pe->max_depth;
+ if (curr_pe->max_depth == 0)
+ temp_port->sp_max_depth = curr_pe->max_depth;
+ if (temp_port->sp_max_depth != 0 &&
+ temp_port->sp_max_depth < curr_pe->max_depth) {
+ temp_port->sp_max_depth = curr_pe->max_depth;
+ }
+ AppLayerProtoDetectProbingParserElementAppend(&temp_port->sp,
+ AppLayerProtoDetectProbingParserElementDuplicate(curr_pe));
+ temp_port->alproto_mask |= curr_pe->alproto_mask;
+ }
+ temp_port = temp_port->next;
+ } /* while */
+ } /* if */
+
+ error:
+ SCReturn;
+}
+
+/***** Static Internal Calls: PM registration *****/
+
+static void AppLayerProtoDetectPMGetIpprotos(AppProto alproto,
+ uint8_t *ipprotos)
+{
+ SCEnter();
+
+ for (uint8_t i = 0; i < FLOW_PROTO_DEFAULT; i++) {
+ uint8_t ipproto = FlowGetReverseProtoMapping(i);
+ for (int j = 0; j < 2; j++) {
+ AppLayerProtoDetectPMCtx *pm_ctx = &alpd_ctx.ctx_ipp[i].ctx_pm[j];
+
+ for (SigIntId x = 0; x < pm_ctx->max_sig_id; x++) {
+ const AppLayerProtoDetectPMSignature *s = pm_ctx->map[x];
+ if (s->alproto == alproto)
+ ipprotos[ipproto / 8] |= 1 << (ipproto % 8);
+ }
+ }
+ }
+
+ SCReturn;
+}
+
+static int AppLayerProtoDetectPMSetContentIDs(AppLayerProtoDetectPMCtx *ctx)
+{
+ SCEnter();
+
+ typedef struct TempContainer_ {
+ PatIntId id;
+ uint16_t content_len;
+ uint8_t *content;
+ } TempContainer;
+
+ AppLayerProtoDetectPMSignature *s = NULL;
+ uint32_t struct_total_size = 0;
+ uint32_t content_total_size = 0;
+ /* array hash buffer */
+ uint8_t *ahb = NULL;
+ uint8_t *content = NULL;
+ uint16_t content_len = 0;
+ PatIntId max_id = 0;
+ TempContainer *struct_offset = NULL;
+ uint8_t *content_offset = NULL;
+ int ret = 0;
+
+ if (ctx->head == NULL)
+ goto end;
+
+ for (s = ctx->head; s != NULL; s = s->next) {
+ struct_total_size += sizeof(TempContainer);
+ content_total_size += s->cd->content_len;
+ ctx->max_sig_id++;
+ }
+
+ ahb = SCMalloc(sizeof(uint8_t) * (struct_total_size + content_total_size));
+ if (unlikely(ahb == NULL))
+ goto error;
+
+ struct_offset = (TempContainer *)ahb;
+ content_offset = ahb + struct_total_size;
+ for (s = ctx->head; s != NULL; s = s->next) {
+ TempContainer *tcdup = (TempContainer *)ahb;
+ content = s->cd->content;
+ content_len = s->cd->content_len;
+
+ for (; tcdup != struct_offset; tcdup++) {
+ if (tcdup->content_len != content_len ||
+ SCMemcmp(tcdup->content, content, tcdup->content_len) != 0)
+ {
+ continue;
+ }
+ break;
+ }
+
+ if (tcdup != struct_offset) {
+ s->cd->id = tcdup->id;
+ continue;
+ }
+
+ struct_offset->content_len = content_len;
+ struct_offset->content = content_offset;
+ content_offset += content_len;
+ memcpy(struct_offset->content, content, content_len);
+ struct_offset->id = max_id++;
+ s->cd->id = struct_offset->id;
+
+ struct_offset++;
+ }
+
+ ctx->max_pat_id = max_id;
+
+ goto end;
+ error:
+ ret = -1;
+ end:
+ if (ahb != NULL)
+ SCFree(ahb);
+ SCReturnInt(ret);
+}
+
+static int AppLayerProtoDetectPMMapSignatures(AppLayerProtoDetectPMCtx *ctx)
+{
+ SCEnter();
+
+ int ret = 0;
+ AppLayerProtoDetectPMSignature *s, *next_s;
+ int mpm_ret;
+ SigIntId id = 0;
+
+ ctx->map = SCMalloc(ctx->max_sig_id * sizeof(AppLayerProtoDetectPMSignature *));
+ if (ctx->map == NULL)
+ goto error;
+ memset(ctx->map, 0, ctx->max_sig_id * sizeof(AppLayerProtoDetectPMSignature *));
+
+ /* add an array indexed by rule id to look up the sig */
+ for (s = ctx->head; s != NULL; ) {
+ next_s = s->next;
+ s->id = id++;
+ SCLogDebug("s->id %u offset %u depth %u",
+ s->id, s->cd->offset, s->cd->depth);
+
+ if (s->cd->flags & DETECT_CONTENT_NOCASE) {
+ mpm_ret = MpmAddPatternCI(&ctx->mpm_ctx,
+ s->cd->content, s->cd->content_len,
+ s->cd->offset, s->cd->depth, s->cd->id, s->id, 0);
+ if (mpm_ret < 0)
+ goto error;
+ } else {
+ mpm_ret = MpmAddPatternCS(&ctx->mpm_ctx,
+ s->cd->content, s->cd->content_len,
+ s->cd->offset, s->cd->depth, s->cd->id, s->id, 0);
+ if (mpm_ret < 0)
+ goto error;
+ }
+
+ ctx->map[s->id] = s;
+ s->next = NULL;
+ s = next_s;
+ }
+ ctx->head = NULL;
+
+ goto end;
+ error:
+ ret = -1;
+ end:
+ SCReturnInt(ret);
+}
+
+static int AppLayerProtoDetectPMPrepareMpm(AppLayerProtoDetectPMCtx *ctx)
+{
+ SCEnter();
+
+ int ret = 0;
+ MpmCtx *mpm_ctx = &ctx->mpm_ctx;
+
+ if (mpm_table[mpm_ctx->mpm_type].Prepare(mpm_ctx) < 0)
+ goto error;
+
+ goto end;
+ error:
+ ret = -1;
+ end:
+ SCReturnInt(ret);
+}
+
+static void AppLayerProtoDetectPMFreeSignature(AppLayerProtoDetectPMSignature *sig)
+{
+ SCEnter();
+ if (sig == NULL)
+ SCReturn;
+ if (sig->cd)
+ DetectContentFree(NULL, sig->cd);
+ SCFree(sig);
+ SCReturn;
+}
+
+static int AppLayerProtoDetectPMAddSignature(AppLayerProtoDetectPMCtx *ctx, DetectContentData *cd,
+ AppProto alproto, uint8_t direction,
+ ProbingParserFPtr PPFunc,
+ uint16_t pp_min_depth, uint16_t pp_max_depth)
+{
+ SCEnter();
+
+ AppLayerProtoDetectPMSignature *s = SCCalloc(1, sizeof(*s));
+ if (unlikely(s == NULL))
+ SCReturnInt(-1);
+
+ s->alproto = alproto;
+ s->direction = direction;
+ s->cd = cd;
+ s->PPFunc = PPFunc;
+ s->pp_min_depth = pp_min_depth;
+ s->pp_max_depth = pp_max_depth;
+
+ /* prepend to the list */
+ s->next = ctx->head;
+ ctx->head = s;
+
+ SCReturnInt(0);
+}
+
+static int AppLayerProtoDetectPMRegisterPattern(uint8_t ipproto, AppProto alproto,
+ const char *pattern,
+ uint16_t depth, uint16_t offset,
+ uint8_t direction,
+ uint8_t is_cs,
+ ProbingParserFPtr PPFunc,
+ uint16_t pp_min_depth, uint16_t pp_max_depth)
+{
+ SCEnter();
+
+ AppLayerProtoDetectCtxIpproto *ctx_ipp = &alpd_ctx.ctx_ipp[FlowGetProtoMapping(ipproto)];
+ AppLayerProtoDetectPMCtx *ctx_pm = NULL;
+ int ret = 0;
+
+ DetectContentData *cd = DetectContentParseEncloseQuotes(
+ alpd_ctx.spm_global_thread_ctx, pattern);
+ if (cd == NULL)
+ goto error;
+ cd->depth = depth;
+ cd->offset = offset;
+ if (!is_cs) {
+ /* Rebuild as nocase */
+ SpmDestroyCtx(cd->spm_ctx);
+ cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1,
+ alpd_ctx.spm_global_thread_ctx);
+ if (cd->spm_ctx == NULL) {
+ goto error;
+ }
+ cd->flags |= DETECT_CONTENT_NOCASE;
+ }
+ if (depth < cd->content_len)
+ goto error;
+
+ if (direction & STREAM_TOSERVER)
+ ctx_pm = (AppLayerProtoDetectPMCtx *)&ctx_ipp->ctx_pm[0];
+ else
+ ctx_pm = (AppLayerProtoDetectPMCtx *)&ctx_ipp->ctx_pm[1];
+
+ if (pp_max_depth > ctx_pm->pp_max_len)
+ ctx_pm->pp_max_len = pp_max_depth;
+ if (depth < ctx_pm->min_len)
+ ctx_pm->min_len = depth;
+
+ /* Finally turn it into a signature and add to the ctx. */
+ AppLayerProtoDetectPMAddSignature(ctx_pm, cd, alproto, direction,
+ PPFunc, pp_min_depth, pp_max_depth);
+
+ goto end;
+ error:
+ DetectContentFree(NULL, cd);
+ ret = -1;
+ end:
+ SCReturnInt(ret);
+}
+
+/***** Protocol Retrieval *****/
+
+AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx, Flow *f,
+ const uint8_t *buf, uint32_t buflen, uint8_t ipproto, uint8_t flags, bool *reverse_flow)
+{
+ SCEnter();
+ SCLogDebug("buflen %u for %s direction", buflen,
+ (flags & STREAM_TOSERVER) ? "toserver" : "toclient");
+
+ AppProto alproto = ALPROTO_UNKNOWN;
+ AppProto pm_alproto = ALPROTO_UNKNOWN;
+
+ if (!FLOW_IS_PM_DONE(f, flags)) {
+ AppProto pm_results[ALPROTO_MAX];
+ uint16_t pm_matches = AppLayerProtoDetectPMGetProto(
+ tctx, f, buf, buflen, flags, pm_results, reverse_flow);
+ if (pm_matches > 0) {
+ DEBUG_VALIDATE_BUG_ON(pm_matches > 1);
+ alproto = pm_results[0];
+
+ // rerun probing parser for other direction if it is unknown
+ uint8_t reverse_dir = (flags & STREAM_TOSERVER) ? STREAM_TOCLIENT : STREAM_TOSERVER;
+ if (FLOW_IS_PP_DONE(f, reverse_dir)) {
+ AppProto rev_alproto = (flags & STREAM_TOSERVER) ? f->alproto_tc : f->alproto_ts;
+ if (rev_alproto == ALPROTO_UNKNOWN) {
+ FLOW_RESET_PP_DONE(f, reverse_dir);
+ }
+ }
+
+ /* HACK: if detected protocol is dcerpc/udp, we run PP as well
+ * to avoid misdetecting DNS as DCERPC. */
+ if (!(ipproto == IPPROTO_UDP && alproto == ALPROTO_DCERPC))
+ goto end;
+
+ pm_alproto = alproto;
+
+ /* fall through */
+ }
+ }
+
+ if (!FLOW_IS_PP_DONE(f, flags)) {
+ bool rflow = false;
+ alproto = AppLayerProtoDetectPPGetProto(f, buf, buflen, ipproto, flags, &rflow);
+ if (AppProtoIsValid(alproto)) {
+ if (rflow) {
+ *reverse_flow = true;
+ }
+ goto end;
+ }
+ }
+
+ /* Look if flow can be found in expectation list */
+ if (!FLOW_IS_PE_DONE(f, flags)) {
+ alproto = AppLayerProtoDetectPEGetProto(f, ipproto, flags);
+ }
+
+ end:
+ if (!AppProtoIsValid(alproto))
+ alproto = pm_alproto;
+
+ SCReturnUInt(alproto);
+}
+
+static void AppLayerProtoDetectFreeProbingParsers(AppLayerProtoDetectProbingParser *pp)
+{
+ SCEnter();
+
+ AppLayerProtoDetectProbingParser *tmp_pp = NULL;
+
+ if (pp == NULL)
+ goto end;
+
+ while (pp != NULL) {
+ tmp_pp = pp->next;
+ AppLayerProtoDetectProbingParserFree(pp);
+ pp = tmp_pp;
+ }
+
+ end:
+ SCReturn;
+}
+
+static void AppLayerProtoDetectFreeAliases(void)
+{
+ SCEnter();
+
+ AppLayerProtoDetectAliases *cur_alias = alpda_ctx;
+ if (cur_alias == NULL)
+ goto end;
+
+ AppLayerProtoDetectAliases *next_alias = NULL;
+ while (cur_alias != NULL) {
+ next_alias = cur_alias->next;
+ SCFree(cur_alias);
+ cur_alias = next_alias;
+ }
+
+ alpda_ctx = NULL;
+
+end:
+ SCReturn;
+}
+
+/***** State Preparation *****/
+
+int AppLayerProtoDetectPrepareState(void)
+{
+ SCEnter();
+
+ AppLayerProtoDetectPMCtx *ctx_pm;
+ int i, j;
+ int ret = 0;
+
+ for (i = 0; i < FLOW_PROTO_DEFAULT; i++) {
+ for (j = 0; j < 2; j++) {
+ ctx_pm = &alpd_ctx.ctx_ipp[i].ctx_pm[j];
+
+ if (AppLayerProtoDetectPMSetContentIDs(ctx_pm) < 0)
+ goto error;
+
+ if (ctx_pm->max_sig_id == 0)
+ continue;
+
+ if (AppLayerProtoDetectPMMapSignatures(ctx_pm) < 0)
+ goto error;
+ if (AppLayerProtoDetectPMPrepareMpm(ctx_pm) < 0)
+ goto error;
+ }
+ }
+
+#ifdef DEBUG
+ if (SCLogDebugEnabled()) {
+ AppLayerProtoDetectPrintProbingParsers(alpd_ctx.ctx_pp);
+ }
+#endif
+
+ goto end;
+ error:
+ ret = -1;
+ end:
+ SCReturnInt(ret);
+}
+
+/***** PP registration *****/
+
+/** \brief register parser at a port
+ *
+ * \param direction STREAM_TOSERVER or STREAM_TOCLIENT for dp or sp
+ */
+void AppLayerProtoDetectPPRegister(uint8_t ipproto,
+ const char *portstr,
+ AppProto alproto,
+ uint16_t min_depth, uint16_t max_depth,
+ uint8_t direction,
+ ProbingParserFPtr ProbingParser1,
+ ProbingParserFPtr ProbingParser2)
+{
+ SCEnter();
+
+ DetectPort *head = NULL;
+ DetectPortParse(NULL,&head, portstr);
+ DetectPort *temp_dp = head;
+ while (temp_dp != NULL) {
+ uint16_t port = temp_dp->port;
+ if (port == 0 && temp_dp->port2 != 0)
+ port++;
+ for (;;) {
+ AppLayerProtoDetectInsertNewProbingParser(&alpd_ctx.ctx_pp,
+ ipproto,
+ port,
+ alproto,
+ min_depth, max_depth,
+ direction,
+ ProbingParser1,
+ ProbingParser2);
+ if (port == temp_dp->port2) {
+ break;
+ } else {
+ port++;
+ }
+ }
+ temp_dp = temp_dp->next;
+ }
+ DetectPortCleanupList(NULL,head);
+
+ SCReturn;
+}
+
+int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name,
+ uint8_t ipproto,
+ const char *alproto_name,
+ AppProto alproto,
+ uint16_t min_depth, uint16_t max_depth,
+ ProbingParserFPtr ProbingParserTs,
+ ProbingParserFPtr ProbingParserTc)
+{
+ SCEnter();
+
+ char param[100];
+ int r;
+ ConfNode *node;
+ ConfNode *port_node = NULL;
+ int config = 0;
+
+ r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.",
+ alproto_name, ".detection-ports");
+ if (r < 0) {
+ FatalError("snprintf failure.");
+ } else if (r > (int)sizeof(param)) {
+ FatalError("buffer not big enough to write param.");
+ }
+ node = ConfGetNode(param);
+ if (node == NULL) {
+ SCLogDebug("Entry for %s not found.", param);
+ r = snprintf(param, sizeof(param), "%s%s%s%s%s", "app-layer.protocols.",
+ alproto_name, ".", ipproto_name, ".detection-ports");
+ if (r < 0) {
+ FatalError("snprintf failure.");
+ } else if (r > (int)sizeof(param)) {
+ FatalError("buffer not big enough to write param.");
+ }
+ node = ConfGetNode(param);
+ if (node == NULL)
+ goto end;
+ }
+
+ /* detect by destination port of the flow (e.g. port 53 for DNS) */
+ port_node = ConfNodeLookupChild(node, "dp");
+ if (port_node == NULL)
+ port_node = ConfNodeLookupChild(node, "toserver");
+
+ if (port_node != NULL && port_node->val != NULL) {
+ AppLayerProtoDetectPPRegister(ipproto,
+ port_node->val,
+ alproto,
+ min_depth, max_depth,
+ STREAM_TOSERVER, /* to indicate dp */
+ ProbingParserTs, ProbingParserTc);
+ }
+
+ /* detect by source port of flow */
+ port_node = ConfNodeLookupChild(node, "sp");
+ if (port_node == NULL)
+ port_node = ConfNodeLookupChild(node, "toclient");
+
+ if (port_node != NULL && port_node->val != NULL) {
+ AppLayerProtoDetectPPRegister(ipproto,
+ port_node->val,
+ alproto,
+ min_depth, max_depth,
+ STREAM_TOCLIENT, /* to indicate sp */
+ ProbingParserTc, ProbingParserTs);
+
+ }
+
+ config = 1;
+ end:
+ SCReturnInt(config);
+}
+
+/***** PM registration *****/
+
+int AppLayerProtoDetectPMRegisterPatternCS(uint8_t ipproto, AppProto alproto,
+ const char *pattern,
+ uint16_t depth, uint16_t offset,
+ uint8_t direction)
+{
+ SCEnter();
+ int r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto,
+ pattern, depth, offset,
+ direction, 1 /* case-sensitive */,
+ NULL, 0, 0);
+ SCReturnInt(r);
+}
+
+int AppLayerProtoDetectPMRegisterPatternCSwPP(uint8_t ipproto, AppProto alproto,
+ const char *pattern, uint16_t depth, uint16_t offset,
+ uint8_t direction,
+ ProbingParserFPtr PPFunc,
+ uint16_t pp_min_depth, uint16_t pp_max_depth)
+{
+ SCEnter();
+ int r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto,
+ pattern, depth, offset,
+ direction, 1 /* case-sensitive */,
+ PPFunc, pp_min_depth, pp_max_depth);
+ SCReturnInt(r);
+}
+
+int AppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto,
+ const char *pattern,
+ uint16_t depth, uint16_t offset,
+ uint8_t direction)
+{
+ SCEnter();
+ int r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto,
+ pattern, depth, offset,
+ direction, 0 /* !case-sensitive */,
+ NULL, 0, 0);
+ SCReturnInt(r);
+}
+
+/***** Setup/General Registration *****/
+
+int AppLayerProtoDetectSetup(void)
+{
+ SCEnter();
+
+ int i, j;
+
+ memset(&alpd_ctx, 0, sizeof(alpd_ctx));
+
+ uint8_t spm_matcher = SinglePatternMatchDefaultMatcher();
+ uint8_t mpm_matcher = PatternMatchDefaultMatcher();
+
+ alpd_ctx.spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
+ if (alpd_ctx.spm_global_thread_ctx == NULL) {
+ FatalError("Unable to alloc SpmGlobalThreadCtx.");
+ }
+
+ for (i = 0; i < FLOW_PROTO_DEFAULT; i++) {
+ for (j = 0; j < 2; j++) {
+ MpmInitCtx(&alpd_ctx.ctx_ipp[i].ctx_pm[j].mpm_ctx, mpm_matcher);
+ }
+ }
+
+ AppLayerExpectationSetup();
+
+ SCReturnInt(0);
+}
+
+/**
+ * \todo incomplete. Need more work.
+ */
+int AppLayerProtoDetectDeSetup(void)
+{
+ SCEnter();
+
+ int ipproto_map = 0;
+ int dir = 0;
+ PatIntId id = 0;
+ AppLayerProtoDetectPMCtx *pm_ctx = NULL;
+ AppLayerProtoDetectPMSignature *sig = NULL;
+
+ for (ipproto_map = 0; ipproto_map < FLOW_PROTO_DEFAULT; ipproto_map++) {
+ for (dir = 0; dir < 2; dir++) {
+ pm_ctx = &alpd_ctx.ctx_ipp[ipproto_map].ctx_pm[dir];
+ mpm_table[pm_ctx->mpm_ctx.mpm_type].DestroyCtx(&pm_ctx->mpm_ctx);
+ for (id = 0; id < pm_ctx->max_sig_id; id++) {
+ sig = pm_ctx->map[id];
+ AppLayerProtoDetectPMFreeSignature(sig);
+ }
+ SCFree(pm_ctx->map);
+ pm_ctx->map = NULL;
+ }
+ }
+
+ SpmDestroyGlobalThreadCtx(alpd_ctx.spm_global_thread_ctx);
+
+ AppLayerProtoDetectFreeAliases();
+
+ AppLayerProtoDetectFreeProbingParsers(alpd_ctx.ctx_pp);
+
+ SCReturnInt(0);
+}
+
+void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
+{
+ SCEnter();
+
+ if (alpd_ctx.alproto_names[alproto] == NULL)
+ alpd_ctx.alproto_names[alproto] = alproto_name;
+
+ SCReturn;
+}
+
+void AppLayerProtoDetectRegisterAlias(const char *proto_name, const char *proto_alias)
+{
+ SCEnter();
+
+ AppLayerProtoDetectAliases *new_alias = SCMalloc(sizeof(AppLayerProtoDetectAliases));
+ if (unlikely(new_alias == NULL)) {
+ exit(EXIT_FAILURE);
+ }
+
+ new_alias->proto_name = proto_name;
+ new_alias->proto_alias = proto_alias;
+ new_alias->next = NULL;
+
+ if (alpda_ctx == NULL) {
+ alpda_ctx = new_alias;
+ } else {
+ AppLayerProtoDetectAliases *cur_alias = alpda_ctx;
+ while (cur_alias->next != NULL) {
+ cur_alias = cur_alias->next;
+ }
+ cur_alias->next = new_alias;
+ }
+
+ SCReturn;
+}
+
+/** \brief request applayer to wrap up this protocol and rerun protocol
+ * detection.
+ *
+ * When this is called, the old session is reset unconditionally. A
+ * 'detect/log' flush packet is generated for both direction before
+ * the reset, so allow for final detection and logging.
+ *
+ * \param f flow to act on
+ * \param dp destination port to use in protocol detection. Set to 443
+ * for start tls, set to the HTTP uri port for CONNECT and
+ * set to 0 to not use it.
+ * \param expect_proto expected protocol. AppLayer event will be set if
+ * detected protocol differs from this.
+ */
+bool AppLayerRequestProtocolChange(Flow *f, uint16_t dp, AppProto expect_proto)
+{
+ if (FlowChangeProto(f)) {
+ // If we are already changing protocols, from SMTP to TLS for instance,
+ // and that we do not get TLS but HTTP1, which is requesting change to HTTP2,
+ // we do not proceed the new protocol change
+ return false;
+ }
+ FlowSetChangeProtoFlag(f);
+ f->protodetect_dp = dp;
+ f->alproto_expect = expect_proto;
+ DEBUG_VALIDATE_BUG_ON(f->alproto == ALPROTO_UNKNOWN);
+ f->alproto_orig = f->alproto;
+ // If one side is unknown yet, set it to the other known side
+ if (f->alproto_ts == ALPROTO_UNKNOWN) {
+ f->alproto_ts = f->alproto;
+ }
+ if (f->alproto_tc == ALPROTO_UNKNOWN) {
+ f->alproto_tc = f->alproto;
+ }
+ return true;
+}
+
+/** \brief request applayer to wrap up this protocol and rerun protocol
+ * detection with expectation of TLS. Used by STARTTLS.
+ *
+ * Sets detection port to 443 to make port based TLS detection work for
+ * SMTP, FTP etc as well.
+ *
+ * \param f flow to act on
+ */
+bool AppLayerRequestProtocolTLSUpgrade(Flow *f)
+{
+ return AppLayerRequestProtocolChange(f, 443, ALPROTO_TLS);
+}
+
+void AppLayerProtoDetectReset(Flow *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);
+ FLOW_RESET_PE_DONE(f, STREAM_TOSERVER);
+ FLOW_RESET_PE_DONE(f, STREAM_TOCLIENT);
+ f->probing_parser_toserver_alproto_masks = 0;
+ f->probing_parser_toclient_alproto_masks = 0;
+
+ // Does not free the structures for the parser
+ // keeps f->alstate for new state creation
+ f->alparser = NULL;
+ f->alproto = ALPROTO_UNKNOWN;
+ f->alproto_ts = ALPROTO_UNKNOWN;
+ f->alproto_tc = ALPROTO_UNKNOWN;
+}
+
+int AppLayerProtoDetectConfProtoDetectionEnabledDefault(
+ const char *ipproto, const char *alproto, bool default_enabled)
+{
+ SCEnter();
+
+ BUG_ON(ipproto == NULL || alproto == NULL);
+
+ int enabled = 1;
+ char param[100];
+ ConfNode *node;
+ int r;
+
+ if (RunmodeIsUnittests())
+ goto enabled;
+
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ // so that fuzzig takes place for DNP3 and such
+ default_enabled = true;
+#endif
+
+ r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.",
+ alproto, ".enabled");
+ if (r < 0) {
+ FatalError("snprintf failure.");
+ } else if (r > (int)sizeof(param)) {
+ FatalError("buffer not big enough to write param.");
+ }
+
+ node = ConfGetNode(param);
+ if (node == NULL) {
+ SCLogDebug("Entry for %s not found.", param);
+ r = snprintf(param, sizeof(param), "%s%s%s%s%s", "app-layer.protocols.",
+ alproto, ".", ipproto, ".enabled");
+ if (r < 0) {
+ FatalError("snprintf failure.");
+ } else if (r > (int)sizeof(param)) {
+ FatalError("buffer not big enough to write param.");
+ }
+
+ node = ConfGetNode(param);
+ if (node == NULL) {
+ SCLogDebug("Entry for %s not found.", param);
+ if (default_enabled) {
+ goto enabled;
+ } else {
+ goto disabled;
+ }
+ }
+ }
+
+ if (node->val) {
+ if (ConfValIsTrue(node->val)) {
+ goto enabled;
+ } else if (ConfValIsFalse(node->val)) {
+ goto disabled;
+ } else if (strcasecmp(node->val, "detection-only") == 0) {
+ goto enabled;
+ }
+ }
+
+ /* Invalid or null value. */
+ SCLogError("Invalid value found for %s.", param);
+ exit(EXIT_FAILURE);
+
+ disabled:
+ enabled = 0;
+ enabled:
+ SCReturnInt(enabled);
+}
+
+int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
+{
+ return AppLayerProtoDetectConfProtoDetectionEnabledDefault(ipproto, alproto, true);
+}
+
+AppLayerProtoDetectThreadCtx *AppLayerProtoDetectGetCtxThread(void)
+{
+ SCEnter();
+
+ AppLayerProtoDetectThreadCtx *alpd_tctx = NULL;
+ MpmCtx *mpm_ctx;
+ MpmThreadCtx *mpm_tctx;
+ int i, j;
+ PatIntId max_pat_id = 0;
+
+ for (i = 0; i < FLOW_PROTO_DEFAULT; i++) {
+ for (j = 0; j < 2; j++) {
+ if (max_pat_id == 0) {
+ max_pat_id = alpd_ctx.ctx_ipp[i].ctx_pm[j].max_pat_id;
+
+ } else if (alpd_ctx.ctx_ipp[i].ctx_pm[j].max_pat_id &&
+ max_pat_id < alpd_ctx.ctx_ipp[i].ctx_pm[j].max_pat_id)
+ {
+ max_pat_id = alpd_ctx.ctx_ipp[i].ctx_pm[j].max_pat_id;
+ }
+ }
+ }
+
+ alpd_tctx = SCMalloc(sizeof(*alpd_tctx));
+ if (alpd_tctx == NULL)
+ goto error;
+ memset(alpd_tctx, 0, sizeof(*alpd_tctx));
+
+ /* Get the max pat id for all the mpm ctxs. */
+ if (PmqSetup(&alpd_tctx->pmq) < 0)
+ goto error;
+
+ for (i = 0; i < FLOW_PROTO_DEFAULT; i++) {
+ for (j = 0; j < 2; j++) {
+ mpm_ctx = &alpd_ctx.ctx_ipp[i].ctx_pm[j].mpm_ctx;
+ mpm_tctx = &alpd_tctx->mpm_tctx[i][j];
+ mpm_table[mpm_ctx->mpm_type].InitThreadCtx(mpm_ctx, mpm_tctx);
+ }
+ }
+
+ alpd_tctx->spm_thread_ctx = SpmMakeThreadCtx(alpd_ctx.spm_global_thread_ctx);
+ if (alpd_tctx->spm_thread_ctx == NULL) {
+ goto error;
+ }
+
+ goto end;
+ error:
+ if (alpd_tctx != NULL)
+ AppLayerProtoDetectDestroyCtxThread(alpd_tctx);
+ alpd_tctx = NULL;
+ end:
+ SCReturnPtr(alpd_tctx, "AppLayerProtoDetectThreadCtx");
+}
+
+void AppLayerProtoDetectDestroyCtxThread(AppLayerProtoDetectThreadCtx *alpd_tctx)
+{
+ SCEnter();
+
+ MpmCtx *mpm_ctx;
+ MpmThreadCtx *mpm_tctx;
+ int ipproto_map, dir;
+
+ for (ipproto_map = 0; ipproto_map < FLOW_PROTO_DEFAULT; ipproto_map++) {
+ for (dir = 0; dir < 2; dir++) {
+ mpm_ctx = &alpd_ctx.ctx_ipp[ipproto_map].ctx_pm[dir].mpm_ctx;
+ mpm_tctx = &alpd_tctx->mpm_tctx[ipproto_map][dir];
+ mpm_table[mpm_ctx->mpm_type].DestroyThreadCtx(mpm_ctx, mpm_tctx);
+ }
+ }
+ PmqFree(&alpd_tctx->pmq);
+ if (alpd_tctx->spm_thread_ctx != NULL) {
+ SpmDestroyThreadCtx(alpd_tctx->spm_thread_ctx);
+ }
+ SCFree(alpd_tctx);
+
+ SCReturn;
+}
+
+/***** Utility *****/
+
+void AppLayerProtoDetectSupportedIpprotos(AppProto alproto, uint8_t *ipprotos)
+{
+ SCEnter();
+
+ // Custom case for only signature-only protocol so far
+ if (alproto == ALPROTO_HTTP) {
+ AppLayerProtoDetectSupportedIpprotos(ALPROTO_HTTP1, ipprotos);
+ AppLayerProtoDetectSupportedIpprotos(ALPROTO_HTTP2, ipprotos);
+ } else {
+ AppLayerProtoDetectPMGetIpprotos(alproto, ipprotos);
+ AppLayerProtoDetectPPGetIpprotos(alproto, ipprotos);
+ AppLayerProtoDetectPEGetIpprotos(alproto, ipprotos);
+ }
+
+ SCReturn;
+}
+
+AppProto AppLayerProtoDetectGetProtoByName(const char *alproto_name)
+{
+ SCEnter();
+
+ AppLayerProtoDetectAliases *cur_alias = alpda_ctx;
+ while (cur_alias != NULL) {
+ if (strcasecmp(alproto_name, cur_alias->proto_alias) == 0) {
+ alproto_name = cur_alias->proto_name;
+ }
+
+ cur_alias = cur_alias->next;
+ }
+
+ AppProto a;
+ AppProto b = StringToAppProto(alproto_name);
+ for (a = 0; a < ALPROTO_MAX; a++) {
+ if (alpd_ctx.alproto_names[a] != NULL && AppProtoEquals(b, a)) {
+ // That means return HTTP_ANY if HTTP1 or HTTP2 is enabled
+ SCReturnCT(b, "AppProto");
+ }
+ }
+
+ SCReturnCT(ALPROTO_UNKNOWN, "AppProto");
+}
+
+const char *AppLayerProtoDetectGetProtoName(AppProto alproto)
+{
+ // Special case for http (any version) :
+ // returns "http" if both versions are enabled
+ // and returns "http1" or "http2" if only one version is enabled
+ if (alproto == ALPROTO_HTTP) {
+ if (alpd_ctx.alproto_names[ALPROTO_HTTP1]) {
+ if (alpd_ctx.alproto_names[ALPROTO_HTTP2]) {
+ return "http";
+ } // else
+ return alpd_ctx.alproto_names[ALPROTO_HTTP1];
+ } // else
+ return alpd_ctx.alproto_names[ALPROTO_HTTP2];
+ }
+ return alpd_ctx.alproto_names[alproto];
+}
+
+void AppLayerProtoDetectSupportedAppProtocols(AppProto *alprotos)
+{
+ SCEnter();
+
+ memset(alprotos, 0, ALPROTO_MAX * sizeof(AppProto));
+
+ int alproto;
+
+ for (alproto = 0; alproto != ALPROTO_MAX; alproto++) {
+ if (alpd_ctx.alproto_names[alproto] != NULL)
+ alprotos[alproto] = 1;
+ }
+
+ SCReturn;
+}
+
+uint8_t expectation_proto[ALPROTO_MAX];
+
+static void AppLayerProtoDetectPEGetIpprotos(AppProto alproto,
+ uint8_t *ipprotos)
+{
+ if (expectation_proto[alproto] == IPPROTO_TCP) {
+ ipprotos[IPPROTO_TCP / 8] |= 1 << (IPPROTO_TCP % 8);
+ }
+ if (expectation_proto[alproto] == IPPROTO_UDP) {
+ ipprotos[IPPROTO_UDP / 8] |= 1 << (IPPROTO_UDP % 8);
+ }
+}
+
+void AppLayerRegisterExpectationProto(uint8_t proto, AppProto alproto)
+{
+ if (expectation_proto[alproto]) {
+ if (proto != expectation_proto[alproto]) {
+ SCLogError("Expectation on 2 IP protocols are not supported");
+ }
+ }
+ expectation_proto[alproto] = proto;
+}
+
+/***** Unittests *****/
+
+#ifdef UNITTESTS
+
+#include "app-layer-htp.h"
+#include "detect-engine-alert.h"
+
+static AppLayerProtoDetectCtx alpd_ctx_ut;
+
+void AppLayerProtoDetectUnittestCtxBackup(void)
+{
+ SCEnter();
+ alpd_ctx_ut = alpd_ctx;
+ memset(&alpd_ctx, 0, sizeof(alpd_ctx));
+ SCReturn;
+}
+
+void AppLayerProtoDetectUnittestCtxRestore(void)
+{
+ SCEnter();
+ alpd_ctx = alpd_ctx_ut;
+ memset(&alpd_ctx_ut, 0, sizeof(alpd_ctx_ut));
+ SCReturn;
+}
+
+static int AppLayerProtoDetectTest01(void)
+{
+ AppLayerProtoDetectUnittestCtxBackup();
+ AppLayerProtoDetectSetup();
+
+ const char *buf = "HTTP";
+ AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOCLIENT);
+ buf = "GET";
+ AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOSERVER);
+
+ AppLayerProtoDetectPrepareState();
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1);
+
+ AppLayerProtoDetectDeSetup();
+ AppLayerProtoDetectUnittestCtxRestore();
+ PASS;
+}
+
+static int AppLayerProtoDetectTest02(void)
+{
+ AppLayerProtoDetectUnittestCtxBackup();
+ AppLayerProtoDetectSetup();
+
+ const char *buf = "HTTP";
+ AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOCLIENT);
+ buf = "ftp";
+ AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT);
+
+ AppLayerProtoDetectPrepareState();
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2);
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP1);
+
+ AppLayerProtoDetectDeSetup();
+ AppLayerProtoDetectUnittestCtxRestore();
+ PASS;
+}
+
+static int AppLayerProtoDetectTest03(void)
+{
+ AppLayerProtoDetectUnittestCtxBackup();
+ AppLayerProtoDetectSetup();
+
+ uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n";
+ AppProto pm_results[ALPROTO_MAX];
+ memset(pm_results, 0, sizeof(pm_results));
+ Flow f;
+ memset(&f, 0x00, sizeof(f));
+ f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
+
+
+ const char *buf = "HTTP";
+ AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOCLIENT);
+ buf = "220 ";
+ AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT);
+
+ AppLayerProtoDetectPrepareState();
+ /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
+ * it sets internal structures which depends on the above function. */
+ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread();
+ FAIL_IF_NULL(alpd_tctx);
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP1);
+
+ bool rflow = false;
+ uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
+ &f, l7data, sizeof(l7data),
+ STREAM_TOCLIENT,
+ pm_results, &rflow);
+ FAIL_IF(cnt != 1);
+ FAIL_IF(pm_results[0] != ALPROTO_HTTP1);
+
+ AppLayerProtoDetectDestroyCtxThread(alpd_tctx);
+ AppLayerProtoDetectDeSetup();
+ AppLayerProtoDetectUnittestCtxRestore();
+ PASS;
+}
+
+static int AppLayerProtoDetectTest04(void)
+{
+ AppLayerProtoDetectUnittestCtxBackup();
+ AppLayerProtoDetectSetup();
+
+ uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n";
+ Flow f;
+ memset(&f, 0x00, sizeof(f));
+ AppProto pm_results[ALPROTO_MAX];
+ memset(pm_results, 0, sizeof(pm_results));
+ f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
+
+ const char *buf = "200 ";
+ AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP1, buf, 13, 0, STREAM_TOCLIENT);
+
+ AppLayerProtoDetectPrepareState();
+ /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
+ * it sets internal structures which depends on the above function. */
+ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread();
+ FAIL_IF_NULL(alpd_tctx);
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP1);
+
+ bool rdir = false;
+ uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
+ &f, l7data, sizeof(l7data), STREAM_TOCLIENT,
+ pm_results, &rdir);
+ FAIL_IF(cnt != 1);
+ FAIL_IF(pm_results[0] != ALPROTO_HTTP1);
+
+ AppLayerProtoDetectDestroyCtxThread(alpd_tctx);
+ AppLayerProtoDetectDeSetup();
+ AppLayerProtoDetectUnittestCtxRestore();
+ PASS;
+}
+
+static int AppLayerProtoDetectTest05(void)
+{
+ AppLayerProtoDetectUnittestCtxBackup();
+ AppLayerProtoDetectSetup();
+
+ uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n<HTML><BODY>Blahblah</BODY></HTML>";
+ AppProto pm_results[ALPROTO_MAX];
+ memset(pm_results, 0, sizeof(pm_results));
+ Flow f;
+ memset(&f, 0x00, sizeof(f));
+ f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
+
+ const char *buf = "HTTP";
+ AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOCLIENT);
+ buf = "220 ";
+ AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT);
+
+ AppLayerProtoDetectPrepareState();
+ /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
+ * it sets internal structures which depends on the above function. */
+ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread();
+ FAIL_IF_NULL(alpd_tctx);
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP1);
+
+ bool rdir = false;
+ uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
+ &f, l7data, sizeof(l7data),
+ STREAM_TOCLIENT,
+ pm_results, &rdir);
+ FAIL_IF(cnt != 1);
+ FAIL_IF(pm_results[0] != ALPROTO_HTTP1);
+
+ AppLayerProtoDetectDestroyCtxThread(alpd_tctx);
+ AppLayerProtoDetectDeSetup();
+ AppLayerProtoDetectUnittestCtxRestore();
+ PASS;
+}
+
+static int AppLayerProtoDetectTest06(void)
+{
+ AppLayerProtoDetectUnittestCtxBackup();
+ AppLayerProtoDetectSetup();
+
+ uint8_t l7data[] = "220 Welcome to the OISF FTP server\r\n";
+ AppProto pm_results[ALPROTO_MAX];
+ memset(pm_results, 0, sizeof(pm_results));
+ Flow f;
+ memset(&f, 0x00, sizeof(f));
+ f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
+
+ const char *buf = "HTTP";
+ AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOCLIENT);
+ buf = "220 ";
+ AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT);
+
+ AppLayerProtoDetectPrepareState();
+ /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
+ * it sets internal structures which depends on the above function. */
+ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread();
+ FAIL_IF_NULL(alpd_tctx);
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP1);
+
+ bool rdir = false;
+ uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
+ &f, l7data, sizeof(l7data), STREAM_TOCLIENT,
+ pm_results, &rdir);
+ FAIL_IF(cnt != 1);
+ FAIL_IF(pm_results[0] != ALPROTO_FTP);
+
+ AppLayerProtoDetectDestroyCtxThread(alpd_tctx);
+ AppLayerProtoDetectDeSetup();
+ AppLayerProtoDetectUnittestCtxRestore();
+ PASS;
+}
+
+static int AppLayerProtoDetectTest07(void)
+{
+ AppLayerProtoDetectUnittestCtxBackup();
+ AppLayerProtoDetectSetup();
+
+ uint8_t l7data[] = "220 Welcome to the OISF HTTP/FTP server\r\n";
+ Flow f;
+ memset(&f, 0x00, sizeof(f));
+ f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
+ AppProto pm_results[ALPROTO_MAX];
+ memset(pm_results, 0, sizeof(pm_results));
+
+ const char *buf = "HTTP";
+ AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP1, buf, 4, 0, STREAM_TOCLIENT);
+
+ AppLayerProtoDetectPrepareState();
+ /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
+ * it sets internal structures which depends on the above function. */
+ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread();
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP1);
+
+ bool rdir = false;
+ uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
+ &f, l7data, sizeof(l7data), STREAM_TOCLIENT,
+ pm_results, &rdir);
+ FAIL_IF(cnt != 0);
+
+ AppLayerProtoDetectDestroyCtxThread(alpd_tctx);
+ AppLayerProtoDetectDeSetup();
+ AppLayerProtoDetectUnittestCtxRestore();
+ PASS;
+}
+
+static int AppLayerProtoDetectTest08(void)
+{
+ AppLayerProtoDetectUnittestCtxBackup();
+ AppLayerProtoDetectSetup();
+
+ uint8_t l7data[] = {
+ 0x00, 0x00, 0x00, 0x85, 0xff, 0x53, 0x4d, 0x42,
+ 0x72, 0x00, 0x00, 0x00, 0x00, 0x18, 0x53, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x02,
+ 0x50, 0x43, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f,
+ 0x52, 0x4b, 0x20, 0x50, 0x52, 0x4f, 0x47, 0x52,
+ 0x41, 0x4d, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02,
+ 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x31, 0x2e,
+ 0x30, 0x00, 0x02, 0x57, 0x69, 0x6e, 0x64, 0x6f,
+ 0x77, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x57,
+ 0x6f, 0x72, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70,
+ 0x73, 0x20, 0x33, 0x2e, 0x31, 0x61, 0x00, 0x02,
+ 0x4c, 0x4d, 0x31, 0x2e, 0x32, 0x58, 0x30, 0x30,
+ 0x32, 0x00, 0x02, 0x4c, 0x41, 0x4e, 0x4d, 0x41,
+ 0x4e, 0x32, 0x2e, 0x31, 0x00, 0x02, 0x4e, 0x54,
+ 0x20, 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31, 0x32,
+ 0x00
+ };
+ AppProto pm_results[ALPROTO_MAX];
+ memset(pm_results, 0, sizeof(pm_results));
+ Flow f;
+ memset(&f, 0x00, sizeof(f));
+ f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
+
+ const char *buf = "|ff|SMB";
+ AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, buf, 8, 4, STREAM_TOCLIENT);
+
+ AppLayerProtoDetectPrepareState();
+ /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
+ * it sets internal structures which depends on the above function. */
+ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread();
+ FAIL_IF_NULL(alpd_tctx);
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_SMB);
+
+ bool rdir = false;
+ uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
+ &f, l7data, sizeof(l7data), STREAM_TOCLIENT,
+ pm_results, &rdir);
+ FAIL_IF(cnt != 1);
+ FAIL_IF(pm_results[0] != ALPROTO_SMB);
+
+ AppLayerProtoDetectDestroyCtxThread(alpd_tctx);
+ AppLayerProtoDetectDeSetup();
+ AppLayerProtoDetectUnittestCtxRestore();
+ PASS;
+}
+
+static int AppLayerProtoDetectTest09(void)
+{
+ AppLayerProtoDetectUnittestCtxBackup();
+ AppLayerProtoDetectSetup();
+
+ uint8_t l7data[] = {
+ 0x00, 0x00, 0x00, 0x66, 0xfe, 0x53, 0x4d, 0x42,
+ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x02
+ };
+ AppProto pm_results[ALPROTO_MAX];
+ memset(pm_results, 0, sizeof(pm_results));
+ Flow f;
+ memset(&f, 0x00, sizeof(f));
+ f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
+
+ const char *buf = "|fe|SMB";
+ AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB, buf, 8, 4, STREAM_TOCLIENT);
+
+ AppLayerProtoDetectPrepareState();
+ /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
+ * it sets internal structures which depends on the above function. */
+ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread();
+ FAIL_IF_NULL(alpd_tctx);
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_SMB);
+
+ bool rdir = false;
+ uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
+ &f, l7data, sizeof(l7data), STREAM_TOCLIENT,
+ pm_results, &rdir);
+ FAIL_IF(cnt != 1);
+ FAIL_IF(pm_results[0] != ALPROTO_SMB);
+
+ AppLayerProtoDetectDestroyCtxThread(alpd_tctx);
+ AppLayerProtoDetectDeSetup();
+ AppLayerProtoDetectUnittestCtxRestore();
+ PASS;
+}
+
+static int AppLayerProtoDetectTest10(void)
+{
+ AppLayerProtoDetectUnittestCtxBackup();
+ AppLayerProtoDetectSetup();
+
+ uint8_t l7data[] = {
+ 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0xb8, 0x4a, 0x9f, 0x4d, 0x1c, 0x7d, 0xcf, 0x11,
+ 0x86, 0x1e, 0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x57,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a,
+ 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00,
+ 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00
+ };
+ AppProto pm_results[ALPROTO_MAX];
+ memset(pm_results, 0, sizeof(pm_results));
+ Flow f;
+ memset(&f, 0x00, sizeof(f));
+ f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
+
+ const char *buf = "|05 00|";
+ AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_DCERPC, buf, 4, 0, STREAM_TOCLIENT);
+
+ AppLayerProtoDetectPrepareState();
+ /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
+ * it sets internal structures which depends on the above function. */
+ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread();
+ FAIL_IF_NULL(alpd_tctx);
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_DCERPC);
+
+ bool rdir = false;
+ uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
+ &f, l7data, sizeof(l7data), STREAM_TOCLIENT,
+ pm_results, &rdir);
+ FAIL_IF(cnt != 1);
+ FAIL_IF(pm_results[0] != ALPROTO_DCERPC);
+
+ AppLayerProtoDetectDestroyCtxThread(alpd_tctx);
+ AppLayerProtoDetectDeSetup();
+ AppLayerProtoDetectUnittestCtxRestore();
+ PASS;
+}
+
+/**
+ * \test Why we still get http for connect... obviously because
+ * we also match on the reply, duh
+ */
+static int AppLayerProtoDetectTest11(void)
+{
+ AppLayerProtoDetectUnittestCtxBackup();
+ AppLayerProtoDetectSetup();
+
+ uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n";
+ uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n";
+ AppProto pm_results[ALPROTO_MAX];
+ memset(pm_results, 0, sizeof(pm_results));
+ Flow f;
+ memset(&f, 0x00, sizeof(f));
+ f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
+
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_TCP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_TCP, ALPROTO_HTTP1, "GET", 3, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_TCP, ALPROTO_HTTP1, "PUT", 3, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_TCP, ALPROTO_HTTP1, "POST", 4, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_TCP, ALPROTO_HTTP1, "TRACE", 5, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_TCP, ALPROTO_HTTP1, "OPTIONS", 7, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_TCP, ALPROTO_HTTP1, "CONNECT", 7, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_TCP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOCLIENT);
+
+ AppLayerProtoDetectPrepareState();
+ /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
+ * it sets internal structures which depends on the above function. */
+ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread();
+ FAIL_IF_NULL(alpd_tctx);
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 7);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map == NULL);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL);
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[0]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[1]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[2]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[3]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[4]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[5]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[6]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP1);
+
+ bool rdir = false;
+ uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
+ &f, l7data, sizeof(l7data), STREAM_TOSERVER,
+ pm_results, &rdir);
+ FAIL_IF(cnt != 1);
+ FAIL_IF(pm_results[0] != ALPROTO_HTTP1);
+
+ memset(pm_results, 0, sizeof(pm_results));
+ cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
+ &f, l7data_resp, sizeof(l7data_resp), STREAM_TOCLIENT,
+ pm_results, &rdir);
+ FAIL_IF(cnt != 1);
+ FAIL_IF(pm_results[0] != ALPROTO_HTTP1);
+
+ AppLayerProtoDetectDestroyCtxThread(alpd_tctx);
+ AppLayerProtoDetectDeSetup();
+ AppLayerProtoDetectUnittestCtxRestore();
+ PASS;
+}
+
+/**
+ * \test AlpProtoSignature test
+ */
+static int AppLayerProtoDetectTest12(void)
+{
+ AppLayerProtoDetectUnittestCtxBackup();
+ AppLayerProtoDetectSetup();
+
+ int r = 0;
+
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_TCP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOSERVER);
+ if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].head == NULL ||
+ alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL)
+ {
+ printf("failure 1\n");
+ goto end;
+ }
+
+ AppLayerProtoDetectPrepareState();
+ if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 1) {
+ printf("failure 2\n");
+ goto end;
+ }
+ if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].head != NULL ||
+ alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map == NULL)
+ {
+ printf("failure 3\n");
+ goto end;
+ }
+ if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[0]->alproto != ALPROTO_HTTP1) {
+ printf("failure 4\n");
+ goto end;
+ }
+ if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[0]->cd->id != 0) {
+ printf("failure 5\n");
+ goto end;
+ }
+ if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[0]->next != NULL) {
+ printf("failure 6\n");
+ goto end;
+ }
+
+ r = 1;
+
+ end:
+ AppLayerProtoDetectDeSetup();
+ AppLayerProtoDetectUnittestCtxRestore();
+ return r;
+}
+
+/**
+ * \test What about if we add some sigs only for udp but call for tcp?
+ * It should not detect any proto
+ */
+static int AppLayerProtoDetectTest13(void)
+{
+ AppLayerProtoDetectUnittestCtxBackup();
+ AppLayerProtoDetectSetup();
+
+ uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n";
+ uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n";
+ AppProto pm_results[ALPROTO_MAX];
+
+ Flow f;
+ memset(&f, 0x00, sizeof(f));
+ f.protomap = FlowGetProtoMapping(IPPROTO_TCP);
+
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "GET", 3, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "PUT", 3, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "POST", 4, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "TRACE", 5, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "OPTIONS", 7, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "CONNECT", 7, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOCLIENT);
+
+ AppLayerProtoDetectPrepareState();
+ /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
+ * it sets internal structures which depends on the above function. */
+ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread();
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].max_pat_id != 7);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].max_pat_id != 1);
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[0]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[1]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[2]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[3]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[4]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[5]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[6]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP1);
+
+ memset(pm_results, 0, sizeof(pm_results));
+ bool rdir = false;
+ uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
+ &f, l7data, sizeof(l7data), STREAM_TOSERVER,
+ pm_results, &rdir);
+ FAIL_IF(cnt != 0);
+
+ memset(pm_results, 0, sizeof(pm_results));
+ cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
+ &f, l7data_resp, sizeof(l7data_resp), STREAM_TOCLIENT,
+ pm_results, &rdir);
+ FAIL_IF(cnt != 0);
+
+ AppLayerProtoDetectDestroyCtxThread(alpd_tctx);
+ AppLayerProtoDetectDeSetup();
+ AppLayerProtoDetectUnittestCtxRestore();
+ PASS;
+}
+
+/**
+ * \test What about if we add some sigs only for udp calling it for UDP?
+ * It should detect ALPROTO_HTTP1 (over udp). This is just a check
+ * to ensure that TCP/UDP differences work correctly.
+ */
+static int AppLayerProtoDetectTest14(void)
+{
+ AppLayerProtoDetectUnittestCtxBackup();
+ AppLayerProtoDetectSetup();
+
+ uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n";
+ uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n";
+ AppProto pm_results[ALPROTO_MAX];
+ uint32_t cnt;
+ Flow f;
+ memset(&f, 0x00, sizeof(f));
+ f.protomap = FlowGetProtoMapping(IPPROTO_UDP);
+
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "GET", 3, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "PUT", 3, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "POST", 4, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "TRACE", 5, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "OPTIONS", 7, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "CONNECT", 7, 0, STREAM_TOSERVER);
+ AppLayerProtoDetectPMRegisterPatternCS(
+ IPPROTO_UDP, ALPROTO_HTTP1, "HTTP", 4, 0, STREAM_TOCLIENT);
+
+ AppLayerProtoDetectPrepareState();
+ /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since
+ * it sets internal structures which depends on the above function. */
+ AppLayerProtoDetectThreadCtx *alpd_tctx = AppLayerProtoDetectGetCtxThread();
+ FAIL_IF_NULL(alpd_tctx);
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].max_pat_id != 7);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].max_pat_id != 1);
+
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[0]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[1]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[2]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[3]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[4]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[5]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[6]->alproto != ALPROTO_HTTP1);
+ FAIL_IF(alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP1);
+
+ memset(pm_results, 0, sizeof(pm_results));
+ bool rdir = false;
+ cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
+ &f, l7data, sizeof(l7data), STREAM_TOSERVER,
+ pm_results, &rdir);
+ FAIL_IF(cnt != 1);
+ FAIL_IF(pm_results[0] != ALPROTO_HTTP1);
+
+ memset(pm_results, 0, sizeof(pm_results));
+ cnt = AppLayerProtoDetectPMGetProto(alpd_tctx,
+ &f, l7data_resp, sizeof(l7data_resp), STREAM_TOCLIENT,
+ pm_results, &rdir);
+ FAIL_IF(cnt != 1);
+ FAIL_IF(pm_results[0] != ALPROTO_HTTP1);
+
+ AppLayerProtoDetectDestroyCtxThread(alpd_tctx);
+ AppLayerProtoDetectDeSetup();
+ AppLayerProtoDetectUnittestCtxRestore();
+ PASS;
+}
+
+typedef struct AppLayerProtoDetectPPTestDataElement_ {
+ const char *alproto_name;
+ AppProto alproto;
+ uint16_t port;
+ uint32_t alproto_mask;
+ uint32_t min_depth;
+ uint32_t max_depth;
+} AppLayerProtoDetectPPTestDataElement;
+
+typedef struct AppLayerProtoDetectPPTestDataPort_ {
+ uint16_t port;
+ uint32_t alproto_mask;
+ uint16_t dp_max_depth;
+ uint16_t sp_max_depth;
+
+ AppLayerProtoDetectPPTestDataElement *toserver_element;
+ AppLayerProtoDetectPPTestDataElement *toclient_element;
+ int ts_no_of_element;
+ int tc_no_of_element;
+} AppLayerProtoDetectPPTestDataPort;
+
+
+typedef struct AppLayerProtoDetectPPTestDataIPProto_ {
+ uint8_t ipproto;
+
+ AppLayerProtoDetectPPTestDataPort *port;
+ int no_of_port;
+} AppLayerProtoDetectPPTestDataIPProto;
+
+static int AppLayerProtoDetectPPTestData(AppLayerProtoDetectProbingParser *pp,
+ AppLayerProtoDetectPPTestDataIPProto *ip_proto,
+ int no_of_ip_proto)
+{
+ int result = 0;
+ int i = -1, j = -1 , k = -1;
+#ifdef DEBUG
+ int dir = 0;
+#endif
+ for (i = 0; i < no_of_ip_proto; i++, pp = pp->next) {
+ if (pp->ipproto != ip_proto[i].ipproto)
+ goto end;
+
+ AppLayerProtoDetectProbingParserPort *pp_port = pp->port;
+ for (k = 0; k < ip_proto[i].no_of_port; k++, pp_port = pp_port->next) {
+ if (pp_port->port != ip_proto[i].port[k].port)
+ goto end;
+ if (pp_port->alproto_mask != ip_proto[i].port[k].alproto_mask)
+ goto end;
+ if (pp_port->alproto_mask != ip_proto[i].port[k].alproto_mask)
+ goto end;
+ if (pp_port->dp_max_depth != ip_proto[i].port[k].dp_max_depth)
+ goto end;
+ if (pp_port->sp_max_depth != ip_proto[i].port[k].sp_max_depth)
+ goto end;
+
+ AppLayerProtoDetectProbingParserElement *pp_element = pp_port->dp;
+#ifdef DEBUG
+ dir = 0;
+#endif
+ for (j = 0 ; j < ip_proto[i].port[k].ts_no_of_element;
+ j++, pp_element = pp_element->next) {
+
+ if (pp_element->alproto != ip_proto[i].port[k].toserver_element[j].alproto) {
+ goto end;
+ }
+ if (pp_element->port != ip_proto[i].port[k].toserver_element[j].port) {
+ goto end;
+ }
+ if (pp_element->alproto_mask != ip_proto[i].port[k].toserver_element[j].alproto_mask) {
+ goto end;
+ }
+ if (pp_element->min_depth != ip_proto[i].port[k].toserver_element[j].min_depth) {
+ goto end;
+ }
+ if (pp_element->max_depth != ip_proto[i].port[k].toserver_element[j].max_depth) {
+ goto end;
+ }
+ } /* for */
+ if (pp_element != NULL)
+ goto end;
+
+ pp_element = pp_port->sp;
+#ifdef DEBUG
+ dir = 1;
+#endif
+ for (j = 0 ; j < ip_proto[i].port[k].tc_no_of_element; j++, pp_element = pp_element->next) {
+ if (pp_element->alproto != ip_proto[i].port[k].toclient_element[j].alproto) {
+ goto end;
+ }
+ if (pp_element->port != ip_proto[i].port[k].toclient_element[j].port) {
+ goto end;
+ }
+ if (pp_element->alproto_mask != ip_proto[i].port[k].toclient_element[j].alproto_mask) {
+ goto end;
+ }
+ if (pp_element->min_depth != ip_proto[i].port[k].toclient_element[j].min_depth) {
+ goto end;
+ }
+ if (pp_element->max_depth != ip_proto[i].port[k].toclient_element[j].max_depth) {
+ goto end;
+ }
+ } /* for */
+ if (pp_element != NULL)
+ goto end;
+ }
+ if (pp_port != NULL)
+ goto end;
+ }
+ if (pp != NULL)
+ goto end;
+
+ result = 1;
+ end:
+#ifdef DEBUG
+ printf("i = %d, k = %d, j = %d(%s)\n", i, k, j, (dir == 0) ? "ts" : "tc");
+#endif
+ return result;
+}
+
+static uint16_t ProbingParserDummyForTesting(Flow *f, uint8_t direction,
+ const uint8_t *input,
+ uint32_t input_len, uint8_t *rdir)
+{
+ return 0;
+}
+
+static int AppLayerProtoDetectTest15(void)
+{
+ AppLayerProtoDetectUnittestCtxBackup();
+ AppLayerProtoDetectSetup();
+
+ int result = 0;
+
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_HTTP1, 5, 8, STREAM_TOSERVER,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "80",
+ ALPROTO_SMB,
+ 5, 6,
+ STREAM_TOSERVER,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "80",
+ ALPROTO_FTP,
+ 7, 10,
+ STREAM_TOSERVER,
+ ProbingParserDummyForTesting, NULL);
+
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "81",
+ ALPROTO_DCERPC,
+ 9, 10,
+ STREAM_TOSERVER,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "81",
+ ALPROTO_FTP,
+ 7, 15,
+ STREAM_TOSERVER,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "0",
+ ALPROTO_SMTP,
+ 12, 0,
+ STREAM_TOSERVER,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "0",
+ ALPROTO_TLS,
+ 12, 18,
+ STREAM_TOSERVER,
+ ProbingParserDummyForTesting, NULL);
+
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "85",
+ ALPROTO_DCERPC,
+ 9, 10,
+ STREAM_TOSERVER,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "85",
+ ALPROTO_FTP,
+ 7, 15,
+ STREAM_TOSERVER,
+ ProbingParserDummyForTesting, NULL);
+ result = 1;
+
+ AppLayerProtoDetectPPRegister(IPPROTO_UDP,
+ "85",
+ ALPROTO_IMAP,
+ 12, 23,
+ STREAM_TOSERVER,
+ ProbingParserDummyForTesting, NULL);
+
+ /* toclient */
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "0",
+ ALPROTO_JABBER,
+ 12, 23,
+ STREAM_TOCLIENT,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "0",
+ ALPROTO_IRC,
+ 12, 14,
+ STREAM_TOCLIENT,
+ ProbingParserDummyForTesting, NULL);
+
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "85",
+ ALPROTO_DCERPC,
+ 9, 10,
+ STREAM_TOCLIENT,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "81",
+ ALPROTO_FTP,
+ 7, 15,
+ STREAM_TOCLIENT,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "0",
+ ALPROTO_TLS,
+ 12, 18,
+ STREAM_TOCLIENT,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP, "80", ALPROTO_HTTP1, 5, 8, STREAM_TOCLIENT,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "81",
+ ALPROTO_DCERPC,
+ 9, 10,
+ STREAM_TOCLIENT,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "90",
+ ALPROTO_FTP,
+ 7, 15,
+ STREAM_TOCLIENT,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "80",
+ ALPROTO_SMB,
+ 5, 6,
+ STREAM_TOCLIENT,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_UDP,
+ "85",
+ ALPROTO_IMAP,
+ 12, 23,
+ STREAM_TOCLIENT,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "0",
+ ALPROTO_SMTP,
+ 12, 17,
+ STREAM_TOCLIENT,
+ ProbingParserDummyForTesting, NULL);
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "80",
+ ALPROTO_FTP,
+ 7, 10,
+ STREAM_TOCLIENT,
+ ProbingParserDummyForTesting, NULL);
+
+ AppLayerProtoDetectPPTestDataElement element_ts_80[] = {
+ { "http", ALPROTO_HTTP1, 80, 1 << ALPROTO_HTTP1, 5, 8 },
+ { "smb", ALPROTO_SMB, 80, 1 << ALPROTO_SMB, 5, 6 },
+ { "ftp", ALPROTO_FTP, 80, 1 << ALPROTO_FTP, 7, 10 },
+ { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 0 },
+ { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 },
+ { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 25 },
+ { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 },
+ };
+ AppLayerProtoDetectPPTestDataElement element_tc_80[] = { { "http", ALPROTO_HTTP1, 80,
+ 1 << ALPROTO_HTTP1, 5, 8 },
+ { "smb", ALPROTO_SMB, 80, 1 << ALPROTO_SMB, 5, 6 },
+ { "ftp", ALPROTO_FTP, 80, 1 << ALPROTO_FTP, 7, 10 },
+ { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 },
+ { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 14 },
+ { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 },
+ { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 17 } };
+
+ AppLayerProtoDetectPPTestDataElement element_ts_81[] = {
+ { "dcerpc", ALPROTO_DCERPC, 81, 1 << ALPROTO_DCERPC, 9, 10 },
+ { "ftp", ALPROTO_FTP, 81, 1 << ALPROTO_FTP, 7, 15 },
+ { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 0 },
+ { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 },
+ { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 25 },
+ { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 },
+ };
+ AppLayerProtoDetectPPTestDataElement element_tc_81[] = {
+ { "ftp", ALPROTO_FTP, 81, 1 << ALPROTO_FTP, 7, 15 },
+ { "dcerpc", ALPROTO_DCERPC, 81, 1 << ALPROTO_DCERPC, 9, 10 },
+ { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 },
+ { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 14 },
+ { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 },
+ { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 17 }
+ };
+
+ AppLayerProtoDetectPPTestDataElement element_ts_85[] = {
+ { "dcerpc", ALPROTO_DCERPC, 85, 1 << ALPROTO_DCERPC, 9, 10 },
+ { "ftp", ALPROTO_FTP, 85, 1 << ALPROTO_FTP, 7, 15 },
+ { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 0 },
+ { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 },
+ { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 25 },
+ { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 },
+ };
+ AppLayerProtoDetectPPTestDataElement element_tc_85[] = {
+ { "dcerpc", ALPROTO_DCERPC, 85, 1 << ALPROTO_DCERPC, 9, 10 },
+ { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 },
+ { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 14 },
+ { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 },
+ { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 17 }
+ };
+
+ AppLayerProtoDetectPPTestDataElement element_ts_90[] = {
+ { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 0 },
+ { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 },
+ { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 25 },
+ { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 },
+ };
+ AppLayerProtoDetectPPTestDataElement element_tc_90[] = {
+ { "ftp", ALPROTO_FTP, 90, 1 << ALPROTO_FTP, 7, 15 },
+ { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 },
+ { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 14 },
+ { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 },
+ { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 17 }
+ };
+
+ AppLayerProtoDetectPPTestDataElement element_ts_0[] = {
+ { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 0 },
+ { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 },
+ { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 25 },
+ { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 },
+ };
+ AppLayerProtoDetectPPTestDataElement element_tc_0[] = {
+ { "jabber", ALPROTO_JABBER, 0, 1 << ALPROTO_JABBER, 12, 23 },
+ { "irc", ALPROTO_IRC, 0, 1 << ALPROTO_IRC, 12, 14 },
+ { "tls", ALPROTO_TLS, 0, 1 << ALPROTO_TLS, 12, 18 },
+ { "smtp", ALPROTO_SMTP, 0, 1 << ALPROTO_SMTP, 12, 17 }
+ };
+
+
+ AppLayerProtoDetectPPTestDataElement element_ts_85_udp[] = {
+ { "imap", ALPROTO_IMAP, 85, 1 << ALPROTO_IMAP, 12, 23 },
+ };
+ AppLayerProtoDetectPPTestDataElement element_tc_85_udp[] = {
+ { "imap", ALPROTO_IMAP, 85, 1 << ALPROTO_IMAP, 12, 23 },
+ };
+
+ AppLayerProtoDetectPPTestDataPort ports_tcp[] = {
+ {
+ 80,
+ ((1 << ALPROTO_HTTP1) | (1 << ALPROTO_SMB) | (1 << ALPROTO_FTP) |
+ (1 << ALPROTO_SMTP) | (1 << ALPROTO_TLS) | (1 << ALPROTO_IRC) |
+ (1 << ALPROTO_JABBER)),
+ ((1 << ALPROTO_HTTP1) | (1 << ALPROTO_SMB) | (1 << ALPROTO_FTP) |
+ (1 << ALPROTO_JABBER) | (1 << ALPROTO_IRC) | (1 << ALPROTO_TLS) |
+ (1 << ALPROTO_SMTP)),
+ 23,
+ element_ts_80,
+ element_tc_80,
+ sizeof(element_ts_80) / sizeof(AppLayerProtoDetectPPTestDataElement),
+ sizeof(element_tc_80) / sizeof(AppLayerProtoDetectPPTestDataElement),
+ },
+ {
+ 81,
+ ((1 << ALPROTO_DCERPC) | (1 << ALPROTO_FTP) | (1 << ALPROTO_SMTP) |
+ (1 << ALPROTO_TLS) | (1 << ALPROTO_IRC) | (1 << ALPROTO_JABBER)),
+ ((1 << ALPROTO_FTP) | (1 << ALPROTO_DCERPC) | (1 << ALPROTO_JABBER) |
+ (1 << ALPROTO_IRC) | (1 << ALPROTO_TLS) | (1 << ALPROTO_SMTP)),
+ 23,
+ element_ts_81,
+ element_tc_81,
+ sizeof(element_ts_81) / sizeof(AppLayerProtoDetectPPTestDataElement),
+ sizeof(element_tc_81) / sizeof(AppLayerProtoDetectPPTestDataElement),
+ },
+ { 85,
+ ((1 << ALPROTO_DCERPC) | (1 << ALPROTO_FTP) | (1 << ALPROTO_SMTP) |
+ (1 << ALPROTO_TLS) | (1 << ALPROTO_IRC) | (1 << ALPROTO_JABBER)),
+ ((1 << ALPROTO_DCERPC) | (1 << ALPROTO_JABBER) | (1 << ALPROTO_IRC) |
+ (1 << ALPROTO_TLS) | (1 << ALPROTO_SMTP)),
+ 23, element_ts_85, element_tc_85,
+ sizeof(element_ts_85) / sizeof(AppLayerProtoDetectPPTestDataElement),
+ sizeof(element_tc_85) / sizeof(AppLayerProtoDetectPPTestDataElement) },
+ { 90,
+ ((1 << ALPROTO_SMTP) | (1 << ALPROTO_TLS) | (1 << ALPROTO_IRC) |
+ (1 << ALPROTO_JABBER)),
+ ((1 << ALPROTO_FTP) | (1 << ALPROTO_JABBER) | (1 << ALPROTO_IRC) |
+ (1 << ALPROTO_TLS) | (1 << ALPROTO_SMTP)),
+ 23, element_ts_90, element_tc_90,
+ sizeof(element_ts_90) / sizeof(AppLayerProtoDetectPPTestDataElement),
+ sizeof(element_tc_90) / sizeof(AppLayerProtoDetectPPTestDataElement) },
+ { 0,
+ ((1 << ALPROTO_SMTP) | (1 << ALPROTO_TLS) | (1 << ALPROTO_IRC) |
+ (1 << ALPROTO_JABBER)),
+ ((1 << ALPROTO_JABBER) | (1 << ALPROTO_IRC) | (1 << ALPROTO_TLS) |
+ (1 << ALPROTO_SMTP)),
+ 23, element_ts_0, element_tc_0,
+ sizeof(element_ts_0) / sizeof(AppLayerProtoDetectPPTestDataElement),
+ sizeof(element_tc_0) / sizeof(AppLayerProtoDetectPPTestDataElement) }
+ };
+
+ AppLayerProtoDetectPPTestDataPort ports_udp[] = {
+ { 85,
+ (1 << ALPROTO_IMAP),
+ (1 << ALPROTO_IMAP),
+ 23,
+ element_ts_85_udp, element_tc_85_udp,
+ sizeof(element_ts_85_udp) / sizeof(AppLayerProtoDetectPPTestDataElement),
+ sizeof(element_tc_85_udp) / sizeof(AppLayerProtoDetectPPTestDataElement),
+ },
+ };
+
+ AppLayerProtoDetectPPTestDataIPProto ip_proto[] = {
+ { IPPROTO_TCP,
+ ports_tcp,
+ sizeof(ports_tcp) / sizeof(AppLayerProtoDetectPPTestDataPort),
+ },
+ { IPPROTO_UDP,
+ ports_udp,
+ sizeof(ports_udp) / sizeof(AppLayerProtoDetectPPTestDataPort),
+ },
+ };
+
+
+ if (AppLayerProtoDetectPPTestData(alpd_ctx.ctx_pp, ip_proto,
+ sizeof(ip_proto) / sizeof(AppLayerProtoDetectPPTestDataIPProto)) == 0) {
+ goto end;
+ }
+ result = 1;
+
+ end:
+ AppLayerProtoDetectDeSetup();
+ AppLayerProtoDetectUnittestCtxRestore();
+ return result;
+}
+
+
+/** \test test if the engine detect the proto and match with it */
+static int AppLayerProtoDetectTest16(void)
+{
+ int result = 0;
+ Flow *f = NULL;
+ HtpState *http_state = NULL;
+ uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n"
+ "User-Agent: Mozilla/1.0\r\n"
+ "Cookie: hellocatch\r\n\r\n";
+ uint32_t http_buf1_len = sizeof(http_buf1) - 1;
+ TcpSession ssn;
+ Packet *p = NULL;
+ Signature *s = NULL;
+ ThreadVars tv;
+ DetectEngineThreadCtx *det_ctx = NULL;
+ DetectEngineCtx *de_ctx = NULL;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&tv, 0, sizeof(ThreadVars));
+ memset(&ssn, 0, sizeof(TcpSession));
+
+ p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
+ if (p == NULL) {
+ printf("packet setup failed: ");
+ goto end;
+ }
+
+ f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
+ if (f == NULL) {
+ printf("flow setup failed: ");
+ goto end;
+ }
+ f->protoctx = &ssn;
+ f->proto = IPPROTO_TCP;
+ p->flow = f;
+
+ p->flowflags |= FLOW_PKT_TOSERVER;
+ p->flowflags |= FLOW_PKT_ESTABLISHED;
+ p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
+
+ f->alproto = ALPROTO_HTTP1;
+
+ StreamTcpInitConfig(true);
+
+ de_ctx = DetectEngineCtxInit();
+ if (de_ctx == NULL) {
+ goto end;
+ }
+ de_ctx->flags |= DE_QUIET;
+
+ s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any "
+ "(msg:\"Test content option\"; "
+ "sid:1;)");
+ if (s == NULL) {
+ goto end;
+ }
+
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+ int r = AppLayerParserParse(
+ NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, http_buf1, http_buf1_len);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ goto end;
+ }
+
+ http_state = f->alstate;
+ if (http_state == NULL) {
+ printf("no http state: ");
+ goto end;
+ }
+
+ /* do detect */
+ SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+
+ if (!PacketAlertCheck(p, 1)) {
+ printf("sig 1 didn't alert, but it should: ");
+ goto end;
+ }
+ result = 1;
+ end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ if (det_ctx != NULL)
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ if (de_ctx != NULL)
+ SigGroupCleanup(de_ctx);
+ if (de_ctx != NULL)
+ DetectEngineCtxFree(de_ctx);
+
+ StreamTcpFreeConfig(true);
+
+ UTHFreePackets(&p, 1);
+ UTHFreeFlow(f);
+ return result;
+}
+
+/** \test test if the engine detect the proto on a non standar port
+ * and match with it */
+static int AppLayerProtoDetectTest17(void)
+{
+ int result = 0;
+ Flow *f = NULL;
+ HtpState *http_state = NULL;
+ uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n"
+ "User-Agent: Mozilla/1.0\r\n"
+ "Cookie: hellocatch\r\n\r\n";
+ uint32_t http_buf1_len = sizeof(http_buf1) - 1;
+ TcpSession ssn;
+ Packet *p = NULL;
+ Signature *s = NULL;
+ ThreadVars tv;
+ DetectEngineThreadCtx *det_ctx = NULL;
+ DetectEngineCtx *de_ctx = NULL;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&tv, 0, sizeof(ThreadVars));
+ memset(&ssn, 0, sizeof(TcpSession));
+
+ p = UTHBuildPacketSrcDstPorts(http_buf1, http_buf1_len, IPPROTO_TCP, 12345, 88);
+
+ f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
+ if (f == NULL)
+ goto end;
+ f->protoctx = &ssn;
+ f->proto = IPPROTO_TCP;
+ p->flow = f;
+ p->flowflags |= FLOW_PKT_TOSERVER;
+ p->flowflags |= FLOW_PKT_ESTABLISHED;
+ p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
+ f->alproto = ALPROTO_HTTP1;
+
+ StreamTcpInitConfig(true);
+
+ de_ctx = DetectEngineCtxInit();
+ if (de_ctx == NULL) {
+ goto end;
+ }
+ de_ctx->flags |= DE_QUIET;
+
+ s = de_ctx->sig_list = SigInit(de_ctx, "alert http any !80 -> any any "
+ "(msg:\"http over non standar port\"; "
+ "sid:1;)");
+ if (s == NULL) {
+ goto end;
+ }
+
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+ int r = AppLayerParserParse(
+ NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, http_buf1, http_buf1_len);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ goto end;
+ }
+
+ http_state = f->alstate;
+ if (http_state == NULL) {
+ printf("no http state: ");
+ goto end;
+ }
+
+ /* do detect */
+ SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+
+ if (!PacketAlertCheck(p, 1)) {
+ printf("sig 1 didn't alert, but it should: ");
+ goto end;
+ }
+
+ result = 1;
+
+ end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ if (det_ctx != NULL)
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ if (de_ctx != NULL)
+ SigGroupCleanup(de_ctx);
+ if (de_ctx != NULL)
+ DetectEngineCtxFree(de_ctx);
+
+ StreamTcpFreeConfig(true);
+
+ UTHFreePackets(&p, 1);
+ UTHFreeFlow(f);
+ return result;
+}
+
+/** \test test if the engine detect the proto and doesn't match
+ * because the sig expects another proto (ex ftp)*/
+static int AppLayerProtoDetectTest18(void)
+{
+ int result = 0;
+ Flow *f = NULL;
+ HtpState *http_state = NULL;
+ uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n"
+ "User-Agent: Mozilla/1.0\r\n"
+ "Cookie: hellocatch\r\n\r\n";
+ uint32_t http_buf1_len = sizeof(http_buf1) - 1;
+ TcpSession ssn;
+ Packet *p = NULL;
+ Signature *s = NULL;
+ ThreadVars tv;
+ DetectEngineThreadCtx *det_ctx = NULL;
+ DetectEngineCtx *de_ctx = NULL;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&tv, 0, sizeof(ThreadVars));
+ memset(&ssn, 0, sizeof(TcpSession));
+
+ p = UTHBuildPacket(http_buf1, http_buf1_len, IPPROTO_TCP);
+
+ f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
+ if (f == NULL)
+ goto end;
+ f->protoctx = &ssn;
+ f->proto = IPPROTO_TCP;
+ p->flow = f;
+ p->flowflags |= FLOW_PKT_TOSERVER;
+ p->flowflags |= FLOW_PKT_ESTABLISHED;
+ p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
+ f->alproto = ALPROTO_HTTP1;
+
+ StreamTcpInitConfig(true);
+
+ de_ctx = DetectEngineCtxInit();
+ if (de_ctx == NULL) {
+ goto end;
+ }
+ de_ctx->flags |= DE_QUIET;
+
+ s = de_ctx->sig_list = SigInit(de_ctx, "alert ftp any any -> any any "
+ "(msg:\"Test content option\"; "
+ "sid:1;)");
+ if (s == NULL) {
+ goto end;
+ }
+
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+ int r = AppLayerParserParse(
+ NULL, alp_tctx, f, ALPROTO_HTTP1, STREAM_TOSERVER, http_buf1, http_buf1_len);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ goto end;
+ }
+
+ http_state = f->alstate;
+ if (http_state == NULL) {
+ printf("no http state: ");
+ goto end;
+ }
+
+ /* do detect */
+ SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+
+ if (PacketAlertCheck(p, 1)) {
+ printf("sig 1 alerted, but it should not (it's not ftp): ");
+ goto end;
+ }
+
+ result = 1;
+ end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ if (det_ctx != NULL)
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ if (de_ctx != NULL)
+ SigGroupCleanup(de_ctx);
+ if (de_ctx != NULL)
+ DetectEngineCtxFree(de_ctx);
+
+ StreamTcpFreeConfig(true);
+
+ UTHFreePackets(&p, 1);
+ UTHFreeFlow(f);
+ return result;
+}
+
+/** \test test if the engine detect the proto and doesn't match
+ * because the packet has another proto (ex ftp) */
+static int AppLayerProtoDetectTest19(void)
+{
+ int result = 0;
+ Flow *f = NULL;
+ uint8_t http_buf1[] = "MPUT one\r\n";
+ uint32_t http_buf1_len = sizeof(http_buf1) - 1;
+ TcpSession ssn;
+ Packet *p = NULL;
+ Signature *s = NULL;
+ ThreadVars tv;
+ DetectEngineThreadCtx *det_ctx = NULL;
+ DetectEngineCtx *de_ctx = NULL;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&tv, 0, sizeof(ThreadVars));
+ memset(&ssn, 0, sizeof(TcpSession));
+
+ p = UTHBuildPacketSrcDstPorts(http_buf1, http_buf1_len, IPPROTO_TCP, 12345, 88);
+
+ f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
+ if (f == NULL)
+ goto end;
+ f->protoctx = &ssn;
+ f->proto = IPPROTO_TCP;
+ p->flow = f;
+ p->flowflags |= FLOW_PKT_TOSERVER;
+ p->flowflags |= FLOW_PKT_ESTABLISHED;
+ p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
+ f->alproto = ALPROTO_FTP;
+
+ StreamTcpInitConfig(true);
+
+ de_ctx = DetectEngineCtxInit();
+ if (de_ctx == NULL) {
+ goto end;
+ }
+ de_ctx->flags |= DE_QUIET;
+
+ s = de_ctx->sig_list = SigInit(de_ctx, "alert http any !80 -> any any "
+ "(msg:\"http over non standar port\"; "
+ "sid:1;)");
+ if (s == NULL) {
+ goto end;
+ }
+
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+ int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_FTP,
+ STREAM_TOSERVER, http_buf1, http_buf1_len);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ goto end;
+ }
+
+ /* do detect */
+ SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+
+ if (PacketAlertCheck(p, 1)) {
+ printf("sig 1 alerted, but it should not (it's ftp): ");
+ goto end;
+ }
+
+ result = 1;
+
+ end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ if (det_ctx != NULL)
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ if (de_ctx != NULL)
+ SigGroupCleanup(de_ctx);
+ if (de_ctx != NULL)
+ DetectEngineCtxFree(de_ctx);
+
+ StreamTcpFreeConfig(true);
+ UTHFreePackets(&p, 1);
+ UTHFreeFlow(f);
+ return result;
+}
+
+void AppLayerProtoDetectUnittestsRegister(void)
+{
+ SCEnter();
+
+ UtRegisterTest("AppLayerProtoDetectTest01", AppLayerProtoDetectTest01);
+ UtRegisterTest("AppLayerProtoDetectTest02", AppLayerProtoDetectTest02);
+ UtRegisterTest("AppLayerProtoDetectTest03", AppLayerProtoDetectTest03);
+ UtRegisterTest("AppLayerProtoDetectTest04", AppLayerProtoDetectTest04);
+ UtRegisterTest("AppLayerProtoDetectTest05", AppLayerProtoDetectTest05);
+ UtRegisterTest("AppLayerProtoDetectTest06", AppLayerProtoDetectTest06);
+ UtRegisterTest("AppLayerProtoDetectTest07", AppLayerProtoDetectTest07);
+ UtRegisterTest("AppLayerProtoDetectTest08", AppLayerProtoDetectTest08);
+ UtRegisterTest("AppLayerProtoDetectTest09", AppLayerProtoDetectTest09);
+ UtRegisterTest("AppLayerProtoDetectTest10", AppLayerProtoDetectTest10);
+ UtRegisterTest("AppLayerProtoDetectTest11", AppLayerProtoDetectTest11);
+ UtRegisterTest("AppLayerProtoDetectTest12", AppLayerProtoDetectTest12);
+ UtRegisterTest("AppLayerProtoDetectTest13", AppLayerProtoDetectTest13);
+ UtRegisterTest("AppLayerProtoDetectTest14", AppLayerProtoDetectTest14);
+ UtRegisterTest("AppLayerProtoDetectTest15", AppLayerProtoDetectTest15);
+ UtRegisterTest("AppLayerProtoDetectTest16", AppLayerProtoDetectTest16);
+ UtRegisterTest("AppLayerProtoDetectTest17", AppLayerProtoDetectTest17);
+ UtRegisterTest("AppLayerProtoDetectTest18", AppLayerProtoDetectTest18);
+ UtRegisterTest("AppLayerProtoDetectTest19", AppLayerProtoDetectTest19);
+
+ SCReturn;
+}
+
+#endif /* UNITTESTS */