diff options
author | 2015-09-09 22:21:41 -0700 | |
---|---|---|
committer | 2015-09-09 22:21:41 -0700 | |
commit | 8879b125d26e8db1a5633de5a9c692eb2d1c4f83 (patch) | |
tree | c7259d85a991b83dfa85ab2e339360669fc1f58e /framework/src/suricata/src/app-layer-detect-proto.c | |
parent | 13d05bc8458758ee39cb829098241e89616717ee (diff) |
suricata checkin based on commit id a4bce14770beee46a537eda3c3f6e8e8565d5d0a
Change-Id: I9a214fa0ee95e58fc640e50bd604dac7f42db48f
Diffstat (limited to 'framework/src/suricata/src/app-layer-detect-proto.c')
-rw-r--r-- | framework/src/suricata/src/app-layer-detect-proto.c | 3776 |
1 files changed, 3776 insertions, 0 deletions
diff --git a/framework/src/suricata/src/app-layer-detect-proto.c b/framework/src/suricata/src/app-layer-detect-proto.c new file mode 100644 index 00000000..ed029e5e --- /dev/null +++ b/framework/src/suricata/src/app-layer-detect-proto.c @@ -0,0 +1,3776 @@ +/* Copyright (C) 2007-2014 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 "debug.h" +#include "decode.h" +#include "threads.h" +#include "threadvars.h" +#include "tm-threads.h" + +#include "detect.h" +#include "detect-engine-port.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 "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 "conf.h" +#include "util-memcmp.h" +#include "util-spm.h" +#include "util-cuda.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; + /* \todo check if we can reduce the bottom 2 vars to uint16_t */ + /* the min length of data that has to be supplied to invoke the parser */ + uint32_t min_depth; + /* the max length of data after which this parser won't be invoked */ + uint32_t max_depth; + /* the probing parser function */ + ProbingParserFPtr ProbingParser; + + 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; + /* \todo Change this into a non-pointer */ + DetectContentData *cd; + struct AppLayerProtoDetectPMSignature_ *next; +} AppLayerProtoDetectPMSignature; + +typedef struct AppLayerProtoDetectPMCtx_ { + uint16_t 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; +} 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]; + + AppLayerProtoDetectProbingParser *ctx_pp; + + /* Indicates the protocols that have registered themselves + * for protocol detection. This table is independent of the + * ipproto. */ + char *alproto_names[ALPROTO_MAX]; +} AppLayerProtoDetectCtx; + +/** + * \brief The app layer protocol detection thread context. + */ +struct AppLayerProtoDetectThreadCtx_ { + PatternMatcherQueue pmq; + /* The value 2 is for direction(0 - toserver, 1 - toclient). */ + MpmThreadCtx mpm_tctx[FLOW_PROTO_DEFAULT][2]; +}; + +/* The global app layer proto detection context. */ +static AppLayerProtoDetectCtx alpd_ctx; + +/***** Static Internal Calls: Protocol Retrieval *****/ + +/** \internal + * \brief Handle SPM search for Signature */ +static AppProto AppLayerProtoDetectPMMatchSignature(const AppLayerProtoDetectPMSignature *s, + uint8_t *buf, uint16_t buflen, + uint8_t ipproto) +{ + SCEnter(); + AppProto proto = ALPROTO_UNKNOWN; + uint8_t *found = NULL; + + if (s->cd->offset > buflen) { + SCLogDebug("s->co->offset (%"PRIu16") > buflen (%"PRIu16")", + s->cd->offset, buflen); + goto end; + } + + if (s->cd->depth > buflen) { + SCLogDebug("s->co->depth (%"PRIu16") > buflen (%"PRIu16")", + s->cd->depth, buflen); + goto end; + } + + uint8_t *sbuf = buf + s->cd->offset; + uint16_t sbuflen = s->cd->depth - s->cd->offset; + SCLogDebug("s->co->offset (%"PRIu16") s->cd->depth (%"PRIu16")", + s->cd->offset, s->cd->depth); + + if (s->cd->flags & DETECT_CONTENT_NOCASE) + found = BoyerMooreNocase(s->cd->content, s->cd->content_len, sbuf, sbuflen, s->cd->bm_ctx); + else + found = BoyerMoore(s->cd->content, s->cd->content_len, sbuf, sbuflen, s->cd->bm_ctx); + if (found != NULL) + proto = s->alproto; + + end: + SCReturnUInt(proto); +} + +/** \internal + * \brief Run Pattern Sigs against buffer + * \param pm_results[out] AppProto array of size ALPROTO_MAX */ +static AppProto AppLayerProtoDetectPMGetProto(AppLayerProtoDetectThreadCtx *tctx, + Flow *f, + uint8_t *buf, uint16_t buflen, + uint8_t direction, + uint8_t ipproto, + AppProto *pm_results) +{ + SCEnter(); + + pm_results[0] = ALPROTO_UNKNOWN; + + AppLayerProtoDetectPMCtx *pm_ctx; + MpmThreadCtx *mpm_tctx; + uint16_t pm_matches = 0; + uint8_t cnt; + uint16_t searchlen; + + if (f->protomap >= FLOW_PROTO_DEFAULT) + return ALPROTO_UNKNOWN; + + if (direction & 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 (pm_ctx->mpm_ctx.pattern_cnt == 0) + goto end; + + searchlen = buflen; + if (searchlen > pm_ctx->max_len) + searchlen = pm_ctx->max_len; + + uint32_t search_cnt = 0; + + /* do the mpm search */ + 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) + goto end; + + /* 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 (cnt = 0; cnt < tctx->pmq.pattern_id_array_cnt; cnt++) { + const AppLayerProtoDetectPMSignature *s = pm_ctx->map[tctx->pmq.pattern_id_array[cnt]]; + while (s != NULL) { + AppProto proto = AppLayerProtoDetectPMMatchSignature(s, + buf, searchlen, ipproto); + + /* store each unique proto once */ + if (proto != ALPROTO_UNKNOWN && + !(pm_results_bf[proto / 8] & (1 << (proto % 8))) ) + { + pm_results[pm_matches++] = proto; + pm_results_bf[proto / 8] |= 1 << (proto % 8); + } + s = s->next; + } + } + + end: + PmqReset(&tctx->pmq); + if (buflen >= pm_ctx->max_len) + FLOW_SET_PM_DONE(f, direction); + SCReturnUInt(pm_matches); +} + +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 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, + uint8_t *buf, uint32_t buflen, + uint8_t ipproto, uint8_t direction) +{ + const AppLayerProtoDetectProbingParserPort *pp_port_dp = NULL; + const AppLayerProtoDetectProbingParserPort *pp_port_sp = NULL; + const AppLayerProtoDetectProbingParserElement *pe = NULL; + const AppLayerProtoDetectProbingParserElement *pe1 = NULL; + const AppLayerProtoDetectProbingParserElement *pe2 = NULL; + AppProto alproto = ALPROTO_UNKNOWN; + uint32_t *alproto_masks; + uint32_t mask = 0; + + if (direction & STREAM_TOSERVER) { + /* first try the destination port */ + pp_port_dp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, f->dp); + alproto_masks = &f->probing_parser_toserver_alproto_masks; + if (pp_port_dp != NULL) { + SCLogDebug("toserver - Probing parser found for destination port %"PRIu16, f->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, + f->dp); + } + + pp_port_sp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, f->sp); + if (pp_port_sp != NULL) { + SCLogDebug("toserver - Probing parser found for source port %"PRIu16, f->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, + f->sp); + } + } else { + /* first try the destination port */ + pp_port_dp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, f->dp); + alproto_masks = &f->probing_parser_toclient_alproto_masks; + if (pp_port_dp != NULL) { + SCLogDebug("toclient - Probing parser found for destination port %"PRIu16, f->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, + f->dp); + } + + pp_port_sp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, f->sp); + if (pp_port_sp != NULL) { + SCLogDebug("toclient - Probing parser found for source port %"PRIu16, f->sp); + + pe2 = pp_port_sp->sp; + } else { + SCLogDebug("toclient - No probing parser registered for source port %"PRIu16, + f->sp); + } + } + + if (pe1 == NULL && pe2 == NULL) { + SCLogDebug("%s - No probing parsers found for either port", + (direction & STREAM_TOSERVER) ? "toserver":"toclient"); + FLOW_SET_PP_DONE(f, direction); + goto end; + } + + /* run the parser(s) */ + pe = pe1; + while (pe != NULL) { + if ((buflen < pe->min_depth) || + (alproto_masks[0] & pe->alproto_mask)) { + pe = pe->next; + continue; + } + + alproto = pe->ProbingParser(buf, buflen, NULL); + if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED) + goto end; + if (alproto == ALPROTO_FAILED || + (pe->max_depth != 0 && buflen > pe->max_depth)) { + alproto_masks[0] |= pe->alproto_mask; + } + pe = pe->next; + } + pe = pe2; + while (pe != NULL) { + if ((buflen < pe->min_depth) || + (alproto_masks[0] & pe->alproto_mask)) { + pe = pe->next; + continue; + } + + alproto = pe->ProbingParser(buf, buflen, NULL); + if (alproto != ALPROTO_UNKNOWN && alproto != ALPROTO_FAILED) + goto end; + if (alproto == ALPROTO_FAILED || + (pe->max_depth != 0 && buflen > pe->max_depth)) { + alproto_masks[0] |= pe->alproto_mask; + } + pe = pe->next; + } + + /* get the mask we need for this direction */ + 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; + else + mask = 0; + + if (alproto_masks[0] == mask) { + FLOW_SET_PP_DONE(f, direction); + SCLogDebug("%s, mask is now %08x, needed %08x, so done", + (direction & STREAM_TOSERVER) ? "toserver":"toclient", alproto_masks[0], mask); + } else { + SCLogDebug("%s, mask is now %08x, need %08x", + (direction & STREAM_TOSERVER) ? "toserver":"toclient", alproto_masks[0], mask); + } + + end: + SCLogDebug("%s, mask is now %08x", + (direction & 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)) { + SCLogError(SC_ERR_ALPARSER, "Unknown protocol detected - %"PRIu16, + alproto); + exit(EXIT_FAILURE); + } + + SCReturnUInt(1 << 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, + uint16_t (*AppLayerProtoDetectProbingParser) + (uint8_t *input, uint32_t input_len, uint32_t *offset)) +{ + 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->ProbingParser = AppLayerProtoDetectProbingParser; + pe->next = NULL; + + if (max_depth != 0 && min_depth >= max_depth) { + SCLogError(SC_ERR_ALPARSER, "Invalid arguments sent to " + "register the probing parser. min_depth >= max_depth"); + goto error; + } + if (alproto <= ALPROTO_UNKNOWN || alproto >= ALPROTO_MAX) { + SCLogError(SC_ERR_ALPARSER, "Invalid arguments sent to register " + "the probing parser. Invalid alproto - %d", alproto); + goto error; + } + if (AppLayerProtoDetectProbingParser == NULL) { + SCLogError(SC_ERR_ALPARSER, "Invalid arguments sent to " + "register the probing parser. Probing parser func NULL"); + 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->ProbingParser = pe->ProbingParser; + new_pe->next = NULL; + + SCReturnPtr(new_pe, "AppLayerProtoDetectProbingParserElement"); +} + +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) { + + if (pp_pe->alproto == ALPROTO_HTTP) + printf(" alproto: ALPROTO_HTTP\n"); + else if (pp_pe->alproto == ALPROTO_FTP) + printf(" alproto: ALPROTO_FTP\n"); + else if (pp_pe->alproto == ALPROTO_SMTP) + printf(" alproto: ALPROTO_SMTP\n"); + else if (pp_pe->alproto == ALPROTO_TLS) + printf(" alproto: ALPROTO_TLS\n"); + else if (pp_pe->alproto == ALPROTO_SSH) + printf(" alproto: ALPROTO_SSH\n"); + else if (pp_pe->alproto == ALPROTO_IMAP) + printf(" alproto: ALPROTO_IMAP\n"); + else if (pp_pe->alproto == ALPROTO_MSN) + printf(" alproto: ALPROTO_MSN\n"); + else if (pp_pe->alproto == ALPROTO_JABBER) + printf(" alproto: ALPROTO_JABBER\n"); + else if (pp_pe->alproto == ALPROTO_SMB) + printf(" alproto: ALPROTO_SMB\n"); + else if (pp_pe->alproto == ALPROTO_SMB2) + printf(" alproto: ALPROTO_SMB2\n"); + else if (pp_pe->alproto == ALPROTO_DCERPC) + printf(" alproto: ALPROTO_DCERPC\n"); + else if (pp_pe->alproto == ALPROTO_IRC) + printf(" alproto: ALPROTO_IRC\n"); + else if (pp_pe->alproto == ALPROTO_DNS) + printf(" alproto: ALPROTO_DNS\n"); + else if (pp_pe->alproto == ALPROTO_MODBUS) + printf(" alproto: ALPROTO_MODBUS\n"); + else + printf("impossible\n"); + + 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) { + + if (pp_pe->alproto == ALPROTO_HTTP) + printf(" alproto: ALPROTO_HTTP\n"); + else if (pp_pe->alproto == ALPROTO_FTP) + printf(" alproto: ALPROTO_FTP\n"); + else if (pp_pe->alproto == ALPROTO_SMTP) + printf(" alproto: ALPROTO_SMTP\n"); + else if (pp_pe->alproto == ALPROTO_TLS) + printf(" alproto: ALPROTO_TLS\n"); + else if (pp_pe->alproto == ALPROTO_SSH) + printf(" alproto: ALPROTO_SSH\n"); + else if (pp_pe->alproto == ALPROTO_IMAP) + printf(" alproto: ALPROTO_IMAP\n"); + else if (pp_pe->alproto == ALPROTO_MSN) + printf(" alproto: ALPROTO_MSN\n"); + else if (pp_pe->alproto == ALPROTO_JABBER) + printf(" alproto: ALPROTO_JABBER\n"); + else if (pp_pe->alproto == ALPROTO_SMB) + printf(" alproto: ALPROTO_SMB\n"); + else if (pp_pe->alproto == ALPROTO_SMB2) + printf(" alproto: ALPROTO_SMB2\n"); + else if (pp_pe->alproto == ALPROTO_DCERPC) + printf(" alproto: ALPROTO_DCERPC\n"); + else if (pp_pe->alproto == ALPROTO_IRC) + printf(" alproto: ALPROTO_IRC\n"); + else if (pp_pe->alproto == ALPROTO_DNS) + printf(" alproto: ALPROTO_DNS\n"); + else if (pp_pe->alproto == ALPROTO_MODBUS) + printf(" alproto: ALPROTO_MODBUS\n"); + else + printf("impossible\n"); + + 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; +} + +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 ProbingParser) +{ + 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(SC_ERR_ALPARSER, "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, + ProbingParser); + if (new_pe == NULL) + goto error; + curr_pe = new_pe; + AppLayerProtoDetectProbingParserElement **head_pe; + if (direction & STREAM_TOSERVER) { + 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 { + 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(); + + const AppLayerProtoDetectPMSignature *s = NULL; + int pat_id, max_pat_id; + + int i, j; + uint8_t ipproto; + + for (i = 0; i < FLOW_PROTO_DEFAULT; i++) { + ipproto = FlowGetReverseProtoMapping(i); + for (j = 0; j < 2; j++) { + AppLayerProtoDetectPMCtx *pm_ctx = &alpd_ctx.ctx_ipp[i].ctx_pm[j]; + max_pat_id = pm_ctx->max_pat_id; + + for (pat_id = 0; pat_id < max_pat_id; pat_id++) { + s = pm_ctx->map[pat_id]; + while (s != NULL) { + if (s->alproto == alproto) + ipprotos[ipproto / 8] |= 1 << (ipproto % 8); + s = s->next; + } + } + } + } + + 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; + uint8_t content_len = 0; + PatIntId max_id = 0; + TempContainer *struct_offset = NULL; + uint8_t *content_offset = NULL; + TempContainer *dup = 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; + } + + 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) { + dup = (TempContainer *)ahb; + content = s->cd->content; + content_len = s->cd->content_len; + + for (; dup != struct_offset; dup++) { + if (dup->content_len != content_len || + SCMemcmp(dup->content, content, dup->content_len) != 0) + { + continue; + } + break; + } + + if (dup != struct_offset) { + s->cd->id = dup->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; + PatIntId max_pat_id = 0, tmp_pat_id; + AppLayerProtoDetectPMSignature *s, *next_s; + int mpm_ret; + + max_pat_id = ctx->max_pat_id; + + ctx->map = SCMalloc((max_pat_id) * sizeof(AppLayerProtoDetectPMSignature *)); + if (ctx->map == NULL) + goto error; + memset(ctx->map, 0, (max_pat_id) * sizeof(AppLayerProtoDetectPMSignature *)); + + /* add an array indexed by pattern id to look up the sig */ + for (s = ctx->head; s != NULL;) { + next_s = s->next; + s->next = ctx->map[s->cd->id]; + ctx->map[s->cd->id] = s; + s = next_s; + } + ctx->head = NULL; + + + for (tmp_pat_id = 0; tmp_pat_id < max_pat_id; tmp_pat_id++) { + s = NULL; + for (s = ctx->map[tmp_pat_id]; s != NULL; s = s->next) { + if (s->cd->flags & DETECT_CONTENT_NOCASE) { + break; + } + } + /* if s != NULL now, it's CI. If NULL, CS */ + + if (s != NULL) { + mpm_ret = MpmAddPatternCI(&ctx->mpm_ctx, + s->cd->content, s->cd->content_len, + 0, 0, tmp_pat_id, 0, 0); + if (mpm_ret < 0) + goto error; + } else { + s = ctx->map[tmp_pat_id]; + if (s == NULL) + goto error; + + mpm_ret = MpmAddPatternCS(&ctx->mpm_ctx, + s->cd->content, s->cd->content_len, + 0, 0, tmp_pat_id, 0, 0); + if (mpm_ret < 0) + goto error; + } + } + + 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(sig->cd); + SCFree(sig); + SCReturn; +} + +static int AppLayerProtoDetectPMAddSignature(AppLayerProtoDetectPMCtx *ctx, DetectContentData *cd, + AppProto alproto) +{ + SCEnter(); + + int ret = 0; + AppLayerProtoDetectPMSignature *s = SCMalloc(sizeof(*s)); + if (unlikely(s == NULL)) + goto error; + memset(s, 0, sizeof(*s)); + + s->alproto = alproto; + s->cd = cd; + + /* prepend to the list */ + s->next = ctx->head; + ctx->head = s; + + goto end; + error: + ret = -1; + end: + SCReturnInt(ret); +} + +static int AppLayerProtoDetectPMRegisterPattern(uint8_t ipproto, AppProto alproto, + char *pattern, + uint16_t depth, uint16_t offset, + uint8_t direction, + uint8_t is_cs) +{ + SCEnter(); + + AppLayerProtoDetectCtxIpproto *ctx_ipp = &alpd_ctx.ctx_ipp[FlowGetProtoMapping(ipproto)]; + AppLayerProtoDetectPMCtx *ctx_pm = NULL; + DetectContentData *cd; + int ret = 0; + + cd = DetectContentParseEncloseQuotes(pattern); + if (cd == NULL) + goto error; + cd->depth = depth; + cd->offset = offset; + if (!is_cs) { + BoyerMooreCtxToNocase(cd->bm_ctx, cd->content, cd->content_len); + 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 (depth > ctx_pm->max_len) + ctx_pm->max_len = 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); + + goto end; + error: + ret = -1; + end: + SCReturnInt(ret); +} + +/***** Protocol Retrieval *****/ + +AppProto AppLayerProtoDetectGetProto(AppLayerProtoDetectThreadCtx *tctx, + Flow *f, + uint8_t *buf, uint32_t buflen, + uint8_t ipproto, uint8_t direction) +{ + SCEnter(); + + AppProto alproto = ALPROTO_UNKNOWN; + AppProto pm_results[ALPROTO_MAX]; + uint16_t pm_matches; + + if (!FLOW_IS_PM_DONE(f, direction)) { + pm_matches = AppLayerProtoDetectPMGetProto(tctx, f, + buf, buflen, + direction, + ipproto, + pm_results); + if (pm_matches > 0) { + alproto = pm_results[0]; + goto end; + } + } + + if (!FLOW_IS_PP_DONE(f, direction)) + alproto = AppLayerProtoDetectPPGetProto(f, buf, buflen, ipproto, direction); + + end: + SCReturnCT(alproto, "AppProto"); +} + +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; +} + +/***** 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_pat_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, + char *portstr, + AppProto alproto, + uint16_t min_depth, uint16_t max_depth, + uint8_t direction, + ProbingParserFPtr ProbingParser) +{ + SCEnter(); + + DetectPort *head = NULL; + DetectPortParse(NULL,&head, portstr); + DetectPort *temp_dp = head; + while (temp_dp != NULL) { + uint32_t port = temp_dp->port; + if (port == 0 && temp_dp->port2 != 0) + port++; + for ( ; port <= temp_dp->port2; port++) { + AppLayerProtoDetectInsertNewProbingParser(&alpd_ctx.ctx_pp, + ipproto, + port, + alproto, + min_depth, max_depth, + direction, + ProbingParser); + } + temp_dp = temp_dp->next; + } + DetectPortCleanupList(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 ProbingParser) +{ + 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) { + SCLogError(SC_ERR_FATAL, "snprintf failure."); + exit(EXIT_FAILURE); + } else if (r > (int)sizeof(param)) { + SCLogError(SC_ERR_FATAL, "buffer not big enough to write param."); + exit(EXIT_FAILURE); + } + 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) { + SCLogError(SC_ERR_FATAL, "snprintf failure."); + exit(EXIT_FAILURE); + } else if (r > (int)sizeof(param)) { + SCLogError(SC_ERR_FATAL, "buffer not big enough to write param."); + exit(EXIT_FAILURE); + } + 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 */ + ProbingParser); + } + + /* 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 */ + ProbingParser); + + } + + config = 1; + end: + SCReturnInt(config); +} + +/***** PM registration *****/ + +int AppLayerProtoDetectPMRegisterPatternCS(uint8_t ipproto, AppProto alproto, + char *pattern, + uint16_t depth, uint16_t offset, + uint8_t direction) +{ + SCEnter(); + int r = 0; + r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto, + pattern, + depth, offset, + direction, + 1 /* case-sensitive */); + SCReturnInt(r); +} + +int AppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, + char *pattern, + uint16_t depth, uint16_t offset, + uint8_t direction) +{ + SCEnter(); + int r = 0; + r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto, + pattern, + depth, offset, + direction, + 0 /* !case-sensitive */); + SCReturnInt(r); +} + +/***** Setup/General Registration *****/ + +int AppLayerProtoDetectSetup(void) +{ + SCEnter(); + + int i, j; + + memset(&alpd_ctx, 0, sizeof(alpd_ctx)); + + 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_AC); + } + } + 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, *next_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.ctx); + for (id = 0; id < pm_ctx->max_pat_id; id++) { + sig = pm_ctx->map[id]; + while (sig != NULL) { + next_sig = sig->next; + AppLayerProtoDetectPMFreeSignature(sig); + sig = next_sig; + } + } + } + } + + AppLayerProtoDetectFreeProbingParsers(alpd_ctx.ctx_pp); + + SCReturnInt(0); +} + +void AppLayerProtoDetectRegisterProtocol(AppProto alproto, char *alproto_name) +{ + SCEnter(); + + if (alpd_ctx.alproto_names[alproto] != NULL) + goto end; + + alpd_ctx.alproto_names[alproto] = alproto_name; + + goto end; + end: + SCReturn; +} + +int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, + const char *alproto) +{ + SCEnter(); + + BUG_ON(ipproto == NULL || alproto == NULL); + + int enabled = 1; + char param[100]; + ConfNode *node; + int r; + + if (RunmodeIsUnittests()) + goto enabled; + + r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.", + alproto, ".enabled"); + if (r < 0) { + SCLogError(SC_ERR_FATAL, "snprintf failure."); + exit(EXIT_FAILURE); + } else if (r > (int)sizeof(param)) { + SCLogError(SC_ERR_FATAL, "buffer not big enough to write param."); + exit(EXIT_FAILURE); + } + + 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) { + SCLogError(SC_ERR_FATAL, "snprintf failure."); + exit(EXIT_FAILURE); + } else if (r > (int)sizeof(param)) { + SCLogError(SC_ERR_FATAL, "buffer not big enough to write param."); + exit(EXIT_FAILURE); + } + + node = ConfGetNode(param); + if (node == NULL) { + SCLogDebug("Entry for %s not found.", param); + goto enabled; + } + } + + 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(SC_ERR_FATAL, "Invalid value found for %s.", param); + exit(EXIT_FAILURE); + + disabled: + enabled = 0; + enabled: + SCReturnInt(enabled); +} + +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, max_pat_id) < 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, 0); + } + } + + 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); + SCFree(alpd_tctx); + + SCReturn; +} + +/***** Utility *****/ + +void AppLayerProtoDetectSupportedIpprotos(AppProto alproto, uint8_t *ipprotos) +{ + SCEnter(); + + AppLayerProtoDetectPMGetIpprotos(alproto, ipprotos); + AppLayerProtoDetectPPGetIpprotos(alproto, ipprotos); + + SCReturn; +} + +AppProto AppLayerProtoDetectGetProtoByName(char *alproto_name) +{ + SCEnter(); + + AppProto a; + for (a = 0; a < ALPROTO_MAX; a++) { + if (alpd_ctx.alproto_names[a] != NULL && + strlen(alpd_ctx.alproto_names[a]) == strlen(alproto_name) && + (SCMemcmp(alpd_ctx.alproto_names[a], alproto_name, strlen(alproto_name)) == 0)) + { + SCReturnCT(a, "AppProto"); + } + } + + SCReturnCT(ALPROTO_UNKNOWN, "AppProto"); +} + +char *AppLayerProtoDetectGetProtoName(AppProto alproto) +{ + 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; +} + +/***** Unittests *****/ + +#ifdef UNITTESTS + +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; +} + +int AppLayerProtoDetectTest01(void) +{ + AppLayerProtoDetectUnittestCtxBackup(); + AppLayerProtoDetectSetup(); + + char *buf; + int r = 0; + + buf = "HTTP"; + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); + buf = "GET"; + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOSERVER); + + AppLayerProtoDetectPrepareState(); + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 1) { + printf("Failure - " + "alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 1\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1) { + printf("Failure - " + "alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1\n"); + goto end; + } + + r = 1; + + end: + AppLayerProtoDetectDeSetup(); + AppLayerProtoDetectUnittestCtxRestore(); + return r; +} + +int AppLayerProtoDetectTest02(void) +{ + AppLayerProtoDetectUnittestCtxBackup(); + AppLayerProtoDetectSetup(); + + char *buf; + int r = 0; + + buf = "HTTP"; + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); + buf = "ftp"; + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); + + AppLayerProtoDetectPrepareState(); + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_FTP\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1].alproto != ALPROTO_HTTP\n"); + goto end; + } + + r = 1; + + end: + AppLayerProtoDetectDeSetup(); + AppLayerProtoDetectUnittestCtxRestore(); + return r; +} + +int AppLayerProtoDetectTest03(void) +{ + AppLayerProtoDetectUnittestCtxBackup(); + AppLayerProtoDetectSetup(); + + uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n"; + char *buf; + int r = 0; + Flow f; + AppProto pm_results[ALPROTO_MAX]; + AppLayerProtoDetectThreadCtx *alpd_tctx; + + memset(&f, 0x00, sizeof(f)); + f.protomap = FlowGetProtoMapping(IPPROTO_TCP); + + memset(pm_results, 0, sizeof(pm_results)); + + buf = "HTTP"; + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, 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. */ + alpd_tctx = AppLayerProtoDetectGetCtxThread(); + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_FTP\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1].alproto != ALPROTO_HTTP\n"); + goto end; + } + + uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, + &f, + l7data, sizeof(l7data), + STREAM_TOCLIENT, + IPPROTO_TCP, + pm_results); + if (cnt != 1 && pm_results[0] != ALPROTO_HTTP) { + printf("cnt != 1 && pm_results[0] != AlPROTO_HTTP\n"); + goto end; + } + + r = 1; + + end: + if (alpd_tctx != NULL) + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDeSetup(); + AppLayerProtoDetectUnittestCtxRestore(); + return r; +} + +int AppLayerProtoDetectTest04(void) +{ + AppLayerProtoDetectUnittestCtxBackup(); + AppLayerProtoDetectSetup(); + + uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n"; + char *buf; + int r = 0; + Flow f; + AppProto pm_results[ALPROTO_MAX]; + AppLayerProtoDetectThreadCtx *alpd_tctx; + + memset(&f, 0x00, sizeof(f)); + f.protomap = FlowGetProtoMapping(IPPROTO_TCP); + + memset(pm_results, 0, sizeof(pm_results)); + + buf = "200 "; + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, buf, 13, 0, STREAM_TOCLIENT); + + AppLayerProtoDetectPrepareState(); + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since + * it sets internal structures which depends on the above function. */ + alpd_tctx = AppLayerProtoDetectGetCtxThread(); + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_HTTP\n"); + goto end; + } + + uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, + &f, + l7data, sizeof(l7data), + STREAM_TOCLIENT, + IPPROTO_TCP, + pm_results); + if (cnt != 1 && pm_results[0] != ALPROTO_HTTP) { + printf("cnt != 1 && pm_results[0] != AlPROTO_HTTP\n"); + goto end; + } + + r = 1; + + end: + if (alpd_tctx != NULL) + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDeSetup(); + AppLayerProtoDetectUnittestCtxRestore(); + return r; +} + +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>"; + char *buf; + int r = 0; + Flow f; + AppProto pm_results[ALPROTO_MAX]; + AppLayerProtoDetectThreadCtx *alpd_tctx; + + memset(&f, 0x00, sizeof(f)); + f.protomap = FlowGetProtoMapping(IPPROTO_TCP); + + memset(pm_results, 0, sizeof(pm_results)); + + buf = "HTTP"; + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, 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. */ + alpd_tctx = AppLayerProtoDetectGetCtxThread(); + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_FTP\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1].alproto != ALPROTO_HTTP\n"); + goto end; + } + + uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, + &f, + l7data, sizeof(l7data), + STREAM_TOCLIENT, + IPPROTO_TCP, + pm_results); + if (cnt != 1 && pm_results[0] != ALPROTO_HTTP) { + printf("cnt != 1 && pm_results[0] != AlPROTO_HTTP\n"); + goto end; + } + + r = 1; + + end: + if (alpd_tctx != NULL) + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDeSetup(); + AppLayerProtoDetectUnittestCtxRestore(); + return r; +} + +int AppLayerProtoDetectTest06(void) +{ + AppLayerProtoDetectUnittestCtxBackup(); + AppLayerProtoDetectSetup(); + + uint8_t l7data[] = "220 Welcome to the OISF FTP server\r\n"; + char *buf; + int r = 0; + Flow f; + AppProto pm_results[ALPROTO_MAX]; + AppLayerProtoDetectThreadCtx *alpd_tctx; + + memset(&f, 0x00, sizeof(f)); + f.protomap = FlowGetProtoMapping(IPPROTO_TCP); + + buf = "HTTP"; + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, 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. */ + alpd_tctx = AppLayerProtoDetectGetCtxThread(); + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_FTP) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_FTP\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1]->alproto != ALPROTO_HTTP) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[1].alproto != ALPROTO_HTTP\n"); + goto end; + } + + uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, + &f, + l7data, sizeof(l7data), + STREAM_TOCLIENT, + IPPROTO_TCP, + pm_results); + if (cnt != 1 && pm_results[0] != ALPROTO_FTP) { + printf("cnt != 1 && pm_results[0] != AlPROTO_FTP\n"); + goto end; + } + + r = 1; + + end: + if (alpd_tctx != NULL) + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDeSetup(); + AppLayerProtoDetectUnittestCtxRestore(); + return r; +} + +int AppLayerProtoDetectTest07(void) +{ + AppLayerProtoDetectUnittestCtxBackup(); + AppLayerProtoDetectSetup(); + + uint8_t l7data[] = "220 Welcome to the OISF HTTP/FTP server\r\n"; + char *buf; + int r = 0; + Flow f; + AppProto pm_results[ALPROTO_MAX]; + AppLayerProtoDetectThreadCtx *alpd_tctx; + + memset(&f, 0x00, sizeof(f)); + f.protomap = FlowGetProtoMapping(IPPROTO_TCP); + + memset(pm_results, 0, sizeof(pm_results)); + + buf = "HTTP"; + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); + + AppLayerProtoDetectPrepareState(); + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since + * it sets internal structures which depends on the above function. */ + alpd_tctx = AppLayerProtoDetectGetCtxThread(); + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_HTTP\n"); + goto end; + } + + uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, + &f, + l7data, sizeof(l7data), + STREAM_TOCLIENT, + IPPROTO_TCP, + pm_results); + if (cnt != 0) { + printf("cnt != 0\n"); + goto end; + } + + r = 1; + + end: + if (alpd_tctx != NULL) + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDeSetup(); + AppLayerProtoDetectUnittestCtxRestore(); + return r; +} + +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 + }; + char *buf; + int r = 0; + Flow f; + AppProto pm_results[ALPROTO_MAX]; + AppLayerProtoDetectThreadCtx *alpd_tctx; + + memset(&f, 0x00, sizeof(f)); + f.protomap = FlowGetProtoMapping(IPPROTO_TCP); + + memset(pm_results, 0, sizeof(pm_results)); + + 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. */ + alpd_tctx = AppLayerProtoDetectGetCtxThread(); + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_SMB) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_SMB\n"); + goto end; + } + + uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, + &f, + l7data, sizeof(l7data), + STREAM_TOCLIENT, + IPPROTO_TCP, + pm_results); + if (cnt != 1 && pm_results[0] != ALPROTO_SMB) { + printf("cnt != 1 && pm_results[0] != AlPROTO_SMB\n"); + goto end; + } + + r = 1; + + end: + if (alpd_tctx != NULL) + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDeSetup(); + AppLayerProtoDetectUnittestCtxRestore(); + return r; +} + +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 + }; + char *buf; + int r = 0; + Flow f; + AppProto pm_results[ALPROTO_MAX]; + AppLayerProtoDetectThreadCtx *alpd_tctx; + + memset(&f, 0x00, sizeof(f)); + f.protomap = FlowGetProtoMapping(IPPROTO_TCP); + + memset(pm_results, 0, sizeof(pm_results)); + + buf = "|fe|SMB"; + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_SMB2, buf, 8, 4, STREAM_TOCLIENT); + + AppLayerProtoDetectPrepareState(); + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since + * it sets internal structures which depends on the above function. */ + alpd_tctx = AppLayerProtoDetectGetCtxThread(); + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_SMB2) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_SMB2\n"); + goto end; + } + + uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, + &f, + l7data, sizeof(l7data), + STREAM_TOCLIENT, + IPPROTO_TCP, + pm_results); + if (cnt != 1 && pm_results[0] != ALPROTO_SMB2) { + printf("cnt != 1 && pm_results[0] != AlPROTO_SMB2\n"); + goto end; + } + + r = 1; + + end: + if (alpd_tctx != NULL) + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDeSetup(); + AppLayerProtoDetectUnittestCtxRestore(); + return r; +} + +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 + }; + char *buf; + int r = 0; + Flow f; + AppProto pm_results[ALPROTO_MAX]; + AppLayerProtoDetectThreadCtx *alpd_tctx; + + memset(&f, 0x00, sizeof(f)); + f.protomap = FlowGetProtoMapping(IPPROTO_TCP); + + memset(pm_results, 0, sizeof(pm_results)); + + 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. */ + alpd_tctx = AppLayerProtoDetectGetCtxThread(); + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 0\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 2\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_DCERPC) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0].alproto != ALPROTO_DCERPC\n"); + goto end; + } + + uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, + &f, + l7data, sizeof(l7data), + STREAM_TOCLIENT, + IPPROTO_TCP, + pm_results); + if (cnt != 1 && pm_results[0] != ALPROTO_DCERPC) { + printf("cnt != 1 && pm_results[0] != AlPROTO_DCERPC\n"); + goto end; + } + + r = 1; + + end: + if (alpd_tctx != NULL) + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDeSetup(); + AppLayerProtoDetectUnittestCtxRestore(); + return r; +} + +/** + * \test Why we still get http for connect... obviously because + * we also match on the reply, duh + */ +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"; + int r = 0; + Flow f; + AppProto pm_results[ALPROTO_MAX]; + AppLayerProtoDetectThreadCtx *alpd_tctx; + + memset(&f, 0x00, sizeof(f)); + f.protomap = FlowGetProtoMapping(IPPROTO_TCP); + + memset(pm_results, 0, sizeof(pm_results)); + + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "GET", 3, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "PUT", 3, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "POST", 4, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "TRACE", 5, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "OPTIONS", 7, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "CONNECT", 7, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOCLIENT); + + AppLayerProtoDetectPrepareState(); + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since + * it sets internal structures which depends on the above function. */ + alpd_tctx = AppLayerProtoDetectGetCtxThread(); + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 7) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].max_pat_id != 7\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].max_pat_id != 1\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map == NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map != NULL\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map == NULL) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map != NULL\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[0]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[1]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[2]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[3]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[4]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[5]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[0].map[6]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_TCP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP) + { + printf("failure 1\n"); + goto end; + } + + memset(pm_results, 0, sizeof(pm_results)); + uint32_t cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, + &f, + l7data, sizeof(l7data), + STREAM_TOSERVER, + IPPROTO_TCP, + pm_results); + if (cnt != 1 && pm_results[0] != ALPROTO_HTTP) { + printf("l7data - cnt != 1 && pm_results[0] != AlPROTO_HTTP\n"); + goto end; + } + + memset(pm_results, 0, sizeof(pm_results)); + cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, + &f, + l7data_resp, sizeof(l7data_resp), + STREAM_TOCLIENT, + IPPROTO_TCP, + pm_results); + if (cnt != 1 && pm_results[0] != ALPROTO_HTTP) { + printf("l7data_resp - cnt != 1 && pm_results[0] != AlPROTO_HTTP\n"); + goto end; + } + + r = 1; + + end: + if (alpd_tctx != NULL) + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDeSetup(); + AppLayerProtoDetectUnittestCtxRestore(); + return r; +} + +/** + * \test AlpProtoSignature test + */ +int AppLayerProtoDetectTest12(void) +{ + AppLayerProtoDetectUnittestCtxBackup(); + AppLayerProtoDetectSetup(); + + int r = 0; + + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_HTTP, "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_HTTP) { + 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 + */ +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"; + int r = 0; + Flow f; + AppProto pm_results[ALPROTO_MAX]; + AppLayerProtoDetectThreadCtx *alpd_tctx; + uint32_t cnt; + + memset(&f, 0x00, sizeof(f)); + f.protomap = FlowGetProtoMapping(IPPROTO_TCP); + + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "GET", 3, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "PUT", 3, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "POST", 4, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "TRACE", 5, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "OPTIONS", 7, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "CONNECT", 7, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOCLIENT); + + AppLayerProtoDetectPrepareState(); + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since + * it sets internal structures which depends on the above function. */ + alpd_tctx = AppLayerProtoDetectGetCtxThread(); + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].max_pat_id != 7) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].max_pat_id != 7\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].max_pat_id != 1) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].max_pat_id != 1\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[0]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[1]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[2]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[3]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[4]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[5]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[6]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP) + { + printf("failure 1\n"); + goto end; + } + + memset(pm_results, 0, sizeof(pm_results)); + cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, + &f, + l7data, sizeof(l7data), + STREAM_TOSERVER, + IPPROTO_TCP, + pm_results); + if (cnt != 0) { + printf("l7data - cnt != 0\n"); + goto end; + } + + memset(pm_results, 0, sizeof(pm_results)); + cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, + &f, + l7data_resp, sizeof(l7data_resp), + STREAM_TOCLIENT, + IPPROTO_TCP, + pm_results); + if (cnt != 0) { + printf("l7data_resp - cnt != 0\n"); + goto end; + } + + r = 1; + + end: + if (alpd_tctx != NULL) + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDeSetup(); + AppLayerProtoDetectUnittestCtxRestore(); + return r; +} + +/** + * \test What about if we add some sigs only for udp calling it for UDP? + * It should detect ALPROTO_HTTP (over udp). This is just a check + * to ensure that TCP/UDP differences work correctly. + */ +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"; + int r = 0; + Flow f; + AppProto pm_results[ALPROTO_MAX]; + AppLayerProtoDetectThreadCtx *alpd_tctx; + uint32_t cnt; + + memset(&f, 0x00, sizeof(f)); + f.protomap = FlowGetProtoMapping(IPPROTO_UDP); + + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "GET", 3, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "PUT", 3, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "POST", 4, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "TRACE", 5, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "OPTIONS", 7, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "CONNECT", 7, 0, STREAM_TOSERVER); + AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOCLIENT); + + AppLayerProtoDetectPrepareState(); + /* AppLayerProtoDetectGetCtxThread() should be called post AppLayerProtoDetectPrepareState(), since + * it sets internal structures which depends on the above function. */ + alpd_tctx = AppLayerProtoDetectGetCtxThread(); + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].max_pat_id != 7) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].max_pat_id != 7\n"); + goto end; + } + if (alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].max_pat_id != 1) { + printf("alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].max_pat_id != 1\n"); + goto end; + } + + if (alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[0]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[1]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[2]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[3]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[4]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[5]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[0].map[6]->alproto != ALPROTO_HTTP || + alpd_ctx.ctx_ipp[FLOW_PROTO_UDP].ctx_pm[1].map[0]->alproto != ALPROTO_HTTP) + { + printf("failure 1\n"); + goto end; + } + + memset(pm_results, 0, sizeof(pm_results)); + cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, + &f, + l7data, sizeof(l7data), + STREAM_TOSERVER, + IPPROTO_UDP, + pm_results); + if (cnt != 1 && pm_results[0] != ALPROTO_HTTP) { + printf("l7data - cnt != 0\n"); + goto end; + } + + memset(pm_results, 0, sizeof(pm_results)); + cnt = AppLayerProtoDetectPMGetProto(alpd_tctx, + &f, + l7data_resp, sizeof(l7data_resp), + STREAM_TOCLIENT, + IPPROTO_UDP, + pm_results); + if (cnt != 1 && pm_results[0] != ALPROTO_HTTP) { + printf("l7data_resp - cnt != 0\n"); + goto end; + } + + r = 1; + + end: + if (alpd_tctx != NULL) + AppLayerProtoDetectDestroyCtxThread(alpd_tctx); + AppLayerProtoDetectDeSetup(); + AppLayerProtoDetectUnittestCtxRestore(); + return r; +} + +typedef struct AppLayerProtoDetectPPTestDataElement_ { + 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(uint8_t *input, + uint32_t input_len, + uint32_t *offset) +{ + return 0; +} + +static int AppLayerProtoDetectTest15(void) +{ + AppLayerProtoDetectUnittestCtxBackup(); + AppLayerProtoDetectSetup(); + + int result = 0; + + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "80", + ALPROTO_HTTP, + 5, 8, + STREAM_TOSERVER, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "80", + ALPROTO_SMB, + 5, 6, + STREAM_TOSERVER, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "80", + ALPROTO_FTP, + 7, 10, + STREAM_TOSERVER, + ProbingParserDummyForTesting); + + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "81", + ALPROTO_DCERPC, + 9, 10, + STREAM_TOSERVER, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "81", + ALPROTO_FTP, + 7, 15, + STREAM_TOSERVER, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "0", + ALPROTO_SMTP, + 12, 0, + STREAM_TOSERVER, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "0", + ALPROTO_TLS, + 12, 18, + STREAM_TOSERVER, + ProbingParserDummyForTesting); + + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "85", + ALPROTO_DCERPC, + 9, 10, + STREAM_TOSERVER, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "85", + ALPROTO_FTP, + 7, 15, + STREAM_TOSERVER, + ProbingParserDummyForTesting); + result = 1; + + AppLayerProtoDetectPPRegister(IPPROTO_UDP, + "85", + ALPROTO_IMAP, + 12, 23, + STREAM_TOSERVER, + ProbingParserDummyForTesting); + + /* toclient */ + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "0", + ALPROTO_JABBER, + 12, 23, + STREAM_TOCLIENT, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "0", + ALPROTO_IRC, + 12, 14, + STREAM_TOCLIENT, + ProbingParserDummyForTesting); + + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "85", + ALPROTO_DCERPC, + 9, 10, + STREAM_TOCLIENT, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "81", + ALPROTO_FTP, + 7, 15, + STREAM_TOCLIENT, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "0", + ALPROTO_TLS, + 12, 18, + STREAM_TOCLIENT, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "80", + ALPROTO_HTTP, + 5, 8, + STREAM_TOCLIENT, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "81", + ALPROTO_DCERPC, + 9, 10, + STREAM_TOCLIENT, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "90", + ALPROTO_FTP, + 7, 15, + STREAM_TOCLIENT, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "80", + ALPROTO_SMB, + 5, 6, + STREAM_TOCLIENT, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_UDP, + "85", + ALPROTO_IMAP, + 12, 23, + STREAM_TOCLIENT, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "0", + ALPROTO_SMTP, + 12, 17, + STREAM_TOCLIENT, + ProbingParserDummyForTesting); + AppLayerProtoDetectPPRegister(IPPROTO_TCP, + "80", + ALPROTO_FTP, + 7, 10, + STREAM_TOCLIENT, + ProbingParserDummyForTesting); + + AppLayerProtoDetectPPTestDataElement element_ts_80[] = { + { "http", ALPROTO_HTTP, 80, 1 << ALPROTO_HTTP, 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_HTTP, 80, 1 << ALPROTO_HTTP, 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_HTTP) | (1 << ALPROTO_SMB) | (1 << ALPROTO_FTP) | + (1 << ALPROTO_SMTP) | (1 << ALPROTO_TLS) | (1 << ALPROTO_IRC) | (1 << ALPROTO_JABBER)), + ((1 << ALPROTO_HTTP) | (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_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + 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); + + SCMutexLock(&f->m); + int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + SCMutexUnlock(&f->m); + + 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_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + 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); + + SCMutexLock(&f->m); + int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + SCMutexUnlock(&f->m); + + 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_HTTP; + + StreamTcpInitConfig(TRUE); + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + de_ctx->mpm_matcher = MPM_B2G; + 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); + + SCMutexLock(&f->m); + int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + SCMutexUnlock(&f->m); + + 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->mpm_matcher = MPM_B2G; + 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); + + SCMutexLock(&f->m); + int r = AppLayerParserParse(alp_tctx, f, ALPROTO_FTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + SCMutexUnlock(&f->m); + + /* 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; +} + +/** \test test if the engine detect the proto and match with it + * and also against a content option */ +static int AppLayerProtoDetectTest20(void) +{ + int result = 0; + Flow *f = 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; + p->flow = f; + p->flowflags |= FLOW_PKT_TOSERVER; + p->flowflags |= FLOW_PKT_ESTABLISHED; + p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; + f->alproto = ALPROTO_HTTP; + f->proto = IPPROTO_TCP; + p->flags |= PKT_STREAM_ADD; + p->flags |= PKT_STREAM_EOF; + + de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + goto end; + } + + StreamTcpInitConfig(TRUE); + + StreamMsg *stream_msg = StreamMsgGetFromPool(); + if (stream_msg == NULL) { + printf("no stream_msg: "); + goto end; + } + + memcpy(stream_msg->data, http_buf1, http_buf1_len); + stream_msg->data_len = http_buf1_len; + + ssn.toserver_smsg_head = stream_msg; + ssn.toserver_smsg_tail = stream_msg; + + de_ctx->mpm_matcher = MPM_B2G; + de_ctx->flags |= DE_QUIET; + + s = de_ctx->sig_list = SigInit(de_ctx, "alert http any any -> any any " + "(msg:\"Test content option\"; " + "content:\"one\"; sid:1;)"); + if (s == NULL) { + goto end; + } + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); + + SCMutexLock(&f->m); + int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len); + if (r != 0) { + printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); + SCMutexUnlock(&f->m); + goto end; + } + SCMutexUnlock(&f->m); + + /* 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; +} + + +void AppLayerProtoDetectUnittestsRegister(void) +{ + SCEnter(); + + UtRegisterTest("AppLayerProtoDetectTest01", AppLayerProtoDetectTest01, 1); + UtRegisterTest("AppLayerProtoDetectTest02", AppLayerProtoDetectTest02, 1); + UtRegisterTest("AppLayerProtoDetectTest03", AppLayerProtoDetectTest03, 1); + UtRegisterTest("AppLayerProtoDetectTest04", AppLayerProtoDetectTest04, 1); + UtRegisterTest("AppLayerProtoDetectTest05", AppLayerProtoDetectTest05, 1); + UtRegisterTest("AppLayerProtoDetectTest06", AppLayerProtoDetectTest06, 1); + UtRegisterTest("AppLayerProtoDetectTest07", AppLayerProtoDetectTest07, 1); + UtRegisterTest("AppLayerProtoDetectTest08", AppLayerProtoDetectTest08, 1); + UtRegisterTest("AppLayerProtoDetectTest09", AppLayerProtoDetectTest09, 1); + UtRegisterTest("AppLayerProtoDetectTest10", AppLayerProtoDetectTest10, 1); + UtRegisterTest("AppLayerProtoDetectTest11", AppLayerProtoDetectTest11, 1); + UtRegisterTest("AppLayerProtoDetectTest12", AppLayerProtoDetectTest12, 1); + UtRegisterTest("AppLayerProtoDetectTest13", AppLayerProtoDetectTest13, 1); + UtRegisterTest("AppLayerProtoDetectTest14", AppLayerProtoDetectTest14, 1); + UtRegisterTest("AppLayerProtoDetectTest15", AppLayerProtoDetectTest15, 1); + UtRegisterTest("AppLayerProtoDetectTest16", AppLayerProtoDetectTest16, 1); + UtRegisterTest("AppLayerProtoDetectTest17", AppLayerProtoDetectTest17, 1); + UtRegisterTest("AppLayerProtoDetectTest18", AppLayerProtoDetectTest18, 1); + UtRegisterTest("AppLayerProtoDetectTest19", AppLayerProtoDetectTest19, 1); + UtRegisterTest("AppLayerProtoDetectTest20", AppLayerProtoDetectTest20, 1); + + SCReturn; +} + +#endif /* UNITTESTS */ |