suricata
app-layer-ftp.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2017 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  *
24  * App Layer Parser for FTP
25  */
26 
27 #include "suricata-common.h"
28 #include "debug.h"
29 #include "decode.h"
30 #include "threads.h"
31 
32 #include "util-print.h"
33 #include "util-pool.h"
34 
35 #include "flow-util.h"
36 #include "flow-storage.h"
37 
38 #include "detect-engine-state.h"
39 
40 #include "stream-tcp-private.h"
41 #include "stream-tcp-reassemble.h"
42 #include "stream-tcp.h"
43 #include "stream.h"
44 
45 #include "app-layer.h"
46 #include "app-layer-protos.h"
47 #include "app-layer-parser.h"
48 #include "app-layer-ftp.h"
49 #include "app-layer-expectation.h"
50 
51 #include "util-spm.h"
52 #include "util-unittest.h"
53 #include "util-debug.h"
54 #include "util-memcmp.h"
55 #include "util-memrchr.h"
56 #include "util-byte.h"
57 #include "util-mem.h"
58 #include "util-misc.h"
59 
60 #ifdef HAVE_RUST
61 #include "rust-ftp-mod-gen.h"
62 #endif
63 
64 #include "output-json.h"
65 
66 uint64_t ftp_config_memcap = 0;
67 
68 SC_ATOMIC_DECLARE(uint64_t, ftp_memuse);
69 SC_ATOMIC_DECLARE(uint64_t, ftp_memcap);
70 
71 static void FTPParseMemcap(void)
72 {
73  const char *conf_val;
74 
75  /** set config values for memcap, prealloc and hash_size */
76  if ((ConfGet("app-layer.protocols.ftp.memcap", &conf_val)) == 1)
77  {
78  if (ParseSizeStringU64(conf_val, &ftp_config_memcap) < 0) {
79  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing ftp.memcap "
80  "from conf file - %s. Killing engine",
81  conf_val);
82  exit(EXIT_FAILURE);
83  }
84  SCLogInfo("FTP memcap: %"PRIu64, ftp_config_memcap);
85  } else {
86  /* default to unlimited */
88  }
89 
90  SC_ATOMIC_INIT(ftp_memuse);
91  SC_ATOMIC_INIT(ftp_memcap);
92 }
93 
94 static void FTPIncrMemuse(uint64_t size)
95 {
96  (void) SC_ATOMIC_ADD(ftp_memuse, size);
97  return;
98 }
99 
100 static void FTPDecrMemuse(uint64_t size)
101 {
102  (void) SC_ATOMIC_SUB(ftp_memuse, size);
103  return;
104 }
105 
107 {
108  uint64_t tmpval = SC_ATOMIC_GET(ftp_memuse);
109  return tmpval;
110 }
111 
113 {
114  uint64_t tmpval = SC_ATOMIC_GET(ftp_memcap);
115  return tmpval;
116 }
117 
118 /**
119  * \brief Check if alloc'ing "size" would mean we're over memcap
120  *
121  * \retval 1 if in bounds
122  * \retval 0 if not in bounds
123  */
124 static int FTPCheckMemcap(uint64_t size)
125 {
126  if (ftp_config_memcap == 0 || size + SC_ATOMIC_GET(ftp_memuse) <= ftp_config_memcap)
127  return 1;
128  (void) SC_ATOMIC_ADD(ftp_memcap, 1);
129  return 0;
130 }
131 
132 static void *FTPMalloc(size_t size)
133 {
134  void *ptr = NULL;
135 
136  if (FTPCheckMemcap((uint32_t)size) == 0)
137  return NULL;
138 
139  ptr = SCMalloc(size);
140 
141  if (unlikely(ptr == NULL))
142  return NULL;
143 
144  FTPIncrMemuse((uint64_t)size);
145 
146  return ptr;
147 }
148 
149 static void *FTPCalloc(size_t n, size_t size)
150 {
151  void *ptr = NULL;
152 
153  if (FTPCheckMemcap((uint32_t)(n * size)) == 0)
154  return NULL;
155 
156  ptr = SCCalloc(n, size);
157 
158  if (unlikely(ptr == NULL))
159  return NULL;
160 
161  FTPIncrMemuse((uint64_t)(n * size));
162 
163  return ptr;
164 }
165 
166 static void *FTPRealloc(void *ptr, size_t orig_size, size_t size)
167 {
168  void *rptr = NULL;
169 
170  if (FTPCheckMemcap((uint32_t)(size - orig_size)) == 0)
171  return NULL;
172 
173  rptr = SCRealloc(ptr, size);
174  if (rptr == NULL)
175  return NULL;
176 
177  if (size > orig_size) {
178  FTPIncrMemuse(size - orig_size);
179  } else {
180  FTPDecrMemuse(orig_size - size);
181  }
182 
183  return rptr;
184 }
185 
186 static void FTPFree(void *ptr, size_t size)
187 {
188  SCFree(ptr);
189 
190  FTPDecrMemuse((uint64_t)size);
191 }
192 
193 static int FTPGetLineForDirection(FtpState *state, FtpLineState *line_state)
194 {
195  void *ptmp;
196  if (line_state->current_line_lf_seen == 1) {
197  /* we have seen the lf for the previous line. Clear the parser
198  * details to parse new line */
199  line_state->current_line_lf_seen = 0;
200  if (line_state->current_line_db == 1) {
201  line_state->current_line_db = 0;
202  FTPFree(line_state->db, line_state->db_len);
203  line_state->db = NULL;
204  line_state->db_len = 0;
205  state->current_line = NULL;
206  state->current_line_len = 0;
207  }
208  }
209 
210  uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
211 
212  if (lf_idx == NULL) {
213  /* fragmented lines. Decoder event for special cases. Not all
214  * fragmented lines should be treated as a possible evasion
215  * attempt. With multi payload ftp chunks we can have valid
216  * cases of fragmentation. But within the same segment chunk
217  * if we see fragmentation then it's definitely something you
218  * should alert about */
219  if (line_state->current_line_db == 0) {
220  line_state->db = FTPMalloc(state->input_len);
221  if (line_state->db == NULL) {
222  return -1;
223  }
224  line_state->current_line_db = 1;
225  memcpy(line_state->db, state->input, state->input_len);
226  line_state->db_len = state->input_len;
227  } else {
228  ptmp = FTPRealloc(line_state->db, line_state->db_len,
229  (line_state->db_len + state->input_len));
230  if (ptmp == NULL) {
231  FTPFree(line_state->db, line_state->db_len);
232  line_state->db = NULL;
233  line_state->db_len = 0;
234  return -1;
235  }
236  line_state->db = ptmp;
237 
238  memcpy(line_state->db + line_state->db_len,
239  state->input, state->input_len);
240  line_state->db_len += state->input_len;
241  }
242  state->input += state->input_len;
243  state->input_len = 0;
244 
245  return -1;
246 
247  } else {
248  line_state->current_line_lf_seen = 1;
249 
250  if (line_state->current_line_db == 1) {
251  ptmp = FTPRealloc(line_state->db, line_state->db_len,
252  (line_state->db_len + (lf_idx + 1 - state->input)));
253  if (ptmp == NULL) {
254  FTPFree(line_state->db, line_state->db_len);
255  line_state->db = NULL;
256  line_state->db_len = 0;
257  return -1;
258  }
259  line_state->db = ptmp;
260 
261  memcpy(line_state->db + line_state->db_len,
262  state->input, (lf_idx + 1 - state->input));
263  line_state->db_len += (lf_idx + 1 - state->input);
264 
265  if (line_state->db_len > 1 &&
266  line_state->db[line_state->db_len - 2] == 0x0D) {
267  line_state->db_len -= 2;
268  state->current_line_delimiter_len = 2;
269  } else {
270  line_state->db_len -= 1;
271  state->current_line_delimiter_len = 1;
272  }
273 
274  state->current_line = line_state->db;
275  state->current_line_len = line_state->db_len;
276 
277  } else {
278  state->current_line = state->input;
279  state->current_line_len = lf_idx - state->input;
280 
281  if (state->input != lf_idx &&
282  *(lf_idx - 1) == 0x0D) {
283  state->current_line_len--;
284  state->current_line_delimiter_len = 2;
285  } else {
286  state->current_line_delimiter_len = 1;
287  }
288  }
289 
290  state->input_len -= (lf_idx - state->input) + 1;
291  state->input = (lf_idx + 1);
292 
293  return 0;
294  }
295 
296 }
297 
298 static int FTPGetLine(FtpState *state)
299 {
300  SCEnter();
301 
302  /* we have run out of input */
303  if (state->input_len <= 0)
304  return -1;
305 
306  /* toserver */
307  if (state->direction == 0)
308  return FTPGetLineForDirection(state, &state->line_state[0]);
309  else
310  return FTPGetLineForDirection(state, &state->line_state[1]);
311 }
312 
313 /**
314  * \brief This function is called to determine and set which command is being
315  * transfered to the ftp server
316  * \param ftp_state the ftp state structure for the parser
317  * \param input input line of the command
318  * \param len of the command
319  *
320  * \retval 1 when the command is parsed, 0 otherwise
321  */
322 static int FTPParseRequestCommand(void *ftp_state, uint8_t *input,
323  uint32_t input_len)
324 {
325  SCEnter();
326  FtpState *fstate = (FtpState *)ftp_state;
327  fstate->command = FTP_COMMAND_UNKNOWN;
328 
329  if (input_len >= 4 && SCMemcmpLowercase("port", input, 4) == 0) {
330  fstate->command = FTP_COMMAND_PORT;
331  }
332 
333  if (input_len >= 4 && SCMemcmpLowercase("eprt", input, 4) == 0) {
334  fstate->command = FTP_COMMAND_EPRT;
335  }
336 
337  if (input_len >= 8 && SCMemcmpLowercase("auth tls", input, 8) == 0) {
338  fstate->command = FTP_COMMAND_AUTH_TLS;
339  }
340 
341  if (input_len >= 4 && SCMemcmpLowercase("pasv", input, 4) == 0) {
342  fstate->command = FTP_COMMAND_PASV;
343  }
344 
345  if (input_len > 5 && SCMemcmpLowercase("retr", input, 4) == 0) {
346  fstate->command = FTP_COMMAND_RETR;
347  }
348 
349  if (input_len >= 4 && SCMemcmpLowercase("epsv", input, 4) == 0) {
350  fstate->command = FTP_COMMAND_EPSV;
351  }
352 
353  if (input_len > 5 && SCMemcmpLowercase("stor", input, 4) == 0) {
354  fstate->command = FTP_COMMAND_STOR;
355  }
356 
357  return 1;
358 }
359 
361  /** Need to look like a ExpectationData so DFree must
362  * be first field . */
363  void (*DFree)(void *);
364  uint64_t flow_id;
365  uint8_t *file_name;
366  uint16_t file_len;
368 };
369 
370 static void FtpTransferCmdFree(void *data)
371 {
372  struct FtpTransferCmd *cmd = (struct FtpTransferCmd *) data;
373  if (cmd == NULL)
374  return;
375  if (cmd->file_name) {
376  FTPFree(cmd->file_name, cmd->file_len);
377  }
378  FTPFree(cmd, sizeof(struct FtpTransferCmd));
379 }
380 
381 static uint16_t ftp_validate_port(int computed_port_value)
382 {
383  unsigned int port_val = computed_port_value;
384 
385  if (port_val && port_val > UINT16_MAX)
386  return 0;
387 
388  return ((uint16_t) (port_val));
389 }
390 
391 /**
392  * \brief This function extracts a port number from the command input line for IPv6 FTP usage
393  * \param input input line of the command
394  * \param input_len length of the request
395  *
396  * \retval 0 if a port number could not be extracted; otherwise, the dynamic port number
397  */
398 static uint16_t FTPGetV6PortNumber(uint8_t *input, uint32_t input_len)
399 {
400  uint8_t *ptr = memrchr(input, '|', input_len);
401  if (ptr == NULL) {
402  return 0;
403  }
404 
405  int n_length = ptr - input - 1;
406  if (n_length < 4)
407  return 0;
408 
409  ptr = memrchr(input, '|', n_length);
410  if (ptr == NULL)
411  return 0;
412 
413  return ftp_validate_port(atoi((char *)ptr + 1));
414 }
415 
416 /**
417  * \brief This function extracts a port number from the command input line for IPv4 FTP usage
418  * \param input input line of the command
419  * \param input_len length of the request
420  *
421  * \retval 0 if a port number could not be extracted; otherwise, the dynamic port number
422  */
423 static uint16_t FTPGetV4PortNumber(uint8_t *input, uint32_t input_len)
424 {
425  uint16_t part1, part2;
426  uint8_t *ptr = memrchr(input, ',', input_len);
427  if (ptr == NULL)
428  return 0;
429 
430  part2 = atoi((char *)ptr + 1);
431  ptr = memrchr(input, ',', (ptr - input) - 1);
432  if (ptr == NULL)
433  return 0;
434  part1 = atoi((char *)ptr + 1);
435 
436  return ftp_validate_port(256 * part1 + part2);
437 }
438 
439 
440 /**
441  * \brief This function is called to retrieve a ftp request
442  * \param ftp_state the ftp state structure for the parser
443  * \param input input line of the command
444  * \param input_len length of the request
445  * \param output the resulting output
446  *
447  * \retval 1 when the command is parsed, 0 otherwise
448  */
449 static int FTPParseRequest(Flow *f, void *ftp_state,
450  AppLayerParserState *pstate,
451  uint8_t *input, uint32_t input_len,
452  void *local_data, const uint8_t flags)
453 {
454  SCEnter();
455  /* PrintRawDataFp(stdout, input,input_len); */
456 
457  FtpState *state = (FtpState *)ftp_state;
458  void *ptmp;
459 
460  if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
461  SCReturnInt(1);
462  } else if (input == NULL || input_len == 0) {
463  SCReturnInt(-1);
464  }
465 
466  state->input = input;
467  state->input_len = input_len;
468  /* toserver stream */
469  state->direction = 0;
470 
471  int direction = STREAM_TOSERVER;
472  while (FTPGetLine(state) >= 0) {
473  FTPParseRequestCommand(state,
474  state->current_line, state->current_line_len);
475  switch (state->command) {
476  case FTP_COMMAND_EPRT:
477  // fallthrough
478  case FTP_COMMAND_PORT:
479  if (state->current_line_len + 1 > state->port_line_size) {
480  /* Allocate an extra byte for a NULL terminator */
481  ptmp = FTPRealloc(state->port_line, state->port_line_size,
482  state->current_line_len + 1);
483  if (ptmp == NULL) {
484  if (state->port_line) {
485  FTPFree(state->port_line, state->port_line_size);
486  state->port_line = NULL;
487  state->port_line_size = 0;
488  }
489  return 0;
490  }
491  state->port_line = ptmp;
492  state->port_line_size = state->current_line_len + 1;
493  }
494  memcpy(state->port_line, state->current_line,
495  state->current_line_len);
496  state->port_line[state->current_line_len] = '\0';
497  state->port_line_len = state->current_line_len;
498  break;
499  case FTP_COMMAND_RETR:
500  /* change direction (default to server) so expectation will handle
501  * the correct message when expectation will match.
502  */
503  direction = STREAM_TOCLIENT;
504  // fallthrough
505  case FTP_COMMAND_STOR:
506  {
507  /* No dyn port negotiated so get out */
508  if (state->dyn_port == 0) {
509  SCReturnInt(-1);
510  }
511  struct FtpTransferCmd *data = FTPCalloc(1, sizeof(struct FtpTransferCmd));
512  if (data == NULL)
513  SCReturnInt(-1);
514  data->DFree = FtpTransferCmdFree;
515  /* Min size has been checked in FTPParseRequestCommand */
516  data->file_name = FTPCalloc(state->current_line_len - 4, sizeof(char));
517  if (data->file_name == NULL) {
518  FtpTransferCmdFree(data);
519  SCReturnInt(-1);
520  }
521  data->file_name[state->current_line_len - 5] = 0;
522  data->file_len = state->current_line_len - 5;
523  memcpy(data->file_name, state->current_line + 5, state->current_line_len - 5);
524  data->cmd = state->command;
525  data->flow_id = FlowGetId(f);
526  int ret = AppLayerExpectationCreate(f,
527  state->active ? STREAM_TOSERVER : direction,
528  0, state->dyn_port, ALPROTO_FTPDATA, data);
529  if (ret == -1) {
530  FtpTransferCmdFree(data);
531  SCLogDebug("No expectation created.");
532  SCReturnInt(-1);
533  } else {
534  SCLogDebug("Expectation created [direction: %s, dynamic port %"PRIu16"].",
535  state->active ? "to server" : "to client",
536  state->dyn_port);
537  }
538 
539  /* reset the dyn port to avoid duplicate */
540  state->dyn_port = 0;
541  /* reset active/passive indicator */
542  state->active = false;
543  }
544  break;
545  default:
546  break;
547  }
548  }
549 
550  return 1;
551 }
552 
553 static int FTPParsePassiveResponse(Flow *f, FtpState *state, uint8_t *input, uint32_t input_len)
554 {
555  uint16_t dyn_port =
556 #ifdef HAVE_RUST
557  rs_ftp_pasv_response(input, input_len);
558 #else
559  FTPGetV4PortNumber(input, input_len);
560 #endif
561  if (dyn_port == 0) {
562  return -1;
563  }
564  SCLogDebug("FTP passive mode (v4): dynamic port %"PRIu16"", dyn_port);
565  state->active = false;
566  state->dyn_port = dyn_port;
567 
568  return 0;
569 }
570 
571 static int FTPParsePassiveResponseV6(Flow *f, FtpState *state, uint8_t *input, uint32_t input_len)
572 {
573  uint16_t dyn_port =
574 #ifdef HAVE_RUST
575  rs_ftp_epsv_response(input, input_len);
576 #else
577  FTPGetV6PortNumber(input, input_len);
578 #endif
579  if (dyn_port == 0) {
580  return -1;
581  }
582  SCLogDebug("FTP passive mode (v6): dynamic port %"PRIu16"", dyn_port);
583  state->active = false;
584  state->dyn_port = dyn_port;
585  return 0;
586 }
587 
588 /**
589  * \brief This function is called to retrieve a ftp response
590  * \param ftp_state the ftp state structure for the parser
591  * \param input input line of the command
592  * \param input_len length of the request
593  * \param output the resulting output
594  *
595  * \retval 1 when the command is parsed, 0 otherwise
596  */
597 static int FTPParseResponse(Flow *f, void *ftp_state, AppLayerParserState *pstate,
598  uint8_t *input, uint32_t input_len,
599  void *local_data, const uint8_t flags)
600 {
601  FtpState *state = (FtpState *)ftp_state;
602 
603  if (state->command == FTP_COMMAND_AUTH_TLS) {
604  if (input_len >= 4 && SCMemcmp("234 ", input, 4) == 0) {
606  }
607  }
608 
609  if (state->command == FTP_COMMAND_EPRT) {
610  uint16_t dyn_port = FTPGetV6PortNumber(state->port_line, state->port_line_len);
611  if (dyn_port == 0) {
612  return 0;
613  }
614  state->dyn_port = dyn_port;
615  state->active = true;
616  SCLogDebug("FTP active mode (v6): dynamic port %"PRIu16"", dyn_port);
617  }
618 
619  if (state->command == FTP_COMMAND_PORT) {
620  if ((flags & STREAM_TOCLIENT)) {
621  uint16_t dyn_port = FTPGetV4PortNumber(state->port_line, state->port_line_len);
622  if (dyn_port == 0) {
623  return 0;
624  }
625  state->dyn_port = dyn_port;
626  state->active = true;
627  SCLogDebug("FTP active mode (v4): dynamic port %"PRIu16"", dyn_port);
628  }
629  }
630  if (state->command == FTP_COMMAND_PASV) {
631  if (input_len >= 4 && SCMemcmp("227 ", input, 4) == 0) {
632  FTPParsePassiveResponse(f, ftp_state, input, input_len);
633  }
634  }
635 
636  if (state->command == FTP_COMMAND_EPSV) {
637  if (input_len >= 4 && SCMemcmp("229 ", input, 4) == 0) {
638  FTPParsePassiveResponseV6(f, ftp_state, input, input_len);
639  }
640  }
641 
642  return 1;
643 }
644 
645 #ifdef DEBUG
646 static SCMutex ftp_state_mem_lock = SCMUTEX_INITIALIZER;
647 static uint64_t ftp_state_memuse = 0;
648 static uint64_t ftp_state_memcnt = 0;
649 #endif
650 
651 static void *FTPStateAlloc(void)
652 {
653  void *s = FTPMalloc(sizeof(FtpState));
654  if (unlikely(s == NULL))
655  return NULL;
656 
657  memset(s, 0, sizeof(FtpState));
658 
659 #ifdef DEBUG
660  SCMutexLock(&ftp_state_mem_lock);
661  ftp_state_memcnt++;
662  ftp_state_memuse+=sizeof(FtpState);
663  SCMutexUnlock(&ftp_state_mem_lock);
664 #endif
665  return s;
666 }
667 
668 static void FTPStateFree(void *s)
669 {
670  FtpState *fstate = (FtpState *) s;
671  if (fstate->port_line != NULL)
672  FTPFree(fstate->port_line, fstate->port_line_size);
673  if (fstate->line_state[0].db)
674  FTPFree(fstate->line_state[0].db, fstate->line_state[0].db_len);
675  if (fstate->line_state[1].db)
676  FTPFree(fstate->line_state[1].db, fstate->line_state[1].db_len);
677 
678  //AppLayerDecoderEventsFreeEvents(&s->decoder_events);
679 
680  if (fstate->de_state != NULL) {
682  }
683 
684  FTPFree(s, sizeof(FtpState));
685 #ifdef DEBUG
686  SCMutexLock(&ftp_state_mem_lock);
687  ftp_state_memcnt--;
688  ftp_state_memuse-=sizeof(FtpState);
689  SCMutexUnlock(&ftp_state_mem_lock);
690 #endif
691 }
692 
693 static int FTPSetTxDetectState(void *vtx, DetectEngineState *de_state)
694 {
695  FtpState *ftp_state = (FtpState *)vtx;
696  ftp_state->de_state = de_state;
697  return 0;
698 }
699 
700 static DetectEngineState *FTPGetTxDetectState(void *vtx)
701 {
702  FtpState *ftp_state = (FtpState *)vtx;
703  return ftp_state->de_state;
704 }
705 
706 static void FTPStateTransactionFree(void *state, uint64_t tx_id)
707 {
708  /* do nothing */
709 }
710 
711 static void *FTPGetTx(void *state, uint64_t tx_id)
712 {
713  FtpState *ftp_state = (FtpState *)state;
714  return ftp_state;
715 }
716 
717 static uint64_t FTPGetTxCnt(void *state)
718 {
719  /* single tx */
720  return 1;
721 }
722 
723 static int FTPGetAlstateProgressCompletionStatus(uint8_t direction)
724 {
725  return FTP_STATE_FINISHED;
726 }
727 
728 static int FTPGetAlstateProgress(void *tx, uint8_t direction)
729 {
730  FtpState *ftp_state = (FtpState *)tx;
731 
732  if (direction == STREAM_TOSERVER &&
733  ftp_state->command == FTP_COMMAND_PORT) {
734  return FTP_STATE_PORT_DONE;
735  }
736 
737  /* TODO: figure out further progress handling */
738 
739  return FTP_STATE_IN_PROGRESS;
740 }
741 
742 
743 static int FTPRegisterPatternsForProtocolDetection(void)
744 {
746  "220 (", 5, 0, STREAM_TOCLIENT) < 0)
747  {
748  return -1;
749  }
751  "FEAT", 4, 0, STREAM_TOSERVER) < 0)
752  {
753  return -1;
754  }
756  "USER ", 5, 0, STREAM_TOSERVER) < 0)
757  {
758  return -1;
759  }
761  "PASS ", 5, 0, STREAM_TOSERVER) < 0)
762  {
763  return -1;
764  }
766  "PORT ", 5, 0, STREAM_TOSERVER) < 0)
767  {
768  return -1;
769  }
770 
771  return 0;
772 }
773 
774 
776 
777 /**
778  * \brief This function is called to retrieve a ftp request
779  * \param ftp_state the ftp state structure for the parser
780  * \param input input line of the command
781  * \param input_len length of the request
782  * \param output the resulting output
783  *
784  * \retval 1 when the command is parsed, 0 otherwise
785  */
786 static int FTPDataParse(Flow *f, FtpDataState *ftpdata_state,
787  AppLayerParserState *pstate,
788  uint8_t *input, uint32_t input_len,
789  void *local_data, int direction)
790 {
791  uint16_t flags = FileFlowToFlags(f, direction);
792  int ret = 0;
793  /* we depend on detection engine for file pruning */
794  flags |= FILE_USE_DETECT;
795  if (ftpdata_state->files == NULL) {
797  if (data == NULL) {
798  SCReturnInt(-1);
799  }
800 
801  ftpdata_state->files = FileContainerAlloc();
802  if (ftpdata_state->files == NULL) {
804  SCReturnInt(-1);
805  }
806 
807  ftpdata_state->file_name = data->file_name;
808  ftpdata_state->file_len = data->file_len;
809  data->file_name = NULL;
810  data->file_len = 0;
811  f->parent_id = data->flow_id;
812  ftpdata_state->command = data->cmd;
813  switch (data->cmd) {
814  case FTP_COMMAND_STOR:
815  ftpdata_state->direction = STREAM_TOSERVER;
816  break;
817  case FTP_COMMAND_RETR:
818  ftpdata_state->direction = STREAM_TOCLIENT;
819  break;
820  default:
821  break;
822  }
823 
824  /* open with fixed track_id 0 as we can have just one
825  * file per ftp-data flow. */
826  if (FileOpenFileWithId(ftpdata_state->files, &sbcfg,
827  0ULL, (uint8_t *) ftpdata_state->file_name,
828  ftpdata_state->file_len,
829  input, input_len, flags) != 0) {
830  SCLogDebug("Can't open file");
831  ret = -1;
832  }
834  } else {
835  if (input_len != 0) {
836  ret = FileAppendData(ftpdata_state->files, input, input_len);
837  if (ret == -2) {
838  ret = 0;
839  SCLogDebug("FileAppendData() - file no longer being extracted");
840  goto out;
841  } else if (ret < 0) {
842  SCLogDebug("FileAppendData() failed: %d", ret);
843  ret = -2;
844  goto out;
845  }
846  } else {
847  ret = FileCloseFile(ftpdata_state->files, NULL, 0, flags);
848  ftpdata_state->state = FTPDATA_STATE_FINISHED;
849  if (ret < 0)
850  goto out;
851  }
852  }
853 
854  if (input_len && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
855  ret = FileCloseFile(ftpdata_state->files, (uint8_t *) NULL, 0, flags);
856  ftpdata_state->state = FTPDATA_STATE_FINISHED;
857  }
858 
859 out:
860  if (ftpdata_state->files) {
861  FilePrune(ftpdata_state->files);
862  }
863  return ret;
864 }
865 
866 static int FTPDataParseRequest(Flow *f, void *ftp_state,
867  AppLayerParserState *pstate,
868  uint8_t *input, uint32_t input_len,
869  void *local_data, const uint8_t flags)
870 {
871  return FTPDataParse(f, ftp_state, pstate, input, input_len,
872  local_data, STREAM_TOSERVER);
873 }
874 
875 static int FTPDataParseResponse(Flow *f, void *ftp_state,
876  AppLayerParserState *pstate,
877  uint8_t *input, uint32_t input_len,
878  void *local_data, const uint8_t flags)
879 {
880  return FTPDataParse(f, ftp_state, pstate, input, input_len,
881  local_data, STREAM_TOCLIENT);
882 }
883 
884 #ifdef DEBUG
885 static SCMutex ftpdata_state_mem_lock = SCMUTEX_INITIALIZER;
886 static uint64_t ftpdata_state_memuse = 0;
887 static uint64_t ftpdata_state_memcnt = 0;
888 #endif
889 
890 static void *FTPDataStateAlloc(void)
891 {
892  void *s = FTPMalloc(sizeof(FtpDataState));
893  if (unlikely(s == NULL))
894  return NULL;
895 
896  memset(s, 0, sizeof(FtpDataState));
897  ((FtpDataState *)s)->state = FTPDATA_STATE_IN_PROGRESS;
898 
899 #ifdef DEBUG
900  SCMutexLock(&ftpdata_state_mem_lock);
901  ftpdata_state_memcnt++;
902  ftpdata_state_memuse+=sizeof(FtpDataState);
903  SCMutexUnlock(&ftpdata_state_mem_lock);
904 #endif
905  return s;
906 }
907 
908 static void FTPDataStateFree(void *s)
909 {
910  FtpDataState *fstate = (FtpDataState *) s;
911 
912  if (fstate->de_state != NULL) {
914  }
915  if (fstate->file_name != NULL) {
916  FTPFree(fstate->file_name, fstate->file_len);
917  }
918 
919  FileContainerFree(fstate->files);
920 
921  SCFree(s);
922 #ifdef DEBUG
923  SCMutexLock(&ftpdata_state_mem_lock);
924  ftpdata_state_memcnt--;
925  ftpdata_state_memuse-=sizeof(FtpDataState);
926  SCMutexUnlock(&ftpdata_state_mem_lock);
927 #endif
928 }
929 
930 static int FTPDataSetTxDetectState(void *vtx, DetectEngineState *de_state)
931 {
932  FtpDataState *ftp_state = (FtpDataState *)vtx;
933  ftp_state->de_state = de_state;
934  return 0;
935 }
936 
937 static DetectEngineState *FTPDataGetTxDetectState(void *vtx)
938 {
939  FtpDataState *ftp_state = (FtpDataState *)vtx;
940  return ftp_state->de_state;
941 }
942 
943 static void FTPDataStateTransactionFree(void *state, uint64_t tx_id)
944 {
945  /* do nothing */
946 }
947 
948 static void *FTPDataGetTx(void *state, uint64_t tx_id)
949 {
950  FtpDataState *ftp_state = (FtpDataState *)state;
951  return ftp_state;
952 }
953 
954 static uint64_t FTPDataGetTxCnt(void *state)
955 {
956  /* ftp-data is single tx */
957  return 1;
958 }
959 
960 static int FTPDataGetAlstateProgressCompletionStatus(uint8_t direction)
961 {
962  return FTPDATA_STATE_FINISHED;
963 }
964 
965 static int FTPDataGetAlstateProgress(void *tx, uint8_t direction)
966 {
967  FtpDataState *ftpdata_state = (FtpDataState *)tx;
968  return ftpdata_state->state;
969 }
970 
971 static FileContainer *FTPDataStateGetFiles(void *state, uint8_t direction)
972 {
973  FtpDataState *ftpdata_state = (FtpDataState *)state;
974 
975  if (direction != ftpdata_state->direction)
976  SCReturnPtr(NULL, "FileContainer");
977 
978  SCReturnPtr(ftpdata_state->files, "FileContainer");
979 }
980 
982 {
983  const char *proto_name = "ftp";
984  const char *proto_data_name = "ftp-data";
985 
986  /** FTP */
987  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
989  if (FTPRegisterPatternsForProtocolDetection() < 0 )
990  return;
992  }
993 
994  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
996  FTPParseRequest);
998  FTPParseResponse);
999  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTP, FTPStateAlloc, FTPStateFree);
1001 
1002  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTP, FTPStateTransactionFree);
1003 
1005  FTPGetTxDetectState, FTPSetTxDetectState);
1006 
1007  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTP, FTPGetTx);
1008 
1009  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxCnt);
1010 
1011  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetAlstateProgress);
1012 
1014  FTPGetAlstateProgressCompletionStatus);
1015 
1016 
1019  FTPDataParseRequest);
1021  FTPDataParseResponse);
1022  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateAlloc, FTPDataStateFree);
1024  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateTransactionFree);
1026  FTPDataGetTxDetectState, FTPDataSetTxDetectState);
1027 
1028  AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateGetFiles);
1029 
1030  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTx);
1031 
1032  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTxCnt);
1033 
1034  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetAlstateProgress);
1035 
1037  FTPDataGetAlstateProgressCompletionStatus);
1038 
1039  sbcfg.buf_size = 4096;
1040  sbcfg.Malloc = FTPMalloc;
1041  sbcfg.Calloc = FTPCalloc;
1042  sbcfg.Realloc = FTPRealloc;
1043  sbcfg.Free = FTPFree;
1044 
1045  FTPParseMemcap();
1046  } else {
1047  SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
1048  "still on.", proto_name);
1049  }
1050 #ifdef UNITTESTS
1052 #endif
1053 }
1054 
1056 {
1057 #ifdef DEBUG
1058  SCMutexLock(&ftp_state_mem_lock);
1059  SCLogDebug("ftp_state_memcnt %"PRIu64", ftp_state_memuse %"PRIu64"",
1060  ftp_state_memcnt, ftp_state_memuse);
1061  SCMutexUnlock(&ftp_state_mem_lock);
1062 #endif
1063 }
1064 
1065 
1066 #ifdef HAVE_LIBJANSSON
1067 json_t *JsonFTPDataAddMetadata(const Flow *f)
1068 {
1069  const FtpDataState *ftp_state = NULL;
1070  if (f->alstate == NULL)
1071  return NULL;
1072  ftp_state = (FtpDataState *)f->alstate;
1073  json_t *ftpd = json_object();
1074  if (ftpd == NULL)
1075  return NULL;
1076  if (ftp_state->file_name) {
1077  size_t size = ftp_state->file_len * 2 + 1;
1078  char string[size];
1079  BytesToStringBuffer(ftp_state->file_name, ftp_state->file_len, string, size);
1080  json_object_set_new(ftpd, "filename", SCJsonString(string));
1081  }
1082  switch (ftp_state->command) {
1083  case FTP_COMMAND_STOR:
1084  json_object_set_new(ftpd, "command", json_string("STOR"));
1085  break;
1086  case FTP_COMMAND_RETR:
1087  json_object_set_new(ftpd, "command", json_string("RETR"));
1088  break;
1089  default:
1090  break;
1091  }
1092  return ftpd;
1093 }
1094 #endif /* HAVE_LIBJANSSON */
1095 
1096 /* UNITTESTS */
1097 #ifdef UNITTESTS
1098 
1099 /** \test Send a get request in one chunk. */
1100 static int FTPParserTest01(void)
1101 {
1102  int result = 1;
1103  Flow f;
1104  uint8_t ftpbuf[] = "PORT 192,168,1,1,0,80\r\n";
1105  uint32_t ftplen = sizeof(ftpbuf) - 1; /* minus the \0 */
1106  TcpSession ssn;
1108 
1109  memset(&f, 0, sizeof(f));
1110  memset(&ssn, 0, sizeof(ssn));
1111 
1112  FLOW_INITIALIZE(&f);
1113  f.protoctx = (void *)&ssn;
1114  f.proto = IPPROTO_TCP;
1115  f.alproto = ALPROTO_FTP;
1116 
1118 
1119  FLOWLOCK_WRLOCK(&f);
1120  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1121  STREAM_TOSERVER | STREAM_EOF, ftpbuf, ftplen);
1122  if (r != 0) {
1123  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1124  result = 0;
1125  FLOWLOCK_UNLOCK(&f);
1126  goto end;
1127  }
1128  FLOWLOCK_UNLOCK(&f);
1129 
1130  FtpState *ftp_state = f.alstate;
1131  if (ftp_state == NULL) {
1132  SCLogDebug("no ftp state: ");
1133  result = 0;
1134  goto end;
1135  }
1136 
1137  if (ftp_state->command != FTP_COMMAND_PORT) {
1138  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_PORT, ftp_state->command);
1139  result = 0;
1140  goto end;
1141  }
1142 
1143 end:
1144  if (alp_tctx != NULL)
1145  AppLayerParserThreadCtxFree(alp_tctx);
1147  FLOW_DESTROY(&f);
1148  return result;
1149 }
1150 
1151 /** \test Send a splitted get request. */
1152 static int FTPParserTest03(void)
1153 {
1154  int result = 1;
1155  Flow f;
1156  uint8_t ftpbuf1[] = "POR";
1157  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1158  uint8_t ftpbuf2[] = "T 192,168,1";
1159  uint32_t ftplen2 = sizeof(ftpbuf2) - 1; /* minus the \0 */
1160  uint8_t ftpbuf3[] = "1,1,10,20\r\n";
1161  uint32_t ftplen3 = sizeof(ftpbuf3) - 1; /* minus the \0 */
1162  TcpSession ssn;
1164 
1165  memset(&f, 0, sizeof(f));
1166  memset(&ssn, 0, sizeof(ssn));
1167 
1168  FLOW_INITIALIZE(&f);
1169  f.protoctx = (void *)&ssn;
1170  f.proto = IPPROTO_TCP;
1171  f.alproto = ALPROTO_FTP;
1172 
1174 
1175  FLOWLOCK_WRLOCK(&f);
1176  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1177  STREAM_TOSERVER | STREAM_START, ftpbuf1,
1178  ftplen1);
1179  if (r != 0) {
1180  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1181  result = 0;
1182  FLOWLOCK_UNLOCK(&f);
1183  goto end;
1184  }
1185  FLOWLOCK_UNLOCK(&f);
1186 
1187  FLOWLOCK_WRLOCK(&f);
1188  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER,
1189  ftpbuf2, ftplen2);
1190  if (r != 0) {
1191  SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1192  result = 0;
1193  FLOWLOCK_UNLOCK(&f);
1194  goto end;
1195  }
1196  FLOWLOCK_UNLOCK(&f);
1197 
1198  FLOWLOCK_WRLOCK(&f);
1199  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1200  STREAM_TOSERVER | STREAM_EOF, ftpbuf3, ftplen3);
1201  if (r != 0) {
1202  SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1203  result = 0;
1204  FLOWLOCK_UNLOCK(&f);
1205  goto end;
1206  }
1207  FLOWLOCK_UNLOCK(&f);
1208 
1209  FtpState *ftp_state = f.alstate;
1210  if (ftp_state == NULL) {
1211  SCLogDebug("no ftp state: ");
1212  result = 0;
1213  goto end;
1214  }
1215 
1216  if (ftp_state->command != FTP_COMMAND_PORT) {
1217  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_PORT, ftp_state->command);
1218  result = 0;
1219  goto end;
1220  }
1221 
1222 end:
1223  if (alp_tctx != NULL)
1224  AppLayerParserThreadCtxFree(alp_tctx);
1226  return result;
1227 }
1228 
1229 /** \test See how it deals with an incomplete request. */
1230 static int FTPParserTest06(void)
1231 {
1232  int result = 1;
1233  Flow f;
1234  uint8_t ftpbuf1[] = "PORT";
1235  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1236  TcpSession ssn;
1238 
1239  memset(&f, 0, sizeof(f));
1240  memset(&ssn, 0, sizeof(ssn));
1241 
1242  FLOW_INITIALIZE(&f);
1243  f.protoctx = (void *)&ssn;
1244  f.proto = IPPROTO_TCP;
1245  f.alproto = ALPROTO_FTP;
1246 
1248 
1249  FLOWLOCK_WRLOCK(&f);
1250  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1252  ftpbuf1,
1253  ftplen1);
1254  if (r != 0) {
1255  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1256  result = 0;
1257  FLOWLOCK_UNLOCK(&f);
1258  goto end;
1259  }
1260  FLOWLOCK_UNLOCK(&f);
1261 
1262  FtpState *ftp_state = f.alstate;
1263  if (ftp_state == NULL) {
1264  SCLogDebug("no ftp state: ");
1265  result = 0;
1266  goto end;
1267  }
1268 
1269  if (ftp_state->command != FTP_COMMAND_UNKNOWN) {
1270  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_UNKNOWN, ftp_state->command);
1271  result = 0;
1272  goto end;
1273  }
1274 
1275 end:
1276  if (alp_tctx != NULL)
1277  AppLayerParserThreadCtxFree(alp_tctx);
1279  FLOW_DESTROY(&f);
1280  return result;
1281 }
1282 
1283 /** \test See how it deals with an incomplete request in multiple chunks. */
1284 static int FTPParserTest07(void)
1285 {
1286  int result = 1;
1287  Flow f;
1288  uint8_t ftpbuf1[] = "PO";
1289  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1290  uint8_t ftpbuf2[] = "RT\r\n";
1291  uint32_t ftplen2 = sizeof(ftpbuf2) - 1; /* minus the \0 */
1292  TcpSession ssn;
1294 
1295  memset(&f, 0, sizeof(f));
1296  memset(&ssn, 0, sizeof(ssn));
1297 
1298  FLOW_INITIALIZE(&f);
1299  f.protoctx = (void *)&ssn;
1300  f.proto = IPPROTO_TCP;
1301  f.alproto = ALPROTO_FTP;
1302 
1304 
1305  FLOWLOCK_WRLOCK(&f);
1306  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1307  STREAM_TOSERVER | STREAM_START, ftpbuf1,
1308  ftplen1);
1309  if (r != 0) {
1310  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1311  result = 0;
1312  FLOWLOCK_UNLOCK(&f);
1313  goto end;
1314  }
1315  FLOWLOCK_UNLOCK(&f);
1316 
1317  FLOWLOCK_WRLOCK(&f);
1318  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1319  STREAM_TOSERVER | STREAM_EOF, ftpbuf2, ftplen2);
1320  if (r != 0) {
1321  SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1322  result = 0;
1323  FLOWLOCK_UNLOCK(&f);
1324  goto end;
1325  }
1326  FLOWLOCK_UNLOCK(&f);
1327 
1328  FtpState *ftp_state = f.alstate;
1329  if (ftp_state == NULL) {
1330  SCLogDebug("no ftp state: ");
1331  result = 0;
1332  goto end;
1333  }
1334 
1335  if (ftp_state->command != FTP_COMMAND_PORT) {
1336  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ",
1337  FTP_COMMAND_PORT, ftp_state->command);
1338  result = 0;
1339  goto end;
1340  }
1341 
1342 end:
1343  if (alp_tctx != NULL)
1344  AppLayerParserThreadCtxFree(alp_tctx);
1346  FLOW_DESTROY(&f);
1347  return result;
1348 }
1349 
1350 /** \test Test case where chunks are smaller than the delim length and the
1351  * last chunk is supposed to match the delim. */
1352 static int FTPParserTest10(void)
1353 {
1354  int result = 1;
1355  Flow f;
1356  uint8_t ftpbuf1[] = "PORT 1,2,3,4,5,6\r\n";
1357  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1358  TcpSession ssn;
1360  int r = 0;
1361  memset(&f, 0, sizeof(f));
1362  memset(&ssn, 0, sizeof(ssn));
1363 
1364  FLOW_INITIALIZE(&f);
1365  f.protoctx = (void *)&ssn;
1366  f.proto = IPPROTO_TCP;
1367  f.alproto = ALPROTO_FTP;
1368 
1370 
1371  uint32_t u;
1372  for (u = 0; u < ftplen1; u++) {
1373  uint8_t flags = 0;
1374 
1375  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
1376  else if (u == (ftplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
1377  else flags = STREAM_TOSERVER;
1378 
1379  FLOWLOCK_WRLOCK(&f);
1380  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, flags,
1381  &ftpbuf1[u], 1);
1382  if (r != 0) {
1383  SCLogDebug("toserver chunk %" PRIu32 " returned %" PRId32 ", expected 0: ", u, r);
1384  result = 0;
1385  FLOWLOCK_UNLOCK(&f);
1386  goto end;
1387  }
1388  FLOWLOCK_UNLOCK(&f);
1389  }
1390 
1391  FtpState *ftp_state = f.alstate;
1392  if (ftp_state == NULL) {
1393  SCLogDebug("no ftp state: ");
1394  result = 0;
1395  goto end;
1396  }
1397 
1398  if (ftp_state->command != FTP_COMMAND_PORT) {
1399  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_PORT, ftp_state->command);
1400  result = 0;
1401  goto end;
1402  }
1403 
1404 end:
1405  if (alp_tctx != NULL)
1406  AppLayerParserThreadCtxFree(alp_tctx);
1408  FLOW_DESTROY(&f);
1409  return result;
1410 }
1411 #endif /* UNITTESTS */
1412 
1414 {
1415 #ifdef UNITTESTS
1416  UtRegisterTest("FTPParserTest01", FTPParserTest01);
1417  UtRegisterTest("FTPParserTest03", FTPParserTest03);
1418  UtRegisterTest("FTPParserTest06", FTPParserTest06);
1419  UtRegisterTest("FTPParserTest07", FTPParserTest07);
1420  UtRegisterTest("FTPParserTest10", FTPParserTest10);
1421 #endif /* UNITTESTS */
1422 }
1423 
#define SCMutex
#define STREAMING_BUFFER_CONFIG_INITIALIZER
uint16_t flags
#define SCMemcmp(a, b, c)
Definition: util-memcmp.h:369
#define SCLogDebug(...)
Definition: util-debug.h:335
FtpLineState line_state[2]
uint8_t * input
void *(* Malloc)(size_t size)
int AppLayerExpectationGetDataId(void)
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
uint8_t proto
Definition: flow.h:344
FileContainer * FileContainerAlloc(void)
allocate a FileContainer
Definition: util-file.c:380
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:243
#define unlikely(expr)
Definition: util-optimize.h:35
int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
Given a protocol name, checks if proto detection is enabled in the conf file.
int16_t file_len
int AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint8_t flag)
void AppLayerParserRegisterParserAcceptableDataDirection(uint8_t ipproto, AppProto alproto, uint8_t direction)
void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, DetectEngineState *(*GetTxDetectState)(void *tx), int(*SetTxDetectState)(void *tx, DetectEngineState *))
uint8_t * file_name
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:107
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
void(* DFree)(void *)
void StreamTcpFreeConfig(char quiet)
Definition: stream-tcp.c:669
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:240
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
Definition: util-atomic.h:124
uint64_t FTPMemuseGlobalCounter(void)
#define TRUE
#define SCMutexLock(mut)
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:331
void * protoctx
Definition: flow.h:400
void *(* Calloc)(size_t n, size_t size)
FtpRequestCommand command
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:203
FtpRequestCommand cmd
void * alstate
Definition: flow.h:438
SC_ATOMIC_DECLARE(uint64_t, ftp_memuse)
int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name)
check if a parser is enabled in the config Returns enabled always if: were running unittests and when...
#define SC_ATOMIC_INIT(name)
Initialize the previously declared atomic variable and it&#39;s lock.
Definition: util-atomic.h:81
uint8_t direction
#define SCCalloc(nm, a)
Definition: util-mem.h:197
int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, uint8_t direction, AppLayerParserFPtr Parser)
Register app layer parser for the protocol.
#define SCMutexUnlock(mut)
uint64_t ftp_config_memcap
Definition: app-layer-ftp.c:66
struct FtpState_ FtpState
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
void * memrchr(const void *s, int c, size_t n)
Definition: util-memrchr.c:30
#define SCMUTEX_INITIALIZER
void AppLayerParserRegisterGetFilesFunc(uint8_t ipproto, AppProto alproto, FileContainer *(*StateGetFiles)(void *, uint8_t))
void AppLayerRegisterExpectationProto(uint8_t proto, AppProto alproto)
Data structures and function prototypes for keeping state for the detection engine.
FtpRequestCommand command
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
#define FLOW_DESTROY(f)
Definition: flow-util.h:119
void FTPParserRegisterTests(void)
#define STREAM_EOF
Definition: stream.h:30
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
void FileContainerFree(FileContainer *ffc)
Free a FileContainer.
Definition: util-file.c:416
void RegisterFTPParsers(void)
void AppLayerRequestProtocolTLSUpgrade(Flow *f)
request applayer to wrap up this protocol and rerun protocol detection with expectation of TLS...
void *(* Realloc)(void *ptr, size_t orig_size, size_t size)
DetectEngineState * de_state
void BytesToStringBuffer(const uint8_t *bytes, size_t nbytes, char *outstr, size_t outlen)
Turn byte array into string.
Definition: util-byte.c:85
#define SCEnter(...)
Definition: util-debug.h:337
void StreamTcpInitConfig(char)
To initialize the stream global configuration data.
Definition: stream-tcp.c:365
#define STREAM_TOCLIENT
Definition: stream.h:32
uint64_t FTPMemcapGlobalCounter(void)
void AppLayerParserRegisterGetStateProgressCompletionStatus(AppProto alproto, int(*StateGetProgressCompletionStatus)(uint8_t direction))
uint8_t * port_line
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol&#39;s parser thread context.
uint16_t dyn_port
void DetectEngineStateFree(DetectEngineState *state)
Frees a DetectEngineState object.
#define SCReturnInt(x)
Definition: util-debug.h:341
void FilePrune(FileContainer *ffc)
Definition: util-file.c:345
#define SCRealloc(x, a)
Definition: util-mem.h:182
uint8_t * current_line
#define SCMalloc(a)
Definition: util-mem.h:166
#define FILE_USE_DETECT
Definition: util-file.h:49
void FTPAtExitPrintStats(void)
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:254
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
uint32_t db_len
#define SCFree(a)
Definition: util-mem.h:228
uint16_t tx_id
uint8_t current_line_lf_seen
uint32_t port_line_len
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
int64_t parent_id
Definition: flow.h:389
#define STREAM_START
Definition: stream.h:29
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:39
uint8_t direction
#define STREAM_TOSERVER
Definition: stream.h:31
int AppLayerExpectationCreate(Flow *f, int direction, Port src, Port dst, AppProto alproto, void *data)
#define SCReturnPtr(x, type)
Definition: util-debug.h:353
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:868
int FileCloseFile(FileContainer *ffc, const uint8_t *data, uint32_t data_len, uint16_t flags)
Close a File.
Definition: util-file.c:963
#define APP_LAYER_PARSER_EOF
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:192
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
Definition: util-file.c:217
void * FlowGetStorageById(Flow *f, int id)
Definition: flow-storage.c:39
uint32_t port_line_size
uint16_t file_len
struct FtpDataState_ FtpDataState
int AppLayerProtoDetectPMRegisterPatternCI(uint8_t ipproto, AppProto alproto, const char *pattern, uint16_t depth, uint16_t offset, uint8_t direction)
Registers a case-insensitive pattern for protocol detection.
FtpRequestCommand
Definition: app-layer-ftp.h:33
uint32_t current_line_len
DetectEngineState * de_state
uint8_t * db
uint8_t * file_name
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void), void(*StateFree)(void *))
AppProto alproto
application level protocol
Definition: flow.h:409
int FileAppendData(FileContainer *ffc, 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:663
void FlowFreeStorageById(Flow *f, int id)
Definition: flow-storage.c:54
int32_t input_len
Flow data structure.
Definition: flow.h:325
uint8_t current_line_delimiter_len
void(* Free)(void *ptr, size_t size)
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, uint8_t *input, uint32_t input_len)
FileContainer * files
uint8_t current_line_db
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))
uint64_t flow_id