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