#include "app-layer-expectation.h"
#include "util-spm.h"
+#include "util-mpm.h"
#include "util-unittest.h"
#include "util-debug.h"
#include "util-memcmp.h"
#include "output-json.h"
+typedef struct FTPThreadCtx_ {
+ MpmThreadCtx *ftp_mpm_thread_ctx;
+ PrefilterRuleStore *pmq;
+} FTPThreadCtx;
+
+#define FTP_MPM mpm_default_matcher
+
+static MpmCtx *ftp_mpm_ctx = NULL;
+
const FtpCommand FtpCommands[FTP_COMMAND_MAX + 1] = {
/* Parsed and handled */
- { FTP_COMMAND_PORT, "PORT", "port", 4},
- { FTP_COMMAND_EPRT, "EPRT", "eprt", 4},
- { FTP_COMMAND_AUTH_TLS, "AUTH TLS", "auth tls", 8},
- { FTP_COMMAND_PASV, "PASV", "pasv", 4},
- { FTP_COMMAND_RETR, "RETR", "retr", 4},
- { FTP_COMMAND_EPSV, "EPSV", "epsv", 4},
- { FTP_COMMAND_STOR, "STOR", "stor", 4},
+ { FTP_COMMAND_PORT, "PORT", 4},
+ { FTP_COMMAND_EPRT, "EPRT", 4},
+ { FTP_COMMAND_AUTH_TLS, "AUTH TLS", 8},
+ { FTP_COMMAND_PASV, "PASV", 4},
+ { FTP_COMMAND_RETR, "RETR", 4},
+ { FTP_COMMAND_EPSV, "EPSV", 4},
+ { FTP_COMMAND_STOR, "STOR", 4},
/* Parsed, but not handled */
- { FTP_COMMAND_ABOR, "ABOR", "abor", 4},
- { FTP_COMMAND_ACCT, "ACCT", "acct", 4},
- { FTP_COMMAND_ALLO, "ALLO", "allo", 4},
- { FTP_COMMAND_APPE, "APPE", "appe", 4},
- { FTP_COMMAND_CDUP, "CDUP", "cdup", 4},
- { FTP_COMMAND_CHMOD, "CHMOD", "chmod", 5},
- { FTP_COMMAND_CWD, "CWD", "cwd", 3},
- { FTP_COMMAND_DELE, "DELE", "dele", 4},
- { FTP_COMMAND_HELP, "HELP", "help", 4},
- { FTP_COMMAND_IDLE, "IDLE", "idle", 4},
- { FTP_COMMAND_LIST, "LIST", "list", 4},
- { FTP_COMMAND_MAIL, "MAIL", "mail", 4},
- { FTP_COMMAND_MDTM, "MDTM", "mdtm", 4},
- { FTP_COMMAND_MKD, "MKD", "mkd", 3},
- { FTP_COMMAND_MLFL, "MLFL", "mlfl", 4},
- { FTP_COMMAND_MODE, "MODE", "mode", 4},
- { FTP_COMMAND_MRCP, "MRCP", "mrcp", 4},
- { FTP_COMMAND_MRSQ, "MRSQ", "mrsq", 4},
- { FTP_COMMAND_MSAM, "MSAM", "msam", 4},
- { FTP_COMMAND_MSND, "MSND", "msnd", 4},
- { FTP_COMMAND_MSOM, "MSOM", "msom", 4},
- { FTP_COMMAND_NLST, "NLST", "nlst", 4},
- { FTP_COMMAND_NOOP, "NOOP", "noop", 4},
- { FTP_COMMAND_PASS, "PASS", "pass", 4},
- { FTP_COMMAND_PWD, "PWD", "pwd", 3},
- { FTP_COMMAND_QUIT, "QUIT", "quit", 4},
- { FTP_COMMAND_REIN, "REIN", "rein", 4},
- { FTP_COMMAND_REST, "REST", "rest", 4},
- { FTP_COMMAND_RMD, "RMD", "rmd", 3},
- { FTP_COMMAND_RNFR, "RNFR", "rnfr", 4},
- { FTP_COMMAND_RNTO, "RNTO", "rnto", 4},
- { FTP_COMMAND_SITE, "SITE", "site", 4},
- { FTP_COMMAND_SIZE, "SIZE", "size", 4},
- { FTP_COMMAND_SMNT, "SMNT", "smnt", 4},
- { FTP_COMMAND_STAT, "STAT", "stat", 4},
- { FTP_COMMAND_STOU, "STOU", "stou", 4},
- { FTP_COMMAND_STRU, "STRU", "stru", 4},
- { FTP_COMMAND_SYST, "SYST", "syst", 4},
- { FTP_COMMAND_TYPE, "TYPE", "type", 4},
- { FTP_COMMAND_UMASK, "UMASK", "umask", 5},
- { FTP_COMMAND_USER, "USER", "user", 4},
- { FTP_COMMAND_UNKNOWN, NULL, NULL, 0}
+ { FTP_COMMAND_ABOR, "ABOR", 4},
+ { FTP_COMMAND_ACCT, "ACCT", 4},
+ { FTP_COMMAND_ALLO, "ALLO", 4},
+ { FTP_COMMAND_APPE, "APPE", 4},
+ { FTP_COMMAND_CDUP, "CDUP", 4},
+ { FTP_COMMAND_CHMOD, "CHMOD", 5},
+ { FTP_COMMAND_CWD, "CWD", 3},
+ { FTP_COMMAND_DELE, "DELE", 4},
+ { FTP_COMMAND_HELP, "HELP", 4},
+ { FTP_COMMAND_IDLE, "IDLE", 4},
+ { FTP_COMMAND_LIST, "LIST", 4},
+ { FTP_COMMAND_MAIL, "MAIL", 4},
+ { FTP_COMMAND_MDTM, "MDTM", 4},
+ { FTP_COMMAND_MKD, "MKD", 3},
+ { FTP_COMMAND_MLFL, "MLFL", 4},
+ { FTP_COMMAND_MODE, "MODE", 4},
+ { FTP_COMMAND_MRCP, "MRCP", 4},
+ { FTP_COMMAND_MRSQ, "MRSQ", 4},
+ { FTP_COMMAND_MSAM, "MSAM", 4},
+ { FTP_COMMAND_MSND, "MSND", 4},
+ { FTP_COMMAND_MSOM, "MSOM", 4},
+ { FTP_COMMAND_NLST, "NLST", 4},
+ { FTP_COMMAND_NOOP, "NOOP", 4},
+ { FTP_COMMAND_PASS, "PASS", 4},
+ { FTP_COMMAND_PWD, "PWD", 3},
+ { FTP_COMMAND_QUIT, "QUIT", 4},
+ { FTP_COMMAND_REIN, "REIN", 4},
+ { FTP_COMMAND_REST, "REST", 4},
+ { FTP_COMMAND_RMD, "RMD", 3},
+ { FTP_COMMAND_RNFR, "RNFR", 4},
+ { FTP_COMMAND_RNTO, "RNTO", 4},
+ { FTP_COMMAND_SITE, "SITE", 4},
+ { FTP_COMMAND_SIZE, "SIZE", 4},
+ { FTP_COMMAND_SMNT, "SMNT", 4},
+ { FTP_COMMAND_STAT, "STAT", 4},
+ { FTP_COMMAND_STOU, "STOU", 4},
+ { FTP_COMMAND_STRU, "STRU", 4},
+ { FTP_COMMAND_SYST, "SYST", 4},
+ { FTP_COMMAND_TYPE, "TYPE", 4},
+ { FTP_COMMAND_UMASK, "UMASK", 5},
+ { FTP_COMMAND_USER, "USER", 4},
+ { FTP_COMMAND_UNKNOWN, NULL, 0}
};
uint64_t ftp_config_memcap = 0;
FTPFree(str, sizeof(FTPString));
}
+static void *FTPLocalStorageAlloc(void)
+{
+ /* needed by the mpm */
+ FTPThreadCtx *td = SCCalloc(1, sizeof(*td));
+ if (td == NULL) {
+ exit(EXIT_FAILURE);
+ }
+
+ td->pmq = SCCalloc(1, sizeof(*td->pmq));
+ if (td->pmq == NULL) {
+ exit(EXIT_FAILURE);
+ }
+ PmqSetup(td->pmq);
+
+ td->ftp_mpm_thread_ctx = SCCalloc(1, sizeof(MpmThreadCtx));
+ if (unlikely(td->ftp_mpm_thread_ctx == NULL)) {
+ exit(EXIT_FAILURE);
+ }
+ MpmInitThreadCtx(td->ftp_mpm_thread_ctx, FTP_MPM);
+ return td;
+}
+
+static void FTPLocalStorageFree(void *ptr)
+{
+ FTPThreadCtx *td = ptr;
+ if (td != NULL) {
+ if (td->pmq != NULL) {
+ PmqFree(td->pmq);
+ SCFree(td->pmq);
+ }
+
+ if (td->ftp_mpm_thread_ctx != NULL) {
+ mpm_table[FTP_MPM].DestroyThreadCtx(ftp_mpm_ctx, td->ftp_mpm_thread_ctx);
+ SCFree(td->ftp_mpm_thread_ctx);
+ }
+
+ SCFree(td);
+ }
+
+ return;
+}
static FTPTransaction *FTPTransactionCreate(FtpState *state)
{
SCEnter();
* transferred to the ftp server
* \param input input line of the command
* \param len of the command
+ * \param thread context
* \param cmd_descriptor when the command has been parsed
*
* \retval 1 when the command is parsed, 0 otherwise
*/
-static int FTPParseRequestCommand(uint8_t *input, uint32_t input_len, const FtpCommand **cmd_descriptor)
+static int FTPParseRequestCommand(uint8_t *input, uint32_t input_len,
+ FTPThreadCtx *td,
+ const FtpCommand **cmd_descriptor)
{
SCEnter();
- *cmd_descriptor = NULL;
-
- for (int i = 0; i < FTP_COMMAND_MAX - 1; i++) {
- if (!FtpCommands[i].command_length) {
- break;
- }
- if (input_len >= FtpCommands[i].command_length &&
- SCMemcmpLowercase(FtpCommands[i].command_name_lower,
- input, FtpCommands[i].command_length) == 0) {
-
- *cmd_descriptor = &FtpCommands[i];
- return 1;
- }
+ /* I don't like this pmq reset here. We'll devise a method later, that
+ * should make the use of the mpm very efficient */
+ PmqReset(td->pmq);
+ int mpm_cnt = mpm_table[FTP_MPM].Search(ftp_mpm_ctx, td->ftp_mpm_thread_ctx,
+ td->pmq, input, input_len);
+ if (mpm_cnt) {
+ *cmd_descriptor = &FtpCommands[td->pmq->rule_id_array[0]];
+ SCReturn(1);
}
- return 0;
+
+ *cmd_descriptor = NULL;
+ SCReturn(0);
}
struct FtpTransferCmd {
uint8_t *input, uint32_t input_len,
void *local_data, const uint8_t flags)
{
+ FTPThreadCtx *thread_data = local_data;
+
SCEnter();
/* PrintRawDataFp(stdout, input,input_len); */
while (FTPGetLine(state) >= 0) {
const FtpCommand *cmd_descriptor;
- if (!FTPParseRequestCommand(state->current_line, state->current_line_len, &cmd_descriptor)) {
+ if (!FTPParseRequestCommand(state->current_line, state->current_line_len, thread_data, &cmd_descriptor)) {
state->command = FTP_COMMAND_UNKNOWN;
continue;
}
while ((tx = TAILQ_FIRST(&fstate->tx_list))) {
TAILQ_REMOVE(&fstate->tx_list, tx, next);
SCLogDebug("[%s] state %p id %"PRIu64", Freeing %d bytes at %p",
- tx->command_descriptor->command_name_upper,
+ tx->command_descriptor->command_name,
s, tx->tx_id,
tx->request_length, tx->request);
FTPTransactionFree(tx);
SCReturnPtr(ftpdata_state->files, "FileContainer");
}
+static void FTPSetMpmState(void)
+{
+ ftp_mpm_ctx = SCMalloc(sizeof(MpmCtx));
+ if (unlikely(ftp_mpm_ctx == NULL)) {
+ exit(EXIT_FAILURE);
+ }
+ memset(ftp_mpm_ctx, 0, sizeof(MpmCtx));
+ MpmInitCtx(ftp_mpm_ctx, FTP_MPM);
+
+ uint32_t i = 0;
+ for (i = 0; i < sizeof(FtpCommands)/sizeof(FtpCommand) - 1; i++) {
+ const FtpCommand *cmd = &FtpCommands[i];
+ MpmAddPatternCI(ftp_mpm_ctx,
+ (uint8_t *)cmd->command_name,
+ cmd->command_length,
+ 0 /* defunct */, 0 /* defunct */,
+ i /* id */, i /* rule id */ , 0 /* no flags */);
+ }
+
+ mpm_table[FTP_MPM].Prepare(ftp_mpm_ctx);
+
+}
+
+static void FTPFreeMpmState(void)
+{
+ if (ftp_mpm_ctx != NULL) {
+ mpm_table[FTP_MPM].DestroyCtx(ftp_mpm_ctx);
+ SCFree(ftp_mpm_ctx);
+ ftp_mpm_ctx = NULL;
+ }
+}
+
void RegisterFTPParsers(void)
{
const char *proto_name = "ftp";
AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_FTP, FTPStateGetTxLogged,
FTPStateSetTxLogged);
+ AppLayerParserRegisterLocalStorageFunc(IPPROTO_TCP, ALPROTO_FTP, FTPLocalStorageAlloc,
+ FTPLocalStorageFree);
AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_FTP, FTPGetTxCnt);
AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_FTP, FTPGetAlstateProgress);
SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
"still on.", proto_name);
}
+
+ FTPSetMpmState();
+
#ifdef UNITTESTS
AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_FTP, FTPParserRegisterTests);
#endif
return ftpd;
}
+/**
+ * \brief Free memory allocated for global SMTP parser state.
+ */
+void FTPParserCleanup(void)
+{
+ FTPFreeMpmState();
+}
+
/* UNITTESTS */
#ifdef UNITTESTS