suricata
app-layer-ftp.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2020 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 Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
22  * \author Eric Leblond <eric@regit.org>
23  * \author Jeff Lucovsky <jeff@lucovsky.org>
24  *
25  * App Layer Parser for FTP
26  */
27 
28 #include "suricata-common.h"
29 #include "debug.h"
30 #include "decode.h"
31 #include "threads.h"
32 
33 #include "util-print.h"
34 #include "util-pool.h"
35 
36 #include "flow-util.h"
37 #include "flow-storage.h"
38 
39 #include "detect-engine-state.h"
40 
41 #include "stream-tcp-private.h"
42 #include "stream-tcp-reassemble.h"
43 #include "stream-tcp.h"
44 #include "stream.h"
45 
46 #include "app-layer.h"
47 #include "app-layer-protos.h"
48 #include "app-layer-parser.h"
49 #include "app-layer-ftp.h"
50 #include "app-layer-expectation.h"
51 
52 #include "util-spm.h"
53 #include "util-mpm.h"
54 #include "util-unittest.h"
55 #include "util-debug.h"
56 #include "util-memcmp.h"
57 #include "util-memrchr.h"
58 #include "util-mem.h"
59 #include "util-misc.h"
60 
61 #include "output-json.h"
62 #include "rust.h"
63 
64 typedef struct FTPThreadCtx_ {
68 
69 #define FTP_MPM mpm_default_matcher
70 
71 static MpmCtx *ftp_mpm_ctx = NULL;
72 
74  /* Parsed and handled */
75  { FTP_COMMAND_PORT, "PORT", 4},
76  { FTP_COMMAND_EPRT, "EPRT", 4},
77  { FTP_COMMAND_AUTH_TLS, "AUTH TLS", 8},
78  { FTP_COMMAND_PASV, "PASV", 4},
79  { FTP_COMMAND_RETR, "RETR", 4},
80  { FTP_COMMAND_EPSV, "EPSV", 4},
81  { FTP_COMMAND_STOR, "STOR", 4},
82 
83  /* Parsed, but not handled */
84  { FTP_COMMAND_ABOR, "ABOR", 4},
85  { FTP_COMMAND_ACCT, "ACCT", 4},
86  { FTP_COMMAND_ALLO, "ALLO", 4},
87  { FTP_COMMAND_APPE, "APPE", 4},
88  { FTP_COMMAND_CDUP, "CDUP", 4},
89  { FTP_COMMAND_CHMOD, "CHMOD", 5},
90  { FTP_COMMAND_CWD, "CWD", 3},
91  { FTP_COMMAND_DELE, "DELE", 4},
92  { FTP_COMMAND_HELP, "HELP", 4},
93  { FTP_COMMAND_IDLE, "IDLE", 4},
94  { FTP_COMMAND_LIST, "LIST", 4},
95  { FTP_COMMAND_MAIL, "MAIL", 4},
96  { FTP_COMMAND_MDTM, "MDTM", 4},
97  { FTP_COMMAND_MKD, "MKD", 3},
98  { FTP_COMMAND_MLFL, "MLFL", 4},
99  { FTP_COMMAND_MODE, "MODE", 4},
100  { FTP_COMMAND_MRCP, "MRCP", 4},
101  { FTP_COMMAND_MRSQ, "MRSQ", 4},
102  { FTP_COMMAND_MSAM, "MSAM", 4},
103  { FTP_COMMAND_MSND, "MSND", 4},
104  { FTP_COMMAND_MSOM, "MSOM", 4},
105  { FTP_COMMAND_NLST, "NLST", 4},
106  { FTP_COMMAND_NOOP, "NOOP", 4},
107  { FTP_COMMAND_PASS, "PASS", 4},
108  { FTP_COMMAND_PWD, "PWD", 3},
109  { FTP_COMMAND_QUIT, "QUIT", 4},
110  { FTP_COMMAND_REIN, "REIN", 4},
111  { FTP_COMMAND_REST, "REST", 4},
112  { FTP_COMMAND_RMD, "RMD", 3},
113  { FTP_COMMAND_RNFR, "RNFR", 4},
114  { FTP_COMMAND_RNTO, "RNTO", 4},
115  { FTP_COMMAND_SITE, "SITE", 4},
116  { FTP_COMMAND_SIZE, "SIZE", 4},
117  { FTP_COMMAND_SMNT, "SMNT", 4},
118  { FTP_COMMAND_STAT, "STAT", 4},
119  { FTP_COMMAND_STOU, "STOU", 4},
120  { FTP_COMMAND_STRU, "STRU", 4},
121  { FTP_COMMAND_SYST, "SYST", 4},
122  { FTP_COMMAND_TYPE, "TYPE", 4},
123  { FTP_COMMAND_UMASK, "UMASK", 5},
124  { FTP_COMMAND_USER, "USER", 4},
125  { FTP_COMMAND_UNKNOWN, NULL, 0}
126 };
127 uint64_t ftp_config_memcap = 0;
128 
129 SC_ATOMIC_DECLARE(uint64_t, ftp_memuse);
130 SC_ATOMIC_DECLARE(uint64_t, ftp_memcap);
131 
132 static FTPTransaction *FTPGetOldestTx(FtpState *);
133 
134 static void FTPParseMemcap(void)
135 {
136  const char *conf_val;
137 
138  /** set config values for memcap, prealloc and hash_size */
139  if ((ConfGet("app-layer.protocols.ftp.memcap", &conf_val)) == 1)
140  {
141  if (ParseSizeStringU64(conf_val, &ftp_config_memcap) < 0) {
142  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing ftp.memcap "
143  "from conf file - %s. Killing engine",
144  conf_val);
145  exit(EXIT_FAILURE);
146  }
147  SCLogInfo("FTP memcap: %"PRIu64, ftp_config_memcap);
148  } else {
149  /* default to unlimited */
150  ftp_config_memcap = 0;
151  }
152 
153  SC_ATOMIC_INIT(ftp_memuse);
154  SC_ATOMIC_INIT(ftp_memcap);
155 }
156 
157 static void FTPIncrMemuse(uint64_t size)
158 {
159  (void) SC_ATOMIC_ADD(ftp_memuse, size);
160  return;
161 }
162 
163 static void FTPDecrMemuse(uint64_t size)
164 {
165  (void) SC_ATOMIC_SUB(ftp_memuse, size);
166  return;
167 }
168 
170 {
171  uint64_t tmpval = SC_ATOMIC_GET(ftp_memuse);
172  return tmpval;
173 }
174 
176 {
177  uint64_t tmpval = SC_ATOMIC_GET(ftp_memcap);
178  return tmpval;
179 }
180 
181 /**
182  * \brief Check if alloc'ing "size" would mean we're over memcap
183  *
184  * \retval 1 if in bounds
185  * \retval 0 if not in bounds
186  */
187 static int FTPCheckMemcap(uint64_t size)
188 {
189  if (ftp_config_memcap == 0 || size + SC_ATOMIC_GET(ftp_memuse) <= ftp_config_memcap)
190  return 1;
191  (void) SC_ATOMIC_ADD(ftp_memcap, 1);
192  return 0;
193 }
194 
195 static void *FTPMalloc(size_t size)
196 {
197  void *ptr = NULL;
198 
199  if (FTPCheckMemcap((uint32_t)size) == 0)
200  return NULL;
201 
202  ptr = SCMalloc(size);
203 
204  if (unlikely(ptr == NULL))
205  return NULL;
206 
207  FTPIncrMemuse((uint64_t)size);
208 
209  return ptr;
210 }
211 
212 static void *FTPCalloc(size_t n, size_t size)
213 {
214  if (FTPCheckMemcap((uint32_t)(n * size)) == 0)
215  return NULL;
216 
217  void *ptr = SCCalloc(n, size);
218 
219  if (unlikely(ptr == NULL))
220  return NULL;
221 
222  FTPIncrMemuse((uint64_t)(n * size));
223  return ptr;
224 }
225 
226 static void *FTPRealloc(void *ptr, size_t orig_size, size_t size)
227 {
228  void *rptr = NULL;
229 
230  if (FTPCheckMemcap((uint32_t)(size - orig_size)) == 0)
231  return NULL;
232 
233  rptr = SCRealloc(ptr, size);
234  if (rptr == NULL)
235  return NULL;
236 
237  if (size > orig_size) {
238  FTPIncrMemuse(size - orig_size);
239  } else {
240  FTPDecrMemuse(orig_size - size);
241  }
242 
243  return rptr;
244 }
245 
246 static void FTPFree(void *ptr, size_t size)
247 {
248  SCFree(ptr);
249 
250  FTPDecrMemuse((uint64_t)size);
251 }
252 
253 static FTPString *FTPStringAlloc(void)
254 {
255  return FTPCalloc(1, sizeof(FTPString));
256 }
257 
258 static void FTPStringFree(FTPString *str)
259 {
260  if (str->str) {
261  FTPFree(str->str, str->len);
262  }
263 
264  FTPFree(str, sizeof(FTPString));
265 }
266 
267 static void *FTPLocalStorageAlloc(void)
268 {
269  /* needed by the mpm */
270  FTPThreadCtx *td = SCCalloc(1, sizeof(*td));
271  if (td == NULL) {
272  exit(EXIT_FAILURE);
273  }
274 
275  td->pmq = SCCalloc(1, sizeof(*td->pmq));
276  if (td->pmq == NULL) {
277  exit(EXIT_FAILURE);
278  }
279  PmqSetup(td->pmq);
280 
281  td->ftp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx));
282  if (unlikely(td->ftp_mpm_thread_ctx == NULL)) {
283  exit(EXIT_FAILURE);
284  }
286  return td;
287 }
288 
289 static void FTPLocalStorageFree(void *ptr)
290 {
291  FTPThreadCtx *td = ptr;
292  if (td != NULL) {
293  if (td->pmq != NULL) {
294  PmqFree(td->pmq);
295  SCFree(td->pmq);
296  }
297 
298  if (td->ftp_mpm_thread_ctx != NULL) {
301  }
302 
303  SCFree(td);
304  }
305 
306  return;
307 }
308 static FTPTransaction *FTPTransactionCreate(FtpState *state)
309 {
310  SCEnter();
311  FTPTransaction *tx = FTPCalloc(1, sizeof(*tx));
312  if (tx == NULL) {
313  return NULL;
314  }
315 
316  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
317  tx->tx_id = state->tx_cnt++;
318 
319  TAILQ_INIT(&tx->response_list);
320 
321  SCLogDebug("new transaction %p (state tx cnt %"PRIu64")", tx, state->tx_cnt);
322  return tx;
323 }
324 
325 static void FTPTransactionFree(FTPTransaction *tx)
326 {
327  SCEnter();
328 
329  if (tx->de_state != NULL) {
331  }
332 
333  if (tx->request) {
334  FTPFree(tx->request, tx->request_length);
335  }
336 
337  FTPString *str = NULL;
338  while ((str = TAILQ_FIRST(&tx->response_list))) {
339  TAILQ_REMOVE(&tx->response_list, str, next);
340  FTPStringFree(str);
341  }
342 
343  FTPFree(tx, sizeof(*tx));
344 }
345 
346 static int FTPGetLineForDirection(FtpState *state, FtpLineState *line_state)
347 {
348  void *ptmp;
349  if (line_state->current_line_lf_seen == 1) {
350  /* we have seen the lf for the previous line. Clear the parser
351  * details to parse new line */
352  line_state->current_line_lf_seen = 0;
353  if (line_state->current_line_db == 1) {
354  line_state->current_line_db = 0;
355  FTPFree(line_state->db, line_state->db_len);
356  line_state->db = NULL;
357  line_state->db_len = 0;
358  state->current_line = NULL;
359  state->current_line_len = 0;
360  }
361  }
362 
363  uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
364 
365  if (lf_idx == NULL) {
366  /* fragmented lines. Decoder event for special cases. Not all
367  * fragmented lines should be treated as a possible evasion
368  * attempt. With multi payload ftp chunks we can have valid
369  * cases of fragmentation. But within the same segment chunk
370  * if we see fragmentation then it's definitely something you
371  * should alert about */
372  if (line_state->current_line_db == 0) {
373  line_state->db = FTPMalloc(state->input_len);
374  if (line_state->db == NULL) {
375  return -1;
376  }
377  line_state->current_line_db = 1;
378  memcpy(line_state->db, state->input, state->input_len);
379  line_state->db_len = state->input_len;
380  } else {
381  ptmp = FTPRealloc(line_state->db, line_state->db_len,
382  (line_state->db_len + state->input_len));
383  if (ptmp == NULL) {
384  FTPFree(line_state->db, line_state->db_len);
385  line_state->db = NULL;
386  line_state->db_len = 0;
387  return -1;
388  }
389  line_state->db = ptmp;
390 
391  memcpy(line_state->db + line_state->db_len,
392  state->input, state->input_len);
393  line_state->db_len += state->input_len;
394  }
395  state->input += state->input_len;
396  state->input_len = 0;
397 
398  return -1;
399 
400  } else {
401  line_state->current_line_lf_seen = 1;
402 
403  if (line_state->current_line_db == 1) {
404  ptmp = FTPRealloc(line_state->db, line_state->db_len,
405  (line_state->db_len + (lf_idx + 1 - state->input)));
406  if (ptmp == NULL) {
407  FTPFree(line_state->db, line_state->db_len);
408  line_state->db = NULL;
409  line_state->db_len = 0;
410  return -1;
411  }
412  line_state->db = ptmp;
413 
414  memcpy(line_state->db + line_state->db_len,
415  state->input, (lf_idx + 1 - state->input));
416  line_state->db_len += (lf_idx + 1 - state->input);
417 
418  if (line_state->db_len > 1 &&
419  line_state->db[line_state->db_len - 2] == 0x0D) {
420  line_state->db_len -= 2;
421  state->current_line_delimiter_len = 2;
422  } else {
423  line_state->db_len -= 1;
424  state->current_line_delimiter_len = 1;
425  }
426 
427  state->current_line = line_state->db;
428  state->current_line_len = line_state->db_len;
429 
430  } else {
431  state->current_line = state->input;
432  state->current_line_len = lf_idx - state->input;
433 
434  if (state->input != lf_idx &&
435  *(lf_idx - 1) == 0x0D) {
436  state->current_line_len--;
437  state->current_line_delimiter_len = 2;
438  } else {
439  state->current_line_delimiter_len = 1;
440  }
441  }
442 
443  state->input_len -= (lf_idx - state->input) + 1;
444  state->input = (lf_idx + 1);
445 
446  return 0;
447  }
448 
449 }
450 
451 static int FTPGetLine(FtpState *state)
452 {
453  SCEnter();
454 
455  /* we have run out of input */
456  if (state->input_len <= 0)
457  return -1;
458 
459  /* toserver */
460  if (state->direction == 0)
461  return FTPGetLineForDirection(state, &state->line_state[0]);
462  else
463  return FTPGetLineForDirection(state, &state->line_state[1]);
464 }
465 
466 /**
467  * \brief This function is called to determine and set which command is being
468  * transferred to the ftp server
469  * \param thread context
470  * \param input input line of the command
471  * \param len of the command
472  * \param cmd_descriptor when the command has been parsed
473  *
474  * \retval 1 when the command is parsed, 0 otherwise
475  */
476 static int FTPParseRequestCommand(FTPThreadCtx *td,
477  const uint8_t *input, uint32_t input_len,
478  const FtpCommand **cmd_descriptor)
479 {
480  SCEnter();
481 
482  /* I don't like this pmq reset here. We'll devise a method later, that
483  * should make the use of the mpm very efficient */
484  PmqReset(td->pmq);
485  int mpm_cnt = mpm_table[FTP_MPM].Search(ftp_mpm_ctx, td->ftp_mpm_thread_ctx,
486  td->pmq, input, input_len);
487  if (mpm_cnt) {
488  *cmd_descriptor = &FtpCommands[td->pmq->rule_id_array[0]];
489  SCReturnInt(1);
490  }
491 
492  *cmd_descriptor = NULL;
493  SCReturnInt(0);
494 }
495 
497  /** Need to look like a ExpectationData so DFree must
498  * be first field . */
499  void (*DFree)(void *);
500  uint64_t flow_id;
501  uint8_t *file_name;
502  uint16_t file_len;
504 };
505 
506 static void FtpTransferCmdFree(void *data)
507 {
508  struct FtpTransferCmd *cmd = (struct FtpTransferCmd *) data;
509  if (cmd == NULL)
510  return;
511  if (cmd->file_name) {
512  FTPFree(cmd->file_name, cmd->file_len + 1);
513  }
514  FTPFree(cmd, sizeof(struct FtpTransferCmd));
515 }
516 
517 static uint32_t CopyCommandLine(uint8_t **dest, const uint8_t *src, uint32_t length)
518 {
519  if (likely(length)) {
520  uint8_t *where = FTPCalloc(length + 1, sizeof(char));
521  if (unlikely(where == NULL)) {
522  return 0;
523  }
524  memcpy(where, src, length);
525 
526  /* Remove trailing newlines/carriage returns */
527  while (length && isspace((unsigned char) where[length - 1])) {
528  length--;
529  }
530 
531  where[length] = '\0';
532  *dest = where;
533  }
534  /* either 0 or actual */
535  return length ? length + 1 : 0;
536 }
537 
538 
539 /**
540  * \brief This function is called to retrieve a ftp request
541  * \param ftp_state the ftp state structure for the parser
542  * \param input input line of the command
543  * \param input_len length of the request
544  * \param output the resulting output
545  *
546  * \retval APP_LAYER_OK when input was process successfully
547  * \retval APP_LAYER_ERROR when a unrecoverable error was encountered
548  */
549 static AppLayerResult FTPParseRequest(Flow *f, void *ftp_state,
550  AppLayerParserState *pstate,
551  const uint8_t *input, uint32_t input_len,
552  void *local_data, const uint8_t flags)
553 {
554  FTPThreadCtx *thread_data = local_data;
555 
556  SCEnter();
557  /* PrintRawDataFp(stdout, input,input_len); */
558 
559  FtpState *state = (FtpState *)ftp_state;
560  void *ptmp;
561 
562  if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) {
564  } else if (input == NULL || input_len == 0) {
566  }
567 
568  state->input = input;
569  state->input_len = input_len;
570  /* toserver stream */
571  state->direction = 0;
572 
573  int direction = STREAM_TOSERVER;
574  while (FTPGetLine(state) >= 0) {
575  const FtpCommand *cmd_descriptor;
576 
577  if (!FTPParseRequestCommand(thread_data,
578  state->current_line, state->current_line_len,
579  &cmd_descriptor)) {
580  state->command = FTP_COMMAND_UNKNOWN;
581  continue;
582  }
583 
584  state->command = cmd_descriptor->command;
585 
586  FTPTransaction *tx = FTPTransactionCreate(state);
587  if (unlikely(tx == NULL))
589  state->curr_tx = tx;
590 
591  tx->command_descriptor = cmd_descriptor;
592  tx->request_length = CopyCommandLine(&tx->request,
593  state->current_line, state->current_line_len);
594 
595  /* change direction (default to server) so expectation will handle
596  * the correct message when expectation will match.
597  * For ftp active mode, data connection direction is opposite to
598  * control direction.
599  */
600  if ((state->active && state->command == FTP_COMMAND_STOR) ||
601  (!state->active && state->command == FTP_COMMAND_RETR)) {
602  direction = STREAM_TOCLIENT;
603  }
604 
605  switch (state->command) {
606  case FTP_COMMAND_EPRT:
607  // fallthrough
608  case FTP_COMMAND_PORT:
609  if (state->current_line_len + 1 > state->port_line_size) {
610  /* Allocate an extra byte for a NULL terminator */
611  ptmp = FTPRealloc(state->port_line, state->port_line_size,
612  state->current_line_len);
613  if (ptmp == NULL) {
614  if (state->port_line) {
615  FTPFree(state->port_line, state->port_line_size);
616  state->port_line = NULL;
617  state->port_line_size = 0;
618  }
620  }
621  state->port_line = ptmp;
622  state->port_line_size = state->current_line_len;
623  }
624  memcpy(state->port_line, state->current_line,
625  state->current_line_len);
626  state->port_line_len = state->current_line_len;
627  break;
628  case FTP_COMMAND_RETR:
629  // fallthrough
630  case FTP_COMMAND_STOR: {
631  /* Ensure that there is a negotiated dyn port and a file
632  * name -- need more than 5 chars: cmd [4], space, <filename>
633  */
634  if (state->dyn_port == 0 || state->current_line_len < 6) {
636  }
637  struct FtpTransferCmd *data = FTPCalloc(1, sizeof(struct FtpTransferCmd));
638  if (data == NULL)
640  data->DFree = FtpTransferCmdFree;
641  /*
642  * Min size has been checked in FTPParseRequestCommand
643  * PATH_MAX includes the null
644  */
645  int file_name_len = MIN(PATH_MAX - 1, state->current_line_len - 5);
646  data->file_name = FTPCalloc(file_name_len + 1, sizeof(char));
647  if (data->file_name == NULL) {
648  FtpTransferCmdFree(data);
650  }
651  data->file_name[file_name_len] = 0;
652  data->file_len = file_name_len;
653  memcpy(data->file_name, state->current_line + 5, file_name_len);
654  data->cmd = state->command;
655  data->flow_id = FlowGetId(f);
656  int ret = AppLayerExpectationCreate(f, direction,
657  0, state->dyn_port, ALPROTO_FTPDATA, data);
658  if (ret == -1) {
659  FtpTransferCmdFree(data);
660  SCLogDebug("No expectation created.");
662  } else {
663  SCLogDebug("Expectation created [direction: %s, dynamic port %"PRIu16"].",
664  state->active ? "to server" : "to client",
665  state->dyn_port);
666  }
667 
668  /* reset the dyn port to avoid duplicate */
669  state->dyn_port = 0;
670  /* reset active/passive indicator */
671  state->active = false;
672  }
673  break;
674  default:
675  break;
676  }
677  }
678 
680 }
681 
682 static int FTPParsePassiveResponse(Flow *f, FtpState *state, const uint8_t *input, uint32_t input_len)
683 {
684  uint16_t dyn_port = rs_ftp_pasv_response(input, input_len);
685  if (dyn_port == 0) {
686  return -1;
687  }
688  SCLogDebug("FTP passive mode (v4): dynamic port %"PRIu16"", dyn_port);
689  state->active = false;
690  state->dyn_port = dyn_port;
691  state->curr_tx->dyn_port = dyn_port;
692  state->curr_tx->active = false;
693 
694  return 0;
695 }
696 
697 static int FTPParsePassiveResponseV6(Flow *f, FtpState *state, const uint8_t *input, uint32_t input_len)
698 {
699  uint16_t dyn_port = rs_ftp_epsv_response(input, input_len);
700  if (dyn_port == 0) {
701  return -1;
702  }
703  SCLogDebug("FTP passive mode (v6): dynamic port %"PRIu16"", dyn_port);
704  state->active = false;
705  state->dyn_port = dyn_port;
706  state->curr_tx->dyn_port = dyn_port;
707  state->curr_tx->active = false;
708  return 0;
709 }
710 
711 /**
712  * \brief Handle preliminary replies -- keep tx open
713  * \retval bool True for a positive preliminary reply; false otherwise
714  *
715  * 1yz Positive Preliminary reply
716  *
717  * The requested action is being initiated; expect another
718  * reply before proceeding with a new command
719  */
720 static inline bool FTPIsPPR(const uint8_t *input, uint32_t input_len)
721 {
722  return input_len >= 4 && isdigit(input[0]) && input[0] == '1' &&
723  isdigit(input[1]) && isdigit(input[2]) && isspace(input[3]);
724 }
725 
726 /**
727  * \brief This function is called to retrieve a ftp response
728  * \param ftp_state the ftp state structure for the parser
729  * \param input input line of the command
730  * \param input_len length of the request
731  * \param output the resulting output
732  *
733  * \retval 1 when the command is parsed, 0 otherwise
734  */
735 static AppLayerResult FTPParseResponse(Flow *f, void *ftp_state, AppLayerParserState *pstate,
736  const uint8_t *input, uint32_t input_len,
737  void *local_data, const uint8_t flags)
738 {
739  FtpState *state = (FtpState *)ftp_state;
740 
741  if (unlikely(input_len == 0)) {
743  }
744  state->input = input;
745  state->input_len = input_len;
746  /* toclient stream */
747  state->direction = 1;
748 
749  while (FTPGetLine(state) >= 0) {
750  FTPTransaction *tx = FTPGetOldestTx(state);
751  if (tx == NULL) {
752  tx = FTPTransactionCreate(state);
753  }
754  if (unlikely(tx == NULL)) {
756  }
757  if (state->command == FTP_COMMAND_UNKNOWN || tx->command_descriptor == NULL) {
758  /* unknown */
760  }
761 
762  state->curr_tx = tx;
763  uint16_t dyn_port;
764  switch (state->command) {
766  if (state->current_line_len >= 4 && SCMemcmp("234 ", state->current_line, 4) == 0) {
768  }
769  break;
770 
771  case FTP_COMMAND_EPRT:
772  dyn_port = rs_ftp_active_eprt(state->port_line, state->port_line_len);
773  if (dyn_port == 0) {
774  goto tx_complete;
775  }
776  state->dyn_port = dyn_port;
777  state->active = true;
778  tx->dyn_port = dyn_port;
779  tx->active = true;
780  SCLogDebug("FTP active mode (v6): dynamic port %"PRIu16"", dyn_port);
781  break;
782 
783  case FTP_COMMAND_PORT:
784  dyn_port = rs_ftp_active_port(state->port_line, state->port_line_len);
785  if (dyn_port == 0) {
786  goto tx_complete;
787  }
788  state->dyn_port = dyn_port;
789  state->active = true;
790  tx->dyn_port = state->dyn_port;
791  tx->active = true;
792  SCLogDebug("FTP active mode (v4): dynamic port %"PRIu16"", dyn_port);
793  break;
794 
795  case FTP_COMMAND_PASV:
796  if (state->current_line_len >= 4 && SCMemcmp("227 ", state->current_line, 4) == 0) {
797  FTPParsePassiveResponse(f, ftp_state, state->current_line, state->current_line_len);
798  }
799  break;
800 
801  case FTP_COMMAND_EPSV:
802  if (state->current_line_len >= 4 && SCMemcmp("229 ", state->current_line, 4) == 0) {
803  FTPParsePassiveResponseV6(f, ftp_state, state->current_line, state->current_line_len);
804  }
805  break;
806  default:
807  break;
808  }
809 
810  if (likely(state->current_line_len)) {
811  FTPString *response = FTPStringAlloc();
812  if (likely(response)) {
813  response->len = CopyCommandLine(&response->str, state->current_line, state->current_line_len);
814  TAILQ_INSERT_TAIL(&tx->response_list, response, next);
815  }
816  }
817 
818  /* Handle preliminary replies -- keep tx open */
819  if (FTPIsPPR(state->current_line, state->current_line_len)) {
820  continue;
821  }
822  tx_complete:
823  tx->done = true;
824  }
825 
827 }
828 
829 
830 #ifdef DEBUG
831 static SCMutex ftp_state_mem_lock = SCMUTEX_INITIALIZER;
832 static uint64_t ftp_state_memuse = 0;
833 static uint64_t ftp_state_memcnt = 0;
834 #endif
835 
836 static void *FTPStateAlloc(void *orig_state, AppProto proto_orig)
837 {
838  void *s = FTPCalloc(1, sizeof(FtpState));
839  if (unlikely(s == NULL))
840  return NULL;
841 
842  FtpState *ftp_state = (FtpState *) s;
843  TAILQ_INIT(&ftp_state->tx_list);
844 
845 #ifdef DEBUG
846  SCMutexLock(&ftp_state_mem_lock);
847  ftp_state_memcnt++;
848  ftp_state_memuse+=sizeof(FtpState);
849  SCMutexUnlock(&ftp_state_mem_lock);
850 #endif
851  return s;
852 }
853 
854 static void FTPStateFree(void *s)
855 {
856  FtpState *fstate = (FtpState *) s;
857  if (fstate->port_line != NULL)
858  FTPFree(fstate->port_line, fstate->port_line_size);
859  if (fstate->line_state[0].db)
860  FTPFree(fstate->line_state[0].db, fstate->line_state[0].db_len);
861  if (fstate->line_state[1].db)
862  FTPFree(fstate->line_state[1].db, fstate->line_state[1].db_len);
863 
864  //AppLayerDecoderEventsFreeEvents(&s->decoder_events);
865 
866  FTPTransaction *tx = NULL;
867  while ((tx = TAILQ_FIRST(&fstate->tx_list))) {
868  TAILQ_REMOVE(&fstate->tx_list, tx, next);
869  SCLogDebug("[%s] state %p id %"PRIu64", Freeing %d bytes at %p",
871  s, tx->tx_id,
872  tx->request_length, tx->request);
873  FTPTransactionFree(tx);
874  }
875 
876  FTPFree(s, sizeof(FtpState));
877 #ifdef DEBUG
878  SCMutexLock(&ftp_state_mem_lock);
879  ftp_state_memcnt--;
880  ftp_state_memuse-=sizeof(FtpState);
881  SCMutexUnlock(&ftp_state_mem_lock);
882 #endif
883 }
884 
885 static int FTPSetTxDetectState(void *vtx, DetectEngineState *de_state)
886 {
887  FTPTransaction *tx = (FTPTransaction *)vtx;
888  tx->de_state = de_state;
889  return 0;
890 }
891 
892 /**
893  * \brief This function returns the oldest open transaction; if none
894  * are open, then the oldest transaction is returned
895  * \param ftp_state the ftp state structure for the parser
896  *
897  * \retval transaction pointer when a transaction was found; NULL otherwise.
898  */
899 static FTPTransaction *FTPGetOldestTx(FtpState *ftp_state)
900 {
901  if (unlikely(!ftp_state)) {
902  SCLogDebug("NULL state object; no transactions available");
903  return NULL;
904  }
905  FTPTransaction *tx = NULL;
906  FTPTransaction *lasttx = NULL;
907  TAILQ_FOREACH(tx, &ftp_state->tx_list, next) {
908  /* Return oldest open tx */
909  if (!tx->done) {
910  SCLogDebug("Returning tx %p id %"PRIu64, tx, tx->tx_id);
911  return tx;
912  }
913  /* save for the end */
914  lasttx = tx;
915  }
916  /* All tx are closed; return last element */
917  if (lasttx)
918  SCLogDebug("Returning OLDEST tx %p id %"PRIu64, lasttx, lasttx->tx_id);
919  return lasttx;
920 }
921 
922 static void *FTPGetTx(void *state, uint64_t tx_id)
923 {
924  FtpState *ftp_state = (FtpState *)state;
925  if (ftp_state) {
926  FTPTransaction *tx = NULL;
927 
928  if (ftp_state->curr_tx == NULL)
929  return NULL;
930  if (ftp_state->curr_tx->tx_id == tx_id)
931  return ftp_state->curr_tx;
932 
933  TAILQ_FOREACH(tx, &ftp_state->tx_list, next) {
934  if (tx->tx_id == tx_id)
935  return tx;
936  }
937  }
938  return NULL;
939 }
940 
941 static DetectEngineState *FTPGetTxDetectState(void *vtx)
942 {
943  FTPTransaction *tx = (FTPTransaction *)vtx;
944  return tx->de_state;
945 }
946 
947 
948 static AppLayerTxData *FTPGetTxData(void *vtx)
949 {
950  FTPTransaction *tx = (FTPTransaction *)vtx;
951  return &tx->tx_data;
952 }
953 
954 static void FTPStateTransactionFree(void *state, uint64_t tx_id)
955 {
956  FtpState *ftp_state = state;
957  FTPTransaction *tx = NULL;
958  TAILQ_FOREACH(tx, &ftp_state->tx_list, next) {
959  if (tx_id < tx->tx_id)
960  break;
961  else if (tx_id > tx->tx_id)
962  continue;
963 
964  if (tx == ftp_state->curr_tx)
965  ftp_state->curr_tx = NULL;
966  TAILQ_REMOVE(&ftp_state->tx_list, tx, next);
967  FTPTransactionFree(tx);
968  break;
969  }
970 }
971 
972 static uint64_t FTPGetTxCnt(void *state)
973 {
974  uint64_t cnt = 0;
975  FtpState *ftp_state = state;
976  if (ftp_state) {
977  cnt = ftp_state->tx_cnt;
978  }
979  SCLogDebug("returning state %p %"PRIu64, state, cnt);
980  return cnt;
981 }
982 
983 static int FTPGetAlstateProgressCompletionStatus(uint8_t direction)
984 {
985  return FTP_STATE_FINISHED;
986 }
987 
988 static int FTPGetAlstateProgress(void *vtx, uint8_t direction)
989 {
990  SCLogDebug("tx %p", vtx);
991  FTPTransaction *tx = vtx;
992 
993  if (!tx->done) {
994  if (direction == STREAM_TOSERVER &&
996  return FTP_STATE_PORT_DONE;
997  }
998  return FTP_STATE_IN_PROGRESS;
999  }
1000 
1001  return FTP_STATE_FINISHED;
1002 }
1003 
1004 
1005 static int FTPRegisterPatternsForProtocolDetection(void)
1006 {
1008  "220 (", 5, 0, STREAM_TOCLIENT) < 0)
1009  {
1010  return -1;
1011  }
1013  "FEAT", 4, 0, STREAM_TOSERVER) < 0)
1014  {
1015  return -1;
1016  }
1018  "USER ", 5, 0, STREAM_TOSERVER) < 0)
1019  {
1020  return -1;
1021  }
1023  "PASS ", 5, 0, STREAM_TOSERVER) < 0)
1024  {
1025  return -1;
1026  }
1028  "PORT ", 5, 0, STREAM_TOSERVER) < 0)
1029  {
1030  return -1;
1031  }
1032 
1033  return 0;
1034 }
1035 
1036 
1038 
1039 /**
1040  * \brief This function is called to retrieve a ftp request
1041  * \param ftp_state the ftp state structure for the parser
1042  * \param input input line of the command
1043  * \param input_len length of the request
1044  * \param output the resulting output
1045  *
1046  * \retval 1 when the command is parsed, 0 otherwise
1047  */
1048 static AppLayerResult FTPDataParse(Flow *f, FtpDataState *ftpdata_state,
1049  AppLayerParserState *pstate,
1050  const uint8_t *input, uint32_t input_len,
1051  void *local_data, int direction)
1052 {
1053  uint16_t flags = FileFlowToFlags(f, direction);
1054  int ret = 0;
1055  /* we depend on detection engine for file pruning */
1057  if (ftpdata_state->files == NULL) {
1059  if (data == NULL) {
1061  }
1062 
1063  ftpdata_state->files = FileContainerAlloc();
1064  if (ftpdata_state->files == NULL) {
1067  }
1068 
1069  ftpdata_state->file_name = data->file_name;
1070  ftpdata_state->file_len = data->file_len;
1071  data->file_name = NULL;
1072  data->file_len = 0;
1073  f->parent_id = data->flow_id;
1074  ftpdata_state->command = data->cmd;
1075  switch (data->cmd) {
1076  case FTP_COMMAND_STOR:
1077  ftpdata_state->direction = STREAM_TOSERVER;
1078  break;
1079  case FTP_COMMAND_RETR:
1080  ftpdata_state->direction = STREAM_TOCLIENT;
1081  break;
1082  default:
1083  break;
1084  }
1085 
1086  /* open with fixed track_id 0 as we can have just one
1087  * file per ftp-data flow. */
1088  if (FileOpenFileWithId(ftpdata_state->files, &sbcfg,
1089  0ULL, (uint8_t *) ftpdata_state->file_name,
1090  ftpdata_state->file_len,
1091  input, input_len, flags) != 0) {
1092  SCLogDebug("Can't open file");
1093  ret = -1;
1094  }
1096  } else {
1097  if (input_len != 0) {
1098  ret = FileAppendData(ftpdata_state->files, input, input_len);
1099  if (ret == -2) {
1100  ret = 0;
1101  SCLogDebug("FileAppendData() - file no longer being extracted");
1102  goto out;
1103  } else if (ret < 0) {
1104  SCLogDebug("FileAppendData() failed: %d", ret);
1105  ret = -2;
1106  goto out;
1107  }
1108  } else {
1109  ret = FileCloseFile(ftpdata_state->files, NULL, 0, flags);
1110  ftpdata_state->state = FTPDATA_STATE_FINISHED;
1111  if (ret < 0)
1112  goto out;
1113  }
1114  }
1115 
1116  const bool eof_flag = flags & STREAM_TOSERVER ?
1119  if (input_len && eof_flag) {
1120  ret = FileCloseFile(ftpdata_state->files, (uint8_t *) NULL, 0, flags);
1121  ftpdata_state->state = FTPDATA_STATE_FINISHED;
1122  }
1123 
1124 out:
1125  if (ret < 0) {
1127  }
1129 }
1130 
1131 static AppLayerResult FTPDataParseRequest(Flow *f, void *ftp_state,
1132  AppLayerParserState *pstate,
1133  const uint8_t *input, uint32_t input_len,
1134  void *local_data, const uint8_t flags)
1135 {
1136  return FTPDataParse(f, ftp_state, pstate, input, input_len,
1137  local_data, STREAM_TOSERVER);
1138 }
1139 
1140 static AppLayerResult FTPDataParseResponse(Flow *f, void *ftp_state,
1141  AppLayerParserState *pstate,
1142  const uint8_t *input, uint32_t input_len,
1143  void *local_data, const uint8_t flags)
1144 {
1145  return FTPDataParse(f, ftp_state, pstate, input, input_len,
1146  local_data, STREAM_TOCLIENT);
1147 }
1148 
1149 #ifdef DEBUG
1150 static SCMutex ftpdata_state_mem_lock = SCMUTEX_INITIALIZER;
1151 static uint64_t ftpdata_state_memuse = 0;
1152 static uint64_t ftpdata_state_memcnt = 0;
1153 #endif
1154 
1155 static void *FTPDataStateAlloc(void *orig_state, AppProto proto_orig)
1156 {
1157  void *s = FTPCalloc(1, sizeof(FtpDataState));
1158  if (unlikely(s == NULL))
1159  return NULL;
1160 
1161  FtpDataState *state = (FtpDataState *) s;
1163 
1164 #ifdef DEBUG
1165  SCMutexLock(&ftpdata_state_mem_lock);
1166  ftpdata_state_memcnt++;
1167  ftpdata_state_memuse+=sizeof(FtpDataState);
1168  SCMutexUnlock(&ftpdata_state_mem_lock);
1169 #endif
1170  return s;
1171 }
1172 
1173 static void FTPDataStateFree(void *s)
1174 {
1175  FtpDataState *fstate = (FtpDataState *) s;
1176 
1177  if (fstate->de_state != NULL) {
1179  }
1180  if (fstate->file_name != NULL) {
1181  FTPFree(fstate->file_name, fstate->file_len + 1);
1182  }
1183 
1184  FileContainerFree(fstate->files);
1185 
1186  FTPFree(s, sizeof(FtpDataState));
1187 #ifdef DEBUG
1188  SCMutexLock(&ftpdata_state_mem_lock);
1189  ftpdata_state_memcnt--;
1190  ftpdata_state_memuse-=sizeof(FtpDataState);
1191  SCMutexUnlock(&ftpdata_state_mem_lock);
1192 #endif
1193 }
1194 
1195 static int FTPDataSetTxDetectState(void *vtx, DetectEngineState *de_state)
1196 {
1197  FtpDataState *ftp_state = (FtpDataState *)vtx;
1198  ftp_state->de_state = de_state;
1199  return 0;
1200 }
1201 
1202 static DetectEngineState *FTPDataGetTxDetectState(void *vtx)
1203 {
1204  FtpDataState *ftp_state = (FtpDataState *)vtx;
1205  return ftp_state->de_state;
1206 }
1207 
1208 static AppLayerTxData *FTPDataGetTxData(void *vtx)
1209 {
1210  FtpDataState *ftp_state = (FtpDataState *)vtx;
1211  return &ftp_state->tx_data;
1212 }
1213 
1214 static void FTPDataStateTransactionFree(void *state, uint64_t tx_id)
1215 {
1216  /* do nothing */
1217 }
1218 
1219 static void *FTPDataGetTx(void *state, uint64_t tx_id)
1220 {
1221  FtpDataState *ftp_state = (FtpDataState *)state;
1222  return ftp_state;
1223 }
1224 
1225 static uint64_t FTPDataGetTxCnt(void *state)
1226 {
1227  /* ftp-data is single tx */
1228  return 1;
1229 }
1230 
1231 static int FTPDataGetAlstateProgressCompletionStatus(uint8_t direction)
1232 {
1233  return FTPDATA_STATE_FINISHED;
1234 }
1235 
1236 static int FTPDataGetAlstateProgress(void *tx, uint8_t direction)
1237 {
1238  FtpDataState *ftpdata_state = (FtpDataState *)tx;
1239  return ftpdata_state->state;
1240 }
1241 
1242 static FileContainer *FTPDataStateGetFiles(void *state, uint8_t direction)
1243 {
1244  FtpDataState *ftpdata_state = (FtpDataState *)state;
1245 
1246  if (direction != ftpdata_state->direction)
1247  SCReturnPtr(NULL, "FileContainer");
1248 
1249  SCReturnPtr(ftpdata_state->files, "FileContainer");
1250 }
1251 
1252 static void FTPSetMpmState(void)
1253 {
1254  ftp_mpm_ctx = SCMalloc(sizeof(MpmCtx));
1255  if (unlikely(ftp_mpm_ctx == NULL)) {
1256  exit(EXIT_FAILURE);
1257  }
1258  memset(ftp_mpm_ctx, 0, sizeof(MpmCtx));
1259  MpmInitCtx(ftp_mpm_ctx, FTP_MPM);
1260 
1261  uint32_t i = 0;
1262  for (i = 0; i < sizeof(FtpCommands)/sizeof(FtpCommand) - 1; i++) {
1263  const FtpCommand *cmd = &FtpCommands[i];
1264  if (cmd->command_length == 0)
1265  continue;
1266 
1267  MpmAddPatternCI(ftp_mpm_ctx,
1268  (uint8_t *)cmd->command_name,
1269  cmd->command_length,
1270  0 /* defunct */, 0 /* defunct */,
1271  i /* id */, i /* rule id */ , 0 /* no flags */);
1272  }
1273 
1274  mpm_table[FTP_MPM].Prepare(ftp_mpm_ctx);
1275 
1276 }
1277 
1278 static void FTPFreeMpmState(void)
1279 {
1280  if (ftp_mpm_ctx != NULL) {
1281  mpm_table[FTP_MPM].DestroyCtx(ftp_mpm_ctx);
1282  SCFree(ftp_mpm_ctx);
1283  ftp_mpm_ctx = NULL;
1284  }
1285 }
1286 
1288 {
1289  const char *proto_name = "ftp";
1290  const char *proto_data_name = "ftp-data";
1291 
1292  /** FTP */
1293  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
1295  if (FTPRegisterPatternsForProtocolDetection() < 0 )
1296  return;
1298  }
1299 
1300  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
1302  FTPParseRequest);
1304  FTPParseResponse);
1305  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTP, FTPStateAlloc, FTPStateFree);
1307 
1308  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTP, FTPStateTransactionFree);
1309 
1311  FTPGetTxDetectState, FTPSetTxDetectState);
1312 
1313  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTP, FTPGetTx);
1314  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxData);
1315 
1316  AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_FTP, FTPLocalStorageAlloc,
1317  FTPLocalStorageFree);
1318  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxCnt);
1319 
1320  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetAlstateProgress);
1321 
1323  FTPGetAlstateProgressCompletionStatus);
1324 
1325 
1328  FTPDataParseRequest);
1330  FTPDataParseResponse);
1331  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateAlloc, FTPDataStateFree);
1333  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateTransactionFree);
1335  FTPDataGetTxDetectState, FTPDataSetTxDetectState);
1336 
1337  AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateGetFiles);
1338 
1339  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTx);
1340  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTxData);
1341 
1342  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTxCnt);
1343 
1344  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetAlstateProgress);
1345 
1347  FTPDataGetAlstateProgressCompletionStatus);
1348 
1349  sbcfg.buf_size = 4096;
1350  sbcfg.Malloc = FTPMalloc;
1351  sbcfg.Calloc = FTPCalloc;
1352  sbcfg.Realloc = FTPRealloc;
1353  sbcfg.Free = FTPFree;
1354 
1355  FTPParseMemcap();
1356  } else {
1357  SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
1358  "still on.", proto_name);
1359  }
1360 
1361  FTPSetMpmState();
1362 
1363 #ifdef UNITTESTS
1365 #endif
1366 }
1367 
1369 {
1370 #ifdef DEBUG
1371  SCMutexLock(&ftp_state_mem_lock);
1372  SCLogDebug("ftp_state_memcnt %"PRIu64", ftp_state_memuse %"PRIu64"",
1373  ftp_state_memcnt, ftp_state_memuse);
1374  SCMutexUnlock(&ftp_state_mem_lock);
1375 #endif
1376 }
1377 
1378 
1379 /*
1380  * \brief Returns the ending offset of the next line from a multi-line buffer.
1381  *
1382  * "Buffer" refers to a FTP response in a single buffer containing multiple lines.
1383  * Here, "next line" is defined as terminating on
1384  * - Newline character
1385  * - Null character
1386  *
1387  * \param buffer Contains zero or more characters.
1388  * \param len Size, in bytes, of buffer.
1389  *
1390  * \retval Offset from the start of buffer indicating the where the
1391  * next "line ends". The characters between the input buffer and this
1392  * value comprise the line.
1393  *
1394  * NULL is found first or a newline isn't found, then UINT16_MAX is returned.
1395  */
1396 uint16_t JsonGetNextLineFromBuffer(const char *buffer, const uint16_t len)
1397 {
1398  if (!buffer || *buffer == '\0') {
1399  return UINT16_MAX;
1400  }
1401 
1402  char *c = strchr(buffer, '\n');
1403  return c == NULL ? len : c - buffer + 1;
1404 }
1405 
1406 void EveFTPDataAddMetadata(const Flow *f, JsonBuilder *jb)
1407 {
1408  const FtpDataState *ftp_state = NULL;
1409  if (f->alstate == NULL)
1410  return;
1411 
1412  ftp_state = (FtpDataState *)f->alstate;
1413 
1414  if (ftp_state->file_name) {
1415  jb_set_string_from_bytes(jb, "filename", ftp_state->file_name, ftp_state->file_len);
1416  }
1417  switch (ftp_state->command) {
1418  case FTP_COMMAND_STOR:
1419  JB_SET_STRING(jb, "command", "STOR");
1420  break;
1421  case FTP_COMMAND_RETR:
1422  JB_SET_STRING(jb, "command", "RETR");
1423  break;
1424  default:
1425  break;
1426  }
1427 }
1428 
1429 /**
1430  * \brief Free memory allocated for global FTP parser state.
1431  */
1433 {
1434  FTPFreeMpmState();
1435 }
1436 
1437 /* UNITTESTS */
1438 #ifdef UNITTESTS
1439 
1440 /** \test Send a get request in one chunk. */
1441 static int FTPParserTest01(void)
1442 {
1443  int result = 1;
1444  Flow f;
1445  uint8_t ftpbuf[] = "PORT 192,168,1,1,0,80\r\n";
1446  uint32_t ftplen = sizeof(ftpbuf) - 1; /* minus the \0 */
1447  TcpSession ssn;
1449 
1450  memset(&f, 0, sizeof(f));
1451  memset(&ssn, 0, sizeof(ssn));
1452 
1453  FLOW_INITIALIZE(&f);
1454  f.protoctx = (void *)&ssn;
1455  f.proto = IPPROTO_TCP;
1456  f.alproto = ALPROTO_FTP;
1457 
1459 
1460  FLOWLOCK_WRLOCK(&f);
1461  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1462  STREAM_TOSERVER | STREAM_EOF, ftpbuf, ftplen);
1463  if (r != 0) {
1464  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1465  result = 0;
1466  FLOWLOCK_UNLOCK(&f);
1467  goto end;
1468  }
1469  FLOWLOCK_UNLOCK(&f);
1470 
1471  FtpState *ftp_state = f.alstate;
1472  if (ftp_state == NULL) {
1473  SCLogDebug("no ftp state: ");
1474  result = 0;
1475  goto end;
1476  }
1477 
1478  if (ftp_state->command != FTP_COMMAND_PORT) {
1479  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_PORT, ftp_state->command);
1480  result = 0;
1481  goto end;
1482  }
1483 
1484 end:
1485  if (alp_tctx != NULL)
1488  FLOW_DESTROY(&f);
1489  return result;
1490 }
1491 
1492 /** \test Send a split get request. */
1493 static int FTPParserTest03(void)
1494 {
1495  int result = 1;
1496  Flow f;
1497  uint8_t ftpbuf1[] = "POR";
1498  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1499  uint8_t ftpbuf2[] = "T 192,168,1";
1500  uint32_t ftplen2 = sizeof(ftpbuf2) - 1; /* minus the \0 */
1501  uint8_t ftpbuf3[] = "1,1,10,20\r\n";
1502  uint32_t ftplen3 = sizeof(ftpbuf3) - 1; /* minus the \0 */
1503  TcpSession ssn;
1505 
1506  memset(&f, 0, sizeof(f));
1507  memset(&ssn, 0, sizeof(ssn));
1508 
1509  FLOW_INITIALIZE(&f);
1510  f.protoctx = (void *)&ssn;
1511  f.proto = IPPROTO_TCP;
1512  f.alproto = ALPROTO_FTP;
1513 
1515 
1516  FLOWLOCK_WRLOCK(&f);
1517  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1518  STREAM_TOSERVER | STREAM_START, ftpbuf1,
1519  ftplen1);
1520  if (r != 0) {
1521  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1522  result = 0;
1523  FLOWLOCK_UNLOCK(&f);
1524  goto end;
1525  }
1526  FLOWLOCK_UNLOCK(&f);
1527 
1528  FLOWLOCK_WRLOCK(&f);
1530  ftpbuf2, ftplen2);
1531  if (r != 0) {
1532  SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1533  result = 0;
1534  FLOWLOCK_UNLOCK(&f);
1535  goto end;
1536  }
1537  FLOWLOCK_UNLOCK(&f);
1538 
1539  FLOWLOCK_WRLOCK(&f);
1540  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1541  STREAM_TOSERVER | STREAM_EOF, ftpbuf3, ftplen3);
1542  if (r != 0) {
1543  SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1544  result = 0;
1545  FLOWLOCK_UNLOCK(&f);
1546  goto end;
1547  }
1548  FLOWLOCK_UNLOCK(&f);
1549 
1550  FtpState *ftp_state = f.alstate;
1551  if (ftp_state == NULL) {
1552  SCLogDebug("no ftp state: ");
1553  result = 0;
1554  goto end;
1555  }
1556 
1557  if (ftp_state->command != FTP_COMMAND_PORT) {
1558  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_PORT, ftp_state->command);
1559  result = 0;
1560  goto end;
1561  }
1562 
1563 end:
1564  if (alp_tctx != NULL)
1567  return result;
1568 }
1569 
1570 /** \test See how it deals with an incomplete request. */
1571 static int FTPParserTest06(void)
1572 {
1573  int result = 1;
1574  Flow f;
1575  uint8_t ftpbuf1[] = "PORT";
1576  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1577  TcpSession ssn;
1579 
1580  memset(&f, 0, sizeof(f));
1581  memset(&ssn, 0, sizeof(ssn));
1582 
1583  FLOW_INITIALIZE(&f);
1584  f.protoctx = (void *)&ssn;
1585  f.proto = IPPROTO_TCP;
1586  f.alproto = ALPROTO_FTP;
1587 
1589 
1590  FLOWLOCK_WRLOCK(&f);
1591  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1593  ftpbuf1,
1594  ftplen1);
1595  if (r != 0) {
1596  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1597  result = 0;
1598  FLOWLOCK_UNLOCK(&f);
1599  goto end;
1600  }
1601  FLOWLOCK_UNLOCK(&f);
1602 
1603  FtpState *ftp_state = f.alstate;
1604  if (ftp_state == NULL) {
1605  SCLogDebug("no ftp state: ");
1606  result = 0;
1607  goto end;
1608  }
1609 
1610  if (ftp_state->command != FTP_COMMAND_UNKNOWN) {
1611  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_UNKNOWN, ftp_state->command);
1612  result = 0;
1613  goto end;
1614  }
1615 
1616 end:
1617  if (alp_tctx != NULL)
1620  FLOW_DESTROY(&f);
1621  return result;
1622 }
1623 
1624 /** \test See how it deals with an incomplete request in multiple chunks. */
1625 static int FTPParserTest07(void)
1626 {
1627  int result = 1;
1628  Flow f;
1629  uint8_t ftpbuf1[] = "PO";
1630  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1631  uint8_t ftpbuf2[] = "RT\r\n";
1632  uint32_t ftplen2 = sizeof(ftpbuf2) - 1; /* minus the \0 */
1633  TcpSession ssn;
1635 
1636  memset(&f, 0, sizeof(f));
1637  memset(&ssn, 0, sizeof(ssn));
1638 
1639  FLOW_INITIALIZE(&f);
1640  f.protoctx = (void *)&ssn;
1641  f.proto = IPPROTO_TCP;
1642  f.alproto = ALPROTO_FTP;
1643 
1645 
1646  FLOWLOCK_WRLOCK(&f);
1647  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1648  STREAM_TOSERVER | STREAM_START, ftpbuf1,
1649  ftplen1);
1650  if (r != 0) {
1651  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1652  result = 0;
1653  FLOWLOCK_UNLOCK(&f);
1654  goto end;
1655  }
1656  FLOWLOCK_UNLOCK(&f);
1657 
1658  FLOWLOCK_WRLOCK(&f);
1659  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1660  STREAM_TOSERVER | STREAM_EOF, ftpbuf2, ftplen2);
1661  if (r != 0) {
1662  SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1663  result = 0;
1664  FLOWLOCK_UNLOCK(&f);
1665  goto end;
1666  }
1667  FLOWLOCK_UNLOCK(&f);
1668 
1669  FtpState *ftp_state = f.alstate;
1670  if (ftp_state == NULL) {
1671  SCLogDebug("no ftp state: ");
1672  result = 0;
1673  goto end;
1674  }
1675 
1676  if (ftp_state->command != FTP_COMMAND_PORT) {
1677  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ",
1678  FTP_COMMAND_PORT, ftp_state->command);
1679  result = 0;
1680  goto end;
1681  }
1682 
1683 end:
1684  if (alp_tctx != NULL)
1687  FLOW_DESTROY(&f);
1688  return result;
1689 }
1690 
1691 /** \test Test case where chunks are smaller than the delim length and the
1692  * last chunk is supposed to match the delim. */
1693 static int FTPParserTest10(void)
1694 {
1695  int result = 1;
1696  Flow f;
1697  uint8_t ftpbuf1[] = "PORT 1,2,3,4,5,6\r\n";
1698  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1699  TcpSession ssn;
1701  int r = 0;
1702  memset(&f, 0, sizeof(f));
1703  memset(&ssn, 0, sizeof(ssn));
1704 
1705  FLOW_INITIALIZE(&f);
1706  f.protoctx = (void *)&ssn;
1707  f.proto = IPPROTO_TCP;
1708  f.alproto = ALPROTO_FTP;
1709 
1711 
1712  uint32_t u;
1713  for (u = 0; u < ftplen1; u++) {
1714  uint8_t flags = 0;
1715 
1716  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
1717  else if (u == (ftplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
1718  else flags = STREAM_TOSERVER;
1719 
1720  FLOWLOCK_WRLOCK(&f);
1722  &ftpbuf1[u], 1);
1723  if (r != 0) {
1724  SCLogDebug("toserver chunk %" PRIu32 " returned %" PRId32 ", expected 0: ", u, r);
1725  result = 0;
1726  FLOWLOCK_UNLOCK(&f);
1727  goto end;
1728  }
1729  FLOWLOCK_UNLOCK(&f);
1730  }
1731 
1732  FtpState *ftp_state = f.alstate;
1733  if (ftp_state == NULL) {
1734  SCLogDebug("no ftp state: ");
1735  result = 0;
1736  goto end;
1737  }
1738 
1739  if (ftp_state->command != FTP_COMMAND_PORT) {
1740  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_PORT, ftp_state->command);
1741  result = 0;
1742  goto end;
1743  }
1744 
1745 end:
1746  if (alp_tctx != NULL)
1749  FLOW_DESTROY(&f);
1750  return result;
1751 }
1752 
1753 /** \test Supply RETR without a filename */
1754 static int FTPParserTest11(void)
1755 {
1756  int result = 1;
1757  Flow f;
1758  uint8_t ftpbuf1[] = "PORT 192,168,1,1,0,80\r\n";
1759  uint8_t ftpbuf2[] = "RETR\r\n";
1760  uint8_t ftpbuf3[] = "227 OK\r\n";
1761  TcpSession ssn;
1762 
1764 
1765  memset(&f, 0, sizeof(f));
1766  memset(&ssn, 0, sizeof(ssn));
1767 
1768  FLOW_INITIALIZE(&f);
1769  f.protoctx = (void *)&ssn;
1770  f.proto = IPPROTO_TCP;
1771  f.alproto = ALPROTO_FTP;
1772 
1774 
1775  FLOWLOCK_WRLOCK(&f);
1776  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1777  STREAM_TOSERVER | STREAM_START, ftpbuf1,
1778  sizeof(ftpbuf1) - 1);
1779  if (r != 0) {
1780  result = 0;
1781  FLOWLOCK_UNLOCK(&f);
1782  goto end;
1783  }
1784  FLOWLOCK_UNLOCK(&f);
1785 
1786  /* Response */
1787  FLOWLOCK_WRLOCK(&f);
1788  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1790  ftpbuf3,
1791  sizeof(ftpbuf3) - 1);
1792  if (r != 0) {
1793  result = 0;
1794  FLOWLOCK_UNLOCK(&f);
1795  goto end;
1796  }
1797  FLOWLOCK_UNLOCK(&f);
1798 
1799  FLOWLOCK_WRLOCK(&f);
1800  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1801  STREAM_TOSERVER, ftpbuf2,
1802  sizeof(ftpbuf2) - 1);
1803  if (r == 0) {
1804  SCLogDebug("parse should've failed");
1805  result = 0;
1806  FLOWLOCK_UNLOCK(&f);
1807  goto end;
1808  }
1809  FLOWLOCK_UNLOCK(&f);
1810 
1811  FtpState *ftp_state = f.alstate;
1812  if (ftp_state == NULL) {
1813  SCLogDebug("no ftp state: ");
1814  result = 0;
1815  goto end;
1816  }
1817 
1818  if (ftp_state->command != FTP_COMMAND_RETR) {
1819  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ",
1820  FTP_COMMAND_RETR, ftp_state->command);
1821  result = 0;
1822  goto end;
1823  }
1824 
1825 end:
1826  if (alp_tctx != NULL)
1829  FLOW_DESTROY(&f);
1830  return result;
1831 }
1832 
1833 /** \test Supply STOR without a filename */
1834 static int FTPParserTest12(void)
1835 {
1836  int result = 1;
1837  Flow f;
1838  uint8_t ftpbuf1[] = "PORT 192,168,1,1,0,80\r\n";
1839  uint8_t ftpbuf2[] = "STOR\r\n";
1840  uint8_t ftpbuf3[] = "227 OK\r\n";
1841  TcpSession ssn;
1842 
1844 
1845  memset(&f, 0, sizeof(f));
1846  memset(&ssn, 0, sizeof(ssn));
1847 
1848  FLOW_INITIALIZE(&f);
1849  f.protoctx = (void *)&ssn;
1850  f.proto = IPPROTO_TCP;
1851  f.alproto = ALPROTO_FTP;
1852 
1854 
1855  FLOWLOCK_WRLOCK(&f);
1856  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1857  STREAM_TOSERVER | STREAM_START, ftpbuf1,
1858  sizeof(ftpbuf1) - 1);
1859  if (r != 0) {
1860  result = 0;
1861  FLOWLOCK_UNLOCK(&f);
1862  goto end;
1863  }
1864  FLOWLOCK_UNLOCK(&f);
1865 
1866  /* Response */
1867  FLOWLOCK_WRLOCK(&f);
1868  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1870  ftpbuf3,
1871  sizeof(ftpbuf3) - 1);
1872  if (r != 0) {
1873  result = 0;
1874  FLOWLOCK_UNLOCK(&f);
1875  goto end;
1876  }
1877  FLOWLOCK_UNLOCK(&f);
1878 
1879  FLOWLOCK_WRLOCK(&f);
1880  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1881  STREAM_TOSERVER, ftpbuf2,
1882  sizeof(ftpbuf2) - 1);
1883  if (r == 0) {
1884  SCLogDebug("parse should've failed");
1885  result = 0;
1886  FLOWLOCK_UNLOCK(&f);
1887  goto end;
1888  }
1889  FLOWLOCK_UNLOCK(&f);
1890 
1891  FtpState *ftp_state = f.alstate;
1892  if (ftp_state == NULL) {
1893  SCLogDebug("no ftp state: ");
1894  result = 0;
1895  goto end;
1896  }
1897 
1898  if (ftp_state->command != FTP_COMMAND_STOR) {
1899  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ",
1900  FTP_COMMAND_STOR, ftp_state->command);
1901  result = 0;
1902  goto end;
1903  }
1904 
1905 end:
1906  if (alp_tctx != NULL)
1909  FLOW_DESTROY(&f);
1910  return result;
1911 }
1912 #endif /* UNITTESTS */
1913 
1915 {
1916 #ifdef UNITTESTS
1917  UtRegisterTest("FTPParserTest01", FTPParserTest01);
1918  UtRegisterTest("FTPParserTest03", FTPParserTest03);
1919  UtRegisterTest("FTPParserTest06", FTPParserTest06);
1920  UtRegisterTest("FTPParserTest07", FTPParserTest07);
1921  UtRegisterTest("FTPParserTest10", FTPParserTest10);
1922  UtRegisterTest("FTPParserTest11", FTPParserTest11);
1923  UtRegisterTest("FTPParserTest12", FTPParserTest12);
1924 #endif /* UNITTESTS */
1925 }
1926 
MpmInitThreadCtx
void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher)
Definition: util-mpm.c:249
FtpLineState_::current_line_lf_seen
uint8_t current_line_lf_seen
Definition: app-layer-ftp.h:125
AppLayerParserRegisterGetStateProgressFunc
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
Definition: app-layer-parser.c:475
FTPTransaction_::command_descriptor
const FtpCommand * command_descriptor
Definition: app-layer-ftp.h:145
FileContainer_
Definition: util-file.h:100
len
uint8_t len
Definition: app-layer-dnp3.h:2
FTP_COMMAND_USER
@ FTP_COMMAND_USER
Definition: app-layer-ftp.h:84
FTP_COMMAND_STAT
@ FTP_COMMAND_STAT
Definition: app-layer-ftp.h:77
FTP_COMMAND_DELE
@ FTP_COMMAND_DELE
Definition: app-layer-ftp.h:46
FTPTransaction_::request
uint8_t * request
Definition: app-layer-ftp.h:142
StreamingBufferConfig_::Malloc
void *(* Malloc)(size_t size)
Definition: util-streaming-buffer.h:71
AppLayerProtoDetectPMRegisterPatternCI
int AppLayerProtoDetectPMRegisterPatternCI(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.
Definition: app-layer-detect-proto.c:1750
FTPThreadCtx_
Definition: app-layer-ftp.c:64
FtpTransferCmd::flow_id
uint64_t flow_id
Definition: app-layer-ftp.c:500
StreamingBufferConfig_::buf_size
uint32_t buf_size
Definition: util-streaming-buffer.h:70
AppLayerParserRegisterLocalStorageFunc
void AppLayerParserRegisterLocalStorageFunc(uint8_t ipproto, AppProto alproto, void *(*LocalStorageAlloc)(void), void(*LocalStorageFree)(void *))
Definition: app-layer-parser.c:411
FTP_COMMAND_ALLO
@ FTP_COMMAND_ALLO
Definition: app-layer-ftp.h:40
TAILQ_INIT
#define TAILQ_INIT(head)
Definition: queue.h:370
FtpState_::active
bool active
Definition: app-layer-ftp.h:166
flow-util.h
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:315
FtpCommands
const FtpCommand FtpCommands[FTP_COMMAND_MAX+1]
Definition: app-layer-ftp.c:73
FileContainerAlloc
FileContainer * FileContainerAlloc(void)
allocate a FileContainer
Definition: util-file.c:423
FtpDataState_::state
uint8_t state
Definition: app-layer-ftp.h:208
StreamingBufferConfig_::Calloc
void *(* Calloc)(size_t n, size_t size)
Definition: util-streaming-buffer.h:72
DetectEngineState_
Definition: detect-engine-state.h:92
MpmThreadCtx_
Definition: util-mpm.h:46
FtpState_::input_len
int32_t input_len
Definition: app-layer-ftp.h:164
stream-tcp.h
FtpState
struct FtpState_ FtpState
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
FTPString_::len
uint16_t len
Definition: app-layer-ftp.h:130
PrefilterRuleStore_
structure for storing potential rule matches
Definition: util-prefilter.h:32
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:202
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
FtpLineState_::db_len
uint32_t db_len
Definition: app-layer-ftp.h:122
MpmInitCtx
void MpmInitCtx(MpmCtx *mpm_ctx, uint16_t matcher)
Definition: util-mpm.c:254
FTP_COMMAND_RNFR
@ FTP_COMMAND_RNFR
Definition: app-layer-ftp.h:72
Flow_::proto
uint8_t proto
Definition: flow.h:365
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:73
FtpState_::command
FtpRequestCommand command
Definition: app-layer-ftp.h:182
AppLayerParserConfParserEnabled
int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name)
check if a parser is enabled in the config Returns enabled always if: were running unittests
Definition: app-layer-parser.c:301
FTP_STATE_PORT_DONE
@ FTP_STATE_PORT_DONE
Definition: app-layer-ftp.h:32
STREAMING_BUFFER_CONFIG_INITIALIZER
#define STREAMING_BUFFER_CONFIG_INITIALIZER
Definition: util-streaming-buffer.h:77
FtpLineState_::current_line_db
uint8_t current_line_db
Definition: app-layer-ftp.h:123
threads.h
Flow_
Flow data structure.
Definition: flow.h:347
FTPTransaction_::done
bool done
Definition: app-layer-ftp.h:148
FTP_COMMAND_MSND
@ FTP_COMMAND_MSND
Definition: app-layer-ftp.h:59
FTP_COMMAND_EPSV
@ FTP_COMMAND_EPSV
Definition: app-layer-ftp.h:47
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:333
AppLayerParserRegisterParserAcceptableDataDirection
void AppLayerParserRegisterParserAcceptableDataDirection(uint8_t ipproto, AppProto alproto, uint8_t direction)
Definition: app-layer-parser.c:371
FTP_COMMAND_RNTO
@ FTP_COMMAND_RNTO
Definition: app-layer-ftp.h:73
FtpState_::line_state
FtpLineState line_state[2]
Definition: app-layer-ftp.h:180
AppLayerParserRegisterTxFreeFunc
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))
Definition: app-layer-parser.c:486
FTP_COMMAND_MODE
@ FTP_COMMAND_MODE
Definition: app-layer-ftp.h:55
FTPTransaction_::tx_data
AppLayerTxData tx_data
Definition: app-layer-ftp.h:138
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:350
FTP_COMMAND_RMD
@ FTP_COMMAND_RMD
Definition: app-layer-ftp.h:71
FtpDataState_::command
FtpRequestCommand command
Definition: app-layer-ftp.h:207
FTPMemuseGlobalCounter
uint64_t FTPMemuseGlobalCounter(void)
Definition: app-layer-ftp.c:169
AppLayerParserThreadCtxFree
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
Definition: app-layer-parser.c:278
FTP_COMMAND_ABOR
@ FTP_COMMAND_ABOR
Definition: app-layer-ftp.h:38
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
rust.h
MIN
#define MIN(x, y)
Definition: suricata-common.h:377
FTP_COMMAND_MKD
@ FTP_COMMAND_MKD
Definition: app-layer-ftp.h:53
FtpCommand_::command
FtpRequestCommand command
Definition: app-layer-ftp.h:93
ALPROTO_FTP
@ ALPROTO_FTP
Definition: app-layer-protos.h:31
stream-tcp-reassemble.h
AppLayerParserRegisterDetectStateFuncs
void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, DetectEngineState *(*GetTxDetectState)(void *tx), int(*SetTxDetectState)(void *tx, DetectEngineState *))
Definition: app-layer-parser.c:562
FTP_COMMAND_LIST
@ FTP_COMMAND_LIST
Definition: app-layer-ftp.h:50
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:121
FtpCommand_::command_name
const char * command_name
Definition: app-layer-ftp.h:94
FtpDataState_::file_len
int16_t file_len
Definition: app-layer-ftp.h:206
TAILQ_INSERT_TAIL
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:385
AppLayerExpectationGetDataId
int AppLayerExpectationGetDataId(void)
Definition: app-layer-expectation.c:287
app-layer-ftp.h
APP_LAYER_PARSER_EOF_TS
#define APP_LAYER_PARSER_EOF_TS
Definition: app-layer-parser.h:41
Flow_::protoctx
void * protoctx
Definition: flow.h:441
FileAppendData
int FileAppendData(FileContainer *ffc, 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:722
FtpDataState_::direction
uint8_t direction
Definition: app-layer-ftp.h:209
util-unittest.h
FtpTransferCmd::file_len
uint16_t file_len
Definition: app-layer-ftp.c:502
FtpState_::direction
uint8_t direction
Definition: app-layer-ftp.h:165
SC_ATOMIC_DECLARE
SC_ATOMIC_DECLARE(uint64_t, ftp_memuse)
FTPParserCleanup
void FTPParserCleanup(void)
Free memory allocated for global FTP parser state.
Definition: app-layer-ftp.c:1432
FLOWLOCK_UNLOCK
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:264
STREAM_START
#define STREAM_START
Definition: stream.h:29
FTP_COMMAND_HELP
@ FTP_COMMAND_HELP
Definition: app-layer-ftp.h:48
FTPDATA_STATE_IN_PROGRESS
@ FTPDATA_STATE_IN_PROGRESS
Definition: app-layer-ftp.h:195
FTP_COMMAND_SIZE
@ FTP_COMMAND_SIZE
Definition: app-layer-ftp.h:75
util-memcmp.h
FTPDATA_STATE_FINISHED
@ FTPDATA_STATE_FINISHED
Definition: app-layer-ftp.h:196
SC_ERR_SIZE_PARSE
@ SC_ERR_SIZE_PARSE
Definition: util-error.h:230
ConfGet
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:330
FTP_COMMAND_CWD
@ FTP_COMMAND_CWD
Definition: app-layer-ftp.h:45
FTP_COMMAND_MSAM
@ FTP_COMMAND_MSAM
Definition: app-layer-ftp.h:58
FTP_COMMAND_SITE
@ FTP_COMMAND_SITE
Definition: app-layer-ftp.h:74
FtpState_
Definition: app-layer-ftp.h:162
app-layer-expectation.h
FLOW_INITIALIZE
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:39
AppLayerParserStateIssetFlag
int AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint8_t flag)
Definition: app-layer-parser.c:1623
FTP_COMMAND_STOU
@ FTP_COMMAND_STOU
Definition: app-layer-ftp.h:79
TAILQ_REMOVE
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:412
decode.h
util-debug.h
JB_SET_STRING
#define JB_SET_STRING(jb, key, val)
Definition: rust.h:24
TAILQ_FIRST
#define TAILQ_FIRST(head)
Definition: queue.h:339
FtpState_::port_line
uint8_t * port_line
Definition: app-layer-ftp.h:186
AppLayerParserState_
Definition: app-layer-parser.c:154
FTP_COMMAND_APPE
@ FTP_COMMAND_APPE
Definition: app-layer-ftp.h:41
FTPThreadCtx_::pmq
PrefilterRuleStore * pmq
Definition: app-layer-ftp.c:66
FileFlowToFlags
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
Definition: util-file.c:231
output-json.h
FtpState_::curr_tx
FTPTransaction * curr_tx
Definition: app-layer-ftp.h:168
FTP_COMMAND_TYPE
@ FTP_COMMAND_TYPE
Definition: app-layer-ftp.h:82
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
STREAM_TOSERVER
#define STREAM_TOSERVER
Definition: stream.h:31
alp_tctx
AppLayerParserThreadCtx * alp_tctx
Definition: fuzz_applayerparserparse.c:19
FLOWLOCK_WRLOCK
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:261
AppLayerParserRegisterGetFilesFunc
void AppLayerParserRegisterGetFilesFunc(uint8_t ipproto, AppProto alproto, FileContainer *(*StateGetFiles)(void *, uint8_t))
Definition: app-layer-parser.c:425
util-print.h
SCEnter
#define SCEnter(...)
Definition: util-debug.h:300
FTP_COMMAND_PORT
@ FTP_COMMAND_PORT
Definition: app-layer-ftp.h:65
FTP_COMMAND_MAX
@ FTP_COMMAND_MAX
Definition: app-layer-ftp.h:88
FTP_COMMAND_REIN
@ FTP_COMMAND_REIN
Definition: app-layer-ftp.h:68
FtpTransferCmd::cmd
FtpRequestCommand cmd
Definition: app-layer-ftp.c:503
AppLayerParserRegisterStateFuncs
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void *, AppProto), void(*StateFree)(void *))
Definition: app-layer-parser.c:398
app-layer-parser.h
TRUE
#define TRUE
Definition: suricata-common.h:33
FtpState_::input
const uint8_t * input
Definition: app-layer-ftp.h:163
FTP_STATE_FINISHED
@ FTP_STATE_FINISHED
Definition: app-layer-ftp.h:33
PmqReset
void PmqReset(PrefilterRuleStore *)
Reset a Pmq for reusage. Meant to be called after a single search.
Definition: util-prefilter.c:101
SC_ATOMIC_SUB
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
Definition: util-atomic.h:342
FTPParserRegisterTests
void FTPParserRegisterTests(void)
Definition: app-layer-ftp.c:1914
RegisterFTPParsers
void RegisterFTPParsers(void)
Definition: app-layer-ftp.c:1287
stream.h
AppLayerParserRegisterProtocolUnittests
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
Definition: app-layer-parser.c:1721
AppLayerExpectationCreate
int AppLayerExpectationCreate(Flow *f, int direction, Port src, Port dst, AppProto alproto, void *data)
Definition: app-layer-expectation.c:218
FtpCommand_
Definition: app-layer-ftp.h:92
StreamTcpFreeConfig
void StreamTcpFreeConfig(char quiet)
Definition: stream-tcp.c:668
FtpTransferCmd
Definition: app-layer-ftp.c:496
stream-tcp-private.h
APP_LAYER_PARSER_EOF_TC
#define APP_LAYER_PARSER_EOF_TC
Definition: app-layer-parser.h:42
ftp_config_memcap
uint64_t ftp_config_memcap
Definition: app-layer-ftp.c:127
FTP_COMMAND_CHMOD
@ FTP_COMMAND_CHMOD
Definition: app-layer-ftp.h:44
AppLayerRegisterExpectationProto
void AppLayerRegisterExpectationProto(uint8_t proto, AppProto alproto)
Definition: app-layer-detect-proto.c:2091
MpmTableElmt_::Prepare
int(* Prepare)(struct MpmCtx_ *)
Definition: util-mpm.h:161
FTP_COMMAND_SYST
@ FTP_COMMAND_SYST
Definition: app-layer-ftp.h:81
FileOpenFileWithId
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:933
SCReturnPtr
#define SCReturnPtr(x, type)
Definition: util-debug.h:316
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
AppLayerProtoDetectRegisterProtocol
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
Definition: app-layer-detect-proto.c:1825
FtpDataState
struct FtpDataState_ FtpDataState
FTP_COMMAND_ACCT
@ FTP_COMMAND_ACCT
Definition: app-layer-ftp.h:39
FTPMemcapGlobalCounter
uint64_t FTPMemcapGlobalCounter(void)
Definition: app-layer-ftp.c:175
MpmTableElmt_::Search
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition: util-mpm.h:162
FTP_COMMAND_MRSQ
@ FTP_COMMAND_MRSQ
Definition: app-layer-ftp.h:57
FtpDataState_::tx_data
AppLayerTxData tx_data
Definition: app-layer-ftp.h:210
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:217
AppLayerParserRegisterParser
int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, uint8_t direction, AppLayerParserFPtr Parser)
Register app layer parser for the protocol.
Definition: app-layer-parser.c:359
DetectEngineStateFree
void DetectEngineStateFree(DetectEngineState *state)
Frees a DetectEngineState object.
Definition: detect-engine-state.c:175
AppLayerParserRegisterGetStateProgressCompletionStatus
void AppLayerParserRegisterGetStateProgressCompletionStatus(AppProto alproto, int(*StateGetProgressCompletionStatus)(uint8_t direction))
Definition: app-layer-parser.c:527
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
AppLayerParserThreadCtxAlloc
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
Definition: app-layer-parser.c:252
AppLayerParserRegisterGetTx
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
Definition: app-layer-parser.c:508
FtpState_::current_line
const uint8_t * current_line
Definition: app-layer-ftp.h:174
util-mem.h
length
uint16_t length
Definition: app-layer-modbus.c:2
APP_LAYER_OK
#define APP_LAYER_OK
Definition: app-layer-parser.h:60
flow-storage.h
AppLayerRequestProtocolTLSUpgrade
void AppLayerRequestProtocolTLSUpgrade(Flow *f)
request applayer to wrap up this protocol and rerun protocol detection with expectation of TLS....
Definition: app-layer-detect-proto.c:1864
SCReturnStruct
#define SCReturnStruct(x)
Definition: util-debug.h:320
FTPTransaction_::request_length
uint32_t request_length
Definition: app-layer-ftp.h:141
util-mpm.h
flags
uint8_t flags
Definition: decode-gre.h:0
FTP_COMMAND_NOOP
@ FTP_COMMAND_NOOP
Definition: app-layer-ftp.h:62
AppLayerParserParse
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
Definition: app-layer-parser.c:1178
FtpLineState_
Definition: app-layer-ftp.h:118
FTP_COMMAND_CDUP
@ FTP_COMMAND_CDUP
Definition: app-layer-ftp.h:43
suricata-common.h
FTP_COMMAND_PASS
@ FTP_COMMAND_PASS
Definition: app-layer-ftp.h:63
FtpState_::current_line_len
uint32_t current_line_len
Definition: app-layer-ftp.h:176
FTPTransaction_::de_state
DetectEngineState * de_state
Definition: app-layer-ftp.h:156
FtpState_::port_line_len
uint32_t port_line_len
Definition: app-layer-ftp.h:184
FtpState_::dyn_port
uint16_t dyn_port
Definition: app-layer-ftp.h:188
util-spm.h
STREAM_TOCLIENT
#define STREAM_TOCLIENT
Definition: stream.h:32
PmqFree
void PmqFree(PrefilterRuleStore *)
Cleanup and free a Pmq.
Definition: util-prefilter.c:126
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:257
ALPROTO_FTPDATA
@ ALPROTO_FTPDATA
Definition: app-layer-protos.h:47
FtpTransferCmd::DFree
void(* DFree)(void *)
Definition: app-layer-ftp.c:499
AppLayerParserRegisterTxDataFunc
void AppLayerParserRegisterTxDataFunc(uint8_t ipproto, AppProto alproto, AppLayerTxData *(*GetTxData)(void *tx))
Definition: app-layer-parser.c:574
FTPAtExitPrintStats
void FTPAtExitPrintStats(void)
Definition: app-layer-ftp.c:1368
Flow_::parent_id
int64_t parent_id
Definition: flow.h:430
FTP_COMMAND_MRCP
@ FTP_COMMAND_MRCP
Definition: app-layer-ftp.h:56
FtpDataState_
Definition: app-layer-ftp.h:200
FTP_COMMAND_PWD
@ FTP_COMMAND_PWD
Definition: app-layer-ftp.h:66
FTP_COMMAND_STRU
@ FTP_COMMAND_STRU
Definition: app-layer-ftp.h:80
StreamingBufferConfig_
Definition: util-streaming-buffer.h:67
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
FTP_COMMAND_UNKNOWN
@ FTP_COMMAND_UNKNOWN
Definition: app-layer-ftp.h:37
FTP_COMMAND_MAIL
@ FTP_COMMAND_MAIL
Definition: app-layer-ftp.h:51
FTP_COMMAND_UMASK
@ FTP_COMMAND_UMASK
Definition: app-layer-ftp.h:83
str
#define str(s)
Definition: suricata-common.h:273
MpmTableElmt_::DestroyCtx
void(* DestroyCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:145
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Flow_::alstate
void * alstate
Definition: flow.h:476
PmqSetup
int PmqSetup(PrefilterRuleStore *)
Setup a pmq.
Definition: util-prefilter.c:36
StreamingBufferConfig_::Free
void(* Free)(void *ptr, size_t size)
Definition: util-streaming-buffer.h:74
src
uint16_t src
Definition: app-layer-dnp3.h:5
FtpState_::tx_cnt
uint64_t tx_cnt
Definition: app-layer-ftp.h:170
EveFTPDataAddMetadata
void EveFTPDataAddMetadata(const Flow *f, JsonBuilder *jb)
Definition: app-layer-ftp.c:1406
StreamTcpInitConfig
void StreamTcpInitConfig(char)
To initialize the stream global configuration data.
Definition: stream-tcp.c:365
FtpDataState_::de_state
DetectEngineState * de_state
Definition: app-layer-ftp.h:204
STREAM_EOF
#define STREAM_EOF
Definition: stream.h:30
FlowGetStorageById
void * FlowGetStorageById(Flow *f, int id)
Definition: flow-storage.c:39
mpm_table
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition: util-mpm.c:48
app-layer-protos.h
FTP_COMMAND_IDLE
@ FTP_COMMAND_IDLE
Definition: app-layer-ftp.h:49
AppLayerParserRegisterGetTxCnt
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
Definition: app-layer-parser.c:497
APP_LAYER_ERROR
#define APP_LAYER_ERROR
Definition: app-layer-parser.h:64
FtpState_::port_line_size
uint32_t port_line_size
Definition: app-layer-ftp.h:185
FTP_COMMAND_RETR
@ FTP_COMMAND_RETR
Definition: app-layer-ftp.h:70
FTP_MPM
#define FTP_MPM
Definition: app-layer-ftp.c:69
FTPTransaction_::tx_id
uint64_t tx_id
Definition: app-layer-ftp.h:136
FTPTransaction_::dyn_port
uint16_t dyn_port
Definition: app-layer-ftp.h:147
FTPTransaction_::active
bool active
Definition: app-layer-ftp.h:149
FILE_USE_DETECT
#define FILE_USE_DETECT
Definition: util-file.h:49
FTP_COMMAND_STOR
@ FTP_COMMAND_STOR
Definition: app-layer-ftp.h:78
FtpDataState_::files
FileContainer * files
Definition: app-layer-ftp.h:203
likely
#define likely(expr)
Definition: util-optimize.h:32
FTP_COMMAND_MSOM
@ FTP_COMMAND_MSOM
Definition: app-layer-ftp.h:60
MpmTableElmt_::DestroyThreadCtx
void(* DestroyThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *)
Definition: util-mpm.h:146
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:87
FTP_COMMAND_EPRT
@ FTP_COMMAND_EPRT
Definition: app-layer-ftp.h:85
FileContainerFree
void FileContainerFree(FileContainer *ffc)
Free a FileContainer.
Definition: util-file.c:459
FTPString_
Definition: app-layer-ftp.h:128
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:376
FtpLineState_::db
uint8_t * db
Definition: app-layer-ftp.h:121
MpmCtx_
Definition: util-mpm.h:88
TcpSession_
Definition: stream-tcp-private.h:261
JsonGetNextLineFromBuffer
uint16_t JsonGetNextLineFromBuffer(const char *buffer, const uint16_t len)
Definition: app-layer-ftp.c:1396
util-misc.h
FtpRequestCommand
FtpRequestCommand
Definition: app-layer-ftp.h:36
FTPTransaction_
Definition: app-layer-ftp.h:134
FTPThreadCtx
struct FTPThreadCtx_ FTPThreadCtx
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:450
FlowFreeStorageById
void FlowFreeStorageById(Flow *f, int id)
Definition: flow-storage.c:54
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
FTP_COMMAND_REST
@ FTP_COMMAND_REST
Definition: app-layer-ftp.h:69
util-pool.h
FTP_STATE_IN_PROGRESS
@ FTP_STATE_IN_PROGRESS
Definition: app-layer-ftp.h:31
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:304
FtpState_::current_line_delimiter_len
uint8_t current_line_delimiter_len
Definition: app-layer-ftp.h:177
MpmAddPatternCI
int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags)
Definition: util-mpm.c:304
SCMemcmp
#define SCMemcmp(a, b, c)
Definition: util-memcmp.h:369
FTP_COMMAND_PASV
@ FTP_COMMAND_PASV
Definition: app-layer-ftp.h:64
AppLayerProtoDetectConfProtoDetectionEnabled
int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
Given a protocol name, checks if proto detection is enabled in the conf file.
Definition: app-layer-detect-proto.c:1888
FileCloseFile
int FileCloseFile(FileContainer *ffc, const uint8_t *data, uint32_t data_len, uint16_t flags)
Close a File.
Definition: util-file.c:1027
FTP_COMMAND_AUTH_TLS
@ FTP_COMMAND_AUTH_TLS
Definition: app-layer-ftp.h:42
util-memrchr.h
SCMutex
#define SCMutex
Definition: threads-debug.h:114
FTPString_::str
uint8_t * str
Definition: app-layer-ftp.h:129
FTPThreadCtx_::ftp_mpm_thread_ctx
MpmThreadCtx * ftp_mpm_thread_ctx
Definition: app-layer-ftp.c:65
FLOW_DESTROY
#define FLOW_DESTROY(f)
Definition: flow-util.h:130
FTP_COMMAND_NLST
@ FTP_COMMAND_NLST
Definition: app-layer-ftp.h:61
FTP_COMMAND_MDTM
@ FTP_COMMAND_MDTM
Definition: app-layer-ftp.h:52
FTP_COMMAND_SMNT
@ FTP_COMMAND_SMNT
Definition: app-layer-ftp.h:76
FTP_COMMAND_QUIT
@ FTP_COMMAND_QUIT
Definition: app-layer-ftp.h:67
debug.h
StreamingBufferConfig_::Realloc
void *(* Realloc)(void *ptr, size_t orig_size, size_t size)
Definition: util-streaming-buffer.h:73
FtpDataState_::file_name
uint8_t * file_name
Definition: app-layer-ftp.h:202
FTP_COMMAND_MLFL
@ FTP_COMMAND_MLFL
Definition: app-layer-ftp.h:54
FtpTransferCmd::file_name
uint8_t * file_name
Definition: app-layer-ftp.c:501
app-layer.h
PrefilterRuleStore_::rule_id_array
SigIntId * rule_id_array
Definition: util-prefilter.h:36