suricata
app-layer-smtp.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2025 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18/**
19 * \file
20 *
21 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
22 */
23
24#include "suricata.h"
25#include "suricata-common.h"
26#include "decode.h"
27
28#include "stream-tcp.h"
29
30#include "app-layer.h"
32#include "app-layer-protos.h"
33#include "app-layer-parser.h"
34#include "app-layer-frames.h"
35#include "app-layer-events.h"
36#include "app-layer-smtp.h"
37
38#include "util-enum.h"
39#include "util-mpm.h"
40#include "util-debug.h"
41#include "util-byte.h"
42#include "util-unittest.h"
44#include "util-memcmp.h"
45#include "flow-util.h"
46
47#include "detect-engine.h"
48#include "detect-engine-state.h"
49#include "detect-engine-build.h"
50#include "detect-parse.h"
51
52#include "conf.h"
53
54#include "util-mem.h"
55#include "util-misc.h"
56#include "util-validate.h"
57
58/* content-limit default value */
59#define FILEDATA_CONTENT_LIMIT 100000
60/* content-inspect-min-size default value */
61#define FILEDATA_CONTENT_INSPECT_MIN_SIZE 32768
62/* content-inspect-window default value */
63#define FILEDATA_CONTENT_INSPECT_WINDOW 4096
64
65/* raw extraction default value */
66#define SMTP_RAW_EXTRACTION_DEFAULT_VALUE false
67
68#define SMTP_COMMAND_BUFFER_STEPS 5
69
70/* we are in process of parsing a fresh command. Just a placeholder. If we
71 * are not in STATE_COMMAND_DATA_MODE, we have to be in this mode */
72// unused #define SMTP_PARSER_STATE_COMMAND_MODE 0x00
73/* we are in mode of parsing a command's data. Used when we are parsing tls
74 * or accepting the rfc 2822 mail after DATA command */
75#define SMTP_PARSER_STATE_COMMAND_DATA_MODE 0x01
76/* Used to indicate that the parser has seen the first reply */
77#define SMTP_PARSER_STATE_FIRST_REPLY_SEEN 0x04
78/* Used to indicate that the parser is parsing a multiline reply */
79#define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY 0x08
80/* Used to indicate that the server supports pipelining */
81#define SMTP_PARSER_STATE_PIPELINING_SERVER 0x10
82
83/* Various SMTP commands
84 * We currently have var-ified just STARTTLS and DATA, since we need to them
85 * for state transitions. The rest are just indicate as OTHER_CMD. Other
86 * commands would be introduced as and when needed */
87#define SMTP_COMMAND_STARTTLS 1
88#define SMTP_COMMAND_DATA 2
89#define SMTP_COMMAND_BDAT 3
90/* not an actual command per se, but the mode where we accept the mail after
91 * DATA has it's own reply code for completion, from the server. We give this
92 * stage a pseudo command of it's own, so that we can add this to the command
93 * buffer to match with the reply */
94#define SMTP_COMMAND_DATA_MODE 4
95/* All other commands are represented by this var */
96#define SMTP_COMMAND_OTHER_CMD 5
97#define SMTP_COMMAND_RSET 6
98
99#define SMTP_DEFAULT_MAX_TX 256
100
101typedef struct SMTPInput_ {
102 /* current input that is being parsed */
103 const uint8_t *buf;
104 int32_t len;
105
106 /* original length of an input */
107 int32_t orig_len;
108
109 /* Consumed bytes till current line */
110 int32_t consumed;
112
113typedef struct SMTPLine_ {
114 /** current line extracted by the parser from the call to SMTPGetline() */
115 const uint8_t *buf;
116 /** length of the line in current_line. Doesn't include the delimiter */
117 int32_t len;
118 uint8_t delim_len;
121
123 { "INVALID_REPLY", SMTP_DECODER_EVENT_INVALID_REPLY },
124 { "UNABLE_TO_MATCH_REPLY_WITH_REQUEST", SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST },
125 { "MAX_COMMAND_LINE_LEN_EXCEEDED", SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED },
126 { "MAX_REPLY_LINE_LEN_EXCEEDED", SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED },
127 { "INVALID_PIPELINED_SEQUENCE", SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE },
128 { "BDAT_CHUNK_LEN_EXCEEDED", SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED },
129 { "NO_SERVER_WELCOME_MESSAGE", SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE },
130 { "TLS_REJECTED", SMTP_DECODER_EVENT_TLS_REJECTED },
131 { "DATA_COMMAND_REJECTED", SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED },
132 { "FAILED_PROTOCOL_CHANGE", SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE },
133
134 /* MIME Events */
135 { "MIME_PARSE_FAILED", SMTP_DECODER_EVENT_MIME_PARSE_FAILED },
136 { "MIME_INVALID_BASE64", SMTP_DECODER_EVENT_MIME_INVALID_BASE64 },
137 { "MIME_INVALID_QP", SMTP_DECODER_EVENT_MIME_INVALID_QP },
138 { "MIME_LONG_LINE", SMTP_DECODER_EVENT_MIME_LONG_LINE },
139 { "MIME_LONG_ENC_LINE", SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE },
140 { "MIME_LONG_HEADER_NAME", SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME },
141 { "MIME_LONG_HEADER_VALUE", SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE },
142 { "MIME_LONG_BOUNDARY", SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG },
143 { "MIME_LONG_FILENAME", SMTP_DECODER_EVENT_MIME_LONG_FILENAME },
144
145 /* Invalid behavior or content */
146 { "DUPLICATE_FIELDS", SMTP_DECODER_EVENT_DUPLICATE_FIELDS },
147 { "UNPARSABLE_CONTENT", SMTP_DECODER_EVENT_UNPARSABLE_CONTENT },
148 { "TRUNCATED_LINE", SMTP_DECODER_EVENT_TRUNCATED_LINE },
149 { NULL, -1 },
150};
151
157
159 {
160 "command_line",
162 },
163 {
164 "data",
166 },
167 {
168 "response_line",
170 },
171 { NULL, -1 },
172};
173
174static int SMTPGetFrameIdByName(const char *frame_name)
175{
176 int id = SCMapEnumNameToValue(frame_name, smtp_frame_table);
177 if (id < 0) {
178 return -1;
179 }
180 return id;
181}
182
183static const char *SMTPGetFrameNameById(const uint8_t frame_id)
184{
185 const char *name = SCMapEnumValueToName(frame_id, smtp_frame_table);
186 return name;
187}
188
193
194#define SMTP_MPM mpm_default_matcher
195
196static MpmCtx *smtp_mpm_ctx = NULL;
197
198/* smtp reply codes. If an entry is made here, please make a simultaneous
199 * entry in smtp_reply_map */
209
212
213 SMTP_REPLY_401, // Unauthorized
214 SMTP_REPLY_402, // Command not implemented
216 SMTP_REPLY_435, // Your account has not yet been verified
220 SMTP_REPLY_454, // Temporary authentication failure
222
228 SMTP_REPLY_511, // Bad email address
229 SMTP_REPLY_521, // Server does not accept mail
230 SMTP_REPLY_522, // Recipient has exceeded mailbox limit
231 SMTP_REPLY_525, // User Account Disabled
232 SMTP_REPLY_530, // Authentication required
233 SMTP_REPLY_534, // Authentication mechanism is too weak
234 SMTP_REPLY_535, // Authentication credentials invalid
235 SMTP_REPLY_541, // No response from host
236 SMTP_REPLY_543, // Routing server failure. No available route
243};
244
246 { "211", SMTP_REPLY_211 },
247 { "214", SMTP_REPLY_214 },
248 { "220", SMTP_REPLY_220 },
249 { "221", SMTP_REPLY_221 },
250 { "235", SMTP_REPLY_235 },
251 { "250", SMTP_REPLY_250 },
252 { "251", SMTP_REPLY_251 },
253 { "252", SMTP_REPLY_252 },
254
255 { "334", SMTP_REPLY_334 },
256 { "354", SMTP_REPLY_354 },
257
258 { "401", SMTP_REPLY_401 },
259 { "402", SMTP_REPLY_402 },
260 { "421", SMTP_REPLY_421 },
261 { "435", SMTP_REPLY_435 },
262 { "450", SMTP_REPLY_450 },
263 { "451", SMTP_REPLY_451 },
264 { "452", SMTP_REPLY_452 },
265 { "454", SMTP_REPLY_454 },
266 // { "4.7.0", SMTP_REPLY_454 }, // rfc4954
267 { "455", SMTP_REPLY_455 },
268
269 { "500", SMTP_REPLY_500 },
270 { "501", SMTP_REPLY_501 },
271 { "502", SMTP_REPLY_502 },
272 { "503", SMTP_REPLY_503 },
273 { "504", SMTP_REPLY_504 },
274 { "511", SMTP_REPLY_511 },
275 { "521", SMTP_REPLY_521 },
276 { "522", SMTP_REPLY_522 },
277 { "525", SMTP_REPLY_525 },
278 { "530", SMTP_REPLY_530 },
279 { "534", SMTP_REPLY_534 },
280 { "535", SMTP_REPLY_535 },
281 { "541", SMTP_REPLY_541 },
282 { "543", SMTP_REPLY_543 },
283 { "550", SMTP_REPLY_550 },
284 { "551", SMTP_REPLY_551 },
285 { "552", SMTP_REPLY_552 },
286 { "553", SMTP_REPLY_553 },
287 { "554", SMTP_REPLY_554 },
288 { "555", SMTP_REPLY_555 },
289 { NULL, -1 },
290};
291
292/* Create SMTP config structure */
294 .decode_mime = true,
295 .content_limit = FILEDATA_CONTENT_LIMIT,
296 .content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE,
297 .content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW,
298 .raw_extraction = SMTP_RAW_EXTRACTION_DEFAULT_VALUE,
300};
301
302static SMTPString *SMTPStringAlloc(void);
303
304#define SCHEME_SUFFIX_LEN 3
305
306/**
307 * \brief Configure SMTP Mime Decoder by parsing out mime section of YAML
308 * config file
309 *
310 * \return none
311 */
312static void SMTPConfigure(void) {
313
314 SCEnter();
315 intmax_t imval;
316 uint32_t content_limit = 0;
317 uint32_t content_inspect_min_size = 0;
318 uint32_t content_inspect_window = 0;
319
320 SCConfNode *config = SCConfGetNode("app-layer.protocols.smtp.mime");
321 if (config != NULL) {
322 SCConfNode *extract_urls_schemes = NULL;
323
324 int val;
325 int ret = SCConfGetChildValueBool(config, "decode-mime", &val);
326 if (ret) {
328 }
329
330 ret = SCConfGetChildValueBool(config, "decode-base64", &val);
331 if (ret) {
332 SCMimeSmtpConfigDecodeBase64(val);
333 }
334
335 ret = SCConfGetChildValueBool(config, "decode-quoted-printable", &val);
336 if (ret) {
337 SCMimeSmtpConfigDecodeQuoted(val);
338 }
339
340 ret = SCConfGetChildValueInt(config, "header-value-depth", &imval);
341 if (ret) {
342 if (imval < 0 || imval > UINT32_MAX) {
343 FatalError("Invalid value for header-value-depth");
344 }
345 SCMimeSmtpConfigHeaderValueDepth((uint32_t)imval);
346 }
347
348 ret = SCConfGetChildValueBool(config, "extract-urls", &val);
349 if (ret) {
350 SCMimeSmtpConfigExtractUrls(val);
351 }
352
353 /* Parse extract-urls-schemes from mime config, add '://' suffix to found schemes,
354 * and provide a default value of 'http' for the schemes to be extracted
355 * if no schemes are found in the config */
356 extract_urls_schemes = SCConfNodeLookupChild(config, "extract-urls-schemes");
357 if (extract_urls_schemes) {
358 SCConfNode *scheme = NULL;
359
360 TAILQ_FOREACH (scheme, &extract_urls_schemes->head, next) {
361 size_t scheme_len = strlen(scheme->val);
362 if (scheme_len > UINT16_MAX - SCHEME_SUFFIX_LEN) {
363 FatalError("Too long value for extract-urls-schemes");
364 }
365 if (scheme->val[scheme_len - 1] != '/') {
366 scheme_len += SCHEME_SUFFIX_LEN;
367 char *new_val = SCMalloc(scheme_len + 1);
368 if (unlikely(new_val == NULL)) {
369 FatalError("SCMalloc failure.");
370 }
371 int r = snprintf(new_val, scheme_len + 1, "%s://", scheme->val);
372 if (r != (int)scheme_len) {
373 FatalError("snprintf failure for SMTP url extraction scheme.");
374 }
375 SCFree(scheme->val);
376 scheme->val = new_val;
377 }
378 int r = SCMimeSmtpConfigExtractUrlsSchemeAdd(scheme->val);
379 if (r < 0) {
380 FatalError("Failed to add smtp extract url scheme");
381 }
382 }
383 } else {
384 /* Add default extract url scheme 'http' since
385 * extract-urls-schemes wasn't found in the config */
386 SCMimeSmtpConfigExtractUrlsSchemeAdd("http://");
387 }
388
389 ret = SCConfGetChildValueBool(config, "log-url-scheme", &val);
390 if (ret) {
391 SCMimeSmtpConfigLogUrlScheme(val);
392 }
393
394 ret = SCConfGetChildValueBool(config, "body-md5", &val);
395 if (ret) {
396 SCMimeSmtpConfigBodyMd5(val);
397 }
398 }
399
400 SCConfNode *t = SCConfGetNode("app-layer.protocols.smtp.inspected-tracker");
401 SCConfNode *p = NULL;
402
403 if (t != NULL) {
404 TAILQ_FOREACH(p, &t->head, next) {
405 if (strcasecmp("content-limit", p->name) == 0) {
406 if (ParseSizeStringU32(p->val, &content_limit) < 0) {
407 SCLogWarning("parsing content-limit %s failed", p->val);
408 content_limit = FILEDATA_CONTENT_LIMIT;
409 }
410 smtp_config.content_limit = content_limit;
411 }
412
413 if (strcasecmp("content-inspect-min-size", p->name) == 0) {
414 if (ParseSizeStringU32(p->val, &content_inspect_min_size) < 0) {
415 SCLogWarning("parsing content-inspect-min-size %s failed", p->val);
416 content_inspect_min_size = FILEDATA_CONTENT_INSPECT_MIN_SIZE;
417 }
418 smtp_config.content_inspect_min_size = content_inspect_min_size;
419 }
420
421 if (strcasecmp("content-inspect-window", p->name) == 0) {
422 if (ParseSizeStringU32(p->val, &content_inspect_window) < 0) {
423 SCLogWarning("parsing content-inspect-window %s failed", p->val);
424 content_inspect_window = FILEDATA_CONTENT_INSPECT_WINDOW;
425 }
426 smtp_config.content_inspect_window = content_inspect_window;
427 }
428 }
429 }
430
431 smtp_config.sbcfg.buf_size = content_limit ? content_limit : 256;
432
433 if (SCConfGetBool("app-layer.protocols.smtp.raw-extraction",
434 (int *)&smtp_config.raw_extraction) != 1) {
436 }
438 SCLogError("\"decode-mime\" and \"raw-extraction\" "
439 "options can't be enabled at the same time, "
440 "disabling raw extraction");
442 }
443
444 uint64_t value = SMTP_DEFAULT_MAX_TX;
446 const char *str = NULL;
447 if (SCConfGet("app-layer.protocols.smtp.max-tx", &str) == 1) {
448 if (ParseSizeStringU64(str, &value) < 0) {
449 SCLogWarning("max-tx value cannot be deduced: %s,"
450 " keeping default",
451 str);
452 }
453 smtp_config.max_tx = value;
454 }
455
456 SCReturn;
457}
458
459static void SMTPSetEvent(SMTPState *s, uint8_t e)
460{
461 SCLogDebug("setting event %u", e);
462
463 if (s->curr_tx != NULL) {
465 // s->events++;
466 return;
467 }
468 SCLogDebug("couldn't set event %u", e);
469}
470
471static SMTPTransaction *SMTPTransactionCreate(SMTPState *state)
472{
473 if (state->tx_cnt > smtp_config.max_tx) {
474 return NULL;
475 }
476 SMTPTransaction *tx = SCCalloc(1, sizeof(*tx));
477 if (tx == NULL) {
478 return NULL;
479 }
480
481 TAILQ_INIT(&tx->rcpt_to_list);
482 tx->tx_data.file_tx = STREAM_TOSERVER; // can xfer files
483 return tx;
484}
485
486static void FlagDetectStateNewFile(SMTPTransaction *tx)
487{
488 if (tx && tx->tx_data.de_state) {
489 SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW set");
490 tx->tx_data.de_state->dir_state[0].flags |= DETECT_ENGINE_STATE_FLAG_FILE_NEW;
491 } else if (tx == NULL) {
492 SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW NOT set, no TX");
493 } else if (tx->tx_data.de_state == NULL) {
494 SCLogDebug("DETECT_ENGINE_STATE_FLAG_FILE_NEW NOT set, no TX DESTATE");
495 }
496}
497
498static void SMTPNewFile(SMTPTransaction *tx, File *file)
499{
500 DEBUG_VALIDATE_BUG_ON(tx == NULL);
501 DEBUG_VALIDATE_BUG_ON(file == NULL);
502#ifdef UNITTESTS
503 if (RunmodeIsUnittests()) {
504 if (tx == NULL || file == NULL) {
505 return;
506 }
507 }
508#endif
509 FlagDetectStateNewFile(tx);
510 tx->tx_data.files_opened++;
511
512 /* set inspect sizes used in file pruning logic.
513 * TODO consider moving this to the file.data code that
514 * would actually have use for this. */
517}
518
519/**
520 * \internal
521 * \brief Get the next line from input. It doesn't do any length validation.
522 *
523 * \param state The smtp state.
524 *
525 * \retval 0 On success.
526 * \retval -1 Either when we don't have any new lines to supply anymore or
527 * on failure.
528 */
529static AppLayerResult SMTPGetLine(Flow *f, StreamSlice *slice, SMTPState *state, SMTPInput *input,
530 SMTPLine *line, uint16_t direction)
531{
532 SCEnter();
533
534 /* we have run out of input */
535 if (input->len <= 0)
536 return APP_LAYER_ERROR;
537
538 const uint8_t type = direction == 0 ? SMTP_FRAME_COMMAND_LINE : SMTP_FRAME_RESPONSE_LINE;
539 Frame *frame = AppLayerFrameGetLastOpenByType(f, direction, type);
540 if (frame == NULL) {
541 if (direction == 0 &&
545 f, slice, input->buf + input->consumed, -1, 0, SMTP_FRAME_COMMAND_LINE);
546 /* can't set tx id before (possibly) creating it */
547
548 } else if (direction == 1) {
550 f, slice, input->buf + input->consumed, -1, 1, SMTP_FRAME_RESPONSE_LINE);
551 if (frame != NULL && state->curr_tx) {
552 AppLayerFrameSetTxId(frame, state->curr_tx->tx_id);
553 }
554 }
555 }
556 SCLogDebug("frame %p", frame);
557
558 uint8_t *lf_idx = memchr(input->buf + input->consumed, 0x0a, input->len);
559 bool discard_till_lf = (direction == 0) ? state->discard_till_lf_ts : state->discard_till_lf_tc;
560
561 if (lf_idx == NULL) {
562 if (!discard_till_lf && input->len >= SMTP_LINE_BUFFER_LIMIT) {
563 line->buf = input->buf;
565 line->delim_len = 0;
567 }
568 SCReturnStruct(APP_LAYER_INCOMPLETE(input->consumed, input->len + 1));
569 } else {
570 /* There could be one chunk of command data that has LF but post the line limit
571 * e.g. input_len = 5077
572 * lf_idx = 5010
573 * max_line_len = 4096 */
574 uint32_t o_consumed = input->consumed;
575 input->consumed = (uint32_t)(lf_idx - input->buf + 1);
576 line->len = input->consumed - o_consumed;
577 line->lf_found = true;
578 DEBUG_VALIDATE_BUG_ON(line->len < 0);
579 if (line->len < 0)
581 input->len -= line->len;
582 DEBUG_VALIDATE_BUG_ON((input->consumed + input->len) != input->orig_len);
583 line->buf = input->buf + o_consumed;
584
585 if (frame != NULL) {
586 frame->len = (int64_t)line->len;
587 }
588
589 if (line->len >= SMTP_LINE_BUFFER_LIMIT) {
591 line->delim_len = 0;
593 }
594 if (discard_till_lf) {
595 // Whatever came in with first LF should also get discarded
596 if (direction == 0) {
597 state->discard_till_lf_ts = false;
598 } else {
599 state->discard_till_lf_tc = false;
600 }
601 line->len = 0;
602 line->delim_len = 0;
604 }
605 if (input->consumed >= 2 && input->buf[input->consumed - 2] == 0x0D) {
606 line->delim_len = 2;
607 line->len -= 2;
608 } else {
609 line->delim_len = 1;
610 line->len -= 1;
611 }
613 }
614}
615
616static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state)
617{
618 SCEnter();
619 void *ptmp;
620
621 if (state->cmds_cnt >= state->cmds_buffer_len) {
622 int increment = SMTP_COMMAND_BUFFER_STEPS;
623 if ((int)(state->cmds_buffer_len + SMTP_COMMAND_BUFFER_STEPS) > (int)USHRT_MAX) {
624 increment = USHRT_MAX - state->cmds_buffer_len;
625 }
626
627 ptmp = SCRealloc(state->cmds,
628 sizeof(uint8_t) * (state->cmds_buffer_len + increment));
629 if (ptmp == NULL) {
630 SCFree(state->cmds);
631 state->cmds = NULL;
632 SCLogDebug("SCRealloc failure");
633 return -1;
634 }
635 state->cmds = ptmp;
636
637 state->cmds_buffer_len += increment;
638 }
639 if (state->cmds_cnt >= 1 &&
640 ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) ||
641 (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) {
642 /* decoder event */
644 /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP,
645 * STARTTLS as the last command in pipelined mode */
646 }
647
648 /** \todo decoder event */
649 if ((int)(state->cmds_cnt + 1) > (int)USHRT_MAX) {
650 SCLogDebug("command buffer overflow");
651 return -1;
652 }
653
654 state->cmds[state->cmds_cnt] = command;
655 state->cmds_cnt++;
656
657 return 0;
658}
659
660static int SMTPProcessCommandBDAT(SMTPState *state, const SMTPLine *line)
661{
662 SCEnter();
663
664 state->bdat_chunk_idx += (line->len + line->delim_len);
665 if (state->bdat_chunk_idx > state->bdat_chunk_len) {
666 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
667 /* decoder event */
669 SCReturnInt(-1);
670 } else if (state->bdat_chunk_idx == state->bdat_chunk_len) {
671 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
672 }
673
674 SCReturnInt(0);
675}
676
677static void SetMimeEvents(SMTPState *state, uint32_t events)
678{
679 if (events == 0) {
680 return;
681 }
682
683 if (events & MIME_ANOM_INVALID_BASE64) {
684 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_BASE64);
685 }
686 if (events & MIME_ANOM_INVALID_QP) {
687 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_INVALID_QP);
688 }
689 if (events & MIME_ANOM_LONG_LINE) {
690 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_LINE);
691 }
692 if (events & MIME_ANOM_LONG_ENC_LINE) {
693 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE);
694 }
695 if (events & MIME_ANOM_LONG_HEADER_NAME) {
696 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME);
697 }
698 if (events & MIME_ANOM_LONG_HEADER_VALUE) {
700 }
701 if (events & MIME_ANOM_LONG_BOUNDARY) {
703 }
704 if (events & MIME_ANOM_LONG_FILENAME) {
705 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_FILENAME);
706 }
707}
708
709static inline void SMTPTransactionComplete(SMTPState *state)
710{
711 DEBUG_VALIDATE_BUG_ON(state->curr_tx == NULL);
712 if (state->curr_tx)
713 state->curr_tx->done = true;
714}
715
716/**
717 * \retval 0 ok
718 * \retval -1 error
719 */
720static int SMTPProcessCommandDATA(
721 SMTPState *state, SMTPTransaction *tx, Flow *f, const SMTPLine *line)
722{
723 SCEnter();
724 DEBUG_VALIDATE_BUG_ON(tx == NULL);
725
726 SCTxDataUpdateFileFlags(&tx->tx_data, state->state_data.file_flags);
728 /* looks like are still waiting for a confirmation from the server */
729 return 0;
730 }
731
732 if (line->len == 1 && line->buf[0] == '.') {
733 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
734 /* kinda like a hack. The mail sent in DATA mode, would be
735 * acknowledged with a reply. We insert a dummy command to
736 * the command buffer to be used by the reply handler to match
737 * the reply received */
738 SMTPInsertCommandIntoCommandBuffer(SMTP_COMMAND_DATA_MODE, state);
740 /* we use this as the signal that message data is complete. */
741 FileCloseFile(&tx->files_ts, &smtp_config.sbcfg, NULL, 0, 0);
742 } else if (smtp_config.decode_mime && tx->mime_state != NULL) {
743 /* Complete parsing task */
744 SCSmtpMimeComplete(tx->mime_state);
745 if (tx->files_ts.tail && tx->files_ts.tail->state == FILE_STATE_OPENED) {
746 FileCloseFile(&tx->files_ts, &smtp_config.sbcfg, NULL, 0,
747 FileFlowToFlags(f, STREAM_TOSERVER));
748 }
749 }
750 SMTPTransactionComplete(state);
751 SCLogDebug("marked tx as done");
752 } else if (smtp_config.raw_extraction) {
753 // message not over, store the line. This is a substitution of
754 // ProcessDataChunk
755 FileAppendData(&tx->files_ts, &smtp_config.sbcfg, line->buf, line->len + line->delim_len);
756 }
757
758 /* If DATA, then parse out a MIME message */
759 if (state->current_command == SMTP_COMMAND_DATA &&
761
762 if (smtp_config.decode_mime && tx->mime_state != NULL) {
763 uint32_t events;
764 uint16_t flags = FileFlowToFlags(f, STREAM_TOSERVER);
765 const uint8_t *filename = NULL;
766 uint16_t filename_len = 0;
767 uint32_t depth;
768
769 /* we depend on detection engine for file pruning */
771 MimeSmtpParserResult ret = SCSmtpMimeParseLine(
772 line->buf, line->len, line->delim_len, &events, tx->mime_state);
773 SetMimeEvents(state, events);
774 switch (ret) {
775 case MimeSmtpFileOpen:
776 // get filename owned by mime state
777 SCMimeSmtpGetFilename(state->curr_tx->mime_state, &filename, &filename_len);
778
779 if (filename_len == 0) {
780 // not an attachment
781 break;
782 }
783 depth = (uint32_t)(smtp_config.content_inspect_min_size +
784 (state->toserver_data_count -
786 SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %" PRIu32,
787 depth);
788 StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, depth);
789
790 if (filename_len > SC_FILENAME_MAX) {
791 filename_len = SC_FILENAME_MAX;
792 SMTPSetEvent(state, SMTP_DECODER_EVENT_MIME_LONG_FILENAME);
793 }
795 state->file_track_id++, filename, filename_len, NULL, 0,
796 flags) != 0) {
797 SCLogDebug("FileOpenFile() failed");
798 }
799 SMTPNewFile(state->curr_tx, tx->files_ts.tail);
800 break;
801 case MimeSmtpFileChunk:
802 // rust already run FileAppendData
803 if (tx->files_ts.tail && tx->files_ts.tail->content_inspected == 0 &&
805 depth = (uint32_t)(smtp_config.content_inspect_min_size +
806 (state->toserver_data_count -
810 "StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u", depth);
811 StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, depth);
812 /* after the start of the body inspection, disable the depth logic */
813 } else if (tx->files_ts.tail && tx->files_ts.tail->content_inspected > 0) {
814 StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, 0);
815 /* expand the limit as long as we get file data, as the file data is bigger
816 * on the wire due to base64 */
817 } else {
818 depth = (uint32_t)(smtp_config.content_inspect_min_size +
819 (state->toserver_data_count -
821 SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %" PRIu32,
822 depth);
823 StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, depth);
824 }
825 break;
826 case MimeSmtpFileClose:
827 if (tx->files_ts.tail && tx->files_ts.tail->state == FILE_STATE_OPENED) {
828 if (FileCloseFile(&tx->files_ts, &smtp_config.sbcfg, NULL, 0, flags) != 0) {
829 SCLogDebug("FileCloseFile() failed: %d", ret);
830 }
831 } else {
832 SCLogDebug("File already closed");
833 }
834 depth = (uint32_t)(state->toserver_data_count -
837 SCLogDebug("StreamTcpReassemblySetMinInspectDepth STREAM_TOSERVER %u", depth);
838 StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER, depth);
839 }
840 }
841 }
842
843 return 0;
844}
845
846static inline bool IsReplyToCommand(const SMTPState *state, const uint8_t cmd)
847{
848 return (state->cmds_idx < state->cmds_buffer_len &&
849 state->cmds[state->cmds_idx] == cmd);
850}
851
852static int SMTPProcessReply(
853 SMTPState *state, Flow *f, SMTPThreadCtx *td, SMTPInput *input, const SMTPLine *line)
854{
855 SCEnter();
856
857 /* Line with just LF */
858 if (line->len == 0 && input->consumed == 1 && line->delim_len == 1) {
859 return 0; // to continue processing further
860 }
861
862 if (state->curr_tx) {
863 state->curr_tx->tx_data.updated_tc = true;
864 }
865 /* the reply code has to contain at least 3 bytes, to hold the 3 digit
866 * reply code */
867 if (line->len < 3) {
868 /* decoder event */
869 SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
870 return -1;
871 }
872
873 if (line->len >= 4) {
875 if (line->buf[3] != '-') {
876 state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
877 }
878 } else {
879 if (line->buf[3] == '-') {
881 }
882 }
883 } else {
885 state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
886 }
887 }
888
889 /* I don't like this pmq reset here. We'll devise a method later, that
890 * should make the use of the mpm very efficient */
891 PmqReset(td->pmq);
892 int mpm_cnt = mpm_table[SMTP_MPM].Search(
893 smtp_mpm_ctx, td->smtp_mpm_thread_ctx, td->pmq, line->buf, 3);
894 if (mpm_cnt == 0) {
895 /* set decoder event - reply code invalid */
896 SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
897 SCLogDebug("invalid reply code %02x %02x %02x", line->buf[0], line->buf[1], line->buf[2]);
898 SCReturnInt(-1);
899 }
900 enum SMTPCode reply_code = smtp_reply_map[td->pmq->rule_id_array[0]].enum_value;
901 SCLogDebug("REPLY: reply_code %u / %s", reply_code,
902 smtp_reply_map[reply_code].enum_name);
903
904 if (state->cmds_idx == state->cmds_cnt) {
906 /* the first server reply can be a multiline message. Let's
907 * flag the fact that we have seen the first reply only at the end
908 * of a multiline reply
909 */
912 if (reply_code == SMTP_REPLY_220)
913 SCReturnInt(0);
914 else {
915 SMTPSetEvent(state, SMTP_DECODER_EVENT_INVALID_REPLY);
916 SCReturnInt(0);
917 }
918 } else {
919 /* decoder event - unable to match reply with request */
920 SCLogDebug("unable to match reply with request");
921 SCReturnInt(0);
922 }
923 }
924
925 if (state->cmds_cnt == 0) {
926 /* reply but not a command we have stored, fall through */
927 } else if (IsReplyToCommand(state, SMTP_COMMAND_STARTTLS)) {
928 if (reply_code == SMTP_REPLY_220) {
929 /* we are entering STARTTLS data mode */
933 }
934 if (state->curr_tx) {
935 SMTPTransactionComplete(state);
936 }
937 } else {
938 /* decoder event */
939 SMTPSetEvent(state, SMTP_DECODER_EVENT_TLS_REJECTED);
940 }
941 } else if (IsReplyToCommand(state, SMTP_COMMAND_DATA)) {
942 if (reply_code == SMTP_REPLY_354) {
943 /* Next comes the mail for the DATA command in toserver direction */
945 } else {
946 /* decoder event */
948 // reset data mode if we had entered it prematurely
949 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
950 }
951 SMTPSetEvent(state, SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED);
952 }
953 } else if (IsReplyToCommand(state, SMTP_COMMAND_RSET)) {
954 if (reply_code == SMTP_REPLY_250 && state->curr_tx &&
956 SMTPTransactionComplete(state);
957 }
958 } else {
959 /* we don't care for any other command for now */
960 }
961
962 /* if it is a multi-line reply, we need to move the index only once for all
963 * the line of the reply. We unset the multiline flag on the last
964 * line of the multiline reply, following which we increment the index */
966 state->cmds_idx++;
968 /* we check if the server is indicating pipelining support */
969 if (reply_code == SMTP_REPLY_250 && line->len == 14 &&
970 SCMemcmpLowercase("pipelining", line->buf + 4, 10) == 0) {
972 }
973 }
974
975 /* if we have matched all the buffered commands, reset the cnt and index */
976 if (state->cmds_idx == state->cmds_cnt) {
977 state->cmds_cnt = 0;
978 state->cmds_idx = 0;
979 }
981
982 return 0;
983}
984
985static int SMTPParseCommandBDAT(SMTPState *state, const SMTPLine *line)
986{
987 SCEnter();
988
989 int i = 4;
990 while (i < line->len) {
991 if (line->buf[i] != ' ') {
992 break;
993 }
994 i++;
995 }
996 if (i == 4) {
997 /* decoder event */
998 return -1;
999 }
1000 if (i == line->len) {
1001 /* decoder event */
1002 return -1;
1003 }
1004 // copy in temporary null-terminated buffer for conversion
1005 char strbuf[24];
1006 int len = 23;
1007 if (line->len - i < len) {
1008 len = line->len - i;
1009 }
1010 memcpy(strbuf, line->buf + i, len);
1011 strbuf[len] = '\0';
1012 if (ByteExtractStringUint32(&state->bdat_chunk_len, 10, 0, strbuf) < 0) {
1013 /* decoder event */
1014 return -1;
1015 }
1016
1017 return 0;
1018}
1019
1020static int SMTPParseCommandWithParam(SMTPState *state, const SMTPLine *line, uint8_t prefix_len,
1021 uint8_t **target, uint16_t *target_len)
1022{
1023 int i = prefix_len + 1;
1024
1025 while (i < line->len) {
1026 if (line->buf[i] != ' ') {
1027 break;
1028 }
1029 i++;
1030 }
1031
1032 /* rfc1870: with the size extension the mail from can be followed by an option.
1033 We use the space separator to detect it. */
1034 int spc_i = i;
1035 while (spc_i < line->len) {
1036 if (line->buf[spc_i] == ' ') {
1037 break;
1038 }
1039 spc_i++;
1040 }
1041
1042 *target = SCMalloc(spc_i - i + 1);
1043 if (*target == NULL)
1044 return -1;
1045 memcpy(*target, line->buf + i, spc_i - i);
1046 (*target)[spc_i - i] = '\0';
1047 if (spc_i - i > UINT16_MAX) {
1048 *target_len = UINT16_MAX;
1050 } else {
1051 *target_len = (uint16_t)(spc_i - i);
1052 }
1053
1054 return 0;
1055}
1056
1057static int SMTPParseCommandHELO(SMTPState *state, const SMTPLine *line)
1058{
1059 if (state->helo) {
1060 SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1061 return 0;
1062 }
1063 return SMTPParseCommandWithParam(state, line, 4, &state->helo, &state->helo_len);
1064}
1065
1066static int SMTPParseCommandMAILFROM(SMTPState *state, const SMTPLine *line)
1067{
1068 if (state->curr_tx->mail_from) {
1069 SMTPSetEvent(state, SMTP_DECODER_EVENT_DUPLICATE_FIELDS);
1070 return 0;
1071 }
1072 return SMTPParseCommandWithParam(
1073 state, line, 9, &state->curr_tx->mail_from, &state->curr_tx->mail_from_len);
1074}
1075
1076static int SMTPParseCommandRCPTTO(SMTPState *state, const SMTPLine *line)
1077{
1078 uint8_t *rcptto;
1079 uint16_t rcptto_len;
1080
1081 if (SMTPParseCommandWithParam(state, line, 7, &rcptto, &rcptto_len) == 0) {
1082 SMTPString *rcptto_str = SMTPStringAlloc();
1083 if (rcptto_str) {
1084 rcptto_str->str = rcptto;
1085 rcptto_str->len = rcptto_len;
1086 TAILQ_INSERT_TAIL(&state->curr_tx->rcpt_to_list, rcptto_str, next);
1087 } else {
1088 SCFree(rcptto);
1089 return -1;
1090 }
1091 } else {
1092 return -1;
1093 }
1094 return 0;
1095}
1096
1097/* consider 'rset' and 'quit' to be part of the existing state */
1098static int NoNewTx(SMTPState *state, const SMTPLine *line)
1099{
1101 if (line->len >= 4 && SCMemcmpLowercase("rset", line->buf, 4) == 0) {
1102 return 1;
1103 } else if (line->len >= 4 && SCMemcmpLowercase("quit", line->buf, 4) == 0) {
1104 return 1;
1105 }
1106 }
1107 return 0;
1108}
1109
1110/* XXX have a better name */
1111#define rawmsgname "rawmsg"
1112
1113/*
1114 * @brief Process an SMTP Request
1115 *
1116 * Parse and decide the current command and set appropriate variables on the state
1117 * accordingly. Create transactions if needed or update the current transaction
1118 * with the appropriate data/params. Pass the control to the respective command
1119 * parser in the end.
1120 *
1121 * @param state Pointer to current SMTPState
1122 * @param f Pointer to the current Flow
1123 * @param pstate Pointer to the current AppLayerParserState
1124 * @param input Pointer to the current input data to SMTP parser
1125 * @param line Pointer to the current line being parsed by the SMTP parser
1126 * @return 0 for success
1127 * -1 for errors and inconsistent states
1128 * -2 if MIME state could not be allocated
1129 * */
1130static int SMTPProcessRequest(
1131 SMTPState *state, Flow *f, SMTPInput *input, const SMTPLine *line, const StreamSlice *slice)
1132{
1133 SCEnter();
1134 SMTPTransaction *tx = state->curr_tx;
1135
1137 if (frame) {
1138 frame->len = (int64_t)line->len;
1139 } else {
1140 if (!(state->current_command == SMTP_COMMAND_DATA &&
1143 f, slice, line->buf, line->len, 0, SMTP_FRAME_COMMAND_LINE);
1144 }
1145 }
1146
1147 /* If current input is to be discarded because it completes a long line,
1148 * line's length and delimiter len are reset to 0. Skip processing this line.
1149 * This line is only to get us out of the state where we should discard any
1150 * data till LF. */
1151 if (line->len == 0 && line->delim_len == 0) {
1152 return 0;
1153 }
1154 if (state->curr_tx == NULL || (state->curr_tx->done && !NoNewTx(state, line))) {
1155 tx = SMTPTransactionCreate(state);
1156 if (tx == NULL)
1157 return -1;
1158 state->curr_tx = tx;
1159 TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
1160 tx->tx_id = state->tx_cnt++;
1161
1162 /* keep track of the start of the tx */
1166 }
1167 if (frame != NULL && state->curr_tx) {
1168 AppLayerFrameSetTxId(frame, state->curr_tx->tx_id);
1169 }
1170 tx->tx_data.updated_ts = true;
1171
1172 state->toserver_data_count += (line->len + line->delim_len);
1173
1176 }
1177
1178 /* there are 2 commands that can push it into this COMMAND_DATA mode -
1179 * STARTTLS and DATA */
1181 int r = 0;
1182 AppLayerParserTriggerRawStreamInspection(f, STREAM_TOSERVER);
1183
1184 if (line->len >= 8 && SCMemcmpLowercase("starttls", line->buf, 8) == 0) {
1186 } else if (line->len >= 4 && SCMemcmpLowercase("data", line->buf, 4) == 0) {
1188 if (state->curr_tx->is_data) {
1189 // We did not receive a confirmation from server
1190 // And now client sends a next DATA
1191 SMTPSetEvent(state, SMTP_DECODER_EVENT_UNPARSABLE_CONTENT);
1192 SCReturnInt(0);
1193 } else if (smtp_config.raw_extraction) {
1195 (uint8_t *)rawmsgname, strlen(rawmsgname), NULL, 0,
1196 FILE_NOMD5 | FILE_NOMAGIC) == 0) {
1197 SMTPNewFile(tx, tx->files_ts.tail);
1198 }
1199 } else if (smtp_config.decode_mime) {
1201 tx->mime_state = SCMimeSmtpStateInit(&tx->files_ts, &smtp_config.sbcfg);
1202 if (tx->mime_state == NULL) {
1203 SCLogDebug("MimeDecInitParser() failed to "
1204 "allocate data");
1205 return -1;
1206 }
1207 }
1208 state->curr_tx->is_data = true;
1209
1210 Frame *data_frame = AppLayerFrameNewByPointer(
1211 f, slice, input->buf + input->consumed, -1, 0, SMTP_FRAME_DATA);
1212 if (data_frame == NULL) {
1213 SCLogDebug("data_frame %p - no data frame set up", data_frame);
1214 } else {
1215 AppLayerFrameSetTxId(data_frame, state->curr_tx->tx_id);
1216 }
1217
1218 /* Enter immediately data mode without waiting for server reply */
1221 }
1222 } else if (line->len >= 4 && SCMemcmpLowercase("bdat", line->buf, 4) == 0) {
1223 r = SMTPParseCommandBDAT(state, line);
1224 if (r == -1) {
1225 SCReturnInt(-1);
1226 }
1229 } else if (line->len >= 4 && ((SCMemcmpLowercase("helo", line->buf, 4) == 0) ||
1230 SCMemcmpLowercase("ehlo", line->buf, 4) == 0)) {
1231 r = SMTPParseCommandHELO(state, line);
1232 if (r == -1) {
1233 SCReturnInt(-1);
1234 }
1236 } else if (line->len >= 9 && SCMemcmpLowercase("mail from", line->buf, 9) == 0) {
1237 r = SMTPParseCommandMAILFROM(state, line);
1238 if (r == -1) {
1239 SCReturnInt(-1);
1240 }
1242 } else if (line->len >= 7 && SCMemcmpLowercase("rcpt to", line->buf, 7) == 0) {
1243 r = SMTPParseCommandRCPTTO(state, line);
1244 if (r == -1) {
1245 SCReturnInt(-1);
1246 }
1248 } else if (line->len >= 4 && SCMemcmpLowercase("rset", line->buf, 4) == 0) {
1249 // Resets chunk index in case of connection reuse
1250 state->bdat_chunk_idx = 0;
1252 } else {
1254 }
1255
1256 /* Every command is inserted into a command buffer, to be matched
1257 * against reply(ies) sent by the server */
1258 if (SMTPInsertCommandIntoCommandBuffer(state->current_command, state) == -1) {
1259 SCReturnInt(-1);
1260 }
1261
1262 SCReturnInt(r);
1263 }
1264
1265 switch (state->current_command) {
1266 case SMTP_COMMAND_DATA:
1267 return SMTPProcessCommandDATA(state, tx, f, line);
1268
1269 case SMTP_COMMAND_BDAT:
1270 return SMTPProcessCommandBDAT(state, line);
1271
1272 default:
1273 /* we have nothing to do with any other command at this instant.
1274 * Just let it go through */
1275 SCReturnInt(0);
1276 }
1277}
1278
1279static inline void ResetLine(SMTPLine *line)
1280{
1281 if (line != NULL) {
1282 line->len = 0;
1283 line->delim_len = 0;
1284 line->buf = NULL;
1285 }
1286}
1287
1288/*
1289 * @brief Pre Process the data that comes in DATA mode.
1290 *
1291 * If currently, the command that is being processed is DATA, whatever data
1292 * comes as a part of it must be handled by this function. This is because
1293 * there should be no char limit imposition on the line arriving in the DATA
1294 * mode. Such limits are in place for any lines passed to the GetLine function
1295 * and the lines are capped there at SMTP_LINE_BUFFER_LIMIT.
1296 * One such limit in DATA mode may lead to file data or parts of e-mail being
1297 * truncated if the line were too long.
1298 *
1299 * @param state Pointer to the current SMTPState
1300 * @param f Pointer to the current Flow
1301 * @param pstate Pointer to the current AppLayerParserState
1302 * @param input Pointer to the current input data to SMTP parser
1303 * @param line Pointer to the current line being parsed by the SMTP parser
1304 * @return 0 for success
1305 * 1 for handing control over to GetLine
1306 * -1 for errors and inconsistent states
1307 * */
1308static int SMTPPreProcessCommands(
1309 SMTPState *state, Flow *f, StreamSlice *slice, SMTPInput *input, SMTPLine *line)
1310{
1312 DEBUG_VALIDATE_BUG_ON(line->len != 0);
1313 DEBUG_VALIDATE_BUG_ON(line->delim_len != 0);
1314
1315 /* fall back to strict line parsing for mime header parsing */
1316 if (state->curr_tx && state->curr_tx->mime_state &&
1317 SCMimeSmtpGetState(state->curr_tx->mime_state) < MimeSmtpBody)
1318 return 1;
1319
1320 bool line_complete = false;
1321 const int32_t input_len = input->len;
1322 const int32_t offset = input->consumed;
1323 for (int32_t i = 0; i < input_len; i++) {
1324 if (input->buf[offset + i] == 0x0d) {
1325 if (i < input_len - 1 && input->buf[offset + i + 1] == 0x0a) {
1326 i++;
1327 line->delim_len++;
1328 }
1329 /* Line is just ending in CR */
1330 line->delim_len++;
1331 line_complete = true;
1332 } else if (input->buf[offset + i] == 0x0a) {
1333 /* Line is just ending in LF */
1334 line->delim_len++;
1335 line_complete = true;
1336 }
1337 /* Either line is complete or fragmented */
1338 if (line_complete || (i == input_len - 1)) {
1339 DEBUG_VALIDATE_BUG_ON(input->consumed + input->len != input->orig_len);
1340 DEBUG_VALIDATE_BUG_ON(input->len == 0 && input_len != 0);
1341 /* state->input_len reflects data from start of the line in progress. */
1342 if ((input->len == 1 && input->buf[input->consumed] == '-') ||
1343 (input->len > 1 && input->buf[input->consumed] == '-' &&
1344 input->buf[input->consumed + 1] == '-')) {
1345 SCLogDebug("Possible boundary, yield to GetLine");
1346 return 1;
1347 }
1348 /* total_consumed should be input consumed so far + i + 1 */
1349 int32_t total_consumed = offset + i + 1;
1350 int32_t current_line_consumed = total_consumed - input->consumed;
1351 DEBUG_VALIDATE_BUG_ON(current_line_consumed < line->delim_len);
1352 line->buf = input->buf + input->consumed;
1353 line->len = current_line_consumed - line->delim_len;
1354 DEBUG_VALIDATE_BUG_ON(line->len < 0);
1355 if (line->len < 0) {
1356 return -1;
1357 }
1358
1359 input->consumed = total_consumed;
1360 input->len -= current_line_consumed;
1361 DEBUG_VALIDATE_BUG_ON(input->consumed + input->len != input->orig_len);
1362 if (SMTPProcessRequest(state, f, input, line, slice) == -1) {
1363 return -1;
1364 }
1365 line_complete = false;
1366 line->buf = NULL;
1367 line->len = 0;
1368 line->delim_len = 0;
1369
1370 /* bail if `SMTPProcessRequest` ended the data mode */
1373 if (data_frame) {
1374 data_frame->len = (slice->offset + input->consumed) - data_frame->offset;
1375 }
1376 break;
1377 }
1378 }
1379 }
1380 return 0;
1381}
1382
1383static AppLayerResult SMTPParse(uint8_t direction, Flow *f, SMTPState *state,
1384 AppLayerParserState *pstate, StreamSlice stream_slice, SMTPThreadCtx *thread_data)
1385{
1386 SCEnter();
1387
1388 const uint8_t *input_buf = StreamSliceGetData(&stream_slice);
1389 uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
1390
1391 if (input_buf == NULL &&
1392 ((direction == 0 && SCAppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) ||
1393 (direction == 1 &&
1396 } else if (input_buf == NULL || input_len == 0) {
1398 }
1399
1400 SMTPInput input = { .buf = input_buf, .len = input_len, .orig_len = input_len, .consumed = 0 };
1401 SMTPLine line = { NULL, 0, 0, false };
1402
1403 /* toserver */
1404 if (direction == 0) {
1405 if (((state->current_command == SMTP_COMMAND_DATA) ||
1406 (state->current_command == SMTP_COMMAND_BDAT)) &&
1408 int ret = SMTPPreProcessCommands(state, f, &stream_slice, &input, &line);
1409 DEBUG_VALIDATE_BUG_ON(ret != 0 && ret != -1 && ret != 1);
1410 if (ret == 0 && input.consumed == input.orig_len) {
1412 } else if (ret < 0) {
1414 }
1415 }
1416 AppLayerResult res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1417 while (res.status == 0) {
1418 int retval = SMTPProcessRequest(state, f, &input, &line, &stream_slice);
1419 if (retval != 0)
1421 if (line.delim_len == 0 && line.len == SMTP_LINE_BUFFER_LIMIT) {
1422 if (!line.lf_found) {
1423 state->discard_till_lf_ts = true;
1424 }
1425 input.consumed = input.len + 1; // For the newly found LF
1426 SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE);
1427 break;
1428 }
1429 /* If request was successfully parsed, reset line as it has already been used
1430 * wherever it had to be */
1431 ResetLine(&line);
1432
1433 /* If DATA mode was entered in the middle of input parsing, exempt it from GetLine as we
1434 * don't want input limits to be exercised on DATA data. Here, SMTPPreProcessCommands
1435 * should either consume all the data or return in case it encounters another boundary.
1436 * In case of another boundary, the control should be passed to SMTPGetLine */
1437 if ((input.len > 0) && (state->current_command == SMTP_COMMAND_DATA) &&
1439 int ret = SMTPPreProcessCommands(state, f, &stream_slice, &input, &line);
1440 DEBUG_VALIDATE_BUG_ON(ret != 0 && ret != -1 && ret != 1);
1441 if (ret == 0 && input.consumed == input.orig_len) {
1443 } else if (ret < 0) {
1445 }
1446 }
1447 res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1448 }
1449 if (res.status == 1)
1450 return res;
1451 /* toclient */
1452 } else {
1453 AppLayerResult res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1454 while (res.status == 0) {
1455 if (SMTPProcessReply(state, f, thread_data, &input, &line) != 0)
1457 if (line.delim_len == 0 && line.len == SMTP_LINE_BUFFER_LIMIT) {
1458 if (!line.lf_found) {
1459 state->discard_till_lf_tc = true;
1460 }
1461 input.consumed = input.len + 1; // For the newly found LF
1462 SMTPSetEvent(state, SMTP_DECODER_EVENT_TRUNCATED_LINE);
1463 break;
1464 }
1465 res = SMTPGetLine(f, &stream_slice, state, &input, &line, direction);
1466 }
1467 if (res.status == 1)
1468 return res;
1469 }
1470
1472}
1473
1474static AppLayerResult SMTPParseClientRecord(Flow *f, void *alstate, AppLayerParserState *pstate,
1475 StreamSlice stream_slice, void *local_data)
1476{
1477 SCEnter();
1478
1479 /* first arg 0 is toserver */
1480 return SMTPParse(0, f, alstate, pstate, stream_slice, local_data);
1481}
1482
1483static AppLayerResult SMTPParseServerRecord(Flow *f, void *alstate, AppLayerParserState *pstate,
1484 StreamSlice stream_slice, void *local_data)
1485{
1486 SCEnter();
1487
1488 /* first arg 1 is toclient */
1489 return SMTPParse(1, f, alstate, pstate, stream_slice, local_data);
1490}
1491
1492/**
1493 * \internal
1494 * \brief Function to allocate SMTP state memory.
1495 */
1496void *SMTPStateAlloc(void *orig_state, AppProto proto_orig)
1497{
1498 SMTPState *smtp_state = SCCalloc(1, sizeof(SMTPState));
1499 if (unlikely(smtp_state == NULL))
1500 return NULL;
1501
1502 smtp_state->cmds = SCMalloc(sizeof(uint8_t) *
1504 if (smtp_state->cmds == NULL) {
1505 SCFree(smtp_state);
1506 return NULL;
1507 }
1509
1510 TAILQ_INIT(&smtp_state->tx_list);
1511
1512 return smtp_state;
1513}
1514
1515static SMTPString *SMTPStringAlloc(void)
1516{
1517 SMTPString *smtp_string = SCCalloc(1, sizeof(SMTPString));
1518 if (unlikely(smtp_string == NULL))
1519 return NULL;
1520
1521 return smtp_string;
1522}
1523
1524
1525static void SMTPStringFree(SMTPString *str)
1526{
1527 if (str->str) {
1528 SCFree(str->str);
1529 }
1530 SCFree(str);
1531}
1532
1533static void *SMTPLocalStorageAlloc(void)
1534{
1535 /* needed by the mpm */
1536 SMTPThreadCtx *td = SCCalloc(1, sizeof(*td));
1537 if (td == NULL) {
1538 exit(EXIT_FAILURE);
1539 }
1540
1541 td->pmq = SCCalloc(1, sizeof(*td->pmq));
1542 if (td->pmq == NULL) {
1543 exit(EXIT_FAILURE);
1544 }
1545 PmqSetup(td->pmq);
1546
1547 td->smtp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx));
1548 if (unlikely(td->smtp_mpm_thread_ctx == NULL)) {
1549 exit(EXIT_FAILURE);
1550 }
1552 return td;
1553}
1554
1555static void SMTPLocalStorageFree(void *ptr)
1556{
1557 SMTPThreadCtx *td = ptr;
1558 if (td != NULL) {
1559 if (td->pmq != NULL) {
1560 PmqFree(td->pmq);
1561 SCFree(td->pmq);
1562 }
1563
1564 if (td->smtp_mpm_thread_ctx != NULL) {
1567 }
1568
1569 SCFree(td);
1570 }
1571}
1572
1573static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state)
1574{
1575 if (tx->mime_state != NULL) {
1576 SCMimeSmtpStateFree(tx->mime_state);
1577 }
1578
1579 SCAppLayerTxDataCleanup(&tx->tx_data);
1580
1581 if (tx->mail_from)
1582 SCFree(tx->mail_from);
1583
1584 SMTPString *str = NULL;
1585 while ((str = TAILQ_FIRST(&tx->rcpt_to_list))) {
1586 TAILQ_REMOVE(&tx->rcpt_to_list, str, next);
1587 SMTPStringFree(str);
1588 }
1590
1591 SCFree(tx);
1592}
1593
1594/**
1595 * \internal
1596 * \brief Function to free SMTP state memory.
1597 */
1598static void SMTPStateFree(void *p)
1599{
1600 SMTPState *smtp_state = (SMTPState *)p;
1601
1602 if (smtp_state->cmds != NULL) {
1603 SCFree(smtp_state->cmds);
1604 }
1605
1606 if (smtp_state->helo) {
1607 SCFree(smtp_state->helo);
1608 }
1609
1610 SMTPTransaction *tx = NULL;
1611 while ((tx = TAILQ_FIRST(&smtp_state->tx_list))) {
1612 TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1613 SMTPTransactionFree(tx, smtp_state);
1614 }
1615
1616 SCFree(smtp_state);
1617}
1618
1619static void SMTPSetMpmState(void)
1620{
1621 smtp_mpm_ctx = SCCalloc(1, sizeof(MpmCtx));
1622 if (unlikely(smtp_mpm_ctx == NULL)) {
1623 exit(EXIT_FAILURE);
1624 }
1625 MpmInitCtx(smtp_mpm_ctx, SMTP_MPM);
1626
1627 uint32_t i = 0;
1628 for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) {
1629 SCEnumCharMap *map = &smtp_reply_map[i];
1630 /* The third argument is 3, because reply code is always 3 bytes. */
1631 MpmAddPatternCI(smtp_mpm_ctx, (uint8_t *)map->enum_name, 3,
1632 0 /* defunct */, 0 /* defunct */,
1633 i /* pattern id */, i /* rule id */ , 0 /* no flags */);
1634 }
1635
1636 mpm_table[SMTP_MPM].Prepare(NULL, smtp_mpm_ctx);
1637}
1638
1639static void SMTPFreeMpmState(void)
1640{
1641 if (smtp_mpm_ctx != NULL) {
1642 mpm_table[SMTP_MPM].DestroyCtx(smtp_mpm_ctx);
1643 SCFree(smtp_mpm_ctx);
1644 smtp_mpm_ctx = NULL;
1645 }
1646}
1647
1648static int SMTPStateGetEventInfo(
1649 const char *event_name, uint8_t *event_id, AppLayerEventType *event_type)
1650{
1651 if (SCAppLayerGetEventIdByName(event_name, smtp_decoder_event_table, event_id) == 0) {
1652 *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1653 return 0;
1654 }
1655 return -1;
1656}
1657
1658static int SMTPStateGetEventInfoById(
1659 uint8_t event_id, const char **event_name, AppLayerEventType *event_type)
1660{
1661 *event_name = SCMapEnumValueToName(event_id, smtp_decoder_event_table);
1662 if (*event_name == NULL) {
1663 SCLogError("event \"%d\" not present in "
1664 "smtp's enum map table.",
1665 event_id);
1666 /* yes this is fatal */
1667 return -1;
1668 }
1669
1670 *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
1671
1672 return 0;
1673}
1674
1675static AppProto SMTPServerProbingParser(
1676 const Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir)
1677{
1678 // another check for minimum length
1679 if (len < 5) {
1680 return ALPROTO_UNKNOWN;
1681 }
1682 // begins by 220
1683 if (input[0] != '2' || input[1] != '2' || input[2] != '0') {
1684 return ALPROTO_FAILED;
1685 }
1686 // followed by space or hypen
1687 if (input[3] != ' ' && input[3] != '-') {
1688 return ALPROTO_FAILED;
1689 }
1690 // If client side is SMTP, do not validate domain
1691 // so that server banner can be parsed first.
1692 if (f->alproto_ts == ALPROTO_SMTP) {
1693 if (memchr(input + 4, '\n', len - 4) != NULL) {
1694 return ALPROTO_SMTP;
1695 }
1696 return ALPROTO_UNKNOWN;
1697 }
1699 if (f->todstbytecnt > 4 && (f->alproto_ts == ALPROTO_UNKNOWN || f->alproto_ts == ALPROTO_TLS)) {
1700 // Only validates SMTP if client side is unknown
1701 // despite having received bytes.
1702 r = ALPROTO_SMTP;
1703 }
1704 uint32_t offset = SCValidateDomain(input + 4, len - 4);
1705 if (offset == 0) {
1706 return ALPROTO_FAILED;
1707 }
1708 if (r != ALPROTO_UNKNOWN && memchr(input + 4, '\n', len - 4) != NULL) {
1709 return r;
1710 }
1711 // This should not go forever because of engine limiting probing parsers.
1712 return ALPROTO_UNKNOWN;
1713}
1714
1715static int SMTPRegisterPatternsForProtocolDetection(void)
1716{
1718 IPPROTO_TCP, ALPROTO_SMTP, "EHLO", 4, 0, STREAM_TOSERVER) < 0) {
1719 return -1;
1720 }
1722 IPPROTO_TCP, ALPROTO_SMTP, "HELO", 4, 0, STREAM_TOSERVER) < 0) {
1723 return -1;
1724 }
1726 IPPROTO_TCP, ALPROTO_SMTP, "QUIT", 4, 0, STREAM_TOSERVER) < 0) {
1727 return -1;
1728 }
1730 "tcp", IPPROTO_TCP, "smtp", ALPROTO_SMTP, 0, 5, NULL, SMTPServerProbingParser)) {
1731 // STREAM_TOSERVER means here use 25 as flow destination port
1732 SCAppLayerProtoDetectPPRegister(IPPROTO_TCP, "25,465", ALPROTO_SMTP, 0, 5, STREAM_TOSERVER,
1733 NULL, SMTPServerProbingParser);
1734 }
1735
1736 return 0;
1737}
1738
1739static void SMTPStateTransactionFree (void *state, uint64_t tx_id)
1740{
1741 SMTPState *smtp_state = state;
1742 SMTPTransaction *tx = NULL;
1743 TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1744 if (tx_id < tx->tx_id)
1745 break;
1746 else if (tx_id > tx->tx_id)
1747 continue;
1748
1749 if (tx == smtp_state->curr_tx)
1750 smtp_state->curr_tx = NULL;
1751 TAILQ_REMOVE(&smtp_state->tx_list, tx, next);
1752 SMTPTransactionFree(tx, state);
1753 break;
1754 }
1755
1756
1757}
1758
1759/** \retval cnt highest tx id */
1760static uint64_t SMTPStateGetTxCnt(void *state)
1761{
1762 uint64_t cnt = 0;
1763 SMTPState *smtp_state = state;
1764 if (smtp_state) {
1765 cnt = smtp_state->tx_cnt;
1766 }
1767 SCLogDebug("returning %"PRIu64, cnt);
1768 return cnt;
1769}
1770
1771static void *SMTPStateGetTx(void *state, uint64_t id)
1772{
1773 SMTPState *smtp_state = state;
1774 if (smtp_state) {
1775 SMTPTransaction *tx = NULL;
1776
1777 if (smtp_state->curr_tx == NULL)
1778 return NULL;
1779 if (smtp_state->curr_tx->tx_id == id)
1780 return smtp_state->curr_tx;
1781
1782 TAILQ_FOREACH(tx, &smtp_state->tx_list, next) {
1783 if (tx->tx_id == id)
1784 return tx;
1785 }
1786 }
1787 return NULL;
1788}
1789
1790static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction)
1791{
1792 SMTPTransaction *tx = vtx;
1793 return tx->done;
1794}
1795
1796static AppLayerGetFileState SMTPGetTxFiles(void *txv, uint8_t direction)
1797{
1798 AppLayerGetFileState files = { .fc = NULL, .cfg = &smtp_config.sbcfg };
1799 SMTPTransaction *tx = (SMTPTransaction *)txv;
1800
1801 if (direction & STREAM_TOSERVER) {
1802 files.fc = &tx->files_ts;
1803 }
1804 return files;
1805}
1806
1807static AppLayerTxData *SMTPGetTxData(void *vtx)
1808{
1809 SMTPTransaction *tx = (SMTPTransaction *)vtx;
1810 return &tx->tx_data;
1811}
1812
1813static AppLayerStateData *SMTPGetStateData(void *vstate)
1814{
1815 SMTPState *state = (SMTPState *)vstate;
1816 return &state->state_data;
1817}
1818
1819/** \brief SMTP tx iterator, specialized for its linked list
1820 *
1821 * \retval txptr or NULL if no more txs in list
1822 */
1823static AppLayerGetTxIterTuple SMTPGetTxIterator(const uint8_t ipproto, const AppProto alproto,
1824 void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state)
1825{
1826 SMTPState *smtp_state = (SMTPState *)alstate;
1827 AppLayerGetTxIterTuple no_tuple = { NULL, 0, false };
1828 if (smtp_state) {
1829 SMTPTransaction *tx_ptr;
1830 if (state->un.ptr == NULL) {
1831 tx_ptr = TAILQ_FIRST(&smtp_state->tx_list);
1832 } else {
1833 tx_ptr = (SMTPTransaction *)state->un.ptr;
1834 }
1835 if (tx_ptr) {
1836 while (tx_ptr->tx_id < min_tx_id) {
1837 tx_ptr = TAILQ_NEXT(tx_ptr, next);
1838 if (!tx_ptr) {
1839 return no_tuple;
1840 }
1841 }
1842 if (tx_ptr->tx_id >= max_tx_id) {
1843 return no_tuple;
1844 }
1845 state->un.ptr = TAILQ_NEXT(tx_ptr, next);
1846 AppLayerGetTxIterTuple tuple = {
1847 .tx_ptr = tx_ptr,
1848 .tx_id = tx_ptr->tx_id,
1849 .has_next = (state->un.ptr != NULL),
1850 };
1851 return tuple;
1852 }
1853 }
1854 return no_tuple;
1855}
1856
1857/**
1858 * \brief Register the SMTP Protocol parser.
1859 */
1861{
1862 const char *proto_name = "smtp";
1863
1864 if (SCAppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
1866 if (SMTPRegisterPatternsForProtocolDetection() < 0 )
1867 return;
1868 } else {
1869 SCLogInfo("Protocol detection and parser disabled for %s protocol.",
1870 proto_name);
1871 return;
1872 }
1873
1874 if (SCAppLayerParserConfParserEnabled("tcp", proto_name)) {
1875 AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);
1876
1877 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOSERVER,
1878 SMTPParseClientRecord);
1879 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_SMTP, STREAM_TOCLIENT,
1880 SMTPParseServerRecord);
1881
1882 AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfo);
1883 AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetEventInfoById);
1884
1885 AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPLocalStorageAlloc,
1886 SMTPLocalStorageFree);
1887
1888 AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateTransactionFree);
1889 AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxFiles);
1890 AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetAlstateProgress);
1891 AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTxCnt);
1892 AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_SMTP, SMTPStateGetTx);
1893 AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxIterator);
1894 AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetTxData);
1895 AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_SMTP, SMTPGetStateData);
1898 IPPROTO_TCP, ALPROTO_SMTP, SMTPGetFrameIdByName, SMTPGetFrameNameById);
1899 } else {
1900 SCLogInfo("Parser disabled for %s protocol. Protocol detection still on.", proto_name);
1901 }
1902
1903 SMTPSetMpmState();
1904
1905 SMTPConfigure();
1906
1907#ifdef UNITTESTS
1909#endif
1910}
1911
1912/**
1913 * \brief Free memory allocated for global SMTP parser state.
1914 */
1916{
1917 SMTPFreeMpmState();
1918}
1919
1920/***************************************Unittests******************************/
1921
1922#ifdef UNITTESTS
1923#include "detect-engine-alert.h"
1924
1925static void SMTPTestInitConfig(void)
1926{
1930
1932
1934}
1935
1936/*
1937 * \test Test STARTTLS.
1938 */
1939static int SMTPParserTest01(void)
1940{
1941 int result = 0;
1942 Flow f;
1943 int r = 0;
1944
1945 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
1946 uint8_t welcome_reply[] = {
1947 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
1948 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1949 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
1950 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
1951 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
1952 0x0d, 0x0a
1953 };
1954 uint32_t welcome_reply_len = sizeof(welcome_reply);
1955
1956 /* EHLO [192.168.0.158]<CR><LF> */
1957 uint8_t request1[] = {
1958 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39,
1959 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e,
1960 0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a
1961 };
1962 uint32_t request1_len = sizeof(request1);
1963 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
1964 * 250-SIZE 35882577<CR><LF>
1965 * 250-8BITMIME<CR><LF>
1966 * 250-STARTTLS<CR><LF>
1967 * 250 ENHANCEDSTATUSCODES<CR><LF>
1968 */
1969 uint8_t reply1[] = {
1970 0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67,
1971 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
1972 0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75,
1973 0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
1974 0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e,
1975 0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e,
1976 0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30,
1977 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35,
1978 0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a,
1979 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54,
1980 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35,
1981 0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54,
1982 0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20,
1983 0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44,
1984 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f,
1985 0x44, 0x45, 0x53, 0x0d, 0x0a
1986 };
1987 uint32_t reply1_len = sizeof(reply1);
1988
1989 /* STARTTLS<CR><LF> */
1990 uint8_t request2[] = {
1991 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
1992 0x0d, 0x0a
1993 };
1994 uint32_t request2_len = sizeof(request2);
1995 /* 220 2.0.0 Ready to start TLS<CR><LF> */
1996 uint8_t reply2[] = {
1997 0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1998 0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20,
1999 0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
2000 0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a
2001 };
2002 uint32_t reply2_len = sizeof(reply2);
2003
2004 TcpSession ssn;
2006
2007 memset(&f, 0, sizeof(f));
2008 memset(&ssn, 0, sizeof(ssn));
2009
2010 FLOW_INITIALIZE(&f);
2011 f.protoctx = (void *)&ssn;
2012 f.proto = IPPROTO_TCP;
2014
2015 StreamTcpInitConfig(true);
2016 SMTPTestInitConfig();
2017
2019 STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2020 if (r != 0) {
2021 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2022 goto end;
2023 }
2024 SMTPState *smtp_state = f.alstate;
2025 if (smtp_state == NULL) {
2026 printf("no smtp state: ");
2027 goto end;
2028 }
2029 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2031 printf("smtp parser in inconsistent state\n");
2032 goto end;
2033 }
2034
2036 STREAM_TOSERVER, request1, request1_len);
2037 if (r != 0) {
2038 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2039 goto end;
2040 }
2041 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2042 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2044 printf("smtp parser in inconsistent state\n");
2045 goto end;
2046 }
2047
2049 STREAM_TOCLIENT, reply1, reply1_len);
2050 if (r != 0) {
2051 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2052 goto end;
2053 }
2054 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2056 printf("smtp parser in inconsistent state\n");
2057 goto end;
2058 }
2059
2061 STREAM_TOSERVER, request2, request2_len);
2062 if (r != 0) {
2063 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2064 goto end;
2065 }
2066 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2067 smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
2069 printf("smtp parser in inconsistent state\n");
2070 goto end;
2071 }
2072
2074 STREAM_TOCLIENT, reply2, reply2_len);
2075 if (r != 0) {
2076 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2077 goto end;
2078 }
2079 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2080 smtp_state->parser_state !=
2082 printf("smtp parser in inconsistent state\n");
2083 goto end;
2084 }
2085
2086 if (!FlowChangeProto(&f)) {
2087 goto end;
2088 }
2089
2090 result = 1;
2091end:
2092 if (alp_tctx != NULL)
2094 StreamTcpFreeConfig(true);
2095 FLOW_DESTROY(&f);
2096 return result;
2097}
2098
2099/**
2100 * \test Test multiple DATA commands(full mail transactions).
2101 */
2102static int SMTPParserTest02(void)
2103{
2104 int result = 0;
2105 Flow f;
2106 int r = 0;
2107
2108 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
2109 uint8_t welcome_reply[] = {
2110 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
2111 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
2112 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
2113 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
2114 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
2115 0x0d, 0x0a
2116 };
2117 uint32_t welcome_reply_len = sizeof(welcome_reply);
2118
2119 /* EHLO boo.com<CR><LF> */
2120 uint8_t request1[] = {
2121 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2122 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2123 };
2124 uint32_t request1_len = sizeof(request1);
2125 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
2126 * 250-SIZE 35882577<CR><LF>
2127 * 250-8BITMIME<CR><LF>
2128 * 250-STARTTLS<CR><LF>
2129 * 250 ENHANCEDSTATUSCODES<CR><LF>
2130 */
2131 uint8_t reply1[] = {
2132 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2133 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2134 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2135 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2136 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2137 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2138 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2139 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2140 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2141 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2142 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2143 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2144 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2145 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2146 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2147 };
2148 uint32_t reply1_len = sizeof(reply1);
2149
2150 /* MAIL FROM:asdff@asdf.com<CR><LF> */
2151 uint8_t request2[] = {
2152 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2153 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
2154 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2155 0x0d, 0x0a
2156 };
2157 uint32_t request2_len = sizeof(request2);
2158 /* 250 2.1.0 Ok<CR><LF> */
2159 uint8_t reply2[] = {
2160 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2161 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2162 };
2163 uint32_t reply2_len = sizeof(reply2);
2164
2165 /* RCPT TO:bimbs@gmail.com<CR><LF> */
2166 uint8_t request3[] = {
2167 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2168 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2169 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2170 0x0a
2171 };
2172 uint32_t request3_len = sizeof(request3);
2173 /* 250 2.1.5 Ok<CR><LF> */
2174 uint8_t reply3[] = {
2175 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2176 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2177 };
2178 uint32_t reply3_len = sizeof(reply3);
2179
2180 /* DATA<CR><LF> */
2181 uint8_t request4[] = {
2182 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2183 };
2184 uint32_t request4_len = sizeof(request4);
2185 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2186 uint8_t reply4[] = {
2187 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2188 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2189 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2190 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2191 0x4c, 0x46, 0x3e, 0x0d, 0x0a
2192 };
2193 uint32_t reply4_len = sizeof(reply4);
2194
2195 /* FROM:asdff@asdf.com<CR><LF> */
2196 uint8_t request5_1[] = {
2197 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2198 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2199 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2200 };
2201 uint32_t request5_1_len = sizeof(request5_1);
2202 /* TO:bimbs@gmail.com<CR><LF> */
2203 uint8_t request5_2[] = {
2204 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2205 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2206 0x6f, 0x6d, 0x0d, 0x0a
2207 };
2208 uint32_t request5_2_len = sizeof(request5_2);
2209 /* <CR><LF> */
2210 uint8_t request5_3[] = {
2211 0x0d, 0x0a
2212 };
2213 uint32_t request5_3_len = sizeof(request5_3);
2214 /* this is test mail1<CR><LF> */
2215 uint8_t request5_4[] = {
2216 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2217 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2218 0x6c, 0x31, 0x0d, 0x0a
2219 };
2220 uint32_t request5_4_len = sizeof(request5_4);
2221 /* .<CR><LF> */
2222 uint8_t request5_5[] = {
2223 0x2e, 0x0d, 0x0a
2224 };
2225 uint32_t request5_5_len = sizeof(request5_5);
2226 /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
2227 uint8_t reply5[] = {
2228 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2229 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2230 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2231 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
2232 0x46, 0x32, 0x0d, 0x0a
2233 };
2234 uint32_t reply5_len = sizeof(reply5);
2235
2236 /* MAIL FROM:asdfg@asdf.com<CR><LF> */
2237 uint8_t request6[] = {
2238 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2239 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40,
2240 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2241 0x0d, 0x0a
2242 };
2243 uint32_t request6_len = sizeof(request6);
2244 /* 250 2.1.0 Ok<CR><LF> */
2245 uint8_t reply6[] = {
2246 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2247 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2248 };
2249 uint32_t reply6_len = sizeof(reply6);
2250
2251 /* RCPT TO:bimbs@gmail.com<CR><LF> */
2252 uint8_t request7[] = {
2253 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2254 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2255 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2256 0x0a
2257 };
2258 uint32_t request7_len = sizeof(request7);
2259 /* 250 2.1.5 Ok<CR><LF> */
2260 uint8_t reply7[] = {
2261 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2262 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2263 };
2264 uint32_t reply7_len = sizeof(reply7);
2265
2266 /* DATA<CR><LF> */
2267 uint8_t request8[] = {
2268 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
2269 };
2270 uint32_t request8_len = sizeof(request8);
2271 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
2272 uint8_t reply8[] = {
2273 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
2274 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
2275 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
2276 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
2277 0x4c, 0x46, 0x3e, 0x0d, 0x0a
2278 };
2279 uint32_t reply8_len = sizeof(reply8);
2280
2281 /* FROM:asdfg@gmail.com<CR><LF> */
2282 uint8_t request9_1[] = {
2283 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2284 0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
2285 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2286 };
2287 uint32_t request9_1_len = sizeof(request9_1);
2288 /* TO:bimbs@gmail.com<CR><LF> */
2289 uint8_t request9_2[] = {
2290 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
2291 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
2292 0x6f, 0x6d, 0x0d, 0x0a
2293 };
2294 uint32_t request9_2_len = sizeof(request9_2);
2295 /* <CR><LF> */
2296 uint8_t request9_3[] = {
2297 0x0d, 0x0a
2298 };
2299 uint32_t request9_3_len = sizeof(request9_3);
2300 /* this is test mail2<CR><LF> */
2301 uint8_t request9_4[] = {
2302 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
2303 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
2304 0x6c, 0x32, 0x0d, 0x0a
2305 };
2306 uint32_t request9_4_len = sizeof(request9_4);
2307 /* .<CR><LF> */
2308 uint8_t request9_5[] = {
2309 0x2e, 0x0d, 0x0a
2310 };
2311 uint32_t request9_5_len = sizeof(request9_5);
2312 /* 250 2.0.0 Ok: queued as 28CFF20BF2<CR><LF> */
2313 uint8_t reply9[] = {
2314 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2315 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
2316 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
2317 0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42,
2318 0x46, 0x32, 0x0d, 0x0a
2319 };
2320 uint32_t reply9_len = sizeof(reply9);
2321
2322 /* QUIT<CR><LF> */
2323 uint8_t request10[] = {
2324 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
2325 };
2326 uint32_t request10_len = sizeof(request10);
2327 /* 221 2.0.0 Bye<CR><LF> */
2328 uint8_t reply10[] = {
2329 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
2330 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
2331 };
2332 uint32_t reply10_len = sizeof(reply10);
2333
2334 TcpSession ssn;
2336
2337 memset(&f, 0, sizeof(f));
2338 memset(&ssn, 0, sizeof(ssn));
2339
2340 FLOW_INITIALIZE(&f);
2341 f.protoctx = (void *)&ssn;
2342 f.proto = IPPROTO_TCP;
2344
2345 StreamTcpInitConfig(true);
2346 SMTPTestInitConfig();
2347
2349 STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2350 if (r != 0) {
2351 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2352 goto end;
2353 }
2354 SMTPState *smtp_state = f.alstate;
2355 if (smtp_state == NULL) {
2356 printf("no smtp state: ");
2357 goto end;
2358 }
2359 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2361 printf("smtp parser in inconsistent state\n");
2362 goto end;
2363 }
2364
2366 STREAM_TOSERVER, request1, request1_len);
2367 if (r != 0) {
2368 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2369 goto end;
2370 }
2371 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2372 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2374 printf("smtp parser in inconsistent state\n");
2375 goto end;
2376 }
2377
2379 STREAM_TOCLIENT, reply1, reply1_len);
2380 if (r != 0) {
2381 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2382 goto end;
2383 }
2384 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2386 printf("smtp parser in inconsistent state\n");
2387 goto end;
2388 }
2389
2391 STREAM_TOSERVER, request2, request2_len);
2392 if (r != 0) {
2393 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2394 goto end;
2395 }
2396 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2397 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2399 printf("smtp parser in inconsistent state\n");
2400 goto end;
2401 }
2402
2404 STREAM_TOCLIENT, reply2, reply2_len);
2405 if (r != 0) {
2406 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2407 goto end;
2408 }
2409 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2411 printf("smtp parser in inconsistent state\n");
2412 goto end;
2413 }
2414
2416 STREAM_TOSERVER, request3, request3_len);
2417 if (r != 0) {
2418 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2419 goto end;
2420 }
2421 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2422 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2424 printf("smtp parser in inconsistent state\n");
2425 goto end;
2426 }
2427
2429 STREAM_TOCLIENT, reply3, reply3_len);
2430 if (r != 0) {
2431 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2432 goto end;
2433 }
2434 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2436 printf("smtp parser in inconsistent state\n");
2437 goto end;
2438 }
2439
2441 STREAM_TOSERVER, request4, request4_len);
2442 if (r != 0) {
2443 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2444 goto end;
2445 }
2446 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2447 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2449 printf("smtp parser in inconsistent state\n");
2450 goto end;
2451 }
2452
2454 STREAM_TOCLIENT, reply4, reply4_len);
2455 if (r != 0) {
2456 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2457 goto end;
2458 }
2459 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2460 smtp_state->parser_state !=
2462 printf("smtp parser in inconsistent state\n");
2463 goto end;
2464 }
2465
2467 STREAM_TOSERVER, request5_1, request5_1_len);
2468 if (r != 0) {
2469 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2470 goto end;
2471 }
2472 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2473 smtp_state->parser_state !=
2475
2476 printf("smtp parser in inconsistent state\n");
2477 goto end;
2478 }
2479
2481 STREAM_TOSERVER, request5_2, request5_2_len);
2482 if (r != 0) {
2483 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2484 goto end;
2485 }
2486 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2487 smtp_state->parser_state !=
2489
2490 printf("smtp parser in inconsistent state\n");
2491 goto end;
2492 }
2493
2495 STREAM_TOSERVER, request5_3, request5_3_len);
2496 if (r != 0) {
2497 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2498 goto end;
2499 }
2500 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2501 smtp_state->parser_state !=
2503
2504 printf("smtp parser in inconsistent state\n");
2505 goto end;
2506 }
2507
2509 STREAM_TOSERVER, request5_4, request5_4_len);
2510 if (r != 0) {
2511 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2512 goto end;
2513 }
2514 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2515 smtp_state->parser_state !=
2517
2518 printf("smtp parser in inconsistent state\n");
2519 goto end;
2520 }
2521
2523 STREAM_TOSERVER, request5_5, request5_5_len);
2524 if (r != 0) {
2525 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2526 goto end;
2527 }
2528 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2529 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2531 printf("smtp parser in inconsistent state\n");
2532 goto end;
2533 }
2534
2536 STREAM_TOCLIENT, reply5, reply5_len);
2537 if (r != 0) {
2538 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2539 goto end;
2540 }
2541 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2543 printf("smtp parser in inconsistent state\n");
2544 goto end;
2545 }
2546
2548 STREAM_TOSERVER, request6, request6_len);
2549 if (r != 0) {
2550 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2551 goto end;
2552 }
2553 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2554 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2556 printf("smtp parser in inconsistent state\n");
2557 goto end;
2558 }
2559
2561 STREAM_TOCLIENT, reply6, reply6_len);
2562 if (r != 0) {
2563 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2564 goto end;
2565 }
2566 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2568 printf("smtp parser in inconsistent state\n");
2569 goto end;
2570 }
2571
2573 STREAM_TOSERVER, request7, request7_len);
2574 if (r != 0) {
2575 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2576 goto end;
2577 }
2578 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2579 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2581 printf("smtp parser in inconsistent state\n");
2582 goto end;
2583 }
2584
2586 STREAM_TOCLIENT, reply7, reply7_len);
2587 if (r != 0) {
2588 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2589 goto end;
2590 }
2591 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2593 printf("smtp parser in inconsistent state\n");
2594 goto end;
2595 }
2596
2598 STREAM_TOSERVER, request8, request8_len);
2599 if (r != 0) {
2600 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2601 goto end;
2602 }
2603 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2604 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
2606 printf("smtp parser in inconsistent state\n");
2607 goto end;
2608 }
2609
2611 STREAM_TOCLIENT, reply8, reply8_len);
2612 if (r != 0) {
2613 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2614 goto end;
2615 }
2616 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2617 smtp_state->parser_state !=
2619 printf("smtp parser in inconsistent state\n");
2620 goto end;
2621 }
2622
2624 STREAM_TOSERVER, request9_1, request9_1_len);
2625 if (r != 0) {
2626 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2627 goto end;
2628 }
2629 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2630 smtp_state->parser_state !=
2632
2633 printf("smtp parser in inconsistent state\n");
2634 goto end;
2635 }
2636
2638 STREAM_TOSERVER, request9_2, request9_2_len);
2639 if (r != 0) {
2640 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2641 goto end;
2642 }
2643 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2644 smtp_state->parser_state !=
2646
2647 printf("smtp parser in inconsistent state\n");
2648 goto end;
2649 }
2650
2652 STREAM_TOSERVER, request9_3, request9_3_len);
2653 if (r != 0) {
2654 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2655 goto end;
2656 }
2657 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2658 smtp_state->parser_state !=
2660
2661 printf("smtp parser in inconsistent state\n");
2662 goto end;
2663 }
2664
2666 STREAM_TOSERVER, request9_4, request9_4_len);
2667 if (r != 0) {
2668 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2669 goto end;
2670 }
2671 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2672 smtp_state->parser_state !=
2674
2675 printf("smtp parser in inconsistent state\n");
2676 goto end;
2677 }
2678
2680 STREAM_TOSERVER, request9_5, request9_5_len);
2681 if (r != 0) {
2682 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2683 goto end;
2684 }
2685 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2686 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
2688 printf("smtp parser in inconsistent state\n");
2689 goto end;
2690 }
2691
2693 STREAM_TOCLIENT, reply9, reply9_len);
2694 if (r != 0) {
2695 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2696 goto end;
2697 }
2698 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2700 printf("smtp parser in inconsistent state\n");
2701 goto end;
2702 }
2703
2705 STREAM_TOSERVER, request10, request10_len);
2706 if (r != 0) {
2707 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2708 goto end;
2709 }
2710 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2711 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2713 printf("smtp parser in inconsistent state\n");
2714 goto end;
2715 }
2716
2718 STREAM_TOCLIENT, reply10, reply10_len);
2719 if (r != 0) {
2720 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2721 goto end;
2722 }
2723 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2725 printf("smtp parser in inconsistent state\n");
2726 goto end;
2727 }
2728
2729 result = 1;
2730end:
2731 if (alp_tctx != NULL)
2733 StreamTcpFreeConfig(true);
2734 FLOW_DESTROY(&f);
2735 return result;
2736}
2737
2738/**
2739 * \test Testing parsing pipelined commands.
2740 */
2741static int SMTPParserTest03(void)
2742{
2743 int result = 0;
2744 Flow f;
2745 int r = 0;
2746
2747 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2748 uint8_t welcome_reply[] = {
2749 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2750 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2751 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2752 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2753 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2754 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2755 };
2756 uint32_t welcome_reply_len = sizeof(welcome_reply);
2757
2758 /* EHLO boo.com<CR><LF> */
2759 uint8_t request1[] = {
2760 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2761 0x2e, 0x63, 0x6f, 0x6d, 0x0a
2762 };
2763 uint32_t request1_len = sizeof(request1);
2764 /* 250-poona_slack_vm1.localdomain<CR><LF>
2765 * 250-PIPELINING<CR><LF>
2766 * 250-SIZE 10240000<CR><LF>
2767 * 250-VRFY<CR><LF>
2768 * 250-ETRN<CR><LF>
2769 * 250-ENHANCEDSTATUSCODES<CR><LF>
2770 * 250-8BITMIME<CR><LF>
2771 * 250 DSN<CR><LF>
2772 */
2773 uint8_t reply1[] = {
2774 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
2775 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2776 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2777 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
2778 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
2779 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
2780 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
2781 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
2782 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2783 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
2784 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
2785 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
2786 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
2787 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
2788 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
2789 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
2790 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
2791 };
2792 uint32_t reply1_len = sizeof(reply1);
2793
2794 /* MAIL FROM:pbsf@asdfs.com<CR><LF>
2795 * RCPT TO:pbsf@asdfs.com<CR><LF>
2796 * DATA<CR><LF>
2797 * Immediate data
2798 */
2799 uint8_t request2[] = {
2800 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2801 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2802 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2803 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
2804 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
2805 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
2806 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
2807 0x49, 0x6d, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74,
2808 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x0d, 0x0a,
2809 };
2810 uint32_t request2_len = sizeof(request2);
2811 /* 250 2.1.0 Ok<CR><LF>
2812 * 250 2.1.5 Ok<CR><LF>
2813 * 354 End data with <CR><LF>.<CR><LF>|<CR><LF>|
2814 */
2815 uint8_t reply2[] = {
2816 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2817 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35,
2818 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20,
2819 0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20,
2820 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61,
2821 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43,
2822 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c,
2823 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d,
2824 0x0a
2825 };
2826 uint32_t reply2_len = sizeof(reply2);
2827
2828 TcpSession ssn;
2830
2831 memset(&f, 0, sizeof(f));
2832 memset(&ssn, 0, sizeof(ssn));
2833
2834 FLOW_INITIALIZE(&f);
2835 f.protoctx = (void *)&ssn;
2836 f.proto = IPPROTO_TCP;
2838
2839 StreamTcpInitConfig(true);
2840 SMTPTestInitConfig();
2841
2843 STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2844 if (r != 0) {
2845 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2846 goto end;
2847 }
2848 SMTPState *smtp_state = f.alstate;
2849 if (smtp_state == NULL) {
2850 printf("no smtp state: ");
2851 goto end;
2852 }
2853 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2855 printf("smtp parser in inconsistent state\n");
2856 goto end;
2857 }
2858
2860 STREAM_TOSERVER, request1, request1_len);
2861 if (r != 0) {
2862 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2863 goto end;
2864 }
2865 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2866 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2868 printf("smtp parser in inconsistent state\n");
2869 goto end;
2870 }
2871
2873 STREAM_TOCLIENT, reply1, reply1_len);
2874 if (r != 0) {
2875 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2876 goto end;
2877 }
2878 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2879 smtp_state->parser_state !=
2881 printf("smtp parser in inconsistent state\n");
2882 goto end;
2883 }
2884
2886 STREAM_TOSERVER, request2, request2_len);
2887 if (r != 0) {
2888 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2889 goto end;
2890 }
2891 if (smtp_state->cmds_cnt != 3 || smtp_state->cmds_idx != 0 ||
2892 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2893 smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD ||
2894 smtp_state->cmds[2] != SMTP_COMMAND_DATA ||
2895 smtp_state->parser_state !=
2898 printf("smtp parser in inconsistent state\n");
2899 goto end;
2900 }
2901
2903 STREAM_TOCLIENT, reply2, reply2_len);
2904 if (r != 0) {
2905 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2906 goto end;
2907 }
2908 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2909 smtp_state->parser_state !=
2912 printf("smtp parser in inconsistent state\n");
2913 goto end;
2914 }
2915
2916 result = 1;
2917end:
2918 if (alp_tctx != NULL)
2920 StreamTcpFreeConfig(true);
2921 FLOW_DESTROY(&f);
2922 return result;
2923}
2924
2925/*
2926 * \test Test smtp with just <LF> delimiter instead of <CR><LF>.
2927 */
2928static int SMTPParserTest04(void)
2929{
2930 int result = 0;
2931 Flow f;
2932 int r = 0;
2933
2934 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
2935 uint8_t welcome_reply[] = {
2936 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2937 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2938 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2939 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2940 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2941 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2942 };
2943 uint32_t welcome_reply_len = sizeof(welcome_reply);
2944
2945 /* EHLO boo.com<CR><LF> */
2946 uint8_t request1[] = {
2947 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
2948 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
2949 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
2950 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
2951 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
2952 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
2953 };
2954 uint32_t request1_len = sizeof(request1);
2955
2956 TcpSession ssn;
2958
2959 memset(&f, 0, sizeof(f));
2960 memset(&ssn, 0, sizeof(ssn));
2961
2962 FLOW_INITIALIZE(&f);
2963 f.protoctx = (void *)&ssn;
2964 f.proto = IPPROTO_TCP;
2966
2967 StreamTcpInitConfig(true);
2968 SMTPTestInitConfig();
2969
2971 STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
2972 if (r != 0) {
2973 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2974 goto end;
2975 }
2976 SMTPState *smtp_state = f.alstate;
2977 if (smtp_state == NULL) {
2978 printf("no smtp state: ");
2979 goto end;
2980 }
2981 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
2983 printf("smtp parser in inconsistent state\n");
2984 goto end;
2985 }
2986
2988 STREAM_TOSERVER, request1, request1_len);
2989 if (r != 0) {
2990 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2991 goto end;
2992 }
2993 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
2994 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2996 printf("smtp parser in inconsistent state\n");
2997 goto end;
2998 }
2999
3000 result = 1;
3001end:
3002 if (alp_tctx != NULL)
3004 StreamTcpFreeConfig(true);
3005 FLOW_DESTROY(&f);
3006 return result;
3007}
3008
3009/*
3010 * \test Test STARTTLS fail.
3011 */
3012static int SMTPParserTest05(void)
3013{
3014 int result = 0;
3015 Flow f;
3016 int r = 0;
3017
3018 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
3019 uint8_t welcome_reply[] = {
3020 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
3021 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3022 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3023 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
3024 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
3025 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
3026 };
3027 uint32_t welcome_reply_len = sizeof(welcome_reply);
3028
3029 /* EHLO boo.com<CR><LF> */
3030 uint8_t request1[] = {
3031 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3032 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3033 };
3034 uint32_t request1_len = sizeof(request1);
3035 /* 250-poona_slack_vm1.localdomain<CR><LF>
3036 * 250-PIPELINING<CR><LF>
3037 * 250-SIZE 10240000<CR><LF>
3038 * 250-VRFY<CR><LF>
3039 * 250-ETRN<CR><LF>
3040 * 250-ENHANCEDSTATUSCODES<CR><LF>
3041 * 250-8BITMIME<CR><LF>
3042 * 250 DSN<CR><LF>
3043 */
3044 uint8_t reply1[] = {
3045 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
3046 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3047 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3048 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
3049 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
3050 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
3051 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
3052 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
3053 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3054 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
3055 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
3056 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
3057 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
3058 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
3059 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
3060 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
3061 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
3062 };
3063 uint32_t reply1_len = sizeof(reply1);
3064
3065 /* STARTTLS<CR><LF> */
3066 uint8_t request2[] = {
3067 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3068 0x0d, 0x0a
3069 };
3070 uint32_t request2_len = sizeof(request2);
3071 /* 502 5.5.2 Error: command not recognized<CR><LF> */
3072 uint8_t reply2[] = {
3073 0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e,
3074 0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a,
3075 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
3076 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63,
3077 0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d,
3078 0x0a
3079 };
3080 uint32_t reply2_len = sizeof(reply2);
3081
3082 /* QUIT<CR><LF> */
3083 uint8_t request3[] = {
3084 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
3085
3086 };
3087 uint32_t request3_len = sizeof(request3);
3088 /* 221 2.0.0 Bye<CR><LF> */
3089 uint8_t reply3[] = {
3090 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
3091 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
3092 };
3093 uint32_t reply3_len = sizeof(reply3);
3094
3095 TcpSession ssn;
3097
3098 memset(&f, 0, sizeof(f));
3099 memset(&ssn, 0, sizeof(ssn));
3100
3101 FLOW_INITIALIZE(&f);
3102 f.protoctx = (void *)&ssn;
3103 f.proto = IPPROTO_TCP;
3105
3106 StreamTcpInitConfig(true);
3107 SMTPTestInitConfig();
3108
3110 STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3111 if (r != 0) {
3112 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3113 goto end;
3114 }
3115 SMTPState *smtp_state = f.alstate;
3116 if (smtp_state == NULL) {
3117 printf("no smtp state: ");
3118 goto end;
3119 }
3120 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3122 printf("smtp parser in inconsistent state\n");
3123 goto end;
3124 }
3125
3127 STREAM_TOSERVER, request1, request1_len);
3128 if (r != 0) {
3129 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3130 goto end;
3131 }
3132 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3133 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3135 printf("smtp parser in inconsistent state\n");
3136 goto end;
3137 }
3138
3140 STREAM_TOCLIENT, reply1, reply1_len);
3141 if (r != 0) {
3142 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3143 goto end;
3144 }
3145 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3146 smtp_state->parser_state !=
3148 printf("smtp parser in inconsistent state\n");
3149 goto end;
3150 }
3151
3153 STREAM_TOSERVER, request2, request2_len);
3154 if (r != 0) {
3155 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3156 goto end;
3157 }
3158 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3159 smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
3160 smtp_state->parser_state !=
3162 printf("smtp parser in inconsistent state\n");
3163 goto end;
3164 }
3165
3167 STREAM_TOCLIENT, reply2, reply2_len);
3168 if (r != 0) {
3169 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3170 goto end;
3171 }
3172 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3173 smtp_state->parser_state !=
3175 printf("smtp parser in inconsistent state\n");
3176 goto end;
3177 }
3178
3179 if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
3181 (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
3182 (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
3183 goto end;
3184 }
3185
3187 STREAM_TOSERVER, request3, request3_len);
3188 if (r != 0) {
3189 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3190 goto end;
3191 }
3192 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3193 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3194 smtp_state->parser_state !=
3196 printf("smtp parser in inconsistent state\n");
3197 goto end;
3198 }
3199
3201 STREAM_TOCLIENT, reply3, reply3_len);
3202 if (r != 0) {
3203 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3204 goto end;
3205 }
3206 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3207 smtp_state->parser_state !=
3209 printf("smtp parser in inconsistent state\n");
3210 goto end;
3211 }
3212
3213 result = 1;
3214end:
3215 if (alp_tctx != NULL)
3217 StreamTcpFreeConfig(true);
3218 FLOW_DESTROY(&f);
3219 return result;
3220}
3221
3222/**
3223 * \test Test multiple DATA commands(full mail transactions).
3224 */
3225static int SMTPParserTest06(void)
3226{
3227 int result = 0;
3228 Flow f;
3229 int r = 0;
3230
3231 uint8_t welcome_reply[] = {
3232 0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30,
3233 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3234 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3235 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3236 0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e,
3237 0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69,
3238 0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f,
3239 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c,
3240 0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b,
3241 0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20,
3242 0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f,
3243 0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63,
3244 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20,
3245 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
3246 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69,
3247 0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f,
3248 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73,
3249 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
3250 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f,
3251 0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68,
3252 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72,
3253 0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73,
3254 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e,
3255 0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f,
3256 0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74,
3257 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c,
3258 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
3259 0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20,
3260 0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70,
3261 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63,
3262 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
3263 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
3264 0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f,
3265 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61,
3266 0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69,
3267 0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62,
3268 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35,
3269 0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d,
3270 0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a
3271 };
3272 uint32_t welcome_reply_len = sizeof(welcome_reply);
3273
3274 uint8_t request1[] = {
3275 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43,
3276 0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63,
3277 0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69,
3278 0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d,
3279 0x0a
3280 };
3281 uint32_t request1_len = sizeof(request1);
3282
3283 uint8_t reply1[] = {
3284 0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30,
3285 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
3286 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
3287 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
3288 0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31,
3289 0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c,
3290 0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31,
3291 0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39,
3292 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53,
3293 0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39,
3294 0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35,
3295 0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69,
3296 0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3297 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49,
3298 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3299 0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47,
3300 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3301 0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3302 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
3303 0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
3304 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b,
3305 0x0d, 0x0a
3306 };
3307 uint32_t reply1_len = sizeof(reply1);
3308
3309 /* MAIL FROM:asdff@asdf.com<CR><LF> */
3310 uint8_t request2[] = {
3311 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3312 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
3313 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
3314 0x0d, 0x0a
3315 };
3316 uint32_t request2_len = sizeof(request2);
3317 /* 250 2.1.0 Ok<CR><LF> */
3318 uint8_t reply2[] = {
3319 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3320 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3321 };
3322 uint32_t reply2_len = sizeof(reply2);
3323
3324 /* RCPT TO:bimbs@gmail.com<CR><LF> */
3325 uint8_t request3[] = {
3326 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
3327 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
3328 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3329 0x0a
3330 };
3331 uint32_t request3_len = sizeof(request3);
3332 /* 250 2.1.5 Ok<CR><LF> */
3333 uint8_t reply3[] = {
3334 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3335 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3336 };
3337 uint32_t reply3_len = sizeof(reply3);
3338
3339 /* BDAT 51<CR><LF> */
3340 uint8_t request4[] = {
3341 0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d,
3342 0x0a,
3343 };
3344 uint32_t request4_len = sizeof(request4);
3345
3346 uint8_t request5[] = {
3347 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3348 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3349 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3350 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a,
3351 };
3352 uint32_t request5_len = sizeof(request5);
3353
3354 uint8_t request6[] = {
3355 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
3356 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
3357 0x66, 0x0d, 0x0a,
3358 };
3359 uint32_t request6_len = sizeof(request6);
3360
3361 TcpSession ssn;
3363
3364 memset(&f, 0, sizeof(f));
3365 memset(&ssn, 0, sizeof(ssn));
3366
3367 FLOW_INITIALIZE(&f);
3368 f.protoctx = (void *)&ssn;
3369 f.proto = IPPROTO_TCP;
3371
3372 StreamTcpInitConfig(true);
3373 SMTPTestInitConfig();
3374
3376 STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3377 if (r != 0) {
3378 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3379 goto end;
3380 }
3381 SMTPState *smtp_state = f.alstate;
3382 if (smtp_state == NULL) {
3383 printf("no smtp state: ");
3384 goto end;
3385 }
3386 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3388 printf("smtp parser in inconsistent state\n");
3389 goto end;
3390 }
3391
3393 STREAM_TOSERVER, request1, request1_len);
3394 if (r != 0) {
3395 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3396 goto end;
3397 }
3398 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3399 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3401 printf("smtp parser in inconsistent state\n");
3402 goto end;
3403 }
3404
3406 STREAM_TOCLIENT, reply1, reply1_len);
3407 if (r != 0) {
3408 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3409 goto end;
3410 }
3411 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3413 printf("smtp parser in inconsistent state\n");
3414 goto end;
3415 }
3416
3418 STREAM_TOSERVER, request2, request2_len);
3419 if (r != 0) {
3420 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3421 goto end;
3422 }
3423 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3424 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3426 printf("smtp parser in inconsistent state\n");
3427 goto end;
3428 }
3429
3431 STREAM_TOCLIENT, reply2, reply2_len);
3432 if (r != 0) {
3433 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3434 goto end;
3435 }
3436 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3438 printf("smtp parser in inconsistent state\n");
3439 goto end;
3440 }
3441
3443 STREAM_TOSERVER, request3, request3_len);
3444 if (r != 0) {
3445 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3446 goto end;
3447 }
3448 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3449 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
3451 printf("smtp parser in inconsistent state\n");
3452 goto end;
3453 }
3454
3456 STREAM_TOCLIENT, reply3, reply3_len);
3457 if (r != 0) {
3458 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3459 goto end;
3460 }
3461 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3463 printf("smtp parser in inconsistent state\n");
3464 goto end;
3465 }
3466
3468 STREAM_TOSERVER, request4, request4_len);
3469 if (r != 0) {
3470 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3471 goto end;
3472 }
3473 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3474 smtp_state->cmds[0] != SMTP_COMMAND_BDAT ||
3475 smtp_state->parser_state !=
3477 smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 0) {
3478 printf("smtp parser in inconsistent state\n");
3479 goto end;
3480 }
3481
3483 STREAM_TOSERVER, request5, request5_len);
3484 if (r != 0) {
3485 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3486 goto end;
3487 }
3488 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3489 smtp_state->parser_state !=
3491 smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 32) {
3492 printf("smtp parser in inconsistent state\n");
3493 goto end;
3494 }
3495
3497 STREAM_TOSERVER, request6, request6_len);
3498 if (r != 0) {
3499 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3500 goto end;
3501 }
3502 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3504 smtp_state->bdat_chunk_len != 51 || smtp_state->bdat_chunk_idx != 51) {
3505 printf("smtp parser in inconsistent state\n");
3506 goto end;
3507 }
3508
3509 result = 1;
3510end:
3511 if (alp_tctx != NULL)
3513 StreamTcpFreeConfig(true);
3514 FLOW_DESTROY(&f);
3515 return result;
3516}
3517
3518static int SMTPParserTest12(void)
3519{
3520 int result = 0;
3521 Signature *s = NULL;
3522 ThreadVars th_v;
3523 Packet *p = NULL;
3524 Flow f;
3525 TcpSession ssn;
3526 DetectEngineThreadCtx *det_ctx = NULL;
3527 DetectEngineCtx *de_ctx = NULL;
3528 SMTPState *smtp_state = NULL;
3529 int r = 0;
3530
3531 /* EHLO boo.com<CR><LF> */
3532 uint8_t request1[] = {
3533 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3534 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3535 };
3536 int32_t request1_len = sizeof(request1);
3537
3538 /* 388<CR><LF>
3539 */
3540 uint8_t reply1[] = {
3541 0x31, 0x38, 0x38, 0x0d, 0x0a,
3542 };
3543 uint32_t reply1_len = sizeof(reply1);
3544
3546
3547 memset(&th_v, 0, sizeof(th_v));
3548 memset(&f, 0, sizeof(f));
3549 memset(&ssn, 0, sizeof(ssn));
3550
3551 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3552
3553 FLOW_INITIALIZE(&f);
3554 f.protoctx = (void *)&ssn;
3555 f.proto = IPPROTO_TCP;
3557 p->flow = &f;
3562
3563 StreamTcpInitConfig(true);
3564 SMTPTestInitConfig();
3565
3567 if (de_ctx == NULL)
3568 goto end;
3569
3570 de_ctx->flags |= DE_QUIET;
3571
3572 s = DetectEngineAppendSig(de_ctx,"alert tcp any any -> any any "
3573 "(msg:\"SMTP event handling\"; "
3574 "app-layer-event: smtp.invalid_reply; "
3575 "sid:1;)");
3576 if (s == NULL)
3577 goto end;
3578
3580 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3581
3583 STREAM_TOSERVER | STREAM_START, request1,
3584 request1_len);
3585 if (r != 0) {
3586 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3587 goto end;
3588 }
3589
3590 smtp_state = f.alstate;
3591 if (smtp_state == NULL) {
3592 printf("no smtp state: ");
3593 goto end;
3594 }
3595
3596 /* do detect */
3597 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3598
3599 if (PacketAlertCheck(p, 1)) {
3600 printf("sid 1 matched. It shouldn't match: ");
3601 goto end;
3602 }
3603
3605 STREAM_TOCLIENT | STREAM_TOCLIENT, reply1,
3606 reply1_len);
3607 if (r == 0) {
3608 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3609 goto end;
3610 }
3611
3612 /* do detect */
3613 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3614
3615 if (!PacketAlertCheck(p, 1)) {
3616 printf("sid 1 didn't match. Should have matched: ");
3617 goto end;
3618 }
3619
3620 result = 1;
3621
3622end:
3625
3626 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
3628
3629 if (alp_tctx != NULL)
3631 StreamTcpFreeConfig(true);
3632 FLOW_DESTROY(&f);
3633 UTHFreePackets(&p, 1);
3634 return result;
3635}
3636
3637static int SMTPParserTest13(void)
3638{
3639 int result = 0;
3640 Signature *s = NULL;
3641 ThreadVars th_v;
3642 Packet *p = NULL;
3643 Flow f;
3644 TcpSession ssn;
3645 DetectEngineThreadCtx *det_ctx = NULL;
3646 DetectEngineCtx *de_ctx = NULL;
3647 SMTPState *smtp_state = NULL;
3648 int r = 0;
3649
3650 /* EHLO boo.com<CR><LF> */
3651 uint8_t request1[] = {
3652 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3653 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
3654 };
3655 int32_t request1_len = sizeof(request1);
3656
3657 /* 250<CR><LF>
3658 */
3659 uint8_t reply1[] = {
3660 0x32, 0x35, 0x30, 0x0d, 0x0a,
3661 };
3662 uint32_t reply1_len = sizeof(reply1);
3663
3664 /* MAIL FROM:pbsf@asdfs.com<CR><LF>
3665 * RCPT TO:pbsf@asdfs.com<CR><LF>
3666 * DATA<CR><LF>
3667 * STARTTLS<CR><LF>
3668 */
3669 uint8_t request2[] = {
3670 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3671 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3672 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3673 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
3674 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
3675 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
3676 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a,
3677 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
3678 0x0d, 0x0a
3679 };
3680 uint32_t request2_len = sizeof(request2);
3681
3683
3684 memset(&th_v, 0, sizeof(th_v));
3685 memset(&f, 0, sizeof(f));
3686 memset(&ssn, 0, sizeof(ssn));
3687
3688 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
3689
3690 FLOW_INITIALIZE(&f);
3691 f.protoctx = (void *)&ssn;
3692 f.proto = IPPROTO_TCP;
3694 p->flow = &f;
3699
3700 StreamTcpInitConfig(true);
3701 SMTPTestInitConfig();
3702
3704 if (de_ctx == NULL)
3705 goto end;
3706
3707 de_ctx->flags |= DE_QUIET;
3708
3709 s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
3710 "(msg:\"SMTP event handling\"; "
3711 "app-layer-event: "
3712 "smtp.invalid_pipelined_sequence; "
3713 "sid:1;)");
3714 if (s == NULL)
3715 goto end;
3716
3718 DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
3719
3721 STREAM_TOSERVER | STREAM_START, request1,
3722 request1_len);
3723 if (r != 0) {
3724 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3725 goto end;
3726 }
3727
3728 smtp_state = f.alstate;
3729 if (smtp_state == NULL) {
3730 printf("no smtp state: ");
3731 goto end;
3732 }
3733
3734 /* do detect */
3735 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3736
3737 if (PacketAlertCheck(p, 1)) {
3738 printf("sid 1 matched. It shouldn't match: ");
3739 goto end;
3740 }
3741
3743 STREAM_TOCLIENT, reply1, reply1_len);
3744 if (r != 0) {
3745 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3746 goto end;
3747 }
3748
3749 /* do detect */
3750 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3751
3752 if (PacketAlertCheck(p, 1)) {
3753 printf("sid 1 matched. It shouldn't match: ");
3754 goto end;
3755 }
3756
3758 STREAM_TOSERVER, request2, request2_len);
3759 if (r != 0) {
3760 printf("AppLayerParse for smtp failed. Returned %" PRId32, r);
3761 goto end;
3762 }
3763
3764 /* do detect */
3765 SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
3766
3767 if (!PacketAlertCheck(p, 1)) {
3768 printf("sid 1 didn't match. Should have matched: ");
3769 goto end;
3770 }
3771
3772 result = 1;
3773
3774end:
3777
3778 DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
3780
3781 if (alp_tctx != NULL)
3783 StreamTcpFreeConfig(true);
3784 FLOW_DESTROY(&f);
3785 UTHFreePackets(&p, 1);
3786 return result;
3787}
3788
3789/**
3790 * \test Test DATA command w/MIME message.
3791 */
3792static int SMTPParserTest14(void)
3793{
3794 int result = 0;
3795 Flow f;
3796 int r = 0;
3797
3798 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
3799 static uint8_t welcome_reply[] = {
3800 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
3801 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
3802 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
3803 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
3804 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
3805 0x0d, 0x0a
3806 };
3807 static uint32_t welcome_reply_len = sizeof(welcome_reply);
3808
3809 /* EHLO boo.com<CR><LF> */
3810 static uint8_t request1[] = {
3811 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
3812 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
3813 };
3814 static uint32_t request1_len = sizeof(request1);
3815 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
3816 * 250-SIZE 35882577<CR><LF>
3817 * 250-8BITMIME<CR><LF>
3818 * 250-STARTTLS<CR><LF>
3819 * 250 ENHANCEDSTATUSCODES<CR><LF>
3820 */
3821 static uint8_t reply1[] = {
3822 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
3823 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
3824 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
3825 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
3826 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
3827 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
3828 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
3829 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
3830 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
3831 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
3832 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
3833 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
3834 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
3835 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
3836 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
3837 };
3838 static uint32_t reply1_len = sizeof(reply1);
3839
3840 /* MAIL FROM:asdff@asdf.com<CR><LF> */
3841 static uint8_t request2[] = {
3842 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
3843 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
3844 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
3845 0x0d, 0x0a
3846 };
3847 static uint32_t request2_len = sizeof(request2);
3848 /* 250 2.1.0 Ok<CR><LF> */
3849 static uint8_t reply2[] = {
3850 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3851 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3852 };
3853 static uint32_t reply2_len = sizeof(reply2);
3854
3855 /* RCPT TO:bimbs@gmail.com<CR><LF> */
3856 static uint8_t request3[] = {
3857 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
3858 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
3859 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
3860 0x0a
3861 };
3862 static uint32_t request3_len = sizeof(request3);
3863 /* 250 2.1.5 Ok<CR><LF> */
3864 static uint8_t reply3[] = {
3865 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
3866 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
3867 };
3868 static uint32_t reply3_len = sizeof(reply3);
3869
3870 /* DATA<CR><LF> */
3871 static uint8_t request4[] = {
3872 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
3873 };
3874 static uint32_t request4_len = sizeof(request4);
3875 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
3876 static uint8_t reply4[] = {
3877 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
3878 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
3879 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
3880 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
3881 0x4c, 0x46, 0x3e, 0x0d, 0x0a
3882 };
3883 static uint32_t reply4_len = sizeof(reply4);
3884
3885 /* MIME_MSG */
3886 static uint64_t filesize = 133;
3887 static uint8_t request4_msg[] = {
3888 0x4D, 0x49, 0x4D, 0x45, 0x2D, 0x56, 0x65, 0x72,
3889 0x73, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x31, 0x2E,
3890 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
3891 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A,
3892 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61,
3893 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6F, 0x63, 0x74,
3894 0x65, 0x74, 0x2D, 0x73, 0x74, 0x72, 0x65, 0x61,
3895 0x6D, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65,
3896 0x6E, 0x74, 0x2D, 0x54, 0x72, 0x61, 0x6E, 0x73,
3897 0x66, 0x65, 0x72, 0x2D, 0x45, 0x6E, 0x63, 0x6F,
3898 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x62, 0x61,
3899 0x73, 0x65, 0x36, 0x34, 0x0D, 0x0A, 0x43, 0x6F,
3900 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x44, 0x69,
3901 0x73, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x69, 0x6F,
3902 0x6E, 0x3A, 0x20, 0x61, 0x74, 0x74, 0x61, 0x63,
3903 0x68, 0x6D, 0x65, 0x6E, 0x74, 0x3B, 0x20, 0x66,
3904 0x69, 0x6C, 0x65, 0x6E, 0x61, 0x6D, 0x65, 0x3D,
3905 0x22, 0x74, 0x65, 0x73, 0x74, 0x2E, 0x65, 0x78,
3906 0x65, 0x22, 0x3B, 0x0D, 0x0A, 0x0D, 0x0A, 0x54,
3907 0x56, 0x6F, 0x41, 0x41, 0x46, 0x42, 0x46, 0x41,
3908 0x41, 0x42, 0x4D, 0x41, 0x51, 0x45, 0x41, 0x61,
3909 0x69, 0x70, 0x59, 0x77, 0x77, 0x41, 0x41, 0x41,
3910 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
3911 0x41, 0x41, 0x44, 0x41, 0x51, 0x73, 0x42, 0x43,
3912 0x41, 0x41, 0x42, 0x41, 0x41, 0x43, 0x41, 0x41,
3913 0x41, 0x41, 0x41, 0x41, 0x48, 0x6B, 0x41, 0x41,
3914 0x41, 0x41, 0x4D, 0x41, 0x41, 0x41, 0x41, 0x65,
3915 0x51, 0x41, 0x41, 0x41, 0x41, 0x77, 0x41, 0x41,
3916 0x41, 0x41, 0x41, 0x41, 0x45, 0x41, 0x41, 0x42,
3917 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
3918 0x41, 0x42, 0x30, 0x41, 0x41, 0x41, 0x41, 0x49,
3919 0x41, 0x41, 0x41, 0x41, 0x41, 0x51, 0x41, 0x41,
3920 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42,
3921 0x41, 0x45, 0x41, 0x41, 0x49, 0x67, 0x41, 0x41,
3922 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
3923 0x67, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
3924 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
3925 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
3926 0x41, 0x42, 0x63, 0x58, 0x44, 0x59, 0x32, 0x4C,
3927 0x6A, 0x6B, 0x7A, 0x4C, 0x6A, 0x59, 0x34, 0x4C,
3928 0x6A, 0x5A, 0x63, 0x65, 0x67, 0x41, 0x41, 0x4F,
3929 0x41, 0x3D, 0x3D, 0x0D,0x0A };
3930 static uint32_t request4_msg_len = sizeof(request4_msg);
3931
3932 /* DATA COMPLETED */
3933 static uint8_t request4_end[] = {
3934 0x0d, 0x0a, 0x2e, 0x0d, 0x0a
3935 };
3936 static uint32_t request4_end_len = sizeof(request4_end);
3937 /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
3938 static uint8_t reply4_end[] = {
3939 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
3940 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
3941 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
3942 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
3943 0x46, 0x32, 0x0d, 0x0a
3944 };
3945 static uint32_t reply4_end_len = sizeof(reply4_end);
3946
3947 /* QUIT<CR><LF> */
3948 static uint8_t request5[] = {
3949 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
3950 };
3951 static uint32_t request5_len = sizeof(request5);
3952 /* 221 2.0.0 Bye<CR><LF> */
3953 static uint8_t reply5[] = {
3954 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
3955 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
3956 };
3957 static uint32_t reply5_len = sizeof(reply5);
3958
3959 TcpSession ssn;
3961
3962 memset(&f, 0, sizeof(f));
3963 memset(&ssn, 0, sizeof(ssn));
3964
3965 FLOW_INITIALIZE(&f);
3966 f.protoctx = (void *)&ssn;
3967 f.proto = IPPROTO_TCP;
3969
3970 StreamTcpInitConfig(true);
3971 SMTPTestInitConfig();
3972
3973 /* Welcome reply */
3975 STREAM_TOCLIENT, welcome_reply, welcome_reply_len);
3976 if (r != 0) {
3977 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3978 goto end;
3979 }
3980 SMTPState *smtp_state = f.alstate;
3981 if (smtp_state == NULL) {
3982 printf("no smtp state: ");
3983 goto end;
3984 }
3985 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
3987 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
3988 goto end;
3989 }
3990
3992 STREAM_TOSERVER, request1, request1_len);
3993 if (r != 0) {
3994 printf("smtp check returned %" PRId32 ", expected 0: ", r);
3995 goto end;
3996 }
3997 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
3998 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4000 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4001 goto end;
4002 }
4003
4004 /* EHLO Reply */
4006 STREAM_TOCLIENT, reply1, reply1_len);
4007 if (r != 0) {
4008 printf("smtp check returned %" PRId32 ", expected 0: ", r);
4009 goto end;
4010 }
4011
4012 if ((smtp_state->helo_len != 7) || strncmp("boo.com", (char *)smtp_state->helo, 7)) {
4013 printf("incorrect parsing of HELO field '%s' (%d)\n", smtp_state->helo, smtp_state->helo_len);
4014 goto end;
4015 }
4016
4017 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4019 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4020 goto end;
4021 }
4022
4023 /* MAIL FROM Request */
4025 STREAM_TOSERVER, request2, request2_len);
4026 if (r != 0) {
4027 printf("smtp check returned %" PRId32 ", expected 0: ", r);
4028 goto end;
4029 }
4030 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4031 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4033 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4034 goto end;
4035 }
4036
4037 /* MAIL FROM Reply */
4039 STREAM_TOCLIENT, reply2, reply2_len);
4040 if (r != 0) {
4041 printf("smtp check returned %" PRId32 ", expected 0: ", r);
4042 goto end;
4043 }
4044
4045 if ((smtp_state->curr_tx->mail_from_len != 14) ||
4046 strncmp("asdff@asdf.com", (char *)smtp_state->curr_tx->mail_from, 14)) {
4047 printf("incorrect parsing of MAIL FROM field '%s' (%d)\n",
4048 smtp_state->curr_tx->mail_from,
4049 smtp_state->curr_tx->mail_from_len);
4050 goto end;
4051 }
4052
4053 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4055 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4056 goto end;
4057 }
4058
4059 /* RCPT TO Request */
4061 STREAM_TOSERVER, request3, request3_len);
4062 if (r != 0) {
4063 printf("smtp check returned %" PRId32 ", expected 0: ", r);
4064 goto end;
4065 }
4066 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4067 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4069 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4070 goto end;
4071 }
4072
4073 /* RCPT TO Reply */
4075 STREAM_TOCLIENT, reply3, reply3_len);
4076 if (r != 0) {
4077 printf("smtp check returned %" PRId32 ", expected 0: ", r);
4078 goto end;
4079 }
4080 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4082 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4083 goto end;
4084 }
4085
4086 /* Enable mime decoding */
4087 smtp_config.decode_mime = true;
4088 SCMimeSmtpConfigDecodeBase64(1);
4089 SCMimeSmtpConfigDecodeQuoted(1);
4090
4091 /* DATA request */
4093 STREAM_TOSERVER, request4, request4_len);
4094 if (r != 0) {
4095 printf("smtp check returned %" PRId32 ", expected 0: ", r);
4096 goto end;
4097 }
4098
4099 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4100 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
4102 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4103 goto end;
4104 }
4105
4106 /* Data reply */
4108 STREAM_TOCLIENT, reply4, reply4_len);
4109 if (r != 0) {
4110 printf("smtp check returned %" PRId32 ", expected 0: ", r);
4111 goto end;
4112 }
4113 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4114 smtp_state->parser_state !=
4116 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4117 goto end;
4118 }
4119
4120 /* DATA message */
4122 STREAM_TOSERVER, request4_msg, request4_msg_len);
4123 if (r != 0) {
4124 printf("smtp check returned %" PRId32 ", expected 0: ", r);
4125 goto end;
4126 }
4127
4128 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4129 smtp_state->curr_tx->mime_state == NULL ||
4130 smtp_state->parser_state !=
4132 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4133 goto end;
4134 }
4135
4136 /* DATA . request */
4138 STREAM_TOSERVER, request4_end, request4_end_len);
4139 if (r != 0) {
4140 printf("smtp check returned %" PRId32 ", expected 0: ", r);
4141 goto end;
4142 }
4143
4144 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4145 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
4146 smtp_state->curr_tx->mime_state == NULL ||
4148 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4149 goto end;
4150 }
4151
4152 SMTPState *state = (SMTPState *) f.alstate;
4153 FAIL_IF_NULL(state);
4154 FAIL_IF_NULL(state->curr_tx);
4155
4156 FileContainer *files = &state->curr_tx->files_ts;
4157 if (files != NULL && files->head != NULL) {
4158 File *file = files->head;
4159
4160 if(strncmp((const char *)file->name, "test.exe", 8) != 0){
4161 printf("smtp-mime file name is incorrect");
4162 goto end;
4163 }
4164 if (FileTrackedSize(file) != filesize){
4165 printf("smtp-mime file size %"PRIu64" is incorrect", FileDataSize(file));
4166 goto end;
4167 }
4168 static uint8_t org_binary[] = {
4169 0x4D, 0x5A, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00,
4170 0x4C, 0x01, 0x01, 0x00, 0x6A, 0x2A, 0x58, 0xC3,
4171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4172 0x04, 0x00, 0x03, 0x01, 0x0B, 0x01, 0x08, 0x00,
4173 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
4174 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4175 0x79, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
4176 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00,
4177 0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00,
4178 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
4179 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00,
4180 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4181 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4182 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4183 0x00, 0x00, 0x00, 0x00, 0x5C, 0x5C, 0x36, 0x36,
4184 0x2E, 0x39, 0x33, 0x2E, 0x36, 0x38, 0x2E, 0x36,
4185 0x5C, 0x7A, 0x00, 0x00, 0x38,};
4186
4188 org_binary, sizeof(org_binary)) != 1)
4189 {
4190 printf("smtp-mime file data incorrect\n");
4191 goto end;
4192 }
4193 }
4194
4195 /* DATA . reply */
4197 STREAM_TOCLIENT, reply4_end, reply4_end_len);
4198 if (r != 0) {
4199 printf("smtp check returned %" PRId32 ", expected 0: ", r);
4200 goto end;
4201 }
4202 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4204 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4205 goto end;
4206 }
4207
4208 /* QUIT Request */
4210 STREAM_TOSERVER, request5, request5_len);
4211 if (r != 0) {
4212 printf("smtp check returned %" PRId32 ", expected 0: ", r);
4213 goto end;
4214 }
4215 if (smtp_state->cmds_cnt != 1 || smtp_state->cmds_idx != 0 ||
4216 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
4218 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4219 goto end;
4220 }
4221
4222 /* QUIT Reply */
4224 STREAM_TOCLIENT, reply5, reply5_len);
4225 if (r != 0) {
4226 printf("smtp check returned %" PRId32 ", expected 0: ", r);
4227 goto end;
4228 }
4229 if (smtp_state->cmds_cnt != 0 || smtp_state->cmds_idx != 0 ||
4231 printf("smtp parser in inconsistent state l.%d\n", __LINE__);
4232 goto end;
4233 }
4234
4235 result = 1;
4236end:
4237 if (alp_tctx != NULL)
4239 StreamTcpFreeConfig(true);
4240 FLOW_DESTROY(&f);
4241 return result;
4242}
4243#endif /* UNITTESTS */
4244
4246{
4247#ifdef UNITTESTS
4248 UtRegisterTest("SMTPParserTest01", SMTPParserTest01);
4249 UtRegisterTest("SMTPParserTest02", SMTPParserTest02);
4250 UtRegisterTest("SMTPParserTest03", SMTPParserTest03);
4251 UtRegisterTest("SMTPParserTest04", SMTPParserTest04);
4252 UtRegisterTest("SMTPParserTest05", SMTPParserTest05);
4253 UtRegisterTest("SMTPParserTest06", SMTPParserTest06);
4254 UtRegisterTest("SMTPParserTest12", SMTPParserTest12);
4255 UtRegisterTest("SMTPParserTest13", SMTPParserTest13);
4256 UtRegisterTest("SMTPParserTest14", SMTPParserTest14);
4257#endif /* UNITTESTS */
4258}
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
int SCAppLayerProtoDetectPPParseConfPorts(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)
void SCAppLayerProtoDetectPPRegister(uint8_t ipproto, const char *portstr, AppProto alproto, uint16_t min_depth, uint16_t max_depth, uint8_t direction, ProbingParserFPtr ProbingParser1, ProbingParserFPtr ProbingParser2)
register parser at a port
int SCAppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction)
Registers a case-insensitive pattern for protocol detection.
int SCAppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
Given a protocol name, checks if proto detection is enabled in the conf file.
bool SCAppLayerRequestProtocolTLSUpgrade(Flow *f)
request applayer to wrap up this protocol and rerun protocol detection with expectation of TLS....
uint8_t len
int SCAppLayerGetEventIdByName(const char *event_name, SCEnumCharMap *table, uint8_t *event_id)
void AppLayerDecoderEventsSetEventRaw(AppLayerDecoderEvents **sevents, uint8_t event)
Set an app layer decoder event.
void AppLayerFrameSetTxId(Frame *r, uint64_t tx_id)
Frame * AppLayerFrameNewByPointer(Flow *f, const StreamSlice *stream_slice, const uint8_t *frame_start, const int64_t len, int dir, uint8_t frame_type)
create new frame using a pointer to start of the frame
Frame * AppLayerFrameGetLastOpenByType(Flow *f, const int dir, const uint8_t frame_type)
struct HtpBodyChunk_ * next
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))
uint16_t SCAppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint16_t flag)
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
void AppLayerParserRegisterTxDataFunc(uint8_t ipproto, AppProto alproto, AppLayerTxData *(*GetTxData)(void *tx))
void AppLayerParserTriggerRawStreamInspection(Flow *f, int direction)
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
void AppLayerParserRegisterStateProgressCompletionStatus(AppProto alproto, const int ts, const int tc)
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
void AppLayerParserRegisterGetTxFilesFunc(uint8_t ipproto, AppProto alproto, AppLayerGetFileState(*GetTxFiles)(void *, uint8_t))
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
void AppLayerParserRegisterStateDataFunc(uint8_t ipproto, AppProto alproto, AppLayerStateData *(*GetStateData)(void *state))
void AppLayerParserRegisterGetTxIterator(uint8_t ipproto, AppProto alproto, AppLayerGetTxIteratorFunc Func)
void AppLayerParserRegisterLocalStorageFunc(uint8_t ipproto, AppProto alproto, void *(*LocalStorageAlloc)(void), void(*LocalStorageFree)(void *))
int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, uint8_t direction, AppLayerParserFPtr Parser)
Register app layer parser for the protocol.
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, int(*StateGetEventInfo)(const char *event_name, uint8_t *event_id, AppLayerEventType *event_type))
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
int SCAppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name)
check if a parser is enabled in the config Returns enabled always if: were running unittests
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void *, AppProto), void(*StateFree)(void *))
void AppLayerParserRegisterGetEventInfoById(uint8_t ipproto, AppProto alproto, int(*StateGetEventInfoById)(uint8_t event_id, const char **event_name, AppLayerEventType *event_type))
void AppLayerParserRegisterGetFrameFuncs(uint8_t ipproto, AppProto alproto, AppLayerParserGetFrameIdByNameFn GetIdByNameFunc, AppLayerParserGetFrameNameByIdFn GetNameByIdFunc)
struct AppLayerGetFileState AppLayerGetFileState
struct AppLayerGetTxIterTuple AppLayerGetTxIterTuple
struct AppLayerTxData AppLayerTxData
#define APP_LAYER_PARSER_EOF_TC
#define APP_LAYER_OK
#define APP_LAYER_INCOMPLETE(c, n)
struct AppLayerResult AppLayerResult
#define APP_LAYER_PARSER_EOF_TS
#define APP_LAYER_ERROR
struct StreamSlice StreamSlice
struct AppLayerStateData AppLayerStateData
enum AppLayerEventType AppLayerEventType
uint16_t AppProto
@ ALPROTO_TLS
@ ALPROTO_FAILED
@ ALPROTO_SMTP
@ ALPROTO_UNKNOWN
#define FILEDATA_CONTENT_LIMIT
#define SMTP_COMMAND_RSET
void * SMTPStateAlloc(void *orig_state, AppProto proto_orig)
#define FILEDATA_CONTENT_INSPECT_MIN_SIZE
#define FILEDATA_CONTENT_INSPECT_WINDOW
struct SMTPThreadCtx_ SMTPThreadCtx
#define SMTP_COMMAND_DATA_MODE
void SMTPParserCleanup(void)
Free memory allocated for global SMTP parser state.
struct SMTPLine_ SMTPLine
#define SMTP_MPM
#define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY
#define SMTP_PARSER_STATE_FIRST_REPLY_SEEN
SCEnumCharMap smtp_reply_map[]
SMTPCode
@ SMTP_REPLY_525
@ SMTP_REPLY_402
@ SMTP_REPLY_552
@ SMTP_REPLY_421
@ SMTP_REPLY_502
@ SMTP_REPLY_551
@ SMTP_REPLY_550
@ SMTP_REPLY_435
@ SMTP_REPLY_530
@ SMTP_REPLY_541
@ SMTP_REPLY_252
@ SMTP_REPLY_521
@ SMTP_REPLY_334
@ SMTP_REPLY_214
@ SMTP_REPLY_554
@ SMTP_REPLY_504
@ SMTP_REPLY_500
@ SMTP_REPLY_511
@ SMTP_REPLY_553
@ SMTP_REPLY_451
@ SMTP_REPLY_455
@ SMTP_REPLY_401
@ SMTP_REPLY_221
@ SMTP_REPLY_235
@ SMTP_REPLY_220
@ SMTP_REPLY_250
@ SMTP_REPLY_543
@ SMTP_REPLY_501
@ SMTP_REPLY_503
@ SMTP_REPLY_454
@ SMTP_REPLY_251
@ SMTP_REPLY_450
@ SMTP_REPLY_522
@ SMTP_REPLY_211
@ SMTP_REPLY_354
@ SMTP_REPLY_534
@ SMTP_REPLY_535
@ SMTP_REPLY_555
@ SMTP_REPLY_452
SMTPFrameTypes
@ SMTP_FRAME_RESPONSE_LINE
@ SMTP_FRAME_DATA
@ SMTP_FRAME_COMMAND_LINE
#define SMTP_COMMAND_DATA
SCEnumCharMap smtp_frame_table[]
#define SMTP_COMMAND_BDAT
#define SMTP_DEFAULT_MAX_TX
void SMTPParserRegisterTests(void)
SCEnumCharMap smtp_decoder_event_table[]
SMTPConfig smtp_config
#define rawmsgname
#define SMTP_PARSER_STATE_COMMAND_DATA_MODE
#define SMTP_COMMAND_OTHER_CMD
struct SMTPInput_ SMTPInput
void RegisterSMTPParsers(void)
Register the SMTP Protocol parser.
#define SMTP_RAW_EXTRACTION_DEFAULT_VALUE
#define SCHEME_SUFFIX_LEN
#define SMTP_COMMAND_BUFFER_STEPS
#define SMTP_PARSER_STATE_PIPELINING_SERVER
#define SMTP_COMMAND_STARTTLS
@ SMTP_DECODER_EVENT_UNABLE_TO_MATCH_REPLY_WITH_REQUEST
@ SMTP_DECODER_EVENT_MAX_REPLY_LINE_LEN_EXCEEDED
@ SMTP_DECODER_EVENT_MIME_INVALID_BASE64
@ SMTP_DECODER_EVENT_TRUNCATED_LINE
@ SMTP_DECODER_EVENT_INVALID_REPLY
@ SMTP_DECODER_EVENT_BDAT_CHUNK_LEN_EXCEEDED
@ SMTP_DECODER_EVENT_TLS_REJECTED
@ SMTP_DECODER_EVENT_MIME_PARSE_FAILED
@ SMTP_DECODER_EVENT_MAX_COMMAND_LINE_LEN_EXCEEDED
@ SMTP_DECODER_EVENT_UNPARSABLE_CONTENT
@ SMTP_DECODER_EVENT_MIME_LONG_FILENAME
@ SMTP_DECODER_EVENT_MIME_LONG_HEADER_NAME
@ SMTP_DECODER_EVENT_INVALID_PIPELINED_SEQUENCE
@ SMTP_DECODER_EVENT_MIME_LONG_ENC_LINE
@ SMTP_DECODER_EVENT_NO_SERVER_WELCOME_MESSAGE
@ SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED
@ SMTP_DECODER_EVENT_MIME_LONG_HEADER_VALUE
@ SMTP_DECODER_EVENT_DUPLICATE_FIELDS
@ SMTP_DECODER_EVENT_MIME_INVALID_QP
@ SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE
@ SMTP_DECODER_EVENT_MIME_BOUNDARY_TOO_LONG
@ SMTP_DECODER_EVENT_MIME_LONG_LINE
#define SMTP_LINE_BUFFER_LIMIT
SCConfNode * SCConfNodeLookupChild(const SCConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition conf.c:796
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition conf.c:181
int SCConfGetChildValueInt(const SCConfNode *base, const char *name, intmax_t *val)
Definition conf.c:449
int SCConfGetBool(const char *name, int *val)
Retrieve a configuration value as a boolean.
Definition conf.c:497
int SCConfGetChildValueBool(const SCConfNode *base, const char *name, int *val)
Definition conf.c:515
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition conf.c:350
uint8_t flags
Definition decode-gre.h:0
uint16_t type
#define PKT_HAS_FLOW
Definition decode.h:1266
#define PKT_STREAM_EST
Definition decode.h:1262
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
void SigCleanSignatures(DetectEngineCtx *de_ctx)
int SigGroupCleanup(DetectEngineCtx *de_ctx)
DetectEngineCtx * DetectEngineCtxInit(void)
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Data structures and function prototypes for keeping state for the detection engine.
#define DETECT_ENGINE_STATE_FLAG_FILE_NEW
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
uint32_t id
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition detect.c:2420
#define DE_QUIET
Definition detect.h:330
#define FLOW_INITIALIZE(f)
Definition flow-util.h:38
#define FLOW_DESTROY(f)
Definition flow-util.h:119
int FlowChangeProto(Flow *f)
Check if change proto flag is set for flow.
Definition flow.c:196
#define FLOW_NOPAYLOAD_INSPECTION
Definition flow.h:67
#define FLOW_PKT_TOSERVER
Definition flow.h:233
#define FLOW_PKT_ESTABLISHED
Definition flow.h:235
AppLayerParserThreadCtx * alp_tctx
DetectEngineCtx * de_ctx
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:252
#define TAILQ_INIT(head)
Definition queue.h:262
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition queue.h:294
#define TAILQ_FIRST(head)
Definition queue.h:250
#define TAILQ_REMOVE(head, elm, field)
Definition queue.h:312
#define TAILQ_NEXT(elm, field)
Definition queue.h:307
#define STREAMTCP_STREAM_FLAG_NOREASSEMBLY
#define STREAMTCP_FLAG_APP_LAYER_DISABLED
void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
void StreamTcpFreeConfig(bool quiet)
Definition stream-tcp.c:859
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition stream-tcp.c:488
union AppLayerGetTxIterState::@7 un
main detection engine ctx
Definition detect.h:932
uint8_t flags
Definition detect.h:934
uint8_t * name
Definition util-file.h:88
StreamingBuffer * sb
Definition util-file.h:83
uint64_t size
Definition util-file.h:102
FileState state
Definition util-file.h:82
uint64_t content_inspected
Definition util-file.h:99
Flow data structure.
Definition flow.h:356
AppProto alproto_ts
Definition flow.h:451
uint8_t proto
Definition flow.h:378
uint32_t flags
Definition flow.h:421
AppProto alproto
application level protocol
Definition flow.h:450
void * alstate
Definition flow.h:479
void * protoctx
Definition flow.h:441
uint64_t todstbytecnt
Definition flow.h:497
int64_t len
uint64_t offset
int(* Prepare)(MpmConfig *, struct MpmCtx_ *)
Definition util-mpm.h:175
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition util-mpm.h:178
void(* DestroyCtx)(struct MpmCtx_ *)
Definition util-mpm.h:154
uint8_t flowflags
Definition decode.h:532
struct Flow_ * flow
Definition decode.h:546
uint32_t flags
Definition decode.h:544
structure for storing potential rule matches
char * name
Definition conf.h:38
char * val
Definition conf.h:39
const char * enum_name
Definition util-enum.h:28
Structure for containing configuration options.
StreamingBufferConfig sbcfg
uint32_t content_inspect_min_size
uint64_t max_tx
uint32_t content_inspect_window
uint32_t content_limit
int32_t orig_len
const uint8_t * buf
int32_t consumed
const uint8_t * buf
uint8_t delim_len
uint16_t helo_len
AppLayerStateData state_data
uint8_t * helo
uint8_t current_command
uint32_t bdat_chunk_len
uint16_t cmds_buffer_len
uint64_t toserver_data_count
uint16_t cmds_idx
uint16_t cmds_cnt
bool discard_till_lf_tc
uint32_t bdat_chunk_idx
uint8_t parser_state
bool discard_till_lf_ts
uint64_t toserver_last_data_stamp
uint64_t tx_cnt
SMTPTransaction * curr_tx
uint8_t * cmds
uint32_t file_track_id
uint8_t * str
PrefilterRuleStore * pmq
MpmThreadCtx * smtp_mpm_thread_ctx
AppLayerTxData tx_data
MimeStateSMTP * mime_state
FileContainer files_ts
Signature container.
Definition detect.h:668
Per thread variable structure.
Definition threadvars.h:58
#define str(s)
int RunmodeIsUnittests(void)
Definition suricata.c:270
const char * name
uint32_t cnt
int ByteExtractStringUint32(uint32_t *res, int base, size_t len, const char *str)
Definition util-byte.c:239
#define SCEnter(...)
Definition util-debug.h:277
#define FatalError(...)
Definition util-debug.h:510
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition util-debug.h:255
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition util-debug.h:225
#define SCReturnStruct(x)
Definition util-debug.h:297
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCReturn
Definition util-debug.h:279
int SCMapEnumNameToValue(const char *enum_name, SCEnumCharMap *table)
Maps a string name to an enum value from the supplied table. Please specify the last element of any m...
Definition util-enum.c:40
const char * SCMapEnumValueToName(int enum_value, SCEnumCharMap *table)
Maps an enum value to a string name, from the supplied table.
Definition util-enum.c:68
int FileAppendData(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data, uint32_t data_len)
Store/handle a chunk of file data in the File structure The last file in the FileContainer will be us...
Definition util-file.c:766
uint64_t FileDataSize(const File *file)
get the size of the file data
Definition util-file.c:309
uint64_t FileTrackedSize(const File *file)
get the size of the file
Definition util-file.c:326
void FileContainerRecycle(FileContainer *ffc, const StreamingBufferConfig *cfg)
Recycle a FileContainer.
Definition util-file.c:496
int FileCloseFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, const uint8_t *data, uint32_t data_len, uint16_t flags)
Close a File.
Definition util-file.c:1062
void FileSetInspectSizes(File *file, const uint32_t win, const uint32_t min)
Definition util-file.c:843
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
Definition util-file.c:273
int FileOpenFileWithId(FileContainer *ffc, const StreamingBufferConfig *sbcfg, uint32_t track_id, const uint8_t *name, uint16_t name_len, const uint8_t *data, uint32_t data_len, uint16_t flags)
Open a new File.
Definition util-file.c:967
#define FILE_USE_DETECT
Definition util-file.h:58
#define SC_FILENAME_MAX
Definition util-file.h:62
#define FILE_NOMAGIC
Definition util-file.h:46
#define FILE_NOMD5
Definition util-file.h:47
@ FILE_STATE_OPENED
Definition util-file.h:70
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
#define SCRealloc(ptr, sz)
Definition util-mem.h:50
#define SCCalloc(nm, sz)
Definition util-mem.h:53
int ParseSizeStringU32(const char *size, uint32_t *res)
Definition util-misc.c:173
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition util-misc.c:190
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition util-mpm.c:47
void MpmDestroyThreadCtx(MpmThreadCtx *mpm_thread_ctx, const uint16_t matcher)
Definition util-mpm.c:202
int MpmAddPatternCI(MpmCtx *mpm_ctx, const uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags)
Definition util-mpm.c:258
void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher)
Definition util-mpm.c:195
void MpmInitCtx(MpmCtx *mpm_ctx, uint8_t matcher)
Definition util-mpm.c:209
#define unlikely(expr)
int PmqSetup(PrefilterRuleStore *pmq)
Setup a pmq.
void PmqReset(PrefilterRuleStore *pmq)
Reset a Pmq for reusage. Meant to be called after a single search.
void PmqFree(PrefilterRuleStore *pmq)
Cleanup and free a Pmq.
int StreamingBufferCompareRawData(const StreamingBuffer *sb, const uint8_t *rawdata, uint32_t rawdata_len)
uint64_t offset
#define STREAMING_BUFFER_CONFIG_INITIALIZER
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
#define DEBUG_VALIDATE_BUG_ON(exp)