file extract: pruning

Add pruning of files in memory so we keep only memory what we really need.
Fix magic logic.
Reset file part of the de_state on receiving another file in the same tx.
remotes/origin/master-1.2.x
Victor Julien 15 years ago
parent 1c934acc85
commit 04ea70ccf7

@ -93,9 +93,20 @@ int HTPFileOpen(HtpState *s, uint8_t *filename, uint16_t filename_len,
} }
} }
if (s->f->flags & FLOW_FILE_NO_HANDLING) { if (s->f->flags & FLOW_FILE_NO_STORE) {
flags |= FILE_NOSTORE; flags |= FILE_NOSTORE;
} }
if (s->f->flags & FLOW_FILE_NO_MAGIC) {
flags |= FILE_NOMAGIC;
}
/* if the previous file is in the same txid, we
* reset the file part of the stateful detection
* engine. */
if (s->files && s->files->tail && s->files->tail->txid == txid) {
SCLogDebug("new file in same tx, resetting de_state");
DeStateResetFileInspection(s->f);
}
if (FileOpenFile(s->files, filename, filename_len, if (FileOpenFile(s->files, filename, filename_len,
data, data_len, flags) == NULL) data, data_len, flags) == NULL)
@ -105,6 +116,7 @@ int HTPFileOpen(HtpState *s, uint8_t *filename, uint16_t filename_len,
FileSetTx(s->files->tail, txid); FileSetTx(s->files->tail, txid);
FilePrune(s->files);
end: end:
SCReturnInt(retval); SCReturnInt(retval);
} }
@ -144,6 +156,7 @@ int HTPFileStoreChunk(HtpState *s, uint8_t *data, uint32_t data_len) {
retval = -2; retval = -2;
} }
FilePrune(s->files);
end: end:
SCReturnInt(retval); SCReturnInt(retval);
} }
@ -183,6 +196,7 @@ int HTPFileClose(HtpState *s, uint8_t *data, uint32_t data_len, uint8_t flags) {
retval = -2; retval = -2;
} }
FilePrune(s->files);
end: end:
SCReturnInt(retval); SCReturnInt(retval);
} }

@ -74,6 +74,7 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Flo
SigMatch *sm = NULL; SigMatch *sm = NULL;
int r = 0; int r = 0;
int match = 0; int match = 0;
int store_r = 0;
SCLogDebug("file inspection... %p", ffc); SCLogDebug("file inspection... %p", ffc);
@ -132,8 +133,11 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Flo
} }
} }
/* continue inspection for other files as we may want to store
* those as well. We'll return 1 (match) regardless of their
* results though */
if (r == 1) if (r == 1)
break; store_r = 1;
/* if this is a filestore sig, and the sig can't match /* if this is a filestore sig, and the sig can't match
* return 3 so we can distinguish */ * return 3 so we can distinguish */
@ -145,6 +149,8 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Flo
} }
} }
if (store_r == 1)
r = 1;
SCReturnInt(r); SCReturnInt(r);
} }
@ -189,7 +195,7 @@ int DetectFileInspectHttp(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Flow *
start_tx = AppLayerTransactionGetInspectId(f); start_tx = AppLayerTransactionGetInspectId(f);
/* tx cnt is incremented after request finishes, so we need to inspect /* tx cnt is incremented after request finishes, so we need to inspect
* response one before the lowest. */ * response one before the lowest. */
if (flags & STREAM_TOCLIENT && start_tx) if ((flags & STREAM_TOCLIENT) && start_tx > 0)
start_tx--; start_tx--;
end_tx = list_size(htp_state->connp->conn->transactions); end_tx = list_size(htp_state->connp->conn->transactions);
} }

@ -596,6 +596,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx,
} }
} else { } else {
if (inspect_flags != 0 && (inspect_flags == match_flags)) { if (inspect_flags != 0 && (inspect_flags == match_flags)) {
match_flags |= DE_STATE_FLAG_FULL_MATCH;
r = 1; r = 1;
} }
} }
@ -667,20 +668,32 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete
SCLogDebug("id of signature to inspect: %"PRIuMAX, SCLogDebug("id of signature to inspect: %"PRIuMAX,
(uintmax_t)s->id); (uintmax_t)s->id);
RULE_PROFILING_START;
/* if we already fully matched previously, detect that here */ /* if we already fully matched previously, detect that here */
if (item->flags & DE_STATE_FLAG_FULL_MATCH) { if (item->flags & DE_STATE_FLAG_FULL_MATCH) {
det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_FULL; if (item->flags & DE_STATE_FLAG_FILE_INSPECT && f->de_state->flags & DE_STATE_FILE_NEW) {
goto next_sig; /* new file, fall through */
item->flags &= ~DE_STATE_FLAG_FILE_INSPECT;
} else {
det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_FULL;
SCLogDebug("full match state");
continue;
}
} }
/* if we know for sure we can't ever match, detect that here */ /* if we know for sure we can't ever match, detect that here */
if (item->flags & DE_STATE_FLAG_SIG_CANT_MATCH) { if (item->flags & DE_STATE_FLAG_SIG_CANT_MATCH) {
det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NOMATCH; if (item->flags & DE_STATE_FLAG_FILE_INSPECT && f->de_state->flags & DE_STATE_FILE_NEW) {
goto next_sig; /* new file, fall through */
item->flags &= ~DE_STATE_FLAG_FILE_INSPECT;
item->flags &= ~DE_STATE_FLAG_SIG_CANT_MATCH;
} else {
det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NOMATCH;
continue;
}
} }
RULE_PROFILING_START;
/* let's continue detection */ /* let's continue detection */
/* first, check uricontent */ /* first, check uricontent */
@ -937,7 +950,6 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete
SCLogDebug("signature %"PRIu32" match state %s", SCLogDebug("signature %"PRIu32" match state %s",
s->id, DeStateMatchResultToString(det_ctx->de_state_sig_array[item->sid])); s->id, DeStateMatchResultToString(det_ctx->de_state_sig_array[item->sid]));
next_sig:
RULE_PROFILING_END(s, match); RULE_PROFILING_END(s, match);
} }
@ -955,6 +967,7 @@ next_sig:
} }
end: end:
f->de_state->flags &= ~DE_STATE_FILE_NEW;
SCMutexUnlock(&f->de_state_m); SCMutexUnlock(&f->de_state_m);
SCReturnInt(0); SCReturnInt(0);
} }
@ -978,6 +991,18 @@ int DeStateRestartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngin
SCReturnInt(0); SCReturnInt(0);
} }
void DeStateResetFileInspection(Flow *f) {
if (f == NULL) {
SCReturn;
}
SCMutexLock(&f->de_state_m);
if (f->de_state != NULL) {
f->de_state->flags |= DE_STATE_FILE_NEW;
}
SCMutexUnlock(&f->de_state_m);
}
#ifdef UNITTESTS #ifdef UNITTESTS
#include "flow-util.h" #include "flow-util.h"

@ -76,6 +76,7 @@
/* state flags */ /* state flags */
#define DE_STATE_FILE_STORE_DISABLED 0x0001 #define DE_STATE_FILE_STORE_DISABLED 0x0001
#define DE_STATE_FILE_NEW 0x0002
/** per signature detection engine state */ /** per signature detection engine state */
typedef enum { typedef enum {
@ -138,6 +139,8 @@ int DeStateDetectContinueDetection(ThreadVars *, DetectEngineCtx *,
const char *DeStateMatchResultToString(DeStateMatchResult); const char *DeStateMatchResultToString(DeStateMatchResult);
int DeStateUpdateInspectTransactionId(Flow *, char); int DeStateUpdateInspectTransactionId(Flow *, char);
void DeStateResetFileInspection(Flow *f);
#endif /* __DETECT_ENGINE_STATE_H__ */ #endif /* __DETECT_ENGINE_STATE_H__ */
/** /**

@ -88,6 +88,7 @@ int FilemagicLookup(File *file) {
SCReturnInt(-1); SCReturnInt(-1);
} }
/* initial chunk already matching our requirement */
if (file->chunks_head->len >= FILEMAGIC_MIN_SIZE) { if (file->chunks_head->len >= FILEMAGIC_MIN_SIZE) {
file->magic = MagicLookup(file->chunks_head->data, FILEMAGIC_MIN_SIZE); file->magic = MagicLookup(file->chunks_head->data, FILEMAGIC_MIN_SIZE);
} else { } else {
@ -271,6 +272,7 @@ static int DetectFilemagicSetup (DetectEngineCtx *de_ctx, Signature *s, char *st
AppLayerHtpNeedFileInspection(); AppLayerHtpNeedFileInspection();
/** \todo remove this once we support more than http */
s->alproto = ALPROTO_HTTP; s->alproto = ALPROTO_HTTP;
s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_MAGIC); s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_MAGIC);

@ -1775,17 +1775,31 @@ end:
p->flow->flags |= FLOW_SGH_TOCLIENT; p->flow->flags |= FLOW_SGH_TOCLIENT;
} }
/* if we know both sides of the flow have had their sgh check if (p->flow->flags & FLOW_SGH_TOCLIENT && p->flow->flags & FLOW_SGH_TOSERVER) {
* and both are null, we will never decide to store. So disable /* if we know both sides of the flow have had their sgh check
* storage completely. */ * and both are null, we will never decide to store. So disable
if (p->flow->flags & FLOW_SGH_TOCLIENT && p->flow->flags & FLOW_SGH_TOSERVER && * storage completely. */
(p->flow->sgh_toserver == NULL || if ((p->flow->sgh_toserver == NULL ||
p->flow->sgh_toserver->filestore_cnt == 0) p->flow->sgh_toserver->filestore_cnt == 0)
&& &&
(p->flow->sgh_toclient == NULL || (p->flow->sgh_toclient == NULL ||
p->flow->sgh_toclient->filestore_cnt == 0)) p->flow->sgh_toclient->filestore_cnt == 0))
{ {
FileDisableStoring(p->flow); FileDisableStoring(p->flow);
}
/* check if this flow needs magic, if not disable it */
if (!(FileForceMagic())) {
if ((p->flow->sgh_toserver == NULL ||
!(p->flow->sgh_toserver->flags & SIG_GROUP_HEAD_HAVEFILEMAGIC))
&&
(p->flow->sgh_toclient == NULL ||
!(p->flow->sgh_toclient->flags & SIG_GROUP_HEAD_HAVEFILEMAGIC)))
{
SCLogInfo("disabling magic for flow");
FileDisableMagic(p->flow);
}
}
} }
} }

@ -921,9 +921,6 @@ typedef struct SigGroupHead_ {
/** the number of signatures in this sgh that have the filestore keyword /** the number of signatures in this sgh that have the filestore keyword
* set. */ * set. */
uint16_t filestore_cnt; uint16_t filestore_cnt;
#if __WORDSIZE == 64
uint32_t pad2;
#endif
/** Array with sig ptrs... size is sig_cnt * sizeof(Signature *) */ /** Array with sig ptrs... size is sig_cnt * sizeof(Signature *) */
Signature **match_array; Signature **match_array;

@ -91,7 +91,9 @@
#define FLOW_TC_PM_PP_ALPROTO_DETECT_DONE 0x00400000 #define FLOW_TC_PM_PP_ALPROTO_DETECT_DONE 0x00400000
#define FLOW_TIMEOUT_REASSEMBLY_DONE 0x00800000 #define FLOW_TIMEOUT_REASSEMBLY_DONE 0x00800000
/** even if the flow has files, don't store 'm */ /** even if the flow has files, don't store 'm */
#define FLOW_FILE_NO_HANDLING 0x01000000 #define FLOW_FILE_NO_STORE 0x01000000
/** no magic on files in this flow */
#define FLOW_FILE_NO_MAGIC 0x02000000
/** flow is ipv4 */ /** flow is ipv4 */
#define FLOW_IPV4 0x01000000 #define FLOW_IPV4 0x01000000

@ -61,7 +61,6 @@ static void LogFileLogDeInitCtx(OutputCtx *);
SC_ATOMIC_DECLARE(unsigned int, file_id); SC_ATOMIC_DECLARE(unsigned int, file_id);
static char g_logfile_base_dir[PATH_MAX] = "/tmp"; static char g_logfile_base_dir[PATH_MAX] = "/tmp";
static int g_logfile_force_magic = 0;
void TmModuleLogFileLogRegister (void) { void TmModuleLogFileLogRegister (void) {
tmm_modules[TMM_FILELOG].name = MODULE_NAME; tmm_modules[TMM_FILELOG].name = MODULE_NAME;
@ -85,7 +84,6 @@ typedef struct LogFileLogThread_ {
uint32_t file_cnt; uint32_t file_cnt;
} LogFileLogThread; } LogFileLogThread;
static void CreateTimeString (const struct timeval *ts, char *str, size_t size) { static void CreateTimeString (const struct timeval *ts, char *str, size_t size) {
time_t time = ts->tv_sec; time_t time = ts->tv_sec;
struct tm local_tm; struct tm local_tm;
@ -151,31 +149,30 @@ static void LogFileLogCloseMetaFile(File *ff) {
char metafilename[PATH_MAX] = ""; char metafilename[PATH_MAX] = "";
snprintf(metafilename, sizeof(metafilename), "%s.meta", filename); snprintf(metafilename, sizeof(metafilename), "%s.meta", filename);
FILE *fp = fopen(metafilename, "a"); FILE *fp = fopen(metafilename, "a");
if (fp != NULL) {
fprintf(fp, "MAGIC: %s\n",
ff->magic ? ff->magic : "<unknown>");
if (g_logfile_force_magic || ff->magic != NULL) { switch (ff->state) {
if (g_logfile_force_magic && ff->magic == NULL) { case FILE_STATE_CLOSED:
FilemagicLookup(ff); fprintf(fp, "STATE: CLOSED\n");
break;
case FILE_STATE_TRUNCATED:
fprintf(fp, "STATE: TRUNCATED\n");
break;
case FILE_STATE_ERROR:
fprintf(fp, "STATE: ERROR\n");
break;
default:
fprintf(fp, "STATE: UNKNOWN\n");
break;
} }
fprintf(fp, "MAGIC: %s\n", ff->magic ? ff->magic : "<unknown>"); fprintf(fp, "SIZE: %"PRIu64"\n", ff->size);
}
switch (ff->state) { fclose(fp);
case FILE_STATE_CLOSED: } else {
fprintf(fp, "STATE: CLOSED\n"); SCLogInfo("opening %s failed: %s", metafilename, strerror(errno));
break;
case FILE_STATE_TRUNCATED:
fprintf(fp, "STATE: TRUNCATED\n");
break;
case FILE_STATE_ERROR:
fprintf(fp, "STATE: ERROR\n");
break;
default:
fprintf(fp, "STATE: UNKNOWN\n");
break;
} }
fprintf(fp, "SIZE: %"PRIu64"\n", ff->size);
fclose(fp);
} }
static TmEcode LogFileLogWrap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq, int ipver) static TmEcode LogFileLogWrap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq, int ipver)
@ -197,9 +194,12 @@ static TmEcode LogFileLogWrap(ThreadVars *tv, Packet *p, void *data, PacketQueue
if (ffc != NULL) { if (ffc != NULL) {
File *ff; File *ff;
for (ff = ffc->head; ff != NULL; ff = ff->next) { for (ff = ffc->head; ff != NULL; ff = ff->next) {
int file_open = 0;
int file_fd = -1; int file_fd = -1;
if (FileForceMagic() && ff->magic == NULL) {
FilemagicLookup(ff);
}
SCLogDebug("ff %p", ff); SCLogDebug("ff %p", ff);
if (ff->state == FILE_STATE_STORED) { if (ff->state == FILE_STATE_STORED) {
SCLogDebug("ff->state == FILE_STATE_STORED"); SCLogDebug("ff->state == FILE_STATE_STORED");
@ -215,7 +215,7 @@ static TmEcode LogFileLogWrap(ThreadVars *tv, Packet *p, void *data, PacketQueue
for (ffd = ff->chunks_head; ffd != NULL; ffd = ffd->next) { for (ffd = ff->chunks_head; ffd != NULL; ffd = ffd->next) {
SCLogDebug("ffd %p", ffd); SCLogDebug("ffd %p", ffd);
if (ffd->stored == 1) { if (ffd->stored == 1) {
if (file_close == 1) { if (file_close == 1 && ffd->next == NULL) {
LogFileLogCloseMetaFile(ff); LogFileLogCloseMetaFile(ff);
ff->state = FILE_STATE_STORED; ff->state = FILE_STATE_STORED;
} }
@ -225,56 +225,65 @@ static TmEcode LogFileLogWrap(ThreadVars *tv, Packet *p, void *data, PacketQueue
/* store */ /* store */
SCLogDebug("trying to open file"); SCLogDebug("trying to open file");
char filename[PATH_MAX] = "";
if (ff->file_id == 0) { if (ff->file_id == 0) {
ff->file_id = SC_ATOMIC_ADD(file_id, 1); ff->file_id = SC_ATOMIC_ADD(file_id, 1);
file_open = 1;
}
char filename[PATH_MAX] = ""; snprintf(filename, sizeof(filename), "%s/file.%u",
snprintf(filename, sizeof(filename), "%s/file.%u", g_logfile_base_dir, ff->file_id);
g_logfile_base_dir, ff->file_id);
file_fd = open(filename, O_CREAT | O_TRUNC | O_NOFOLLOW | O_WRONLY, 0644); file_fd = open(filename, O_CREAT | O_TRUNC | O_NOFOLLOW | O_WRONLY, 0644);
if (file_fd == -1) { if (file_fd == -1) {
SCLogDebug("failed to open file"); SCLogDebug("failed to open file");
continue; continue;
} }
if (file_open == 1) {
/* create a .meta file that contains time, src/dst/sp/dp/proto */ /* create a .meta file that contains time, src/dst/sp/dp/proto */
LogFileLogCreateMetaFile(p, ff, filename, ipver); LogFileLogCreateMetaFile(p, ff, filename, ipver);
aft->file_cnt++; aft->file_cnt++;
} else { } else {
SCLogDebug("already open file"); snprintf(filename, sizeof(filename), "%s/file.%u",
g_logfile_base_dir, ff->file_id);
file_fd = open(filename, O_APPEND | O_NOFOLLOW | O_WRONLY);
if (file_fd == -1) {
SCLogDebug("failed to open file %s: %s", filename, strerror(errno));
continue;
}
} }
ssize_t r = write(file_fd, (const void *)ffd->data, (size_t)ffd->len); ssize_t r = write(file_fd, (const void *)ffd->data, (size_t)ffd->len);
if (r == -1) { if (r == -1) {
SCLogDebug("write failed: %s", strerror(errno)); SCLogDebug("write failed: %s", strerror(errno));
close(file_fd);
file_fd = -1;
continue; continue;
} }
close(file_fd);
file_fd = -1;
if (ff->state == FILE_STATE_CLOSED || if (ff->state == FILE_STATE_CLOSED ||
ff->state == FILE_STATE_TRUNCATED || ff->state == FILE_STATE_TRUNCATED ||
ff->state == FILE_STATE_ERROR || ff->state == FILE_STATE_ERROR ||
file_close == 1) (file_close == 1 && ff->state < FILE_STATE_CLOSED))
{ {
if (ffd->next == NULL) { if (ffd->next == NULL) {
LogFileLogCloseMetaFile(ff); LogFileLogCloseMetaFile(ff);
ff->state = FILE_STATE_STORED; ff->state = FILE_STATE_STORED;
if (file_fd != -1) {
close(file_fd);
file_fd = -1;
}
} }
} }
ffd->stored = 1; ffd->stored = 1;
} }
} }
FilePrune(ffc);
} }
SCMutexUnlock(&p->flow->m); SCMutexUnlock(&p->flow->m);
SCReturnInt(TM_ECODE_OK); SCReturnInt(TM_ECODE_OK);
} }
@ -290,6 +299,7 @@ TmEcode LogFileLogIPv6(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, P
TmEcode LogFileLog (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) TmEcode LogFileLog (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq)
{ {
SCEnter(); SCEnter();
int r = TM_ECODE_OK;
/* no flow, no htp state */ /* no flow, no htp state */
if (p->flow == NULL) { if (p->flow == NULL) {
@ -300,13 +310,15 @@ TmEcode LogFileLog (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pack
SCReturnInt(TM_ECODE_OK); SCReturnInt(TM_ECODE_OK);
} }
SCLogDebug("p->pcap_cnt %"PRIu64, p->pcap_cnt);
if (PKT_IS_IPV4(p)) { if (PKT_IS_IPV4(p)) {
SCReturnInt(LogFileLogIPv4(tv, p, data, pq, postpq)); r = LogFileLogIPv4(tv, p, data, pq, postpq);
} else if (PKT_IS_IPV6(p)) { } else if (PKT_IS_IPV6(p)) {
SCReturnInt(LogFileLogIPv6(tv, p, data, pq, postpq)); r = LogFileLogIPv6(tv, p, data, pq, postpq);
} }
SCReturnInt(TM_ECODE_OK); SCReturnInt(r);
} }
TmEcode LogFileLogThreadInit(ThreadVars *t, void *initdata, void **data) TmEcode LogFileLogThreadInit(ThreadVars *t, void *initdata, void **data)
@ -395,7 +407,7 @@ OutputCtx *LogFileLogInitCtx(ConfNode *conf)
const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic"); const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic");
if (force_magic != NULL && ConfValIsTrue(force_magic)) { if (force_magic != NULL && ConfValIsTrue(force_magic)) {
g_logfile_force_magic = 1; FileForceMagicEnable();
SCLogInfo("forcing magic lookup for stored files"); SCLogInfo("forcing magic lookup for stored files");
} }

Loading…
Cancel
Save