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;
}
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,
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);
FilePrune(s->files);
end:
SCReturnInt(retval);
}
@ -144,6 +156,7 @@ int HTPFileStoreChunk(HtpState *s, uint8_t *data, uint32_t data_len) {
retval = -2;
}
FilePrune(s->files);
end:
SCReturnInt(retval);
}
@ -183,6 +196,7 @@ int HTPFileClose(HtpState *s, uint8_t *data, uint32_t data_len, uint8_t flags) {
retval = -2;
}
FilePrune(s->files);
end:
SCReturnInt(retval);
}

@ -74,6 +74,7 @@ static int DetectFileInspect(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Flo
SigMatch *sm = NULL;
int r = 0;
int match = 0;
int store_r = 0;
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)
break;
store_r = 1;
/* if this is a filestore sig, and the sig can't match
* 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);
}
@ -189,7 +195,7 @@ int DetectFileInspectHttp(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, Flow *
start_tx = AppLayerTransactionGetInspectId(f);
/* tx cnt is incremented after request finishes, so we need to inspect
* response one before the lowest. */
if (flags & STREAM_TOCLIENT && start_tx)
if ((flags & STREAM_TOCLIENT) && start_tx > 0)
start_tx--;
end_tx = list_size(htp_state->connp->conn->transactions);
}

@ -596,6 +596,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx,
}
} else {
if (inspect_flags != 0 && (inspect_flags == match_flags)) {
match_flags |= DE_STATE_FLAG_FULL_MATCH;
r = 1;
}
}
@ -667,20 +668,32 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete
SCLogDebug("id of signature to inspect: %"PRIuMAX,
(uintmax_t)s->id);
RULE_PROFILING_START;
/* if we already fully matched previously, detect that here */
if (item->flags & DE_STATE_FLAG_FULL_MATCH) {
det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_FULL;
goto next_sig;
if (item->flags & DE_STATE_FLAG_FILE_INSPECT && f->de_state->flags & DE_STATE_FILE_NEW) {
/* 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 (item->flags & DE_STATE_FLAG_SIG_CANT_MATCH) {
det_ctx->de_state_sig_array[item->sid] = DE_STATE_MATCH_NOMATCH;
goto next_sig;
if (item->flags & DE_STATE_FLAG_FILE_INSPECT && f->de_state->flags & DE_STATE_FILE_NEW) {
/* 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 */
/* first, check uricontent */
@ -937,7 +950,6 @@ int DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, Dete
SCLogDebug("signature %"PRIu32" match state %s",
s->id, DeStateMatchResultToString(det_ctx->de_state_sig_array[item->sid]));
next_sig:
RULE_PROFILING_END(s, match);
}
@ -955,6 +967,7 @@ next_sig:
}
end:
f->de_state->flags &= ~DE_STATE_FILE_NEW;
SCMutexUnlock(&f->de_state_m);
SCReturnInt(0);
}
@ -978,6 +991,18 @@ int DeStateRestartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngin
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
#include "flow-util.h"

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

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

@ -1775,17 +1775,31 @@ end:
p->flow->flags |= FLOW_SGH_TOCLIENT;
}
/* if we know both sides of the flow have had their sgh check
* and both are null, we will never decide to store. So disable
* storage completely. */
if (p->flow->flags & FLOW_SGH_TOCLIENT && p->flow->flags & FLOW_SGH_TOSERVER &&
(p->flow->sgh_toserver == NULL ||
if (p->flow->flags & FLOW_SGH_TOCLIENT && p->flow->flags & FLOW_SGH_TOSERVER) {
/* if we know both sides of the flow have had their sgh check
* and both are null, we will never decide to store. So disable
* storage completely. */
if ((p->flow->sgh_toserver == NULL ||
p->flow->sgh_toserver->filestore_cnt == 0)
&&
(p->flow->sgh_toclient == NULL ||
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
* set. */
uint16_t filestore_cnt;
#if __WORDSIZE == 64
uint32_t pad2;
#endif
/** Array with sig ptrs... size is sig_cnt * sizeof(Signature *) */
Signature **match_array;

@ -91,7 +91,9 @@
#define FLOW_TC_PM_PP_ALPROTO_DETECT_DONE 0x00400000
#define FLOW_TIMEOUT_REASSEMBLY_DONE 0x00800000
/** 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 */
#define FLOW_IPV4 0x01000000

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

Loading…
Cancel
Save