mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3837 lines
132 KiB
C
3837 lines
132 KiB
C
/* 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 "app-layer-expectation.h"
|
|
|
|
#include "conf.h"
|
|
#include "util-memcmp.h"
|
|
#include "util-spm.h"
|
|
#include "util-debug.h"
|
|
|
|
#include "runmodes.h"
|
|
|
|
typedef struct AppLayerProtoDetectProbingParserElement_ {
|
|
AppProto alproto;
|
|
/* \todo don't really need it. See if you can get rid of it */
|
|
uint16_t port;
|
|
/* \todo calculate at runtime and get rid of this var */
|
|
uint32_t alproto_mask;
|
|
/* \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 to_server probing parser function */
|
|
ProbingParserFPtr ProbingParserTs;
|
|
|
|
/* the to_client probing parser function */
|
|
ProbingParserFPtr ProbingParserTc;
|
|
|
|
struct AppLayerProtoDetectProbingParserElement_ *next;
|
|
} AppLayerProtoDetectProbingParserElement;
|
|
|
|
typedef struct AppLayerProtoDetectProbingParserPort_ {
|
|
/* the port no for which probing parser(s) are invoked */
|
|
uint16_t port;
|
|
|
|
uint32_t alproto_mask;
|
|
|
|
/* the max depth for all the probing parsers registered for this port */
|
|
uint16_t dp_max_depth;
|
|
uint16_t sp_max_depth;
|
|
|
|
AppLayerProtoDetectProbingParserElement *dp;
|
|
AppLayerProtoDetectProbingParserElement *sp;
|
|
|
|
struct AppLayerProtoDetectProbingParserPort_ *next;
|
|
} AppLayerProtoDetectProbingParserPort;
|
|
|
|
typedef struct AppLayerProtoDetectProbingParser_ {
|
|
uint8_t ipproto;
|
|
AppLayerProtoDetectProbingParserPort *port;
|
|
|
|
struct AppLayerProtoDetectProbingParser_ *next;
|
|
} AppLayerProtoDetectProbingParser;
|
|
|
|
typedef struct AppLayerProtoDetectPMSignature_ {
|
|
AppProto alproto;
|
|
SigIntId id;
|
|
/* \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;
|
|
SigIntId max_sig_id;
|
|
} AppLayerProtoDetectPMCtx;
|
|
|
|
typedef struct AppLayerProtoDetectCtxIpproto_ {
|
|
/* 0 - toserver, 1 - toclient */
|
|
AppLayerProtoDetectPMCtx ctx_pm[2];
|
|
} AppLayerProtoDetectCtxIpproto;
|
|
|
|
/**
|
|
* \brief The app layer protocol detection context.
|
|
*/
|
|
typedef struct AppLayerProtoDetectCtx_ {
|
|
/* Context per ip_proto.
|
|
* \todo Modify ctx_ipp to hold for only tcp and udp. The rest can be
|
|
* implemented if needed. Waste of space otherwise. */
|
|
AppLayerProtoDetectCtxIpproto ctx_ipp[FLOW_PROTO_DEFAULT];
|
|
|
|
/* Global SPM thread context prototype. */
|
|
SpmGlobalThreadCtx *spm_global_thread_ctx;
|
|
|
|
AppLayerProtoDetectProbingParser *ctx_pp;
|
|
|
|
/* Indicates the protocols that have registered themselves
|
|
* for protocol detection. This table is independent of the
|
|
* ipproto. */
|
|
const char *alproto_names[ALPROTO_MAX];
|
|
} AppLayerProtoDetectCtx;
|
|
|
|
/**
|
|
* \brief The app layer protocol detection thread context.
|
|
*/
|
|
struct AppLayerProtoDetectThreadCtx_ {
|
|
PrefilterRuleStore pmq;
|
|
/* The value 2 is for direction(0 - toserver, 1 - toclient). */
|
|
MpmThreadCtx mpm_tctx[FLOW_PROTO_DEFAULT][2];
|
|
SpmThreadCtx *spm_thread_ctx;
|
|
};
|
|
|
|
/* The global app layer proto detection context. */
|
|
static AppLayerProtoDetectCtx alpd_ctx;
|
|
|
|
static void AppLayerProtoDetectPEGetIpprotos(AppProto alproto,
|
|
uint8_t *ipprotos);
|
|
|
|
/***** Static Internal Calls: Protocol Retrieval *****/
|
|
|
|
/** \internal
|
|
* \brief Handle SPM search for Signature */
|
|
static AppProto AppLayerProtoDetectPMMatchSignature(const AppLayerProtoDetectPMSignature *s,
|
|
AppLayerProtoDetectThreadCtx *tctx,
|
|
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);
|
|
|
|
found = SpmScan(s->cd->spm_ctx, tctx->spm_thread_ctx, sbuf, sbuflen);
|
|
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.rule_id_array_cnt; cnt++) {
|
|
const AppLayerProtoDetectPMSignature *s = pm_ctx->map[tctx->pmq.rule_id_array[cnt]];
|
|
while (s != NULL) {
|
|
AppProto proto = AppLayerProtoDetectPMMatchSignature(s,
|
|
tctx, 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 expectation to see if there is some for this flow.
|
|
*
|
|
*/
|
|
static AppProto AppLayerProtoDetectPEGetProto(Flow *f, uint8_t ipproto,
|
|
uint8_t direction)
|
|
{
|
|
AppProto alproto = ALPROTO_UNKNOWN;
|
|
|
|
SCLogDebug("expectation check for %p (dir %d)", f, direction);
|
|
FLOW_SET_PE_DONE(f, direction);
|
|
|
|
alproto = AppLayerExpectationHandle(f, direction);
|
|
|
|
return alproto;
|
|
}
|
|
|
|
/**
|
|
* \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;
|
|
|
|
const uint16_t dp = f->protodetect_dp ? f->protodetect_dp : f->dp;
|
|
const uint16_t sp = f->sp;
|
|
|
|
if (direction & STREAM_TOSERVER) {
|
|
/* first try the destination port */
|
|
pp_port_dp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, dp);
|
|
alproto_masks = &f->probing_parser_toserver_alproto_masks;
|
|
if (pp_port_dp != NULL) {
|
|
SCLogDebug("toserver - Probing parser found for destination port %"PRIu16, dp);
|
|
|
|
/* found based on destination port, so use dp registration */
|
|
pe1 = pp_port_dp->dp;
|
|
} else {
|
|
SCLogDebug("toserver - No probing parser registered for dest port %"PRIu16, dp);
|
|
}
|
|
|
|
pp_port_sp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, sp);
|
|
if (pp_port_sp != NULL) {
|
|
SCLogDebug("toserver - Probing parser found for source port %"PRIu16, sp);
|
|
|
|
/* found based on source port, so use sp registration */
|
|
pe2 = pp_port_sp->sp;
|
|
} else {
|
|
SCLogDebug("toserver - No probing parser registered for source port %"PRIu16, sp);
|
|
}
|
|
} else {
|
|
/* first try the destination port */
|
|
pp_port_dp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, dp);
|
|
alproto_masks = &f->probing_parser_toclient_alproto_masks;
|
|
if (pp_port_dp != NULL) {
|
|
SCLogDebug("toclient - Probing parser found for destination port %"PRIu16, dp);
|
|
|
|
/* found based on destination port, so use dp registration */
|
|
pe1 = pp_port_dp->dp;
|
|
} else {
|
|
SCLogDebug("toclient - No probing parser registered for dest port %"PRIu16, dp);
|
|
}
|
|
|
|
pp_port_sp = AppLayerProtoDetectGetProbingParsers(alpd_ctx.ctx_pp, ipproto, sp);
|
|
if (pp_port_sp != NULL) {
|
|
SCLogDebug("toclient - Probing parser found for source port %"PRIu16, sp);
|
|
|
|
pe2 = pp_port_sp->sp;
|
|
} else {
|
|
SCLogDebug("toclient - No probing parser registered for source port %"PRIu16, sp);
|
|
}
|
|
}
|
|
|
|
if (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;
|
|
}
|
|
|
|
if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) {
|
|
alproto = pe->ProbingParserTs(f, buf, buflen, NULL);
|
|
} else if (pe->ProbingParserTc != NULL) {
|
|
alproto = pe->ProbingParserTc(f, 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;
|
|
}
|
|
|
|
if (direction & STREAM_TOSERVER && pe->ProbingParserTs != NULL) {
|
|
alproto = pe->ProbingParserTs(f, buf, buflen, NULL);
|
|
} else if (pe->ProbingParserTc != NULL) {
|
|
alproto = pe->ProbingParserTc(f, 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;
|
|
|
|
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)
|
|
{
|
|
AppLayerProtoDetectProbingParserElement *pe = AppLayerProtoDetectProbingParserElementAlloc();
|
|
|
|
pe->alproto = alproto;
|
|
pe->port = port;
|
|
pe->alproto_mask = AppLayerProtoDetectProbingParserGetMask(alproto);
|
|
pe->min_depth = min_depth;
|
|
pe->max_depth = max_depth;
|
|
pe->next = NULL;
|
|
|
|
if (max_depth != 0 && min_depth >= max_depth) {
|
|
SCLogError(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;
|
|
}
|
|
|
|
SCReturnPtr(pe, "AppLayerProtoDetectProbingParserElement");
|
|
error:
|
|
AppLayerProtoDetectProbingParserElementFree(pe);
|
|
SCReturnPtr(NULL, "AppLayerProtoDetectProbingParserElement");
|
|
}
|
|
|
|
static AppLayerProtoDetectProbingParserElement *
|
|
AppLayerProtoDetectProbingParserElementDuplicate(AppLayerProtoDetectProbingParserElement *pe)
|
|
{
|
|
SCEnter();
|
|
|
|
AppLayerProtoDetectProbingParserElement *new_pe = AppLayerProtoDetectProbingParserElementAlloc();
|
|
|
|
new_pe->alproto = pe->alproto;
|
|
new_pe->port = pe->port;
|
|
new_pe->alproto_mask = pe->alproto_mask;
|
|
new_pe->min_depth = pe->min_depth;
|
|
new_pe->max_depth = pe->max_depth;
|
|
new_pe->ProbingParserTs = pe->ProbingParserTs;
|
|
new_pe->ProbingParserTc = pe->ProbingParserTc;
|
|
new_pe->next = NULL;
|
|
|
|
SCReturnPtr(new_pe, "AppLayerProtoDetectProbingParserElement");
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
static void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingParser *pp)
|
|
{
|
|
SCEnter();
|
|
|
|
AppLayerProtoDetectProbingParserPort *pp_port = NULL;
|
|
AppLayerProtoDetectProbingParserElement *pp_pe = NULL;
|
|
|
|
printf("\nProtocol Detection Configuration\n");
|
|
|
|
for ( ; pp != NULL; pp = pp->next) {
|
|
/* print ip protocol */
|
|
if (pp->ipproto == IPPROTO_TCP)
|
|
printf("IPProto: TCP\n");
|
|
else if (pp->ipproto == IPPROTO_UDP)
|
|
printf("IPProto: UDP\n");
|
|
else
|
|
printf("IPProto: %"PRIu8"\n", pp->ipproto);
|
|
|
|
pp_port = pp->port;
|
|
for ( ; pp_port != NULL; pp_port = pp_port->next) {
|
|
if (pp_port->dp != NULL) {
|
|
printf(" Port: %"PRIu16 "\n", pp_port->port);
|
|
|
|
printf(" Destination port: (max-depth: %"PRIu16 ", "
|
|
"mask - %"PRIu32")\n",
|
|
pp_port->dp_max_depth,
|
|
pp_port->alproto_mask);
|
|
pp_pe = pp_port->dp;
|
|
for ( ; pp_pe != NULL; pp_pe = pp_pe->next) {
|
|
|
|
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_FTPDATA)
|
|
printf(" alproto: ALPROTO_FTPDATA\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 if (pp_pe->alproto == ALPROTO_ENIP)
|
|
printf(" alproto: ALPROTO_ENIP\n");
|
|
else if (pp_pe->alproto == ALPROTO_NFS)
|
|
printf(" alproto: ALPROTO_NFS\n");
|
|
else if (pp_pe->alproto == ALPROTO_NTP)
|
|
printf(" alproto: ALPROTO_NTP\n");
|
|
else if (pp_pe->alproto == ALPROTO_TFTP)
|
|
printf(" alproto: ALPROTO_TFTP\n");
|
|
else if (pp_pe->alproto == ALPROTO_IKEV2)
|
|
printf(" alproto: ALPROTO_IKEV2\n");
|
|
else if (pp_pe->alproto == ALPROTO_TEMPLATE)
|
|
printf(" alproto: ALPROTO_TEMPLATE\n");
|
|
else if (pp_pe->alproto == ALPROTO_DNP3)
|
|
printf(" alproto: ALPROTO_DNP3\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_FTPDATA)
|
|
printf(" alproto: ALPROTO_FTPDATA\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 if (pp_pe->alproto == ALPROTO_ENIP)
|
|
printf(" alproto: ALPROTO_ENIP\n");
|
|
else if (pp_pe->alproto == ALPROTO_NFS)
|
|
printf(" alproto: ALPROTO_NFS\n");
|
|
else if (pp_pe->alproto == ALPROTO_NTP)
|
|
printf(" alproto: ALPROTO_NTP\n");
|
|
else if (pp_pe->alproto == ALPROTO_TFTP)
|
|
printf(" alproto: ALPROTO_TFTP\n");
|
|
else if (pp_pe->alproto == ALPROTO_IKEV2)
|
|
printf(" alproto: ALPROTO_IKEV2\n");
|
|
else if (pp_pe->alproto == ALPROTO_TEMPLATE)
|
|
printf(" alproto: ALPROTO_TEMPLATE\n");
|
|
else if (pp_pe->alproto == ALPROTO_DNP3)
|
|
printf(" alproto: ALPROTO_DNP3\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;
|
|
}
|
|
#endif
|
|
|
|
static void AppLayerProtoDetectProbingParserElementAppend(AppLayerProtoDetectProbingParserElement **head_pe,
|
|
AppLayerProtoDetectProbingParserElement *new_pe)
|
|
{
|
|
SCEnter();
|
|
|
|
if (*head_pe == NULL) {
|
|
*head_pe = new_pe;
|
|
goto end;
|
|
}
|
|
|
|
if ((*head_pe)->port == 0) {
|
|
if (new_pe->port != 0) {
|
|
new_pe->next = *head_pe;
|
|
*head_pe = new_pe;
|
|
} else {
|
|
AppLayerProtoDetectProbingParserElement *temp_pe = *head_pe;
|
|
while (temp_pe->next != NULL)
|
|
temp_pe = temp_pe->next;
|
|
temp_pe->next = new_pe;
|
|
}
|
|
} else {
|
|
AppLayerProtoDetectProbingParserElement *temp_pe = *head_pe;
|
|
if (new_pe->port == 0) {
|
|
while (temp_pe->next != NULL)
|
|
temp_pe = temp_pe->next;
|
|
temp_pe->next = new_pe;
|
|
} else {
|
|
while (temp_pe->next != NULL && temp_pe->next->port != 0)
|
|
temp_pe = temp_pe->next;
|
|
new_pe->next = temp_pe->next;
|
|
temp_pe->next = new_pe;
|
|
|
|
}
|
|
}
|
|
|
|
end:
|
|
SCReturn;
|
|
}
|
|
|
|
static void AppLayerProtoDetectProbingParserAppend(AppLayerProtoDetectProbingParser **head_pp,
|
|
AppLayerProtoDetectProbingParser *new_pp)
|
|
{
|
|
SCEnter();
|
|
|
|
if (*head_pp == NULL) {
|
|
*head_pp = new_pp;
|
|
goto end;
|
|
}
|
|
|
|
AppLayerProtoDetectProbingParser *temp_pp = *head_pp;
|
|
while (temp_pp->next != NULL)
|
|
temp_pp = temp_pp->next;
|
|
temp_pp->next = new_pp;
|
|
|
|
end:
|
|
SCReturn;
|
|
}
|
|
|
|
static void AppLayerProtoDetectProbingParserPortAppend(AppLayerProtoDetectProbingParserPort **head_port,
|
|
AppLayerProtoDetectProbingParserPort *new_port)
|
|
{
|
|
SCEnter();
|
|
|
|
if (*head_port == NULL) {
|
|
*head_port = new_port;
|
|
goto end;
|
|
}
|
|
|
|
if ((*head_port)->port == 0) {
|
|
new_port->next = *head_port;
|
|
*head_port = new_port;
|
|
} else {
|
|
AppLayerProtoDetectProbingParserPort *temp_port = *head_port;
|
|
while (temp_port->next != NULL && temp_port->next->port != 0) {
|
|
temp_port = temp_port->next;
|
|
}
|
|
new_port->next = temp_port->next;
|
|
temp_port->next = new_port;
|
|
}
|
|
|
|
end:
|
|
SCReturn;
|
|
}
|
|
|
|
static void AppLayerProtoDetectInsertNewProbingParser(AppLayerProtoDetectProbingParser **pp,
|
|
uint8_t ipproto,
|
|
uint16_t port,
|
|
AppProto alproto,
|
|
uint16_t min_depth, uint16_t max_depth,
|
|
uint8_t direction,
|
|
ProbingParserFPtr ProbingParser1,
|
|
ProbingParserFPtr ProbingParser2)
|
|
{
|
|
SCEnter();
|
|
|
|
/* get the top level ipproto pp */
|
|
AppLayerProtoDetectProbingParser *curr_pp = *pp;
|
|
while (curr_pp != NULL) {
|
|
if (curr_pp->ipproto == ipproto)
|
|
break;
|
|
curr_pp = curr_pp->next;
|
|
}
|
|
if (curr_pp == NULL) {
|
|
AppLayerProtoDetectProbingParser *new_pp = AppLayerProtoDetectProbingParserAlloc();
|
|
new_pp->ipproto = ipproto;
|
|
AppLayerProtoDetectProbingParserAppend(pp, new_pp);
|
|
curr_pp = new_pp;
|
|
}
|
|
|
|
/* get the top level port pp */
|
|
AppLayerProtoDetectProbingParserPort *curr_port = curr_pp->port;
|
|
while (curr_port != NULL) {
|
|
if (curr_port->port == port)
|
|
break;
|
|
curr_port = curr_port->next;
|
|
}
|
|
if (curr_port == NULL) {
|
|
AppLayerProtoDetectProbingParserPort *new_port = AppLayerProtoDetectProbingParserPortAlloc();
|
|
new_port->port = port;
|
|
AppLayerProtoDetectProbingParserPortAppend(&curr_pp->port, new_port);
|
|
curr_port = new_port;
|
|
if (direction & STREAM_TOSERVER) {
|
|
curr_port->dp_max_depth = max_depth;
|
|
} else {
|
|
curr_port->sp_max_depth = max_depth;
|
|
}
|
|
|
|
AppLayerProtoDetectProbingParserPort *zero_port;
|
|
|
|
zero_port = curr_pp->port;
|
|
while (zero_port != NULL && zero_port->port != 0) {
|
|
zero_port = zero_port->next;
|
|
}
|
|
if (zero_port != NULL) {
|
|
AppLayerProtoDetectProbingParserElement *zero_pe;
|
|
|
|
zero_pe = zero_port->dp;
|
|
for ( ; zero_pe != NULL; zero_pe = zero_pe->next) {
|
|
if (curr_port->dp == NULL)
|
|
curr_port->dp_max_depth = zero_pe->max_depth;
|
|
if (zero_pe->max_depth == 0)
|
|
curr_port->dp_max_depth = zero_pe->max_depth;
|
|
if (curr_port->dp_max_depth != 0 &&
|
|
curr_port->dp_max_depth < zero_pe->max_depth) {
|
|
curr_port->dp_max_depth = zero_pe->max_depth;
|
|
}
|
|
|
|
AppLayerProtoDetectProbingParserElement *dup_pe =
|
|
AppLayerProtoDetectProbingParserElementDuplicate(zero_pe);
|
|
AppLayerProtoDetectProbingParserElementAppend(&curr_port->dp, dup_pe);
|
|
curr_port->alproto_mask |= dup_pe->alproto_mask;
|
|
}
|
|
|
|
zero_pe = zero_port->sp;
|
|
for ( ; zero_pe != NULL; zero_pe = zero_pe->next) {
|
|
if (curr_port->sp == NULL)
|
|
curr_port->sp_max_depth = zero_pe->max_depth;
|
|
if (zero_pe->max_depth == 0)
|
|
curr_port->sp_max_depth = zero_pe->max_depth;
|
|
if (curr_port->sp_max_depth != 0 &&
|
|
curr_port->sp_max_depth < zero_pe->max_depth) {
|
|
curr_port->sp_max_depth = zero_pe->max_depth;
|
|
}
|
|
|
|
AppLayerProtoDetectProbingParserElement *dup_pe =
|
|
AppLayerProtoDetectProbingParserElementDuplicate(zero_pe);
|
|
AppLayerProtoDetectProbingParserElementAppend(&curr_port->sp, dup_pe);
|
|
curr_port->alproto_mask |= dup_pe->alproto_mask;
|
|
}
|
|
} /* if (zero_port != NULL) */
|
|
} /* if (curr_port == NULL) */
|
|
|
|
/* insert the pe_pp */
|
|
AppLayerProtoDetectProbingParserElement *curr_pe;
|
|
if (direction & STREAM_TOSERVER)
|
|
curr_pe = curr_port->dp;
|
|
else
|
|
curr_pe = curr_port->sp;
|
|
while (curr_pe != NULL) {
|
|
if (curr_pe->alproto == alproto) {
|
|
SCLogError(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);
|
|
if (new_pe == NULL)
|
|
goto error;
|
|
curr_pe = new_pe;
|
|
AppLayerProtoDetectProbingParserElement **head_pe;
|
|
if (direction & STREAM_TOSERVER) {
|
|
curr_pe->ProbingParserTs = ProbingParser1;
|
|
curr_pe->ProbingParserTc = ProbingParser2;
|
|
if (curr_port->dp == NULL)
|
|
curr_port->dp_max_depth = new_pe->max_depth;
|
|
if (new_pe->max_depth == 0)
|
|
curr_port->dp_max_depth = new_pe->max_depth;
|
|
if (curr_port->dp_max_depth != 0 &&
|
|
curr_port->dp_max_depth < new_pe->max_depth) {
|
|
curr_port->dp_max_depth = new_pe->max_depth;
|
|
}
|
|
curr_port->alproto_mask |= new_pe->alproto_mask;
|
|
head_pe = &curr_port->dp;
|
|
} else {
|
|
curr_pe->ProbingParserTs = ProbingParser2;
|
|
curr_pe->ProbingParserTc = ProbingParser1;
|
|
if (curr_port->sp == NULL)
|
|
curr_port->sp_max_depth = new_pe->max_depth;
|
|
if (new_pe->max_depth == 0)
|
|
curr_port->sp_max_depth = new_pe->max_depth;
|
|
if (curr_port->sp_max_depth != 0 &&
|
|
curr_port->sp_max_depth < new_pe->max_depth) {
|
|
curr_port->sp_max_depth = new_pe->max_depth;
|
|
}
|
|
curr_port->alproto_mask |= new_pe->alproto_mask;
|
|
head_pe = &curr_port->sp;
|
|
}
|
|
AppLayerProtoDetectProbingParserElementAppend(head_pe, new_pe);
|
|
|
|
if (curr_port->port == 0) {
|
|
AppLayerProtoDetectProbingParserPort *temp_port = curr_pp->port;
|
|
while (temp_port != NULL && temp_port->port != 0) {
|
|
if (direction & STREAM_TOSERVER) {
|
|
if (temp_port->dp == NULL)
|
|
temp_port->dp_max_depth = curr_pe->max_depth;
|
|
if (curr_pe->max_depth == 0)
|
|
temp_port->dp_max_depth = curr_pe->max_depth;
|
|
if (temp_port->dp_max_depth != 0 &&
|
|
temp_port->dp_max_depth < curr_pe->max_depth) {
|
|
temp_port->dp_max_depth = curr_pe->max_depth;
|
|
}
|
|
AppLayerProtoDetectProbingParserElementAppend(&temp_port->dp,
|
|
AppLayerProtoDetectProbingParserElementDuplicate(curr_pe));
|
|
temp_port->alproto_mask |= curr_pe->alproto_mask;
|
|
} else {
|
|
if (temp_port->sp == NULL)
|
|
temp_port->sp_max_depth = curr_pe->max_depth;
|
|
if (curr_pe->max_depth == 0)
|
|
temp_port->sp_max_depth = curr_pe->max_depth;
|
|
if (temp_port->sp_max_depth != 0 &&
|
|
temp_port->sp_max_depth < curr_pe->max_depth) {
|
|
temp_port->sp_max_depth = curr_pe->max_depth;
|
|
}
|
|
AppLayerProtoDetectProbingParserElementAppend(&temp_port->sp,
|
|
AppLayerProtoDetectProbingParserElementDuplicate(curr_pe));
|
|
temp_port->alproto_mask |= curr_pe->alproto_mask;
|
|
}
|
|
temp_port = temp_port->next;
|
|
} /* while */
|
|
} /* if */
|
|
|
|
error:
|
|
SCReturn;
|
|
}
|
|
|
|
/***** Static Internal Calls: PM registration *****/
|
|
|
|
static void AppLayerProtoDetectPMGetIpprotos(AppProto alproto,
|
|
uint8_t *ipprotos)
|
|
{
|
|
SCEnter();
|
|
|
|
const AppLayerProtoDetectPMSignature *s = NULL;
|
|
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];
|
|
|
|
SigIntId x;
|
|
for (x = 0; x < pm_ctx->max_sig_id;x++) {
|
|
s = pm_ctx->map[x];
|
|
if (s->alproto == alproto)
|
|
ipprotos[ipproto / 8] |= 1 << (ipproto % 8);
|
|
}
|
|
}
|
|
}
|
|
|
|
SCReturn;
|
|
}
|
|
|
|
static int AppLayerProtoDetectPMSetContentIDs(AppLayerProtoDetectPMCtx *ctx)
|
|
{
|
|
SCEnter();
|
|
|
|
typedef struct TempContainer_ {
|
|
PatIntId id;
|
|
uint16_t content_len;
|
|
uint8_t *content;
|
|
} TempContainer;
|
|
|
|
AppLayerProtoDetectPMSignature *s = NULL;
|
|
uint32_t struct_total_size = 0;
|
|
uint32_t content_total_size = 0;
|
|
/* array hash buffer */
|
|
uint8_t *ahb = NULL;
|
|
uint8_t *content = NULL;
|
|
uint8_t content_len = 0;
|
|
PatIntId max_id = 0;
|
|
TempContainer *struct_offset = NULL;
|
|
uint8_t *content_offset = NULL;
|
|
int ret = 0;
|
|
|
|
if (ctx->head == NULL)
|
|
goto end;
|
|
|
|
for (s = ctx->head; s != NULL; s = s->next) {
|
|
struct_total_size += sizeof(TempContainer);
|
|
content_total_size += s->cd->content_len;
|
|
ctx->max_sig_id++;
|
|
}
|
|
|
|
ahb = SCMalloc(sizeof(uint8_t) * (struct_total_size + content_total_size));
|
|
if (unlikely(ahb == NULL))
|
|
goto error;
|
|
|
|
struct_offset = (TempContainer *)ahb;
|
|
content_offset = ahb + struct_total_size;
|
|
for (s = ctx->head; s != NULL; s = s->next) {
|
|
TempContainer *tcdup = (TempContainer *)ahb;
|
|
content = s->cd->content;
|
|
content_len = s->cd->content_len;
|
|
|
|
for (; tcdup != struct_offset; tcdup++) {
|
|
if (tcdup->content_len != content_len ||
|
|
SCMemcmp(tcdup->content, content, tcdup->content_len) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (tcdup != struct_offset) {
|
|
s->cd->id = tcdup->id;
|
|
continue;
|
|
}
|
|
|
|
struct_offset->content_len = content_len;
|
|
struct_offset->content = content_offset;
|
|
content_offset += content_len;
|
|
memcpy(struct_offset->content, content, content_len);
|
|
struct_offset->id = max_id++;
|
|
s->cd->id = struct_offset->id;
|
|
|
|
struct_offset++;
|
|
}
|
|
|
|
ctx->max_pat_id = max_id;
|
|
|
|
goto end;
|
|
error:
|
|
ret = -1;
|
|
end:
|
|
if (ahb != NULL)
|
|
SCFree(ahb);
|
|
SCReturnInt(ret);
|
|
}
|
|
|
|
static int AppLayerProtoDetectPMMapSignatures(AppLayerProtoDetectPMCtx *ctx)
|
|
{
|
|
SCEnter();
|
|
|
|
int ret = 0;
|
|
AppLayerProtoDetectPMSignature *s, *next_s;
|
|
int mpm_ret;
|
|
SigIntId id = 0;
|
|
|
|
ctx->map = SCMalloc(ctx->max_sig_id * sizeof(AppLayerProtoDetectPMSignature *));
|
|
if (ctx->map == NULL)
|
|
goto error;
|
|
memset(ctx->map, 0, ctx->max_sig_id * sizeof(AppLayerProtoDetectPMSignature *));
|
|
|
|
/* add an array indexed by rule id to look up the sig */
|
|
for (s = ctx->head; s != NULL; ) {
|
|
next_s = s->next;
|
|
s->id = id++;
|
|
SCLogDebug("s->id %u", s->id);
|
|
|
|
if (s->cd->flags & DETECT_CONTENT_NOCASE) {
|
|
mpm_ret = MpmAddPatternCI(&ctx->mpm_ctx,
|
|
s->cd->content, s->cd->content_len,
|
|
0, 0, s->cd->id, s->id, 0);
|
|
if (mpm_ret < 0)
|
|
goto error;
|
|
} else {
|
|
mpm_ret = MpmAddPatternCS(&ctx->mpm_ctx,
|
|
s->cd->content, s->cd->content_len,
|
|
0, 0, s->cd->id, s->id, 0);
|
|
if (mpm_ret < 0)
|
|
goto error;
|
|
}
|
|
|
|
ctx->map[s->id] = s;
|
|
s->next = NULL;
|
|
s = next_s;
|
|
}
|
|
ctx->head = NULL;
|
|
|
|
goto end;
|
|
error:
|
|
ret = -1;
|
|
end:
|
|
SCReturnInt(ret);
|
|
}
|
|
|
|
static int AppLayerProtoDetectPMPrepareMpm(AppLayerProtoDetectPMCtx *ctx)
|
|
{
|
|
SCEnter();
|
|
|
|
int ret = 0;
|
|
MpmCtx *mpm_ctx = &ctx->mpm_ctx;
|
|
|
|
if (mpm_table[mpm_ctx->mpm_type].Prepare(mpm_ctx) < 0)
|
|
goto error;
|
|
|
|
goto end;
|
|
error:
|
|
ret = -1;
|
|
end:
|
|
SCReturnInt(ret);
|
|
}
|
|
|
|
static void AppLayerProtoDetectPMFreeSignature(AppLayerProtoDetectPMSignature *sig)
|
|
{
|
|
SCEnter();
|
|
if (sig == NULL)
|
|
SCReturn;
|
|
if (sig->cd)
|
|
DetectContentFree(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,
|
|
const 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(alpd_ctx.spm_global_thread_ctx,
|
|
pattern);
|
|
if (cd == NULL)
|
|
goto error;
|
|
cd->depth = depth;
|
|
cd->offset = offset;
|
|
if (!is_cs) {
|
|
/* Rebuild as nocase */
|
|
SpmDestroyCtx(cd->spm_ctx);
|
|
cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1,
|
|
alpd_ctx.spm_global_thread_ctx);
|
|
if (cd->spm_ctx == NULL) {
|
|
goto error;
|
|
}
|
|
cd->flags |= DETECT_CONTENT_NOCASE;
|
|
}
|
|
if (depth < cd->content_len)
|
|
goto error;
|
|
|
|
if (direction & STREAM_TOSERVER)
|
|
ctx_pm = (AppLayerProtoDetectPMCtx *)&ctx_ipp->ctx_pm[0];
|
|
else
|
|
ctx_pm = (AppLayerProtoDetectPMCtx *)&ctx_ipp->ctx_pm[1];
|
|
|
|
if (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);
|
|
if (alproto != ALPROTO_UNKNOWN)
|
|
goto end;
|
|
}
|
|
|
|
/* Look if flow can be found in expectation list */
|
|
if (!FLOW_IS_PE_DONE(f, direction)) {
|
|
alproto = AppLayerProtoDetectPEGetProto(f, ipproto, direction);
|
|
}
|
|
|
|
end:
|
|
SCReturnUInt(alproto);
|
|
}
|
|
|
|
static void AppLayerProtoDetectFreeProbingParsers(AppLayerProtoDetectProbingParser *pp)
|
|
{
|
|
SCEnter();
|
|
|
|
AppLayerProtoDetectProbingParser *tmp_pp = NULL;
|
|
|
|
if (pp == NULL)
|
|
goto end;
|
|
|
|
while (pp != NULL) {
|
|
tmp_pp = pp->next;
|
|
AppLayerProtoDetectProbingParserFree(pp);
|
|
pp = tmp_pp;
|
|
}
|
|
|
|
end:
|
|
SCReturn;
|
|
}
|
|
|
|
/***** State Preparation *****/
|
|
|
|
int AppLayerProtoDetectPrepareState(void)
|
|
{
|
|
SCEnter();
|
|
|
|
AppLayerProtoDetectPMCtx *ctx_pm;
|
|
int i, j;
|
|
int ret = 0;
|
|
|
|
for (i = 0; i < FLOW_PROTO_DEFAULT; i++) {
|
|
for (j = 0; j < 2; j++) {
|
|
ctx_pm = &alpd_ctx.ctx_ipp[i].ctx_pm[j];
|
|
|
|
if (AppLayerProtoDetectPMSetContentIDs(ctx_pm) < 0)
|
|
goto error;
|
|
|
|
if (ctx_pm->max_sig_id == 0)
|
|
continue;
|
|
|
|
if (AppLayerProtoDetectPMMapSignatures(ctx_pm) < 0)
|
|
goto error;
|
|
if (AppLayerProtoDetectPMPrepareMpm(ctx_pm) < 0)
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (SCLogDebugEnabled()) {
|
|
AppLayerProtoDetectPrintProbingParsers(alpd_ctx.ctx_pp);
|
|
}
|
|
#endif
|
|
|
|
goto end;
|
|
error:
|
|
ret = -1;
|
|
end:
|
|
SCReturnInt(ret);
|
|
}
|
|
|
|
/***** PP registration *****/
|
|
|
|
/** \brief register parser at a port
|
|
*
|
|
* \param direction STREAM_TOSERVER or STREAM_TOCLIENT for dp or sp
|
|
*/
|
|
void AppLayerProtoDetectPPRegister(uint8_t ipproto,
|
|
const char *portstr,
|
|
AppProto alproto,
|
|
uint16_t min_depth, uint16_t max_depth,
|
|
uint8_t direction,
|
|
ProbingParserFPtr ProbingParser1,
|
|
ProbingParserFPtr ProbingParser2)
|
|
{
|
|
SCEnter();
|
|
|
|
DetectPort *head = NULL;
|
|
DetectPortParse(NULL,&head, portstr);
|
|
DetectPort *temp_dp = head;
|
|
while (temp_dp != NULL) {
|
|
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,
|
|
ProbingParser1,
|
|
ProbingParser2);
|
|
}
|
|
temp_dp = temp_dp->next;
|
|
}
|
|
DetectPortCleanupList(NULL,head);
|
|
|
|
SCReturn;
|
|
}
|
|
|
|
int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name,
|
|
uint8_t ipproto,
|
|
const char *alproto_name,
|
|
AppProto alproto,
|
|
uint16_t min_depth, uint16_t max_depth,
|
|
ProbingParserFPtr ProbingParserTs,
|
|
ProbingParserFPtr ProbingParserTc)
|
|
{
|
|
SCEnter();
|
|
|
|
char param[100];
|
|
int r;
|
|
ConfNode *node;
|
|
ConfNode *port_node = NULL;
|
|
int config = 0;
|
|
|
|
r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.",
|
|
alproto_name, ".detection-ports");
|
|
if (r < 0) {
|
|
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 */
|
|
ProbingParserTs, ProbingParserTc);
|
|
}
|
|
|
|
/* detect by source port of flow */
|
|
port_node = ConfNodeLookupChild(node, "sp");
|
|
if (port_node == NULL)
|
|
port_node = ConfNodeLookupChild(node, "toclient");
|
|
|
|
if (port_node != NULL && port_node->val != NULL) {
|
|
AppLayerProtoDetectPPRegister(ipproto,
|
|
port_node->val,
|
|
alproto,
|
|
min_depth, max_depth,
|
|
STREAM_TOCLIENT, /* to indicate sp */
|
|
ProbingParserTc, ProbingParserTs);
|
|
|
|
}
|
|
|
|
config = 1;
|
|
end:
|
|
SCReturnInt(config);
|
|
}
|
|
|
|
/***** PM registration *****/
|
|
|
|
int AppLayerProtoDetectPMRegisterPatternCS(uint8_t ipproto, AppProto alproto,
|
|
const char *pattern,
|
|
uint16_t depth, uint16_t offset,
|
|
uint8_t direction)
|
|
{
|
|
SCEnter();
|
|
int r = 0;
|
|
r = AppLayerProtoDetectPMRegisterPattern(ipproto, alproto,
|
|
pattern,
|
|
depth, offset,
|
|
direction,
|
|
1 /* case-sensitive */);
|
|
SCReturnInt(r);
|
|
}
|
|
|
|
int AppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto,
|
|
const 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));
|
|
|
|
uint16_t spm_matcher = SinglePatternMatchDefaultMatcher();
|
|
uint16_t mpm_matcher = PatternMatchDefaultMatcher();
|
|
|
|
alpd_ctx.spm_global_thread_ctx = SpmInitGlobalThreadCtx(spm_matcher);
|
|
if (alpd_ctx.spm_global_thread_ctx == NULL) {
|
|
SCLogError(SC_ERR_FATAL, "Unable to alloc SpmGlobalThreadCtx.");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
for (i = 0; i < FLOW_PROTO_DEFAULT; i++) {
|
|
for (j = 0; j < 2; j++) {
|
|
MpmInitCtx(&alpd_ctx.ctx_ipp[i].ctx_pm[j].mpm_ctx, mpm_matcher);
|
|
}
|
|
}
|
|
|
|
AppLayerExpectationSetup();
|
|
|
|
SCReturnInt(0);
|
|
}
|
|
|
|
/**
|
|
* \todo incomplete. Need more work.
|
|
*/
|
|
int AppLayerProtoDetectDeSetup(void)
|
|
{
|
|
SCEnter();
|
|
|
|
int ipproto_map = 0;
|
|
int dir = 0;
|
|
PatIntId id = 0;
|
|
AppLayerProtoDetectPMCtx *pm_ctx = NULL;
|
|
AppLayerProtoDetectPMSignature *sig = NULL;
|
|
|
|
for (ipproto_map = 0; ipproto_map < FLOW_PROTO_DEFAULT; ipproto_map++) {
|
|
for (dir = 0; dir < 2; dir++) {
|
|
pm_ctx = &alpd_ctx.ctx_ipp[ipproto_map].ctx_pm[dir];
|
|
mpm_table[pm_ctx->mpm_ctx.mpm_type].DestroyCtx(&pm_ctx->mpm_ctx);
|
|
for (id = 0; id < pm_ctx->max_sig_id; id++) {
|
|
sig = pm_ctx->map[id];
|
|
AppLayerProtoDetectPMFreeSignature(sig);
|
|
}
|
|
}
|
|
}
|
|
|
|
SpmDestroyGlobalThreadCtx(alpd_ctx.spm_global_thread_ctx);
|
|
|
|
AppLayerProtoDetectFreeProbingParsers(alpd_ctx.ctx_pp);
|
|
|
|
SCReturnInt(0);
|
|
}
|
|
|
|
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
|
|
{
|
|
SCEnter();
|
|
|
|
if (alpd_ctx.alproto_names[alproto] != NULL)
|
|
goto end;
|
|
|
|
alpd_ctx.alproto_names[alproto] = alproto_name;
|
|
|
|
goto end;
|
|
end:
|
|
SCReturn;
|
|
}
|
|
|
|
/** \brief request applayer to wrap up this protocol and rerun protocol
|
|
* detection.
|
|
*
|
|
* When this is called, the old session is reset unconditionally. A
|
|
* 'detect/log' flush packet is generated for both direction before
|
|
* the reset, so allow for final detection and logging.
|
|
*
|
|
* \param f flow to act on
|
|
* \param dp destination port to use in protocol detection. Set to 443
|
|
* for start tls, set to the HTTP uri port for CONNECT and
|
|
* set to 0 to not use it.
|
|
* \param expect_proto expected protocol. AppLayer event will be set if
|
|
* detected protocol differs from this.
|
|
*/
|
|
void AppLayerRequestProtocolChange(Flow *f, uint16_t dp, AppProto expect_proto)
|
|
{
|
|
FlowSetChangeProtoFlag(f);
|
|
f->protodetect_dp = dp;
|
|
f->alproto_expect = expect_proto;
|
|
}
|
|
|
|
/** \brief request applayer to wrap up this protocol and rerun protocol
|
|
* detection with expectation of TLS. Used by STARTTLS.
|
|
*
|
|
* Sets detection port to 443 to make port based TLS detection work for
|
|
* SMTP, FTP etc as well.
|
|
*
|
|
* \param f flow to act on
|
|
*/
|
|
void AppLayerRequestProtocolTLSUpgrade(Flow *f)
|
|
{
|
|
AppLayerRequestProtocolChange(f, 443, ALPROTO_TLS);
|
|
}
|
|
|
|
void AppLayerProtoDetectReset(Flow *f)
|
|
{
|
|
FlowUnsetChangeProtoFlag(f);
|
|
FLOW_RESET_PM_DONE(f, STREAM_TOSERVER);
|
|
FLOW_RESET_PM_DONE(f, STREAM_TOCLIENT);
|
|
FLOW_RESET_PP_DONE(f, STREAM_TOSERVER);
|
|
FLOW_RESET_PP_DONE(f, STREAM_TOCLIENT);
|
|
FLOW_RESET_PE_DONE(f, STREAM_TOSERVER);
|
|
FLOW_RESET_PE_DONE(f, STREAM_TOCLIENT);
|
|
f->probing_parser_toserver_alproto_masks = 0;
|
|
f->probing_parser_toclient_alproto_masks = 0;
|
|
|
|
AppLayerParserStateCleanup(f, f->alstate, f->alparser);
|
|
f->alstate = NULL;
|
|
f->alparser = NULL;
|
|
f->alproto = ALPROTO_UNKNOWN;
|
|
f->alproto_ts = ALPROTO_UNKNOWN;
|
|
f->alproto_tc = ALPROTO_UNKNOWN;
|
|
}
|
|
|
|
int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto,
|
|
const char *alproto)
|
|
{
|
|
SCEnter();
|
|
|
|
BUG_ON(ipproto == NULL || alproto == NULL);
|
|
|
|
int enabled = 1;
|
|
char param[100];
|
|
ConfNode *node;
|
|
int r;
|
|
|
|
#ifdef AFLFUZZ_APPLAYER
|
|
goto enabled;
|
|
#endif
|
|
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) < 0)
|
|
goto error;
|
|
|
|
for (i = 0; i < FLOW_PROTO_DEFAULT; i++) {
|
|
for (j = 0; j < 2; j++) {
|
|
mpm_ctx = &alpd_ctx.ctx_ipp[i].ctx_pm[j].mpm_ctx;
|
|
mpm_tctx = &alpd_tctx->mpm_tctx[i][j];
|
|
mpm_table[mpm_ctx->mpm_type].InitThreadCtx(mpm_ctx, mpm_tctx);
|
|
}
|
|
}
|
|
|
|
alpd_tctx->spm_thread_ctx = SpmMakeThreadCtx(alpd_ctx.spm_global_thread_ctx);
|
|
if (alpd_tctx->spm_thread_ctx == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
goto end;
|
|
error:
|
|
if (alpd_tctx != NULL)
|
|
AppLayerProtoDetectDestroyCtxThread(alpd_tctx);
|
|
alpd_tctx = NULL;
|
|
end:
|
|
SCReturnPtr(alpd_tctx, "AppLayerProtoDetectThreadCtx");
|
|
}
|
|
|
|
void AppLayerProtoDetectDestroyCtxThread(AppLayerProtoDetectThreadCtx *alpd_tctx)
|
|
{
|
|
SCEnter();
|
|
|
|
MpmCtx *mpm_ctx;
|
|
MpmThreadCtx *mpm_tctx;
|
|
int ipproto_map, dir;
|
|
|
|
for (ipproto_map = 0; ipproto_map < FLOW_PROTO_DEFAULT; ipproto_map++) {
|
|
for (dir = 0; dir < 2; dir++) {
|
|
mpm_ctx = &alpd_ctx.ctx_ipp[ipproto_map].ctx_pm[dir].mpm_ctx;
|
|
mpm_tctx = &alpd_tctx->mpm_tctx[ipproto_map][dir];
|
|
mpm_table[mpm_ctx->mpm_type].DestroyThreadCtx(mpm_ctx, mpm_tctx);
|
|
}
|
|
}
|
|
PmqFree(&alpd_tctx->pmq);
|
|
if (alpd_tctx->spm_thread_ctx != NULL) {
|
|
SpmDestroyThreadCtx(alpd_tctx->spm_thread_ctx);
|
|
}
|
|
SCFree(alpd_tctx);
|
|
|
|
SCReturn;
|
|
}
|
|
|
|
/***** Utility *****/
|
|
|
|
void AppLayerProtoDetectSupportedIpprotos(AppProto alproto, uint8_t *ipprotos)
|
|
{
|
|
SCEnter();
|
|
|
|
AppLayerProtoDetectPMGetIpprotos(alproto, ipprotos);
|
|
AppLayerProtoDetectPPGetIpprotos(alproto, ipprotos);
|
|
AppLayerProtoDetectPEGetIpprotos(alproto, ipprotos);
|
|
|
|
SCReturn;
|
|
}
|
|
|
|
AppProto AppLayerProtoDetectGetProtoByName(const 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");
|
|
}
|
|
|
|
const 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;
|
|
}
|
|
|
|
uint8_t expectation_proto[ALPROTO_MAX];
|
|
|
|
static void AppLayerProtoDetectPEGetIpprotos(AppProto alproto,
|
|
uint8_t *ipprotos)
|
|
{
|
|
if (expectation_proto[alproto] == IPPROTO_TCP) {
|
|
ipprotos[IPPROTO_TCP / 8] |= 1 << (IPPROTO_TCP % 8);
|
|
}
|
|
if (expectation_proto[alproto] == IPPROTO_UDP) {
|
|
ipprotos[IPPROTO_UDP / 8] |= 1 << (IPPROTO_UDP % 8);
|
|
}
|
|
}
|
|
|
|
void AppLayerRegisterExpectationProto(uint8_t proto, AppProto alproto)
|
|
{
|
|
if (expectation_proto[alproto]) {
|
|
if (proto != expectation_proto[alproto]) {
|
|
SCLogError(SC_ERR_NOT_SUPPORTED,
|
|
"Expectation on 2 IP protocols are not supported");
|
|
}
|
|
}
|
|
expectation_proto[alproto] = proto;
|
|
}
|
|
|
|
/***** 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;
|
|
}
|
|
|
|
static int AppLayerProtoDetectTest01(void)
|
|
{
|
|
AppLayerProtoDetectUnittestCtxBackup();
|
|
AppLayerProtoDetectSetup();
|
|
|
|
const 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;
|
|
}
|
|
|
|
static int AppLayerProtoDetectTest02(void)
|
|
{
|
|
AppLayerProtoDetectUnittestCtxBackup();
|
|
AppLayerProtoDetectSetup();
|
|
|
|
int r = 0;
|
|
|
|
const char *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;
|
|
}
|
|
|
|
static int AppLayerProtoDetectTest03(void)
|
|
{
|
|
AppLayerProtoDetectUnittestCtxBackup();
|
|
AppLayerProtoDetectSetup();
|
|
|
|
uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n";
|
|
const 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;
|
|
}
|
|
|
|
static int AppLayerProtoDetectTest04(void)
|
|
{
|
|
AppLayerProtoDetectUnittestCtxBackup();
|
|
AppLayerProtoDetectSetup();
|
|
|
|
uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n";
|
|
const 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;
|
|
}
|
|
|
|
static int AppLayerProtoDetectTest05(void)
|
|
{
|
|
AppLayerProtoDetectUnittestCtxBackup();
|
|
AppLayerProtoDetectSetup();
|
|
|
|
uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n<HTML><BODY>Blahblah</BODY></HTML>";
|
|
const 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;
|
|
}
|
|
|
|
static int AppLayerProtoDetectTest06(void)
|
|
{
|
|
AppLayerProtoDetectUnittestCtxBackup();
|
|
AppLayerProtoDetectSetup();
|
|
|
|
uint8_t l7data[] = "220 Welcome to the OISF FTP server\r\n";
|
|
const 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;
|
|
}
|
|
|
|
static int AppLayerProtoDetectTest07(void)
|
|
{
|
|
AppLayerProtoDetectUnittestCtxBackup();
|
|
AppLayerProtoDetectSetup();
|
|
|
|
uint8_t l7data[] = "220 Welcome to the OISF HTTP/FTP server\r\n";
|
|
const 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;
|
|
}
|
|
|
|
static int AppLayerProtoDetectTest08(void)
|
|
{
|
|
AppLayerProtoDetectUnittestCtxBackup();
|
|
AppLayerProtoDetectSetup();
|
|
|
|
uint8_t l7data[] = {
|
|
0x00, 0x00, 0x00, 0x85, 0xff, 0x53, 0x4d, 0x42,
|
|
0x72, 0x00, 0x00, 0x00, 0x00, 0x18, 0x53, 0xc8,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x02,
|
|
0x50, 0x43, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f,
|
|
0x52, 0x4b, 0x20, 0x50, 0x52, 0x4f, 0x47, 0x52,
|
|
0x41, 0x4d, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02,
|
|
0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x31, 0x2e,
|
|
0x30, 0x00, 0x02, 0x57, 0x69, 0x6e, 0x64, 0x6f,
|
|
0x77, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x57,
|
|
0x6f, 0x72, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70,
|
|
0x73, 0x20, 0x33, 0x2e, 0x31, 0x61, 0x00, 0x02,
|
|
0x4c, 0x4d, 0x31, 0x2e, 0x32, 0x58, 0x30, 0x30,
|
|
0x32, 0x00, 0x02, 0x4c, 0x41, 0x4e, 0x4d, 0x41,
|
|
0x4e, 0x32, 0x2e, 0x31, 0x00, 0x02, 0x4e, 0x54,
|
|
0x20, 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31, 0x32,
|
|
0x00
|
|
};
|
|
const 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;
|
|
}
|
|
|
|
static int AppLayerProtoDetectTest09(void)
|
|
{
|
|
AppLayerProtoDetectUnittestCtxBackup();
|
|
AppLayerProtoDetectSetup();
|
|
|
|
uint8_t l7data[] = {
|
|
0x00, 0x00, 0x00, 0x66, 0xfe, 0x53, 0x4d, 0x42,
|
|
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x01, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x02, 0x02
|
|
};
|
|
const 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;
|
|
}
|
|
|
|
static int AppLayerProtoDetectTest10(void)
|
|
{
|
|
AppLayerProtoDetectUnittestCtxBackup();
|
|
AppLayerProtoDetectSetup();
|
|
|
|
uint8_t l7data[] = {
|
|
0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00,
|
|
0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0xd0, 0x16, 0xd0, 0x16, 0x00, 0x00, 0x00, 0x00,
|
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
|
0xb8, 0x4a, 0x9f, 0x4d, 0x1c, 0x7d, 0xcf, 0x11,
|
|
0x86, 0x1e, 0x00, 0x20, 0xaf, 0x6e, 0x7c, 0x57,
|
|
0x00, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a,
|
|
0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00,
|
|
0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00
|
|
};
|
|
const 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
|
|
*/
|
|
static int AppLayerProtoDetectTest11(void)
|
|
{
|
|
AppLayerProtoDetectUnittestCtxBackup();
|
|
AppLayerProtoDetectSetup();
|
|
|
|
uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n";
|
|
uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n";
|
|
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
|
|
*/
|
|
static 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
|
|
*/
|
|
static int AppLayerProtoDetectTest13(void)
|
|
{
|
|
AppLayerProtoDetectUnittestCtxBackup();
|
|
AppLayerProtoDetectSetup();
|
|
|
|
uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n";
|
|
uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n";
|
|
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.
|
|
*/
|
|
static int AppLayerProtoDetectTest14(void)
|
|
{
|
|
AppLayerProtoDetectUnittestCtxBackup();
|
|
AppLayerProtoDetectSetup();
|
|
|
|
uint8_t l7data[] = "CONNECT www.ssllabs.com:443 HTTP/1.0\r\n";
|
|
uint8_t l7data_resp[] = "HTTP/1.1 405 Method Not Allowed\r\n";
|
|
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_ {
|
|
const char *alproto_name;
|
|
AppProto alproto;
|
|
uint16_t port;
|
|
uint32_t alproto_mask;
|
|
uint32_t min_depth;
|
|
uint32_t max_depth;
|
|
} AppLayerProtoDetectPPTestDataElement;
|
|
|
|
typedef struct AppLayerProtoDetectPPTestDataPort_ {
|
|
uint16_t port;
|
|
uint32_t alproto_mask;
|
|
uint16_t dp_max_depth;
|
|
uint16_t sp_max_depth;
|
|
|
|
AppLayerProtoDetectPPTestDataElement *toserver_element;
|
|
AppLayerProtoDetectPPTestDataElement *toclient_element;
|
|
int ts_no_of_element;
|
|
int tc_no_of_element;
|
|
} AppLayerProtoDetectPPTestDataPort;
|
|
|
|
|
|
typedef struct AppLayerProtoDetectPPTestDataIPProto_ {
|
|
uint8_t ipproto;
|
|
|
|
AppLayerProtoDetectPPTestDataPort *port;
|
|
int no_of_port;
|
|
} AppLayerProtoDetectPPTestDataIPProto;
|
|
|
|
static int AppLayerProtoDetectPPTestData(AppLayerProtoDetectProbingParser *pp,
|
|
AppLayerProtoDetectPPTestDataIPProto *ip_proto,
|
|
int no_of_ip_proto)
|
|
{
|
|
int result = 0;
|
|
int i = -1, j = -1 , k = -1;
|
|
#ifdef DEBUG
|
|
int dir = 0;
|
|
#endif
|
|
for (i = 0; i < no_of_ip_proto; i++, pp = pp->next) {
|
|
if (pp->ipproto != ip_proto[i].ipproto)
|
|
goto end;
|
|
|
|
AppLayerProtoDetectProbingParserPort *pp_port = pp->port;
|
|
for (k = 0; k < ip_proto[i].no_of_port; k++, pp_port = pp_port->next) {
|
|
if (pp_port->port != ip_proto[i].port[k].port)
|
|
goto end;
|
|
if (pp_port->alproto_mask != ip_proto[i].port[k].alproto_mask)
|
|
goto end;
|
|
if (pp_port->alproto_mask != ip_proto[i].port[k].alproto_mask)
|
|
goto end;
|
|
if (pp_port->dp_max_depth != ip_proto[i].port[k].dp_max_depth)
|
|
goto end;
|
|
if (pp_port->sp_max_depth != ip_proto[i].port[k].sp_max_depth)
|
|
goto end;
|
|
|
|
AppLayerProtoDetectProbingParserElement *pp_element = pp_port->dp;
|
|
#ifdef DEBUG
|
|
dir = 0;
|
|
#endif
|
|
for (j = 0 ; j < ip_proto[i].port[k].ts_no_of_element;
|
|
j++, pp_element = pp_element->next) {
|
|
|
|
if (pp_element->alproto != ip_proto[i].port[k].toserver_element[j].alproto) {
|
|
goto end;
|
|
}
|
|
if (pp_element->port != ip_proto[i].port[k].toserver_element[j].port) {
|
|
goto end;
|
|
}
|
|
if (pp_element->alproto_mask != ip_proto[i].port[k].toserver_element[j].alproto_mask) {
|
|
goto end;
|
|
}
|
|
if (pp_element->min_depth != ip_proto[i].port[k].toserver_element[j].min_depth) {
|
|
goto end;
|
|
}
|
|
if (pp_element->max_depth != ip_proto[i].port[k].toserver_element[j].max_depth) {
|
|
goto end;
|
|
}
|
|
} /* for */
|
|
if (pp_element != NULL)
|
|
goto end;
|
|
|
|
pp_element = pp_port->sp;
|
|
#ifdef DEBUG
|
|
dir = 1;
|
|
#endif
|
|
for (j = 0 ; j < ip_proto[i].port[k].tc_no_of_element; j++, pp_element = pp_element->next) {
|
|
if (pp_element->alproto != ip_proto[i].port[k].toclient_element[j].alproto) {
|
|
goto end;
|
|
}
|
|
if (pp_element->port != ip_proto[i].port[k].toclient_element[j].port) {
|
|
goto end;
|
|
}
|
|
if (pp_element->alproto_mask != ip_proto[i].port[k].toclient_element[j].alproto_mask) {
|
|
goto end;
|
|
}
|
|
if (pp_element->min_depth != ip_proto[i].port[k].toclient_element[j].min_depth) {
|
|
goto end;
|
|
}
|
|
if (pp_element->max_depth != ip_proto[i].port[k].toclient_element[j].max_depth) {
|
|
goto end;
|
|
}
|
|
} /* for */
|
|
if (pp_element != NULL)
|
|
goto end;
|
|
}
|
|
if (pp_port != NULL)
|
|
goto end;
|
|
}
|
|
if (pp != NULL)
|
|
goto end;
|
|
|
|
result = 1;
|
|
end:
|
|
#ifdef DEBUG
|
|
printf("i = %d, k = %d, j = %d(%s)\n", i, k, j, (dir == 0) ? "ts" : "tc");
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
static uint16_t ProbingParserDummyForTesting(Flow *f,
|
|
uint8_t *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, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"80",
|
|
ALPROTO_SMB,
|
|
5, 6,
|
|
STREAM_TOSERVER,
|
|
ProbingParserDummyForTesting, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"80",
|
|
ALPROTO_FTP,
|
|
7, 10,
|
|
STREAM_TOSERVER,
|
|
ProbingParserDummyForTesting, NULL);
|
|
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"81",
|
|
ALPROTO_DCERPC,
|
|
9, 10,
|
|
STREAM_TOSERVER,
|
|
ProbingParserDummyForTesting, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"81",
|
|
ALPROTO_FTP,
|
|
7, 15,
|
|
STREAM_TOSERVER,
|
|
ProbingParserDummyForTesting, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"0",
|
|
ALPROTO_SMTP,
|
|
12, 0,
|
|
STREAM_TOSERVER,
|
|
ProbingParserDummyForTesting, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"0",
|
|
ALPROTO_TLS,
|
|
12, 18,
|
|
STREAM_TOSERVER,
|
|
ProbingParserDummyForTesting, NULL);
|
|
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"85",
|
|
ALPROTO_DCERPC,
|
|
9, 10,
|
|
STREAM_TOSERVER,
|
|
ProbingParserDummyForTesting, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"85",
|
|
ALPROTO_FTP,
|
|
7, 15,
|
|
STREAM_TOSERVER,
|
|
ProbingParserDummyForTesting, NULL);
|
|
result = 1;
|
|
|
|
AppLayerProtoDetectPPRegister(IPPROTO_UDP,
|
|
"85",
|
|
ALPROTO_IMAP,
|
|
12, 23,
|
|
STREAM_TOSERVER,
|
|
ProbingParserDummyForTesting, NULL);
|
|
|
|
/* toclient */
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"0",
|
|
ALPROTO_JABBER,
|
|
12, 23,
|
|
STREAM_TOCLIENT,
|
|
ProbingParserDummyForTesting, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"0",
|
|
ALPROTO_IRC,
|
|
12, 14,
|
|
STREAM_TOCLIENT,
|
|
ProbingParserDummyForTesting, NULL);
|
|
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"85",
|
|
ALPROTO_DCERPC,
|
|
9, 10,
|
|
STREAM_TOCLIENT,
|
|
ProbingParserDummyForTesting, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"81",
|
|
ALPROTO_FTP,
|
|
7, 15,
|
|
STREAM_TOCLIENT,
|
|
ProbingParserDummyForTesting, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"0",
|
|
ALPROTO_TLS,
|
|
12, 18,
|
|
STREAM_TOCLIENT,
|
|
ProbingParserDummyForTesting, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"80",
|
|
ALPROTO_HTTP,
|
|
5, 8,
|
|
STREAM_TOCLIENT,
|
|
ProbingParserDummyForTesting, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"81",
|
|
ALPROTO_DCERPC,
|
|
9, 10,
|
|
STREAM_TOCLIENT,
|
|
ProbingParserDummyForTesting, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"90",
|
|
ALPROTO_FTP,
|
|
7, 15,
|
|
STREAM_TOCLIENT,
|
|
ProbingParserDummyForTesting, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"80",
|
|
ALPROTO_SMB,
|
|
5, 6,
|
|
STREAM_TOCLIENT,
|
|
ProbingParserDummyForTesting, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_UDP,
|
|
"85",
|
|
ALPROTO_IMAP,
|
|
12, 23,
|
|
STREAM_TOCLIENT,
|
|
ProbingParserDummyForTesting, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"0",
|
|
ALPROTO_SMTP,
|
|
12, 17,
|
|
STREAM_TOCLIENT,
|
|
ProbingParserDummyForTesting, NULL);
|
|
AppLayerProtoDetectPPRegister(IPPROTO_TCP,
|
|
"80",
|
|
ALPROTO_FTP,
|
|
7, 10,
|
|
STREAM_TOCLIENT,
|
|
ProbingParserDummyForTesting, NULL);
|
|
|
|
AppLayerProtoDetectPPTestDataElement element_ts_80[] = {
|
|
{ "http", ALPROTO_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->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);
|
|
|
|
FLOWLOCK_WRLOCK(f);
|
|
int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
|
|
STREAM_TOSERVER, http_buf1, http_buf1_len);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
FLOWLOCK_UNLOCK(f);
|
|
goto end;
|
|
}
|
|
FLOWLOCK_UNLOCK(f);
|
|
|
|
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->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);
|
|
|
|
FLOWLOCK_WRLOCK(f);
|
|
int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
|
|
STREAM_TOSERVER, http_buf1, http_buf1_len);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
FLOWLOCK_UNLOCK(f);
|
|
goto end;
|
|
}
|
|
FLOWLOCK_UNLOCK(f);
|
|
|
|
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->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);
|
|
|
|
FLOWLOCK_WRLOCK(f);
|
|
int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_HTTP,
|
|
STREAM_TOSERVER, http_buf1, http_buf1_len);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
FLOWLOCK_UNLOCK(f);
|
|
goto end;
|
|
}
|
|
FLOWLOCK_UNLOCK(f);
|
|
|
|
http_state = f->alstate;
|
|
if (http_state == NULL) {
|
|
printf("no http state: ");
|
|
goto end;
|
|
}
|
|
|
|
/* do detect */
|
|
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
|
|
|
|
if (PacketAlertCheck(p, 1)) {
|
|
printf("sig 1 alerted, but it should not (it's not ftp): ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
end:
|
|
if (alp_tctx != NULL)
|
|
AppLayerParserThreadCtxFree(alp_tctx);
|
|
if (det_ctx != NULL)
|
|
DetectEngineThreadCtxDeinit(&tv, det_ctx);
|
|
if (de_ctx != NULL)
|
|
SigGroupCleanup(de_ctx);
|
|
if (de_ctx != NULL)
|
|
DetectEngineCtxFree(de_ctx);
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
|
|
UTHFreePackets(&p, 1);
|
|
UTHFreeFlow(f);
|
|
return result;
|
|
}
|
|
|
|
/** \test test if the engine detect the proto and doesn't match
|
|
* because the packet has another proto (ex ftp) */
|
|
static int AppLayerProtoDetectTest19(void)
|
|
{
|
|
int result = 0;
|
|
Flow *f = NULL;
|
|
uint8_t http_buf1[] = "MPUT one\r\n";
|
|
uint32_t http_buf1_len = sizeof(http_buf1) - 1;
|
|
TcpSession ssn;
|
|
Packet *p = NULL;
|
|
Signature *s = NULL;
|
|
ThreadVars tv;
|
|
DetectEngineThreadCtx *det_ctx = NULL;
|
|
DetectEngineCtx *de_ctx = NULL;
|
|
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
|
|
|
|
memset(&tv, 0, sizeof(ThreadVars));
|
|
memset(&ssn, 0, sizeof(TcpSession));
|
|
|
|
p = UTHBuildPacketSrcDstPorts(http_buf1, http_buf1_len, IPPROTO_TCP, 12345, 88);
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
|
|
if (f == NULL)
|
|
goto end;
|
|
f->protoctx = &ssn;
|
|
f->proto = IPPROTO_TCP;
|
|
p->flow = f;
|
|
p->flowflags |= FLOW_PKT_TOSERVER;
|
|
p->flowflags |= FLOW_PKT_ESTABLISHED;
|
|
p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST;
|
|
f->alproto = ALPROTO_FTP;
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
de_ctx = DetectEngineCtxInit();
|
|
if (de_ctx == NULL) {
|
|
goto end;
|
|
}
|
|
de_ctx->flags |= DE_QUIET;
|
|
|
|
s = de_ctx->sig_list = SigInit(de_ctx, "alert http any !80 -> any any "
|
|
"(msg:\"http over non standar port\"; "
|
|
"sid:1;)");
|
|
if (s == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
SigGroupBuild(de_ctx);
|
|
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
|
|
|
|
FLOWLOCK_WRLOCK(f);
|
|
int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_FTP,
|
|
STREAM_TOSERVER, http_buf1, http_buf1_len);
|
|
if (r != 0) {
|
|
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
|
|
FLOWLOCK_UNLOCK(f);
|
|
goto end;
|
|
}
|
|
FLOWLOCK_UNLOCK(f);
|
|
|
|
/* do detect */
|
|
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
|
|
|
|
if (PacketAlertCheck(p, 1)) {
|
|
printf("sig 1 alerted, but it should not (it's ftp): ");
|
|
goto end;
|
|
}
|
|
|
|
result = 1;
|
|
|
|
end:
|
|
if (alp_tctx != NULL)
|
|
AppLayerParserThreadCtxFree(alp_tctx);
|
|
if (det_ctx != NULL)
|
|
DetectEngineThreadCtxDeinit(&tv, det_ctx);
|
|
if (de_ctx != NULL)
|
|
SigGroupCleanup(de_ctx);
|
|
if (de_ctx != NULL)
|
|
DetectEngineCtxFree(de_ctx);
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
UTHFreePackets(&p, 1);
|
|
UTHFreeFlow(f);
|
|
return result;
|
|
}
|
|
|
|
void AppLayerProtoDetectUnittestsRegister(void)
|
|
{
|
|
SCEnter();
|
|
|
|
UtRegisterTest("AppLayerProtoDetectTest01", AppLayerProtoDetectTest01);
|
|
UtRegisterTest("AppLayerProtoDetectTest02", AppLayerProtoDetectTest02);
|
|
UtRegisterTest("AppLayerProtoDetectTest03", AppLayerProtoDetectTest03);
|
|
UtRegisterTest("AppLayerProtoDetectTest04", AppLayerProtoDetectTest04);
|
|
UtRegisterTest("AppLayerProtoDetectTest05", AppLayerProtoDetectTest05);
|
|
UtRegisterTest("AppLayerProtoDetectTest06", AppLayerProtoDetectTest06);
|
|
UtRegisterTest("AppLayerProtoDetectTest07", AppLayerProtoDetectTest07);
|
|
UtRegisterTest("AppLayerProtoDetectTest08", AppLayerProtoDetectTest08);
|
|
UtRegisterTest("AppLayerProtoDetectTest09", AppLayerProtoDetectTest09);
|
|
UtRegisterTest("AppLayerProtoDetectTest10", AppLayerProtoDetectTest10);
|
|
UtRegisterTest("AppLayerProtoDetectTest11", AppLayerProtoDetectTest11);
|
|
UtRegisterTest("AppLayerProtoDetectTest12", AppLayerProtoDetectTest12);
|
|
UtRegisterTest("AppLayerProtoDetectTest13", AppLayerProtoDetectTest13);
|
|
UtRegisterTest("AppLayerProtoDetectTest14", AppLayerProtoDetectTest14);
|
|
UtRegisterTest("AppLayerProtoDetectTest15", AppLayerProtoDetectTest15);
|
|
UtRegisterTest("AppLayerProtoDetectTest16", AppLayerProtoDetectTest16);
|
|
UtRegisterTest("AppLayerProtoDetectTest17", AppLayerProtoDetectTest17);
|
|
UtRegisterTest("AppLayerProtoDetectTest18", AppLayerProtoDetectTest18);
|
|
UtRegisterTest("AppLayerProtoDetectTest19", AppLayerProtoDetectTest19);
|
|
|
|
SCReturn;
|
|
}
|
|
|
|
#endif /* UNITTESTS */
|