suricata
app-layer-ftp.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2025 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
22  * \author Eric Leblond <eric@regit.org>
23  * \author Jeff Lucovsky <jlucovsky@oisf.net>
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 uint64_t ftp_config_memcap = 0;
51 uint32_t ftp_config_maxtx = 1024;
52 uint32_t ftp_max_line_len = 4096;
53 
54 SC_ATOMIC_DECLARE(uint64_t, ftp_memuse);
55 SC_ATOMIC_DECLARE(uint64_t, ftp_memcap);
56 
57 static FTPTransaction *FTPGetOldestTx(const FtpState *, FTPTransaction *);
58 
59 static void FTPParseMemcap(void)
60 {
61  SCFTPGetConfigValues(&ftp_config_memcap, &ftp_config_maxtx, &ftp_max_line_len);
62 
63  SC_ATOMIC_INIT(ftp_memuse);
64  SC_ATOMIC_INIT(ftp_memcap);
65 }
66 
67 static void FTPIncrMemuse(uint64_t size)
68 {
69  (void)SC_ATOMIC_ADD(ftp_memuse, size);
70 }
71 
72 static void FTPDecrMemuse(uint64_t size)
73 {
74  (void)SC_ATOMIC_SUB(ftp_memuse, size);
75 }
76 
77 uint64_t FTPMemuseGlobalCounter(void)
78 {
79  uint64_t tmpval = SC_ATOMIC_GET(ftp_memuse);
80  return tmpval;
81 }
82 
83 uint64_t FTPMemcapGlobalCounter(void)
84 {
85  uint64_t tmpval = SC_ATOMIC_GET(ftp_memcap);
86  return tmpval;
87 }
88 
89 int FTPSetMemcap(uint64_t size)
90 {
91  if ((uint64_t)SC_ATOMIC_GET(ftp_memcap) < size) {
92  SC_ATOMIC_SET(ftp_memcap, size);
93  return 1;
94  }
95 
96  return 0;
97 }
98 
99 /**
100  * \brief Check if alloc'ing "size" would mean we're over memcap
101  *
102  * \retval 1 if in bounds
103  * \retval 0 if not in bounds
104  */
105 static int FTPCheckMemcap(uint64_t size)
106 {
107  if (ftp_config_memcap == 0 || size + SC_ATOMIC_GET(ftp_memuse) <= ftp_config_memcap)
108  return 1;
109  (void) SC_ATOMIC_ADD(ftp_memcap, 1);
110  return 0;
111 }
112 
113 static void *FTPCalloc(size_t n, size_t size)
114 {
115  if (FTPCheckMemcap((uint32_t)(n * size)) == 0) {
117  return NULL;
118  }
119 
120  void *ptr = SCCalloc(n, size);
121 
122  if (unlikely(ptr == NULL)) {
124  return NULL;
125  }
126 
127  FTPIncrMemuse((uint64_t)(n * size));
128  return ptr;
129 }
130 
131 static void *FTPRealloc(void *ptr, size_t orig_size, size_t size)
132 {
133  if (FTPCheckMemcap((uint32_t)(size - orig_size)) == 0) {
135  return NULL;
136  }
137 
138  void *rptr = SCRealloc(ptr, size);
139  if (rptr == NULL) {
141  return NULL;
142  }
143 
144  if (size > orig_size) {
145  FTPIncrMemuse(size - orig_size);
146  } else {
147  FTPDecrMemuse(orig_size - size);
148  }
149 
150  return rptr;
151 }
152 
153 static void FTPFree(void *ptr, size_t size)
154 {
155  SCFree(ptr);
156 
157  FTPDecrMemuse((uint64_t)size);
158 }
159 
160 static FTPResponseWrapper *FTPResponseWrapperAlloc(FTPResponseLine *response)
161 {
162  FTPResponseWrapper *wrapper = FTPCalloc(1, sizeof(FTPResponseWrapper));
163  if (likely(wrapper)) {
164  FTPIncrMemuse(response->total_size);
165  wrapper->response = response;
166  }
167  return wrapper;
168 }
169 
170 static void FTPResponseWrapperFree(FTPResponseWrapper *wrapper)
171 {
172  if (wrapper->response) {
173  FTPDecrMemuse(wrapper->response->total_size);
174  SCFTPFreeResponseLine(wrapper->response);
175  }
176 
177  FTPFree(wrapper, sizeof(FTPResponseWrapper));
178 }
179 
180 static void *FTPLocalStorageAlloc(void)
181 {
182  /* needed by the mpm */
183  FTPThreadCtx *td = SCCalloc(1, sizeof(*td));
184  if (td == NULL) {
185  exit(EXIT_FAILURE);
186  }
187 
188  td->pmq = SCCalloc(1, sizeof(*td->pmq));
189  if (td->pmq == NULL) {
190  exit(EXIT_FAILURE);
191  }
192  PmqSetup(td->pmq);
193 
194  td->ftp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx));
195  if (unlikely(td->ftp_mpm_thread_ctx == NULL)) {
196  exit(EXIT_FAILURE);
197  }
199  return td;
200 }
201 
202 static void FTPLocalStorageFree(void *ptr)
203 {
204  FTPThreadCtx *td = ptr;
205  if (td != NULL) {
206  if (td->pmq != NULL) {
207  PmqFree(td->pmq);
208  SCFree(td->pmq);
209  }
210 
211  if (td->ftp_mpm_thread_ctx != NULL) {
214  }
215 
216  SCFree(td);
217  }
218 }
219 static FTPTransaction *FTPTransactionCreate(FtpState *state)
220 {
221  SCEnter();
222  FTPTransaction *firsttx = TAILQ_FIRST(&state->tx_list);
223  if (firsttx && state->tx_cnt - firsttx->tx_id > ftp_config_maxtx) {
224  // FTP does not set events yet...
225  return NULL;
226  }
227  FTPTransaction *tx = FTPCalloc(1, sizeof(*tx));
228  if (tx == NULL) {
229  return NULL;
230  }
231 
232  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
233  tx->tx_id = state->tx_cnt++;
234 
235  TAILQ_INIT(&tx->response_list);
236 
237  SCLogDebug("new transaction %p (state tx cnt %"PRIu64")", tx, state->tx_cnt);
238  return tx;
239 }
240 
241 static void FTPTransactionFree(FTPTransaction *tx)
242 {
243  SCEnter();
244 
245  SCAppLayerTxDataCleanup(&tx->tx_data);
246 
247  if (tx->request) {
248  FTPFree(tx->request, tx->request_length);
249  }
250 
251  FTPResponseWrapper *wrapper;
252  while ((wrapper = TAILQ_FIRST(&tx->response_list))) {
253  TAILQ_REMOVE(&tx->response_list, wrapper, next);
254  FTPResponseWrapperFree(wrapper);
255  }
256 
257  FTPFree(tx, sizeof(*tx));
258 }
259 
260 typedef struct FtpInput_ {
261  const uint8_t *buf;
262  int32_t consumed;
263  int32_t len;
264  int32_t orig_len;
266 
267 static AppLayerResult FTPGetLineForDirection(
268  FtpLineState *line, FtpInput *input, bool *current_line_truncated)
269 {
270  SCEnter();
271 
272  /* we have run out of input */
273  if (input->len <= 0)
274  return APP_LAYER_ERROR;
275 
276  uint8_t *lf_idx = memchr(input->buf + input->consumed, 0x0a, input->len);
277 
278  if (lf_idx == NULL) {
279  if (!(*current_line_truncated) && (uint32_t)input->len >= ftp_max_line_len) {
280  *current_line_truncated = true;
281  line->buf = input->buf;
282  line->len = ftp_max_line_len;
283  line->delim_len = 0;
284  input->len = 0;
286  }
287  SCReturnStruct(APP_LAYER_INCOMPLETE(input->consumed, input->len + 1));
288  } else if (*current_line_truncated) {
289  // Whatever came in with first LF should also get discarded
290  *current_line_truncated = false;
291  line->len = 0;
292  line->delim_len = 0;
293  input->len = 0;
295  } else {
296  // There could be one chunk of command data that has LF but post the line limit
297  // e.g. input_len = 5077
298  // lf_idx = 5010
299  // max_line_len = 4096
300  uint32_t o_consumed = input->consumed;
301  input->consumed = (uint32_t)(lf_idx - input->buf + 1);
302  line->len = input->consumed - o_consumed;
303  input->len -= line->len;
304  line->lf_found = true;
305  DEBUG_VALIDATE_BUG_ON((input->consumed + input->len) != input->orig_len);
306  line->buf = input->buf + o_consumed;
307  if (line->len >= ftp_max_line_len) {
308  *current_line_truncated = true;
309  line->len = ftp_max_line_len;
311  }
312  if (input->consumed >= 2 && input->buf[input->consumed - 2] == 0x0D) {
313  line->delim_len = 2;
314  line->len -= 2;
315  } else {
316  line->delim_len = 1;
317  line->len -= 1;
318  }
320  }
321 }
322 
323 /**
324  * \brief This function is called to determine and set which command is being
325  * transferred to the ftp server
326  * \param thread context
327  * \param input input line of the command
328  * \param len of the command
329  * \param cmd_descriptor when the command has been parsed
330  *
331  * \retval 1 when the command is parsed, 0 otherwise
332  */
333 static int FTPParseRequestCommand(
334  FTPThreadCtx *td, FtpLineState *line, FtpCommandInfo *cmd_descriptor)
335 {
336  SCEnter();
337 
338  /* I don't like this pmq reset here. We'll devise a method later, that
339  * should make the use of the mpm very efficient */
340  PmqReset(td->pmq);
341  int mpm_cnt = mpm_table[FTP_MPM].Search(
342  ftp_mpm_ctx, td->ftp_mpm_thread_ctx, td->pmq, line->buf, line->len);
343  if (mpm_cnt) {
344  uint8_t command_code;
345  if (SCGetFtpCommandInfo(td->pmq->rule_id_array[0], NULL, &command_code, NULL)) {
346  cmd_descriptor->command_code = command_code;
347  /* FTP command indices are expressed in Rust as a u8 */
348  cmd_descriptor->command_index = (uint8_t)td->pmq->rule_id_array[0];
349  SCReturnInt(1);
350  } else {
351  /* Where is out command? */
353  }
354 #ifdef DEBUG
355  if (SCLogDebugEnabled()) {
356  const char *command_name = NULL;
357  (void)SCGetFtpCommandInfo(td->pmq->rule_id_array[0], &command_name, NULL, NULL);
358  SCLogDebug("matching FTP command is %s [code: %d, index %d]", command_name,
359  command_code, td->pmq->rule_id_array[0]);
360  }
361 #endif
362  }
363 
364  cmd_descriptor->command_code = FTP_COMMAND_UNKNOWN;
365  SCReturnInt(0);
366 }
367 
368 static void FtpTransferCmdFree(void *data)
369 {
370  FtpTransferCmd *cmd = (FtpTransferCmd *)data;
371  if (cmd == NULL)
372  return;
373  if (cmd->file_name) {
374  FTPFree((void *)cmd->file_name, cmd->file_len + 1);
375  }
376  SCFTPTransferCmdFree(cmd);
377  FTPDecrMemuse((uint64_t)sizeof(FtpTransferCmd));
378 }
379 
380 static uint32_t CopyCommandLine(uint8_t **dest, FtpLineState *line)
381 {
382  if (likely(line->len)) {
383  uint8_t *where = FTPCalloc(line->len + 1, sizeof(char));
384  if (unlikely(where == NULL)) {
385  return 0;
386  }
387  memcpy(where, line->buf, line->len);
388 
389  /* Remove trailing newlines/carriage returns */
390  while (line->len && isspace((unsigned char)where[line->len - 1])) {
391  line->len--;
392  }
393 
394  where[line->len] = '\0';
395  *dest = where;
396  }
397  /* either 0 or actual */
398  return line->len ? line->len + 1 : 0;
399 }
400 
401 #include "util-print.h"
402 
403 /**
404  * \brief This function is called to retrieve a ftp request
405  * \param ftp_state the ftp state structure for the parser
406  *
407  * \retval APP_LAYER_OK when input was process successfully
408  * \retval APP_LAYER_ERROR when a unrecoverable error was encountered
409  */
410 static AppLayerResult FTPParseRequest(Flow *f, void *ftp_state, AppLayerParserState *pstate,
411  StreamSlice stream_slice, void *local_data)
412 {
413  FTPThreadCtx *thread_data = local_data;
414 
415  SCEnter();
416  /* PrintRawDataFp(stdout, input,input_len); */
417 
418  FtpState *state = (FtpState *)ftp_state;
419  void *ptmp;
420 
421  const uint8_t *input = StreamSliceGetData(&stream_slice);
422  uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
423 
424  if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS)) {
426  } else if (input == NULL || input_len == 0) {
428  }
429 
430  FtpInput ftpi = { .buf = input, .len = input_len, .orig_len = input_len, .consumed = 0 };
431  FtpLineState line = { .buf = NULL, .len = 0, .delim_len = 0, .lf_found = false };
432 
433  uint8_t direction = STREAM_TOSERVER;
434  AppLayerResult res;
435  while (1) {
436  res = FTPGetLineForDirection(&line, &ftpi, &state->current_line_truncated_ts);
437  if (res.status == 1) {
438  return res;
439  } else if (res.status == -1) {
440  break;
441  }
442 
443  FtpCommandInfo cmd_descriptor;
444  if (!FTPParseRequestCommand(thread_data, &line, &cmd_descriptor)) {
445  state->command = FTP_COMMAND_UNKNOWN;
446  continue;
447  }
448 
449  state->command = cmd_descriptor.command_code;
450  FTPTransaction *tx = FTPTransactionCreate(state);
451  if (unlikely(tx == NULL))
453  tx->tx_data.updated_ts = true;
454  state->curr_tx = tx;
455 
456  tx->command_descriptor = cmd_descriptor;
457  tx->request_length = CopyCommandLine(&tx->request, &line);
459 
460  if (line.lf_found) {
461  state->current_line_truncated_ts = false;
462  }
463  if (tx->request_truncated) {
464  AppLayerDecoderEventsSetEventRaw(&tx->tx_data.events, FtpEventRequestCommandTooLong);
465  }
466 
467  /* change direction (default to server) so expectation will handle
468  * the correct message when expectation will match.
469  * For ftp active mode, data connection direction is opposite to
470  * control direction.
471  */
472  if ((state->active && state->command == FTP_COMMAND_STOR) ||
473  (!state->active && state->command == FTP_COMMAND_RETR)) {
474  direction = STREAM_TOCLIENT;
475  }
476 
477  switch (state->command) {
478  case FTP_COMMAND_EPRT:
479  // fallthrough
480  case FTP_COMMAND_PORT:
481  if (line.len + 1 > state->port_line_size) {
482  /* Allocate an extra byte for a NULL terminator */
483  ptmp = FTPRealloc(state->port_line, state->port_line_size, line.len + 1);
484  if (ptmp == NULL) {
485  if (state->port_line) {
486  FTPFree(state->port_line, state->port_line_size);
487  state->port_line = NULL;
488  state->port_line_size = 0;
489  state->port_line_len = 0;
490  }
492  }
493  state->port_line = ptmp;
494  state->port_line_size = line.len + 1;
495  }
496  memcpy(state->port_line, line.buf, line.len);
497  state->port_line_len = line.len;
498  break;
499  case FTP_COMMAND_RETR:
500  // fallthrough
501  case FTP_COMMAND_STOR: {
502  /* Ensure that there is a negotiated dyn port and a file
503  * name -- need more than 5 chars: cmd [4], space, <filename>
504  */
505  if (state->dyn_port == 0 || line.len < 6) {
507  }
508  FtpTransferCmd *data = SCFTPTransferCmdNew();
509  if (data == NULL)
511  FTPIncrMemuse((uint64_t)(sizeof *data));
512  data->data_free = FtpTransferCmdFree;
513 
514  /*
515  * Min size has been checked in FTPParseRequestCommand
516  * SC_FILENAME_MAX includes the null
517  */
518  uint32_t file_name_len = MIN(SC_FILENAME_MAX - 1, line.len - 5);
519 #if SC_FILENAME_MAX > UINT16_MAX
520 #error SC_FILENAME_MAX is greater than UINT16_MAX
521 #endif
522  data->file_name = FTPCalloc(file_name_len + 1, sizeof(char));
523  if (data->file_name == NULL) {
524  FtpTransferCmdFree(data);
526  }
527  data->file_name[file_name_len] = 0;
528  data->file_len = (uint16_t)file_name_len;
529  memcpy(data->file_name, line.buf + 5, file_name_len);
530  data->cmd = state->command;
531  data->flow_id = FlowGetId(f);
532  data->direction = direction;
533  int ret = AppLayerExpectationCreate(f, direction,
534  0, state->dyn_port, ALPROTO_FTPDATA, data);
535  if (ret == -1) {
536  FtpTransferCmdFree(data);
537  SCLogDebug("No expectation created.");
539  } else {
540  SCLogDebug("Expectation created [direction: %s, dynamic port %"PRIu16"].",
541  state->active ? "to server" : "to client",
542  state->dyn_port);
543  }
544 
545  /* reset the dyn port to avoid duplicate */
546  state->dyn_port = 0;
547  /* reset active/passive indicator */
548  state->active = false;
549  } break;
550  default:
551  break;
552  }
553  if (line.len >= ftp_max_line_len) {
554  ftpi.consumed = ftpi.len + 1;
555  break;
556  }
557  }
558 
560 }
561 
562 static int FTPParsePassiveResponse(FtpState *state, const uint8_t *input, uint32_t input_len)
563 {
564  uint16_t dyn_port = SCFTPParsePortPasv(input, input_len);
565  if (dyn_port == 0) {
566  return -1;
567  }
568  SCLogDebug("FTP passive mode (v4): dynamic port %"PRIu16"", dyn_port);
569  state->active = false;
570  state->dyn_port = dyn_port;
571  state->curr_tx->dyn_port = dyn_port;
572  state->curr_tx->active = false;
573 
574  return 0;
575 }
576 
577 static int FTPParsePassiveResponseV6(FtpState *state, const uint8_t *input, uint32_t input_len)
578 {
579  uint16_t dyn_port = SCFTPParsePortEpsv(input, input_len);
580  if (dyn_port == 0) {
581  return -1;
582  }
583  SCLogDebug("FTP passive mode (v6): dynamic port %"PRIu16"", dyn_port);
584  state->active = false;
585  state->dyn_port = dyn_port;
586  state->curr_tx->dyn_port = dyn_port;
587  state->curr_tx->active = false;
588  return 0;
589 }
590 
591 /**
592  * \brief Handle preliminary replies -- keep tx open
593  * \retval bool True for a positive preliminary reply; false otherwise
594  *
595  * 1yz Positive Preliminary reply
596  *
597  * The requested action is being initiated; expect another
598  * reply before proceeding with a new command
599  */
600 static inline bool FTPIsPPR(const uint8_t *input, uint32_t input_len)
601 {
602  return input_len >= 4 && isdigit(input[0]) && input[0] == '1' &&
603  isdigit(input[1]) && isdigit(input[2]) && isspace(input[3]);
604 }
605 
606 /**
607  * \brief This function is called to retrieve a ftp response
608  * \param ftp_state the ftp state structure for the parser
609  * \param input input line of the command
610  * \param input_len length of the request
611  * \param output the resulting output
612  *
613  * \retval 1 when the command is parsed, 0 otherwise
614  */
615 static AppLayerResult FTPParseResponse(Flow *f, void *ftp_state, AppLayerParserState *pstate,
616  StreamSlice stream_slice, void *local_data)
617 {
618  FtpState *state = (FtpState *)ftp_state;
619 
620  const uint8_t *input = StreamSliceGetData(&stream_slice);
621  uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
622 
623  if (unlikely(input_len == 0)) {
625  }
626  FtpInput ftpi = { .buf = input, .len = input_len, .orig_len = input_len, .consumed = 0 };
627  FtpLineState line = { .buf = NULL, .len = 0, .delim_len = 0, .lf_found = false };
628 
629  FTPTransaction *lasttx = TAILQ_FIRST(&state->tx_list);
630  AppLayerResult res;
631  while (1) {
632  res = FTPGetLineForDirection(&line, &ftpi, &state->current_line_truncated_tc);
633  if (res.status == 1) {
634  return res;
635  } else if (res.status == -1) {
636  break;
637  }
638  FTPTransaction *tx = FTPGetOldestTx(state, lasttx);
639  if (tx == NULL) {
640  tx = FTPTransactionCreate(state);
641  }
642  if (unlikely(tx == NULL)) {
644  }
645  lasttx = tx;
646  tx->tx_data.updated_tc = true;
647  if (state->command == FTP_COMMAND_UNKNOWN) {
648  /* unknown */
649  tx->command_descriptor.command_code = FTP_COMMAND_UNKNOWN;
650  }
651 
652  state->curr_tx = tx;
653  uint16_t dyn_port;
654  switch (state->command) {
655  case FTP_COMMAND_AUTH_TLS:
656  if (line.len >= 4 && SCMemcmp("234 ", line.buf, 4) == 0) {
658  }
659  break;
660 
661  case FTP_COMMAND_EPRT:
662  dyn_port = SCFTPParsePortEprt(state->port_line, state->port_line_len);
663  if (dyn_port == 0) {
664  goto tx_complete;
665  }
666  state->dyn_port = dyn_port;
667  state->active = true;
668  tx->dyn_port = dyn_port;
669  tx->active = true;
670  SCLogDebug("FTP active mode (v6): dynamic port %" PRIu16 "", dyn_port);
671  break;
672 
673  case FTP_COMMAND_PORT:
674  dyn_port = SCFTPParsePort(state->port_line, state->port_line_len);
675  if (dyn_port == 0) {
676  goto tx_complete;
677  }
678  state->dyn_port = dyn_port;
679  state->active = true;
680  tx->dyn_port = state->dyn_port;
681  tx->active = true;
682  SCLogDebug("FTP active mode (v4): dynamic port %" PRIu16 "", dyn_port);
683  break;
684 
685  case FTP_COMMAND_PASV:
686  if (line.len >= 4 && SCMemcmp("227 ", line.buf, 4) == 0) {
687  FTPParsePassiveResponse(ftp_state, line.buf, line.len);
688  }
689  break;
690 
691  case FTP_COMMAND_EPSV:
692  if (line.len >= 4 && SCMemcmp("229 ", line.buf, 4) == 0) {
693  FTPParsePassiveResponseV6(ftp_state, line.buf, line.len);
694  }
695  break;
696  default:
697  break;
698  }
699 
700  if (likely(line.len)) {
701  FTPResponseLine *response = SCFTPParseResponseLine((const char *)line.buf, line.len);
702  if (likely(response)) {
703  FTPResponseWrapper *wrapper = FTPResponseWrapperAlloc(response);
704  if (likely(wrapper)) {
705  response->truncated = state->current_line_truncated_tc;
706  if (response->truncated) {
708  &tx->tx_data.events, FtpEventResponseCommandTooLong);
709  }
710  if (line.lf_found) {
711  state->current_line_truncated_tc = false;
712  }
713  TAILQ_INSERT_TAIL(&tx->response_list, wrapper, next);
714  } else {
715  SCFTPFreeResponseLine(response);
716  }
717  } else {
718  SCLogDebug("unable to parse FTP response line \"%s\"", line.buf);
719  }
720  }
721 
722  /* Handle preliminary replies -- keep tx open */
723  if (FTPIsPPR(line.buf, line.len)) {
724  continue;
725  }
726  tx_complete:
727  tx->done = true;
728 
729  if (line.len >= ftp_max_line_len) {
730  ftpi.consumed = ftpi.len + 1;
731  break;
732  }
733  }
734 
736 }
737 
738 
739 #ifdef DEBUG
740 static SCMutex ftp_state_mem_lock = SCMUTEX_INITIALIZER;
741 static uint64_t ftp_state_memuse = 0;
742 static uint64_t ftp_state_memcnt = 0;
743 #endif
744 
745 static void *FTPStateAlloc(void *orig_state, AppProto proto_orig)
746 {
747  void *s = FTPCalloc(1, sizeof(FtpState));
748  if (unlikely(s == NULL))
749  return NULL;
750 
751  FtpState *ftp_state = (FtpState *) s;
752  TAILQ_INIT(&ftp_state->tx_list);
753 
754 #ifdef DEBUG
755  SCMutexLock(&ftp_state_mem_lock);
756  ftp_state_memcnt++;
757  ftp_state_memuse+=sizeof(FtpState);
758  SCMutexUnlock(&ftp_state_mem_lock);
759 #endif
760  return s;
761 }
762 
763 static void FTPStateFree(void *s)
764 {
765  FtpState *fstate = (FtpState *) s;
766  if (fstate->port_line != NULL)
767  FTPFree(fstate->port_line, fstate->port_line_size);
768 
769  FTPTransaction *tx = NULL;
770  while ((tx = TAILQ_FIRST(&fstate->tx_list))) {
771  TAILQ_REMOVE(&fstate->tx_list, tx, next);
772 #ifdef DEBUG
773  if (SCLogDebugEnabled()) {
774  const char *command_name = NULL;
775  (void)SCGetFtpCommandInfo(
776  tx->command_descriptor.command_index, &command_name, NULL, NULL);
777  SCLogDebug("[%s] state %p id %" PRIu64 ", Freeing %d bytes at %p",
778  command_name != NULL ? command_name : "n/a", s, tx->tx_id, tx->request_length,
779  tx->request);
780  }
781 #endif
782 
783  FTPTransactionFree(tx);
784  }
785 
786  FTPFree(s, sizeof(FtpState));
787 #ifdef DEBUG
788  SCMutexLock(&ftp_state_mem_lock);
789  ftp_state_memcnt--;
790  ftp_state_memuse-=sizeof(FtpState);
791  SCMutexUnlock(&ftp_state_mem_lock);
792 #endif
793 }
794 
795 /**
796  * \brief This function returns the oldest open transaction; if none
797  * are open, then the oldest transaction is returned
798  * \param ftp_state the ftp state structure for the parser
799  * \param starttx the ftp transaction where to start looking
800  *
801  * \retval transaction pointer when a transaction was found; NULL otherwise.
802  */
803 static FTPTransaction *FTPGetOldestTx(const FtpState *ftp_state, FTPTransaction *starttx)
804 {
805  if (unlikely(!ftp_state)) {
806  SCLogDebug("NULL state object; no transactions available");
807  return NULL;
808  }
809  FTPTransaction *tx = starttx;
810  FTPTransaction *lasttx = NULL;
811  while(tx != NULL) {
812  /* Return oldest open tx */
813  if (!tx->done) {
814  SCLogDebug("Returning tx %p id %"PRIu64, tx, tx->tx_id);
815  return tx;
816  }
817  /* save for the end */
818  lasttx = tx;
819  tx = TAILQ_NEXT(tx, next);
820  }
821  /* All tx are closed; return last element */
822  if (lasttx)
823  SCLogDebug("Returning OLDEST tx %p id %"PRIu64, lasttx, lasttx->tx_id);
824  return lasttx;
825 }
826 
827 static void *FTPGetTx(void *state, uint64_t tx_id)
828 {
829  FtpState *ftp_state = (FtpState *)state;
830  if (ftp_state) {
831  FTPTransaction *tx = NULL;
832 
833  if (ftp_state->curr_tx == NULL)
834  return NULL;
835  if (ftp_state->curr_tx->tx_id == tx_id)
836  return ftp_state->curr_tx;
837 
838  TAILQ_FOREACH(tx, &ftp_state->tx_list, next) {
839  if (tx->tx_id == tx_id)
840  return tx;
841  }
842  }
843  return NULL;
844 }
845 
846 static AppLayerTxData *FTPGetTxData(void *vtx)
847 {
848  FTPTransaction *tx = (FTPTransaction *)vtx;
849  return &tx->tx_data;
850 }
851 
852 static AppLayerStateData *FTPGetStateData(void *vstate)
853 {
854  FtpState *s = (FtpState *)vstate;
855  return &s->state_data;
856 }
857 
858 static void FTPStateTransactionFree(void *state, uint64_t tx_id)
859 {
860  FtpState *ftp_state = state;
861  FTPTransaction *tx = NULL;
862  TAILQ_FOREACH(tx, &ftp_state->tx_list, next) {
863  if (tx_id < tx->tx_id)
864  break;
865  else if (tx_id > tx->tx_id)
866  continue;
867 
868  if (tx == ftp_state->curr_tx)
869  ftp_state->curr_tx = NULL;
870  TAILQ_REMOVE(&ftp_state->tx_list, tx, next);
871  FTPTransactionFree(tx);
872  break;
873  }
874 }
875 
876 static uint64_t FTPGetTxCnt(void *state)
877 {
878  uint64_t cnt = 0;
879  FtpState *ftp_state = state;
880  if (ftp_state) {
881  cnt = ftp_state->tx_cnt;
882  }
883  SCLogDebug("returning state %p %"PRIu64, state, cnt);
884  return cnt;
885 }
886 
887 static int FTPGetAlstateProgress(void *vtx, uint8_t direction)
888 {
889  SCLogDebug("tx %p", vtx);
890  FTPTransaction *tx = vtx;
891 
892  /* having a tx implies request side is done */
893  if (direction == STREAM_TOSERVER) {
894  return FTP_STATE_FINISHED;
895  }
896  if (!tx->done) {
897  return FTP_STATE_IN_PROGRESS;
898  }
899 
900  return FTP_STATE_FINISHED;
901 }
902 
903 static AppProto FTPUserProbingParser(
904  Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir)
905 {
906  if (f->alproto_tc == ALPROTO_POP3) {
907  // POP traffic begins by same "USER" pattern as FTP
908  return ALPROTO_FAILED;
909  }
910  return ALPROTO_FTP;
911 }
912 
913 static AppProto FTPServerProbingParser(
914  Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir)
915 {
916  // another check for minimum length
917  if (len < 5) {
918  return ALPROTO_UNKNOWN;
919  }
920  // begins by 220
921  if (input[0] != '2' || input[1] != '2' || input[2] != '0') {
922  return ALPROTO_FAILED;
923  }
924  // followed by space or hypen
925  if (input[3] != ' ' && input[3] != '-') {
926  return ALPROTO_FAILED;
927  }
928  if (f->alproto_ts == ALPROTO_FTP || (f->todstbytecnt > 4 && f->alproto_ts == ALPROTO_UNKNOWN)) {
929  // only validates FTP if client side was FTP
930  // or if client side is unknown despite having received bytes
931  if (memchr(input + 4, '\n', len - 4) != NULL) {
932  return ALPROTO_FTP;
933  }
934  }
935  return ALPROTO_UNKNOWN;
936 }
937 
938 static int FTPRegisterPatternsForProtocolDetection(void)
939 {
941  IPPROTO_TCP, ALPROTO_FTP, "220 (", 5, 0, STREAM_TOCLIENT) < 0) {
942  return -1;
943  }
945  IPPROTO_TCP, ALPROTO_FTP, "FEAT", 4, 0, STREAM_TOSERVER) < 0) {
946  return -1;
947  }
948  if (AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_FTP, "USER ", 5, 0,
949  STREAM_TOSERVER, FTPUserProbingParser, 5, 5) < 0) {
950  return -1;
951  }
953  IPPROTO_TCP, ALPROTO_FTP, "PASS ", 5, 0, STREAM_TOSERVER) < 0) {
954  return -1;
955  }
957  IPPROTO_TCP, ALPROTO_FTP, "PORT ", 5, 0, STREAM_TOSERVER) < 0) {
958  return -1;
959  }
960  // Only check FTP on known ports as the banner has nothing special beyond
961  // the response code shared with SMTP.
963  "tcp", IPPROTO_TCP, "ftp", ALPROTO_FTP, 0, 5, NULL, FTPServerProbingParser)) {
964  // STREAM_TOSERVER here means use 21 as flow destination port
965  // and NULL, FTPServerProbingParser means use probing parser to client
966  AppLayerProtoDetectPPRegister(IPPROTO_TCP, "21", ALPROTO_FTP, 0, 5, STREAM_TOSERVER, NULL,
967  FTPServerProbingParser);
968  }
969  return 0;
970 }
971 
972 
974 
975 /**
976  * \brief This function is called to retrieve a ftp request
977  * \param ftp_state the ftp state structure for the parser
978  * \param output the resulting output
979  *
980  * \retval 1 when the command is parsed, 0 otherwise
981  */
982 static AppLayerResult FTPDataParse(Flow *f, FtpDataState *ftpdata_state,
983  AppLayerParserState *pstate, StreamSlice stream_slice, void *local_data, uint8_t direction)
984 {
985  const uint8_t *input = StreamSliceGetData(&stream_slice);
986  uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
987  const bool eof = (direction & STREAM_TOSERVER)
990 
991  SCTxDataUpdateFileFlags(&ftpdata_state->tx_data, ftpdata_state->state_data.file_flags);
992  if (ftpdata_state->tx_data.file_tx == 0)
993  ftpdata_state->tx_data.file_tx = direction & (STREAM_TOSERVER | STREAM_TOCLIENT);
994  if (direction & STREAM_TOSERVER) {
995  ftpdata_state->tx_data.updated_ts = true;
996  } else {
997  ftpdata_state->tx_data.updated_tc = true;
998  }
999  /* we depend on detection engine for file pruning */
1000  const uint16_t flags = FileFlowFlagsToFlags(ftpdata_state->tx_data.file_flags, direction);
1001  int ret = 0;
1002 
1003  SCLogDebug("FTP-DATA input_len %u flags %04x dir %d/%s EOF %s", input_len, flags, direction,
1004  (direction & STREAM_TOSERVER) ? "toserver" : "toclient", eof ? "true" : "false");
1005 
1006  SCLogDebug("FTP-DATA flags %04x dir %d", flags, direction);
1007  if (input_len && ftpdata_state->files == NULL) {
1008  FtpTransferCmd *data =
1009  (FtpTransferCmd *)FlowGetStorageById(f, AppLayerExpectationGetFlowId());
1010  if (data == NULL) {
1012  }
1013 
1014  /* we shouldn't get data in the wrong dir. Don't set things up for this dir */
1015  if ((direction & data->direction) == 0) {
1016  // TODO set event for data in wrong direction
1017  SCLogDebug("input %u not for our direction (%s): %s/%s", input_len,
1018  (direction & STREAM_TOSERVER) ? "toserver" : "toclient",
1019  data->cmd == FTP_COMMAND_STOR ? "STOR" : "RETR",
1020  (data->direction & STREAM_TOSERVER) ? "toserver" : "toclient");
1022  }
1023 
1024  ftpdata_state->files = FileContainerAlloc();
1025  if (ftpdata_state->files == NULL) {
1028  }
1029 
1030  ftpdata_state->file_name = data->file_name;
1031  ftpdata_state->file_len = data->file_len;
1032  data->file_name = NULL;
1033  data->file_len = 0;
1034  f->parent_id = data->flow_id;
1035  ftpdata_state->command = data->cmd;
1036  switch (data->cmd) {
1037  case FTP_COMMAND_STOR:
1038  ftpdata_state->direction = data->direction;
1039  SCLogDebug("STOR data to %s",
1040  (ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient");
1041  break;
1042  case FTP_COMMAND_RETR:
1043  ftpdata_state->direction = data->direction;
1044  SCLogDebug("RETR data to %s",
1045  (ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient");
1046  break;
1047  default:
1048  break;
1049  }
1050 
1051  /* open with fixed track_id 0 as we can have just one
1052  * file per ftp-data flow. */
1053  if (FileOpenFileWithId(ftpdata_state->files, &sbcfg,
1054  0ULL, (uint8_t *) ftpdata_state->file_name,
1055  ftpdata_state->file_len,
1056  input, input_len, flags) != 0) {
1057  SCLogDebug("Can't open file");
1058  ret = -1;
1059  }
1061  ftpdata_state->tx_data.files_opened = 1;
1062  } else {
1063  if (ftpdata_state->state == FTPDATA_STATE_FINISHED) {
1064  SCLogDebug("state is already finished");
1065  DEBUG_VALIDATE_BUG_ON(input_len); // data after state finished is a bug.
1067  }
1068  if ((direction & ftpdata_state->direction) == 0) {
1069  if (input_len) {
1070  // TODO set event for data in wrong direction
1071  }
1072  SCLogDebug("input %u not for us (%s): %s/%s", input_len,
1073  (direction & STREAM_TOSERVER) ? "toserver" : "toclient",
1074  ftpdata_state->command == FTP_COMMAND_STOR ? "STOR" : "RETR",
1075  (ftpdata_state->direction & STREAM_TOSERVER) ? "toserver" : "toclient");
1077  }
1078  if (input_len != 0) {
1079  ret = FileAppendData(ftpdata_state->files, &sbcfg, input, input_len);
1080  if (ret == -2) {
1081  ret = 0;
1082  SCLogDebug("FileAppendData() - file no longer being extracted");
1083  goto out;
1084  } else if (ret < 0) {
1085  SCLogDebug("FileAppendData() failed: %d", ret);
1086  ret = -2;
1087  goto out;
1088  }
1089  }
1090  }
1091 
1092  BUG_ON((direction & ftpdata_state->direction) == 0); // should be unreachable
1093  if (eof) {
1094  ret = FileCloseFile(ftpdata_state->files, &sbcfg, NULL, 0, flags);
1095  ftpdata_state->state = FTPDATA_STATE_FINISHED;
1096  SCLogDebug("closed because of eof: state now FTPDATA_STATE_FINISHED");
1097  }
1098 out:
1099  if (ret < 0) {
1101  }
1103 }
1104 
1105 static AppLayerResult FTPDataParseRequest(Flow *f, void *ftp_state, AppLayerParserState *pstate,
1106  StreamSlice stream_slice, void *local_data)
1107 {
1108  return FTPDataParse(f, ftp_state, pstate, stream_slice, local_data, STREAM_TOSERVER);
1109 }
1110 
1111 static AppLayerResult FTPDataParseResponse(Flow *f, void *ftp_state, AppLayerParserState *pstate,
1112  StreamSlice stream_slice, void *local_data)
1113 {
1114  return FTPDataParse(f, ftp_state, pstate, stream_slice, local_data, STREAM_TOCLIENT);
1115 }
1116 
1117 #ifdef DEBUG
1118 static SCMutex ftpdata_state_mem_lock = SCMUTEX_INITIALIZER;
1119 static uint64_t ftpdata_state_memuse = 0;
1120 static uint64_t ftpdata_state_memcnt = 0;
1121 #endif
1122 
1123 static void *FTPDataStateAlloc(void *orig_state, AppProto proto_orig)
1124 {
1125  void *s = FTPCalloc(1, sizeof(FtpDataState));
1126  if (unlikely(s == NULL))
1127  return NULL;
1128 
1129  FtpDataState *state = (FtpDataState *) s;
1130  state->state = FTPDATA_STATE_IN_PROGRESS;
1131 
1132 #ifdef DEBUG
1133  SCMutexLock(&ftpdata_state_mem_lock);
1134  ftpdata_state_memcnt++;
1135  ftpdata_state_memuse+=sizeof(FtpDataState);
1136  SCMutexUnlock(&ftpdata_state_mem_lock);
1137 #endif
1138  return s;
1139 }
1140 
1141 static void FTPDataStateFree(void *s)
1142 {
1143  FtpDataState *fstate = (FtpDataState *) s;
1144 
1145  SCAppLayerTxDataCleanup(&fstate->tx_data);
1146 
1147  if (fstate->file_name != NULL) {
1148  FTPFree(fstate->file_name, fstate->file_len + 1);
1149  }
1150 
1151  FileContainerFree(fstate->files, &sbcfg);
1152 
1153  FTPFree(s, sizeof(FtpDataState));
1154 #ifdef DEBUG
1155  SCMutexLock(&ftpdata_state_mem_lock);
1156  ftpdata_state_memcnt--;
1157  ftpdata_state_memuse-=sizeof(FtpDataState);
1158  SCMutexUnlock(&ftpdata_state_mem_lock);
1159 #endif
1160 }
1161 
1162 static AppLayerTxData *FTPDataGetTxData(void *vtx)
1163 {
1164  FtpDataState *ftp_state = (FtpDataState *)vtx;
1165  return &ftp_state->tx_data;
1166 }
1167 
1168 static AppLayerStateData *FTPDataGetStateData(void *vstate)
1169 {
1170  FtpDataState *ftp_state = (FtpDataState *)vstate;
1171  return &ftp_state->state_data;
1172 }
1173 
1174 static void FTPDataStateTransactionFree(void *state, uint64_t tx_id)
1175 {
1176  /* do nothing */
1177 }
1178 
1179 static void *FTPDataGetTx(void *state, uint64_t tx_id)
1180 {
1181  FtpDataState *ftp_state = (FtpDataState *)state;
1182  return ftp_state;
1183 }
1184 
1185 static uint64_t FTPDataGetTxCnt(void *state)
1186 {
1187  /* ftp-data is single tx */
1188  return 1;
1189 }
1190 
1191 static int FTPDataGetAlstateProgress(void *tx, uint8_t direction)
1192 {
1193  FtpDataState *ftpdata_state = (FtpDataState *)tx;
1194  if (direction == ftpdata_state->direction)
1195  return ftpdata_state->state;
1196  else
1197  return FTPDATA_STATE_FINISHED;
1198 }
1199 
1200 static AppLayerGetFileState FTPDataStateGetTxFiles(void *tx, uint8_t direction)
1201 {
1202  FtpDataState *ftpdata_state = (FtpDataState *)tx;
1203  AppLayerGetFileState files = { .fc = NULL, .cfg = &sbcfg };
1204 
1205  if (direction == ftpdata_state->direction)
1206  files.fc = ftpdata_state->files;
1207 
1208  return files;
1209 }
1210 
1211 static void FTPSetMpmState(void)
1212 {
1213  ftp_mpm_ctx = SCCalloc(1, sizeof(MpmCtx));
1214  if (unlikely(ftp_mpm_ctx == NULL)) {
1215  exit(EXIT_FAILURE);
1216  }
1217  MpmInitCtx(ftp_mpm_ctx, FTP_MPM);
1218 
1219  SCFTPSetMpmState(ftp_mpm_ctx);
1220  mpm_table[FTP_MPM].Prepare(NULL, ftp_mpm_ctx);
1221 }
1222 
1223 static void FTPFreeMpmState(void)
1224 {
1225  if (ftp_mpm_ctx != NULL) {
1226  mpm_table[FTP_MPM].DestroyCtx(ftp_mpm_ctx);
1227  SCFree(ftp_mpm_ctx);
1228  ftp_mpm_ctx = NULL;
1229  }
1230 }
1231 
1232 /** \brief FTP tx iterator, specialized for its linked list
1233  *
1234  * \retval txptr or NULL if no more txs in list
1235  */
1236 static AppLayerGetTxIterTuple FTPGetTxIterator(const uint8_t ipproto, const AppProto alproto,
1237  void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state)
1238 {
1239  FtpState *ftp_state = (FtpState *)alstate;
1240  AppLayerGetTxIterTuple no_tuple = { NULL, 0, false };
1241  if (ftp_state) {
1242  FTPTransaction *tx_ptr;
1243  if (state->un.ptr == NULL) {
1244  tx_ptr = TAILQ_FIRST(&ftp_state->tx_list);
1245  } else {
1246  tx_ptr = (FTPTransaction *)state->un.ptr;
1247  }
1248  if (tx_ptr) {
1249  while (tx_ptr->tx_id < min_tx_id) {
1250  tx_ptr = TAILQ_NEXT(tx_ptr, next);
1251  if (!tx_ptr) {
1252  return no_tuple;
1253  }
1254  }
1255  if (tx_ptr->tx_id >= max_tx_id) {
1256  return no_tuple;
1257  }
1258  state->un.ptr = TAILQ_NEXT(tx_ptr, next);
1259  AppLayerGetTxIterTuple tuple = {
1260  .tx_ptr = tx_ptr,
1261  .tx_id = tx_ptr->tx_id,
1262  .has_next = (state->un.ptr != NULL),
1263  };
1264  return tuple;
1265  }
1266  }
1267  return no_tuple;
1268 }
1269 
1271 {
1272  const char *proto_name = "ftp";
1273  const char *proto_data_name = "ftp-data";
1274 
1275  /** FTP */
1276  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
1278  if (FTPRegisterPatternsForProtocolDetection() < 0 )
1279  return;
1281  }
1282 
1283  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
1284  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_FTP, STREAM_TOSERVER,
1285  FTPParseRequest);
1286  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_FTP, STREAM_TOCLIENT,
1287  FTPParseResponse);
1288  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTP, FTPStateAlloc, FTPStateFree);
1289  AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_FTP, STREAM_TOSERVER | STREAM_TOCLIENT);
1290 
1291  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTP, FTPStateTransactionFree);
1292 
1293  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTP, FTPGetTx);
1294  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxData);
1295  AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxIterator);
1296  AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetStateData);
1297 
1298  AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_FTP, FTPLocalStorageAlloc,
1299  FTPLocalStorageFree);
1300  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxCnt);
1301 
1302  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetAlstateProgress);
1303 
1305  ALPROTO_FTP, FTP_STATE_FINISHED, FTP_STATE_FINISHED);
1306 
1308  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_FTPDATA, STREAM_TOSERVER,
1309  FTPDataParseRequest);
1310  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_FTPDATA, STREAM_TOCLIENT,
1311  FTPDataParseResponse);
1312  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateAlloc, FTPDataStateFree);
1313  AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP, ALPROTO_FTPDATA, STREAM_TOSERVER | STREAM_TOCLIENT);
1314  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateTransactionFree);
1315 
1316  AppLayerParserRegisterGetTxFilesFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateGetTxFiles);
1317 
1318  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTx);
1319  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTxData);
1320  AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetStateData);
1321 
1322  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTxCnt);
1323 
1324  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetAlstateProgress);
1325 
1327  ALPROTO_FTPDATA, FTPDATA_STATE_FINISHED, FTPDATA_STATE_FINISHED);
1328 
1329  AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_FTP, ftp_get_event_info);
1330  AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_FTP, ftp_get_event_info_by_id);
1331 
1334 
1335  sbcfg.buf_size = 4096;
1336  sbcfg.Calloc = FTPCalloc;
1337  sbcfg.Realloc = FTPRealloc;
1338  sbcfg.Free = FTPFree;
1339 
1340  FTPParseMemcap();
1341  } else {
1342  SCLogInfo("Parser disabled for %s protocol. Protocol detection still on.", proto_name);
1343  }
1344 
1345  FTPSetMpmState();
1346 
1347 #ifdef UNITTESTS
1349 #endif
1350 }
1351 
1352 /*
1353  * \brief Returns the ending offset of the next line from a multi-line buffer.
1354  *
1355  * "Buffer" refers to a FTP response in a single buffer containing multiple lines.
1356  * Here, "next line" is defined as terminating on
1357  * - Newline character
1358  * - Null character
1359  *
1360  * \param buffer Contains zero or more characters.
1361  * \param len Size, in bytes, of buffer.
1362  *
1363  * \retval Offset from the start of buffer indicating the where the
1364  * next "line ends". The characters between the input buffer and this
1365  * value comprise the line.
1366  *
1367  * NULL is found first or a newline isn't found, then UINT16_MAX is returned.
1368  */
1369 uint16_t JsonGetNextLineFromBuffer(const char *buffer, const uint16_t len)
1370 {
1371  if (!buffer || *buffer == '\0') {
1372  return UINT16_MAX;
1373  }
1374 
1375  char *c = strchr(buffer, '\n');
1376  return c == NULL ? len : (uint16_t)(c - buffer + 1);
1377 }
1378 
1379 bool EveFTPDataAddMetadata(void *vtx, SCJsonBuilder *jb)
1380 {
1381  const FtpDataState *ftp_state = (FtpDataState *)vtx;
1382  SCJbOpenObject(jb, "ftp_data");
1383 
1384  if (ftp_state->file_name) {
1385  SCJbSetStringFromBytes(jb, "filename", ftp_state->file_name, ftp_state->file_len);
1386  }
1387  switch (ftp_state->command) {
1388  case FTP_COMMAND_STOR:
1389  JB_SET_STRING(jb, "command", "STOR");
1390  break;
1391  case FTP_COMMAND_RETR:
1392  JB_SET_STRING(jb, "command", "RETR");
1393  break;
1394  default:
1395  break;
1396  }
1397  SCJbClose(jb);
1398  return true;
1399 }
1400 
1401 /**
1402  * \brief Free memory allocated for global FTP parser state.
1403  */
1405 {
1406  FTPFreeMpmState();
1407 }
1408 
1409 /* UNITTESTS */
1410 #ifdef UNITTESTS
1411 #include "stream-tcp.h"
1412 
1413 /** \test Send a get request in one chunk. */
1414 static int FTPParserTest01(void)
1415 {
1416  Flow f;
1417  uint8_t ftpbuf[] = "PORT 192,168,1,1,0,80\r\n";
1418  uint32_t ftplen = sizeof(ftpbuf) - 1; /* minus the \0 */
1419  TcpSession ssn;
1421 
1422  memset(&f, 0, sizeof(f));
1423  memset(&ssn, 0, sizeof(ssn));
1424 
1425  f.protoctx = (void *)&ssn;
1426  f.proto = IPPROTO_TCP;
1427  f.alproto = ALPROTO_FTP;
1428 
1429  StreamTcpInitConfig(true);
1430 
1431  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1432  STREAM_TOSERVER | STREAM_EOF, ftpbuf, ftplen);
1433  FAIL_IF(r != 0);
1434 
1435  FtpState *ftp_state = f.alstate;
1436  FAIL_IF_NULL(ftp_state);
1437  FAIL_IF(ftp_state->command != FTP_COMMAND_PORT);
1438 
1440  StreamTcpFreeConfig(true);
1441  PASS;
1442 }
1443 
1444 /** \test Supply RETR without a filename */
1445 static int FTPParserTest11(void)
1446 {
1447  Flow f;
1448  uint8_t ftpbuf1[] = "PORT 192,168,1,1,0,80\r\n";
1449  uint8_t ftpbuf2[] = "RETR\r\n";
1450  uint8_t ftpbuf3[] = "227 OK\r\n";
1451  TcpSession ssn;
1452 
1454 
1455  memset(&f, 0, sizeof(f));
1456  memset(&ssn, 0, sizeof(ssn));
1457 
1458  f.protoctx = (void *)&ssn;
1459  f.proto = IPPROTO_TCP;
1460  f.alproto = ALPROTO_FTP;
1461 
1462  StreamTcpInitConfig(true);
1463 
1464  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1465  STREAM_TOSERVER | STREAM_START, ftpbuf1,
1466  sizeof(ftpbuf1) - 1);
1467  FAIL_IF(r != 0);
1468 
1469  /* Response */
1470  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1471  STREAM_TOCLIENT,
1472  ftpbuf3,
1473  sizeof(ftpbuf3) - 1);
1474  FAIL_IF(r != 0);
1475 
1476  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1477  STREAM_TOSERVER, ftpbuf2,
1478  sizeof(ftpbuf2) - 1);
1479  FAIL_IF(r == 0);
1480 
1481  FtpState *ftp_state = f.alstate;
1482  FAIL_IF_NULL(ftp_state);
1483 
1484  FAIL_IF(ftp_state->command != FTP_COMMAND_RETR);
1485 
1487  StreamTcpFreeConfig(true);
1488  PASS;
1489 }
1490 
1491 /** \test Supply STOR without a filename */
1492 static int FTPParserTest12(void)
1493 {
1494  Flow f;
1495  uint8_t ftpbuf1[] = "PORT 192,168,1,1,0,80\r\n";
1496  uint8_t ftpbuf2[] = "STOR\r\n";
1497  uint8_t ftpbuf3[] = "227 OK\r\n";
1498  TcpSession ssn;
1499 
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_START, ftpbuf1,
1513  sizeof(ftpbuf1) - 1);
1514  FAIL_IF(r != 0);
1515 
1516  /* Response */
1517  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1518  STREAM_TOCLIENT,
1519  ftpbuf3,
1520  sizeof(ftpbuf3) - 1);
1521  FAIL_IF(r != 0);
1522 
1523  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1524  STREAM_TOSERVER, ftpbuf2,
1525  sizeof(ftpbuf2) - 1);
1526  FAIL_IF(r == 0);
1527 
1528  FtpState *ftp_state = f.alstate;
1529  FAIL_IF_NULL(ftp_state);
1530 
1531  FAIL_IF(ftp_state->command != FTP_COMMAND_STOR);
1532 
1534  StreamTcpFreeConfig(true);
1535  PASS;
1536 }
1537 #endif /* UNITTESTS */
1538 
1540 {
1541 #ifdef UNITTESTS
1542  UtRegisterTest("FTPParserTest01", FTPParserTest01);
1543  UtRegisterTest("FTPParserTest11", FTPParserTest11);
1544  UtRegisterTest("FTPParserTest12", FTPParserTest12);
1545 #endif /* UNITTESTS */
1546 }
1547 
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:69
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:499
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:1567
len
uint8_t len
Definition: app-layer-dnp3.h:2
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
FTPTransaction_::request
uint8_t * request
Definition: app-layer-ftp.h:68
AppLayerGetTxIterState::ptr
void * ptr
Definition: app-layer-parser.h:123
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:1668
FTPThreadCtx_
Definition: app-layer-ftp.c:41
StreamingBufferConfig_::buf_size
uint32_t buf_size
Definition: util-streaming-buffer.h:66
AppLayerParserRegisterLocalStorageFunc
void AppLayerParserRegisterLocalStorageFunc(uint8_t ipproto, AppProto alproto, void *(*LocalStorageAlloc)(void), void(*LocalStorageFree)(void *))
Definition: app-layer-parser.c:459
TAILQ_INIT
#define TAILQ_INIT(head)
Definition: queue.h:262
FtpState_::active
bool active
Definition: app-layer-ftp.h:88
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:314
FileContainerAlloc
FileContainer * FileContainerAlloc(void)
allocate a FileContainer
Definition: util-file.c:497
FtpDataState_::state
uint8_t state
Definition: app-layer-ftp.h:116
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:1854
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
EveFTPDataAddMetadata
bool EveFTPDataAddMetadata(void *vtx, SCJsonBuilder *jb)
Definition: app-layer-ftp.c:1379
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
FtpCommandInfo_
Definition: app-layer-ftp.h:55
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
Flow_::proto
uint8_t proto
Definition: flow.h:378
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:85
FtpState_::command
FtpRequestCommand command
Definition: app-layer-ftp.h:97
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:343
ALPROTO_POP3
@ ALPROTO_POP3
Definition: app-layer-protos.h:71
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:356
FTPTransaction_::done
bool done
Definition: app-layer-ftp.h:75
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:547
AppLayerParserRegisterParserAcceptableDataDirection
void AppLayerParserRegisterParserAcceptableDataDirection(uint8_t ipproto, AppProto alproto, uint8_t direction)
Definition: app-layer-parser.c:413
FtpState_::current_line_truncated_tc
bool current_line_truncated_tc
Definition: app-layer-ftp.h:95
AppLayerParserRegisterTxFreeFunc
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))
Definition: app-layer-parser.c:509
FTPTransaction_::tx_data
AppLayerTxData tx_data
Definition: app-layer-ftp.h:64
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
FtpDataState_::command
FtpRequestCommand command
Definition: app-layer-ftp.h:115
FTPMemuseGlobalCounter
uint64_t FTPMemuseGlobalCounter(void)
Definition: app-layer-ftp.c:77
AppLayerParserThreadCtxFree
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
Definition: app-layer-parser.c:322
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
rust.h
MIN
#define MIN(x, y)
Definition: suricata-common.h:408
FtpLineState_::buf
const uint8_t * buf
Definition: app-layer-ftp.h:38
ALPROTO_FTP
@ ALPROTO_FTP
Definition: app-layer-protos.h:37
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:121
FtpDataState_::file_len
int16_t file_len
Definition: app-layer-ftp.h:114
TAILQ_INSERT_TAIL
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:294
FTPResponseWrapper_
Definition: app-layer-ftp.h:44
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:441
FtpDataState_::direction
uint8_t direction
Definition: app-layer-ftp.h:117
FtpInput_::len
int32_t len
Definition: app-layer-ftp.c:263
SC_ELIMIT
@ SC_ELIMIT
Definition: util-error.h:31
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:1404
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:1527
ftp_max_line_len
uint32_t ftp_max_line_len
Definition: app-layer-ftp.c:52
FtpState_
Definition: app-layer-ftp.h:87
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
APP_LAYER_INCOMPLETE
#define APP_LAYER_INCOMPLETE(c, n)
Definition: app-layer-parser.h:75
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:101
AppLayerParserState_
Definition: app-layer-parser.c:133
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
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:90
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
FtpDataState_::state_data
AppLayerStateData state_data
Definition: app-layer-ftp.h:119
alp_tctx
AppLayerParserThreadCtx * alp_tctx
Definition: fuzz_applayerparserparse.c:22
AppLayerParserRegisterLogger
void AppLayerParserRegisterLogger(uint8_t ipproto, AppProto alproto)
Definition: app-layer-parser.c:490
util-print.h
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
AppLayerParserRegisterStateFuncs
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void *, AppProto), void(*StateFree)(void *))
Definition: app-layer-parser.c:434
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:1654
FtpLineState_::lf_found
bool lf_found
Definition: app-layer-ftp.h:41
app-layer-parser.h
Flow_::todstbytecnt
uint64_t todstbytecnt
Definition: flow.h:497
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:317
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:594
FtpState_::state_data
AppLayerStateData state_data
Definition: app-layer-ftp.h:105
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:1539
RegisterFTPParsers
void RegisterFTPParsers(void)
Definition: app-layer-ftp.c:1270
FTPTransaction_::command_descriptor
FtpCommandInfo command_descriptor
Definition: app-layer-ftp.h:72
AppLayerParserRegisterProtocolUnittests
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
Definition: app-layer-parser.c:1839
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:121
FtpCommandInfo_::command_code
FtpRequestCommand command_code
Definition: app-layer-ftp.h:57
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:50
AppLayerRegisterExpectationProto
void AppLayerRegisterExpectationProto(uint8_t proto, AppProto alproto)
Definition: app-layer-detect-proto.c:2140
FTPResponseWrapper_::response
FTPResponseLine * response
Definition: app-layer-ftp.h:45
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:471
AppLayerProtoDetectRegisterProtocol
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
Definition: app-layer-detect-proto.c:1763
FtpDataState
struct FtpDataState_ FtpDataState
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:83
MpmTableElmt_::Search
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition: util-mpm.h:177
FtpInput
struct FtpInput_ FtpInput
FtpDataState_::tx_data
AppLayerTxData tx_data
Definition: app-layer-ftp.h:118
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:401
FtpInput_::orig_len
int32_t orig_len
Definition: app-layer-ftp.c:264
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:295
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:63
AppLayerTxData
struct AppLayerTxData AppLayerTxData
Definition: detect.h:1494
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:67
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
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:1290
FtpLineState_
Definition: app-layer-ftp.h:35
suricata-common.h
ftp_config_maxtx
uint32_t ftp_config_maxtx
Definition: app-layer-ftp.c:51
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:99
FtpState_::dyn_port
uint16_t dyn_port
Definition: app-layer-ftp.h:103
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:615
AppLayerParserRegisterTxDataFunc
void AppLayerParserRegisterTxDataFunc(uint8_t ipproto, AppProto alproto, AppLayerTxData *(*GetTxData)(void *tx))
Definition: app-layer-parser.c:605
Flow_::parent_id
int64_t parent_id
Definition: flow.h:430
FtpDataState_
Definition: app-layer-ftp.h:109
util-validate.h
StreamingBufferConfig_
Definition: util-streaming-buffer.h:65
FTPSetMemcap
int FTPSetMemcap(uint64_t size)
Definition: app-layer-ftp.c:89
FtpLineState_::delim_len
uint8_t delim_len
Definition: app-layer-ftp.h:40
AppLayerParserRegisterGetTxIterator
void AppLayerParserRegisterGetTxIterator(uint8_t ipproto, AppProto alproto, AppLayerGetTxIteratorFunc Func)
Definition: app-layer-parser.c:539
MpmTableElmt_::Prepare
int(* Prepare)(MpmConfig *, struct MpmCtx_ *)
Definition: util-mpm.h:174
MpmTableElmt_::DestroyCtx
void(* DestroyCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:154
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:1079
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Flow_::alproto_ts
AppProto alproto_ts
Definition: flow.h:451
Flow_::alstate
void * alstate
Definition: flow.h:479
StreamingBufferConfig_::Free
void(* Free)(void *ptr, size_t size)
Definition: util-streaming-buffer.h:71
FtpCommandInfo_::command_index
uint8_t command_index
Definition: app-layer-ftp.h:56
FtpState_::tx_cnt
uint64_t tx_cnt
Definition: app-layer-ftp.h:92
FtpState_::current_line_truncated_ts
bool current_line_truncated_ts
Definition: app-layer-ftp.h:94
sc_errno
thread_local SCError sc_errno
Definition: util-error.c: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
FtpLineState_::len
uint32_t len
Definition: app-layer-ftp.h:39
AppLayerParserRegisterGetTxCnt
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
Definition: app-layer-parser.c:519
APP_LAYER_ERROR
#define APP_LAYER_ERROR
Definition: app-layer-parser.h:67
FtpState_::port_line_size
uint32_t port_line_size
Definition: app-layer-ftp.h:100
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:62
FTPTransaction_::dyn_port
uint16_t dyn_port
Definition: app-layer-ftp.h:74
FTPTransaction_::active
bool active
Definition: app-layer-ftp.h:76
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:562
FtpDataState_::files
FileContainer * files
Definition: app-layer-ftp.h:112
likely
#define likely(expr)
Definition: util-optimize.h:32
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:58
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:93
TcpSession_
Definition: stream-tcp-private.h:283
JsonGetNextLineFromBuffer
uint16_t JsonGetNextLineFromBuffer(const char *buffer, const uint16_t len)
Definition: app-layer-ftp.c:1369
util-misc.h
FileFlowFlagsToFlags
uint16_t FileFlowFlagsToFlags(const uint16_t flow_file_flags, uint8_t direction)
Definition: util-file.c:233
FTPTransaction_
Definition: app-layer-ftp.h:60
FTPThreadCtx
struct FTPThreadCtx_ FTPThreadCtx
AppLayerParserStateIssetFlag
uint16_t AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint16_t flag)
Definition: app-layer-parser.c:1828
Flow_::alproto_tc
AppProto alproto_tc
Definition: flow.h:452
FtpInput_::buf
const uint8_t * buf
Definition: app-layer-ftp.c:261
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:450
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
SCMemcmp
#define SCMemcmp(a, b, c)
Definition: util-memcmp.h:290
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:1964
SCMutex
#define SCMutex
Definition: threads-debug.h:114
FTPThreadCtx_::ftp_mpm_thread_ctx
MpmThreadCtx * ftp_mpm_thread_ctx
Definition: app-layer-ftp.c:42
SCLogDebugEnabled
int SCLogDebugEnabled(void)
Returns whether debug messages are enabled to be logged or not.
Definition: util-debug.c:767
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:262
PmqSetup
int PmqSetup(PrefilterRuleStore *pmq)
Setup a pmq.
Definition: util-prefilter.c:37
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:111
FtpInput_
Definition: app-layer-ftp.c:260
AppLayerGetTxIterState::un
union AppLayerGetTxIterState::@7 un
app-layer.h
PrefilterRuleStore_::rule_id_array
SigIntId * rule_id_array
Definition: util-prefilter.h:38