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