diff --git a/src/Makefile.am b/src/Makefile.am index fa760022f9..6d78210db2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -206,6 +206,7 @@ alert-unified-log.c alert-unified-log.h \ alert-unified-alert.c alert-unified-alert.h \ alert-unified2-alert.c alert-unified2-alert.h \ alert-syslog.c alert-syslog.h \ +log-droplog.c log-droplog.h \ log-httplog.c log-httplog.h \ stream.c stream.h \ stream-tcp.c stream-tcp.h stream-tcp-private.h \ diff --git a/src/alert-fastlog.c b/src/alert-fastlog.c index a84af35f25..7e11f826f1 100644 --- a/src/alert-fastlog.c +++ b/src/alert-fastlog.c @@ -23,10 +23,8 @@ * Logs alerts in a line based text format compatible to Snort's * alert_fast format. * - * \todo Print the protocol as a string * \todo Support classifications * \todo Support more than just IPv4/IPv6 TCP/UDP. - * \todo Print [drop] as well if appropriate */ #include "suricata-common.h" @@ -124,6 +122,8 @@ TmEcode AlertFastLogIPv4(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, AlertFastLogThread *aft = (AlertFastLogThread *)data; int i; char timebuf[64]; + char *action = ""; + extern uint8_t engine_mode; if (p->alerts.cnt == 0) return TM_ECODE_OK; @@ -142,17 +142,23 @@ TmEcode AlertFastLogIPv4(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, 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)); + if (pa->action == ACTION_DROP && IS_ENGINE_MODE_IPS(engine_mode)) { + action = "[Drop] "; + } else if (pa->action == ACTION_DROP) { + action = "[wDrop] "; + } + if (SCProtoNameValid(IPV4_GET_IPPROTO(p)) == TRUE) { - fprintf(aft->file_ctx->fp, "%s [**] [%" PRIu32 ":%" PRIu32 ":%" + fprintf(aft->file_ctx->fp, "%s %s[**] [%" PRIu32 ":%" PRIu32 ":%" PRIu32 "] %s [**] [Classification: %s] [Priority: %"PRIu32"]" - " {%s} %s:%" PRIu32 " -> %s:%" PRIu32 "", timebuf, + " {%s} %s:%" PRIu32 " -> %s:%" PRIu32 "", timebuf, action, pa->gid, pa->sid, pa->rev, pa->msg, pa->class_msg, pa->prio, known_proto[IPV4_GET_IPPROTO(p)], srcip, p->sp, dstip, p->dp); } else { - fprintf(aft->file_ctx->fp, "%s [**] [%" PRIu32 ":%" PRIu32 ":%" + fprintf(aft->file_ctx->fp, "%s %s[**] [%" PRIu32 ":%" PRIu32 ":%" PRIu32 "] %s [**] [Classification: %s] [Priority: %"PRIu32"]" " {PROTO:%03" PRIu32 "} %s:%" PRIu32 " -> %s:%" PRIu32 "", timebuf, - pa->gid, pa->sid, pa->rev, pa->msg, pa->class_msg, pa->prio, + action, pa->gid, pa->sid, pa->rev, pa->msg, pa->class_msg, pa->prio, IPV4_GET_IPPROTO(p), srcip, p->sp, dstip, p->dp); } @@ -170,6 +176,8 @@ TmEcode AlertFastLogIPv6(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, AlertFastLogThread *aft = (AlertFastLogThread *)data; int i; char timebuf[64]; + char *action = ""; + extern uint8_t engine_mode; if (p->alerts.cnt == 0) return TM_ECODE_OK; @@ -187,6 +195,12 @@ TmEcode AlertFastLogIPv6(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, 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)); + if (pa->action == ACTION_DROP && IS_ENGINE_MODE_IPS(engine_mode)) { + action = "[Drop] "; + } else if (pa->action == ACTION_DROP) { + action = "[wDrop] "; + } + if (SCProtoNameValid(IPV6_GET_L4PROTO(p)) == TRUE) { fprintf(aft->file_ctx->fp, "%s [**] [%" PRIu32 ":%" PRIu32 ":%" "" PRIu32 "] %s [**] [Classification: %s] [Priority: %" @@ -217,6 +231,8 @@ TmEcode AlertFastLogDecoderEvent(ThreadVars *tv, Packet *p, void *data, PacketQu AlertFastLogThread *aft = (AlertFastLogThread *)data; int i; char timebuf[64]; + char *action = ""; + extern uint8_t engine_mode; if (p->alerts.cnt == 0) return TM_ECODE_OK; @@ -230,6 +246,12 @@ TmEcode AlertFastLogDecoderEvent(ThreadVars *tv, Packet *p, void *data, PacketQu for (i = 0; i < p->alerts.cnt; i++) { PacketAlert *pa = &p->alerts.alerts[i]; + if (pa->action == ACTION_DROP && IS_ENGINE_MODE_IPS(engine_mode)) { + action = "[Drop] "; + } else if (pa->action == ACTION_DROP) { + action = "[wDrop] "; + } + fprintf(aft->file_ctx->fp, "%s [**] [%" PRIu32 ":%" PRIu32 ":%" PRIu32 "] %s [**] [Classification: %s] [Priority: %" PRIu32 "] [**] [Raw pkt: ", timebuf, pa->gid, pa->sid, pa->rev, pa->msg, pa->class_msg, pa->prio); diff --git a/src/decode-ipv4.h b/src/decode-ipv4.h index 869b518ded..817d7d9f94 100644 --- a/src/decode-ipv4.h +++ b/src/decode-ipv4.h @@ -120,7 +120,7 @@ typedef struct IPV4Hdr_ ((p)->ip4c.flags & IPV4_CACHE_HLEN ? \ (p)->ip4c.hl : ((p)->ip4c.flags |= IPV4_CACHE_HLEN, (p)->ip4c.hl = IPV4_GET_RAW_HLEN((p)->ip4h) << 2)) #define IPV4_GET_IPTOS(p) \ - IPV4_GET_RAW_IPTOS(p) + IPV4_GET_RAW_IPTOS((p)->ip4h) #define IPV4_GET_IPLEN(p) \ ((p)->ip4c.flags & IPV4_CACHE_IPLEN ? \ (p)->ip4c.ip_len : ((p)->ip4c.flags |= IPV4_CACHE_IPLEN, (p)->ip4c.ip_len = ntohs(IPV4_GET_RAW_IPLEN((p)->ip4h)))) diff --git a/src/decode-tcp.h b/src/decode-tcp.h index f89616a65c..c0b370d1b0 100644 --- a/src/decode-tcp.h +++ b/src/decode-tcp.h @@ -75,6 +75,7 @@ #define TCP_GET_RAW_ACK(tcph) ntohl((tcph)->th_ack) #define TCP_GET_RAW_WINDOW(tcph) ntohs((tcph)->th_win) +#define TCP_GET_RAW_URG_POINTER(tcph) ntohs((tcph)->th_urp) /** macro for getting the first timestamp from the packet. Timestamp is in host * order and either returned from the cache or from the packet directly. */ @@ -95,6 +96,7 @@ #define TCP_GET_SEQ(p) TCP_GET_RAW_SEQ(p->tcph) #define TCP_GET_ACK(p) TCP_GET_RAW_ACK(p->tcph) #define TCP_GET_WINDOW(p) TCP_GET_RAW_WINDOW(p->tcph) +#define TCP_GET_URG_POINTER(p) TCP_GET_RAW_URG_POINTER(p->tcph) #define TCP_ISSET_FLAG_FIN(p) ((p)->tcph->th_flags & TH_FIN) #define TCP_ISSET_FLAG_SYN(p) ((p)->tcph->th_flags & TH_SYN) diff --git a/src/flow.h b/src/flow.h index 641ff41541..c9f58f9e16 100644 --- a/src/flow.h +++ b/src/flow.h @@ -69,6 +69,11 @@ /** Sgh for toclient direction set (even if it's NULL) */ #define FLOW_SGH_TOCLIENT 0x1000 +/** packet to server direction has been logged in drop file (only in IPS mode) */ +#define FLOW_TOSERVER_DROP_LOGGED 0x2000 +/** packet to client direction has been logged in drop file (only in IPS mode) */ +#define FLOW_TOCLIENT_DROP_LOGGED 0x4000 + /* pkt flow flags */ #define FLOW_PKT_TOSERVER 0x01 #define FLOW_PKT_TOCLIENT 0x02 diff --git a/src/log-droplog.c b/src/log-droplog.c new file mode 100644 index 0000000000..c74c236b26 --- /dev/null +++ b/src/log-droplog.c @@ -0,0 +1,538 @@ +/* Copyright (C) 2007-2011 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Gurvinder Singh + * + * Drop log module to log the dropped packet information + * + */ + +#include "suricata-common.h" +#include "debug.h" +#include "detect.h" +#include "flow.h" +#include "conf.h" + +#include "threads.h" +#include "tm-threads.h" +#include "threadvars.h" +#include "tm-modules.h" +#include "util-debug.h" + +#include "decode-ipv4.h" +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-reference.h" + +#include "output.h" +#include "log-droplog.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-classification-config.h" +#include "util-mpm-b2g-cuda.h" +#include "util-cuda-handlers.h" +#include "util-privs.h" +#include "util-print.h" +#include "util-proto-name.h" + +#define DEFAULT_LOG_FILENAME "drop.log" + +#define MODULE_NAME "LogDropLog" + +TmEcode LogDropLog (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); +TmEcode LogDropLogNetFilter(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); +TmEcode LogDropLogIPv6(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); +TmEcode LogDropLogDecoderEvent(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); +TmEcode LogDropLogThreadInit(ThreadVars *, void *, void **); +TmEcode LogDropLogThreadDeinit(ThreadVars *, void *); +OutputCtx *LogDropLogInitCtx(ConfNode *); +static void LogDropLogDeInitCtx(OutputCtx *); +static int LogDropLogOpenFileCtx(LogFileCtx *, const char *, const char *); +void LogDropLogRegisterTests(void); +void LogDropLogExitPrintStats(ThreadVars *, void *); + +/** \brief function to register the drop log module */ +void TmModuleLogDropLogRegister (void) { + + tmm_modules[TMM_LOGDROPLOG].name = MODULE_NAME; + tmm_modules[TMM_LOGDROPLOG].ThreadInit = LogDropLogThreadInit; + tmm_modules[TMM_LOGDROPLOG].Func = LogDropLog; + tmm_modules[TMM_LOGDROPLOG].ThreadExitPrintStats = LogDropLogExitPrintStats; + tmm_modules[TMM_LOGDROPLOG].ThreadDeinit = LogDropLogThreadDeinit; + tmm_modules[TMM_LOGDROPLOG].RegisterTests = LogDropLogRegisterTests; + tmm_modules[TMM_LOGDROPLOG].cap_flags = 0; + + OutputRegisterModule(MODULE_NAME, "drop", LogDropLogInitCtx); +} + +typedef struct LogDropLogThread_ { + /** LogFileCtx has the pointer to the file and a mutex to allow multithreading */ + LogFileCtx* file_ctx; + uint64_t drop_cnt; +} LogDropLogThread; + +/** + * \brief Initialize the droplog thread + * \param t Pointer the current thread variable + * \param initdata pointer to the output context + * \param data Pointer to the pointer to droplog thread to be initialized + * + * \return TM_ECODE_OK on success + */ +TmEcode LogDropLogThreadInit(ThreadVars *t, void *initdata, void **data) +{ + LogDropLogThread *dlt = SCMalloc(sizeof(LogDropLogThread)); + if (dlt == NULL) + return TM_ECODE_FAILED; + memset(dlt, 0, sizeof(LogDropLogThread)); + if(initdata == NULL) + { + SCLogDebug("Error getting context for LogDropLog. \"initdata\" argument NULL"); + SCFree(dlt); + return TM_ECODE_FAILED; + } + /** Use the Ouptut Context (file pointer and mutex) */ + dlt->file_ctx = ((OutputCtx *)initdata)->data; + + *data = (void *)dlt; + return TM_ECODE_OK; +} + +/** + * \brief Deinitialize the droplog thread + * \param t Pointer the current thread variable + * \param data Pointer to the droplog thread to be cleared + * + * \return TM_ECODE_OK on success + */ +TmEcode LogDropLogThreadDeinit(ThreadVars *t, void *data) +{ + LogDropLogThread *dlt = (LogDropLogThread *)data; + if (dlt == NULL) { + return TM_ECODE_OK; + } + + /* clear memory */ + memset(dlt, 0, sizeof(LogDropLogThread)); + + SCFree(dlt); + return TM_ECODE_OK; +} + + +/** + * \brief Create a new LogFileCtx for "drop" output style. + * \param conf The configuration node for this output. + * \return A LogFileCtx pointer on success, NULL on failure. + */ +OutputCtx *LogDropLogInitCtx(ConfNode *conf) +{ + const char *enable = ConfNodeLookupChildValue(conf, "enabled"); + if (enable == NULL || strncmp (enable, "no", 2) == 0) { + return NULL; + } + + LogFileCtx *logfile_ctx = LogFileNewCtx(); + if (logfile_ctx == NULL) { + SCLogDebug("LogDropLogInitCtx: Could not create new LogFileCtx"); + return NULL; + } + + const char *filename = ConfNodeLookupChildValue(conf, "filename"); + if (filename == NULL) + filename = DEFAULT_LOG_FILENAME; + + const char *mode = ConfNodeLookupChildValue(conf, "append"); + if (mode == NULL) + mode = DEFAULT_LOG_MODE_APPEND; + + if (LogDropLogOpenFileCtx(logfile_ctx, filename, mode) < 0) { + LogFileFreeCtx(logfile_ctx); + return NULL; + } + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (output_ctx == NULL) + return NULL; + output_ctx->data = logfile_ctx; + output_ctx->DeInit = LogDropLogDeInitCtx; + + SCLogInfo("Drop log output initialized, filename: %s", filename); + + return output_ctx; +} + +/** + * \brief Destroy the LogFileCtx and cleared "drop" output module + * + * \param output_ctx pointer the output context to be cleared + */ +static void LogDropLogDeInitCtx(OutputCtx *output_ctx) +{ + LogFileCtx *logfile_ctx = (LogFileCtx *)output_ctx->data; + LogFileFreeCtx(logfile_ctx); + free(output_ctx); +} + +/** \brief Read the config set the file pointer, open the file + * \param file_ctx pointer to a created LogFileCtx using LogFileNewCtx() + * \param filename name of log file + * \return -1 if failure, 0 if succesful + * */ +static int LogDropLogOpenFileCtx(LogFileCtx *file_ctx, const char *filename, + const char *mode) +{ + char log_path[PATH_MAX]; + char *log_dir; + + if (ConfGet("default-log-dir", &log_dir) != 1) + log_dir = DEFAULT_LOG_DIR; + + snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename); + + if (strcasecmp(mode, "yes") == 0) { + file_ctx->fp = fopen(log_path, "a"); + } else { + file_ctx->fp = fopen(log_path, "w"); + } + + if (file_ctx->fp == NULL) { + SCLogError(SC_ERR_FOPEN, "failed to open %s: %s", log_path, + strerror(errno)); + return -1; + } + + return 0; +} + +/** \brief Function to create the time string from the packet timestamp */ +static void CreateTimeString (const struct timeval *ts, char *str, size_t size) { + time_t time = ts->tv_sec; + struct tm local_tm; + struct tm *t = (struct tm *)localtime_r(&time, &local_tm); + + snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u", + t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, + t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec); +} + +/** + * \brief Log the dropped packets in netfilter format when engine is running + * in inline mode + * + * \param tv Pointer the current thread variables + * \param p Pointer the packet which is being logged + * \param data Pointer to the droplog struct + * \param pq Pointer the packet queue + * \param postpq Pointer the packet queue where this packet will be sent + * + * \return return TM_EODE_OK on success + */ +TmEcode LogDropLogNetFilter (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, + PacketQueue *postpq) +{ + LogDropLogThread *dlt = (LogDropLogThread *)data; + uint16_t proto = 0; + char timebuf[64]; + + if (! (p->action & ACTION_DROP)) + return TM_ECODE_OK; + + CreateTimeString(&p->ts, timebuf, sizeof(timebuf)); + + SCMutexLock(&dlt->file_ctx->fp_mutex); + + char srcip[46] = ""; + char dstip[46] = ""; + + if (PKT_IS_IPV4(p)) { + inet_ntop(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, 16); + inet_ntop(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, 16); + fprintf(dlt->file_ctx->fp, "%s: IN= OUT= SRC=%s DST=%s LEN=%"PRIu16" " + "TOS=0x%02"PRIu8" TTL=%"PRIu8" ID=%"PRIu16"", timebuf, + srcip, dstip, IPV4_GET_IPLEN(p), IPV4_GET_IPTOS(p), + IPV4_GET_IPTTL(p), IPV4_GET_IPID(p)); + proto = IPV4_GET_IPPROTO(p); + } else if (PKT_IS_IPV6(p)) { + 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)); + fprintf(dlt->file_ctx->fp, "%s: IN= OUT= SRC=%s DST=%s LEN=%"PRIu16"" + " TC=%"PRIu32" HOPLIMIT=%"PRIu8" FLOWLBL=%"PRIu32"", timebuf, + srcip, dstip, IPV6_GET_PLEN(p), IPV6_GET_CLASS(p), + IPV6_GET_HLIM(p), IPV6_GET_FLOW(p)); + proto = IPV6_GET_L4PROTO(p); + } + + if (SCProtoNameValid(proto) == TRUE) { + fprintf(dlt->file_ctx->fp, " PROTO=%s",known_proto[proto]); + } else { + fprintf(dlt->file_ctx->fp, " PROTO=%03"PRIu16"",proto); + } + + switch (proto) { + case IPPROTO_TCP: + fprintf(dlt->file_ctx->fp, " SPT=%"PRIu16" DPT=%"PRIu16" " + "SEQ=%"PRIu32" ACK=%"PRIu32" WINDOW=%"PRIu32"", + GET_TCP_SRC_PORT(p), GET_TCP_DST_PORT(p), TCP_GET_SEQ(p), + TCP_GET_ACK(p), TCP_GET_WINDOW(p)); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_SYN(p) ? " SYN" : ""); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_ACK(p) ? " ACK" : ""); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_PUSH(p) ? " PSH" : ""); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_RST(p) ? " RST" : ""); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_URG(p) ? " URG" : ""); + fprintf(dlt->file_ctx->fp, TCP_ISSET_FLAG_FIN(p) ? " FIN" : ""); + fprintf(dlt->file_ctx->fp, " RES=0x%02"PRIu8" URGP=%"PRIu16"", + TCP_GET_RAW_X2(p->tcph), TCP_GET_URG_POINTER(p)); + break; + case IPPROTO_UDP: + fprintf(dlt->file_ctx->fp, " SPT=%"PRIu16" DPT=%"PRIu16"" + " LEN=%"PRIu16"", UDP_GET_SRC_PORT(p), + UDP_GET_DST_PORT(p), UDP_GET_LEN(p)); + break; + case IPPROTO_ICMP: + if (PKT_IS_ICMPV4(p)) { + fprintf(dlt->file_ctx->fp, " TYPE=%"PRIu16" CODE=%"PRIu16"" + " ID=%"PRIu16" SEQ=%"PRIu16"", ICMPV4_GET_TYPE(p), + ICMPV4_GET_CODE(p), ICMPV4_GET_ID(p), ICMPV4_GET_SEQ(p)); + } else if(PKT_IS_ICMPV6(p)) { + fprintf(dlt->file_ctx->fp, " TYPE=%"PRIu16" CODE=%"PRIu16"" + " ID=%"PRIu16" SEQ=%"PRIu16"", ICMPV6_GET_TYPE(p), + ICMPV6_GET_CODE(p), ICMPV6_GET_ID(p), ICMPV6_GET_SEQ(p)); + } + break; + default: + fprintf(dlt->file_ctx->fp," Unknown protocol"); + } + + fprintf(dlt->file_ctx->fp,"\n"); + + fflush(dlt->file_ctx->fp); + + dlt->drop_cnt++; + SCMutexUnlock(&dlt->file_ctx->fp_mutex); + + return TM_ECODE_OK; + +} + +/** + * \brief Log the dropped packets when engine is running in inline mode + * + * \param tv Pointer the current thread variables + * \param p Pointer the packet which is being logged + * \param data Pointer to the droplog struct + * \param pq Pointer the packet queue + * \param postpq Pointer the packet queue where this packet will be sent + * + * \return return TM_EODE_OK on success + */ +TmEcode LogDropLog (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, + PacketQueue *postpq) +{ + /* Check if we are in inline mode or not, if not then no need to log */ + extern uint8_t engine_mode; + if (! IS_ENGINE_MODE_IPS(engine_mode)) { + printf("engine is not running in inlin mode, so returning\n"); + return TM_ECODE_OK; + } + + if ( (p->flow != NULL) && (p->flow->flags & FLOW_ACTION_DROP) ) { + if (PKT_IS_TOSERVER(p) && ! (p->flow->flags & FLOW_TOSERVER_DROP_LOGGED)) + { + p->flow->flags |= FLOW_TOSERVER_DROP_LOGGED; + return LogDropLogNetFilter(tv, p, data, pq, postpq); + } else if (! (p->flow->flags & FLOW_TOCLIENT_DROP_LOGGED)) { + p->flow->flags |= FLOW_TOCLIENT_DROP_LOGGED; + return LogDropLogNetFilter(tv, p, data, pq, postpq); + } + } else { + return LogDropLogNetFilter(tv, p, data, pq, postpq); + } + + return TM_ECODE_OK; + +} + +void LogDropLogExitPrintStats(ThreadVars *tv, void *data) { + LogDropLogThread *dlt = (LogDropLogThread *)data; + if (dlt == NULL) { + return; + } + + SCLogInfo("(%s) Dropped Packets %" PRIu64 "", tv->name, dlt->drop_cnt); +} + +/***************************** Unittests ****************************/ + +#ifdef UNITTESTS + +/** \brief test if the action is drop then packet should be logged */ +int LogDropLogTest01() +{ + int result = 0; + extern uint8_t engine_mode; + SET_ENGINE_MODE_IPS(engine_mode); + + uint8_t *buf = (uint8_t *) "GET /one/ HTTP/1.1\r\n" + "Host: one.example.org\r\n"; + + uint16_t buflen = strlen((char *)buf); + Packet *p = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx; + LogDropLogThread dlt; + LogFileCtx *logfile_ctx = LogFileNewCtx(); + if (logfile_ctx == NULL) { + printf("Could not create new LogFileCtx\n"); + return 0; + } + + memset (&dlt, 0, sizeof(LogDropLogThread)); + dlt.file_ctx = logfile_ctx; + dlt.file_ctx->fp = stdout; + + memset(&th_v, 0, sizeof(th_v)); + p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + return result; + } + + de_ctx->flags |= DE_QUIET; + + SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx); + SCClassConfDeleteDummyClassificationConfigFD(); + + de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any any " + "(msg:\"LogDropLog test\"; content:GET; Classtype:unknown; sid:1;)"); + + result = (de_ctx->sig_list != NULL); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt == 1 && (p->action & ACTION_DROP)) + result = (strcmp(p->alerts.alerts[0].class_msg, "Unknown are we") == 0); + else + result = 0; + + LogDropLog(NULL, p, &dlt, NULL, NULL); + + if (dlt.drop_cnt == 0) { + printf("Packet should be logged but its not\n"); + result = 0; + } + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + UTHFreePackets(&p, 1); + return result; +} + +/** \brief test if the action is alert then packet shouldn't be logged */ +int LogDropLogTest02() +{ + int result = 0; + extern uint8_t engine_mode; + SET_ENGINE_MODE_IPS(engine_mode); + + uint8_t *buf = (uint8_t *) "GET"; + + uint16_t buflen = strlen((char *)buf); + Packet *p = NULL; + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx; + LogDropLogThread dlt; + LogFileCtx *logfile_ctx = LogFileNewCtx(); + if (logfile_ctx == NULL) { + printf("Could not create new LogFileCtx\n"); + return 0; + } + + memset (&dlt, 0, sizeof(LogDropLogThread)); + dlt.file_ctx = logfile_ctx; + dlt.file_ctx->fp = stdout; + + memset(&th_v, 0, sizeof(th_v)); + p = UTHBuildPacket(buf, buflen, IPPROTO_UDP); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL) { + return result; + } + + de_ctx->flags |= DE_QUIET; + + SCClassConfGenerateValidDummyClassConfigFD01(); + SCClassConfLoadClassficationConfigFile(de_ctx); + SCClassConfDeleteDummyClassificationConfigFD(); + + de_ctx->sig_list = SigInit(de_ctx, "alert udp any any -> any any " + "(msg:\"LogDropLog test\"; content:GET; Classtype:unknown; sid:1;)"); + + result = (de_ctx->sig_list != NULL); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + if (p->alerts.cnt == 1 && p->alerts.alerts[0].action != ACTION_DROP) + result = (strcmp(p->alerts.alerts[0].class_msg, "Unknown are we") == 0); + else + result = 0; + + LogDropLog(NULL, p, &dlt, NULL, NULL); + + if (dlt.drop_cnt != 0) { + printf("Packet shouldn't be logged but it is\n"); + result = 0; + } + + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + UTHFreePackets(&p, 1); + return result; +} +#endif + +/** + * \brief This function registers unit tests for AlertFastLog API. + */ +void LogDropLogRegisterTests(void) +{ + +#ifdef UNITTESTS + UtRegisterTest("LogDropLogTest01", LogDropLogTest01, 1); + UtRegisterTest("LogDropLogTest02", LogDropLogTest02, 1); +#endif /* UNITTESTS */ + +} diff --git a/src/log-droplog.h b/src/log-droplog.h new file mode 100644 index 0000000000..2b266ad55c --- /dev/null +++ b/src/log-droplog.h @@ -0,0 +1,31 @@ +/* Copyright (C) 2007-2011 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Gurvinder Singh + * + */ + + +#ifndef ALERT_DROPLOG_H +#define ALERT_DROPLOG_H + +void TmModuleLogDropLogRegister(void); + +#endif /* ALERT_DROPLOG_H */ diff --git a/src/suricata.c b/src/suricata.c index 6283389f7b..91c4c60e56 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -80,6 +80,7 @@ #include "alert-debuglog.h" #include "alert-prelude.h" #include "alert-syslog.h" +#include "log-droplog.h" #include "log-httplog.h" @@ -925,6 +926,7 @@ int main(int argc, char **argv) TmModuleAlertUnifiedAlertRegister(); TmModuleUnified2AlertRegister(); TmModuleAlertSyslogRegister(); + TmModuleLogDropLogRegister(); TmModuleStreamTcpRegister(); TmModuleLogHttpLogRegister(); TmModuleLogHttpLogIPv4Register(); diff --git a/src/tm-modules.h b/src/tm-modules.h index 1829533d3e..01e5e42ebb 100644 --- a/src/tm-modules.h +++ b/src/tm-modules.h @@ -69,6 +69,7 @@ enum { TMM_ALERTPRELUDE, TMM_ALERTDEBUGLOG, TMM_ALERTSYSLOG, + TMM_LOGDROPLOG, TMM_ALERTSYSLOG4, TMM_ALERTSYSLOG6, TMM_RESPONDREJECT, diff --git a/suricata.yaml b/suricata.yaml index 4a55ceb9f2..b1b14d4122 100644 --- a/suricata.yaml +++ b/suricata.yaml @@ -102,6 +102,12 @@ outputs: facility: local5 #level: Info ## possible levels: Emergency, Alert, Critical, ## Error, Warning, Notice, Info, Debug + # a line based information for dropped packet + - drop: + enabled: yes + filename: drop.log + append: yes + # When running in NFQ inline mode, it is possible to use a simulated # non-terminal NFQUEUE verdict.