/* Copyright (c) 2009 Victor Julien */ /** \file * \author Victor Julien * * A simple application layer (L7) protocol detector. It works by allowing * developers to set a series of patterns that if exactly matching indicate * that the session is a certain protocol. * * \todo More advanced detection methods, regex maybe. * \todo Fall back to port based classification if other detection fails. */ #include "suricata-common.h" #include "debug.h" #include "decode.h" #include "threads.h" #include "tm-modules.h" #include "threadvars.h" #include "tm-threads.h" #include "detect.h" #include "detect-engine.h" #include "detect-content.h" #include "detect-engine-mpm.h" #include "util-print.h" #include "util-pool.h" #include "util-unittest.h" #include "stream-tcp-private.h" #include "stream-tcp-reassemble.h" #include "stream-tcp.h" #include "stream.h" #include "app-layer-protos.h" #include "app-layer-parser.h" #include "app-layer-detect-proto.h" #include "util-cuda.h" #include "util-cuda-handlers.h" #include "util-mpm-b2g-cuda.h" #include "util-debug.h" #define INSPECT_BYTES 32 #define ALP_DETECT_MAX 256 /* undef __SC_CUDA_SUPPORT__. We will get back to this later. Need to * analyze the performance of cuda support for app layer */ #undef __SC_CUDA_SUPPORT__ typedef struct AlpProtoDetectDirection_ { MpmCtx mpm_ctx; uint32_t id; uint16_t map[ALP_DETECT_MAX]; /**< a mapping between condition id's and protocol */ uint16_t max_depth; /**< max depth of all patterns, so we can limit the search */ } AlpProtoDetectDirection; typedef struct AlpProtoDetectCtx_ { AlpProtoDetectDirection toserver; AlpProtoDetectDirection toclient; int alp_content_module_handle; } AlpProtoDetectCtx; static AlpProtoDetectCtx alp_proto_ctx; //static AlpProtoDetectThreadCtx alp_proto_tctx; void AlpProtoInit(AlpProtoDetectCtx *ctx) { memset(ctx, 0x00, sizeof(AlpProtoDetectCtx)); #ifndef __SC_CUDA_SUPPORT__ MpmInitCtx(&ctx->toserver.mpm_ctx, MPM_B2G, -1); MpmInitCtx(&ctx->toclient.mpm_ctx, MPM_B2G, -1); #else ctx->alp_content_module_handle = SCCudaHlRegisterModule("SC_ALP_CONTENT_B2G_CUDA"); MpmInitCtx(&ctx->toserver.mpm_ctx, MPM_B2G_CUDA, ctx->alp_content_module_handle); MpmInitCtx(&ctx->toclient.mpm_ctx, MPM_B2G_CUDA, ctx->alp_content_module_handle); #endif memset(&ctx->toserver.map, 0x00, sizeof(ctx->toserver.map)); memset(&ctx->toclient.map, 0x00, sizeof(ctx->toclient.map)); ctx->toserver.id = 0; ctx->toclient.id = 0; } void AlpProtoTestDestroy(AlpProtoDetectCtx *ctx) { mpm_table[ctx->toserver.mpm_ctx.mpm_type].DestroyCtx(&ctx->toserver.mpm_ctx); mpm_table[ctx->toclient.mpm_ctx.mpm_type].DestroyCtx(&ctx->toclient.mpm_ctx); } void AlpProtoDestroy() { SCEnter(); mpm_table[alp_proto_ctx.toserver.mpm_ctx.mpm_type].DestroyCtx(&alp_proto_ctx.toserver.mpm_ctx); mpm_table[alp_proto_ctx.toclient.mpm_ctx.mpm_type].DestroyCtx(&alp_proto_ctx.toclient.mpm_ctx); SCReturn; } /** \brief Add a proto detection string to the detection ctx. * \param ctx The detection ctx * \param ip_proto The IP proto (TCP, UDP, etc) * \param al_proto Application layer proto * \param content A content string in the 'content:"some|20|string"' format. * \param depth Depth setting for the content. E.g. 4 means that the content has to match in the first 4 bytes of the stream. * \param offset Offset setting for the content. E.g. 4 mean that the content has to match after the first 4 bytes of the stream. * \param flags Set STREAM_TOCLIENT or STREAM_TOSERVER for the direction in which to try to match the content. */ void AlpProtoAdd(AlpProtoDetectCtx *ctx, uint16_t ip_proto, uint16_t al_proto, char *content, uint16_t depth, uint16_t offset, uint8_t flags) { DetectContentData *cd = DetectContentParse(content); if (cd == NULL) { return; } cd->depth = depth; cd->offset = offset; //PrintRawDataFp(stdout,cd->content,cd->content_len); AlpProtoDetectDirection *dir; if (flags & STREAM_TOCLIENT) { dir = &ctx->toclient; } else { dir = &ctx->toserver; } mpm_table[dir->mpm_ctx.mpm_type].AddPattern(&dir->mpm_ctx, cd->content, cd->content_len, cd->offset, cd->depth, dir->id, dir->id, 0); dir->map[dir->id] = al_proto; dir->id++; if (depth > dir->max_depth) dir->max_depth = depth; /* no longer need the cd */ DetectContentFree(cd); } void AlpProtoFinalizeThread(AlpProtoDetectCtx *ctx, AlpProtoDetectThreadCtx *tctx) { uint32_t maxid; memset(tctx, 0x00, sizeof(AlpProtoDetectThreadCtx)); if (ctx->toclient.id > 0) { maxid = ctx->toclient.id; mpm_table[ctx->toclient.mpm_ctx.mpm_type].InitThreadCtx(&ctx->toclient.mpm_ctx, &tctx->toclient.mpm_ctx, maxid); PmqSetup(&tctx->toclient.pmq, maxid); } if (ctx->toserver.id > 0) { maxid = ctx->toserver.id; mpm_table[ctx->toserver.mpm_ctx.mpm_type].InitThreadCtx(&ctx->toserver.mpm_ctx, &tctx->toserver.mpm_ctx, maxid); PmqSetup(&tctx->toserver.pmq, maxid); } } void AlpProtoDeFinalize2Thread(AlpProtoDetectThreadCtx *tctx) { if (alp_proto_ctx.toclient.id > 0) { mpm_table[alp_proto_ctx.toclient.mpm_ctx.mpm_type].DestroyThreadCtx (&alp_proto_ctx.toclient.mpm_ctx, &tctx->toclient.mpm_ctx); /* XXX GS any idea why it is invalid free ?*/ //PmqFree(&tctx->toclient.pmq); } if (alp_proto_ctx.toserver.id > 0) { mpm_table[alp_proto_ctx.toserver.mpm_ctx.mpm_type].DestroyThreadCtx (&alp_proto_ctx.toserver.mpm_ctx, &tctx->toserver.mpm_ctx); //PmqFree(&tctx->toserver.pmq); } } /** \brief to be called by ReassemblyThreadInit * \todo this is a hack, we need a proper place to store the global ctx */ void AlpProtoFinalize2Thread(AlpProtoDetectThreadCtx *tctx) { return AlpProtoFinalizeThread(&alp_proto_ctx, tctx); } void AlpProtoFinalizeGlobal(AlpProtoDetectCtx *ctx) { if (ctx == NULL) return; mpm_table[ctx->toclient.mpm_ctx.mpm_type].Prepare(&ctx->toclient.mpm_ctx); mpm_table[ctx->toserver.mpm_ctx.mpm_type].Prepare(&ctx->toserver.mpm_ctx); #ifdef __SC_CUDA_SUPPORT__ CUcontext context; if (SCCudaCtxPopCurrent(&context) == -1) exit(EXIT_FAILURE); if (B2gCudaStartDispatcherThreadAPC("SC_ALP_CONTENT_B2G_CUDA") == -1) exit(EXIT_FAILURE); #endif /* tell the stream reassembler we only want chunks of size max_depth */ StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOCLIENT, ctx->toclient.max_depth); StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOSERVER, ctx->toserver.max_depth); } void AppLayerDetectProtoThreadInit(void) { AlpProtoInit(&alp_proto_ctx); /** \todo register these in the protocol parser api */ /** HTTP */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "GET", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "PUT", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "POST", 4, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "TRACE", 5, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "OPTIONS", 7, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "CONNECT", 7, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOCLIENT); /** SSH */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SSH, "SSH-", 4, 0, STREAM_TOCLIENT); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SSH, "SSH-", 4, 0, STREAM_TOSERVER); /** SSLv2 */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SSL, "|01 03 00|", 5, 2, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SSL, "|16 03 00|", 5, 2, STREAM_TOSERVER); /** SSLv3 */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|01 03 00|", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|16 03 00|", 3, 0, STREAM_TOSERVER); /* client hello */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|16 03 00|", 3, 0, STREAM_TOCLIENT); /* server hello */ /** TLSv1 */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|01 03 01|", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|16 03 01|", 3, 0, STREAM_TOSERVER); /* client hello */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|16 03 01|", 3, 0, STREAM_TOCLIENT); /* server hello */ /** TLSv1.1 */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|01 03 02|", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|16 03 02|", 3, 0, STREAM_TOSERVER); /* client hello */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|16 03 02|", 3, 0, STREAM_TOCLIENT); /* server hello */ /** TLSv1.2 */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|01 03 03|", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|16 03 03|", 3, 0, STREAM_TOSERVER); /* client hello */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_TLS, "|16 03 03|", 3, 0, STREAM_TOCLIENT); /* server hello */ /** IMAP */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_IMAP, "|2A 20|OK|20|", 5, 0, STREAM_TOCLIENT); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_IMAP, "1|20|capability", 12, 0, STREAM_TOSERVER); /** SMTP */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMTP, "EHLO ", 5, 0, STREAM_TOCLIENT); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMTP, "HELO ", 5, 0, STREAM_TOCLIENT); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMTP, "ESMTP ", 64, 4, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMTP, "SMTP ", 64, 4, STREAM_TOSERVER); /** FTP */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_FTP, "USER ", 5, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_FTP, "PASS ", 5, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_FTP, "PORT ", 5, 0, STREAM_TOSERVER); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_FTP, "AUTH SSL", 8, 0, STREAM_TOCLIENT); /** MSN Messenger */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_MSN, "MSNP", 10, 6, STREAM_TOCLIENT); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_MSN, "MSNP", 10, 6, STREAM_TOSERVER); /** Jabber */ //AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_JABBER, "xmlns='jabber|3A|client'", 74, 53, STREAM_TOCLIENT); //AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_JABBER, "xmlns='jabber|3A|client'", 74, 53, STREAM_TOSERVER); /** SMB */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMB, "|ff|SMB", 8, 4, STREAM_TOCLIENT); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMB, "|ff|SMB", 8, 4, STREAM_TOSERVER); /** SMB2 */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMB2, "|fe|SMB", 8, 4, STREAM_TOCLIENT); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMB2, "|fe|SMB", 8, 4, STREAM_TOSERVER); /** SMB2 */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMB2, "|fe 53 4d 42|", 4, 4, STREAM_TOCLIENT); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMB2, "|fe 53 4d 42|", 4, 4, STREAM_TOSERVER); /** DCERPC */ AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_DCERPC, "|05 00|", 2, 0, STREAM_TOCLIENT); AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_DCERPC, "|05 00|", 2, 0, STREAM_TOSERVER); AlpProtoFinalizeGlobal(&alp_proto_ctx); } uint16_t AppLayerDetectGetProto(AlpProtoDetectCtx *ctx, AlpProtoDetectThreadCtx *tctx, uint8_t *buf, uint16_t buflen, uint8_t flags) { SCEnter(); AlpProtoDetectDirection *dir; AlpProtoDetectDirectionThread *tdir; if (flags & STREAM_TOSERVER) { dir = &ctx->toserver; tdir = &tctx->toserver; } else { dir = &ctx->toclient; tdir = &tctx->toclient; } if (dir->id == 0) { SCReturnUInt(ALPROTO_UNKNOWN); } /* see if we can limit the data we scan */ uint16_t scanlen = buflen; if (scanlen > dir->max_depth) scanlen = dir->max_depth; uint16_t proto = ALPROTO_UNKNOWN; uint32_t cnt = 0; #ifndef __SC_CUDA_SUPPORT__ cnt = mpm_table[dir->mpm_ctx.mpm_type].Search(&dir->mpm_ctx, &tdir->mpm_ctx, &tdir->pmq, buf, scanlen); #else Packet *p = SCMalloc(sizeof(Packet)); if (p == NULL) goto end; memset(p, 0, sizeof(Packet)); p->cuda_done = 0; p->cuda_free_packet = 1; p->cuda_search = 0; p->cuda_mpm_ctx = &dir->mpm_ctx; p->cuda_mtc = &tdir->mpm_ctx; p->cuda_pmq = &tdir->pmq; p->payload = buf; p->payload_len = scanlen; B2gCudaPushPacketTo_tv_CMB2_APC(p); SCMutexLock(&p->cuda_mutex_q); SCondWait(&p->cuda_cond_q, &p->cuda_mutex_q); p->cuda_done = 1; SCMutexUnlock(&p->cuda_mutex_q); cnt = p->cuda_matches; #endif SCLogDebug("scan cnt %" PRIu32 "", cnt); if (cnt == 0) { proto = ALPROTO_UNKNOWN; goto end; } /** We just return the first match * \todo what if we have more? */ proto = dir->map[tdir->pmq.sig_id_array[0]]; end: PmqReset(&tdir->pmq); if (mpm_table[dir->mpm_ctx.mpm_type].Cleanup != NULL) { mpm_table[dir->mpm_ctx.mpm_type].Cleanup(&tdir->mpm_ctx); } #if 0 printf("AppLayerDetectGetProto: returning %" PRIu16 " (%s): ", proto, flags & STREAM_TOCLIENT ? "TOCLIENT" : "TOSERVER"); switch (proto) { case ALPROTO_HTTP: printf("HTTP: "); /* print the first 32 bytes */ if (buflen > 0) { PrintRawUriFp(stdout,buf,(buflen>32)?32:buflen); } printf("\n"); break; case ALPROTO_FTP: printf("FTP\n"); break; case ALPROTO_SSL: printf("SSL\n"); break; case ALPROTO_SSH: printf("SSH\n"); break; case ALPROTO_TLS: printf("TLS\n"); break; case ALPROTO_IMAP: printf("IMAP\n"); break; case ALPROTO_SMTP: printf("SMTP\n"); break; case ALPROTO_JABBER: printf("JABBER\n"); break; case ALPROTO_MSN: printf("MSN\n"); break; case ALPROTO_SMB: printf("SMB\n"); break; case ALPROTO_SMB2: printf("SMB2\n"); break; case ALPROTO_DCERPC: printf("DCERPC\n"); break; case ALPROTO_UNKNOWN: default: printf("UNKNOWN (%u): cnt was %u (", proto, cnt); /* print the first 32 bytes */ if (buflen > 0) { PrintRawUriFp(stdout,buf,(buflen>32)?32:buflen); } printf(")\n"); break; } #endif SCReturnUInt(proto); } int AppLayerHandleMsg(AlpProtoDetectThreadCtx *dp_ctx, StreamMsg *smsg) { SCEnter(); uint16_t alproto = ALPROTO_UNKNOWN; int r = 0; TcpSession *ssn = smsg->flow->protoctx; if (ssn != NULL) { alproto = ssn->alproto; } if (ssn != NULL) { if (smsg->flags & STREAM_START) { SCLogDebug("Stream initializer (len %" PRIu32 " (%" PRIu32 "))", smsg->data.data_len, MSG_DATA_SIZE); //printf("=> Init Stream Data -- start\n"); //PrintRawDataFp(stdout, smsg->init.data, smsg->init.data_len); //printf("=> Init Stream Data -- end\n"); alproto = AppLayerDetectGetProto(&alp_proto_ctx, dp_ctx, smsg->data.data, smsg->data.data_len, smsg->flags); if (alproto != ALPROTO_UNKNOWN) { /* store the proto and setup the L7 data array */ StreamL7DataPtrInit(ssn); ssn->alproto = alproto; r = AppLayerParse(smsg->flow, alproto, smsg->flags, smsg->data.data, smsg->data.data_len); } else { SCLogDebug("ALPROTO_UNKNOWN flow %p", smsg->flow); TcpSession *ssn = smsg->flow->protoctx; if (ssn != NULL) { if (smsg->flags & STREAM_TOCLIENT) { StreamTcpSetSessionNoReassemblyFlag(ssn, 1); } else if (smsg->flags & STREAM_TOSERVER) { StreamTcpSetSessionNoReassemblyFlag(ssn, 0); } } } } else { SCLogDebug("stream data (len %" PRIu32 " (%" PRIu32 ")), alproto " "%"PRIu16" (flow %p)", smsg->data.data_len, MSG_DATA_SIZE, alproto, smsg->flow); //printf("=> Stream Data -- start\n"); //PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); //printf("=> Stream Data -- end\n"); /* if we don't have a data object here we are not getting it * a start msg should have gotten us one */ if (alproto != ALPROTO_UNKNOWN) { r = AppLayerParse(smsg->flow, alproto, smsg->flags, smsg->data.data, smsg->data.data_len); } else { SCLogDebug(" smsg not start, but no l7 data? Weird"); } } } /* flow is free again */ smsg->flow->use_cnt--; /* return the used message to the queue */ StreamMsgReturnToPool(smsg); SCReturnInt(r); } #if 0 void *AppLayerDetectProtoThread(void *td) { ThreadVars *tv = (ThreadVars *)td; char run = TRUE; /* get the stream msg queue for this thread */ StreamMsgQueue *stream_q = StreamMsgQueueGetByPort(0); /* set the minimum size we expect */ StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOSERVER, INSPECT_BYTES); StreamMsgQueueSetMinInitChunkLen(FLOW_PKT_TOCLIENT, INSPECT_BYTES); TmThreadsSetFlag(tv, THV_INIT_DONE); /* main loop */ while(run) { TmThreadTestThreadUnPaused(tv); /* grab a msg, can return NULL on signals */ StreamMsg *smsg = StreamMsgGetFromQueue(stream_q); if (smsg != NULL) { AppLayerHandleMsg(smsg, TRUE); } if (TmThreadsCheckFlag(tv, THV_KILL)) { SCPerfUpdateCounterArray(tv->sc_perf_pca, &tv->sc_perf_pctx, 0); run = 0; } } pthread_exit((void *) 0); } void AppLayerDetectProtoThreadSpawn() { ThreadVars *tv_applayerdetect = NULL; tv_applayerdetect = TmThreadCreateMgmtThread("AppLayerDetectProtoThread", AppLayerDetectProtoThread, 0); if (tv_applayerdetect == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(1); } if (TmThreadSpawn(tv_applayerdetect) != TM_ECODE_OK) { printf("ERROR: TmThreadSpawn failed\n"); exit(1); } #ifdef DEBUG printf("AppLayerDetectProtoThread thread created\n"); #endif return; } #endif #ifdef UNITTESTS int AlpDetectTest01(void) { char *buf = SCStrdup("HTTP"); int r = 1; AlpProtoDetectCtx ctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } buf = SCStrdup("GET"); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOSERVER); if (ctx.toserver.id != 1) { r = 0; } SCFree(buf); AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest02(void) { char *buf = SCStrdup("HTTP"); int r = 1; AlpProtoDetectCtx ctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_HTTP) { r = 0; } buf = SCStrdup("220 "); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 2) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_FTP) { r = 0; } AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest03(void) { uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n"; char *buf = SCStrdup("HTTP"); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_HTTP) { r = 0; } buf = SCStrdup("220 "); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 2) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_FTP) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif uint32_t cnt = mpm_table[ctx.toclient.mpm_ctx.mpm_type].Search(&ctx.toclient.mpm_ctx, &tctx.toclient.mpm_ctx, NULL, l7data, sizeof(l7data)); if (cnt != 1) { printf("cnt %u != 1: ", cnt); r = 0; } AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest04(void) { uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\n"; char *buf = SCStrdup("200 "); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_HTTP) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif uint32_t cnt = mpm_table[ctx.toclient.mpm_ctx.mpm_type].Search(&ctx.toclient.mpm_ctx, &tctx.toclient.mpm_ctx, NULL, l7data, sizeof(l7data)); if (cnt != 0) { printf("cnt %u != 0: ", cnt); r = 0; } AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest05(void) { uint8_t l7data[] = "HTTP/1.1 200 OK\r\nServer: Apache/1.0\r\n\r\nBlahblah"; char *buf = SCStrdup("HTTP"); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_HTTP) { r = 0; } buf = SCStrdup("220 "); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 2) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_FTP) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProto(&ctx, &tctx, l7data,sizeof(l7data), STREAM_TOCLIENT); if (proto != ALPROTO_HTTP) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_HTTP); r = 0; } #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest06(void) { uint8_t l7data[] = "220 Welcome to the OISF FTP server\r\n"; char *buf = SCStrdup("HTTP"); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_HTTP) { r = 0; } buf = SCStrdup("220 "); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_FTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 2) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_FTP) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProto(&ctx, &tctx, l7data,sizeof(l7data), STREAM_TOCLIENT); if (proto != ALPROTO_FTP) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_FTP); r = 0; } #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest07(void) { uint8_t l7data[] = "220 Welcome to the OISF HTTP/FTP server\r\n"; char *buf = SCStrdup("HTTP"); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_HTTP, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_HTTP) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProto(&ctx, &tctx, l7data,sizeof(l7data), STREAM_TOCLIENT); if (proto != ALPROTO_UNKNOWN) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_UNKNOWN); r = 0; } #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest08(void) { uint8_t l7data[] = "\x00\x00\x00\x85" // NBSS "\xff\x53\x4d\x42\x72\x00\x00\x00" // SMB "\x00\x18\x53\xc8\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\xff\xfe\x00\x00\x00\x00" "\x00" // WordCount "\x62\x00" // ByteCount "\x02\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20" "\x31\x2e\x30\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00\x02\x57\x69\x6e\x64\x6f\x77\x73" "\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00\x02\x4c" "\x4d\x31\x2e\x32\x58\x30\x30\x32\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00\x02\x4e\x54" "\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00"; char *buf = SCStrdup("|ff|SMB"); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_SMB, buf, 8, 4, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_SMB) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProto(&ctx, &tctx, l7data,sizeof(l7data), STREAM_TOCLIENT); if (proto != ALPROTO_SMB) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_SMB); r = 0; } #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest09(void) { uint8_t l7data[] = "\x00\x00\x00\x66" // NBSS "\xfe\x53\x4d\x42\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00" // SMB2 "\x3f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x24\x00\x01\x00x00\x00\x00\x00\x00\x00\x0\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x02"; char *buf = SCStrdup("|fe|SMB"); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_SMB2, buf, 8, 4, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_SMB2) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProto(&ctx, &tctx, l7data,sizeof(l7data), STREAM_TOCLIENT); if (proto != ALPROTO_SMB2) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_SMB2); r = 0; } #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } int AlpDetectTest10(void) { uint8_t l7data[] = "\x05\x00\x0b\x03\x10\x00\x00\x00\x48\x00\x00\x00" "\x00\x00\x00\x00\xd0\x16\xd0\x16\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00" "\x01\x00\xb8\x4a\x9f\x4d\x1c\x7d\xcf\x11\x86\x1e\x00\x20\xaf\x6e\x7c\x57" "\x00\x00\x00\x00\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10" "\x48\x60\x02\x00\x00\x00"; char *buf = SCStrdup("|05 00|"); int r = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoInit(&ctx); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_DCERPC, buf, 4, 0, STREAM_TOCLIENT); SCFree(buf); if (ctx.toclient.id != 1) { r = 0; } if (ctx.toclient.map[ctx.toclient.id - 1] != ALPROTO_DCERPC) { r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProto(&ctx, &tctx, l7data,sizeof(l7data), STREAM_TOCLIENT); if (proto != ALPROTO_DCERPC) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_DCERPC); r = 0; } #ifdef __SC_CUDA_SUPPORT__ B2gCudaKillDispatcherThreadAPC(); if (SCCudaHlPushCudaContextFromModule("SC_ALP_CONTENT_B2G_CUDA") == -1) { printf("Call to SCCudaHlPushCudaContextForModule() failed\n"); return 0; } #endif AlpProtoTestDestroy(&ctx); #ifdef __SC_CUDA_SUPPORT__ if (SCCudaCtxPopCurrent(NULL) == -1) { printf("Call to SCCudaCtxPopCurrent() failed\n"); return 0; } #endif return r; } /** \test why we still get http for connect... obviously because we also match on the reply, duh */ int AlpDetectTest11(void) { 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 = 1; AlpProtoDetectCtx ctx; AlpProtoDetectThreadCtx tctx; AlpProtoInit(&ctx); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_HTTP, "GET", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_HTTP, "PUT", 3, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_HTTP, "POST", 4, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_HTTP, "TRACE", 5, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_HTTP, "OPTIONS", 7, 0, STREAM_TOSERVER); AlpProtoAdd(&ctx, IPPROTO_TCP, ALPROTO_HTTP, "HTTP", 4, 0, STREAM_TOCLIENT); if (ctx.toserver.id != 6) { printf("ctx.toserver.id %u != 6: ", ctx.toserver.id); r = 0; } if (ctx.toserver.map[ctx.toserver.id - 1] != ALPROTO_HTTP) { printf("ctx.toserver.id %u != %u: ", ctx.toserver.map[ctx.toserver.id - 1],ALPROTO_HTTP); r = 0; } AlpProtoFinalizeGlobal(&ctx); AlpProtoFinalizeThread(&ctx, &tctx); uint8_t proto = AppLayerDetectGetProto(&ctx, &tctx, l7data, sizeof(l7data), STREAM_TOCLIENT); if (proto == ALPROTO_HTTP) { printf("proto %" PRIu8 " == %" PRIu8 ": ", proto, ALPROTO_HTTP); r = 0; } proto = AppLayerDetectGetProto(&ctx, &tctx, l7data_resp, sizeof(l7data_resp), STREAM_TOSERVER); if (proto != ALPROTO_HTTP) { printf("proto %" PRIu8 " != %" PRIu8 ": ", proto, ALPROTO_HTTP); r = 0; } AlpProtoTestDestroy(&ctx); return r; } #endif /* UNITTESTS */ void AlpDetectRegisterTests(void) { #ifdef UNITTESTS UtRegisterTest("AlpDetectTest01", AlpDetectTest01, 1); UtRegisterTest("AlpDetectTest02", AlpDetectTest02, 1); UtRegisterTest("AlpDetectTest03", AlpDetectTest03, 1); UtRegisterTest("AlpDetectTest04", AlpDetectTest04, 1); UtRegisterTest("AlpDetectTest05", AlpDetectTest05, 1); UtRegisterTest("AlpDetectTest06", AlpDetectTest06, 1); UtRegisterTest("AlpDetectTest07", AlpDetectTest07, 1); UtRegisterTest("AlpDetectTest08", AlpDetectTest08, 1); UtRegisterTest("AlpDetectTest09", AlpDetectTest09, 1); UtRegisterTest("AlpDetectTest10", AlpDetectTest10, 1); UtRegisterTest("AlpDetectTest11", AlpDetectTest11, 1); #endif /* UNITTESTS */ }