diff --git a/src/alert-debuglog.c b/src/alert-debuglog.c index bd31517ecd..df2532271f 100644 --- a/src/alert-debuglog.c +++ b/src/alert-debuglog.c @@ -323,12 +323,57 @@ TmEcode AlertDebugLogIPv6(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq return TM_ECODE_OK; } +TmEcode AlertDebugLogDecoderEvent(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) +{ + AlertDebugLogThread *aft = (AlertDebugLogThread *)data; + int i; + char timebuf[64]; + + if (p->alerts.cnt == 0) + return TM_ECODE_OK; + + CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); + + SCMutexLock(&aft->file_ctx->fp_mutex); + + fprintf(aft->file_ctx->fp, "+================\n"); + fprintf(aft->file_ctx->fp, "TIME: %s\n", timebuf); + if (p->pcap_cnt > 0) { + fprintf(aft->file_ctx->fp, "PCAP PKT NUM: %"PRIu64"\n", p->pcap_cnt); + } + fprintf(aft->file_ctx->fp, "ALERT CNT: %" PRIu32 "\n", p->alerts.cnt); + + for (i = 0; i < p->alerts.cnt; i++) { + PacketAlert *pa = &p->alerts.alerts[i]; + + fprintf(aft->file_ctx->fp, "ALERT MSG [%02d]: %s\n", i, pa->msg); + fprintf(aft->file_ctx->fp, "ALERT GID [%02d]: %" PRIu32 "\n", i, pa->gid); + fprintf(aft->file_ctx->fp, "ALERT SID [%02d]: %" PRIu32 "\n", i, pa->sid); + fprintf(aft->file_ctx->fp, "ALERT REV [%02d]: %" PRIu32 "\n", i, pa->rev); + fprintf(aft->file_ctx->fp, "ALERT CLASS [%02d]: %s\n", i, pa->class_msg); + fprintf(aft->file_ctx->fp, "ALERT PRIO [%02d]: %" PRIu32 "\n", i, pa->prio); + } + + aft->file_ctx->alerts += p->alerts.cnt; + + fprintf(aft->file_ctx->fp, "PACKET LEN: %" PRIu32 "\n", p->pktlen); + fprintf(aft->file_ctx->fp, "PACKET:\n"); + PrintRawDataFp(aft->file_ctx->fp, p->pkt, p->pktlen); + + fflush(aft->file_ctx->fp); + SCMutexUnlock(&aft->file_ctx->fp_mutex); + + return TM_ECODE_OK; +} + TmEcode AlertDebugLog (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { if (PKT_IS_IPV4(p)) { return AlertDebugLogIPv4(tv, p, data, pq, postpq); } else if (PKT_IS_IPV6(p)) { return AlertDebugLogIPv6(tv, p, data, pq, postpq); + } else { + return AlertDebugLogDecoderEvent(tv, p, data, pq, postpq); } return TM_ECODE_OK; diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index 2f3adec06f..fb701399fc 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -55,6 +55,7 @@ #include "util-mpm-b2g-cuda.h" #include "util-cuda-handlers.h" #include "util-privs.h" +#include "util-print.h" #define DEFAULT_LOG_FILENAME "fast.log" @@ -202,12 +203,57 @@ TmEcode AlertFastLogIPv6(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, return TM_ECODE_OK; } +TmEcode AlertFastLogDecoderEvent(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) +{ + AlertFastLogThread *aft = (AlertFastLogThread *)data; + int i; + Reference *ref = NULL; + char timebuf[64]; + + if (p->alerts.cnt == 0) + return TM_ECODE_OK; + + CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); + + SCMutexLock(&aft->file_ctx->fp_mutex); + + aft->file_ctx->alerts += p->alerts.cnt; + + for (i = 0; i < p->alerts.cnt; i++) { + PacketAlert *pa = &p->alerts.alerts[i]; + + fprintf(aft->file_ctx->fp, "%s [**] [%" PRIu32 ":%" PRIu32 ":%" PRIu32 "] %s [**] [Classification: %s] [Priority: %" PRIu32 "] [**] [Raw pkt: ", + timebuf, pa->gid, pa->sid, pa->rev, pa->msg, pa->class_msg, pa->prio); + + PrintRawLineHexFp(aft->file_ctx->fp, p->pkt, p->pktlen < 32 ? p->pktlen : 32); + if (p->pcap_cnt != 0) { + fprintf(aft->file_ctx->fp, "] [pcap file packet: %"PRIu64"]", p->pcap_cnt); + } + + if(pa->references != NULL) { + fprintf(aft->file_ctx->fp," "); + for (ref = pa->references; ref != NULL; ref = ref->next) { + fprintf(aft->file_ctx->fp,"[Xref => %s%s]", ref->key, ref->reference); + } + } + + fprintf(aft->file_ctx->fp,"\n"); + + fflush(aft->file_ctx->fp); + } + SCMutexUnlock(&aft->file_ctx->fp_mutex); + + return TM_ECODE_OK; +} + TmEcode AlertFastLog (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { if (PKT_IS_IPV4(p)) { return AlertFastLogIPv4(tv, p, data, pq, postpq); } else if (PKT_IS_IPV6(p)) { return AlertFastLogIPv6(tv, p, data, pq, postpq); + } else { + return AlertFastLogDecoderEvent(tv, p, data, pq, postpq); } return TM_ECODE_OK; diff --git a/src/detect-decode-event.c b/src/detect-decode-event.c index e4b26f901c..ab30ed2ead 100644 --- a/src/detect-decode-event.c +++ b/src/detect-decode-event.c @@ -59,6 +59,7 @@ void DetectDecodeEventRegister (void) { sigmatch_table[DETECT_DECODE_EVENT].Setup = DetectDecodeEventSetup; sigmatch_table[DETECT_DECODE_EVENT].Free = NULL; sigmatch_table[DETECT_DECODE_EVENT].RegisterTests = DecodeEventRegisterTests; + sigmatch_table[DETECT_DECODE_EVENT].flags |= SIGMATCH_DEONLY_COMPAT; const char *eb; int eo; diff --git a/src/detect.c b/src/detect.c index cca6d79a8e..16ed751f04 100644 --- a/src/detect.c +++ b/src/detect.c @@ -520,6 +520,12 @@ SigGroupHead *SigMatchSignaturesGetSgh(DetectEngineCtx *de_ctx, DetectEngineThre int f; SigGroupHead *sgh = NULL; + /* if the packet proto is 0 (not set), we're inspecting it against + * the decoder events sgh we have. */ + if (p->proto == 0 && p->events.cnt > 0) { + SCReturnPtr(de_ctx->decoder_event_sgh, "SigGroupHead"); + } + /* select the flow_gh */ if (p->flowflags & FLOW_PKT_TOCLIENT) f = 0; @@ -1222,8 +1228,10 @@ iponly: } return 1; } + /** - * \brief Check if the initialized signature is inspecting the packet payload + * \internal + * \brief Check if the initialized signature is inspecting the packet payload * \param de_ctx detection engine ctx * \param s the signature * \retval 1 sig is inspecting the payload @@ -1250,6 +1258,43 @@ static int SignatureIsInspectingPayload(DetectEngineCtx *de_ctx, Signature *s) { return 0; } +/** + * \internal + * \brief check if a signature is decoder event matching only + * \param de_ctx detection engine + * \param s the signature to test + * \retval 0 not a DEOnly sig + * \retval 1 DEOnly sig + */ +static int SignatureIsDEOnly(DetectEngineCtx *de_ctx, Signature *s) { + if (s->pmatch != NULL) + return 0; + + if (s->umatch != NULL) + return 0; + + if (s->amatch != NULL) + return 0; + + SigMatch *sm = s->match; + if (sm == NULL) + goto deonly; + + for ( ;sm != NULL; sm = sm->next) { + if ( !(sigmatch_table[sm->type].flags & SIGMATCH_DEONLY_COMPAT)) + return 0; + } + +deonly: + if (!(de_ctx->flags & DE_QUIET)) { + SCLogDebug("DE-ONLY (%" PRIu32 "): source %s, dest %s", s->id, + s->flags & SIG_FLAG_SRC_ANY ? "ANY" : "SET", + s->flags & SIG_FLAG_DST_ANY ? "ANY" : "SET"); + } + + return 1; +} + /** * \brief Add all signatures to their own source address group * @@ -1303,6 +1348,9 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) { cnt_payload++; SCLogDebug("Signature %"PRIu32" is considered \"Payload inspecting\"", tmp_s->id); + } else if (SignatureIsDEOnly(de_ctx, tmp_s) == 1) { + tmp_s->flags |= SIG_FLAG_DEONLY; + SCLogDebug("Signature %"PRIu32" is considered \"Decoder Event only\"", tmp_s->id); } if (tmp_s->flags & SIG_FLAG_APPLAYER) { @@ -1829,6 +1877,15 @@ error: return -1; } +/** + * \internal + * \brief add a decoder event signature to the detection engine ctx + */ +static void DetectEngineAddDecoderEventSig(DetectEngineCtx *de_ctx, Signature *s) { + SCLogDebug("adding signature %"PRIu32" to the decoder event sgh", s->id); + SigGroupHeadAppendSig(de_ctx, &de_ctx->decoder_event_sgh, s); +} + /** * \brief Fill the global src group head, with the sigs included * @@ -1866,13 +1923,15 @@ int SigAddressPrepareStage2(DetectEngineCtx *de_ctx) { /* now for every rule add the source group to our temp lists */ for (tmp_s = de_ctx->sig_list; tmp_s != NULL; tmp_s = tmp_s->next) { - //printf("SigAddressPrepareStage2 tmp_s->id %u\n", tmp_s->id); - if (!(tmp_s->flags & SIG_FLAG_IPONLY)) { + SCLogDebug("tmp_s->id %"PRIu32, tmp_s->id); + if (tmp_s->flags & SIG_FLAG_IPONLY) { + IPOnlyAddSignature(de_ctx, &de_ctx->io_ctx, tmp_s); + } else if (tmp_s->flags & SIG_FLAG_DEONLY) { + DetectEngineAddDecoderEventSig(de_ctx, tmp_s); + } else { DetectEngineLookupFlowAddSig(de_ctx, tmp_s, AF_INET); DetectEngineLookupFlowAddSig(de_ctx, tmp_s, AF_INET6); DetectEngineLookupFlowAddSig(de_ctx, tmp_s, AF_UNSPEC); - } else { - IPOnlyAddSignature(de_ctx, &de_ctx->io_ctx, tmp_s); } sigs++; @@ -2521,6 +2580,15 @@ error: return -1; } +static void DetectEngineBuildDecoderEventSgh(DetectEngineCtx *de_ctx) { + if (de_ctx->decoder_event_sgh == NULL) + return; + + uint32_t max_idx = DetectEngineGetMaxSigId(de_ctx); + SigGroupHeadSetSigCnt(de_ctx->decoder_event_sgh, max_idx); + SigGroupHeadBuildMatchArray(de_ctx, de_ctx->decoder_event_sgh, max_idx); +} + int SigAddressPrepareStage3(DetectEngineCtx *de_ctx) { int r; @@ -2587,6 +2655,9 @@ int SigAddressPrepareStage3(DetectEngineCtx *de_ctx) { } } + /* prepare the decoder event sgh */ + DetectEngineBuildDecoderEventSgh(de_ctx); + /* cleanup group head (uri)content_array's */ SigGroupHeadFreeMpmArrays(de_ctx); /* cleanup group head sig arrays */ @@ -2716,6 +2787,10 @@ int SigAddressPrepareStage4(DetectEngineCtx *de_ctx) { SigGroupHeadBuildHeadArray(de_ctx, sgh); } + if (de_ctx->decoder_event_sgh != NULL) { + SigGroupHeadBuildHeadArray(de_ctx, de_ctx->decoder_event_sgh); + } + SCFree(de_ctx->sgh_array); de_ctx->sgh_array_cnt = 0; de_ctx->sgh_array_size = 0; @@ -2740,7 +2815,7 @@ int SigAddressPrepareStage5(DetectEngineCtx *de_ctx) { for (f = 0; f < FLOW_STATES; f++) { printf("\n"); for (proto = 0; proto < 256; proto++) { - if (proto != 1) + if (proto != 0) continue; for (global_src_gr = de_ctx->flow_gh[f].src_gh[proto]->ipv4_head; global_src_gr != NULL; diff --git a/src/detect.h b/src/detect.h index d40d25605d..22ebb91b9f 100644 --- a/src/detect.h +++ b/src/detect.h @@ -487,6 +487,10 @@ typedef struct DetectEngineCtx_ { struct SigGroupHead_ **sgh_array; uint32_t sgh_array_cnt; uint32_t sgh_array_size; + + /** sgh for signatures that match against invalid packets. In those cases + * we can't lookup by proto, address, port as we don't have these */ + struct SigGroupHead_ *decoder_event_sgh; } DetectEngineCtx; /* Engine groups profiles (low, medium, high, custom) */ diff --git a/src/util-print.c b/src/util-print.c index 740bd7de5f..40357b477f 100644 --- a/src/util-print.c +++ b/src/util-print.c @@ -27,6 +27,28 @@ #include "util-error.h" #include "util-debug.h" +/** + * \brief print a buffer as hex on a single line + * + * Prints in the format "00 AA BB" + * + * \param fp FILE pointer to print to + * \param buf buffer to print from + * \param buflen length of the input buffer + */ +void PrintRawLineHexFp(FILE *fp, uint8_t *buf, uint32_t buflen) +{ + char nbuf[2048] = ""; + char temp[5] = ""; + uint32_t u = 0; + + for (u = 0; u < buflen; u++) { + snprintf(temp, sizeof(temp), "%02X ", buf[u]); + strlcat(nbuf, temp, sizeof(nbuf)); + } + fprintf(fp, "%s", nbuf); +} + void PrintRawUriFp(FILE *fp, uint8_t *buf, uint32_t buflen) { char nbuf[2048] = ""; diff --git a/src/util-print.h b/src/util-print.h index d273db17a5..94e6d807be 100644 --- a/src/util-print.h +++ b/src/util-print.h @@ -24,8 +24,9 @@ #ifndef __UTIL_PRINT_H__ #define __UTIL_PRINT_H__ -void PrintRawUriFp(FILE *fp, uint8_t *buf, uint32_t buflen); -void PrintRawDataFp(FILE *fp, uint8_t *buf, uint32_t buflen); +void PrintRawLineHexFp(FILE *, uint8_t *, uint32_t); +void PrintRawUriFp(FILE *, uint8_t *, uint32_t); +void PrintRawDataFp(FILE *, uint8_t *, uint32_t); #endif /* __UTIL_PRINT_H__ */