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