diff --git a/TODO b/TODO index 6cc3031044..165becf949 100644 --- a/TODO +++ b/TODO @@ -17,3 +17,7 @@ MAIN: - move packet preallocation into it's own function - create a cleanup function + +CUSTOM LOGGING: +- idea: add a logging module that can be told to output things based on flowvars + diff --git a/src/Makefile.am b/src/Makefile.am index 6817ca8d06..0984312832 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,6 +60,7 @@ tmqh-simple.c tmqh-simple.h \ tmqh-nfq.c tmqh-nfq.h \ tmqh-packetpool.c tmqh-packetpool.h \ alert-fastlog.c alert-fastlog.h \ +log-httplog.c log-httplog.h \ alert-unified-log.c alert-unified-log.h \ alert-unified-alert.c alert-unified-alert.h diff --git a/src/detect.c b/src/detect.c index 390c07d296..d0decfc0e0 100644 --- a/src/detect.c +++ b/src/detect.c @@ -63,11 +63,28 @@ void SigLoadSignatures (void) { Signature *prevsig = NULL, *sig; + /* The next 3 rules handle HTTP header capture. */ + + /* http_uri -- for uricontent */ sig = SigInit("alert tcp any any -> any any (msg:\"HTTP URI cap\"; flow:to_server; content:\"GET \"; depth:4; pcre:\"/^GET (?P.*) HTTP\\/\\d\\.\\d\\r\\n/G\"; depth:400; noalert; sid:1;)"); if (sig) { prevsig = sig; sig_list = sig; } + + /* http_host -- for the log-httplog module */ + sig = SigInit("alert tcp any any -> any any (msg:\"HTTP host cap\"; flow:to_server; content:\"Host:\"; depth:400; pcre:\"/^Host: (?P.*)\\r\\n/m\"; noalert; sid:2;)"); + if (sig == NULL) + return; + prevsig->next = sig; + prevsig = sig; + + /* http_ua -- for the log-httplog module */ + sig = SigInit("alert tcp any any -> any any (msg:\"HTTP UA cap\"; flow:to_server; content:\"User-Agent:\"; depth:400; pcre:\"/^User-Agent: (?P.*)\\r\\n/m\"; noalert; sid:3;)"); + if (sig == NULL) + return; + prevsig->next = sig; + prevsig = sig; /* sig = SigInit("alert ip 192.168.0.0/24 any -> 80.126.224.247 any (msg:\"ViCtOr nocase test\"; sid:2000; rev:13; content:ViCtOr; nocase; depth:150;)"); if (sig == NULL) @@ -136,11 +153,6 @@ void SigLoadSignatures (void) prevsig->next = sig; prevsig = sig; - sig = SigInit("alert tcp 192.168.0.10 any -> 0.0.0.0/0 any (msg:\"HTTP host code cap\"; flow:to_server; content:Host:; depth:300; pcre:\"/^Host: (?.*)\\r\\n/m\"; sid:6;)"); - if (sig == NULL) - return; - prevsig->next = sig; - prevsig = sig; sig = SigInit("alert tcp 192.168.0.12 any -> 0.0.0.0/0 any (msg:\"HTTP http_host flowvar www.inliniac.net\"; flow:to_server; flowvar:http_host,\"www.inliniac.net\"; sid:7;)"); if (sig) { prevsig->next = sig; diff --git a/src/log-httplog.c b/src/log-httplog.c new file mode 100644 index 0000000000..1c6452af9d --- /dev/null +++ b/src/log-httplog.c @@ -0,0 +1,215 @@ +/* Copyright (c) 2008 Victor Julien */ + +/* httplog + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vips.h" +#include "debug.h" +#include "detect.h" +#include "flow.h" +#include "flow-var.h" + +#include "threadvars.h" +#include "tm-modules.h" + +#include "threads.h" + +#include "util-unittest.h" + +int LogHttplog (ThreadVars *, Packet *, void *); +int LogHttplogIPv4(ThreadVars *, Packet *, void *); +int LogHttplogIPv6(ThreadVars *, Packet *, void *); +int LogHttplogThreadInit(ThreadVars *, void **); +int LogHttplogThreadDeinit(ThreadVars *, void *); + +void TmModuleLogHttplogRegister (void) { + tmm_modules[TMM_LOGHTTPLOG].name = "LogHttplog"; + tmm_modules[TMM_LOGHTTPLOG].Init = LogHttplogThreadInit; + tmm_modules[TMM_LOGHTTPLOG].Func = LogHttplog; + tmm_modules[TMM_LOGHTTPLOG].Deinit = LogHttplogThreadDeinit; + tmm_modules[TMM_LOGHTTPLOG].RegisterTests = NULL; +} + +void TmModuleLogHttplogIPv4Register (void) { + tmm_modules[TMM_LOGHTTPLOG4].name = "LogHttplogIPv4"; + tmm_modules[TMM_LOGHTTPLOG4].Init = LogHttplogThreadInit; + tmm_modules[TMM_LOGHTTPLOG4].Func = LogHttplogIPv4; + tmm_modules[TMM_LOGHTTPLOG4].Deinit = LogHttplogThreadDeinit; + tmm_modules[TMM_LOGHTTPLOG4].RegisterTests = NULL; +} + +void TmModuleLogHttplogIPv6Register (void) { + tmm_modules[TMM_LOGHTTPLOG6].name = "LogHttplogIPv6"; + tmm_modules[TMM_LOGHTTPLOG6].Init = LogHttplogThreadInit; + tmm_modules[TMM_LOGHTTPLOG6].Func = LogHttplogIPv6; + tmm_modules[TMM_LOGHTTPLOG6].Deinit = LogHttplogThreadDeinit; + tmm_modules[TMM_LOGHTTPLOG6].RegisterTests = NULL; +} + +typedef struct _LogHttplogThread { + FILE *fp; +} LogHttplogThread; + +static void CreateTimeString (const struct timeval *ts, char *str, size_t size) { + time_t time = ts->tv_sec; + struct tm *t = gmtime(&time); + u_int32_t sec = ts->tv_sec % 86400; + + snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", + t->tm_mon + 1, t->tm_mday, t->tm_year - 100, + sec / 3600, (sec % 3600) / 60, sec % 60, + (u_int32_t) ts->tv_usec); +} + +int LogHttplogIPv4(ThreadVars *tv, Packet *p, void *data) +{ + LogHttplogThread *aft = (LogHttplogThread *)data; + int i; + char timebuf[64], hostname[256] = "unknown", ua[256] = "unknown"; + FlowVar *fv; + u_int16_t size; + + /* XXX add a better check for this */ + if (p->http_uri.raw_size[0] == 0) + return 0; + + /* we need a lock */ + mutex_lock(&p->flow->m); + + fv = FlowVarGet(p->flow, "http_host"); + if (fv != NULL) { + size = fv->value_len; + if (size >= sizeof(hostname)) + size = sizeof(hostname) - 1; + + strncpy(hostname,(char *)fv->value,size); + } + fv = FlowVarGet(p->flow, "http_ua"); + if (fv != NULL) { + size = fv->value_len; + if (size >= sizeof(ua)) + size = sizeof(ua) - 1; + + strncpy(ua,(char *)fv->value,size); + } + mutex_unlock(&p->flow->m); + + CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); + + char srcip[16], dstip[16]; + inet_ntop(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip)); + inet_ntop(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip)); + + for (i = 0; i <= p->http_uri.cnt; i++) { + fprintf(aft->fp, "%s %s [**] %s [**] %s [**] %s:%u -> %s:%u\n", + timebuf, hostname, p->http_uri.raw[i], ua, srcip, p->sp, dstip, p->dp); + fflush(aft->fp); + } + return 0; +} + +int LogHttplogIPv6(ThreadVars *tv, Packet *p, void *data) +{ + LogHttplogThread *aft = (LogHttplogThread *)data; + int i; + char timebuf[64], hostname[256] = "unknown", ua[256] = "unknown"; + FlowVar *fv; + u_int16_t size; + + /* XXX add a better check for this */ + if (p->http_uri.raw_size[0] == 0) + return 0; + + /* we need a lock */ + mutex_lock(&p->flow->m); + + fv = FlowVarGet(p->flow, "http_host"); + if (fv != NULL) { + size = fv->value_len; + if (size >= sizeof(hostname)) + size = sizeof(hostname) - 1; + + strncpy(hostname,(char *)fv->value,size); + } + fv = FlowVarGet(p->flow, "http_ua"); + if (fv != NULL) { + size = fv->value_len; + if (size >= sizeof(ua)) + size = sizeof(ua) - 1; + + strncpy(ua,(char *)fv->value,size); + } + mutex_unlock(&p->flow->m); + + CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); + + char srcip[46], dstip[46]; + inet_ntop(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip)); + inet_ntop(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip)); + + for (i = 0; i <= p->http_uri.cnt; i++) { + fprintf(aft->fp, "%s %s [**] %s [**] %s [**] %s:%u -> %s:%u\n", + timebuf, hostname, p->http_uri.raw[i], ua, srcip, p->sp, dstip, p->dp); + fflush(aft->fp); + } + return 0; +} + +int LogHttplog (ThreadVars *tv, Packet *p, void *data) +{ + if (PKT_IS_IPV4(p)) { + return LogHttplogIPv4(tv, p, data); + } else if (PKT_IS_IPV6(p)) { + return LogHttplogIPv6(tv, p, data); + } + + return 0; +} + +int LogHttplogThreadInit(ThreadVars *t, void **data) +{ + LogHttplogThread *aft = malloc(sizeof(LogHttplogThread)); + if (aft == NULL) { + return -1; + } + memset(aft, 0, sizeof(LogHttplogThread)); + + /* XXX */ + aft->fp = fopen("/var/log/eips/http.log", "w"); + if (aft->fp == NULL) { + return -1; + } + + *data = (void *)aft; + return 0; +} + +int LogHttplogThreadDeinit(ThreadVars *t, void *data) +{ + LogHttplogThread *aft = (LogHttplogThread *)data; + if (aft == NULL) { + return 0; + } + + if (aft->fp != NULL) + fclose(aft->fp); + + /* clear memory */ + memset(aft, 0, sizeof(LogHttplogThread)); + + free(aft); + return 0; +} + diff --git a/src/log-httplog.h b/src/log-httplog.h new file mode 100644 index 0000000000..a300769864 --- /dev/null +++ b/src/log-httplog.h @@ -0,0 +1,11 @@ +/* Copyright (c) 2008 Victor Julien */ + +#ifndef __LOG_HTTPLOG_H__ +#define __LOG_HTTPLOG_H__ + +void TmModuleLogHttplogRegister (void); +void TmModuleLogHttplogIPv4Register (void); +void TmModuleLogHttplogIPv6Register (void); + +#endif /* __LOG_HTTPLOG_H__ */ + diff --git a/src/tm-modules.h b/src/tm-modules.h index 13681cda8c..c7ba04a6b2 100644 --- a/src/tm-modules.h +++ b/src/tm-modules.h @@ -19,6 +19,9 @@ enum { TMM_ALERTFASTLOG6, TMM_ALERTUNIFIEDLOG, TMM_ALERTUNIFIEDALERT, + TMM_LOGHTTPLOG, + TMM_LOGHTTPLOG4, + TMM_LOGHTTPLOG6, TMM_SIZE, }; diff --git a/src/vips.c b/src/vips.c index f76630dca3..8b6032ed31 100644 --- a/src/vips.c +++ b/src/vips.c @@ -34,6 +34,8 @@ #include "alert-unified-log.h" #include "alert-unified-alert.h" +#include "log-httplog.h" + #ifdef NFQ #include "source-nfq.h" #include "source-nfq-prototypes.h" @@ -298,6 +300,9 @@ int main(int argc, char **argv) TmModuleAlertFastlogIPv6Register(); TmModuleAlertUnifiedLogRegister(); TmModuleAlertUnifiedAlertRegister(); + TmModuleLogHttplogRegister(); + TmModuleLogHttplogIPv4Register(); + TmModuleLogHttplogIPv6Register(); TmModuleDebugList(); /* test and initialize the unittesting subsystem */ @@ -451,7 +456,7 @@ int main(int argc, char **argv) exit(1); } - ThreadVars *tv_alert = TmThreadCreate("AlertFastlog","alert-queue1","simple","alert-queue2","simple","1slot"); + ThreadVars *tv_alert = TmThreadCreate("AlertFastlog&Httplog","alert-queue1","simple","alert-queue2","simple","2slot"); if (tv_alert == NULL) { printf("ERROR: TmThreadsCreate failed\n"); exit(1); @@ -461,7 +466,14 @@ int main(int argc, char **argv) printf("ERROR: TmModuleGetByName failed\n"); exit(1); } - Tm1SlotSetFunc(tv_alert,tm_module); + Tm2SlotSetFunc1(tv_alert,tm_module); + + tm_module = TmModuleGetByName("LogHttplog"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName failed\n"); + exit(1); + } + Tm2SlotSetFunc2(tv_alert,tm_module); if (TmThreadSpawn(tv_alert) != 0) { printf("ERROR: TmThreadSpawn failed\n");