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