diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index c98fe18511..88cd738c61 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -91,6 +91,74 @@ #define SMTP_EHLO_EXTENSION_STARTTLS #define SMTP_EHLO_EXTENSION_8BITMIME + +#define SMTP_MPM MPM_AC + +static MpmCtx *smtp_mpm_ctx = NULL; +MpmThreadCtx *smtp_mpm_thread_ctx; + +/* smtp reply codes. If an entry is made here, please make a simultaneous + * entry in smtp_reply_map */ +enum { + SMTP_REPLY_211, + SMTP_REPLY_214, + SMTP_REPLY_220, + SMTP_REPLY_221, + SMTP_REPLY_250, + SMTP_REPLY_251, + SMTP_REPLY_252, + + SMTP_REPLY_354, + + SMTP_REPLY_421, + SMTP_REPLY_450, + SMTP_REPLY_451, + SMTP_REPLY_452, + SMTP_REPLY_455, + + SMTP_REPLY_500, + SMTP_REPLY_501, + SMTP_REPLY_502, + SMTP_REPLY_503, + SMTP_REPLY_504, + SMTP_REPLY_550, + SMTP_REPLY_551, + SMTP_REPLY_552, + SMTP_REPLY_553, + SMTP_REPLY_554, + SMTP_REPLY_555, +}; + +SCEnumCharMap smtp_reply_map[ ] = { + { "211", SMTP_REPLY_211 }, + { "214", SMTP_REPLY_214 }, + { "220", SMTP_REPLY_220 }, + { "221", SMTP_REPLY_221 }, + { "250", SMTP_REPLY_250 }, + { "251", SMTP_REPLY_251 }, + { "252", SMTP_REPLY_252 }, + + { "354", SMTP_REPLY_354 }, + + { "421", SMTP_REPLY_421 }, + { "450", SMTP_REPLY_450 }, + { "451", SMTP_REPLY_451 }, + { "452", SMTP_REPLY_452 }, + { "455", SMTP_REPLY_455 }, + + { "500", SMTP_REPLY_500 }, + { "501", SMTP_REPLY_501 }, + { "502", SMTP_REPLY_502 }, + { "503", SMTP_REPLY_503 }, + { "504", SMTP_REPLY_504 }, + { "550", SMTP_REPLY_550 }, + { "551", SMTP_REPLY_551 }, + { "552", SMTP_REPLY_552 }, + { "553", SMTP_REPLY_553 }, + { "554", SMTP_REPLY_554 }, + { "555", SMTP_REPLY_555 }, + { NULL, -1 }, +}; //static void SMTPParserReset(void) //{ // return; @@ -131,7 +199,7 @@ static int SMTPGetLine(SMTPState *state) uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len); if (lf_idx == NULL) { - /* set decoder event */ + /* Fragmented line - set decoder event */ if (state->ts_current_line_db == 0) { state->ts_db = SCMalloc(state->input_len); if (state->ts_db == NULL) { @@ -190,6 +258,7 @@ static int SMTPGetLine(SMTPState *state) state->current_line_len--; state->current_line_delimiter_len = 2; } else { + /* set decoder event for just LF delimiter */ state->current_line_delimiter_len = 1; } } @@ -219,7 +288,7 @@ static int SMTPGetLine(SMTPState *state) uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len); if (lf_idx == NULL) { - /* set decoder event */ + /* Fragmented line - set decoder event */ if (state->tc_current_line_db == 0) { state->tc_db = SCMalloc(state->input_len); if (state->tc_db == NULL) { @@ -278,6 +347,7 @@ static int SMTPGetLine(SMTPState *state) state->current_line_len--; state->current_line_delimiter_len = 2; } else { + /* set decoder event for just LF delimiter */ state->current_line_delimiter_len = 1; } } @@ -373,11 +443,6 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, { uint64_t reply_code = 0; - if (state->cmds_idx == state->cmds_cnt) { - /* decoder event - unable to match reply with request */ - return -1; - } - /* the reply code has to contain at least 3 bytes, to hold the 3 digit * reply code */ if (state->current_line_len < 3) { @@ -401,9 +466,20 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, } } - if (ByteExtractString(&reply_code, 10, 3, - (const char *)state->current_line) < 3) { - /* decoder event */ + /* I don't like this pmq reset here. We'll devise a method later, that + * should make the use of the mpm very efficient */ + PmqReset(state->pmq); + int mpm_cnt = mpm_table[SMTP_MPM].Search(smtp_mpm_ctx, smtp_mpm_thread_ctx, + state->pmq, state->current_line, + 3); + if (mpm_cnt == 0) { + /* set decoder event - reply code invalid */ + return -1; + } + reply_code = smtp_reply_map[state->pmq->pattern_id_array[0]].enum_value; + + if (state->cmds_idx == state->cmds_cnt) { + /* decoder event - unable to match reply with request */ return -1; } @@ -416,13 +492,15 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, * leave without matching it against any buffered command */ if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN; - if (reply_code == 220) { + if (reply_code == SMTP_REPLY_220) { return 0; + } else { + /* set decoder event - first reply from server not a welcome message */ } } if (state->cmds[state->cmds_idx] == SMTP_COMMAND_STARTTLS) { - if (reply_code == 220) { + if (reply_code == SMTP_REPLY_220) { /* we are entering STARRTTLS data mode */ state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; pstate->flags |= APP_LAYER_PARSER_DONE; @@ -432,17 +510,19 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, /* decoder event */ } } else if (state->cmds[state->cmds_idx] == SMTP_COMMAND_DATA) { - if (reply_code == 354) { + if (reply_code == SMTP_REPLY_354) { /* Next comes the mail for the DATA command in toserver direction */ state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; } else { /* decoder event */ } } else { - /* we don't care for any other command */ + /* we don't care for any other command for now */ + /* check if reply falls in the valid list of replies for SMTP. If not + * decoder event */ } - /* if it is a multiline reply, we need to move the index only once for all + /* if it is a multi-line reply, we need to move the index only once for all * the line of the reply. We unset the multiline flag on the last * line of the multiline reply, following which we increment the index */ if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) { @@ -601,6 +681,14 @@ static void *SMTPStateAlloc(void) } smtp_state->cmds_buffer_len = SMTP_COMMAND_BUFFER_STEPS; + smtp_state->pmq = SCMalloc(sizeof(PatternMatcherQueue)); + if (smtp_state->pmq == NULL) { + /* we need to exit here, since it is load time */ + exit(EXIT_FAILURE); + } + PmqSetup(smtp_state->pmq, 0, + sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 2); + return smtp_state; } @@ -612,6 +700,10 @@ static void SMTPStateFree(void *p) { SMTPState *smtp_state = (SMTPState *)p; + if (smtp_state->pmq != NULL) { + PmqFree(smtp_state->pmq); + SCFree(smtp_state->pmq); + } if (smtp_state->cmds != NULL) { SCFree(smtp_state->cmds); } @@ -627,6 +719,41 @@ static void SMTPStateFree(void *p) return; } +static void SMTPSetMpmState(void) +{ + smtp_mpm_ctx = SCMalloc(sizeof(MpmCtx)); + if (smtp_mpm_ctx == NULL) { + /* we need to exit here, since it is load time */ + exit(EXIT_FAILURE); + } + memset(smtp_mpm_ctx, 0, sizeof(MpmCtx)); + + smtp_mpm_thread_ctx = SCMalloc(sizeof(MpmThreadCtx)); + if (smtp_mpm_thread_ctx == NULL) { + /* we need to exit here, since it is load time */ + exit(EXIT_FAILURE); + } + memset(smtp_mpm_thread_ctx, 0, sizeof(MpmThreadCtx)); + + mpm_table[SMTP_MPM].InitCtx(smtp_mpm_ctx, -1); + mpm_table[SMTP_MPM].InitThreadCtx(smtp_mpm_ctx, smtp_mpm_thread_ctx, 0); + + uint32_t i = 0; + for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) { + SCEnumCharMap *map = &smtp_reply_map[i]; + mpm_table[SMTP_MPM].AddPatternNocase(smtp_mpm_ctx, + (uint8_t *)map->enum_name, + 3 /* reply codes always 3 bytes */, + 0 /* now defunct option */, + 0 /* now defunct option */, + i /* pattern id */, + 0 /* no sid */, + 0 /* no flags */); + } + + mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx); +} + /** * \brief Register the SMPT Protocol parser. */ @@ -644,6 +771,8 @@ void RegisterSMTPParsers(void) AppLayerRegisterProto("smtp", ALPROTO_SMTP, STREAM_TOCLIENT, SMTPParseServerRecord); + SMTPSetMpmState(); + return; } diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index dd798b1424..40bc09d917 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -73,6 +73,9 @@ typedef struct SMTPState_ { /** index of the command in the buffer, currently in inspection by reply * handler */ uint16_t cmds_idx; + + /* needed by the mpm */ + PatternMatcherQueue *pmq; } SMTPState; void RegisterSMTPParsers(void); diff --git a/src/detect-engine.c b/src/detect-engine.c index d31c3a7b44..ed84290f0a 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -425,12 +425,16 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) { if (det_ctx->de_state_sig_array == NULL) { return TM_ECODE_FAILED; } + memset(det_ctx->de_state_sig_array, 0, + det_ctx->de_state_sig_array_len * sizeof(uint8_t)); det_ctx->match_array_len = de_ctx->sig_array_len; det_ctx->match_array = SCMalloc(det_ctx->match_array_len * sizeof(Signature *)); if (det_ctx->match_array == NULL) { return TM_ECODE_FAILED; } + memset(det_ctx->match_array, 0, + det_ctx->match_array_len * sizeof(Signature *)); } /** alert counter setup */