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