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  SCFree(cmd->file_name);
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 > 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_len = state->current_line_len;
497  break;
498  case FTP_COMMAND_RETR:
499  /* change direction (default to server) so expectation will handle
500  * the correct message when expectation will match.
501  */
502  direction = STREAM_TOCLIENT;
503  // fallthrough
504  case FTP_COMMAND_STOR:
505  {
506  /* No dyn port negotiated so get out */
507  if (state->dyn_port == 0) {
508  SCReturnInt(-1);
509  }
510  struct FtpTransferCmd *data = FTPCalloc(1, sizeof(struct FtpTransferCmd));
511  if (data == NULL)
512  SCReturnInt(-1);
513  data->DFree = FtpTransferCmdFree;
514  /* Min size has been checked in FTPParseRequestCommand */
515  data->file_name = FTPCalloc(state->current_line_len - 4, sizeof(char));
516  if (data->file_name == NULL) {
517  FTPFree(data, sizeof(struct FtpTransferCmd));
518  SCReturnInt(-1);
519  }
520  data->file_name[state->current_line_len - 5] = 0;
521  data->file_len = state->current_line_len - 5;
522  memcpy(data->file_name, state->current_line + 5, state->current_line_len - 5);
523  data->cmd = state->command;
524  data->flow_id = FlowGetId(f);
525  int ret = AppLayerExpectationCreate(f,
526  state->active ? STREAM_TOSERVER : direction,
527  0, state->dyn_port, ALPROTO_FTPDATA, data);
528  if (ret == -1) {
529  FTPFree(data, sizeof(struct FtpTransferCmd));
530  SCLogDebug("No expectation created.");
531  SCReturnInt(-1);
532  } else {
533  SCLogDebug("Expectation created [direction: %s, dynamic port %"PRIu16"].",
534  state->active ? "to server" : "to client",
535  state->dyn_port);
536  }
537 
538  /* reset the dyn port to avoid duplicate */
539  state->dyn_port = 0;
540  /* reset active/passive indicator */
541  state->active = false;
542  }
543  break;
544  default:
545  break;
546  }
547  }
548 
549  return 1;
550 }
551 
552 static int FTPParsePassiveResponse(Flow *f, FtpState *state, uint8_t *input, uint32_t input_len)
553 {
554  uint16_t dyn_port =
555 #ifdef HAVE_RUST
556  rs_ftp_pasv_response(input, input_len);
557 #else
558  FTPGetV4PortNumber(input, input_len);
559 #endif
560  if (dyn_port == 0) {
561  return -1;
562  }
563  SCLogDebug("FTP passive mode (v4): dynamic port %"PRIu16"", dyn_port);
564  state->active = false;
565  state->dyn_port = dyn_port;
566 
567  return 0;
568 }
569 
570 static int FTPParsePassiveResponseV6(Flow *f, FtpState *state, uint8_t *input, uint32_t input_len)
571 {
572  uint16_t dyn_port =
573 #ifdef HAVE_RUST
574  rs_ftp_epsv_response(input, input_len);
575 #else
576  FTPGetV6PortNumber(input, input_len);
577 #endif
578  if (dyn_port == 0) {
579  return -1;
580  }
581  SCLogDebug("FTP passive mode (v6): dynamic port %"PRIu16"", dyn_port);
582  state->active = false;
583  state->dyn_port = dyn_port;
584  return 0;
585 }
586 
587 /**
588  * \brief This function is called to retrieve a ftp response
589  * \param ftp_state the ftp state structure for the parser
590  * \param input input line of the command
591  * \param input_len length of the request
592  * \param output the resulting output
593  *
594  * \retval 1 when the command is parsed, 0 otherwise
595  */
596 static int FTPParseResponse(Flow *f, void *ftp_state, AppLayerParserState *pstate,
597  uint8_t *input, uint32_t input_len,
598  void *local_data, const uint8_t flags)
599 {
600  FtpState *state = (FtpState *)ftp_state;
601 
602  if (state->command == FTP_COMMAND_AUTH_TLS) {
603  if (input_len >= 4 && SCMemcmp("234 ", input, 4) == 0) {
605  }
606  }
607 
608  if (state->command == FTP_COMMAND_EPRT) {
609  uint16_t dyn_port = FTPGetV6PortNumber(state->port_line, state->port_line_len);
610  if (dyn_port == 0) {
611  return 0;
612  }
613  state->dyn_port = dyn_port;
614  state->active = true;
615  SCLogDebug("FTP active mode (v6): dynamic port %"PRIu16"", dyn_port);
616  }
617 
618  if (state->command == FTP_COMMAND_PORT) {
619  if ((flags & STREAM_TOCLIENT)) {
620  uint16_t dyn_port = FTPGetV4PortNumber(state->port_line, state->port_line_len);
621  if (dyn_port == 0) {
622  return 0;
623  }
624  state->dyn_port = dyn_port;
625  state->active = true;
626  SCLogDebug("FTP active mode (v4): dynamic port %"PRIu16"", dyn_port);
627  }
628  }
629  if (state->command == FTP_COMMAND_PASV) {
630  if (input_len >= 4 && SCMemcmp("227 ", input, 4) == 0) {
631  FTPParsePassiveResponse(f, ftp_state, input, input_len);
632  }
633  }
634 
635  if (state->command == FTP_COMMAND_EPSV) {
636  if (input_len >= 4 && SCMemcmp("229 ", input, 4) == 0) {
637  FTPParsePassiveResponseV6(f, ftp_state, input, input_len);
638  }
639  }
640 
641  return 1;
642 }
643 
644 #ifdef DEBUG
645 static SCMutex ftp_state_mem_lock = SCMUTEX_INITIALIZER;
646 static uint64_t ftp_state_memuse = 0;
647 static uint64_t ftp_state_memcnt = 0;
648 #endif
649 
650 static void *FTPStateAlloc(void)
651 {
652  void *s = FTPMalloc(sizeof(FtpState));
653  if (unlikely(s == NULL))
654  return NULL;
655 
656  memset(s, 0, sizeof(FtpState));
657 
658 #ifdef DEBUG
659  SCMutexLock(&ftp_state_mem_lock);
660  ftp_state_memcnt++;
661  ftp_state_memuse+=sizeof(FtpState);
662  SCMutexUnlock(&ftp_state_mem_lock);
663 #endif
664  return s;
665 }
666 
667 static void FTPStateFree(void *s)
668 {
669  FtpState *fstate = (FtpState *) s;
670  if (fstate->port_line != NULL)
671  FTPFree(fstate->port_line, fstate->port_line_size);
672  if (fstate->line_state[0].db)
673  FTPFree(fstate->line_state[0].db, fstate->line_state[0].db_len);
674  if (fstate->line_state[1].db)
675  FTPFree(fstate->line_state[1].db, fstate->line_state[1].db_len);
676 
677  //AppLayerDecoderEventsFreeEvents(&s->decoder_events);
678 
679  if (fstate->de_state != NULL) {
681  }
682 
683  FTPFree(s, sizeof(FtpState));
684 #ifdef DEBUG
685  SCMutexLock(&ftp_state_mem_lock);
686  ftp_state_memcnt--;
687  ftp_state_memuse-=sizeof(FtpState);
688  SCMutexUnlock(&ftp_state_mem_lock);
689 #endif
690 }
691 
692 static int FTPSetTxDetectState(void *vtx, DetectEngineState *de_state)
693 {
694  FtpState *ftp_state = (FtpState *)vtx;
695  ftp_state->de_state = de_state;
696  return 0;
697 }
698 
699 static DetectEngineState *FTPGetTxDetectState(void *vtx)
700 {
701  FtpState *ftp_state = (FtpState *)vtx;
702  return ftp_state->de_state;
703 }
704 
705 static void FTPStateTransactionFree(void *state, uint64_t tx_id)
706 {
707  /* do nothing */
708 }
709 
710 static void *FTPGetTx(void *state, uint64_t tx_id)
711 {
712  FtpState *ftp_state = (FtpState *)state;
713  return ftp_state;
714 }
715 
716 static uint64_t FTPGetTxCnt(void *state)
717 {
718  /* single tx */
719  return 1;
720 }
721 
722 static int FTPGetAlstateProgressCompletionStatus(uint8_t direction)
723 {
724  return FTP_STATE_FINISHED;
725 }
726 
727 static int FTPGetAlstateProgress(void *tx, uint8_t direction)
728 {
729  FtpState *ftp_state = (FtpState *)tx;
730 
731  if (direction == STREAM_TOSERVER &&
732  ftp_state->command == FTP_COMMAND_PORT) {
733  return FTP_STATE_PORT_DONE;
734  }
735 
736  /* TODO: figure out further progress handling */
737 
738  return FTP_STATE_IN_PROGRESS;
739 }
740 
741 
742 static int FTPRegisterPatternsForProtocolDetection(void)
743 {
745  "220 (", 5, 0, STREAM_TOCLIENT) < 0)
746  {
747  return -1;
748  }
750  "FEAT", 4, 0, STREAM_TOSERVER) < 0)
751  {
752  return -1;
753  }
755  "USER ", 5, 0, STREAM_TOSERVER) < 0)
756  {
757  return -1;
758  }
760  "PASS ", 5, 0, STREAM_TOSERVER) < 0)
761  {
762  return -1;
763  }
765  "PORT ", 5, 0, STREAM_TOSERVER) < 0)
766  {
767  return -1;
768  }
769 
770  return 0;
771 }
772 
773 
775 
776 /**
777  * \brief This function is called to retrieve a ftp request
778  * \param ftp_state the ftp state structure for the parser
779  * \param input input line of the command
780  * \param input_len length of the request
781  * \param output the resulting output
782  *
783  * \retval 1 when the command is parsed, 0 otherwise
784  */
785 static int FTPDataParse(Flow *f, FtpDataState *ftpdata_state,
786  AppLayerParserState *pstate,
787  uint8_t *input, uint32_t input_len,
788  void *local_data, int direction)
789 {
790  uint16_t flags = FileFlowToFlags(f, direction);
791  int ret = 0;
792  /* we depend on detection engine for file pruning */
793  flags |= FILE_USE_DETECT;
794  if (ftpdata_state->files == NULL) {
796  if (data == NULL) {
797  SCReturnInt(-1);
798  }
799 
800  ftpdata_state->files = FileContainerAlloc();
801  if (ftpdata_state->files == NULL) {
803  SCReturnInt(-1);
804  }
805 
806  ftpdata_state->file_name = data->file_name;
807  ftpdata_state->file_len = data->file_len;
808  data->file_name = NULL;
809  data->file_len = 0;
810  f->parent_id = data->flow_id;
811  ftpdata_state->command = data->cmd;
812  switch (data->cmd) {
813  case FTP_COMMAND_STOR:
814  ftpdata_state->direction = STREAM_TOSERVER;
815  break;
816  case FTP_COMMAND_RETR:
817  ftpdata_state->direction = STREAM_TOCLIENT;
818  break;
819  default:
820  break;
821  }
822 
823  if (FileOpenFile(ftpdata_state->files, &sbcfg,
824  (uint8_t *) ftpdata_state->file_name,
825  ftpdata_state->file_len,
826  input, input_len, flags) == NULL) {
827  SCLogDebug("Can't open file");
828  ret = -1;
829  }
831  } else {
832  if (input_len != 0) {
833  ret = FileAppendData(ftpdata_state->files, input, input_len);
834  if (ret == -2) {
835  ret = 0;
836  SCLogDebug("FileAppendData() - file no longer being extracted");
837  goto out;
838  } else if (ret < 0) {
839  SCLogDebug("FileAppendData() failed: %d", ret);
840  ret = -2;
841  goto out;
842  }
843  } else {
844  ret = FileCloseFile(ftpdata_state->files, NULL, 0, flags);
845  ftpdata_state->state = FTPDATA_STATE_FINISHED;
846  if (ret < 0)
847  goto out;
848  }
849  }
850 
851  if (input_len && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
852  ret = FileCloseFile(ftpdata_state->files, (uint8_t *) NULL, 0, flags);
853  ftpdata_state->state = FTPDATA_STATE_FINISHED;
854  }
855 
856 out:
857  if (ftpdata_state->files) {
858  FilePrune(ftpdata_state->files);
859  }
860  return ret;
861 }
862 
863 static int FTPDataParseRequest(Flow *f, void *ftp_state,
864  AppLayerParserState *pstate,
865  uint8_t *input, uint32_t input_len,
866  void *local_data, const uint8_t flags)
867 {
868  return FTPDataParse(f, ftp_state, pstate, input, input_len,
869  local_data, STREAM_TOSERVER);
870 }
871 
872 static int FTPDataParseResponse(Flow *f, void *ftp_state,
873  AppLayerParserState *pstate,
874  uint8_t *input, uint32_t input_len,
875  void *local_data, const uint8_t flags)
876 {
877  return FTPDataParse(f, ftp_state, pstate, input, input_len,
878  local_data, STREAM_TOCLIENT);
879 }
880 
881 #ifdef DEBUG
882 static SCMutex ftpdata_state_mem_lock = SCMUTEX_INITIALIZER;
883 static uint64_t ftpdata_state_memuse = 0;
884 static uint64_t ftpdata_state_memcnt = 0;
885 #endif
886 
887 static void *FTPDataStateAlloc(void)
888 {
889  void *s = FTPMalloc(sizeof(FtpDataState));
890  if (unlikely(s == NULL))
891  return NULL;
892 
893  memset(s, 0, sizeof(FtpDataState));
894  ((FtpDataState *)s)->state = FTPDATA_STATE_IN_PROGRESS;
895 
896 #ifdef DEBUG
897  SCMutexLock(&ftpdata_state_mem_lock);
898  ftpdata_state_memcnt++;
899  ftpdata_state_memuse+=sizeof(FtpDataState);
900  SCMutexUnlock(&ftpdata_state_mem_lock);
901 #endif
902  return s;
903 }
904 
905 static void FTPDataStateFree(void *s)
906 {
907  FtpDataState *fstate = (FtpDataState *) s;
908 
909  if (fstate->de_state != NULL) {
911  }
912  if (fstate->file_name != NULL) {
913  FTPFree(fstate->file_name, fstate->file_len);
914  }
915 
916  FileContainerFree(fstate->files);
917 
918  SCFree(s);
919 #ifdef DEBUG
920  SCMutexLock(&ftpdata_state_mem_lock);
921  ftpdata_state_memcnt--;
922  ftpdata_state_memuse-=sizeof(FtpDataState);
923  SCMutexUnlock(&ftpdata_state_mem_lock);
924 #endif
925 }
926 
927 static int FTPDataSetTxDetectState(void *vtx, DetectEngineState *de_state)
928 {
929  FtpDataState *ftp_state = (FtpDataState *)vtx;
930  ftp_state->de_state = de_state;
931  return 0;
932 }
933 
934 static DetectEngineState *FTPDataGetTxDetectState(void *vtx)
935 {
936  FtpDataState *ftp_state = (FtpDataState *)vtx;
937  return ftp_state->de_state;
938 }
939 
940 static void FTPDataStateTransactionFree(void *state, uint64_t tx_id)
941 {
942  /* do nothing */
943 }
944 
945 static void *FTPDataGetTx(void *state, uint64_t tx_id)
946 {
947  FtpDataState *ftp_state = (FtpDataState *)state;
948  return ftp_state;
949 }
950 
951 static uint64_t FTPDataGetTxCnt(void *state)
952 {
953  /* ftp-data is single tx */
954  return 1;
955 }
956 
957 static int FTPDataGetAlstateProgressCompletionStatus(uint8_t direction)
958 {
959  return FTPDATA_STATE_FINISHED;
960 }
961 
962 static int FTPDataGetAlstateProgress(void *tx, uint8_t direction)
963 {
964  FtpDataState *ftpdata_state = (FtpDataState *)tx;
965  return ftpdata_state->state;
966 }
967 
968 static FileContainer *FTPDataStateGetFiles(void *state, uint8_t direction)
969 {
970  FtpDataState *ftpdata_state = (FtpDataState *)state;
971 
972  if (direction != ftpdata_state->direction)
973  SCReturnPtr(NULL, "FileContainer");
974 
975  SCReturnPtr(ftpdata_state->files, "FileContainer");
976 }
977 
979 {
980  const char *proto_name = "ftp";
981  const char *proto_data_name = "ftp-data";
982 
983  /** FTP */
984  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
986  if (FTPRegisterPatternsForProtocolDetection() < 0 )
987  return;
989  }
990 
991  if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
993  FTPParseRequest);
995  FTPParseResponse);
996  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTP, FTPStateAlloc, FTPStateFree);
998 
999  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTP, FTPStateTransactionFree);
1000 
1002  FTPGetTxDetectState, FTPSetTxDetectState);
1003 
1004  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTP, FTPGetTx);
1005 
1006  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxCnt);
1007 
1008  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetAlstateProgress);
1009 
1011  FTPGetAlstateProgressCompletionStatus);
1012 
1013 
1016  FTPDataParseRequest);
1018  FTPDataParseResponse);
1019  AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateAlloc, FTPDataStateFree);
1021  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateTransactionFree);
1023  FTPDataGetTxDetectState, FTPDataSetTxDetectState);
1024 
1025  AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataStateGetFiles);
1026 
1027  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTx);
1028 
1029  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetTxCnt);
1030 
1031  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTPDATA, FTPDataGetAlstateProgress);
1032 
1034  FTPDataGetAlstateProgressCompletionStatus);
1035 
1036  sbcfg.buf_size = 4096;
1037  sbcfg.Malloc = FTPMalloc;
1038  sbcfg.Calloc = FTPCalloc;
1039  sbcfg.Realloc = FTPRealloc;
1040  sbcfg.Free = FTPFree;
1041 
1042  FTPParseMemcap();
1043  } else {
1044  SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
1045  "still on.", proto_name);
1046  }
1047 #ifdef UNITTESTS
1049 #endif
1050 }
1051 
1053 {
1054 #ifdef DEBUG
1055  SCMutexLock(&ftp_state_mem_lock);
1056  SCLogDebug("ftp_state_memcnt %"PRIu64", ftp_state_memuse %"PRIu64"",
1057  ftp_state_memcnt, ftp_state_memuse);
1058  SCMutexUnlock(&ftp_state_mem_lock);
1059 #endif
1060 }
1061 
1062 
1063 #ifdef HAVE_LIBJANSSON
1064 json_t *JsonFTPDataAddMetadata(const Flow *f)
1065 {
1066  const FtpDataState *ftp_state = NULL;
1067  if (f->alstate == NULL)
1068  return NULL;
1069  ftp_state = (FtpDataState *)f->alstate;
1070  json_t *ftpd = json_object();
1071  if (ftpd == NULL)
1072  return NULL;
1073  if (ftp_state->file_name) {
1074  size_t size = ftp_state->file_len * 2 + 1;
1075  char string[size];
1076  BytesToStringBuffer(ftp_state->file_name, ftp_state->file_len, string, size);
1077  json_object_set_new(ftpd, "filename", SCJsonString(string));
1078  }
1079  switch (ftp_state->command) {
1080  case FTP_COMMAND_STOR:
1081  json_object_set_new(ftpd, "command", json_string("STOR"));
1082  break;
1083  case FTP_COMMAND_RETR:
1084  json_object_set_new(ftpd, "command", json_string("RETR"));
1085  break;
1086  default:
1087  break;
1088  }
1089  return ftpd;
1090 }
1091 #endif /* HAVE_LIBJANSSON */
1092 
1093 /* UNITTESTS */
1094 #ifdef UNITTESTS
1095 
1096 /** \test Send a get request in one chunk. */
1097 static int FTPParserTest01(void)
1098 {
1099  int result = 1;
1100  Flow f;
1101  uint8_t ftpbuf[] = "PORT 192,168,1,1,0,80\r\n";
1102  uint32_t ftplen = sizeof(ftpbuf) - 1; /* minus the \0 */
1103  TcpSession ssn;
1105 
1106  memset(&f, 0, sizeof(f));
1107  memset(&ssn, 0, sizeof(ssn));
1108 
1109  FLOW_INITIALIZE(&f);
1110  f.protoctx = (void *)&ssn;
1111  f.proto = IPPROTO_TCP;
1112  f.alproto = ALPROTO_FTP;
1113 
1115 
1116  FLOWLOCK_WRLOCK(&f);
1117  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1118  STREAM_TOSERVER | STREAM_EOF, ftpbuf, ftplen);
1119  if (r != 0) {
1120  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1121  result = 0;
1122  FLOWLOCK_UNLOCK(&f);
1123  goto end;
1124  }
1125  FLOWLOCK_UNLOCK(&f);
1126 
1127  FtpState *ftp_state = f.alstate;
1128  if (ftp_state == NULL) {
1129  SCLogDebug("no ftp state: ");
1130  result = 0;
1131  goto end;
1132  }
1133 
1134  if (ftp_state->command != FTP_COMMAND_PORT) {
1135  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_PORT, ftp_state->command);
1136  result = 0;
1137  goto end;
1138  }
1139 
1140 end:
1141  if (alp_tctx != NULL)
1142  AppLayerParserThreadCtxFree(alp_tctx);
1144  FLOW_DESTROY(&f);
1145  return result;
1146 }
1147 
1148 /** \test Send a splitted get request. */
1149 static int FTPParserTest03(void)
1150 {
1151  int result = 1;
1152  Flow f;
1153  uint8_t ftpbuf1[] = "POR";
1154  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1155  uint8_t ftpbuf2[] = "T 192,168,1";
1156  uint32_t ftplen2 = sizeof(ftpbuf2) - 1; /* minus the \0 */
1157  uint8_t ftpbuf3[] = "1,1,10,20\r\n";
1158  uint32_t ftplen3 = sizeof(ftpbuf3) - 1; /* minus the \0 */
1159  TcpSession ssn;
1161 
1162  memset(&f, 0, sizeof(f));
1163  memset(&ssn, 0, sizeof(ssn));
1164 
1165  FLOW_INITIALIZE(&f);
1166  f.protoctx = (void *)&ssn;
1167  f.proto = IPPROTO_TCP;
1168  f.alproto = ALPROTO_FTP;
1169 
1171 
1172  FLOWLOCK_WRLOCK(&f);
1173  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1174  STREAM_TOSERVER | STREAM_START, ftpbuf1,
1175  ftplen1);
1176  if (r != 0) {
1177  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1178  result = 0;
1179  FLOWLOCK_UNLOCK(&f);
1180  goto end;
1181  }
1182  FLOWLOCK_UNLOCK(&f);
1183 
1184  FLOWLOCK_WRLOCK(&f);
1185  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, STREAM_TOSERVER,
1186  ftpbuf2, ftplen2);
1187  if (r != 0) {
1188  SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1189  result = 0;
1190  FLOWLOCK_UNLOCK(&f);
1191  goto end;
1192  }
1193  FLOWLOCK_UNLOCK(&f);
1194 
1195  FLOWLOCK_WRLOCK(&f);
1196  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1197  STREAM_TOSERVER | STREAM_EOF, ftpbuf3, ftplen3);
1198  if (r != 0) {
1199  SCLogDebug("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
1200  result = 0;
1201  FLOWLOCK_UNLOCK(&f);
1202  goto end;
1203  }
1204  FLOWLOCK_UNLOCK(&f);
1205 
1206  FtpState *ftp_state = f.alstate;
1207  if (ftp_state == NULL) {
1208  SCLogDebug("no ftp state: ");
1209  result = 0;
1210  goto end;
1211  }
1212 
1213  if (ftp_state->command != FTP_COMMAND_PORT) {
1214  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_PORT, ftp_state->command);
1215  result = 0;
1216  goto end;
1217  }
1218 
1219 end:
1220  if (alp_tctx != NULL)
1221  AppLayerParserThreadCtxFree(alp_tctx);
1223  return result;
1224 }
1225 
1226 /** \test See how it deals with an incomplete request. */
1227 static int FTPParserTest06(void)
1228 {
1229  int result = 1;
1230  Flow f;
1231  uint8_t ftpbuf1[] = "PORT";
1232  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1233  TcpSession ssn;
1235 
1236  memset(&f, 0, sizeof(f));
1237  memset(&ssn, 0, sizeof(ssn));
1238 
1239  FLOW_INITIALIZE(&f);
1240  f.protoctx = (void *)&ssn;
1241  f.proto = IPPROTO_TCP;
1242  f.alproto = ALPROTO_FTP;
1243 
1245 
1246  FLOWLOCK_WRLOCK(&f);
1247  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1249  ftpbuf1,
1250  ftplen1);
1251  if (r != 0) {
1252  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1253  result = 0;
1254  FLOWLOCK_UNLOCK(&f);
1255  goto end;
1256  }
1257  FLOWLOCK_UNLOCK(&f);
1258 
1259  FtpState *ftp_state = f.alstate;
1260  if (ftp_state == NULL) {
1261  SCLogDebug("no ftp state: ");
1262  result = 0;
1263  goto end;
1264  }
1265 
1266  if (ftp_state->command != FTP_COMMAND_UNKNOWN) {
1267  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_UNKNOWN, ftp_state->command);
1268  result = 0;
1269  goto end;
1270  }
1271 
1272 end:
1273  if (alp_tctx != NULL)
1274  AppLayerParserThreadCtxFree(alp_tctx);
1276  FLOW_DESTROY(&f);
1277  return result;
1278 }
1279 
1280 /** \test See how it deals with an incomplete request in multiple chunks. */
1281 static int FTPParserTest07(void)
1282 {
1283  int result = 1;
1284  Flow f;
1285  uint8_t ftpbuf1[] = "PO";
1286  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1287  uint8_t ftpbuf2[] = "RT\r\n";
1288  uint32_t ftplen2 = sizeof(ftpbuf2) - 1; /* minus the \0 */
1289  TcpSession ssn;
1291 
1292  memset(&f, 0, sizeof(f));
1293  memset(&ssn, 0, sizeof(ssn));
1294 
1295  FLOW_INITIALIZE(&f);
1296  f.protoctx = (void *)&ssn;
1297  f.proto = IPPROTO_TCP;
1298  f.alproto = ALPROTO_FTP;
1299 
1301 
1302  FLOWLOCK_WRLOCK(&f);
1303  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1304  STREAM_TOSERVER | STREAM_START, ftpbuf1,
1305  ftplen1);
1306  if (r != 0) {
1307  SCLogDebug("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
1308  result = 0;
1309  FLOWLOCK_UNLOCK(&f);
1310  goto end;
1311  }
1312  FLOWLOCK_UNLOCK(&f);
1313 
1314  FLOWLOCK_WRLOCK(&f);
1315  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP,
1316  STREAM_TOSERVER | STREAM_EOF, ftpbuf2, ftplen2);
1317  if (r != 0) {
1318  SCLogDebug("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
1319  result = 0;
1320  FLOWLOCK_UNLOCK(&f);
1321  goto end;
1322  }
1323  FLOWLOCK_UNLOCK(&f);
1324 
1325  FtpState *ftp_state = f.alstate;
1326  if (ftp_state == NULL) {
1327  SCLogDebug("no ftp state: ");
1328  result = 0;
1329  goto end;
1330  }
1331 
1332  if (ftp_state->command != FTP_COMMAND_PORT) {
1333  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ",
1334  FTP_COMMAND_PORT, ftp_state->command);
1335  result = 0;
1336  goto end;
1337  }
1338 
1339 end:
1340  if (alp_tctx != NULL)
1341  AppLayerParserThreadCtxFree(alp_tctx);
1343  FLOW_DESTROY(&f);
1344  return result;
1345 }
1346 
1347 /** \test Test case where chunks are smaller than the delim length and the
1348  * last chunk is supposed to match the delim. */
1349 static int FTPParserTest10(void)
1350 {
1351  int result = 1;
1352  Flow f;
1353  uint8_t ftpbuf1[] = "PORT 1,2,3,4,5,6\r\n";
1354  uint32_t ftplen1 = sizeof(ftpbuf1) - 1; /* minus the \0 */
1355  TcpSession ssn;
1357  int r = 0;
1358  memset(&f, 0, sizeof(f));
1359  memset(&ssn, 0, sizeof(ssn));
1360 
1361  FLOW_INITIALIZE(&f);
1362  f.protoctx = (void *)&ssn;
1363  f.proto = IPPROTO_TCP;
1364  f.alproto = ALPROTO_FTP;
1365 
1367 
1368  uint32_t u;
1369  for (u = 0; u < ftplen1; u++) {
1370  uint8_t flags = 0;
1371 
1372  if (u == 0) flags = STREAM_TOSERVER|STREAM_START;
1373  else if (u == (ftplen1 - 1)) flags = STREAM_TOSERVER|STREAM_EOF;
1374  else flags = STREAM_TOSERVER;
1375 
1376  FLOWLOCK_WRLOCK(&f);
1377  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_FTP, flags,
1378  &ftpbuf1[u], 1);
1379  if (r != 0) {
1380  SCLogDebug("toserver chunk %" PRIu32 " returned %" PRId32 ", expected 0: ", u, r);
1381  result = 0;
1382  FLOWLOCK_UNLOCK(&f);
1383  goto end;
1384  }
1385  FLOWLOCK_UNLOCK(&f);
1386  }
1387 
1388  FtpState *ftp_state = f.alstate;
1389  if (ftp_state == NULL) {
1390  SCLogDebug("no ftp state: ");
1391  result = 0;
1392  goto end;
1393  }
1394 
1395  if (ftp_state->command != FTP_COMMAND_PORT) {
1396  SCLogDebug("expected command %" PRIu32 ", got %" PRIu32 ": ", FTP_COMMAND_PORT, ftp_state->command);
1397  result = 0;
1398  goto end;
1399  }
1400 
1401 end:
1402  if (alp_tctx != NULL)
1403  AppLayerParserThreadCtxFree(alp_tctx);
1405  FLOW_DESTROY(&f);
1406  return result;
1407 }
1408 #endif /* UNITTESTS */
1409 
1411 {
1412 #ifdef UNITTESTS
1413  UtRegisterTest("FTPParserTest01", FTPParserTest01);
1414  UtRegisterTest("FTPParserTest03", FTPParserTest03);
1415  UtRegisterTest("FTPParserTest06", FTPParserTest06);
1416  UtRegisterTest("FTPParserTest07", FTPParserTest07);
1417  UtRegisterTest("FTPParserTest10", FTPParserTest10);
1418 #endif /* UNITTESTS */
1419 }
1420 
#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:343
FileContainer * FileContainerAlloc(void)
allocate a FileContainer
Definition: util-file.c:380
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:242
#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 *)
File * FileOpenFile(FileContainer *ffc, const StreamingBufferConfig *sbcfg, 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:778
void StreamTcpFreeConfig(char quiet)
Definition: stream-tcp.c:669
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:239
#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:395
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:433
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:115
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:384
#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 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:404
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:324
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