From ecabf621a96d463b7cd7ad8a83b90ddb548e8f3f Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Wed, 5 Dec 2018 09:31:56 +0100 Subject: [PATCH 1/2] smtp: improve pipelining support Fixes #1863 --- src/app-layer-smtp.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index cc6d9ea2ada..29a91c709bc 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -81,6 +81,8 @@ #define SMTP_PARSER_STATE_FIRST_REPLY_SEEN 0x04 /* Used to indicate that the parser is parsing a multiline reply */ #define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY 0x08 +/* Used to indicate that the server supports pipelining */ +#define SMTP_PARSER_STATE_PIPELINING_SERVER 0x10 /* Various SMTP commands * We currently have var-ified just STARTTLS and DATA, since we need to them @@ -1000,6 +1002,12 @@ static int SMTPProcessReply(SMTPState *state, Flow *f, * line of the multiline reply, following which we increment the index */ if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) { state->cmds_idx++; + } else if (state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + /* we check if the server is indicating pipelining support */ + if (reply_code == SMTP_REPLY_250 && state->current_line_len == 14 && + SCMemcmpLowercase("pipelining", state->current_line+4, 10) == 0) { + state->parser_state |= SMTP_PARSER_STATE_PIPELINING_SERVER; + } } /* if we have matched all the buffered commands, reset the cnt and index */ @@ -1189,7 +1197,10 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f, tx->msg_tail = tx->mime_state->msg; } } - + /* Enter immediately data mode without waiting for server reply */ + if (state->parser_state & SMTP_PARSER_STATE_PIPELINING_SERVER) { + state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE; + } } else if (state->current_line_len >= 4 && SCMemcmpLowercase("bdat", state->current_line, 4) == 0) { r = SMTPParseCommandBDAT(state); @@ -2769,6 +2780,7 @@ static int SMTPParserTest03(void) /* MAIL FROM:pbsf@asdfs.com * RCPT TO:pbsf@asdfs.com * DATA + * Immediate data */ uint8_t request2[] = { 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f, @@ -2777,7 +2789,9 @@ static int SMTPParserTest03(void) 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d, - 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a + 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a, + 0x49, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, + 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0d, 0x0a, }; uint32_t request2_len = sizeof(request2); /* 250 2.1.0 Ok @@ -2863,7 +2877,8 @@ static int SMTPParserTest03(void) if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + smtp_state->parser_state != ( SMTP_PARSER_STATE_FIRST_REPLY_SEEN | + SMTP_PARSER_STATE_PIPELINING_SERVER)) { printf("smtp parser in inconsistent state\n"); goto end; } @@ -2883,7 +2898,9 @@ static int SMTPParserTest03(void) smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD || smtp_state->cmds[2] != SMTP_COMMAND_DATA || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | + SMTP_PARSER_STATE_COMMAND_DATA_MODE | + SMTP_PARSER_STATE_PIPELINING_SERVER)) { printf("smtp parser in inconsistent state\n"); goto end; } @@ -2901,7 +2918,8 @@ static int SMTPParserTest03(void) smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | - SMTP_PARSER_STATE_COMMAND_DATA_MODE)) { + SMTP_PARSER_STATE_COMMAND_DATA_MODE | + SMTP_PARSER_STATE_PIPELINING_SERVER)) { printf("smtp parser in inconsistent state\n"); goto end; } From 1b10f69315776f8fc7f2b2e5b0fdee0ecfe19b9e Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Wed, 5 Dec 2018 10:22:18 +0100 Subject: [PATCH 2/2] Fixes other affected tests for smtp pipelining Either checking state has pipelining Or removing pipelining from input --- src/app-layer-smtp.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 29a91c709bc..e525dadb7df 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -1972,8 +1972,6 @@ static int SMTPParserTest02(void) 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d, - 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50, - 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, @@ -3179,7 +3177,8 @@ static int SMTPParserTest05(void) if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | + SMTP_PARSER_STATE_PIPELINING_SERVER)) { printf("smtp parser in inconsistent state\n"); goto end; } @@ -3197,7 +3196,8 @@ static int SMTPParserTest05(void) smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | + SMTP_PARSER_STATE_PIPELINING_SERVER)) { printf("smtp parser in inconsistent state\n"); goto end; } @@ -3214,7 +3214,8 @@ static int SMTPParserTest05(void) if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | + SMTP_PARSER_STATE_PIPELINING_SERVER)) { printf("smtp parser in inconsistent state\n"); goto end; } @@ -3239,7 +3240,8 @@ static int SMTPParserTest05(void) smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 || smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD || - smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) { + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | + SMTP_PARSER_STATE_PIPELINING_SERVER)) { printf("smtp parser in inconsistent state\n"); goto end; } @@ -3256,7 +3258,8 @@ static int SMTPParserTest05(void) if (smtp_state->input_len != 0 || smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 || - smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) { + smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN | + SMTP_PARSER_STATE_PIPELINING_SERVER)) { printf("smtp parser in inconsistent state\n"); goto end; } @@ -3343,8 +3346,6 @@ static int SMTPParserTest06(void) 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39, 0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, - 0x30, 0x2d, 0x50, 0x49, 0x50, 0x45, 0x4c, 0x49, - 0x4e, 0x49, 0x4e, 0x47, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69, 0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49, @@ -4494,8 +4495,6 @@ static int SMTPParserTest14(void) 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f, 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d, - 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50, - 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,