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