Feature options:\
")
+if (ENABLE_STATIC_DAQ)
+ message("\
+ DAQ Modules: Static (${DAQ_STATIC_MODULES})")
+else ()
+ message("\
+ DAQ Modules: Dynamic")
+endif ()
+
if (HAVE_FLATBUFFERS)
message("\
Flatbuffers: ON")
-#
-# Locate DAQ library
-# This module defines
-# DAQ_FOUND, if false, do not try to link to Lua
-#
-# DAQ_FOUND - system has libdaq
-# DAQ_INCLUDE_DIR - the libdaq include directory
-# DAQ_LIBRARIES - the libraries needed to use libdaq
-#
+#[=======================================================================[.rst:
+FindDAQ
+-------
-set (ERROR_MESSAGE
- "
- ERROR! Cannot find LibDAQ. Go get it from
- http://snort.org/snort-downloads or use the --with-daq-*
- options if you have it installed in an unusual place.\n\n"
-)
+Locate LibDAQ include paths and library as well as static DAQ module libraries
-find_path(DAQ_INCLUDE_DIR
- NAMES daq.h
- HINTS ${DAQ_INCLUDE_DIR_HINT}
- NO_SYSTEM_ENVIRONMENT_PATH
-)
+This module defines:
-# find any static libraries
-if (ENABLE_STATIC_DAQ)
- execute_process(
- COMMAND daq-modules-config --static --libs
- OUTPUT_VARIABLE DAQ_STATIC_LIBRARIES
- RESULT_VARIABLE result
- OUTPUT_STRIP_TRAILING_WHITESPACE
- )
+::
- # This will be false if the exit status was 0 and true if the binary was not found
- if (result)
- message(SEND_ERROR
- "
- ERROR! Cannot find LibDAQ's static libraries! Make sure the binary
- file `daq-modules-config` is in your path.\n\n")
- endif()
+ DAQ_FOUND - system has libdaq
+ DAQ_INCLUDE_DIR - the libdaq include directory
+ DAQ_LIBRARIES - the libraries needed to use libdaq
+ DAQ_STATIC_MODULES - the static DAQ modules available
+ DAQ_STATIC_MODULE_LIBS - the set of additional libraries required by the available static DAQ modules
+#]=======================================================================]
- set(DAQ_LIB daq_static)
-else()
- set(DAQ_LIB daq)
- set(DAQ_STATIC_LIBRARIES)
-endif()
+find_package(PkgConfig)
+pkg_check_modules(PC_DAQ libdaq>=3.0.0)
-find_library(DAQ_LIBRARY
- NAMES ${DAQ_LIB}
- HINTS ${DAQ_LIBRARIES_DIR_HINT} # user-specified path in ./configure_cmake.sh
- DOC "DAQ library directory"
+# Use DAQ_INCLUDE_DIR_HINT and DAQ_LIBRARIES_DIR_HINT from configure_cmake.sh as primary hints
+# and then package config information after that.
+find_path(DAQ_INCLUDE_DIR
+ NAMES daq.h
+ HINTS ${DAQ_INCLUDE_DIR_HINT} ${PC_DAQ_INCLUDEDIR} ${PC_DAQ_INCLUDE_DIRS}
+ NO_SYSTEM_ENVIRONMENT_PATH
+)
+find_library(DAQ_LIBRARIES
+ NAMES daq
+ HINTS ${DAQ_LIBRARIES_DIR_HINT} ${PC_DAQ_LIBDIR} ${PC_DAQ_LIBRARY_DIRS}
)
-
-set(DAQ_LIBRARIES ${DAQ_LIBRARY} ${DAQ_STATIC_LIBRARIES})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(DAQ
- REQUIRED_VARS DAQ_LIBRARY DAQ_LIBRARIES DAQ_INCLUDE_DIR
+ REQUIRED_VARS DAQ_LIBRARIES DAQ_INCLUDE_DIR
FAIL_MESSAGE "${ERROR_MESSAGE}"
)
mark_as_advanced(
DAQ_INCLUDE_DIR
- DAQ_LIBRARY
DAQ_LIBRARIES
)
+
+if (PKG_CONFIG_EXECUTABLE AND ENABLE_STATIC_DAQ)
+ execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --list-all
+ OUTPUT_VARIABLE _pkgconfig_list_result
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ string(REGEX MATCHALL "libdaq_static_[^ ]+" AVAILABLE_STATIC_MODULES ${_pkgconfig_list_result})
+ list(REMOVE_DUPLICATES AVAILABLE_STATIC_MODULES)
+ foreach (STATIC_MODULE IN LISTS AVAILABLE_STATIC_MODULES)
+ string(REGEX REPLACE "^libdaq_static_" "" MODULE_NAME ${STATIC_MODULE})
+ list(APPEND DAQ_STATIC_MODULES ${MODULE_NAME})
+ pkg_check_modules(PC_${STATIC_MODULE} ${STATIC_MODULE})
+ foreach (STATIC_MODULE_LIBNAME IN LISTS PC_${STATIC_MODULE}_LIBRARIES)
+ find_library(STATIC_MODULE_LIB
+ NAMES ${STATIC_MODULE_LIBNAME}
+ HINTS ${PC_${STATIC_MODULE}_LIBRARY_DIRS})
+ if (STATIC_MODULE_LIB)
+ list(APPEND DAQ_STATIC_MODULE_LIBS ${STATIC_MODULE_LIB})
+ unset(STATIC_MODULE_LIB CACHE)
+ endif()
+ endforeach()
+ endforeach()
+ if (DAQ_STATIC_MODULE_LIBS)
+ list(REMOVE_DUPLICATES DAQ_STATIC_MODULE_LIBS)
+ endif()
+ if (DAQ_STATIC_MODULES)
+ list(SORT DAQ_STATIC_MODULES)
+ endif()
+endif()
#include <errno.h>
#include <fcntl.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
-#include <daq_api.h>
-#include <sfbpf_dlt.h>
+#include <daq_module_api.h>
#define DAQ_MOD_VERSION 0
#define DAQ_NAME "file"
#define DAQ_TYPE (DAQ_TYPE_FILE_CAPABLE|DAQ_TYPE_INTF_CAPABLE|DAQ_TYPE_MULTI_INSTANCE)
+
+#define FILE_DEFAULT_POOL_SIZE 16
#define FILE_BUF_SZ 16384
-typedef struct {
- char* name;
- int fid;
+#define SET_ERROR(modinst, ...) daq_base_api.set_errbuf(modinst, __VA_ARGS__)
+
+typedef struct _file_msg_desc
+{
+ DAQ_Msg_t msg;
+ DAQ_PktHdr_t pkthdr;
+ DAQ_UsrHdr_t pci;
+ uint8_t* data;
+ struct _file_msg_desc* next;
+} FileMsgDesc;
- int start;
- int stop;
- int eof;
+typedef struct
+{
+ FileMsgDesc* pool;
+ FileMsgDesc* freelist;
+ DAQ_MsgPoolInfo_t info;
+} FileMsgPool;
+typedef struct
+{
+ /* Configuration */
+ char* filename;
unsigned snaplen;
- uint8_t* buf;
- char error[DAQ_ERRBUF_SIZE];
+ /* State */
+ DAQ_ModuleInstance_h modinst;
+ FileMsgPool pool;
+ int fid;
+ volatile bool interrupted;
+
+ bool sof;
+ bool eof;
DAQ_UsrHdr_t pci;
- DAQ_State state;
DAQ_Stats_t stats;
-} FileImpl;
+} FileContext;
+
+static DAQ_BaseAPI_t daq_base_api;
+
+//-------------------------------------------------------------------------
+// utility functions
+//-------------------------------------------------------------------------
+
+static void destroy_message_pool(FileContext* fc)
+{
+ FileMsgPool* pool = &fc->pool;
+ if (pool->pool)
+ {
+ while (pool->info.size > 0)
+ free(pool->pool[--pool->info.size].data);
+ free(pool->pool);
+ pool->pool = NULL;
+ }
+ pool->freelist = NULL;
+ pool->info.available = 0;
+ pool->info.mem_size = 0;
+}
+
+static int create_message_pool(FileContext* fc, unsigned size)
+{
+ FileMsgPool* pool = &fc->pool;
+ pool->pool = calloc(sizeof(FileMsgDesc), size);
+ if (!pool->pool)
+ {
+ SET_ERROR(fc->modinst, "%s: Could not allocate %zu bytes for a packet descriptor pool!",
+ __func__, sizeof(FileMsgDesc) * size);
+ return DAQ_ERROR_NOMEM;
+ }
+ pool->info.mem_size = sizeof(FileMsgDesc) * size;
+ while (pool->info.size < size)
+ {
+ /* Allocate packet data and set up descriptor */
+ FileMsgDesc *desc = &pool->pool[pool->info.size];
+ desc->data = malloc(fc->snaplen);
+ if (!desc->data)
+ {
+ SET_ERROR(fc->modinst, "%s: Could not allocate %d bytes for a packet descriptor message buffer!",
+ __func__, fc->snaplen);
+ return DAQ_ERROR_NOMEM;
+ }
+ pool->info.mem_size += fc->snaplen;
+
+ /* Initialize non-zero invariant packet header fields. */
+ DAQ_PktHdr_t *pkthdr = &desc->pkthdr;
+ pkthdr->address_space_id = 0;
+ pkthdr->ingress_index = DAQ_PKTHDR_UNKNOWN;
+ pkthdr->ingress_group = DAQ_PKTHDR_UNKNOWN;
+ pkthdr->egress_index = DAQ_PKTHDR_UNKNOWN;
+ pkthdr->egress_group = DAQ_PKTHDR_UNKNOWN;
+ pkthdr->flags = 0;
+
+ /* Initialize non-zero invariant message header fields. */
+ DAQ_Msg_t *msg = &desc->msg;
+ msg->owner = fc->modinst;
+ msg->priv = desc;
+
+ /* Place it on the free list */
+ desc->next = pool->freelist;
+ pool->freelist = desc;
+
+ pool->info.size++;
+ }
+ pool->info.available = pool->info.size;
+ return DAQ_SUCCESS;
+}
//-------------------------------------------------------------------------
// file functions
//-------------------------------------------------------------------------
-static int file_setup(FileImpl* impl)
+static int file_setup(FileContext* fc)
{
- if ( !strcmp(impl->name, "tty") )
+ if ( !strcmp(fc->filename, "tty") )
{
- impl->fid = STDIN_FILENO;
+ fc->fid = STDIN_FILENO;
}
- else if ( (impl->fid = open(impl->name, O_RDONLY|O_NONBLOCK)) < 0 )
+ else if ( (fc->fid = open(fc->filename, O_RDONLY|O_NONBLOCK)) < 0 )
{
char error_msg[1024] = {0};
if (strerror_r(errno, error_msg, sizeof(error_msg)) == 0)
- DPE(impl->error, "%s: can't open file (%s)\n", DAQ_NAME, error_msg);
+ SET_ERROR(fc->modinst, "%s: can't open file (%s)", DAQ_NAME, error_msg);
else
- DPE(impl->error, "%s: can't open file: %d\n", DAQ_NAME, errno);
+ SET_ERROR(fc->modinst, "%s: can't open file: %d", DAQ_NAME, errno);
return -1;
}
- impl->start = 1;
+
+ fc->sof = true;
+ fc->eof = false;
return 0;
}
-static void file_cleanup(FileImpl* impl)
+static void file_cleanup(FileContext* fc)
{
- if ( impl->fid > STDIN_FILENO )
- close(impl->fid);
+ if ( fc->fid > STDIN_FILENO )
+ close(fc->fid);
- impl->fid = -1;
-}
-
-static int file_read(FileImpl* impl)
-{
- int n = read(impl->fid, impl->buf, impl->snaplen);
-
- if ( !n )
- {
- if ( !impl->eof )
- {
- impl->eof = 1;
- return 1; // <= zero won't make it :(
- }
- return DAQ_READFILE_EOF;
- }
-
- if ( n < 0 )
- {
- if (errno != EINTR)
- {
- char error_msg[1024] = {0};
- if (strerror_r(errno, error_msg, sizeof(error_msg)) == 0)
- DPE(impl->error, "%s: can't read from file (%s)\n",
- DAQ_NAME, error_msg);
- else
- DPE(impl->error, "%s: can't read from file: %d\n",
- DAQ_NAME, errno);
- }
- return DAQ_ERROR;
- }
- return n;
+ fc->fid = -1;
}
//-------------------------------------------------------------------------
// daq utilities
//-------------------------------------------------------------------------
-static void set_pkt_hdr(FileImpl* impl, DAQ_PktHdr_t* phdr, ssize_t len)
+static void init_packet_message(FileContext* fc, FileMsgDesc* desc)
{
- struct timeval t;
- gettimeofday(&t, NULL);
+ DAQ_PktHdr_t *pkthdr = &desc->pkthdr;
- phdr->ts.tv_sec = t.tv_sec;
- phdr->ts.tv_usec = t.tv_usec;
- phdr->caplen = phdr->pktlen = len;
+ desc->msg.type = DAQ_MSG_TYPE_PACKET;
+ desc->msg.hdr_len = sizeof(*pkthdr);
+ desc->msg.hdr = pkthdr;
+ desc->msg.data_len = 0;
+ desc->msg.data = desc->data;
- phdr->ingress_index = phdr->egress_index = -1;
- phdr->ingress_group = phdr->egress_group = -1;
+ struct timeval t;
+ gettimeofday(&t, NULL);
- phdr->flags = 0;
- phdr->address_space_id = 0;
- phdr->opaque = 0;
+ pkthdr->ts.tv_sec = t.tv_sec;
+ pkthdr->ts.tv_usec = t.tv_usec;
- if ( impl->start )
+ desc->pci = fc->pci;
+ if (fc->sof)
{
- impl->pci.flags = DAQ_USR_FLAG_START_FLOW;
- impl->start = 0;
+ desc->pci.flags |= DAQ_USR_FLAG_START_FLOW;
+ fc->sof = false;
}
- else if ( impl->eof )
- impl->pci.flags = DAQ_USR_FLAG_END_FLOW;
-
- else
- impl->pci.flags = 0;
-
- phdr->priv_ptr = &impl->pci;
}
-static int file_daq_process(
- FileImpl* impl, DAQ_Analysis_Func_t cb, void* user)
+static DAQ_RecvStatus file_read_message(FileContext* fc, FileMsgDesc* desc)
{
- DAQ_PktHdr_t hdr;
- int n = file_read(impl);
+ desc->msg.data = NULL;
+ int n = read(fc->fid, desc->data, fc->snaplen);
- if ( n < 1 )
- return n;
-
- set_pkt_hdr(impl, &hdr, n);
- DAQ_Verdict verdict = cb(user, &hdr, impl->buf);
+ if ( n )
+ {
+ init_packet_message(fc, desc);
+ desc->msg.data_len = n;
+ }
+ else
+ {
+ // create an empty packet message to convey the End of Flow
+ if (!fc->eof)
+ {
+ init_packet_message(fc, desc);
+ desc->pci.flags |= DAQ_USR_FLAG_END_FLOW;
+ fc->eof = true;
+ return DAQ_RSTAT_EOF;
+ }
+ }
- if ( verdict >= MAX_DAQ_VERDICT )
- verdict = DAQ_VERDICT_BLOCK;
+ if ( n < 0 )
+ {
+ if (errno != EINTR)
+ {
+ char error_msg[1024] = {0};
+ if (strerror_r(errno, error_msg, sizeof(error_msg)) == 0)
+ SET_ERROR(fc->modinst, "%s: can't read from file (%s)", DAQ_NAME, error_msg);
+ else
+ SET_ERROR(fc->modinst, "%s: can't read from file: %d", DAQ_NAME, errno);
+ return DAQ_RSTAT_ERROR;
+ }
+ }
- impl->stats.verdicts[verdict]++;
- return n;
+ return DAQ_RSTAT_OK;
}
//-------------------------------------------------------------------------
// daq
//-------------------------------------------------------------------------
-static void file_daq_shutdown (void* handle)
+static int file_daq_module_load(const DAQ_BaseAPI_t* base_api)
{
- FileImpl* impl = (FileImpl*)handle;
-
- if ( impl->name )
- free(impl->name);
+ if (base_api->api_version != DAQ_BASE_API_VERSION || base_api->api_size != sizeof(DAQ_BaseAPI_t))
+ return DAQ_ERROR;
- if ( impl->buf )
- free(impl->buf);
+ daq_base_api = *base_api;
- free(impl);
+ return DAQ_SUCCESS;
}
-//-------------------------------------------------------------------------
-
-static int file_daq_initialize (
- const DAQ_Config_t* cfg, void** handle, char* errBuf, size_t errMax)
+static int file_daq_instantiate(const DAQ_ModuleConfig_h modcfg, DAQ_ModuleInstance_h modinst, void** ctxt_ptr)
{
- FileImpl* impl = calloc(1, sizeof(*impl));
+ FileContext* fc;
+ int rval = DAQ_ERROR;
- if ( !impl )
+ fc = calloc(1, sizeof(*fc));
+ if (!fc)
{
- snprintf(errBuf, errMax, "%s: failed to allocate the ipfw context", DAQ_NAME);
- return DAQ_ERROR_NOMEM;
+ SET_ERROR(modinst, "%s: Couldn't allocate memory for the new File context!", DAQ_NAME);
+ rval = DAQ_ERROR_NOMEM;
+ goto err;
}
+ fc->modinst = modinst;
- impl->fid = -1;
- impl->start = impl->stop = 0;
- impl->snaplen = cfg->snaplen ? cfg->snaplen : FILE_BUF_SZ;
+ fc->snaplen = daq_base_api.config_get_snaplen(modcfg) ? daq_base_api.config_get_snaplen(modcfg) : FILE_BUF_SZ;
+ fc->fid = -1;
- if ( cfg->name )
+ const char* filename = daq_base_api.config_get_input(modcfg);
+ if (filename)
{
- if ( !(impl->name = strdup(cfg->name)) )
+ if (!(fc->filename = strdup(filename)))
{
- snprintf(errBuf, errMax, "%s: failed to allocate the filename", DAQ_NAME);
- free(impl);
- return DAQ_ERROR_NOMEM;
+ SET_ERROR(modinst, "%s: Couldn't allocate memory for the filename!", DAQ_NAME);
+ rval = DAQ_ERROR_NOMEM;
+ goto err;
}
}
- if ( !(impl->buf = malloc(impl->snaplen)) )
- {
- snprintf(errBuf, errMax, "%s: failed to allocate the ipfw buffer", DAQ_NAME);
- file_daq_shutdown(impl);
- return DAQ_ERROR_NOMEM;
- }
+ uint32_t pool_size = daq_base_api.config_get_msg_pool_size(modcfg);
+ rval = create_message_pool(fc, pool_size ? pool_size : FILE_DEFAULT_POOL_SIZE);
+ if (rval != DAQ_SUCCESS)
+ goto err;
- impl->state = DAQ_STATE_INITIALIZED;
+ *ctxt_ptr = fc;
- *handle = impl;
return DAQ_SUCCESS;
+
+err:
+ if (fc)
+ {
+ if (fc->filename)
+ free(fc->filename);
+ destroy_message_pool(fc);
+ free(fc);
+ }
+ return rval;
}
-//-------------------------------------------------------------------------
+static void file_daq_destroy(void* handle)
+{
+ FileContext* fc = (FileContext*) handle;
-static int file_daq_start (void* handle)
+ if (fc->filename)
+ free(fc->filename);
+ destroy_message_pool(fc);
+ free(fc);
+}
+
+static int file_daq_start(void* handle)
{
- FileImpl* impl = (FileImpl*)handle;
+ FileContext* fc = (FileContext*) handle;
- if ( file_setup(impl) )
+ if (file_setup(fc))
return DAQ_ERROR;
- impl->state = DAQ_STATE_STARTED;
return DAQ_SUCCESS;
}
-static int file_daq_stop (void* handle)
+static int file_daq_interrupt(void* handle)
{
- FileImpl* impl = (FileImpl*)handle;
- file_cleanup(impl);
- impl->state = DAQ_STATE_STOPPED;
+ FileContext* fc = (FileContext*) handle;
+ fc->interrupted = true;
return DAQ_SUCCESS;
}
-//-------------------------------------------------------------------------
-
-static int file_daq_inject (
- void* handle, const DAQ_PktHdr_t* hdr, const uint8_t* buf, uint32_t len,
- int rev)
+static int file_daq_stop (void* handle)
{
- (void)handle;
- (void)hdr;
- (void)buf;
- (void)len;
- (void)rev;
- return DAQ_ERROR;
+ FileContext* fc = (FileContext*) handle;
+ file_cleanup(fc);
+ return DAQ_SUCCESS;
}
-//-------------------------------------------------------------------------
-
-static int file_daq_acquire (
- void* handle, int cnt, DAQ_Analysis_Func_t callback, DAQ_Meta_Func_t meta, void* user)
+static int file_daq_ioctl(void* handle, DAQ_IoctlCmd cmd, void* arg, size_t arglen)
{
- (void)meta;
+ (void) handle;
- FileImpl* impl = (FileImpl*)handle;
- int hit = 0, miss = 0;
- impl->stop = 0;
-
- while ( (hit < cnt || cnt <= 0) && !impl->stop )
+ if (cmd == DIOCTL_QUERY_USR_PCI)
{
- int status = file_daq_process(impl, callback, user);
-
- if ( status > 0 )
- {
- hit++;
- miss = 0;
- }
- else if ( status < 0 )
- return status;
-
- else if ( ++miss == 2 )
- break;
+ if (arglen != sizeof(DIOCTL_QueryUsrPCI))
+ return DAQ_ERROR_INVAL;
+ DIOCTL_QueryUsrPCI* qup = (DIOCTL_QueryUsrPCI*) arg;
+ if (!qup->msg)
+ return DAQ_ERROR_INVAL;
+ FileMsgDesc* desc = (FileMsgDesc*) qup->msg->priv;
+ qup->pci = &desc->pci;
+ return DAQ_SUCCESS;
}
- return DAQ_SUCCESS;
-}
-
-//-------------------------------------------------------------------------
-
-static int file_daq_breakloop (void* handle)
-{
- FileImpl* impl = (FileImpl*)handle;
- impl->stop = 1;
- return DAQ_SUCCESS;
-}
-
-static DAQ_State file_daq_check_status (void* handle)
-{
- FileImpl* impl = (FileImpl*)handle;
- return impl->state;
+ return DAQ_ERROR_NOTSUP;
}
-static int file_daq_get_stats (void* handle, DAQ_Stats_t* stats)
+static int file_daq_get_stats(void* handle, DAQ_Stats_t* stats)
{
- FileImpl* impl = (FileImpl*)handle;
- *stats = impl->stats;
+ FileContext* fc = (FileContext*) handle;
+ memcpy(stats, &fc->stats, sizeof(DAQ_Stats_t));
return DAQ_SUCCESS;
}
-static void file_daq_reset_stats (void* handle)
+static void file_daq_reset_stats(void* handle)
{
- FileImpl* impl = (FileImpl*)handle;
- memset(&impl->stats, 0, sizeof(impl->stats));
+ FileContext* fc = (FileContext*) handle;
+ memset(&fc->stats, 0, sizeof(fc->stats));
}
static int file_daq_get_snaplen (void* handle)
{
- FileImpl* impl = (FileImpl*)handle;
- return impl->snaplen;
+ FileContext* fc = (FileContext*) handle;
+ return fc->snaplen;
}
-static uint32_t file_daq_get_capabilities (void* handle)
+static uint32_t file_daq_get_capabilities(void* handle)
{
- (void)handle;
+ (void) handle;
return DAQ_CAPA_BLOCK | DAQ_CAPA_REPLACE | DAQ_CAPA_INJECT | DAQ_CAPA_INJECT_RAW
- | DAQ_CAPA_BREAKLOOP | DAQ_CAPA_UNPRIV_START;
+ | DAQ_CAPA_INTERRUPT | DAQ_CAPA_UNPRIV_START;
}
static int file_daq_get_datalink_type(void *handle)
return DLT_USER;
}
-static const char* file_daq_get_errbuf (void* handle)
+static unsigned file_daq_msg_receive(void* handle, const unsigned max_recv, const DAQ_Msg_t* msgs[], DAQ_RecvStatus* rstat)
{
- FileImpl* impl = (FileImpl*)handle;
- return impl->error;
-}
+ FileContext* fc = (FileContext*) handle;
+ DAQ_RecvStatus status = DAQ_RSTAT_OK;
+ unsigned idx = 0;
-static void file_daq_set_errbuf (void* handle, const char* s)
-{
- FileImpl* impl = (FileImpl*)handle;
- DPE(impl->error, "%s", s ? s : "");
-}
+ while (idx < max_recv)
+ {
+ /* Check to see if the receive has been canceled. If so, reset it and return appropriately. */
+ if (fc->interrupted)
+ {
+ fc->interrupted = false;
+ status = DAQ_RSTAT_INTERRUPTED;
+ break;
+ }
-static int file_daq_get_device_index(void* handle, const char* device)
-{
- (void)handle;
- (void)device;
- return DAQ_ERROR_NOTSUP;
+ /* Make sure that we have a message descriptor available to populate. */
+ FileMsgDesc* desc = fc->pool.freelist;
+ if (!desc)
+ {
+ status = DAQ_RSTAT_NOBUF;
+ break;
+ }
+
+ /* Attempt to read a message into the descriptor. */
+ status = file_read_message(fc, desc);
+ if (status != DAQ_RSTAT_OK)
+ break;
+
+ /* Last, but not least, extract this descriptor from the free list and
+ place the message in the return vector. */
+ fc->pool.freelist = desc->next;
+ desc->next = NULL;
+ fc->pool.info.available--;
+ msgs[idx] = &desc->msg;
+
+ idx++;
+ }
+
+ *rstat = status;
+
+ return idx;
}
-static int file_daq_set_filter (void* handle, const char* filter)
+static int file_daq_msg_finalize(void* handle, const DAQ_Msg_t* msg, DAQ_Verdict verdict)
{
- (void)handle;
- (void)filter;
- return DAQ_ERROR_NOTSUP;
+ FileContext* fc = (FileContext*) handle;
+ FileMsgDesc* desc = (FileMsgDesc *) msg->priv;
+
+ if (verdict >= MAX_DAQ_VERDICT)
+ verdict = DAQ_VERDICT_PASS;
+ fc->stats.verdicts[verdict]++;
+
+ /* Toss the descriptor back on the free list for reuse. */
+ desc->next = fc->pool.freelist;
+ fc->pool.freelist = desc;
+ fc->pool.info.available++;
+
+ return DAQ_SUCCESS;
}
-static int file_query_flow(void* handle, const DAQ_PktHdr_t* hdr, DAQ_QueryFlow_t* query)
+static int file_daq_get_msg_pool_info(void* handle, DAQ_MsgPoolInfo_t* info)
{
- FileImpl* impl = (FileImpl*)handle;
+ FileContext* fc = (FileContext*) handle;
- if ( hdr->priv_ptr != &impl->pci ) // sanity check
- return DAQ_ERROR_INVAL;
+ *info = fc->pool.info;
- if ( query->type == DAQ_USR_QUERY_PCI )
- {
- query->value = &impl->pci;
- query->length = sizeof(impl->pci);
- return DAQ_SUCCESS;
- }
- return DAQ_ERROR_NOTSUP;
+ return DAQ_SUCCESS;
}
//-------------------------------------------------------------------------
#ifdef BUILDING_SO
-DAQ_SO_PUBLIC DAQ_Module_t DAQ_MODULE_DATA =
+DAQ_SO_PUBLIC const DAQ_ModuleAPI_t DAQ_MODULE_DATA =
#else
-DAQ_Module_t file_daq_module_data =
+const DAQ_ModuleAPI_t file_daq_module_data =
#endif
{
- .api_version = DAQ_API_VERSION,
- .module_version = DAQ_MOD_VERSION,
- .name = DAQ_NAME,
- .type = DAQ_TYPE,
- .initialize = file_daq_initialize,
- .set_filter = file_daq_set_filter,
- .start = file_daq_start,
- .acquire = file_daq_acquire,
- .inject = file_daq_inject,
- .breakloop = file_daq_breakloop,
- .stop = file_daq_stop,
- .shutdown = file_daq_shutdown,
- .check_status = file_daq_check_status,
- .get_stats = file_daq_get_stats,
- .reset_stats = file_daq_reset_stats,
- .get_snaplen = file_daq_get_snaplen,
- .get_capabilities = file_daq_get_capabilities,
- .get_datalink_type = file_daq_get_datalink_type,
- .get_errbuf = file_daq_get_errbuf,
- .set_errbuf = file_daq_set_errbuf,
- .get_device_index = file_daq_get_device_index,
- .modify_flow = NULL,
- .hup_prep = NULL,
- .hup_apply = NULL,
- .hup_post = NULL,
- .dp_add_dc = NULL,
- .query_flow = file_query_flow
+ /* .api_version = */ DAQ_MODULE_API_VERSION,
+ /* .api_size = */ sizeof(DAQ_ModuleAPI_t),
+ /* .module_version = */ DAQ_MOD_VERSION,
+ /* .name = */ DAQ_NAME,
+ /* .type = */ DAQ_TYPE,
+ /* .load = */ file_daq_module_load,
+ /* .unload = */ NULL,
+ /* .get_variable_descs = */ NULL,
+ /* .instantiate = */ file_daq_instantiate,
+ /* .destroy = */ file_daq_destroy,
+ /* .set_filter = */ NULL,
+ /* .start = */ file_daq_start,
+ /* .inject = */ NULL,
+ /* .inject_relative = */ NULL,
+ /* .interrupt = */ file_daq_interrupt,
+ /* .stop = */ file_daq_stop,
+ /* .ioctl = */ file_daq_ioctl,
+ /* .get_stats = */ file_daq_get_stats,
+ /* .reset_stats = */ file_daq_reset_stats,
+ /* .get_snaplen = */ file_daq_get_snaplen,
+ /* .get_capabilities = */ file_daq_get_capabilities,
+ /* .get_datalink_type = */ file_daq_get_datalink_type,
+ /* .config_load = */ NULL,
+ /* .config_swap = */ NULL,
+ /* .config_free = */ NULL,
+ /* .msg_receive = */ file_daq_msg_receive,
+ /* .msg_finalize = */ file_daq_msg_finalize,
+ /* .get_msg_pool_info = */ file_daq_get_msg_pool_info,
};
#include <sys/types.h>
#include <unistd.h>
-#include <daq_api.h>
-#include <sfbpf_dlt.h>
+#include <daq_module_api.h>
-#define DAQ_MOD_VERSION 0
+#define DAQ_MOD_VERSION 1
#define DAQ_NAME "hext"
#define DAQ_TYPE (DAQ_TYPE_FILE_CAPABLE|DAQ_TYPE_INTF_CAPABLE|DAQ_TYPE_MULTI_INSTANCE)
+#define HEXT_DEFAULT_POOL_SIZE 16
#define DEF_BUF_SZ 16384
#define MAX_LINE_SZ 128
-typedef struct {
- char* name;
- FILE* fyle;
+#define SET_ERROR(modinst, ...) daq_base_api.set_errbuf(modinst, __VA_ARGS__)
- bool start;
- bool stop;
- bool eof;
- int dlt;
+typedef struct _hext_msg_desc
+{
+ DAQ_Msg_t msg;
+ DAQ_PktHdr_t pkthdr;
+ Flow_Stats_t flowstats;
+ DAQ_UsrHdr_t pci;
+ uint8_t* data;
+ struct _hext_msg_desc* next;
+} HextMsgDesc;
+typedef struct
+{
+ HextMsgDesc* pool;
+ HextMsgDesc* freelist;
+ DAQ_MsgPoolInfo_t info;
+} HextMsgPool;
+
+typedef struct
+{
+ /* Configuration */
+ char* filename;
unsigned snaplen;
- unsigned idx;
+ int dlt;
- uint8_t* buf;
- char line[MAX_LINE_SZ];
- char error[DAQ_ERRBUF_SIZE];
+ /* State */
+ DAQ_ModuleInstance_h modinst;
+ HextMsgPool pool;
+ FILE* fp;
+ volatile bool interrupted;
+
+ bool sof;
+ bool eof;
DAQ_UsrHdr_t pci;
DAQ_UsrHdr_t cfg;
- DAQ_State state;
DAQ_Stats_t stats;
+} HextContext;
+
+static DAQ_VariableDesc_t hext_variable_descriptions[] = {
+ { "dlt", "Data link type to report to the application instead of DLT_USER (integer)", DAQ_VAR_DESC_REQUIRES_ARGUMENT },
+};
- bool meta;
- DAQ_MetaHdr_t hdr;
- Flow_Stats_t flow;
-} HextImpl;
+static DAQ_BaseAPI_t daq_base_api;
//-------------------------------------------------------------------------
// utility functions
//-------------------------------------------------------------------------
-static void set_c2s(HextImpl* impl, int c2s)
+static void destroy_message_pool(HextContext* hc)
{
- if ( c2s )
+ HextMsgPool* pool = &hc->pool;
+ if (pool->pool)
{
- impl->pci = impl->cfg;
+ while (pool->info.size > 0)
+ free(pool->pool[--pool->info.size].data);
+ free(pool->pool);
+ pool->pool = NULL;
+ }
+ pool->freelist = NULL;
+ pool->info.available = 0;
+ pool->info.mem_size = 0;
+}
+
+static int create_message_pool(HextContext* hc, unsigned size)
+{
+ HextMsgPool* pool = &hc->pool;
+ pool->pool = calloc(sizeof(HextMsgDesc), size);
+ if (!pool->pool)
+ {
+ SET_ERROR(hc->modinst, "%s: Could not allocate %zu bytes for a packet descriptor pool!",
+ __func__, sizeof(HextMsgDesc) * size);
+ return DAQ_ERROR_NOMEM;
+ }
+ pool->info.mem_size = sizeof(HextMsgDesc) * size;
+ while (pool->info.size < size)
+ {
+ /* Allocate packet data and set up descriptor */
+ HextMsgDesc *desc = &pool->pool[pool->info.size];
+ desc->data = malloc(hc->snaplen);
+ if (!desc->data)
+ {
+ SET_ERROR(hc->modinst, "%s: Could not allocate %d bytes for a packet descriptor message buffer!",
+ __func__, hc->snaplen);
+ return DAQ_ERROR_NOMEM;
+ }
+ pool->info.mem_size += hc->snaplen;
+
+ /* Initialize non-zero invariant packet header fields. */
+ DAQ_PktHdr_t *pkthdr = &desc->pkthdr;
+ pkthdr->address_space_id = 0;
+ pkthdr->ingress_index = DAQ_PKTHDR_UNKNOWN;
+ pkthdr->ingress_group = DAQ_PKTHDR_UNKNOWN;
+ pkthdr->egress_index = DAQ_PKTHDR_UNKNOWN;
+ pkthdr->egress_group = DAQ_PKTHDR_UNKNOWN;
+ pkthdr->flags = 0;
+
+ /* Initialize non-zero invariant message header fields. */
+ DAQ_Msg_t *msg = &desc->msg;
+ msg->owner = hc->modinst;
+ msg->priv = desc;
+
+ /* Place it on the free list */
+ desc->next = pool->freelist;
+ pool->freelist = desc;
+
+ pool->info.size++;
+ }
+ pool->info.available = pool->info.size;
+ return DAQ_SUCCESS;
+}
+
+static void set_c2s(HextContext* hc, int c2s)
+{
+ if (c2s)
+ {
+ hc->pci = hc->cfg;
}
else
{
- impl->pci.src_addr = impl->cfg.dst_addr;
- impl->pci.dst_addr = impl->cfg.src_addr;
- impl->pci.src_port = impl->cfg.dst_port;
- impl->pci.dst_port = impl->cfg.src_port;
- impl->pci.flags &= ~DAQ_USR_FLAG_TO_SERVER;
+ hc->pci.src_addr = hc->cfg.dst_addr;
+ hc->pci.dst_addr = hc->cfg.src_addr;
+ hc->pci.src_port = hc->cfg.dst_port;
+ hc->pci.dst_port = hc->cfg.src_port;
+ hc->pci.flags &= ~DAQ_USR_FLAG_TO_SERVER;
}
}
char buf[32]; // oversize so pton() errors out if too long
unsigned c = 0;
- while ( isspace(*s) )
+ while (isspace(*s))
s++;
- while ( *s && !isspace(*s) && c < sizeof(buf) )
+ while (*s && !isspace(*s) && c < sizeof(buf))
buf[c++] = *s++;
- if ( c == sizeof(buf) )
+ if (c == sizeof(buf))
--c;
buf[c] = '\0';
*port = atoi(s);
}
-static void parse_pci(HextImpl* impl, const char* s)
+static void parse_pci(HextContext* hc, const char* s)
{
- parse_host(s, &impl->pci.src_addr, &impl->pci.src_port);
+ parse_host(s, &hc->pci.src_addr, &hc->pci.src_port);
s = strstr(s, "->");
- if ( !s )
+ if (!s)
return;
- parse_host(s+2, &impl->pci.dst_addr, &impl->pci.dst_port);
+ parse_host(s+2, &hc->pci.dst_addr, &hc->pci.dst_port);
// hack until client / server is resolved:
- if ( impl->pci.src_port >= impl->pci.dst_port )
- impl->pci.flags |= DAQ_USR_FLAG_TO_SERVER;
+ if (hc->pci.src_port >= hc->pci.dst_port)
+ hc->pci.flags |= DAQ_USR_FLAG_TO_SERVER;
else
- impl->pci.flags &= ~DAQ_USR_FLAG_TO_SERVER;
+ hc->pci.flags &= ~DAQ_USR_FLAG_TO_SERVER;
}
static bool is_ipv4(char const* src)
{
struct in6_addr temp;
- if ( inet_pton(AF_INET, src, &temp) == 1 )
+ if (inet_pton(AF_INET, src, &temp) == 1)
return true;
- else if ( inet_pton(AF_INET6, src, &temp) == 1 )
+ else if (inet_pton(AF_INET6, src, &temp) == 1)
return false;
return false;
static void IpAddr(uint32_t* addr, char const* ip)
{
- if ( is_ipv4(ip) ) {
+ if (is_ipv4(ip))
+ {
addr[0] = 0;
addr[1] = 0;
addr[2] = htonl(0xffff);
inet_pton(AF_INET, ip, &addr[3]);
}
- else {
+ else
inet_pton(AF_INET6, ip, addr);
- }
}
-enum Search {
- I_ZONE,
- E_ZONE,
- I_INT,
- E_INT,
- SRC_HOST,
- SRC_PORT,
- DST_HOST,
- DST_PORT,
- OPAQUE,
- I_PKTS,
- R_PKTS,
- I_DROPPED,
- R_DROPPED,
- I_BYTES,
- R_BYTES,
- IS_QOS,
- SOF_TIME,
- EOF_TIME,
- VLAN_TAG,
- ADDR_SPACE,
- PROTO,
- END
-};
-
-static void set_flowstats(Flow_Stats_t* f, enum Search state, const char* s)
+static bool parse_flowstats(DAQ_MsgType type, const char* line, HextMsgDesc *desc)
{
- switch (state)
- {
- case I_ZONE:
- f->ingressZone = atoi(s);
- break;
-
- case E_ZONE:
- f->egressZone = atoi(s);
- break;
-
- case I_INT:
- f->ingressIntf = atoi(s);
- break;
-
- case E_INT:
- f->egressIntf = atoi(s);
- break;
-
- case SRC_HOST:
- IpAddr((uint32_t*)&f->initiatorIp, s);
- break;
-
- case SRC_PORT:
- f->initiatorPort = htons(atoi(s));
- break;
-
- case DST_HOST:
- IpAddr((uint32_t*)&f->responderIp, s);
- break;
-
- case DST_PORT:
- f->responderPort = htons(atoi(s));
- break;
-
- case OPAQUE:
- f->opaque = atoi(s);
- break;
-
- case I_PKTS:
- f->initiatorPkts = atoi(s);
- break;
-
- case R_PKTS:
- f->responderPkts = atoi(s);
- break;
-
- case I_DROPPED:
- f->initiatorPktsDropped = atoi(s);
- break;
-
- case R_DROPPED:
- f->responderPktsDropped = atoi(s);
- break;
-
- case I_BYTES:
- f->initiatorBytesDropped = atoi(s);
- break;
-
- case R_BYTES:
- f->responderBytesDropped = atoi(s);
- break;
-
- case IS_QOS:
- f->isQoSAppliedOnSrcIntf = atoi(s);
- break;
-
- case SOF_TIME:
- f->sof_timestamp.tv_sec = atoi(s);
- f->sof_timestamp.tv_usec = 0;
- break;
-
- case EOF_TIME:
- f->eof_timestamp.tv_sec = atoi(s);
- f->sof_timestamp.tv_usec = 0;
- break;
-
- case VLAN_TAG:
- f->vlan_tag = atoi(s);
- if (f->vlan_tag == 0)
- f->vlan_tag = 0xfff;
- break;
-
- case ADDR_SPACE:
- f->address_space_id = atoi(s);
- break;
-
- case PROTO:
- f->protocol = atoi(s);
- break;
-
- default:
- break;
- }
-}
-
-static void parse_flowstats(HextImpl* impl, bool sof, const char* line)
-{
- DAQ_MetaHdr_t* h = &impl->hdr;
- Flow_Stats_t* f = &impl->flow;
-
- char token[INET6_ADDRSTRLEN];
- memset(token, 0, sizeof(token));
-
- char* t = token;
- const char* p = line;
-
- if ( sof )
- h->type = DAQ_METAHDR_TYPE_SOF;
- else
- h->type = DAQ_METAHDR_TYPE_EOF;
-
- enum Search search;
- for (search = I_ZONE; search != END; p++)
- {
- if (p[0] == '\0')
- return;
-
- if ((size_t)(t - token) >= sizeof(token) - 1)
- return;
-
- if (isspace(p[0]))
- {
- if (t != token)
- {
- set_flowstats(f, search, token);
- memset(token, 0, sizeof(token));
- t = token;
- search++;
- }
-
- continue;
- }
- else
- {
- *t = *p;
- t++;
- }
- }
+#define FLOWSTATS_FORMAT "%d %d %d %d %s %hu %s %hu %u %lu %lu %lu %lu %lu %lu %hhu %ld %ld %hu %hu %hhu"
+#define FLOWSTATS_ITEMS 21
+ Flow_Stats_t* f = &desc->flowstats;
+ char srcaddr[INET6_ADDRSTRLEN], dstaddr[INET6_ADDRSTRLEN];
+ int rval = sscanf(line, FLOWSTATS_FORMAT, &f->ingressZone, &f->egressZone, &f->ingressIntf,
+ &f->egressIntf, srcaddr, &f->initiatorPort, dstaddr, &f->responderPort, &f->opaque,
+ &f->initiatorPkts, &f->responderPkts, &f->initiatorPktsDropped, &f->responderPktsDropped,
+ &f->initiatorBytesDropped, &f->responderBytesDropped, &f->isQoSAppliedOnSrcIntf,
+ &f->sof_timestamp.tv_sec, &f->eof_timestamp.tv_sec, &f->vlan_tag, &f->address_space_id,
+ &f->protocol);
+ if (rval != FLOWSTATS_ITEMS)
+ return false;
- if (t != token)
- set_flowstats(f, search-1, token);
+ desc->msg.type = type;
+ desc->msg.hdr_len = sizeof(desc->flowstats);
+ desc->msg.hdr = &desc->flowstats;
+ desc->msg.data_len = 0;
+ desc->msg.data = NULL;
- impl->meta = true;
- impl->line[0] = '\0';
-}
+ IpAddr((uint32_t*)&f->initiatorIp, srcaddr);
+ f->initiatorPort = htons(f->initiatorPort);
+ IpAddr((uint32_t*)&f->responderIp, dstaddr);
+ f->responderPort = htons(f->responderPort);
+ f->sof_timestamp.tv_usec = 0;
+ f->eof_timestamp.tv_usec = 0;
+ if (f->vlan_tag == 0)
+ f->vlan_tag = 0xfff;
-static unsigned flush(HextImpl* impl)
-{
- unsigned n = impl->idx;
- impl->idx = 0;
- return n;
+ return true;
}
static uint8_t xlat(char c)
{
- switch ( c )
+ switch (c)
{
case 'r': return '\r';
case 'n': return '\n';
static int unescape(char c, char* u)
{
static int esc = 0;
- if ( !esc && c == '\\' )
+ if (!esc && c == '\\')
{
esc = 1;
return 0;
}
- else if ( esc )
+ else if (esc)
{
esc = 0;
*u = xlat(c);
// $packet -> server
// $client <addr> <port>
// $server <addr> <port>
-static void parse_command(HextImpl* impl, char* s)
+static bool parse_command(HextContext* hc, const char* s, HextMsgDesc *desc)
{
- if ( !strncmp(s, "packet -> client", 16) )
- set_c2s(impl, 0);
+ bool msg = false;
- else if ( !strncmp(s, "packet -> server", 16) )
- set_c2s(impl, 1);
+ if (!strncmp(s, "packet -> client", 16))
+ set_c2s(hc, 0);
- else if ( !strncmp(s, "packet ", 7) )
- parse_pci(impl, s+7);
+ else if (!strncmp(s, "packet -> server", 16))
+ set_c2s(hc, 1);
- else if ( !strncmp(s, "client ", 7) )
- parse_host(s+7, &impl->cfg.src_addr, &impl->cfg.src_port);
+ else if (!strncmp(s, "packet ", 7))
+ parse_pci(hc, s+7);
- else if ( !strncmp(s, "server ", 7) )
- parse_host(s+7, &impl->cfg.dst_addr, &impl->cfg.dst_port);
+ else if (!strncmp(s, "client ", 7))
+ parse_host(s+7, &hc->cfg.src_addr, &hc->cfg.src_port);
- else if ( !strncmp(s, "sof ", 4) )
- parse_flowstats(impl, true, s+4);
+ else if (!strncmp(s, "server ", 7))
+ parse_host(s+7, &hc->cfg.dst_addr, &hc->cfg.dst_port);
- else if ( !strncmp(s, "eof ", 4) )
- parse_flowstats(impl, false, s+4);
+ else if (!strncmp(s, "sof ", 4))
+ msg = parse_flowstats(DAQ_MSG_TYPE_SOF, s+4, desc);
+
+ else if (!strncmp(s, "eof ", 4))
+ msg = parse_flowstats(DAQ_MSG_TYPE_EOF, s+4, desc);
+
+ return msg;
}
// load quoted string data into buffer up to snaplen
-static void parse_string(HextImpl* impl, char* s)
+static void parse_string(HextContext* hc, char* s, HextMsgDesc *desc)
{
char t;
- while ( *s && *s != '"' && impl->idx < impl->snaplen )
+ while (*s && *s != '"' && desc->msg.data_len < hc->snaplen)
{
- if ( unescape(*s++, &t) )
- impl->buf[impl->idx++] = t;
+ if (unescape(*s++, &t))
+ desc->data[desc->msg.data_len++] = t;
}
+ desc->pkthdr.pktlen = desc->msg.data_len;
}
// load hex data into buffer up to snaplen
-static void parse_hex(HextImpl* impl, char* s)
+static void parse_hex(HextContext* hc, char* s, HextMsgDesc *desc)
{
char* t = s;
long x = strtol(t, &s, 16);
- while ( *s && s != t && impl->idx < impl->snaplen )
+ while (*s && s != t && desc->msg.data_len < hc->snaplen)
{
- impl->buf[impl->idx++] = (uint8_t)x;
+ desc->data[desc->msg.data_len++] = (uint8_t) x;
x = strtol(t=s, &s, 16);
}
+ desc->pkthdr.pktlen = desc->msg.data_len;
+}
+
+static void init_packet_message(HextContext* hc, HextMsgDesc* desc)
+{
+ DAQ_PktHdr_t *pkthdr = &desc->pkthdr;
+
+ desc->msg.type = DAQ_MSG_TYPE_PACKET;
+ desc->msg.hdr_len = sizeof(*pkthdr);
+ desc->msg.hdr = pkthdr;
+ desc->msg.data_len = 0;
+ desc->msg.data = desc->data;
+
+ struct timeval t;
+ gettimeofday(&t, NULL);
+
+ pkthdr->ts.tv_sec = t.tv_sec;
+ pkthdr->ts.tv_usec = t.tv_usec;
+
+ desc->pci = hc->pci;
+ if (hc->sof)
+ {
+ desc->pci.flags |= DAQ_USR_FLAG_START_FLOW;
+ hc->sof = false;
+ }
}
-static int parse(HextImpl* impl)
+static bool parse(HextContext* hc, char* line, HextMsgDesc* desc)
{
- char* s = impl->line;
+ char* s = line;
+ bool got_msg = false;
- while ( isspace(*s) )
+ while (isspace(*s))
s++;
- switch ( *s )
+ // Force a flush of the current packet message if we hit a blank line or command
+ switch (*s)
{
case '\0':
- impl->line[0] = '\0';
- return flush(impl);
+ if (desc->msg.data)
+ got_msg = true;
+ break;
case '#':
break;
case '$':
- if ( impl->idx )
- return flush(impl);
+ // Do not reset the line buffer so that we can parse the command the next time through
+ if (desc->msg.data)
+ return true;
- parse_command(impl, s+1);
+ got_msg = parse_command(hc, s+1, desc);
break;
case '"':
- parse_string(impl, s+1);
+ if (!desc->msg.data)
+ init_packet_message(hc, desc);
+ parse_string(hc, s+1, desc);
break;
case 'x':
- parse_hex(impl, s+1);
+ if (!desc->msg.data)
+ init_packet_message(hc, desc);
+ parse_hex(hc, s+1, desc);
break;
}
- impl->line[0] = '\0';
- return 0;
+ line[0] = '\0';
+ return got_msg;
}
-//-------------------------------------------------------------------------
-// file functions
-//-------------------------------------------------------------------------
-
-static int hext_setup(HextImpl* impl)
+static DAQ_RecvStatus hext_read_message(HextContext* hc, HextMsgDesc* desc)
{
- if ( !strcmp(impl->name, "tty") )
- {
- impl->fyle = stdin;
- }
- else if ( !(impl->fyle = fopen(impl->name, "r")) )
- {
- char error_msg[1024] = {0};
- if (strerror_r(errno, error_msg, sizeof(error_msg)) == 0)
- DPE(impl->error, "%s: can't open file (%s)\n",
- DAQ_NAME, error_msg);
- else
- DPE(impl->error, "%s: can't open file: %d\n",
- DAQ_NAME, errno);
- return -1;
- }
- parse_host("192.168.1.2 12345", &impl->cfg.src_addr, &impl->cfg.src_port);
- parse_host("10.1.2.3 80", &impl->cfg.dst_addr, &impl->cfg.dst_port);
-
- impl->cfg.ip_proto = impl->pci.ip_proto = IPPROTO_TCP;
- impl->cfg.flags = impl->pci.flags = DAQ_USR_FLAG_TO_SERVER;
- impl->start = true;
-
- return 0;
-}
-
-static void hext_cleanup(HextImpl* impl)
-{
- if ( impl->fyle != stdin )
- fclose(impl->fyle);
-
- impl->fyle = NULL;
-}
-
-static int hext_read(HextImpl* impl)
-{
- int n = 0;
+ char line[MAX_LINE_SZ];
+ char* s = NULL;
- while ( impl->line[0] || fgets(impl->line, sizeof(impl->line), impl->fyle) )
+ desc->msg.data = NULL;
+ line[0] = '\0';
+ while (line[0] != '\0' || (s = fgets(line, sizeof(line), hc->fp)) != NULL)
{
- if ( (n = parse(impl)) )
+ // FIXIT-L Currently no error checking, just ignores bad lines
+ if (parse(hc, line, desc))
break;
-
- if (impl->meta)
- return 0;
}
- if ( !n )
- n = flush(impl);
-
- if ( !n )
+ if (!s)
{
- if ( (impl->dlt == DLT_USER) && !impl->eof )
+ if (feof(hc->fp))
{
- impl->eof = true;
- return 1; // <= zero won't make it :(
+ // If there is still pending data in a packet message, mark it as End of Flow and flush it
+ // Otherwise, create an empty packet message to convey the End of Flow
+ // FIXIT-M - Make this actually the case, for now Snort can't handle data on packets marked EoF
+ /*
+ if (!hc->eof)
+ {
+ if (!desc->msg.data)
+ init_packet_message(hc, desc);
+ desc->pci.flags |= DAQ_USR_FLAG_END_FLOW;
+ hc->eof = true;
+ return DAQ_RSTAT_OK;
+ }
+ */
+ if (desc->msg.data)
+ return DAQ_RSTAT_OK;
+ if (!hc->eof)
+ {
+ init_packet_message(hc, desc);
+ desc->pci.flags |= DAQ_USR_FLAG_END_FLOW;
+ hc->eof = true;
+ return DAQ_RSTAT_OK;
+ }
+ return DAQ_RSTAT_EOF;
}
- return DAQ_READFILE_EOF;
- }
- if ( n < 0 )
- {
- if (errno != EINTR)
+ if (ferror(hc->fp))
{
char error_msg[1024] = {0};
if (strerror_r(errno, error_msg, sizeof(error_msg)) == 0)
- DPE(impl->error, "%s: can't read from file (%s)\n",
- DAQ_NAME, error_msg);
+ SET_ERROR(hc->modinst, "%s: can't read from file (%s)\n", DAQ_NAME, error_msg);
else
- DPE(impl->error, "%s: can't read from file: %d\n",
- DAQ_NAME, errno);
+ SET_ERROR(hc->modinst, "%s: can't read from file: %d\n", DAQ_NAME, errno);
+ return DAQ_RSTAT_ERROR;
}
- return DAQ_ERROR;
}
- return n;
+
+ return DAQ_RSTAT_OK;
}
//-------------------------------------------------------------------------
-// daq utilities
+// file functions
//-------------------------------------------------------------------------
-static int get_vars (
- HextImpl* impl, const DAQ_Config_t* cfg, char* errBuf, size_t errMax
-) {
- const char* s = NULL;
- DAQ_Dict* entry;
-
- for ( entry = cfg->values; entry; entry = entry->next)
- {
- if ( !strcmp(entry->key, "dlt") )
- s = entry->value;
-
- else
- {
- snprintf(errBuf, errMax, "unknown var (%s)", s);
- return 0;
- }
- }
- if ( s )
- impl->dlt = atoi(s);
-
- return 1;
-}
-
-static void set_pkt_hdr(HextImpl* impl, DAQ_PktHdr_t* phdr, ssize_t len)
+static int hext_setup(HextContext* hc)
{
- struct timeval t;
- gettimeofday(&t, NULL);
-
- phdr->ts.tv_sec = t.tv_sec;
- phdr->ts.tv_usec = t.tv_usec;
- phdr->caplen = phdr->pktlen = len;
-
- phdr->ingress_index = phdr->egress_index = -1;
- phdr->ingress_group = phdr->egress_group = -1;
-
- phdr->flags = 0;
- phdr->address_space_id = 0;
- phdr->opaque = 0;
-
- if ( impl->dlt != DLT_USER )
- {
- phdr->priv_ptr = NULL;
- return;
- }
- impl->pci.flags &= ~(DAQ_USR_FLAG_START_FLOW|DAQ_USR_FLAG_END_FLOW);
-
- if ( impl->start )
+ if (!strcmp(hc->filename, "tty"))
{
- impl->pci.flags |= DAQ_USR_FLAG_START_FLOW;
- impl->start = false;
+ hc->fp = stdin;
}
- else if ( impl->eof )
- impl->pci.flags |= DAQ_USR_FLAG_END_FLOW;
-
- phdr->priv_ptr = &impl->pci;
-}
-
-static int hext_daq_process(
- HextImpl* impl, DAQ_Analysis_Func_t cb, DAQ_Meta_Func_t mb, void* user)
-{
- DAQ_PktHdr_t hdr;
- int n = hext_read(impl);
-
- if (impl->meta && mb)
+ else if (!(hc->fp = fopen(hc->filename, "r")))
{
- mb(user, (const DAQ_MetaHdr_t*)&impl->hdr, (const uint8_t*)&impl->flow);
- impl->meta = false;
- return 0;
+ char error_msg[1024] = {0};
+ if (strerror_r(errno, error_msg, sizeof(error_msg)) == 0)
+ SET_ERROR(hc->modinst, "%s: can't open file (%s)\n", DAQ_NAME, error_msg);
+ else
+ SET_ERROR(hc->modinst, "%s: can't open file: %d\n", DAQ_NAME, errno);
+ return -1;
}
+ parse_host("192.168.1.2 12345", &hc->cfg.src_addr, &hc->cfg.src_port);
+ parse_host("10.1.2.3 80", &hc->cfg.dst_addr, &hc->cfg.dst_port);
- if ( n < 1 )
- return n;
-
- set_pkt_hdr(impl, &hdr, n);
- DAQ_Verdict verdict = cb(user, &hdr, impl->buf);
+ hc->cfg.ip_proto = hc->pci.ip_proto = IPPROTO_TCP;
+ hc->cfg.flags = hc->pci.flags = DAQ_USR_FLAG_TO_SERVER;
+ hc->sof = true;
+ hc->eof = false;
- if ( verdict >= MAX_DAQ_VERDICT )
- verdict = DAQ_VERDICT_BLOCK;
-
- impl->stats.verdicts[verdict]++;
- return n;
+ return 0;
}
+
//-------------------------------------------------------------------------
// daq
//-------------------------------------------------------------------------
-static void hext_daq_shutdown (void* handle)
+static int hext_daq_module_load(const DAQ_BaseAPI_t* base_api)
{
- HextImpl* impl = (HextImpl*)handle;
-
- if ( impl->name )
- free(impl->name);
+ if (base_api->api_version != DAQ_BASE_API_VERSION || base_api->api_size != sizeof(DAQ_BaseAPI_t))
+ return DAQ_ERROR;
- if ( impl->buf )
- free(impl->buf);
+ daq_base_api = *base_api;
- free(impl);
+ return DAQ_SUCCESS;
}
-//-------------------------------------------------------------------------
+static int hext_daq_get_variable_descs(const DAQ_VariableDesc_t** var_desc_table)
+{
+ *var_desc_table = hext_variable_descriptions;
-static int hext_daq_initialize (
- const DAQ_Config_t* cfg, void** handle, char* errBuf, size_t errMax)
+ return sizeof(hext_variable_descriptions) / sizeof(DAQ_VariableDesc_t);
+}
+
+static int hext_daq_instantiate(const DAQ_ModuleConfig_h modcfg, DAQ_ModuleInstance_h modinst, void** ctxt_ptr)
{
- HextImpl* impl = calloc(1, sizeof(*impl));
+ HextContext* hc;
+ int rval = DAQ_ERROR;
- if ( !impl )
+ hc = calloc(1, sizeof(*hc));
+ if (!hc)
{
- snprintf(errBuf, errMax, "%s: failed to allocate the ipfw context", DAQ_NAME);
- return DAQ_ERROR_NOMEM;
+ SET_ERROR(modinst, "%s: Couldn't allocate memory for the new Hext context!", DAQ_NAME);
+ rval = DAQ_ERROR_NOMEM;
+ goto err;
}
+ hc->modinst = modinst;
- impl->snaplen = cfg->snaplen ? cfg->snaplen : DEF_BUF_SZ;
- impl->dlt = DLT_USER;
+ hc->snaplen = daq_base_api.config_get_snaplen(modcfg) ? daq_base_api.config_get_snaplen(modcfg) : DEF_BUF_SZ;
+ hc->dlt = DLT_USER;
- if ( !get_vars(impl, cfg, errBuf, errMax) )
+ const char* varKey, * varValue;
+ daq_base_api.config_first_variable(modcfg, &varKey, &varValue);
+ while (varKey)
{
- free(impl);
- return DAQ_ERROR;
+ /* Retrieve the requested buffer size (default = 0) */
+ if (!strcmp(varKey, "dlt"))
+ hc->dlt = strtol(varValue, NULL, 10);
+ else
+ {
+ SET_ERROR(modinst, "%s: Unknown variable name: '%s'", DAQ_NAME, varKey);
+ rval = DAQ_ERROR_INVAL;
+ goto err;
+ }
+
+ daq_base_api.config_next_variable(modcfg, &varKey, &varValue);
}
- if ( cfg->name )
+ const char* filename = daq_base_api.config_get_input(modcfg);
+ if (filename)
{
- if ( !(impl->name = strdup(cfg->name)) )
+ if (!(hc->filename = strdup(filename)))
{
- snprintf(errBuf, errMax, "%s: failed to allocate the filename", DAQ_NAME);
- free(impl);
- return DAQ_ERROR_NOMEM;
+ SET_ERROR(modinst, "%s: Couldn't allocate memory for the filename!", DAQ_NAME);
+ rval = DAQ_ERROR_NOMEM;
+ goto err;
}
}
- if ( !(impl->buf = malloc(impl->snaplen)) )
- {
- snprintf(errBuf, errMax, "%s: failed to allocate the ipfw buffer", DAQ_NAME);
- hext_daq_shutdown(impl);
- return DAQ_ERROR_NOMEM;
- }
+ uint32_t pool_size = daq_base_api.config_get_msg_pool_size(modcfg);
+ rval = create_message_pool(hc, pool_size ? pool_size : HEXT_DEFAULT_POOL_SIZE);
+ if (rval != DAQ_SUCCESS)
+ goto err;
- impl->state = DAQ_STATE_INITIALIZED;
+ *ctxt_ptr = hc;
- *handle = impl;
return DAQ_SUCCESS;
+
+err:
+ if (hc)
+ {
+ if (hc->filename)
+ free(hc->filename);
+ destroy_message_pool(hc);
+ free(hc);
+ }
+ return rval;
}
-//-------------------------------------------------------------------------
+static void hext_daq_destroy(void* handle)
+{
+ HextContext* hc = (HextContext*) handle;
-static int hext_daq_start (void* handle)
+ if (hc->filename)
+ free(hc->filename);
+ destroy_message_pool(hc);
+ free(hc);
+}
+
+static int hext_daq_start(void* handle)
{
- HextImpl* impl = (HextImpl*)handle;
+ HextContext* hc = (HextContext*) handle;
- if ( hext_setup(impl) )
+ if (hext_setup(hc))
return DAQ_ERROR;
- impl->state = DAQ_STATE_STARTED;
return DAQ_SUCCESS;
}
-static int hext_daq_stop (void* handle)
+static int hext_daq_interrupt(void* handle)
{
- HextImpl* impl = (HextImpl*)handle;
- hext_cleanup(impl);
- impl->state = DAQ_STATE_STOPPED;
+ HextContext* hc = (HextContext*) handle;
+ hc->interrupted = true;
return DAQ_SUCCESS;
}
-//-------------------------------------------------------------------------
-
-static int hext_daq_inject (
- void* handle, const DAQ_PktHdr_t* hdr, const uint8_t* buf, uint32_t len, int rev)
+static int hext_daq_stop(void* handle)
{
- (void)handle;
- (void)hdr;
- (void)buf;
- (void)len;
- (void)rev;
- return DAQ_ERROR;
-}
-
-//-------------------------------------------------------------------------
-
-static int hext_daq_acquire (
- void* handle, int cnt, DAQ_Analysis_Func_t callback, DAQ_Meta_Func_t meta, void* user)
-{
- HextImpl* impl = (HextImpl*)handle;
- int hit = 0, miss = 0;
- impl->stop = false;
+ HextContext* hc = (HextContext*) handle;
- while ( hit < cnt || cnt <= 0 )
- {
- int status = hext_daq_process(impl, callback, meta, user);
+ if (hc->fp != stdin)
+ fclose(hc->fp);
- if ( status > 0 )
- {
- hit++;
- miss = 0;
- }
- else if ( status < 0 )
- return status;
+ hc->fp = NULL;
- else if ( ++miss == 2 || impl->stop )
- break;
- }
return DAQ_SUCCESS;
}
-//-------------------------------------------------------------------------
-
-static int hext_daq_breakloop (void* handle)
+static int hext_daq_ioctl(void* handle, DAQ_IoctlCmd cmd, void* arg, size_t arglen)
{
- HextImpl* impl = (HextImpl*)handle;
- impl->stop = true;
- return DAQ_SUCCESS;
-}
+ (void) handle;
-static DAQ_State hext_daq_check_status (void* handle)
-{
- HextImpl* impl = (HextImpl*)handle;
- return impl->state;
+ if (cmd == DIOCTL_QUERY_USR_PCI)
+ {
+ if (arglen != sizeof(DIOCTL_QueryUsrPCI))
+ return DAQ_ERROR_INVAL;
+ DIOCTL_QueryUsrPCI* qup = (DIOCTL_QueryUsrPCI*) arg;
+ if (!qup->msg)
+ return DAQ_ERROR_INVAL;
+ HextMsgDesc* desc = (HextMsgDesc*) qup->msg->priv;
+ qup->pci = &desc->pci;
+ return DAQ_SUCCESS;
+ }
+ return DAQ_ERROR_NOTSUP;
}
-static int hext_daq_get_stats (void* handle, DAQ_Stats_t* stats)
+static int hext_daq_get_stats(void* handle, DAQ_Stats_t* stats)
{
- HextImpl* impl = (HextImpl*)handle;
- *stats = impl->stats;
+ HextContext* hc = (HextContext*) handle;
+ memcpy(stats, &hc->stats, sizeof(DAQ_Stats_t));
return DAQ_SUCCESS;
}
-static void hext_daq_reset_stats (void* handle)
+static void hext_daq_reset_stats(void* handle)
{
- HextImpl* impl = (HextImpl*)handle;
- memset(&impl->stats, 0, sizeof(impl->stats));
+ HextContext* hc = (HextContext*) handle;
+ memset(&hc->stats, 0, sizeof(hc->stats));
}
static int hext_daq_get_snaplen (void* handle)
{
- HextImpl* impl = (HextImpl*)handle;
- return impl->snaplen;
+ HextContext* hc = (HextContext*) handle;
+ return hc->snaplen;
}
-static uint32_t hext_daq_get_capabilities (void* handle)
+static uint32_t hext_daq_get_capabilities(void* handle)
{
- (void)handle;
+ (void) handle;
return DAQ_CAPA_BLOCK | DAQ_CAPA_REPLACE | DAQ_CAPA_INJECT | DAQ_CAPA_INJECT_RAW
- | DAQ_CAPA_BREAKLOOP | DAQ_CAPA_UNPRIV_START;
+ | DAQ_CAPA_INTERRUPT | DAQ_CAPA_UNPRIV_START;
}
-static int hext_daq_get_datalink_type(void *handle)
+static int hext_daq_get_datalink_type(void* handle)
{
- HextImpl* impl = (HextImpl*)handle;
- return impl->dlt;
+ HextContext* hc = (HextContext*) handle;
+ return hc->dlt;
}
-static const char* hext_daq_get_errbuf (void* handle)
+static unsigned hext_daq_msg_receive(void* handle, const unsigned max_recv, const DAQ_Msg_t* msgs[], DAQ_RecvStatus* rstat)
{
- HextImpl* impl = (HextImpl*)handle;
- return impl->error;
-}
+ HextContext* hc = (HextContext*) handle;
+ DAQ_RecvStatus status = DAQ_RSTAT_OK;
+ unsigned idx = 0;
-static void hext_daq_set_errbuf (void* handle, const char* s)
-{
- HextImpl* impl = (HextImpl*)handle;
- DPE(impl->error, "%s", s ? s : "");
-}
+ while (idx < max_recv)
+ {
+ /* Check to see if the receive has been canceled. If so, reset it and return appropriately. */
+ if (hc->interrupted)
+ {
+ hc->interrupted = false;
+ status = DAQ_RSTAT_INTERRUPTED;
+ break;
+ }
-static int hext_daq_get_device_index(void* handle, const char* device)
-{
- (void)handle;
- (void)device;
- return DAQ_ERROR_NOTSUP;
+ /* Make sure that we have a message descriptor available to populate. */
+ HextMsgDesc* desc = hc->pool.freelist;
+ if (!desc)
+ {
+ status = DAQ_RSTAT_NOBUF;
+ break;
+ }
+
+ /* Attempt to read a message into the descriptor. */
+ status = hext_read_message(hc, desc);
+ if (status != DAQ_RSTAT_OK)
+ break;
+
+ /* Last, but not least, extract this descriptor from the free list and
+ place the message in the return vector. */
+ hc->pool.freelist = desc->next;
+ desc->next = NULL;
+ hc->pool.info.available--;
+ msgs[idx] = &desc->msg;
+
+ idx++;
+ }
+
+ *rstat = status;
+
+ return idx;
}
-static int hext_daq_set_filter (void* handle, const char* filter)
+static int hext_daq_msg_finalize(void* handle, const DAQ_Msg_t* msg, DAQ_Verdict verdict)
{
- (void)handle;
- (void)filter;
- return DAQ_ERROR_NOTSUP;
+ HextContext* hc = (HextContext*) handle;
+ HextMsgDesc* desc = (HextMsgDesc *) msg->priv;
+
+ if (verdict >= MAX_DAQ_VERDICT)
+ verdict = DAQ_VERDICT_PASS;
+ hc->stats.verdicts[verdict]++;
+
+ /* Toss the descriptor back on the free list for reuse. */
+ desc->next = hc->pool.freelist;
+ hc->pool.freelist = desc;
+ hc->pool.info.available++;
+
+ return DAQ_SUCCESS;
}
-static int hext_query_flow(void* handle, const DAQ_PktHdr_t* hdr, DAQ_QueryFlow_t* query)
+static int hext_daq_get_msg_pool_info(void* handle, DAQ_MsgPoolInfo_t* info)
{
- HextImpl* impl = (HextImpl*)handle;
+ HextContext* hc = (HextContext*) handle;
- if ( hdr->priv_ptr != &impl->pci ) // sanity check
- return DAQ_ERROR_INVAL;
+ *info = hc->pool.info;
- if ( query->type == DAQ_USR_QUERY_PCI )
- {
- query->value = &impl->pci;
- query->length = sizeof(impl->pci);
- return DAQ_SUCCESS;
- }
- return DAQ_ERROR_NOTSUP;
+ return DAQ_SUCCESS;
}
//-------------------------------------------------------------------------
#ifdef BUILDING_SO
-DAQ_SO_PUBLIC DAQ_Module_t DAQ_MODULE_DATA =
+DAQ_SO_PUBLIC const DAQ_ModuleAPI_t DAQ_MODULE_DATA =
#else
-DAQ_Module_t hext_daq_module_data =
+const DAQ_ModuleAPI_t hext_daq_module_data =
#endif
{
- .api_version = DAQ_API_VERSION,
- .module_version = DAQ_MOD_VERSION,
- .name = DAQ_NAME,
- .type = DAQ_TYPE,
- .initialize = hext_daq_initialize,
- .set_filter = hext_daq_set_filter,
- .start = hext_daq_start,
- .acquire = hext_daq_acquire,
- .inject = hext_daq_inject,
- .breakloop = hext_daq_breakloop,
- .stop = hext_daq_stop,
- .shutdown = hext_daq_shutdown,
- .check_status = hext_daq_check_status,
- .get_stats = hext_daq_get_stats,
- .reset_stats = hext_daq_reset_stats,
- .get_snaplen = hext_daq_get_snaplen,
- .get_capabilities = hext_daq_get_capabilities,
- .get_datalink_type = hext_daq_get_datalink_type,
- .get_errbuf = hext_daq_get_errbuf,
- .set_errbuf = hext_daq_set_errbuf,
- .get_device_index = hext_daq_get_device_index,
- .modify_flow = NULL,
- .hup_prep = NULL,
- .hup_apply = NULL,
- .hup_post = NULL,
- .dp_add_dc = NULL,
- .query_flow = hext_query_flow
+ /* .api_version = */ DAQ_MODULE_API_VERSION,
+ /* .api_size = */ sizeof(DAQ_ModuleAPI_t),
+ /* .module_version = */ DAQ_MOD_VERSION,
+ /* .name = */ DAQ_NAME,
+ /* .type = */ DAQ_TYPE,
+ /* .load = */ hext_daq_module_load,
+ /* .unload = */ NULL,
+ /* .get_variable_descs = */ hext_daq_get_variable_descs,
+ /* .instantiate = */ hext_daq_instantiate,
+ /* .destroy = */ hext_daq_destroy,
+ /* .set_filter = */ NULL,
+ /* .start = */ hext_daq_start,
+ /* .inject = */ NULL,
+ /* .inject_relative = */ NULL,
+ /* .interrupt = */ hext_daq_interrupt,
+ /* .stop = */ hext_daq_stop,
+ /* .ioctl = */ hext_daq_ioctl,
+ /* .get_stats = */ hext_daq_get_stats,
+ /* .reset_stats = */ hext_daq_reset_stats,
+ /* .get_snaplen = */ hext_daq_get_snaplen,
+ /* .get_capabilities = */ hext_daq_get_capabilities,
+ /* .get_datalink_type = */ hext_daq_get_datalink_type,
+ /* .config_load = */ NULL,
+ /* .config_swap = */ NULL,
+ /* .config_free = */ NULL,
+ /* .msg_receive = */ hext_daq_msg_receive,
+ /* .msg_finalize = */ hext_daq_msg_finalize,
+ /* .get_msg_pool_info = */ hext_daq_get_msg_pool_info,
};
#define DAQ_USER_H
#include <stdint.h>
+#include <daq_common.h>
/* for raw payload only */
#define DLT_USER 230
-/* in: DAQ_QueryFlow_t.type */
-#define DAQ_USR_QUERY_PCI 1000
-
/* DAQ_UsrHdr_t.flags */
#define DAQ_USR_FLAG_TO_SERVER 0x01
#define DAQ_USR_FLAG_START_FLOW 0x02
#define DAQ_USR_FLAG_END_FLOW 0x04
-/* out: DAQ_QueryFlow_t.value */
typedef struct
{
uint32_t src_addr;
uint8_t flags;
} DAQ_UsrHdr_t;
+#define DIOCTL_QUERY_USR_PCI (DAQ_IoctlCmd) 2048
+typedef struct
+{
+ DAQ_Msg_h msg;
+ DAQ_UsrHdr_t* pci;
+} DIOCTL_QueryUsrPCI;
+
#endif
daq =
{
- module = 'dump',
- variables = { "load-mode=read-file", "output=none" }
+ modules =
+ {
+ {
+ name = 'pcap',
+ mode = 'read-file'
+ },
+ {
+ name = 'dump',
+ variables = { 'output = none' }
+ },
+ },
}
normalizer = { tcp = { ips = true } }
daq =
{
- module = 'dump',
- variables = { "load-mode=read-file", "output=none" }
+ modules =
+ {
+ {
+ name = 'pcap',
+ mode = 'read-file'
+ },
+ {
+ name = 'dump',
+ variables = { 'output = none' }
+ },
+ },
}
+
normalizer = { tcp = { ips = true } }
ips.include = 'local.rules'
LIST(APPEND EXTERNAL_INCLUDES ${TIRPC_INCLUDE_DIRS})
endif ()
+if ( ENABLE_STATIC_DAQ )
+ LIST(APPEND EXTERNAL_LIBRARIES ${DAQ_STATIC_MODULE_LIBS})
+endif ()
+
include_directories(BEFORE ${LUAJIT_INCLUDE_DIR})
include_directories(AFTER ${EXTERNAL_INCLUDES})
#include "config.h"
#endif
-#include <sfbpf_dlt.h>
+#include <daq_dlt.h>
#include <random>
#include "config.h"
#endif
-#include <sfbpf_dlt.h>
+#include <daq_dlt.h>
#include "codecs/codec_module.h"
#include "framework/codec.h"
#include "daqs/daq_user.h"
#include "framework/codec.h"
#include "packet_io/sfdaq.h"
+#include "packet_io/sfdaq_instance.h"
using namespace snort;
bool UserCodec::decode(const RawData& raw, CodecData& codec, DecodeData& snort)
{
- DAQ_QueryFlow_t query { DAQ_USR_QUERY_PCI, 0, nullptr };
+ DIOCTL_QueryUsrPCI qup = { raw.daq_msg, nullptr };
- if ( SFDAQ::get_local_instance()->query_flow(raw.pkth, &query) != DAQ_SUCCESS or
- query.length != sizeof(DAQ_UsrHdr_t) )
- {
+ if ( SFDAQ::get_local_instance()->ioctl(DIOCTL_QUERY_USR_PCI, &qup, sizeof(qup)) != DAQ_SUCCESS )
return false;
- }
- const DAQ_UsrHdr_t* pci = (DAQ_UsrHdr_t*)query.value;
+ const DAQ_UsrHdr_t* pci = qup.pci;
if ( !pci )
return false;
#include "config.h"
#endif
-#include <sfbpf_dlt.h>
+#include <daq_dlt.h>
#include "codecs/codec_module.h"
#include "framework/codec.h"
#include "config.h"
#endif
-#include <sfbpf_dlt.h>
+#include <daq_dlt.h>
#include "framework/codec.h"
void ContextSwitcher::stop()
{
- assert(busy.size() == 1);
-
IpsContext* c = busy.back();
+ assert(c);
assert(c->state == IpsContext::BUSY);
-
assert(!c->has_callbacks());
assert(!c->dependencies());
trace_logf(detection, TRACE_DETECTION_ENGINE, "(wire) %" PRIu64 " cs::stop %" PRIu64 " (i=%zu, b=%zu)\n",
get_packet_number(), c->context_num, idle.size(), busy.size());
- busy.pop_back();
-
c->clear_context_data();
c->packet->active = nullptr;
c->packet->action = nullptr;
c->state = IpsContext::IDLE;
+ busy.pop_back();
idle.emplace_back(c);
}
#include "framework/endianness.h"
#include "helpers/ring.h"
#include "latency/packet_latency.h"
+#include "main/analyzer.h"
#include "main/modules.h"
-#include "main/snort.h"
#include "main/snort_config.h"
#include "main/snort_debug.h"
#include "main/thread.h"
DetectionEngine::DetectionEngine()
{
- context = Snort::get_switcher()->interrupt();
+ context = Analyzer::get_switcher()->interrupt();
context->file_data = { nullptr, 0 };
reset();
}
DetectionEngine::~DetectionEngine()
{
- if ( context == Snort::get_switcher()->get_context() )
+ if ( context == Analyzer::get_switcher()->get_context() )
{
// finish_packet is called here so that we clear wire packets at the right time
+ // FIXIT-L if might not be needed anymore with wire packet checks in finish_packet
finish_packet(context->packet, true);
}
}
void DetectionEngine::reset()
{
- IpsContext* c = Snort::get_switcher()->get_context();
+ IpsContext* c = Analyzer::get_switcher()->get_context();
c->alt_data.len = 0; // FIXIT-H need context::reset()
}
IpsContext* DetectionEngine::get_context()
-{ return Snort::get_switcher()->get_context(); }
+{ return Analyzer::get_switcher()->get_context(); }
SF_EVENTQ* DetectionEngine::get_event_queue()
-{ return Snort::get_switcher()->get_context()->equeue; }
+{ return Analyzer::get_switcher()->get_context()->equeue; }
Packet* DetectionEngine::get_current_packet()
-{ return Snort::get_switcher()->get_context()->packet; }
+{ return Analyzer::get_switcher()->get_context()->packet; }
+
+Packet* DetectionEngine::get_current_wire_packet()
+{ return Analyzer::get_switcher()->get_context()->wire_packet; }
void DetectionEngine::set_encode_packet(Packet* p)
-{ Snort::get_switcher()->get_context()->encode_packet = p; }
+{ Analyzer::get_switcher()->get_context()->encode_packet = p; }
Packet* DetectionEngine::get_encode_packet()
-{ return Snort::get_switcher()->get_context()->encode_packet; }
+{ return Analyzer::get_switcher()->get_context()->encode_packet; }
// we need to stay in the current context until rebuild is successful
// any events while rebuilding will be logged against the current packet
static THREAD_LOCAL IpsAction* shutdown_action = nullptr;
wait_for_context();
- IpsContext* c = Snort::get_switcher()->get_next();
- if ( parent ) // FIXIT-L parent can probably be determined by busy queue
+ IpsContext* c = Analyzer::get_switcher()->get_next();
+ if ( parent )
{
c->snapshot_flow(parent->flow);
c->packet_number = parent->context->packet_number;
+ c->wire_packet = parent->context->wire_packet;
}
else
+ {
c->packet_number = get_packet_number();
+ c->wire_packet = nullptr;
+ }
Packet* p = c->packet;
// normal rebuild
if ( parent )
{
+ p->daq_msg = parent->daq_msg;
+ p->daq_instance = parent->daq_instance;
p->active = parent->active;
p->action = parent->action;
}
// processing but parent is already gone (flow cache flush etc..)
- else if ( Snort::get_switcher()->get_context() )
+ else if ( Analyzer::get_switcher()->get_context() )
{
+ p->daq_msg = nullptr;
+ p->daq_instance = nullptr;
p->active = get_current_packet()->active;
p->action = get_current_packet()->action;
}
// shutdown, so use a dummy so null checking is not needed everywhere
else
{
+ p->daq_msg = nullptr;
+ p->daq_instance = nullptr;
p->action = &shutdown_action;
p->active = &shutdown_active;
shutdown_active.reset();
void DetectionEngine::finish_packet(Packet* p, bool flow_deletion)
{
- ContextSwitcher* sw = Snort::get_switcher();
+ ContextSwitcher* sw = Analyzer::get_switcher();
log_events(p);
clear_events(p);
if ( flow_deletion or p->is_rebuilt() )
sw->complete();
-
- // FIXIT-H enable for daqng
-#if 0
- if ( !p->is_rebuilt() )
- {
- sw->stop();
- queue for daq msg finalize
- }
-#endif
}
uint8_t* DetectionEngine::get_buffer(unsigned& max)
{
max = IpsContext::buf_size;
- return Snort::get_switcher()->get_context()->buf;
+ return Analyzer::get_switcher()->get_context()->buf;
}
uint8_t* DetectionEngine::get_next_buffer(unsigned& max)
{
max = IpsContext::buf_size;
- return Snort::get_switcher()->get_next()->buf;
+ return Analyzer::get_switcher()->get_next()->buf;
}
DataBuffer& DetectionEngine::get_alt_buffer(Packet* p)
}
void DetectionEngine::set_file_data(const DataPointer& dp)
-{ Snort::get_switcher()->get_context()->file_data = dp; }
+{ Analyzer::get_switcher()->get_context()->file_data = dp; }
DataPointer& DetectionEngine::get_file_data(IpsContext* c)
{ return c->file_data; }
void DetectionEngine::set_data(unsigned id, IpsContextData* p)
-{ Snort::get_switcher()->get_context()->set_context_data(id, p); }
+{ Analyzer::get_switcher()->get_context()->set_context_data(id, p); }
IpsContextData* DetectionEngine::get_data(unsigned id)
-{ return Snort::get_switcher()->get_context()->get_context_data(id); }
+{ return Analyzer::get_switcher()->get_context()->get_context_data(id); }
IpsContextData* DetectionEngine::get_data(unsigned id, IpsContext* context)
{
if ( context )
return context->get_context_data(id);
- ContextSwitcher* sw = Snort::get_switcher();
+ ContextSwitcher* sw = Analyzer::get_switcher();
if ( !sw )
return nullptr;
r.data = s;
r.offset = off;
- Snort::get_switcher()->get_context()->rpl.emplace_back(r);
+ Analyzer::get_switcher()->get_context()->rpl.emplace_back(r);
}
bool DetectionEngine::get_replacement(std::string& s, unsigned& off)
{
- if ( Snort::get_switcher()->get_context()->rpl.empty() )
+ if ( Analyzer::get_switcher()->get_context()->rpl.empty() )
return false;
- auto rep = Snort::get_switcher()->get_context()->rpl.back();
+ auto rep = Analyzer::get_switcher()->get_context()->rpl.back();
s = rep.data;
off = rep.offset;
- Snort::get_switcher()->get_context()->rpl.pop_back();
+ Analyzer::get_switcher()->get_context()->rpl.pop_back();
return true;
}
void DetectionEngine::clear_replacement()
{
- Snort::get_switcher()->get_context()->rpl.clear();
+ Analyzer::get_switcher()->get_context()->rpl.clear();
}
void DetectionEngine::disable_all(Packet* p)
{ p->context->active_rules = ar; }
void DetectionEngine::set_check_tags(bool enable)
-{ Snort::get_switcher()->get_context()->check_tags = enable; }
+{ Analyzer::get_switcher()->get_context()->check_tags = enable; }
bool DetectionEngine::get_check_tags()
-{ return Snort::get_switcher()->get_context()->check_tags; }
+{ return Analyzer::get_switcher()->get_context()->check_tags; }
//--------------------------------------------------------------------------
// offload / onload
bool DetectionEngine::do_offload(Packet* p)
{
- ContextSwitcher* sw = Snort::get_switcher();
+ ContextSwitcher* sw = Analyzer::get_switcher();
assert(p == p->context->packet);
assert(p->context == sw->get_context());
bool DetectionEngine::offload(Packet* p)
{
- ContextSwitcher* sw = Snort::get_switcher();
+ ContextSwitcher* sw = Analyzer::get_switcher();
bool depends_on_suspended = p->flow ? p->flow->context_chain.front() : sw->non_flow_chain.front();
bool can_offload = offloader->available();
void DetectionEngine::onload()
{
- for( Packet* p; offloader->count() and offloader->get(p); )
+ Packet* p;
+ while (offloader->count() and offloader->get(p))
{
trace_logf(detection, TRACE_DETECTION_ENGINE, "%" PRIu64 " de::onload %" PRIu64 " (r=%d)\n",
p->context->packet_number, p->context->context_num, offloader->count());
p->clear_offloaded();
- IpsContextChain& chain = p->flow ? p->flow->context_chain : Snort::get_switcher()->non_flow_chain;
+ IpsContextChain& chain = p->flow ? p->flow->context_chain : Analyzer::get_switcher()->non_flow_chain;
resume_ready_suspends(chain);
}
trace_logf(detection, TRACE_DETECTION_ENGINE, "%" PRIu64 " de::resume %" PRIu64 " (r=%d)\n",
p->context->packet_number, p->context->context_num, offloader->count());
- Snort::get_switcher()->resume(p->context);
+ ContextSwitcher* sw = Analyzer::get_switcher();
+ sw->resume(p->context);
fp_complete(p);
finish_inspect_with_latency(p); // FIXIT-L should latency be evaluated here?
finish_inspect(p, true);
finish_packet(p);
+
+ if ( !p->is_rebuilt() )
+ {
+ // This happens here to ensure needed contexts are available ASAP as
+ // not directly forwarding leads to deadlocking waiting on new contexts
+ Analyzer::get_local_analyzer()->post_process_packet(p);
+ }
}
void DetectionEngine::wait_for_context()
{
- ContextSwitcher* sw = Snort::get_switcher();
+ ContextSwitcher* sw = Analyzer::get_switcher();
if ( !sw->idle_count() )
{
finish_inspect_with_latency(p);
}
finish_inspect(p, inspected);
+
return true;
}
static IpsContext* get_context();
static Packet* get_current_packet();
+ static Packet* get_current_wire_packet();
static Packet* set_next_packet(Packet* parent = nullptr);
static uint8_t* get_next_buffer(unsigned& max);
static void set_check_tags(bool enable = true);
static bool get_check_tags();
+ static void wait_for_context();
+
private:
static struct SF_EVENTQ* get_event_queue();
static bool do_offload(snort::Packet*);
static void finish_inspect_with_latency(Packet*);
static void finish_inspect(Packet*, bool inspected);
static void finish_packet(Packet*, bool flow_deletion = false);
- static void wait_for_context();
private:
IpsContext* context;
TextLog_Print(tlog,
"Pkt=" STDu64 ", Sec=%lu.%6lu, Len=%u, Cap=%u\n",
p->context->packet_number, (long)p->pkth->ts.tv_sec, (long)p->pkth->ts.tv_usec,
- p->pkth->pktlen, p->pkth->caplen);
+ p->pkth->pktlen, p->pktlen);
TextLog_Print(tlog,
"Pkt Bits: Flags=0x%X, Proto=0x%X, Err=0x%X\n",
std::vector<Replacement> rpl;
Packet* packet;
+ Packet* wire_packet;
Packet* encode_packet;
DAQ_PktHdr_t* pkth;
uint8_t* buf;
if ( returned->metric & TAG_METRIC_BYTES )
{
- int n = p->pkth->caplen;
+ int n = p->pktlen;
if ( n < returned->bytes )
returned->bytes -= n;
else
// Won't add packet to retry queue if it is a retransmit
// and not from the retry queue since it should already
// be there.
- if (!(p->packet_flags & PKT_RETRANSMIT) or
- p->pkth->flags & DAQ_PKT_FLAG_RETRY_PACKET)
+ if (!(p->packet_flags & PKT_RETRANSMIT) or p->is_retry())
{
PacketTracer::log("File signature lookup: adding packet to retry queue. Resume=%d, Waited %" PRIi64 "ms.\n", resume, time_elapsed_ms(&now, &file_ctx->pending_expire_time, lookup_timeout));
}
#include "expect_cache.h"
#include "hash/zhash.h"
-#include "packet_io/sfdaq.h"
+#include "packet_io/sfdaq_instance.h"
#include "protocols/packet.h"
#include "protocols/vlan.h"
#include "pub_sub/expect_events.h"
last = nullptr;
/* Only add TCP and UDP expected flows for now via the DAQ module. */
if (ip_proto == IpProtocol::TCP || ip_proto == IpProtocol::UDP)
- SFDAQ::get_local_instance()->add_expected(ctrlPkt, cliIP, cliPort, srvIP, srvPort,
+ ctrlPkt->daq_instance->add_expected(ctrlPkt, cliIP, cliPort, srvIP, srvPort,
ip_proto, 1000, 0);
}
#include "utils/cpp_macros.h"
struct TextLog;
-struct _daq_pkthdr;
+struct _daq_msg;
+struct _daq_pkt_hdr;
namespace snort
{
struct RawData
{
- const _daq_pkthdr* pkth;
+ const struct _daq_msg* daq_msg;
+ const _daq_pkt_hdr* pkth;
const uint8_t* data;
uint32_t len;
- RawData(const _daq_pkthdr*, const uint8_t*);
+ RawData(const struct _daq_msg* daq_msg, const _daq_pkt_hdr* pkth, const uint8_t* data, uint32_t len) :
+ daq_msg(daq_msg), pkth(pkth), data(data), len(len) { }
};
/* Decode Flags */
#include "log/messages.h"
#include "main.h"
-#include "main/snort.h"
+#include "main/oops_handler.h"
#include "main/snort_config.h"
#include "utils/stats.h"
#include "utils/util.h"
{
// FIXIT-L what should we capture if this is the main thread?
if ( !is_main_thread )
- snort::Snort::capture_packet();
+ OopsHandler::handle_crash();
add_signal(signal, SIG_DFL, false);
raise(signal);
#include "log_text.h"
-#include <sfbpf_dlt.h>
+#include <daq_dlt.h>
#include "detection/detection_engine.h"
#include "detection/signature.h"
}
else if (SnortConfig::verbose_byte_dump())
{
- LogNetData(log, p->pkt, p->pkth->caplen, p);
+ LogNetData(log, p->pkt, p->pktlen, p);
}
}
} // namespace snort
static void ff_iface(Args&)
{
- TextLog_Print(csv_log, "%s", SFDAQ::get_interface_spec());
+ TextLog_Print(csv_log, "%s", SFDAQ::get_input_spec());
}
static void ff_ip_id(Args& a)
event.sig_info->gid, event.sig_info->sid, event.sig_info->rev);
if (SnortConfig::alert_interface())
- TextLog_Print(fast_log, " <%s> ", SFDAQ::get_interface_spec());
+ TextLog_Print(fast_log, " <%s> ", SFDAQ::get_input_spec());
if ( msg )
TextLog_Puts(fast_log, msg);
if (SnortConfig::alert_interface())
{
- const char* iface = SFDAQ::get_interface_spec();
+ const char* iface = SFDAQ::get_input_spec();
TextLog_Print(full_log, " <%s> ", iface);
}
static bool ff_iface(Args& a)
{
print_label(a, "iface");
- TextLog_Quote(json_log, SFDAQ::get_interface_spec());
+ TextLog_Quote(json_log, SFDAQ::get_input_spec());
return true;
}
if (SnortConfig::alert_interface())
{
SnortSnprintfAppend(event_string, sizeof(event_string),
- "<%s> ", SFDAQ::get_interface_spec());
+ "<%s> ", SFDAQ::get_input_spec());
}
}
if ((p != nullptr) && p->ptrs.ip_api.is_ip())
{
talos_log = new AlertLog;
- string ifname = string(SFDAQ::get_interface_spec());
+ string ifname = string(SFDAQ::get_input_spec());
size_t sep_pos = ifname.find_last_of("/\\");
if ( sep_pos != string::npos )
{
us.alert.pkth.ts.tv_sec = (uint32_t)p->pkth->ts.tv_sec;
us.alert.pkth.ts.tv_usec = (uint32_t)p->pkth->ts.tv_usec;
- us.alert.pkth.caplen = p->pkth->caplen;
+ us.alert.pkth.caplen = p->pktlen;
us.alert.pkth.len = p->pkth->pktlen;
memmove(us.alert.pkt, (const void*)p->pkt, us.alert.pkth.caplen);
}
const char* cmd;
switch (ev->get_type()) {
- case DAQ_METAHDR_TYPE_SOF: cmd = "sof"; break;
- case DAQ_METAHDR_TYPE_EOF: cmd = "eof"; break;
+ case DAQ_MSG_TYPE_SOF: cmd = "sof"; break;
+ case DAQ_MSG_TYPE_EOF: cmd = "eof"; break;
default: return;
}
static void log_raw(const Packet* p)
{
TextLog_Print(hext_log, "\n# %u [%u]\n",
- s_pkt_num++, p->pkth->caplen);
+ s_pkt_num++, p->pktlen);
}
static void log_header(const Packet* p)
if ( raw )
{
log_raw(p);
- log_data(p->pkt, p->pkth->caplen, width);
+ log_data(p->pkt, p->pktlen, width);
}
else if ( p->has_tcp_data() )
{
#include "framework/module.h"
#include "log/messages.h"
#include "main/snort_config.h"
-#include "protocols/packet.h"
#include "packet_io/sfdaq.h"
+#include "packet_io/sfdaq_config.h"
+#include "protocols/packet.h"
#include "utils/util.h"
using namespace snort;
// api stuff
//-------------------------------------------------------------------------
-static inline size_t SizeOf(const DAQ_PktHdr_t* pkth)
+static inline size_t SizeOf(const Packet* p)
{
- return PCAP_PKT_HDR_SZ + pkth->caplen;
+ return PCAP_PKT_HDR_SZ + p->pktlen;
}
static void LogTcpdumpSingle(
LtdConfig* data, Packet* p, const char*, Event*)
{
- size_t dumpSize = SizeOf(p->pkth);
+ size_t dumpSize = SizeOf(p);
if ( data->limit && (context.size + dumpSize > data->limit) )
TcpdumpRollLogFile(data);
struct pcap_pkthdr pcaphdr;
pcaphdr.ts = p->pkth->ts;
- pcaphdr.caplen = p->pkth->caplen;
+ pcaphdr.caplen = p->pktlen;
pcaphdr.len = p->pkth->pktlen;
pcap_dump((uint8_t*)context.dumpd, &pcaphdr, p->pkt);
context.size += dumpSize;
dlt = DLT_RAW;
pcap_t* pcap;
- pcap = pcap_open_dead(dlt, SFDAQ::get_snap_len());
+ pcap = pcap_open_dead(dlt, SnortConfig::get_conf()->daq_config->get_mru_size());
if ( !pcap )
FatalError("%s: can't get pcap context\n", S_NAME);
{
logheader.packet_second = htonl((uint32_t)p->pkth->ts.tv_sec);
logheader.packet_microsecond = htonl((uint32_t)p->pkth->ts.tv_usec);
- pkt_length = ( p->is_rebuilt() ) ? p->dsize : p->pkth->caplen;
+ pkt_length = ( p->is_rebuilt() ) ? p->dsize : p->pktlen;
logheader.packet_length = htonl(pkt_length + u2h_len);
write_len += pkt_length + u2h_len;
}
#include "managers/module_manager.h"
#include "managers/plugin_manager.h"
#include "packet_io/sfdaq.h"
+#include "packet_io/sfdaq_config.h"
+#include "packet_io/sfdaq_instance.h"
#include "packet_io/trough.h"
#include "target_based/sftarget_reader.h"
#include "time/periodic.h"
class Pig
{
public:
- Analyzer* analyzer;
- bool awaiting_privilege_change = false;
-
- Pig() { analyzer = nullptr; athread = nullptr; idx = (unsigned)-1; }
+ Pig() = default;
void set_index(unsigned index) { idx = index; }
- void prep(const char* source);
+ bool prep(const char* source);
void start();
void stop();
bool queue_command(AnalyzerCommand*, bool orphan = false);
void reap_commands();
+ Analyzer* analyzer = nullptr;
+ bool awaiting_privilege_change = false;
+ bool requires_privileged_start = true;
+
private:
void reap_command(AnalyzerCommand* ac);
- std::thread* athread;
- unsigned idx;
+ std::thread* athread = nullptr;
+ unsigned idx = (unsigned)-1;
};
-void Pig::prep(const char* source)
+bool Pig::prep(const char* source)
{
- analyzer = new Analyzer(idx, source);
+ SnortConfig* sc = SnortConfig::get_conf();
+ SFDAQInstance *instance = new SFDAQInstance(source, sc->daq_config);
+ if (!SFDAQ::init_instance(instance, sc->bpf_filter))
+ {
+ delete instance;
+ return false;
+ }
+ requires_privileged_start = instance->can_start_unprivileged();
+ analyzer = new Analyzer(instance, idx, source, sc->pkt_cnt);
+ analyzer->set_skip_cnt(sc->pkt_skip);
+#ifdef REG_TEST
+ analyzer->set_pause_after_cnt(sc->pkt_pause_cnt);
+#endif
+ return true;
}
void Pig::start()
int main_resume(lua_State* L)
{
- const bool from_shell = ( L != nullptr );
-
- int pkt_num = 0;
+ bool from_shell = ( L != nullptr );
+ uint64_t pkt_num = 0;
if (from_shell)
{
const int num_of_args = lua_gettop(L);
if (num_of_args)
{
- pkt_num = lua_tonumber(L, 1);
+ pkt_num = lua_tointeger(L, 1);
if (pkt_num < 1)
{
current_request->respond("Invalid usage of resume(n), n should be a number > 0\n");
if ( use_shell(SnortConfig::get_conf()) )
return false;
- /* FIXIT-L X This should really check if the DAQ module was unset as it could be explicitly
- set to the default value */
- if ( !strcmp(SFDAQ::get_type(), SFDAQ::default_type()) )
+ if ( SnortConfig::get_conf()->daq_config->module_configs.empty() )
{
if ( SnortConfig::read_mode() && !Trough::get_queue_size() )
return true;
- if ( !SnortConfig::read_mode() && !SFDAQ::get_input_spec(SnortConfig::get_conf(), 0) )
+ if ( !SnortConfig::read_mode() && !SFDAQ::get_input_spec(SnortConfig::get_conf()->daq_config, 0) )
return true;
}
break;
case Analyzer::State::INITIALIZED:
- if (pig.analyzer->requires_privileged_start() && pending_privileges &&
+ if (pig.requires_privileged_start && pending_privileges &&
!Snort::has_dropped_privileges())
{
if (!pig.awaiting_privilege_change)
break;
case Analyzer::State::STARTED:
- if (!pig.analyzer->requires_privileged_start() && pending_privileges &&
+ if (!pig.requires_privileged_start && pending_privileges &&
!Snort::has_dropped_privileges())
{
if (!pig.awaiting_privilege_change)
// Preemptively prep all pigs in live traffic mode
if (!SnortConfig::read_mode())
{
- for (swine = 0; swine < max_pigs; swine++)
- pigs[swine].prep(SFDAQ::get_input_spec(SnortConfig::get_conf(), swine));
+ for (unsigned i = 0; i < max_pigs; i++)
+ {
+ if (pigs[i].prep(SFDAQ::get_input_spec(SnortConfig::get_conf()->daq_config, i)))
+ swine++;
+ }
}
// Iterate over the drove, spawn them as allowed, and handle their deaths.
if ( !exit_requested and (swine < max_pigs) and (src = Trough::get_next()) )
{
Pig* pig = get_lazy_pig(max_pigs);
- pig->prep(src);
- ++swine;
+ if (pig->prep(src))
+ ++swine;
continue;
}
service_check();
help.h
modules.cc
modules.h
+ oops_handler.cc
+ oops_handler.h
policy.cc
request.cc
request.h
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
-// analyzer.cc author Russ Combs <rucombs@cisco.com>
+// analyzer.cc author Michael Altizer <mialtize@cisco.com>
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "analyzer.h"
+#include <daq.h>
+
#include <thread>
+#include "detection/context_switcher.h"
+#include "detection/detect.h"
+#include "detection/detection_engine.h"
+#include "detection/ips_context.h"
+#include "detection/tag.h"
+#include "file_api/file_service.h"
+#include "filters/detection_filter.h"
+#include "filters/sfthreshold.h"
+#include "flow/ha.h"
+#include "framework/data_bus.h"
+#include "latency/packet_latency.h"
+#include "latency/rule_latency.h"
#include "log/messages.h"
#include "main/swapper.h"
#include "main.h"
+#include "managers/action_manager.h"
+#include "managers/inspector_manager.h"
+#include "managers/ips_manager.h"
+#include "managers/event_manager.h"
+#include "managers/module_manager.h"
+#include "packet_io/active.h"
#include "packet_io/sfdaq.h"
+#include "packet_io/sfdaq_config.h"
+#include "packet_io/sfdaq_instance.h"
+#include "packet_tracer/packet_tracer.h"
+#include "profiler/profiler.h"
+#include "side_channel/side_channel.h"
+#include "stream/stream.h"
+#include "time/packet_time.h"
+#include "utils/stats.h"
#include "analyzer_command.h"
+#include "oops_handler.h"
#include "snort.h"
-#include "thread.h"
+#include "snort_config.h"
+#include "thread_config.h"
using namespace snort;
using namespace std;
-typedef DAQ_Verdict
-(* PacketCallback)(void*, const DAQ_PktHdr_t*, const uint8_t*);
+static MainHook_f main_hook = snort_ignore;
+
+THREAD_LOCAL ProfileStats totalPerfStats;
+static THREAD_LOCAL Analyzer* local_analyzer = nullptr;
+
+//-------------------------------------------------------------------------
+
+class RetryQueue
+{
+ struct Entry
+ {
+ Entry(const struct timeval& next_try, DAQ_Msg_h msg) : next_try(next_try), msg(msg) { }
+
+ struct timeval next_try;
+ DAQ_Msg_h msg;
+ };
+
+public:
+ RetryQueue(unsigned interval_ms)
+ {
+ assert(interval_ms > 0);
+ interval = { interval_ms / 1000, (interval_ms % 1000) * 1000 };
+ }
+
+ ~RetryQueue()
+ {
+ assert(empty());
+ }
+
+ void put(DAQ_Msg_h msg)
+ {
+ struct timeval now, next_try;
+ packet_gettimeofday(&now);
+ timeradd(&now, &interval, &next_try);
+ queue.emplace_back(next_try, msg);
+ }
+
+ DAQ_Msg_h get(const struct timeval* now = nullptr)
+ {
+ if (!empty())
+ {
+ const Entry& entry = queue.front();
+ if (!now || !timercmp(now, &entry.next_try, <))
+ {
+ DAQ_Msg_h msg = entry.msg;
+ queue.pop_front();
+ return msg;
+ }
+ }
+ return nullptr;
+ }
+
+ bool empty() const
+ {
+ return queue.empty();
+ }
+
+private:
+ deque<Entry> queue;
+ struct timeval interval;
+};
+
+//-------------------------------------------------------------------------
+
+/*
+ * Static Class Methods
+ */
+Analyzer* Analyzer::get_local_analyzer()
+{
+ return local_analyzer;
+}
+
+ContextSwitcher* Analyzer::get_switcher()
+{
+ assert(local_analyzer != nullptr);
+ return local_analyzer->switcher;
+}
+
+void Analyzer::set_main_hook(MainHook_f f)
+{
+ main_hook = f;
+}
+
+//-------------------------------------------------------------------------
+// message processing
+//-------------------------------------------------------------------------
+
+static void process_daq_sof_eof_msg(DAQ_Msg_h msg)
+{
+ const Flow_Stats_t *stats = (const Flow_Stats_t *) daq_msg_get_hdr(msg);
+
+ if (msg->type == DAQ_MSG_TYPE_EOF)
+ packet_time_update(&stats->eof_timestamp);
+ else
+ packet_time_update(&stats->sof_timestamp);
+
+ DataBus::publish(DAQ_META_EVENT, nullptr, daq_msg_get_type(msg), (const uint8_t*) stats);
+}
+
+static bool process_packet(Packet* p)
+{
+ assert(p->pkth && p->pkt);
+
+ aux_counts.rx_bytes += p->pktlen;
+
+ PacketTracer::activate(*p);
+
+ // FIXIT-M should not need to set policies here
+ set_default_policy();
+ p->user_inspection_policy_id = get_inspection_policy()->user_policy_id;
+ p->user_ips_policy_id = get_ips_policy()->user_policy_id;
+ p->user_network_policy_id = get_network_policy()->user_policy_id;
+
+ if ( !(p->packet_flags & PKT_IGNORE) )
+ {
+ clear_file_data();
+ // return incomplete status if the main hook indicates not all work was done
+ if (!main_hook(p))
+ return false;
+ }
+
+ return true;
+}
+
+// Finalize DAQ message verdict
+static DAQ_Verdict distill_verdict(Packet* p)
+{
+ DAQ_Verdict verdict = DAQ_VERDICT_PASS;
+ Active* act = p->active;
+
+ // First Pass
+ if ( act->packet_retry_requested() )
+ {
+ verdict = DAQ_VERDICT_RETRY;
+ }
+ else if ( act->session_was_blocked() )
+ {
+ if ( !act->can_block() )
+ verdict = DAQ_VERDICT_PASS;
+ else if ( act->get_tunnel_bypass() )
+ {
+ aux_counts.internal_blacklist++;
+ verdict = DAQ_VERDICT_BLOCK;
+ }
+ else if ( SnortConfig::inline_mode() || act->packet_force_dropped() )
+ verdict = DAQ_VERDICT_BLACKLIST;
+ else
+ verdict = DAQ_VERDICT_IGNORE;
+ }
+
+ // Second Pass, now with more side effects
+ if ( act->packet_was_dropped() && act->can_block() )
+ {
+ if ( verdict == DAQ_VERDICT_PASS )
+ verdict = DAQ_VERDICT_BLOCK;
+ }
+ else if ( verdict == DAQ_VERDICT_RETRY )
+ {
+ }
+ else if ( p->packet_flags & PKT_RESIZED )
+ {
+ // we never increase, only trim, but daq doesn't support resizing wire packet
+ PacketManager::encode_update(p);
+
+ if ( p->daq_instance->inject(p->daq_msg, 0, p->pkt, p->pktlen) == DAQ_SUCCESS )
+ verdict = DAQ_VERDICT_BLOCK;
+ // FIXIT-M X Should we be blocking the wire packet even if the injection fails?
+ }
+ else if ( p->packet_flags & PKT_MODIFIED )
+ {
+ // this packet was normalized and/or has replacements
+ PacketManager::encode_update(p);
+ verdict = DAQ_VERDICT_REPLACE;
+ }
+ else if ( (p->packet_flags & PKT_IGNORE) ||
+ (p->flow && p->flow->get_ignore_direction() == SSN_DIR_BOTH) )
+ {
+ if ( !act->get_tunnel_bypass() )
+ {
+ verdict = DAQ_VERDICT_WHITELIST;
+ }
+ else
+ {
+ verdict = DAQ_VERDICT_PASS;
+ aux_counts.internal_whitelist++;
+ }
+ }
+ else if ( p->ptrs.decode_flags & DECODE_PKT_TRUST )
+ {
+ if (p->flow)
+ p->flow->set_ignore_direction(SSN_DIR_BOTH);
+ verdict = DAQ_VERDICT_WHITELIST;
+ }
+ else
+ verdict = DAQ_VERDICT_PASS;
+
+ return verdict;
+}
+
+/*
+ * Private message processing methods
+ */
+void Analyzer::post_process_daq_pkt_msg(Packet* p)
+{
+ ActionManager::execute(p);
+
+ DAQ_Verdict verdict = distill_verdict(p);
+
+ if (PacketTracer::is_active())
+ {
+ PacketTracer::log("Policies: Network %u, Inspection %u, Detection %u\n",
+ get_network_policy()->user_policy_id, get_inspection_policy()->user_policy_id,
+ get_ips_policy()->user_policy_id);
+ PacketTracer::log("Verdict: %s\n", SFDAQ::verdict_to_string(verdict));
+
+ PacketTracer::dump(p);
+ }
+
+ HighAvailabilityManager::process_update(p->flow, p->pkth);
+
+ p->pkth = nullptr; // no longer avail upon sig segv
+
+ if (verdict == DAQ_VERDICT_RETRY)
+ retry_queue->put(p->daq_msg);
+ else
+ p->daq_instance->finalize_message(p->daq_msg, verdict);
+}
+
+void Analyzer::process_daq_pkt_msg(DAQ_Msg_h msg, bool retry)
+{
+ const DAQ_PktHdr_t* pkthdr = daq_msg_get_pkthdr(msg);
+
+ set_default_policy();
+ Profile profile(totalPerfStats);
+
+ if (!retry)
+ {
+ pc.total_from_daq++;
+ packet_time_update(&pkthdr->ts);
+ }
+
+ DetectionEngine::wait_for_context();
+ switcher->start();
+ Packet* p = switcher->get_context()->packet;
+ oops_handler->set_current_packet(p);
+ p->context->wire_packet = p;
+ p->context->packet_number = pc.total_from_daq;
+
+ DetectionEngine::reset();
+
+ sfthreshold_reset();
+ ActionManager::reset_queue(p);
+
+ p->daq_msg = msg;
+ p->daq_instance = daq_instance;
+ PacketManager::decode(p, pkthdr, daq_msg_get_data(msg), daq_msg_get_data_len(msg), false, retry);
+ if (process_packet(p))
+ {
+ post_process_daq_pkt_msg(p);
+ switcher->stop();
+ }
+
+ Stream::timeout_flows(packet_time());
+ HighAvailabilityManager::process_receive();
+}
+
+void Analyzer::process_daq_msg(DAQ_Msg_h msg, bool retry)
+{
+ switch (daq_msg_get_type(msg))
+ {
+ case DAQ_MSG_TYPE_PACKET:
+ process_daq_pkt_msg(msg, retry);
+ // process_daq_pkt_msg() handles finalizing the message (or tracking it if offloaded)
+ return;
+ case DAQ_MSG_TYPE_SOF:
+ case DAQ_MSG_TYPE_EOF:
+ process_daq_sof_eof_msg(msg);
+ break;
+ default:
+ break;
+ }
+ daq_instance->finalize_message(msg, DAQ_VERDICT_PASS);
+}
+
+void Analyzer::process_retry_queue()
+{
+ if (!retry_queue->empty())
+ {
+ struct timeval now;
+ packet_gettimeofday(&now);
+ DAQ_Msg_h msg;
+ while ((msg = retry_queue->get(&now)) != nullptr)
+ process_daq_msg(msg, true);
+ }
+}
+
+/*
+ * Public packet processing methods
+ */
+bool Analyzer::inspect_rebuilt(Packet* p)
+{
+ // Need to include this b/c call is outside the detect tree
+ Profile detect_profile(detectPerfStats);
+ DeepProfile rebuilt_profile(rebuiltPacketPerfStats);
+
+ DetectionEngine de;
+ return main_hook(p);
+}
-// FIXIT-M add fail open capability
-static THREAD_LOCAL PacketCallback main_func = Snort::packet_callback;
+bool Analyzer::process_rebuilt_packet(Packet* p, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt, uint32_t pktlen)
+{
+ PacketManager::decode(p, pkthdr, pkt, pktlen, true);
+
+ p->packet_flags |= (PKT_PSEUDO | PKT_REBUILT_FRAG);
+ p->pseudo_type = PSEUDO_PKT_IP;
+
+ return process_packet(p);
+}
+
+void Analyzer::post_process_packet(Packet* p)
+{
+ post_process_daq_pkt_msg(p);
+ // FIXIT-? There is an assumption that this is being called on the active context...
+ switcher->stop();
+}
//-------------------------------------------------------------------------
-// analyzer
+// Utility
//-------------------------------------------------------------------------
+void Analyzer::show_source()
+{
+ const char* pcap = source.c_str();
+
+ if (!strcmp(pcap, "-"))
+ pcap = "stdin";
+
+ if (get_run_num() != 1)
+ fprintf(stdout, "%s", "\n");
+
+ fprintf(stdout, "Reading network traffic from \"%s\" with snaplen = %u\n",
+ pcap, SnortConfig::get_conf()->daq_config->get_mru_size());
+}
+
void Analyzer::set_state(State s)
{
state = s;
switch ( s )
{
- case State::NEW: return "NEW";
- case State::INITIALIZED: return "INITIALIZED";
- case State::STARTED: return "STARTED";
- case State::RUNNING: return "RUNNING";
- case State::PAUSED: return "PAUSED";
- case State::STOPPED: return "STOPPED";
- default: assert(false);
+ case State::NEW: return "NEW";
+ case State::INITIALIZED: return "INITIALIZED";
+ case State::STARTED: return "STARTED";
+ case State::RUNNING: return "RUNNING";
+ case State::PAUSED: return "PAUSED";
+ case State::STOPPED: return "STOPPED";
+ default: assert(false);
}
return "UNKNOWN";
}
-Analyzer::Analyzer(unsigned i, const char* s)
+//-------------------------------------------------------------------------
+// Thread life cycle
+//-------------------------------------------------------------------------
+
+void Analyzer::idle()
+{
+ // FIXIT-L this whole thing could be pub-sub
+ DataBus::publish(THREAD_IDLE_EVENT, nullptr);
+ if (SnortConfig::read_mode())
+ Stream::timeout_flows(packet_time());
+ else
+ Stream::timeout_flows(time(nullptr));
+ aux_counts.idle++;
+ HighAvailabilityManager::process_receive();
+}
+
+/*
+ * Perform all packet thread initialization actions that can be taken with dropped privileges
+ * and/or must be called after the DAQ module has been started.
+ */
+void Analyzer::init_unprivileged()
+{
+ // using dummy values until further integration
+ const unsigned max_contexts = 20;
+
+ switcher = new ContextSwitcher;
+
+ for ( unsigned i = 0; i < max_contexts; ++i )
+ switcher->push(new IpsContext);
+
+ SnortConfig* sc = SnortConfig::get_conf();
+
+ CodecManager::thread_init(sc);
+
+ // this depends on instantiated daq capabilities
+ // so it is done here instead of init()
+ Active::thread_init(sc);
+
+ InitTag();
+ EventTrace_Init();
+ detection_filter_init(sc->detection_filter_config);
+ DetectionEngine::thread_init();
+
+ EventManager::open_outputs();
+ IpsManager::setup_options();
+ ActionManager::thread_init(sc);
+ FileService::thread_init();
+ SideChannelManager::thread_init();
+ HighAvailabilityManager::thread_init(); // must be before InspectorManager::thread_init();
+ InspectorManager::thread_init(sc);
+ PacketTracer::thread_init();
+
+ // in case there are HA messages waiting, process them first
+ HighAvailabilityManager::process_receive();
+ PacketManager::thread_init();
+}
+
+void Analyzer::reinit(SnortConfig* sc)
+{
+ InspectorManager::thread_reinit(sc);
+ ActionManager::thread_reinit(sc);
+}
+
+void Analyzer::term()
+{
+ SnortConfig* sc = SnortConfig::get_conf();
+
+ HighAvailabilityManager::thread_term_beginning();
+
+ if ( !sc->dirty_pig )
+ Stream::purge_flows();
+
+ DetectionEngine::idle();
+ InspectorManager::thread_stop(sc);
+ ModuleManager::accumulate(sc);
+ InspectorManager::thread_term(sc);
+ ActionManager::thread_term(sc);
+
+ IpsManager::clear_options();
+ EventManager::close_outputs();
+ CodecManager::thread_term();
+ HighAvailabilityManager::thread_term();
+ SideChannelManager::thread_term();
+
+ oops_handler->set_current_packet(nullptr);
+
+ if ( daq_instance->was_started() )
+ {
+ DAQ_Msg_h msg;
+ while ((msg = retry_queue->get()) != nullptr)
+ daq_instance->finalize_message(msg, DAQ_VERDICT_BLOCK);
+ daq_instance->stop();
+ }
+ SFDAQ::set_local_instance(nullptr);
+
+ PacketLatency::tterm();
+ RuleLatency::tterm();
+
+ Profiler::consolidate_stats();
+
+ DetectionEngine::thread_term();
+ detection_filter_term();
+ EventTrace_Term();
+ CleanupTag();
+ FileService::thread_term();
+ PacketTracer::thread_term();
+ PacketManager::thread_term();
+
+ Active::thread_term();
+ delete switcher;
+}
+
+Analyzer::Analyzer(SFDAQInstance* instance, unsigned i, const char* s, uint64_t msg_cnt)
{
id = i;
+ exit_after_cnt = msg_cnt;
source = s ? s : "";
- daq_instance = nullptr;
- privileged_start = false;
- exit_requested = false;
+ daq_instance = instance;
+ retry_queue = new RetryQueue(200);
set_state(State::NEW);
}
+Analyzer::~Analyzer()
+{
+ delete daq_instance;
+ delete oops_handler;
+ delete retry_queue;
+}
+
void Analyzer::operator()(Swapper* ps, uint16_t run_num)
{
+ oops_handler = new OopsHandler();
+
set_thread_type(STHREAD_TYPE_PACKET);
set_instance_id(id);
set_run_num(run_num);
+ local_analyzer = this;
- ps->apply();
+ ps->apply(*this);
delete ps;
- if (Snort::thread_init_privileged(source.c_str()))
- {
- daq_instance = SFDAQ::get_local_instance();
- privileged_start = daq_instance->can_start_unprivileged();
- set_state(State::INITIALIZED);
+ if (SnortConfig::pcap_show())
+ show_source();
- analyze();
+ // Perform all packet thread initialization actions that need to be taken with escalated
+ // privileges prior to starting the DAQ module.
+ SnortConfig::get_conf()->thread_config->implement_thread_affinity(STHREAD_TYPE_PACKET,
+ get_instance_id());
- Snort::thread_term();
- }
+ SFDAQ::set_local_instance(daq_instance);
+ set_state(State::INITIALIZED);
+
+ // Start the main loop
+ analyze();
+
+ term();
set_state(State::STOPPED);
}
/* Break out of the DAQ acquire loop so that the command will be processed.
This is explicitly safe to call from another thread. */
- if ( state == State::RUNNING and daq_instance )
- daq_instance->break_loop(0);
+ if ( state >= State::STARTED and state < State::STOPPED and daq_instance )
+ daq_instance->interrupt();
}
bool Analyzer::handle_command()
return true;
}
-void Analyzer::analyze()
+void Analyzer::handle_commands()
{
- // The main analyzer loop is terminated by a command returning false or an error during acquire
- while (!exit_requested)
+ while (handle_command())
+ ;
+}
+
+DAQ_RecvStatus Analyzer::process_messages()
+{
+ // Max receive becomes the minimum of the configured batch size, the remaining exit_after
+ // count (if requested), and the remaining pause_after count (if requested).
+ unsigned max_recv = daq_instance->get_batch_size();
+ if (exit_after_cnt && exit_after_cnt < max_recv)
+ max_recv = exit_after_cnt;
+ if (pause_after_cnt && pause_after_cnt < max_recv)
+ max_recv = pause_after_cnt;
+
+ DAQ_RecvStatus rstat = daq_instance->receive_messages(max_recv);
+
+ unsigned num_recv = 0;
+ DAQ_Msg_h msg;
+ while ((msg = daq_instance->next_message()) != nullptr)
{
- TestPause& s_pause = Snort::get_test_pause();
- if (s_pause.get_pause())
+ // Dispose of any messages to be skipped first.
+ if (skip_cnt > 0)
{
- pause();
- s_pause.clear_pause();
- s_pause.set_pause_cnt(0);
- snort::LogMessage("== paused\n");
- }
- if (handle_command())
+ aux_counts.skipped++;
+ skip_cnt--;
+ daq_instance->finalize_message(msg, DAQ_VERDICT_PASS);
continue;
+ }
+ // FIXIT-M add fail open capability
+ // IMPORTANT: process_daq_msg() is responsible for finalizing the messages.
+ num_recv++;
+ process_daq_msg(msg, false);
+ DetectionEngine::onload();
+ process_retry_queue();
+ }
+ if (exit_after_cnt && (exit_after_cnt -= num_recv) == 0)
+ stop();
+ if (pause_after_cnt && (pause_after_cnt -= num_recv) == 0)
+ pause();
+ return rstat;
+}
+
+void Analyzer::analyze()
+{
+ while (!exit_requested)
+ {
// If we're not in the running state (usually either pre-start or paused),
// just keep stalling until something else comes up.
if (state != State::RUNNING)
{
- chrono::milliseconds ms(10);
- this_thread::sleep_for(ms);
+ if (!handle_command())
+ {
+ chrono::milliseconds ms(10);
+ this_thread::sleep_for(ms);
+ }
continue;
}
- if (daq_instance->acquire(0, main_func))
- break;
- // FIXIT-L acquire(0) makes idle processing unlikely under high traffic
- // because it won't return until no packets, signal, etc. that means
- // the idle processing may not be useful or that we need a hook to do
- // things periodically even when traffic is available
- Snort::thread_idle();
+ // Receive and process a batch of messages. Evaluate the receive status after processing
+ // the returned messages to determine if we should immediately continue, take the opportunity
+ // to deal with some house cleaning work, or terminate the analyzer thread.
+ DAQ_RecvStatus rstat = process_messages();
+ if (rstat != DAQ_RSTAT_OK && rstat != DAQ_RSTAT_WOULD_BLOCK)
+ {
+ if (rstat == DAQ_RSTAT_TIMEOUT)
+ {
+ // If the receive timed out, let's do some idle work before continuing.
+ // FIXIT-L Hitting a one second timeout when attached to any real traffic source
+ // is extremely unlikely, so relying on anything in thread_idle() ever being
+ // called is dangerous.
+ idle();
+ }
+ else if (rstat == DAQ_RSTAT_INTERRUPTED)
+ {
+ // If the status reports INTERRUPTED because of an interrupt() call, exit_requested should
+ // be set for the next pass through the main loop. Use this as a hint to check for analyzer
+ // commands.
+ handle_commands();
+ }
+ else
+ {
+ if (rstat == DAQ_RSTAT_NOBUF)
+ ErrorMessage("Exhausted the DAQ message pool!\n");
+ else if (rstat == DAQ_RSTAT_ERROR)
+ ErrorMessage("Error receiving message from the DAQ instance: %s\n", daq_instance->get_error());
+ // Implicitly handled:
+ // DAQ_RSTAT_EOF - File readback completed, job well done; let's get out of here.
+ // DAQ_RSTAT_INVALID - This really shouldn't happen.
+ break;
+ }
+ }
}
}
void Analyzer::run(bool paused)
{
assert(state == State::STARTED);
- Snort::thread_init_unprivileged();
+ init_unprivileged();
if ( paused )
set_state(State::PAUSED);
else
get_state_string());
}
-void Analyzer::resume(int pkt_cnt)
+void Analyzer::resume(uint64_t msg_cnt)
{
if (state == State::PAUSED)
{
- TestPause& s_pause = Snort::get_test_pause();
- s_pause.set_pause_cnt(pkt_cnt);
+ set_pause_after_cnt(msg_cnt);
set_state(State::RUNNING);
}
else
daq_instance->reload();
}
+void Analyzer::rotate()
+{
+ DataBus::publish(THREAD_ROTATE_EVENT, nullptr);
+}
+
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
-// analyzer.h author Russ Combs <rucombs@cisco.com>
+// analyzer.h author Michael Altizer <mialtize@cisco.com>
#ifndef ANALYZER_H
#define ANALYZER_H
// runs in a different thread, it also provides a command facility so that
// to control the thread and swap configuration.
+#include <daq_common.h>
+
#include <atomic>
#include <mutex>
#include <queue>
#include <string>
+#include "thread.h"
+
class AnalyzerCommand;
+class ContextSwitcher;
+class OopsHandler;
+class RetryQueue;
class Swapper;
namespace snort
{
class SFDAQInstance;
+struct Packet;
+struct SnortConfig;
+struct ProfileStats;
}
+typedef bool (* MainHook_f)(snort::Packet*);
+
class Analyzer
{
public:
STOPPED,
NUM_STATES
};
- Analyzer(unsigned id, const char* source);
+
+ static Analyzer* get_local_analyzer();
+ static ContextSwitcher* get_switcher();
+ static void set_main_hook(MainHook_f);
+
+ Analyzer(snort::SFDAQInstance*, unsigned id, const char* source, uint64_t msg_cnt = 0);
+ ~Analyzer();
void operator()(Swapper*, uint16_t run_num);
const char* get_state_string();
const char* get_source() { return source.c_str(); }
+ void set_pause_after_cnt(uint64_t msg_cnt) { pause_after_cnt = msg_cnt; }
+ void set_skip_cnt(uint64_t msg_cnt) { skip_cnt = msg_cnt; }
+
void execute(AnalyzerCommand*);
- bool requires_privileged_start() { return privileged_start; }
+ void post_process_packet(snort::Packet*);
+ bool process_rebuilt_packet(snort::Packet*, const DAQ_PktHdr_t*, const uint8_t* pkt, uint32_t pktlen);
+ bool inspect_rebuilt(snort::Packet*);
// Functions called by analyzer commands
void start();
void run(bool paused = false);
void stop();
void pause();
- void resume(int pkt_cnt);
+ void resume(uint64_t msg_cnt);
void reload_daq();
+ void reinit(snort::SnortConfig*);
+ void rotate();
private:
void analyze();
bool handle_command();
+ void handle_commands();
+ DAQ_RecvStatus process_messages();
+ void process_daq_msg(DAQ_Msg_h, bool retry);
+ void process_daq_pkt_msg(DAQ_Msg_h, bool retry);
+ void post_process_daq_pkt_msg(snort::Packet*);
+ void process_retry_queue();
void set_state(State);
+ void idle();
+ bool init_privileged();
+ void init_unprivileged();
+ void term();
+ void show_source();
public:
std::queue<AnalyzerCommand*> completed_work_queue;
private:
std::atomic<State> state;
- std::atomic<bool> privileged_start;
unsigned id;
- bool exit_requested;
+ bool exit_requested = false;
+
+ uint64_t exit_after_cnt;
+ uint64_t pause_after_cnt = 0;
+ uint64_t skip_cnt = 0;
std::string source;
snort::SFDAQInstance* daq_instance;
+ RetryQueue* retry_queue = nullptr;
+ OopsHandler* oops_handler = nullptr;
+ ContextSwitcher* switcher = nullptr;
std::mutex pending_work_queue_mutex;
};
+extern THREAD_LOCAL snort::ProfileStats totalPerfStats;
+
#endif
void ACResume::execute(Analyzer& analyzer)
{
- analyzer.resume(pkt_count);
+ analyzer.resume(msg_cnt);
}
-void ACRotate::execute(Analyzer&)
+void ACRotate::execute(Analyzer& analyzer)
{
- snort::Snort::thread_rotate();
+ analyzer.rotate();
}
void ACGetStats::execute(Analyzer&)
Swapper::set_reload_in_progress(true);
}
-void ACSwap::execute(Analyzer&)
+void ACSwap::execute(Analyzer& analyzer)
{
if (ps)
- ps->apply();
+ ps->apply(analyzer);
}
ACSwap::~ACSwap()
class ACResume : public AnalyzerCommand
{
public:
- ACResume(int n): pkt_count(n){}
+ ACResume(uint64_t msg_cnt): msg_cnt(msg_cnt) { }
void execute(Analyzer&) override;
const char* stringify() override { return "RESUME"; }
private:
- int pkt_count;
+ uint64_t msg_cnt;
};
class ACRotate : public AnalyzerCommand
[[noreturn]] void list_daqs(SnortConfig* sc)
{
- SFDAQ::load(sc);
+ SFDAQ::load(sc->daq_config);
SFDAQ::print_types(cout);
SFDAQ::unload();
exit(0);
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// oops_handler.cc author Michael Altizer <mialtize@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "oops_handler.h"
+
+#include "protocols/packet.h"
+
+static THREAD_LOCAL OopsHandler* local_oops_handler = nullptr;
+
+void OopsHandler::handle_crash()
+{
+ if (local_oops_handler)
+ local_oops_handler->eternalize();
+}
+
+OopsHandler::OopsHandler()
+{
+ assert(local_oops_handler == nullptr);
+ local_oops_handler = this;
+}
+
+OopsHandler::~OopsHandler()
+{
+ local_oops_handler = nullptr;
+}
+
+void OopsHandler::eternalize()
+{
+ // Copy the crashed thread's data. C++11 specs ensure the
+ // thread that segfaulted will still be running.
+ if (packet && packet->pkth)
+ {
+ pkth = *(packet->pkth);
+ if (packet->pkt)
+ {
+ memcpy(data, packet->pkt, 0xFFFF & packet->pktlen);
+ packet->pkt = data;
+ }
+ }
+}
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// oops_handler.h author Michael Altizer <mialtize@cisco.com>
+
+#ifndef OOPS_HANDLER_H
+#define OOPS_HANDLER_H
+
+#include <daq_common.h>
+
+namespace snort
+{
+struct Packet;
+}
+
+class OopsHandler
+{
+public:
+ static void handle_crash();
+
+ OopsHandler();
+ ~OopsHandler();
+ void set_current_packet(snort::Packet* p) { packet = p; }
+ void eternalize();
+
+private:
+ DAQ_PktHdr_t pkth = { };
+ uint8_t data[65535] = { };
+ snort::Packet* packet = nullptr;
+};
+
+#endif
+
#include "snort.h"
+#include <daq.h>
#include <sys/stat.h>
#include <syslog.h>
#include "actions/ips_actions.h"
#include "codecs/codec_api.h"
#include "connectors/connectors.h"
-#include "decompress/file_decomp.h"
-#include "detection/context_switcher.h"
#include "detection/detect.h"
-#include "detection/detection_engine.h"
-#include "detection/detection_util.h"
#include "detection/fp_config.h"
#include "detection/fp_detect.h"
-#include "detection/ips_context.h"
-#include "detection/tag.h"
#include "file_api/file_service.h"
-#include "filters/detection_filter.h"
#include "filters/rate_filter.h"
#include "filters/sfthreshold.h"
#include "flow/ha.h"
-#include "framework/endianness.h"
#include "framework/mpse.h"
-#include "helpers/base64_encoder.h"
#include "helpers/process.h"
#include "host_tracker/host_cache.h"
-#include "ips_options/ips_flowbits.h"
#include "ips_options/ips_options.h"
-#include "latency/packet_latency.h"
-#include "latency/rule_latency.h"
#include "log/log.h"
#include "log/messages.h"
#include "loggers/loggers.h"
#include "main.h"
#include "main/shell.h"
-#include "main/thread_config.h"
-#include "managers/action_manager.h"
#include "managers/codec_manager.h"
#include "managers/inspector_manager.h"
#include "managers/ips_manager.h"
#include "packet_io/active.h"
#include "packet_io/sfdaq.h"
#include "packet_io/trough.h"
-#include "packet_tracer/packet_tracer.h"
#include "parser/cmd_line.h"
#include "parser/parser.h"
#include "profiler/profiler.h"
#include "search_engines/search_engines.h"
#include "service_inspectors/service_inspectors.h"
#include "side_channel/side_channel.h"
-#include "stream/stream.h"
#include "stream/stream_inspectors.h"
#include "target_based/sftarget_reader.h"
-#include "time/packet_time.h"
#include "time/periodic.h"
#include "utils/util.h"
-#include "utils/util_utf.h"
-#include "utils/util_jsnorm.h"
#ifdef PIGLET
#include "piglet/piglet.h"
using namespace snort;
using namespace std;
-//-------------------------------------------------------------------------
-
static SnortConfig* snort_cmd_line_conf = nullptr;
static pid_t snort_main_thread_pid = 0;
-// non-local for easy access from core
-static THREAD_LOCAL DAQ_PktHdr_t s_pkth;
-static THREAD_LOCAL uint8_t* s_data = nullptr;
-static THREAD_LOCAL Packet* s_packet = nullptr;
-static THREAD_LOCAL ContextSwitcher* s_switcher = nullptr;
-
-ContextSwitcher* Snort::get_switcher()
-{ return s_switcher; }
-
-// Test util - used for pause-after-n and resume(n)
-static THREAD_LOCAL TestPause s_pause;
-
-TestPause& Snort::get_test_pause()
-{ return s_pause; }
-
-void TestPause::set_pause_cnt(int cnt)
-{ pause_cnt = cnt ? (cnt + pc.total_from_daq) : 0; }
-
//-------------------------------------------------------------------------
// perf stats
// FIXIT-M move these to appropriate modules
//-------------------------------------------------------------------------
-static THREAD_LOCAL ProfileStats totalPerfStats;
-static THREAD_LOCAL ProfileStats metaPerfStats;
-
static ProfileStats* get_profile(const char* key)
{
if ( !strcmp(key, "detect") )
if ( !strcmp(key, "total") )
return &totalPerfStats;
- if ( !strcmp(key, "daq_meta") )
- return &metaPerfStats;
-
return nullptr;
}
// helpers
//-------------------------------------------------------------------------
-static bool pass_pkts(Packet*) { return true; }
-static MainHook_f main_hook = pass_pkts;
-
-static void set_policy(Packet* p)
-{
- set_default_policy();
- p->user_inspection_policy_id = get_inspection_policy()->user_policy_id;
- p->user_ips_policy_id = get_ips_policy()->user_policy_id;
- p->user_network_policy_id = get_network_policy()->user_policy_id;
-}
-
-static void show_source(const char* pcap)
-{
- if ( !SnortConfig::pcap_show() )
- return;
-
- if ( !strcmp(pcap, "-") )
- pcap = "stdin";
-
- static bool first = true;
- if ( first )
- first = false;
- else
- fprintf(stdout, "%s", "\n");
-
- fprintf(stdout, "Reading network traffic from \"%s\" with snaplen = %u\n",
- pcap, SFDAQ::get_snap_len());
-}
-
-
//-------------------------------------------------------------------------
// initialization
//-------------------------------------------------------------------------
ScriptManager::load_scripts(snort_cmd_line_conf->script_paths);
PluginManager::load_plugins(snort_cmd_line_conf->plugin_path);
- if ( SnortConfig::get_conf()->logging_flags & LOGGING_FLAG__SHOW_PLUGINS )
+ if ( snort_cmd_line_conf->logging_flags & LOGGING_FLAG__SHOW_PLUGINS )
{
ModuleManager::dump_modules();
PluginManager::dump_plugins();
parser_term(sc);
Active::init(sc);
+
+ LogMessage("%s\n", LOG_DIV);
+
+ SFDAQ::init(sc->daq_config);
}
// this function should only include initialization that must be done as a
/* Drop privileges if requested. */
if (SnortConfig::get_uid() != -1 || SnortConfig::get_gid() != -1)
{
- if (!SFDAQ::unprivileged())
+ if (!SFDAQ::can_run_unprivileged())
{
- ParseError("Cannot drop privileges - %s DAQ does not support unprivileged operation.\n",
- SFDAQ::get_type());
+ ParseError("Cannot drop privileges - at least one of the configured DAQ modules does not support unprivileged operation.\n");
return false;
}
if (!SetUidGid(SnortConfig::get_uid(), SnortConfig::get_gid()))
bool Snort::has_dropped_privileges()
{ return privileges_dropped; }
-void Snort::set_main_hook(MainHook_f f)
-{ main_hook = f; }
-
-Packet* Snort::get_packet()
-{ return s_packet; }
-
void Snort::setup(int argc, char* argv[])
{
set_main_thread();
init(argc, argv);
- LogMessage("%s\n", LOG_DIV);
- SFDAQ::init(SnortConfig::get_conf());
-
if ( SnortConfig::daemon_mode() )
daemonize();
return sc;
}
-void Snort::capture_packet()
-{
- if ( snort_main_thread_pid == gettid() )
- {
- // FIXIT-L main thread crashed. Do anything?
- }
- else
- {
- // Copy the crashed threads data. C++11 specs ensure the
- // thread that segfaulted will still be running.
- if ( s_packet && s_packet->pkth )
- {
- s_pkth = *(s_packet->pkth);
-
- if ( s_packet->pkt )
- {
- memcpy(s_data, s_packet->pkt, 0xFFFF & s_packet->pkth->caplen);
- s_packet->pkt = s_data;
- }
- }
- }
-}
-
-void Snort::thread_idle()
-{
- // FIXIT-L this whole thing could be pub-sub
- DataBus::publish(THREAD_IDLE_EVENT, nullptr);
- if (SnortConfig::read_mode())
- Stream::timeout_flows(packet_time());
- else
- Stream::timeout_flows(time(nullptr));
- aux_counts.idle++;
- HighAvailabilityManager::process_receive();
-}
-
-void Snort::thread_rotate()
-{
- DataBus::publish(THREAD_ROTATE_EVENT, nullptr);
-}
-
-/*
- * Perform all packet thread initialization actions that need to be taken with escalated privileges
- * prior to starting the DAQ module.
- */
-bool Snort::thread_init_privileged(const char* intf)
-{
- s_data = new uint8_t[65535];
- show_source(intf);
-
- SnortConfig::get_conf()->thread_config->implement_thread_affinity(STHREAD_TYPE_PACKET,
- get_instance_id());
-
- // FIXIT-M the start-up sequence is a little off due to dropping privs
- SFDAQInstance* daq_instance = new SFDAQInstance(intf);
- SFDAQ::set_local_instance(daq_instance);
- if (!daq_instance->configure(SnortConfig::get_conf()))
- {
- SFDAQ::set_local_instance(nullptr);
- delete daq_instance;
- return false;
- }
-
- return true;
-}
-
-/*
- * Perform all packet thread initialization actions that can be taken with dropped privileges
- * and/or must be called after the DAQ module has been started.
- */
-void Snort::thread_init_unprivileged()
-{
- // using dummy values until further integration
- const unsigned max_contexts = 20;
-
- s_switcher = new ContextSwitcher;
-
- for ( unsigned i = 0; i < max_contexts; ++i )
- s_switcher->push(new IpsContext);
-
- CodecManager::thread_init(SnortConfig::get_conf());
-
- // this depends on instantiated daq capabilities
- // so it is done here instead of init()
- Active::thread_init(SnortConfig::get_conf());
-
- InitTag();
- EventTrace_Init();
- detection_filter_init(SnortConfig::get_conf()->detection_filter_config);
- DetectionEngine::thread_init();
-
- EventManager::open_outputs();
- IpsManager::setup_options();
- ActionManager::thread_init(SnortConfig::get_conf());
- FileService::thread_init();
- SideChannelManager::thread_init();
- HighAvailabilityManager::thread_init(); // must be before InspectorManager::thread_init();
- InspectorManager::thread_init(SnortConfig::get_conf());
- PacketTracer::thread_init();
-
- // in case there are HA messages waiting, process them first
- HighAvailabilityManager::process_receive();
- PacketManager::thread_init();
-}
-
-void Snort::thread_reinit(SnortConfig* sc)
-{
- InspectorManager::thread_reinit(sc);
- ActionManager::thread_reinit(sc);
-}
-
-void Snort::thread_term()
-{
- HighAvailabilityManager::thread_term_beginning();
-
- if ( !SnortConfig::get_conf()->dirty_pig )
- Stream::purge_flows();
-
- DetectionEngine::idle();
- InspectorManager::thread_stop(SnortConfig::get_conf());
- ModuleManager::accumulate(SnortConfig::get_conf());
- InspectorManager::thread_term(SnortConfig::get_conf());
- ActionManager::thread_term(SnortConfig::get_conf());
-
- IpsManager::clear_options();
- EventManager::close_outputs();
- CodecManager::thread_term();
- HighAvailabilityManager::thread_term();
- SideChannelManager::thread_term();
-
- s_packet = nullptr;
-
- SFDAQInstance* daq_instance = SFDAQ::get_local_instance();
- if ( daq_instance->was_started() )
- daq_instance->stop();
- SFDAQ::set_local_instance(nullptr);
- delete daq_instance;
-
- PacketLatency::tterm();
- RuleLatency::tterm();
-
- Profiler::consolidate_stats();
-
- DetectionEngine::thread_term();
- detection_filter_term();
- EventTrace_Term();
- CleanupTag();
- FileService::thread_term();
- PacketTracer::thread_term();
- PacketManager::thread_term();
-
- Active::thread_term();
- delete s_switcher;
- delete[] s_data;
-}
-
-bool Snort::inspect(Packet* p)
-{
- // Need to include this b/c call is outside the detect tree
- Profile detect_profile(detectPerfStats);
- DeepProfile rebuilt_profile(rebuiltPacketPerfStats);
-
- DetectionEngine de;
- return main_hook(p);
-}
-
-DAQ_Verdict Snort::process_packet(
- Packet* p, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt, bool is_frag)
-{
- aux_counts.rx_bytes += pkthdr->caplen;
-
- PacketManager::decode(p, pkthdr, pkt, is_frag);
- assert(p->pkth && p->pkt);
-
- PacketTracer::activate(*p);
-
- if (is_frag)
- {
- p->packet_flags |= (PKT_PSEUDO | PKT_REBUILT_FRAG);
- p->pseudo_type = PSEUDO_PKT_IP;
- }
-
- set_policy(p); // FIXIT-M should not need this here
-
- if ( !(p->packet_flags & PKT_IGNORE) )
- {
- clear_file_data();
- main_hook(p);
-
- // FIXIT-L remove this onload when DAQng can push multiple packets
- if ( p->flow )
- DetectionEngine::onload(p->flow);
- }
-
- Active* act = p->active;
- // process flow verdicts here
- if ( act->packet_retry_requested() )
- {
- return DAQ_VERDICT_RETRY;
- }
- else if ( act->session_was_blocked() )
- {
- if ( !act->can_block() )
- return DAQ_VERDICT_PASS;
-
- if ( act->get_tunnel_bypass() )
- {
- aux_counts.internal_blacklist++;
- return DAQ_VERDICT_PASS;
- }
-
- if ( SnortConfig::inline_mode() or act->packet_force_dropped() )
- return DAQ_VERDICT_BLACKLIST;
- else
- return DAQ_VERDICT_IGNORE;
- }
-
- return DAQ_VERDICT_PASS;
-}
-
-// process (wire-only) packet verdicts here
-static DAQ_Verdict update_verdict(Packet* p, DAQ_Verdict verdict, int& inject)
-{
- if ( p->active->packet_was_dropped() and p->active->can_block() )
- {
- if ( verdict == DAQ_VERDICT_PASS )
- verdict = DAQ_VERDICT_BLOCK;
- }
- else if ( verdict == DAQ_VERDICT_RETRY )
- {
- return verdict;
- }
- else if ( p->packet_flags & PKT_RESIZED )
- {
- // we never increase, only trim, but daq doesn't support resizing wire packet
- PacketManager::encode_update(p);
-
- if ( !SFDAQ::inject(p->pkth, 0, p->pkt, p->pkth->pktlen) )
- {
- inject = 1;
- verdict = DAQ_VERDICT_BLOCK;
- }
- }
- else if ( p->packet_flags & PKT_MODIFIED )
- {
- // this packet was normalized and/or has replacements
- PacketManager::encode_update(p);
- verdict = DAQ_VERDICT_REPLACE;
- }
- else if ( (p->packet_flags & PKT_IGNORE) ||
- (p->flow && p->flow->get_ignore_direction( ) == SSN_DIR_BOTH) )
- {
- if ( !p->active->get_tunnel_bypass() )
- {
- verdict = DAQ_VERDICT_WHITELIST;
- }
- else
- {
- verdict = DAQ_VERDICT_PASS;
- aux_counts.internal_whitelist++;
- }
- }
- else if ( p->ptrs.decode_flags & DECODE_PKT_TRUST )
- {
- if (p->flow)
- p->flow->set_ignore_direction(SSN_DIR_BOTH);
- verdict = DAQ_VERDICT_WHITELIST;
- }
- else
- {
- verdict = DAQ_VERDICT_PASS;
- }
- return verdict;
-}
-
-DAQ_Verdict Snort::packet_callback(
- void*, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt)
-{
- set_default_policy();
- Profile profile(totalPerfStats);
-
- pc.total_from_daq++;
- packet_time_update(&pkthdr->ts);
-
- if ( SnortConfig::get_conf()->pkt_skip && pc.total_from_daq <= SnortConfig::get_conf()->pkt_skip )
- return DAQ_VERDICT_PASS;
-
- s_switcher->start();
- s_packet = s_switcher->get_context()->packet;
- s_packet->context->packet_number = pc.total_from_daq;
-
- DetectionEngine::reset();
-
- sfthreshold_reset();
- ActionManager::reset_queue(s_packet);
-
- DAQ_Verdict verdict = process_packet(s_packet, pkthdr, pkt);
- ActionManager::execute(s_packet);
-
- int inject = 0;
- verdict = update_verdict(s_packet, verdict, inject);
-
- if (PacketTracer::is_active())
- {
- PacketTracer::log("Policies: Network %u, Inspection %u, Detection %u\n",
- get_network_policy()->user_policy_id, get_inspection_policy()->user_policy_id,
- get_ips_policy()->user_policy_id);
- PacketTracer::log("Verdict: %s\n", SFDAQ::verdict_to_string(verdict));
-
- PacketTracer::dump(pkthdr);
- }
-
- HighAvailabilityManager::process_update(s_packet->flow, pkthdr);
-
- Stream::timeout_flows(pkthdr->ts.tv_sec);
- HighAvailabilityManager::process_receive();
-
- s_packet->pkth = nullptr; // no longer avail upon sig segv
-
- if ( SnortConfig::get_conf()->pkt_cnt && pc.total_from_daq >= SnortConfig::get_conf()->pkt_cnt )
- SFDAQ::break_loop(-1);
-
- // Check for resume(n)
- else if ((s_pause.pause_cnt && pc.total_from_daq >= s_pause.pause_cnt)
-#ifdef REG_TEST // pause-after-n
- || ( SnortConfig::get_conf()->pkt_pause_cnt && !s_pause.was_paused &&
- pc.total_from_daq >= SnortConfig::get_conf()->pkt_pause_cnt )
-#endif
- )
- {
- SFDAQ::break_loop(0);
- s_pause.was_paused = s_pause.pause = true;
- }
-
- s_switcher->stop();
-
- return verdict;
-}
-
namespace snort
{
class Flow;
+class SFDAQInstance;
struct Packet;
struct SnortConfig;
-typedef bool (* MainHook_f)(Packet*);
-
-class TestPause
-{
-public:
- bool get_pause() { return pause; }
- void clear_pause() { pause = false; }
- void set_pause_cnt(int cnt);
-
-public:
- bool pause = false;
- bool was_paused = false;
- uint64_t pause_cnt = 0;
-};
-
class Snort
{
public:
static bool is_reloading();
static bool has_dropped_privileges();
- static bool thread_init_privileged(const char* intf);
- static void thread_init_unprivileged();
- static void thread_reinit(SnortConfig*);
- static void thread_term();
-
- static void thread_idle();
- static void thread_rotate();
-
- static void capture_packet();
-
- static DAQ_Verdict process_packet(
- Packet*, const DAQ_PktHdr_t*, const uint8_t* pkt, bool is_frag=false);
-
- static DAQ_Verdict packet_callback(void*, const DAQ_PktHdr_t*, const uint8_t*);
-
- static bool inspect(Packet*);
-
- static void set_main_hook(MainHook_f);
- static ContextSwitcher* get_switcher();
-
- SO_PUBLIC static Packet* get_packet();
- static TestPause& get_test_pause();
-
private:
static void init(int, char**);
static void term();
#include "utils/util.h"
#include "utils/util_cstring.h"
-#include "snort.h"
+#include "analyzer.h"
#include "thread_config.h"
using namespace snort;
return false;
}
- if (get_conf()->daq_config->mru_size != daq_config->mru_size)
+ if (get_conf()->daq_config->get_mru_size() != daq_config->get_mru_size())
{
ReloadError("Snort Reload: Changing the packet snaplen "
"configuration requires a restart.\n");
output = val;
output_flags |= OUTPUT_FLAG__ALERTS;
- Snort::set_main_hook(DetectionEngine::inspect);
+ Analyzer::set_main_hook(DetectionEngine::inspect);
}
void SnortConfig::set_log_mode(const char* val)
{
if (strcasecmp(val, LOG_NONE) == 0)
{
- Snort::set_main_hook(snort_ignore);
+ Analyzer::set_main_hook(snort_ignore);
EventManager::enable_logs(false);
}
else
if ( !strcmp(val, LOG_DUMP) )
val = LOG_CODECS;
output = val;
- Snort::set_main_hook(snort_log);
+ Analyzer::set_main_hook(snort_log);
}
}
{ "--daq", Parameter::PT_STRING, nullptr, nullptr,
"<type> select packet acquisition module (default is pcap)" },
+ { "--daq-batch-size", Parameter::PT_INT, "1:", "64",
+ "<size> set the DAQ receive batch size", },
+
{ "--daq-dir", Parameter::PT_STRING, nullptr, nullptr,
"<dir> tell snort where to find desired DAQ" },
{ "--daq-list", Parameter::PT_IMPLIED, nullptr, nullptr,
"list packet acquisition modules available in optional dir, default is static modules only" },
+ { "--daq-mode", Parameter::PT_ENUM, "passive | inline | read-file", nullptr,
+ "<mode> select DAQ module operating mode (overrides automatic selection)" },
+
{ "--daq-var", Parameter::PT_STRING, nullptr, nullptr,
"<name=value> specify extra DAQ configuration variable" },
{ return GLOBAL; }
private:
- int instance_id;
+ SFDAQModuleConfig *module_config;
};
bool SnortModule::begin(const char* fqn, int, SnortConfig*)
{
if (!strcmp(fqn, "snort"))
- instance_id = -1;
+ module_config = nullptr;
return true;
}
sc->run_flags |= RUN_FLAG__STATIC_HASH;
else if ( v.is("-i") )
- {
- instance_id++;
- if (instance_id > 0)
- sc->daq_config->set_input_spec(v.get_string(), instance_id);
- else
- sc->daq_config->set_input_spec(v.get_string());
- }
+ sc->daq_config->add_input(v.get_string());
#ifdef SHELL
else if ( v.is("-j") )
sc->set_create_pid_file(true);
else if ( v.is("--daq") )
- sc->daq_config->set_module_name(v.get_string());
+ module_config = sc->daq_config->add_module_config(v.get_string());
+
+ else if ( v.is("--daq-batch-size") )
+ sc->daq_config->set_batch_size(v.get_long());
else if ( v.is("--daq-dir") )
{
while ( getline(ss, path, ':') )
sc->daq_config->add_module_dir(path.c_str());
}
+ else if ( v.is("--daq-mode") )
+ {
+ if (!module_config)
+ return false;
+ switch ( v.get_long() )
+ {
+ case 0:
+ module_config->mode = SFDAQModuleConfig::SFDAQ_MODE_PASSIVE;
+ break;
+ case 1:
+ module_config->mode = SFDAQModuleConfig::SFDAQ_MODE_INLINE;
+ break;
+ case 2:
+ module_config->mode = SFDAQModuleConfig::SFDAQ_MODE_READ_FILE;
+ break;
+ }
+ }
else if ( v.is("--daq-list") )
list_daqs(sc);
else if ( v.is("--daq-var") )
{
- if (instance_id < 0)
- sc->daq_config->set_variable(v.get_string());
- else
- sc->daq_config->set_variable(v.get_string(), instance_id);
+ if (!module_config)
+ return false;
+ module_config->set_variable(v.get_string());
}
else if ( v.is("--dirty-pig") )
sc->set_dirty_pig(true);
#include "target_based/sftarget_reader.h"
+#include "analyzer.h"
#include "snort.h"
#include "snort_config.h"
SFAT_Free(old_attribs);
}
-void Swapper::apply()
+void Swapper::apply(Analyzer& analyzer)
{
if ( new_conf )
{
snort::SnortConfig::set_conf(new_conf);
// FIXIT-M Determine whether we really want to do this before or after the set_conf
if (reload)
- snort::Snort::thread_reinit(new_conf);
+ analyzer.reinit(new_conf);
}
if ( new_attribs )
struct SnortConfig;
}
+class Analyzer;
struct tTargetBasedConfig;
class Swapper
Swapper(tTargetBasedConfig*, tTargetBasedConfig*);
~Swapper();
- void apply();
+ void apply(Analyzer&);
static bool get_reload_in_progress() { return reload_in_progress; }
static void set_reload_in_progress(bool rip) { reload_in_progress = rip; }
void ActionManager::thread_term(SnortConfig*)
{
- // Call tterm for every IPS action plugin ever configured during the lifetime of this thread
- for ( auto& p : *s_tl_actors )
+ if (s_tl_actors)
{
- if ( p.api->tterm )
- p.api->tterm();
+ // Call tterm for every IPS action plugin ever configured during the lifetime of this thread
+ for ( auto& p : *s_tl_actors )
+ {
+ if ( p.api->tterm )
+ p.api->tterm();
+ }
+ delete s_tl_actors;
+ s_tl_actors = nullptr;
}
- delete s_tl_actors;
- s_tl_actors = nullptr;
}
void ActionManager::execute(Packet* p)
return;
if ( !bpf.bf_insns || bpf_filter(bpf.bf_insns, p->pkt,
- p->pkth->caplen, p->pkth->pktlen) )
+ p->pktlen, p->pkth->pktlen) )
{
write_packet(p);
cap_count_stats.matched++;
{
struct pcap_pkthdr pcaphdr;
pcaphdr.ts = p->pkth->ts;
- pcaphdr.caplen = p->pkth->caplen;
+ pcaphdr.caplen = p->pktlen;
pcaphdr.len = p->pkth->pktlen;
pcap_dump((unsigned char*)dumper, &pcaphdr, p->pkt);
pcap_dump_flush(dumper);
static Packet p(false);
static DAQ_PktHdr_t h;
- p.pkt = nullptr;
p.pkth = &h;
- h.caplen = 0;
+ p.pkt = nullptr;
+ p.pktlen = 0;
h.pktlen = 0;
return &p;
Packet p(false);
DAQ_PktHdr_t daq_hdr;
- p.pkt = cooked;
p.pkth = &daq_hdr;
+ p.pkt = cooked;
+ p.pktlen = sizeof(cooked);
- daq_hdr.caplen = sizeof(cooked);
daq_hdr.pktlen = sizeof(cooked);
CaptureModule mod;
p_match.pkt = match;
p_non_match.pkt = non_match;
- daq_hdr.caplen = sizeof(match);
+ p_match.pktlen = sizeof(match);
+ p_non_match.pktlen = sizeof(match);
+
daq_hdr.pktlen = sizeof(match);
CaptureModule mod;
#include "detection/ips_context.h"
#include "log/log.h"
#include "log/messages.h"
-#include "packet_io/sfdaq.h"
+#include "packet_io/sfdaq_instance.h"
#include "protocols/eth.h"
#include "protocols/icmp4.h"
#include "protocols/ip.h"
s_pkt_trace->reset();
}
-void PacketTracer::dump(const DAQ_PktHdr_t* pkt_hdr)
+void PacketTracer::dump(Packet* p)
{
if (is_paused())
return;
if (s_pkt_trace->daq_activated)
- s_pkt_trace->dump_to_daq(pkt_hdr);
+ s_pkt_trace->dump_to_daq(p);
if (s_pkt_trace->user_enabled or s_pkt_trace->shell_enabled)
LogMessage(s_pkt_trace->log_fh, "%s\n", s_pkt_trace->buffer);
PacketTracer::log("Packet %" PRIu64 ": TCP %s, %s, seq %u, ack %u, dsize %u%s\n",
p.context->packet_number, tcpFlags, timestamp,
p.ptrs.tcph->seq(), p.ptrs.tcph->ack(), p.dsize,
- (p.pkth->flags & DAQ_PKT_FLAG_RETRY_PACKET) ? ", retry pkt" : "");
+ p.is_retry() ? ", retry pkt" : "");
else
PacketTracer::log("Packet %" PRIu64 ": TCP %s, %s, seq %u, dsize %u%s\n",
p.context->packet_number, tcpFlags, timestamp, p.ptrs.tcph->seq(),
p.dsize,
- (p.pkth->flags & DAQ_PKT_FLAG_RETRY_PACKET) ? ", retry pkt" : "");
+ p.is_retry() ? ", retry pkt" : "");
break;
}
}
}
-void PacketTracer::dump_to_daq(const DAQ_PktHdr_t* pkt_hdr)
+void PacketTracer::dump_to_daq(Packet* p)
{
- SFDAQ::get_local_instance()->modify_flow_pkt_trace(pkt_hdr, reason,
+ assert(p);
+ p->daq_instance->modify_flow_pkt_trace(p->daq_msg, reason,
(uint8_t *)buffer, buff_len + 1);
}
static uint8_t get_dump_reason()
{ return ((TestPacketTracer*)s_pkt_trace)->dump_reason; }
- void dump_to_daq(const DAQ_PktHdr_t*) override
+ void dump_to_daq(Packet*) override
{ dump_reason = reason; }
static std::vector<bool> get_mutes()
#include <cstdarg>
#include <cstdio>
#include <cstring>
-#include <daq_common.h>
#include <vector>
#include "main/snort_types.h"
static void thread_term();
static void dump(char* output_buff, unsigned int len);
- static void dump(const DAQ_PktHdr_t*);
+ static void dump(Packet*);
static void configure(bool status, const std::string& file_name);
static void set_constraints(const PTSessionConstraints* constraints);
const char *get_debug_session() { return debug_session; }
virtual void open_file();
- virtual void dump_to_daq(const DAQ_PktHdr_t*);
+ virtual void dump_to_daq(Packet*);
virtual void reset();
};
const SfIp* src_addr = p->ptrs.ip_api.get_src();
const SfIp* dst_addr = p->ptrs.ip_api.get_dst();
- int len = p->pkth->caplen;
+ int len = p->pktlen;
if (p->ptrs.tcph)
type = SFS_TYPE_TCP;
{
if (!p->is_rebuilt())
{
- auto len = p->pkth->caplen;
+ auto len = p->pktlen;
if (p->ptrs.tcph)
update_transport_flows(p->ptrs.sp, p->ptrs.dp, tcp, len);
TEST_CASE("no protocol", "[FlowTracker]")
{
Packet p;
- uint32_t* len_ptr = &const_cast<DAQ_PktHdr_t*>(p.pkth)->caplen;
+ uint32_t* len_ptr = &p.pktlen;
PerfConfig config;
config.format = PerfFormat::MOCK;
{
Packet p;
icmp::ICMPHdr icmp;
- uint32_t* len_ptr = &const_cast<DAQ_PktHdr_t*>(p.pkth)->caplen;
+ uint32_t* len_ptr = &p.pktlen;
uint8_t* type_ptr = (uint8_t*) &icmp.type;
PerfConfig config;
{
Packet p;
tcp::TCPHdr tcp;
- uint32_t* len_ptr = &const_cast<DAQ_PktHdr_t*>(p.pkth)->caplen;
+ uint32_t* len_ptr = &p.pktlen;
PerfConfig config;
config.format = PerfFormat::MOCK;
{
Packet p;
udp::UDPHdr udp;
- uint32_t* len_ptr = &const_cast<DAQ_PktHdr_t*>(p.pkth)->caplen;
+ uint32_t* len_ptr = &p.pktlen;
PerfConfig config;
config.format = PerfFormat::MOCK;
set ( PACKET_IO_INCLUDES
active.h
sfdaq.h
+ sfdaq_instance.h
)
if (ENABLE_UNIT_TESTS)
)
endif (ENABLE_UNIT_TESTS)
+if (ENABLE_STATIC_DAQ)
+ foreach (STATIC_MODULE_NAME IN LISTS DAQ_STATIC_MODULES)
+ string(APPEND DAQ_STATIC_MODULE_EXTERNS "extern const DAQ_ModuleAPI_t ${STATIC_MODULE_NAME}_daq_module_data;\n")
+ string(APPEND DAQ_STATIC_MODULE_DATA_ARRAY " &${STATIC_MODULE_NAME}_daq_module_data,\n")
+ endforeach ()
+ configure_file (
+ "${CMAKE_CURRENT_SOURCE_DIR}/sfdaq_static_modules.h.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/sfdaq_static_modules.h"
+ )
+ set_source_files_properties(sfdaq.cc PROPERTIES COMPILE_DEFINITIONS ENABLE_STATIC_DAQ)
+ include_directories(${CMAKE_CURRENT_BINARY_DIR})
+ set(STATIC_DAQ_MODULES_HEADER "sfdaq_static_modules.h")
+endif ()
+
add_library (packet_io OBJECT
active.cc
active.h
sfdaq.h
sfdaq_config.cc
sfdaq_config.h
+ sfdaq_instance.cc
+ sfdaq_instance.h
sfdaq_module.cc
sfdaq_module.h
trough.cc
trough.h
+ ${STATIC_DAQ_MODULES_HEADER}
${TEST_FILES}
)
THREAD_LOCAL Active::Counts snort::active_counts;
typedef int (* send_t) (
- const DAQ_PktHdr_t* h, int rev, const uint8_t* buf, uint32_t len);
+ DAQ_Msg_h msg, int rev, const uint8_t* buf, uint32_t len);
static THREAD_LOCAL eth_t* s_link = nullptr;
static THREAD_LOCAL ip_t* s_ipnet = nullptr;
// helpers
int Active::send_eth(
- const DAQ_PktHdr_t*, int, const uint8_t* buf, uint32_t len)
+ DAQ_Msg_h, int, const uint8_t* buf, uint32_t len)
{
ssize_t sent = eth_send(s_link, buf, len);
active_counts.injects++;
}
int Active::send_ip(
- const DAQ_PktHdr_t*, int, const uint8_t* buf, uint32_t len)
+ DAQ_Msg_h, int, const uint8_t* buf, uint32_t len)
{
ssize_t sent = ip_send(s_ipnet, buf, len);
active_counts.injects++;
if ( !rej )
return;
- s_send(p->pkth, !(ef & ENC_FLAG_FWD), rej, len);
+ s_send(p->daq_msg, !(ef & ENC_FLAG_FWD), rej, len);
}
}
if ( !rej )
return;
- s_send(p->pkth, 1, rej, len);
+ s_send(p->daq_msg, 1, rej, len);
}
bool Active::send_data(
if ( seg )
{
- s_send(p->pkth, !(tmp_flags & ENC_FLAG_FWD), seg, plen);
+ s_send(p->daq_msg, !(tmp_flags & ENC_FLAG_FWD), seg, plen);
active_counts.injects++;
}
}
if ( !seg )
return false;
- s_send(p->pkth, !(flags & ENC_FLAG_FWD), seg, plen);
+ s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen);
active_counts.injects++;
buf += toSend;
if ( !seg )
return false;
- s_send(p->pkth, !(flags & ENC_FLAG_FWD), seg, plen);
+ s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen);
active_counts.injects++;
if (flags & ENC_FLAG_RST_CLNT)
if ( seg )
{
- s_send(p->pkth, !(flags & ENC_FLAG_FWD), seg, plen);
+ s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen);
active_counts.injects++;
}
}
if ( !seg )
return;
- s_send(p->pkth, !(flags & ENC_FLAG_FWD), seg, plen);
+ s_send(p->daq_msg, !(flags & ENC_FLAG_FWD), seg, plen);
}
//--------------------------------------------------------------------
{
bool retry_queued = false;
- if ( ( active_action == ACT_PASS ) and SFDAQ::can_retry() )
+ if ( !p->is_rebuilt() && (active_action == ACT_PASS) )
{
if ( SFDAQ::forwarding_packet(p->pkth) )
{
- if(p->packet_flags & PKT_RETRANSMIT)
+ if (p->packet_flags & PKT_RETRANSMIT)
active_action = ACT_DROP; // Don't add retransmits to retry queue.
else
active_action = ACT_RETRY;
private:
static bool open(const char*);
static void close();
- static int send_eth(const DAQ_PktHdr_t*, int, const uint8_t* buf, uint32_t len);
- static int send_ip(const DAQ_PktHdr_t*, int, const uint8_t* buf, uint32_t len);
+ static int send_eth(DAQ_Msg_h, int, const uint8_t* buf, uint32_t len);
+ static int send_ip(DAQ_Msg_h, int, const uint8_t* buf, uint32_t len);
void update_status(const Packet*, bool force = false);
void daq_update_status(const Packet*);
#include "sfdaq.h"
-extern "C" {
#include <daq.h>
-#include <sfbpf_dlt.h>
-}
-
-#include <cassert>
-#include <mutex>
#include "log/messages.h"
#include "main/snort_config.h"
-#include "protocols/packet.h"
-#include "protocols/vlan.h"
#include "sfdaq_config.h"
+#include "sfdaq_instance.h"
+#ifdef ENABLE_STATIC_DAQ
+#include "sfdaq_static_modules.h"
+#endif
using namespace snort;
using namespace std;
#ifdef DEFAULT_DAQ
-#define XSTR(s) STR(s)
-#define STR(s) #s
-#define DAQ_DEFAULT XSTR(DEFAULT_DAQ)
+#define DAQ_DEFAULT STRINGIFY_MX(DEFAULT_DAQ)
#else
#define DAQ_DEFAULT "pcap"
#endif
-static const int DEFAULT_PKT_SNAPLEN = 1518;
-
// common for all daq threads / instances
-static const DAQ_Module_t* daq_mod = nullptr;
-static DAQ_Mode daq_mode = DAQ_MODE_PASSIVE;
-static uint32_t snap = DEFAULT_PKT_SNAPLEN;
+static DAQ_Config_h daqcfg = nullptr;
+static DAQ_Mode default_daq_mode = DAQ_MODE_PASSIVE;
+static string daq_module_names;
static bool loaded = false;
-static std::mutex bpf_gate;
// specific for each thread / instance
static THREAD_LOCAL SFDAQInstance *local_instance = nullptr;
-/*
- * SFDAQ
- */
-
-void SFDAQ::load(const SnortConfig* sc)
+void SFDAQ::load(const SFDAQConfig* cfg)
{
- const char** dirs = new const char*[sc->daq_config->module_dirs.size() + 1];
+ const char** dirs = new const char*[cfg->module_dirs.size() + 1];
int i = 0;
- for (string& module_dir : sc->daq_config->module_dirs)
+ for (const string& module_dir : cfg->module_dirs)
dirs[i++] = module_dir.c_str();
dirs[i] = nullptr;
- int err = daq_load_modules(dirs);
-
+#ifdef ENABLE_STATIC_DAQ
+ daq_load_static_modules(static_daq_modules);
+#endif
+ int err = daq_load_dynamic_modules(dirs);
if (err)
- FatalError("Can't load DAQ modules = %d\n", err);
+ FatalError("Could not load dynamic DAQ modules! (%d)\n", err);
delete[] dirs;
void SFDAQ::print_types(ostream& ostr)
{
- DAQ_Module_Info_t* list = nullptr;
- int i, nMods = daq_get_module_list(&list);
+ DAQ_Module_h module = daq_modules_first();
- if (nMods)
+ if (module)
ostr << "Available DAQ modules:" << endl;
else
ostr << "No available DAQ modules (try adding directories with --daq-dir)." << endl;
- for (i = 0; i < nMods; i++)
+ while (module)
{
- ostr << list[i].name << "(v" << list[i].version << "):";
+ ostr << daq_module_get_name(module) << "(v" << daq_module_get_version(module) << "):";
- if (list[i].type & DAQ_TYPE_FILE_CAPABLE)
+ uint32_t type = daq_module_get_type(module);
+
+ if (type & DAQ_TYPE_FILE_CAPABLE)
ostr << " readback";
- if (list[i].type & DAQ_TYPE_INTF_CAPABLE)
+ if (type & DAQ_TYPE_INTF_CAPABLE)
ostr << " live";
- if (list[i].type & DAQ_TYPE_INLINE_CAPABLE)
+ if (type & DAQ_TYPE_INLINE_CAPABLE)
ostr << " inline";
- if (list[i].type & DAQ_TYPE_MULTI_INSTANCE)
+ if (type & DAQ_TYPE_MULTI_INSTANCE)
ostr << " multi";
- if (!(list[i].type & DAQ_TYPE_NO_UNPRIV))
+ if (!(type & DAQ_TYPE_NO_UNPRIV))
ostr << " unpriv";
+ if (type & DAQ_TYPE_WRAPPER)
+ ostr << " wrapper";
+
ostr << endl;
+
+ const DAQ_VariableDesc_t *var_desc_table;
+ int num_var_descs = daq_module_get_variable_descs(module, &var_desc_table);
+ if (num_var_descs > 0)
+ {
+ ostr << " Variables:" << endl;
+ for (int i = 0; i < num_var_descs; i++)
+ {
+ ostr << " " << var_desc_table[i].name << " ";
+ if (var_desc_table[i].flags & DAQ_VAR_DESC_REQUIRES_ARGUMENT)
+ ostr << "<arg> ";
+ else if (!(var_desc_table[i].flags & DAQ_VAR_DESC_FORBIDS_ARGUMENT))
+ ostr << "[arg] ";
+ ostr << "- " << var_desc_table[i].description << endl;
+ }
+ }
+
+ module = daq_modules_next();
}
- daq_free_module_list(list, nMods);
}
-static int DAQ_ValidateModule(DAQ_Mode mode)
+/*
+static int DAQ_ValidateModule(DAQ_Module_h module, DAQ_Mode mode)
{
- uint32_t have = daq_get_type(daq_mod);
+ uint32_t have = daq_module_get_type(module);
uint32_t need = 0;
if (mode == DAQ_MODE_READ_FILE)
return ((have & need) != 0);
}
+*/
-void SFDAQ::init(const SnortConfig* sc)
+static bool AddDaqModuleConfig(const SFDAQModuleConfig *dmc)
{
- if (!loaded)
- load(sc);
+ const char* module_name = dmc->name.c_str();
+ DAQ_Module_h module = daq_find_module(module_name);
+ if (!module)
+ {
+ ErrorMessage("Could not find requested DAQ module: %s\n", module_name);
+ return false;
+ }
- const char* type = DAQ_DEFAULT;
+ DAQ_ModuleConfig_h modcfg;
+ int rval;
+ if ((rval = daq_module_config_new(&modcfg, module)) != DAQ_SUCCESS)
+ {
+ ErrorMessage("Error allocating a new DAQ module configuration object! (%d)\n", rval);
+ return false;
+ }
- if (!sc->daq_config->module_name.empty())
- type = sc->daq_config->module_name.c_str();
+ DAQ_Mode mode;
+ if (dmc->mode == SFDAQModuleConfig::SFDAQ_MODE_PASSIVE)
+ mode = DAQ_MODE_PASSIVE;
+ else if (dmc->mode == SFDAQModuleConfig::SFDAQ_MODE_INLINE)
+ mode = DAQ_MODE_INLINE;
+ else if (dmc->mode == SFDAQModuleConfig::SFDAQ_MODE_READ_FILE)
+ mode = DAQ_MODE_READ_FILE;
+ else
+ mode = default_daq_mode;
+ daq_module_config_set_mode(modcfg, mode);
- daq_mod = daq_find_module(type);
+ for (auto& kvp : dmc->variables)
+ {
+ const char* key = kvp.first.c_str();
+ const char* value = kvp.second.length() ? kvp.second.c_str() : nullptr;
+ if (daq_module_config_set_variable(modcfg, key, value) != DAQ_SUCCESS)
+ {
+ ErrorMessage("Error setting DAQ configuration variable with key '%s' and value '%s'! (%d)",
+ key, value, rval);
+ daq_module_config_destroy(modcfg);
+ return false;
+ }
+ }
- if (!daq_mod)
- FatalError("Can't find %s DAQ\n", type);
+ if ((rval = daq_config_push_module_config(daqcfg, modcfg)) != DAQ_SUCCESS)
+ {
+ ErrorMessage("Error pushing DAQ module configuration for '%s' onto the DAQ config! (%d)\n",
+ daq_module_get_name(module), rval);
+ daq_module_config_destroy(modcfg);
+ return false;
+ }
- snap = (sc->daq_config->mru_size > 0) ? sc->daq_config->mru_size : DEFAULT_PKT_SNAPLEN;
+ if (!daq_module_names.empty())
+ daq_module_names.insert(0, 1, ':');
+ daq_module_names.insert(0, module_name);
+
+ return true;
+}
+
+bool SFDAQ::init(const SFDAQConfig* cfg)
+{
+ if (!loaded)
+ load(cfg);
+
+ int rval;
if (SnortConfig::adaptor_inline_mode())
- daq_mode = DAQ_MODE_INLINE;
+ default_daq_mode = DAQ_MODE_INLINE;
else if (SnortConfig::read_mode())
- daq_mode = DAQ_MODE_READ_FILE;
+ default_daq_mode = DAQ_MODE_READ_FILE;
else
- daq_mode = DAQ_MODE_PASSIVE;
+ default_daq_mode = DAQ_MODE_PASSIVE;
+
+ if ((rval = daq_config_new(&daqcfg)) != DAQ_SUCCESS)
+ {
+ ErrorMessage("Error allocating a new DAQ configuration object! (%d)\n", rval);
+ return false;
+ }
+ daq_config_set_msg_pool_size(daqcfg, cfg->get_batch_size() * 4);
+ daq_config_set_snaplen(daqcfg, cfg->get_mru_size());
+ daq_config_set_timeout(daqcfg, cfg->timeout);
+
+ /* If no modules were specified, try to automatically configure with the default. */
+ if (cfg->module_configs.empty())
+ {
+ SFDAQModuleConfig dmc;
+ dmc.name = DAQ_DEFAULT;
+ if (!AddDaqModuleConfig(&dmc))
+ {
+ daq_config_destroy(daqcfg);
+ daqcfg = nullptr;
+ return false;
+ }
+ }
+ /* Otherwise, if the module stack doesn't have a terminal module at the bottom, default
+ to a hardcoded base of the PCAP DAQ module in read-file mode. This is a convenience
+ provided to emulate the previous dump/regtest DAQ module behavior. */
+ else
+ {
+ const char* module_name = cfg->module_configs[0]->name.c_str();
+ DAQ_Module_h module = daq_find_module(module_name);
+ if (module && (daq_module_get_type(module) & DAQ_TYPE_WRAPPER))
+ {
+ SFDAQModuleConfig dmc;
+ dmc.name = "pcap";
+ dmc.mode = SFDAQModuleConfig::SFDAQ_MODE_READ_FILE;
+ if (!AddDaqModuleConfig(&dmc))
+ {
+ daq_config_destroy(daqcfg);
+ daqcfg = nullptr;
+ return false;
+ }
+ }
+ }
+
+ for (SFDAQModuleConfig* dmc : cfg->module_configs)
+ {
+ if (!AddDaqModuleConfig(dmc))
+ {
+ daq_config_destroy(daqcfg);
+ daqcfg = nullptr;
+ return false;
+ }
+ }
+
+/*
if (!DAQ_ValidateModule(daq_mode))
FatalError("%s DAQ does not support %s.\n", type, daq_mode_string(daq_mode));
- LogMessage("%s DAQ configured to %s.\n", type, daq_mode_string(daq_mode));
+*/
+ LogMessage("%s DAQ configured to %s.\n", daq_module_names.c_str(), daq_mode_string(default_daq_mode));
+
+ return true;
}
void SFDAQ::term()
{
+ if (daqcfg)
+ {
+ daq_config_destroy(daqcfg);
+ daqcfg = nullptr;
+ }
+#ifndef REG_TEST
if (loaded)
unload();
- daq_mod = nullptr;
+#endif
}
const char* SFDAQ::verdict_to_string(DAQ_Verdict verdict)
bool SFDAQ::forwarding_packet(const DAQ_PktHdr_t* h)
{
// DAQ mode is inline and the packet will be forwarded?
- return (daq_mode == DAQ_MODE_INLINE && !(h->flags & DAQ_PKT_FLAG_NOT_FORWARDING));
-}
-
-const char* SFDAQ::get_type()
-{
- return daq_mod ? daq_get_name(daq_mod) : "error";
+ return (default_daq_mode == DAQ_MODE_INLINE && !(h->flags & DAQ_PKT_FLAG_NOT_FORWARDING));
}
-// Snort has its own snap applied to packets it acquires via the DAQ. This
-// should not be confused with the snap that was used to capture a pcap which
-// may be different.
-uint32_t SFDAQ::get_snap_len()
+bool SFDAQ::can_run_unprivileged()
{
- return snap;
+ // Iterate over the configured modules to see if any of them don't support unprivileged operation
+ DAQ_ModuleConfig_h modcfg = daq_config_top_module_config(daqcfg);
+ while (modcfg)
+ {
+ DAQ_Module_h module = daq_module_config_get_module(modcfg);
+ if (daq_module_get_type(module) & DAQ_TYPE_NO_UNPRIV)
+ return false;
+ modcfg = daq_config_next_module_config(daqcfg);
+ }
+ return true;
}
-bool SFDAQ::unprivileged()
+bool SFDAQ::init_instance(SFDAQInstance* instance, const string& bpf_string)
{
- return !(daq_get_type(daq_mod) & DAQ_TYPE_NO_UNPRIV);
+ return instance->init(daqcfg, bpf_string);
}
/*
return local_instance;
}
-const char* SFDAQ::get_interface_spec()
+const char* SFDAQ::get_input_spec()
{
- assert(local_instance->get_interface_spec());
- return local_instance->get_interface_spec();
+ return local_instance->get_input_spec();
}
int SFDAQ::get_base_protocol()
return local_instance && local_instance->can_replace();
}
-bool SFDAQ::can_retry()
-{
- return local_instance && local_instance->can_retry();
-}
-
bool SFDAQ::get_tunnel_bypass(uint8_t proto)
{
return local_instance && local_instance->get_tunnel_bypass(proto);
}
-int SFDAQ::inject(const DAQ_PktHdr_t* hdr, int rev, const uint8_t* buf, uint32_t len)
+int SFDAQ::inject(DAQ_Msg_h msg, int rev, const uint8_t* buf, uint32_t len)
{
- return local_instance->inject(hdr, rev, buf, len);
-}
-
-bool SFDAQ::break_loop(int error)
-{
- return local_instance->break_loop(error);
+ return local_instance->inject(msg, rev, buf, len);
}
const DAQ_Stats_t* SFDAQ::get_stats()
return local_instance->get_stats();
}
-const char* SFDAQ::get_input_spec(const SnortConfig* sc, unsigned instance_id)
+const char* SFDAQ::get_input_spec(const SFDAQConfig* cfg, unsigned instance_id)
{
- auto it = sc->daq_config->instances.find(instance_id);
- if (it != sc->daq_config->instances.end() && !it->second->input_spec.empty())
- return it->second->input_spec.c_str();
+ if (cfg->inputs.empty())
+ return nullptr;
- if (!sc->daq_config->input_spec.empty())
- return sc->daq_config->input_spec.c_str();
+ if (instance_id > 0 && instance_id < cfg->inputs.size())
+ return cfg->inputs[instance_id].c_str();
- return nullptr;
+ return cfg->inputs[0].c_str();
}
const char* SFDAQ::default_type()
return DAQ_DEFAULT;
}
-/*
- * SFDAQInstance
- */
-
-SFDAQInstance::SFDAQInstance(const char* intf)
-{
- if (intf)
- interface_spec = intf;
- daq_hand = nullptr;
- daq_dlt = -1;
- s_error = DAQ_SUCCESS;
- memset(&daq_stats, 0, sizeof(daq_stats));
- daq_tunnel_mask = 0;
-}
-
-SFDAQInstance::~SFDAQInstance()
-{
- if (daq_hand)
- daq_shutdown(daq_mod, daq_hand);
-}
-
-static bool DAQ_ValidateInstance(void* daq_hand)
-{
- uint32_t caps = daq_get_capabilities(daq_mod, daq_hand);
-
- if (!SnortConfig::adaptor_inline_mode())
- return true;
-
- if (!(caps & DAQ_CAPA_BLOCK))
- ParseWarning(WARN_DAQ, "inline mode configured but DAQ can't block packets.\n");
-
- return true;
-}
-
-bool SFDAQInstance::configure(const SnortConfig* sc)
-{
- DAQ_Config_t cfg;
- const char* type = daq_get_name(daq_mod);
- char buf[256] = "";
- int err;
-
- memset(&cfg, 0, sizeof(cfg));
-
- cfg.name = const_cast<char*>(interface_spec.c_str());
- cfg.snaplen = snap;
- cfg.timeout = sc->daq_config->timeout;
- cfg.mode = daq_mode;
- cfg.extra = nullptr;
- cfg.flags = 0;
-
- for (auto& kvp : sc->daq_config->variables)
- {
- daq_config_set_value(&cfg, kvp.first.c_str(),
- kvp.second.length() ? kvp.second.c_str() : nullptr);
- }
-
- auto it = sc->daq_config->instances.find(get_instance_id());
- if (it != sc->daq_config->instances.end())
- {
- for (auto& kvp : it->second->variables)
- {
- daq_config_set_value(&cfg, kvp.first.c_str(),
- kvp.second.length() ? kvp.second.c_str() : nullptr);
- }
- }
-
- if (!SnortConfig::read_mode())
- {
- if (!(sc->run_flags & RUN_FLAG__NO_PROMISCUOUS))
- cfg.flags |= DAQ_CFG_PROMISC;
- }
-
- // FIXIT-M - This is sort of an abomination and would ideally be configurable ...
- if (!strcasecmp(type, "dump") or !strcasecmp(type, "regtest"))
- cfg.extra = reinterpret_cast<char*>(const_cast<DAQ_Module_t*>(daq_find_module("pcap")));
-
- err = daq_initialize(daq_mod, &cfg, &daq_hand, buf, sizeof(buf));
- if (err)
- {
- ErrorMessage("Can't initialize DAQ %s (%d) - %s\n", type, err, buf);
- return false;
- }
- daq_config_clear_values(&cfg);
-
- if (!DAQ_ValidateInstance(daq_hand))
- FatalError("DAQ configuration incompatible with intended operation.\n");
-
- set_filter(sc->bpf_filter.c_str());
-
- return true;
-}
-
-void SFDAQInstance::reload()
-{
- void* old_config = nullptr;
- void* new_config = nullptr;
- if (daq_mod && daq_hand)
- {
- if ( ( daq_hup_prep(daq_mod, daq_hand, &new_config) == DAQ_SUCCESS ) and
- ( daq_hup_apply(daq_mod, daq_hand, new_config, &old_config) == DAQ_SUCCESS ) )
- {
- daq_hup_post(daq_mod, daq_hand, old_config);
- }
- }
-}
-
-void SFDAQInstance::abort()
-{
- if (was_started())
- stop();
-
- //DAQ_Delete();
- //DAQ_Term(); FIXIT-L this must be called from main thread on abort
-}
-
-const char* SFDAQInstance::get_interface_spec()
-{
- return interface_spec.c_str();
-}
-
-// That distinction does not hold with datalink types. Snort must use whatever
-// datalink type the DAQ coughs up as its base protocol decoder. For pcaps,
-// the datalink type in the file must be used - which may not be known until
-// start. The value is cached here since it used for packet operations like
-// logging and is needed at shutdown. This avoids sequencing issues.
-int SFDAQInstance::get_base_protocol()
-{
- return daq_dlt;
-}
-
-bool SFDAQInstance::can_inject()
-{
- return (daq_get_capabilities(daq_mod, daq_hand) & DAQ_CAPA_INJECT) != 0;
-}
-
-bool SFDAQInstance::can_inject_raw()
-{
- return (daq_get_capabilities(daq_mod, daq_hand) & DAQ_CAPA_INJECT_RAW) != 0;
-}
-
-bool SFDAQInstance::can_replace()
-{
- return (daq_get_capabilities(daq_mod, daq_hand) & DAQ_CAPA_REPLACE) != 0;
-}
-
-bool SFDAQInstance::can_retry()
-{
- return (daq_get_capabilities(daq_mod, daq_hand) & DAQ_CAPA_RETRY) != 0;
-}
-
-bool SFDAQInstance::can_start_unprivileged()
-{
- return (daq_get_capabilities(daq_mod, daq_hand) & DAQ_CAPA_UNPRIV_START) != 0;
-}
-
-bool SFDAQInstance::can_whitelist()
-{
- return (daq_get_capabilities(daq_mod, daq_hand) & DAQ_CAPA_WHITELIST) != 0;
-}
-
-bool SFDAQInstance::set_filter(const char* bpf)
-{
- int err = 0;
-
- // The BPF can be compiled either during daq_set_filter() or daq_start(),
- // so protect the thread-unsafe BPF scanner/compiler in both places.
-
- if (bpf and *bpf)
- {
- std::lock_guard<std::mutex> lock(bpf_gate);
- err = daq_set_filter(daq_mod, daq_hand, bpf);
- }
-
- if (err)
- FatalError("Can't set DAQ BPF filter to '%s' (%s)\n",
- bpf, daq_get_error(daq_mod, daq_hand));
-
- return (err == DAQ_SUCCESS);
-}
-
-bool SFDAQInstance::start()
-{
- int err;
-
- // The BPF can be compiled either during daq_set_filter() or daq_start(),
- // so protect the thread-unsafe BPF scanner/compiler in both places.
- {
- std::lock_guard<std::mutex> lock(bpf_gate);
- err = daq_start(daq_mod, daq_hand);
- }
-
- if (err)
- ErrorMessage("Can't start DAQ (%d) - %s\n", err, daq_get_error(daq_mod, daq_hand));
- else
- daq_dlt = daq_get_datalink_type(daq_mod, daq_hand);
-
- get_tunnel_capabilities();
-
- return (err == DAQ_SUCCESS);
-}
-
-void SFDAQInstance::get_tunnel_capabilities()
-{
- daq_tunnel_mask = 0;
- if (daq_mod && daq_hand)
- {
- uint32_t caps = daq_get_capabilities(daq_mod, daq_hand);
-
- if (caps & DAQ_CAPA_DECODE_GTP)
- {
- daq_tunnel_mask |= TUNNEL_GTP;
- }
- if (caps & DAQ_CAPA_DECODE_TEREDO)
- {
- daq_tunnel_mask |= TUNNEL_TEREDO;
- }
- if (caps & DAQ_CAPA_DECODE_GRE)
- {
- daq_tunnel_mask |= TUNNEL_GRE;
- }
- if (caps & DAQ_CAPA_DECODE_4IN4)
- {
- daq_tunnel_mask |= TUNNEL_4IN4;
- }
- if (caps & DAQ_CAPA_DECODE_6IN4)
- {
- daq_tunnel_mask |= TUNNEL_6IN4;
- }
- if (caps & DAQ_CAPA_DECODE_4IN6)
- {
- daq_tunnel_mask |= TUNNEL_4IN6;
- }
- if (caps & DAQ_CAPA_DECODE_6IN6)
- {
- daq_tunnel_mask |= TUNNEL_6IN6;
- }
- if (caps & DAQ_CAPA_DECODE_MPLS)
- {
- daq_tunnel_mask |= TUNNEL_MPLS;
- }
- }
-}
-
-bool SFDAQInstance::get_tunnel_bypass(uint8_t proto)
-{
- return (daq_tunnel_mask & proto) != 0;
-}
-
-bool SFDAQInstance::was_started()
-{
- DAQ_State s;
-
- if (!daq_hand)
- return false;
-
- s = daq_check_status(daq_mod, daq_hand);
-
- return (DAQ_STATE_STARTED == s);
-}
-
-bool SFDAQInstance::stop()
-{
- int err = daq_stop(daq_mod, daq_hand);
-
- if (err)
- LogMessage("Can't stop DAQ (%d) - %s\n", err, daq_get_error(daq_mod, daq_hand));
-
- return (err == DAQ_SUCCESS);
-}
-
-static int metacallback(void *user, const DAQ_MetaHdr_t* hdr, const uint8_t* data)
-{
- DataBus::publish(DAQ_META_EVENT, user, hdr->type, data);
- return 0;
-}
-
-int SFDAQInstance::acquire(int max, DAQ_Analysis_Func_t callback)
-{
- int err = daq_acquire_with_meta(daq_mod, daq_hand, max, callback, metacallback, nullptr);
-
- if (err && err != DAQ_READFILE_EOF)
- LogMessage("Can't acquire (%d) - %s\n", err, daq_get_error(daq_mod, daq_hand));
-
- if (s_error != DAQ_SUCCESS)
- {
- err = s_error;
- s_error = DAQ_SUCCESS;
- }
- return err;
-}
-
-int SFDAQInstance::inject(const DAQ_PktHdr_t* h, int rev, const uint8_t* buf, uint32_t len)
-{
- int err = daq_inject(daq_mod, daq_hand, h, buf, len, rev);
-#ifdef DEBUG_MSGS
- if (err)
- LogMessage("Can't inject (%d) - %s\n", err, daq_get_error(daq_mod, daq_hand));
-#endif
- return err;
-}
-
-bool SFDAQInstance::break_loop(int error)
-{
- if (error)
- s_error = error;
- return (daq_breakloop(daq_mod, daq_hand) == DAQ_SUCCESS);
-}
-
-// returns statically allocated stats - don't free
-const DAQ_Stats_t* SFDAQInstance::get_stats()
-{
- if (daq_hand)
- {
- int err = daq_get_stats(daq_mod, daq_hand, &daq_stats);
-
- if (err)
- LogMessage("Can't get DAQ stats (%d) - %s\n", err, daq_get_error(daq_mod, daq_hand));
-
- // Some DAQs don't provide hw numbers, so we default HW RX to the SW equivalent
- // (this means outstanding packets = 0)
- if (!daq_stats.hw_packets_received)
- daq_stats.hw_packets_received = daq_stats.packets_received + daq_stats.packets_filtered;
- }
-
- return &daq_stats;
-}
-
-int SFDAQInstance::query_flow(const DAQ_PktHdr_t* hdr, DAQ_QueryFlow_t* query)
-{
- return daq_query_flow(daq_mod, daq_hand, hdr, query);
-}
-
-int SFDAQInstance::modify_flow_opaque(const DAQ_PktHdr_t* hdr, uint32_t opaque)
-{
- DAQ_ModFlow_t mod;
-
- mod.type = DAQ_MODFLOW_TYPE_OPAQUE;
- mod.length = sizeof(opaque);
- mod.value = &opaque;
-
- return daq_modify_flow(daq_mod, daq_hand, hdr, &mod);
-}
-
-int SFDAQInstance::modify_flow_pkt_trace(const DAQ_PktHdr_t* hdr, uint8_t verdict_reason,
- uint8_t* buff, uint32_t buff_len)
-{
- DAQ_ModFlow_t mod;
- DAQ_ModFlowPktTrace_t mod_tr;
- mod_tr.vreason = verdict_reason;
- mod_tr.pkt_trace_data_len = buff_len;
- mod_tr.pkt_trace_data = buff;
- mod.type = DAQ_MODFLOW_TYPE_PKT_TRACE;
- mod.length = sizeof(DAQ_ModFlowPktTrace_t);
- mod.value = (void*)&mod_tr;
- return daq_modify_flow(daq_mod, daq_hand, hdr, &mod);
-}
-
-// FIXIT-L X Add Snort flag definitions for callers to use and translate/pass them through to
-// the DAQ module
-int SFDAQInstance::add_expected(const Packet* ctrlPkt, const SfIp* cliIP, uint16_t cliPort,
- const SfIp* srvIP, uint16_t srvPort, IpProtocol protocol, unsigned timeout_ms, unsigned /* flags */)
-{
- DAQ_Data_Channel_Params_t daq_params;
- DAQ_DP_key_t dp_key;
-
- dp_key.src_af = cliIP->get_family();
- if (cliIP->is_ip4())
- dp_key.sa.src_ip4.s_addr = cliIP->get_ip4_value();
- else
- memcpy(&dp_key.sa.src_ip6, cliIP->get_ip6_ptr(), sizeof(dp_key.sa.src_ip6));
- dp_key.src_port = cliPort;
-
- dp_key.dst_af = srvIP->get_family();
- if (srvIP->is_ip4())
- dp_key.da.dst_ip4.s_addr = srvIP->get_ip4_value();
- else
- memcpy(&dp_key.da.dst_ip6, srvIP->get_ip6_ptr(), sizeof(dp_key.da.dst_ip6));
- dp_key.dst_port = srvPort;
-
- dp_key.protocol = (uint8_t) protocol;
- dp_key.vlan_cnots = 1;
- if (ctrlPkt->proto_bits & PROTO_BIT__VLAN)
- dp_key.vlan_id = layer::get_vlan_layer(ctrlPkt)->vid();
- else
- dp_key.vlan_id = 0xFFFF;
-
- if (ctrlPkt->proto_bits & PROTO_BIT__GTP)
- dp_key.tunnel_type = DAQ_DP_TUNNEL_TYPE_GTP_TUNNEL;
- else if (ctrlPkt->proto_bits & PROTO_BIT__MPLS)
- dp_key.tunnel_type = DAQ_DP_TUNNEL_TYPE_MPLS_TUNNEL;
-/*
- else if ( ctrlPkt->encapsulated )
- dp_key.tunnel_type = DAQ_DP_TUNNEL_TYPE_OTHER_TUNNEL;
-*/
- else
- dp_key.tunnel_type = DAQ_DP_TUNNEL_TYPE_NON_TUNNEL;
-
- memset(&daq_params, 0, sizeof(daq_params));
- daq_params.timeout_ms = timeout_ms;
-/*
- if (flags & DAQ_DC_FLOAT)
- daq_params.flags |= DAQ_DATA_CHANNEL_FLOAT;
- if (flags & DAQ_DC_ALLOW_MULTIPLE)
- daq_params.flags |= DAQ_DATA_CHANNEL_ALLOW_MULTIPLE;
- if (flags & DAQ_DC_PERSIST)
- daq_params.flags |= DAQ_DATA_CHANNEL_PERSIST;
-*/
-
- return daq_dp_add_dc(daq_mod, daq_hand, ctrlPkt->pkth, &dp_key, nullptr, &daq_params);
-}
#include <daq_common.h>
-#include <string>
+#include <ostream>
#include "main/snort_types.h"
-#include "protocols/protocol_ids.h"
-namespace snort
-{
-struct Packet;
-struct SnortConfig;
-struct SfIp;
+struct SFDAQConfig;
-class SFDAQInstance
+namespace snort
{
-public:
- SFDAQInstance(const char* intf);
- ~SFDAQInstance();
-
- bool configure(const SnortConfig*);
- void set_metacallback(DAQ_Meta_Func_t);
-
- bool start();
- bool was_started();
- bool stop();
- void reload();
- void abort();
-
- int get_base_protocol();
- const char* get_interface_spec();
- const DAQ_Stats_t* get_stats();
-
- bool can_inject();
- bool can_inject_raw();
- bool can_replace();
- bool can_retry();
- bool can_start_unprivileged();
- SO_PUBLIC bool can_whitelist();
-
- int acquire(int max, DAQ_Analysis_Func_t);
- int inject(const DAQ_PktHdr_t*, int rev, const uint8_t* buf, uint32_t len);
- bool break_loop(int error);
-
- SO_PUBLIC int query_flow(const DAQ_PktHdr_t*, DAQ_QueryFlow_t*);
- SO_PUBLIC int modify_flow_opaque(const DAQ_PktHdr_t*, uint32_t opaque);
- int modify_flow_pkt_trace(const DAQ_PktHdr_t*, uint8_t verdict_reason,
- uint8_t* buff, uint32_t buff_len);
- int add_expected(const Packet* ctrlPkt, const SfIp* cliIP, uint16_t cliPort,
- const SfIp* srvIP, uint16_t srvPort, IpProtocol, unsigned timeout_ms,
- unsigned /* flags */);
- bool get_tunnel_bypass(uint8_t proto);
-
-private:
- void get_tunnel_capabilities();
- bool set_filter(const char*);
- std::string interface_spec;
- void* daq_hand;
- int daq_dlt;
- int s_error;
- DAQ_Stats_t daq_stats;
- uint8_t daq_tunnel_mask;
-};
+class SFDAQInstance;
class SFDAQ
{
public:
- static void load(const SnortConfig*);
+ static void load(const SFDAQConfig*);
static void unload();
static void print_types(std::ostream&);
static const char* verdict_to_string(DAQ_Verdict verdict);
- static void init(const SnortConfig*);
+ static bool init(const SFDAQConfig*);
static void term();
- static const char* get_type();
- static const char* get_input_spec(const SnortConfig*, unsigned instance_id);
+ static bool init_instance(SFDAQInstance*, const std::string& bpf_string);
+
+ static const char* get_input_spec(const SFDAQConfig*, unsigned instance_id);
static const char* default_type();
static const DAQ_Stats_t* get_stats();
- static bool unprivileged();
static bool can_inject();
static bool can_inject_raw();
static bool can_replace();
- static bool can_retry();
+ static bool can_run_unprivileged();
SO_PUBLIC static bool get_tunnel_bypass(uint8_t proto);
// FIXIT-M X Temporary thread-local instance helpers to be removed when no longer needed
static void set_local_instance(SFDAQInstance*);
SO_PUBLIC static SFDAQInstance* get_local_instance();
- SO_PUBLIC static const char* get_interface_spec();
+ SO_PUBLIC static const char* get_input_spec();
SO_PUBLIC static int get_base_protocol();
- SO_PUBLIC static uint32_t get_snap_len();
- static int inject(const DAQ_PktHdr_t*, int rev, const uint8_t* buf, uint32_t len);
+ static int inject(DAQ_Msg_h, int rev, const uint8_t* buf, uint32_t len);
static bool forwarding_packet(const DAQ_PktHdr_t*);
- static bool break_loop(int error);
};
}
#endif
using namespace std;
-static const unsigned DEFAULT_PKT_TIMEOUT = 1000; // ms, worst daq resolution is 1 sec
-
static pair<string, string> parse_variable(const char* varkvp)
{
string key = varkvp;
}
/*
- * SFDAQConfigInstance
+ * SFDAQModuleConfig
*/
-SFDAQInstanceConfig::SFDAQInstanceConfig(const SFDAQInstanceConfig& other)
+SFDAQModuleConfig::SFDAQModuleConfig(const SFDAQModuleConfig& other)
{
- input_spec = other.input_spec;
+ name = other.name;
+ mode = other.mode;
variables = other.variables;
}
-void SFDAQInstanceConfig::set_input_spec(const char* input_spec_str)
+void SFDAQModuleConfig::set_variable(const char* varkvp)
{
- if (input_spec_str)
- input_spec = input_spec_str;
- else
- input_spec.clear();
+ if (varkvp)
+ variables.emplace_back(parse_variable(varkvp));
}
-void SFDAQInstanceConfig::set_variable(const char* varkvp)
-{
- variables.emplace_back(parse_variable(varkvp));
-}
/*
* SFDAQConfig
SFDAQConfig::SFDAQConfig()
{
- mru_size = -1;
- timeout = DEFAULT_PKT_TIMEOUT;
+ batch_size = BATCH_SIZE_UNSET;
+ mru_size = SNAPLEN_UNSET;
+ timeout = TIMEOUT_DEFAULT;
}
SFDAQConfig::~SFDAQConfig()
{
- for (auto it : instances)
- delete it.second;
+ for (auto it : module_configs)
+ delete it;
}
-void SFDAQConfig::add_module_dir(const char* module_dir)
+void SFDAQConfig::add_input(const char* input)
{
- if (module_dir)
- module_dirs.emplace_back(module_dir);
+ if (input)
+ inputs.emplace_back(input);
}
-void SFDAQConfig::set_input_spec(const char* input_spec_str, int instance_id)
+SFDAQModuleConfig* SFDAQConfig::add_module_config(const char* module_name)
{
- if (instance_id >= 0)
- {
- SFDAQInstanceConfig* ic;
-
- auto it = instances.find(instance_id);
- if (it == instances.end())
- {
- ic = new SFDAQInstanceConfig;
- instances[instance_id] = ic;
- }
- else
- ic = it->second;
-
- ic->set_input_spec(input_spec_str);
- }
- else
- {
- if (input_spec_str)
- input_spec = input_spec_str;
- else
- input_spec.clear();
- }
+ SFDAQModuleConfig* modcfg = new SFDAQModuleConfig();
+ modcfg->name = module_name;
+ module_configs.emplace_back(modcfg);
+ return modcfg;
}
-void SFDAQConfig::set_module_name(const char* module_name_str)
+void SFDAQConfig::add_module_dir(const char* module_dir)
{
- if (module_name_str)
- module_name = module_name_str;
+ if (module_dir)
+ module_dirs.emplace_back(module_dir);
}
-void SFDAQConfig::set_mru_size(int mru_size_value)
+void SFDAQConfig::set_batch_size(uint32_t batch_size_value)
{
- mru_size = mru_size_value;
+ batch_size = batch_size_value;
}
-void SFDAQConfig::set_variable(const char* varkvp, int instance_id)
+void SFDAQConfig::set_mru_size(int mru_size_value)
{
- if (instance_id >= 0)
- {
- SFDAQInstanceConfig* ic;
-
- auto it = instances.find(instance_id);
- if (it == instances.end())
- {
- ic = new SFDAQInstanceConfig;
- instances[instance_id] = ic;
- }
- else
- ic = it->second;
-
- ic->set_variable(varkvp);
- }
- else
- variables.emplace_back(parse_variable(varkvp));
+ mru_size = mru_size_value;
}
void SFDAQConfig::overlay(const SFDAQConfig* other)
if (!other->module_dirs.empty())
module_dirs = other->module_dirs;
- if (!other->module_name.empty())
- module_name = other->module_name;
-
- if (!other->input_spec.empty())
- input_spec = other->input_spec;
+ if (!other->module_configs.empty())
+ {
+ for (SFDAQModuleConfig *dmc : module_configs)
+ delete dmc;
+ module_configs.clear();
+ for (SFDAQModuleConfig *dmc : other->module_configs)
+ module_configs.emplace_back(new SFDAQModuleConfig(*dmc));
+ }
- if (!other->variables.empty())
- variables = other->variables;
+ if (!other->inputs.empty())
+ inputs = other->inputs;
- if (other->mru_size != -1)
+ if (other->batch_size != BATCH_SIZE_UNSET)
+ batch_size = other->batch_size;
+ if (other->mru_size != SNAPLEN_UNSET)
mru_size = other->mru_size;
-
- for (auto oit = other->instances.begin(); oit != other->instances.end(); oit++)
- {
- SFDAQInstanceConfig* oic = oit->second;
- SFDAQInstanceConfig* ic;
- auto it = instances.find(oit->first);
- if (it != instances.end())
- {
- ic = it->second;
- if (!oic->input_spec.empty())
- ic->input_spec = oic->input_spec;
- if (!oic->variables.empty())
- ic->variables = oic->variables;
- }
- else
- {
- ic = new SFDAQInstanceConfig(*oic);
- instances[oit->first] = ic;
- }
- }
+ timeout = other->timeout;
}
#include <unordered_map>
#include <vector>
-/* Per-Instance override configuration */
-struct SFDAQInstanceConfig
-{
- SFDAQInstanceConfig() = default;
- SFDAQInstanceConfig(const SFDAQInstanceConfig&);
+using DaqVar = std::pair<std::string, std::string>;
+using DaqVarList = std::vector<DaqVar>;
- SFDAQInstanceConfig& operator=(const SFDAQInstanceConfig&) = delete;
+/* Module configuration */
+struct SFDAQModuleConfig
+{
+ enum SFDAQMode
+ {
+ SFDAQ_MODE_UNSET,
+ SFDAQ_MODE_PASSIVE,
+ SFDAQ_MODE_INLINE,
+ SFDAQ_MODE_READ_FILE,
+ };
- void set_input_spec(const char*);
+ SFDAQModuleConfig() = default;
+ SFDAQModuleConfig(const SFDAQModuleConfig&);
void set_variable(const char* varkvp);
- std::string input_spec;
- std::vector<std::pair<std::string, std::string>> variables;
+ std::string name;
+ SFDAQMode mode = SFDAQ_MODE_UNSET;
+ DaqVarList variables;
};
/* General/base configuration */
SFDAQConfig();
~SFDAQConfig();
+ void add_input(const char*);
+ SFDAQModuleConfig* add_module_config(const char* module_name);
void add_module_dir(const char*);
- void set_input_spec(const char*, int instance_id = -1);
- void set_module_name(const char*);
+ void set_batch_size(uint32_t);
void set_mru_size(int);
- void set_variable(const char* varkvp, int instance_id = -1);
+
+ uint32_t get_batch_size() const { return (batch_size == BATCH_SIZE_UNSET) ? BATCH_SIZE_DEFAULT : batch_size; }
+ uint32_t get_mru_size() const { return (mru_size == SNAPLEN_UNSET) ? SNAPLEN_DEFAULT : mru_size; }
void overlay(const SFDAQConfig*);
/* General configuration */
std::vector<std::string> module_dirs;
- std::string module_name;
- /* Module configuration */
- std::string input_spec;
- std::vector<std::pair<std::string, std::string>> variables;
+ /* Instance configuration */
+ std::vector<std::string> inputs;
+ uint32_t batch_size;
int mru_size;
unsigned int timeout;
- std::unordered_map<unsigned, SFDAQInstanceConfig*> instances;
+ std::vector<SFDAQModuleConfig*> module_configs;
+
+ /* Constants */
+ static constexpr uint32_t BATCH_SIZE_UNSET = 0;
+ static constexpr int SNAPLEN_UNSET = -1;
+ static constexpr uint32_t BATCH_SIZE_DEFAULT = 64;
+ static constexpr int SNAPLEN_DEFAULT = 1518;
+ static constexpr unsigned TIMEOUT_DEFAULT = 1000;
};
#endif
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// sfdaq_instance.cc author Michael Altizer <mialtize@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "sfdaq_instance.h"
+
+#include <daq.h>
+
+#include "log/messages.h"
+#include "main/snort_config.h"
+#include "protocols/packet.h"
+#include "protocols/vlan.h"
+
+#include "sfdaq_config.h"
+
+using namespace snort;
+
+SFDAQInstance::SFDAQInstance(const char* input, const SFDAQConfig* cfg)
+{
+ if (input)
+ input_spec = input;
+ batch_size = cfg->get_batch_size();
+ daq_msgs = new DAQ_Msg_h[batch_size];
+}
+
+SFDAQInstance::~SFDAQInstance()
+{
+ delete[] daq_msgs;
+ if (instance)
+ daq_instance_destroy(instance);
+}
+
+static bool DAQ_ValidateInstance(DAQ_Instance_h instance)
+{
+ uint32_t caps = daq_instance_get_capabilities(instance);
+
+ if (!SnortConfig::adaptor_inline_mode())
+ return true;
+
+ if (!(caps & DAQ_CAPA_BLOCK))
+ ParseWarning(WARN_DAQ, "inline mode configured but DAQ can't block packets.\n");
+
+ return true;
+}
+
+bool SFDAQInstance::init(DAQ_Config_h daqcfg, const std::string& bpf_string)
+{
+ char buf[256] = "";
+ int rval;
+
+ /* Reuse the main DAQ instance configuration with the input specification specific to this instance. */
+ daq_config_set_input(daqcfg, input_spec.c_str());
+ if ((rval = daq_instance_instantiate(daqcfg, &instance, buf, sizeof(buf))) != DAQ_SUCCESS)
+ {
+ ErrorMessage("Couldn't construct a DAQ instance: %s (%d)\n", buf, rval);
+ return false;
+ }
+
+ if (!DAQ_ValidateInstance(instance))
+ FatalError("DAQ configuration incompatible with intended operation.\n");
+
+ if (!bpf_string.empty())
+ {
+ rval = daq_instance_set_filter(instance, bpf_string.c_str());
+ if (rval != DAQ_SUCCESS)
+ FatalError("Couldn't set DAQ instance BPF filter to '%s': %s (%d)\n",
+ bpf_string.c_str(), daq_instance_get_error(instance), rval);
+ }
+
+ return true;
+}
+
+void SFDAQInstance::reload()
+{
+ if (!instance)
+ return;
+
+ void* new_config = nullptr;
+ if (daq_instance_config_load(instance, &new_config) == DAQ_SUCCESS)
+ {
+ void* old_config = nullptr;
+ if (daq_instance_config_swap(instance, new_config, &old_config) == DAQ_SUCCESS)
+ daq_instance_config_free(instance, old_config);
+ else
+ daq_instance_config_free(instance, new_config);
+ }
+}
+
+void SFDAQInstance::abort()
+{
+ if (was_started())
+ stop();
+
+ //DAQ_Delete();
+ //DAQ_Term(); FIXIT-L this must be called from main thread on abort
+}
+
+const char* SFDAQInstance::get_input_spec()
+{
+ return input_spec.c_str();
+}
+
+// That distinction does not hold with datalink types. Snort must use whatever
+// datalink type the DAQ coughs up as its base protocol decoder. For pcaps,
+// the datalink type in the file must be used - which may not be known until
+// start. The value is cached here since it used for packet operations like
+// logging and is needed at shutdown. This avoids sequencing issues.
+int SFDAQInstance::get_base_protocol()
+{
+ return dlt;
+}
+
+bool SFDAQInstance::can_inject()
+{
+ return (daq_instance_get_capabilities(instance) & DAQ_CAPA_INJECT) != 0;
+}
+
+bool SFDAQInstance::can_inject_raw()
+{
+ return (daq_instance_get_capabilities(instance) & DAQ_CAPA_INJECT_RAW) != 0;
+}
+
+bool SFDAQInstance::can_replace()
+{
+ return (daq_instance_get_capabilities(instance) & DAQ_CAPA_REPLACE) != 0;
+}
+
+bool SFDAQInstance::can_start_unprivileged()
+{
+ return (daq_instance_get_capabilities(instance) & DAQ_CAPA_UNPRIV_START) != 0;
+}
+
+bool SFDAQInstance::can_whitelist()
+{
+ return (daq_instance_get_capabilities(instance) & DAQ_CAPA_WHITELIST) != 0;
+}
+
+bool SFDAQInstance::start()
+{
+ int rval = daq_instance_start(instance);
+ if (rval != DAQ_SUCCESS)
+ {
+ ErrorMessage("Couldn't start DAQ instance: %s (%d)\n", daq_instance_get_error(instance), rval);
+ return false;
+ }
+
+ DAQ_MsgPoolInfo_t mpool_info;
+ rval = daq_instance_get_msg_pool_info(instance, &mpool_info);
+ if (rval != DAQ_SUCCESS)
+ {
+ ErrorMessage("Couldn't query DAQ message pool info: %s (%d)\n", daq_instance_get_error(instance), rval);
+ stop();
+ return false;
+ }
+ pool_size = mpool_info.size;
+ pool_available = mpool_info.available;
+ assert(pool_size == pool_available);
+
+ dlt = daq_instance_get_datalink_type(instance);
+ get_tunnel_capabilities();
+
+ return (rval == DAQ_SUCCESS);
+}
+
+DAQ_RecvStatus SFDAQInstance::receive_messages(unsigned max_recv)
+{
+ assert(max_recv <= batch_size);
+
+ if (max_recv > pool_available)
+ max_recv = pool_available;
+
+ DAQ_RecvStatus rstat;
+ curr_batch_size = daq_instance_msg_receive(instance, max_recv, daq_msgs, &rstat);
+ pool_available -= curr_batch_size;
+ curr_batch_idx = 0;
+
+ return rstat;
+}
+
+int SFDAQInstance::finalize_message(DAQ_Msg_h msg, DAQ_Verdict verdict)
+{
+ int rval = daq_instance_msg_finalize(instance, msg, verdict);
+ if (rval == DAQ_SUCCESS)
+ pool_available++;
+ return rval;
+}
+
+const char* SFDAQInstance::get_error()
+{
+ return daq_instance_get_error(instance);
+}
+
+void SFDAQInstance::get_tunnel_capabilities()
+{
+ daq_tunnel_mask = 0;
+ if (instance)
+ {
+ uint32_t caps = daq_instance_get_capabilities(instance);
+
+ if (caps & DAQ_CAPA_DECODE_GTP)
+ daq_tunnel_mask |= TUNNEL_GTP;
+ if (caps & DAQ_CAPA_DECODE_TEREDO)
+ daq_tunnel_mask |= TUNNEL_TEREDO;
+ if (caps & DAQ_CAPA_DECODE_GRE)
+ daq_tunnel_mask |= TUNNEL_GRE;
+ if (caps & DAQ_CAPA_DECODE_4IN4)
+ daq_tunnel_mask |= TUNNEL_4IN4;
+ if (caps & DAQ_CAPA_DECODE_6IN4)
+ daq_tunnel_mask |= TUNNEL_6IN4;
+ if (caps & DAQ_CAPA_DECODE_4IN6)
+ daq_tunnel_mask |= TUNNEL_4IN6;
+ if (caps & DAQ_CAPA_DECODE_6IN6)
+ daq_tunnel_mask |= TUNNEL_6IN6;
+ if (caps & DAQ_CAPA_DECODE_MPLS)
+ daq_tunnel_mask |= TUNNEL_MPLS;
+ }
+}
+
+bool SFDAQInstance::get_tunnel_bypass(uint8_t proto)
+{
+ return (daq_tunnel_mask & proto) != 0;
+}
+
+bool SFDAQInstance::was_started()
+{
+ DAQ_State s;
+
+ if (!instance)
+ return false;
+
+ s = daq_instance_check_status(instance);
+
+ return (DAQ_STATE_STARTED == s);
+}
+
+bool SFDAQInstance::stop()
+{
+ assert(pool_size == pool_available);
+
+ int rval = daq_instance_stop(instance);
+
+ if (rval != DAQ_SUCCESS)
+ LogMessage("Couldn't stop DAQ instance: %s (%d)\n", daq_instance_get_error(instance), rval);
+
+ return (rval == DAQ_SUCCESS);
+}
+
+int SFDAQInstance::inject(DAQ_Msg_h msg, int rev, const uint8_t* buf, uint32_t len)
+{
+ int rval = daq_instance_inject_relative(instance, msg, buf, len, rev);
+#ifdef DEBUG_MSGS
+ if (rval != DAQ_SUCCESS)
+ LogMessage("Couldn't inject on DAQ instance: %s (%d)\n", daq_instance_get_error(instance), rval);
+#endif
+ return rval;
+}
+
+bool SFDAQInstance::interrupt()
+{
+ return (daq_instance_interrupt(instance) == DAQ_SUCCESS);
+}
+
+const DAQ_Stats_t* SFDAQInstance::get_stats()
+{
+ if (instance)
+ {
+ int rval = daq_instance_get_stats(instance, &daq_stats);
+ if (rval != DAQ_SUCCESS)
+ LogMessage("Couldn't query DAQ stats: %s (%d)\n", daq_instance_get_error(instance), rval);
+
+ // Some DAQ modules don't provide hardware numbers, so we default HW RX to the SW equivalent
+ // (this means outstanding packets = 0)
+ if (daq_stats.hw_packets_received == 0)
+ daq_stats.hw_packets_received = daq_stats.packets_received + daq_stats.packets_filtered;
+ }
+
+ return &daq_stats;
+}
+
+int SFDAQInstance::ioctl(DAQ_IoctlCmd cmd, void *arg, size_t arglen)
+{
+ return daq_instance_ioctl(instance, cmd, arg, arglen);
+}
+
+int SFDAQInstance::modify_flow_opaque(DAQ_Msg_h msg, uint32_t opaque)
+{
+ DIOCTL_SetFlowOpaque d_sfo;
+ d_sfo.msg = msg;
+ d_sfo.value = opaque;
+
+ return daq_instance_ioctl(instance, DIOCTL_SET_FLOW_OPAQUE, &d_sfo, sizeof(d_sfo));
+}
+
+int SFDAQInstance::modify_flow_pkt_trace(DAQ_Msg_h msg, uint8_t verdict_reason, uint8_t* buff, uint32_t buff_len)
+{
+ DIOCTL_SetPacketTraceData d_sptd;
+
+ d_sptd.msg = msg;
+ d_sptd.verdict_reason = verdict_reason;
+ d_sptd.trace_data_len = buff_len;
+ d_sptd.trace_data = buff;
+
+ return daq_instance_ioctl(instance, DIOCTL_SET_PACKET_TRACE_DATA, &d_sptd, sizeof(d_sptd));
+}
+
+// FIXIT-L X Add Snort flag definitions for callers to use and translate/pass them through to
+// the DAQ module
+int SFDAQInstance::add_expected(const Packet* ctrlPkt, const SfIp* cliIP, uint16_t cliPort,
+ const SfIp* srvIP, uint16_t srvPort, IpProtocol protocol, unsigned timeout_ms, unsigned /* flags */)
+{
+ DIOCTL_CreateExpectedFlow d_cef;
+
+ d_cef.ctrl_msg = ctrlPkt->daq_msg;
+
+ /* Populate the expected flow key */
+ DAQ_EFlow_Key_t* key = &d_cef.key;
+
+ key->src_af = cliIP->get_family();
+ if (cliIP->is_ip4())
+ key->sa.src_ip4.s_addr = cliIP->get_ip4_value();
+ else
+ memcpy(&key->sa.src_ip6, cliIP->get_ip6_ptr(), sizeof(key->sa.src_ip6));
+ key->src_port = cliPort;
+
+ key->dst_af = srvIP->get_family();
+ if (srvIP->is_ip4())
+ key->da.dst_ip4.s_addr = srvIP->get_ip4_value();
+ else
+ memcpy(&key->da.dst_ip6, srvIP->get_ip6_ptr(), sizeof(key->da.dst_ip6));
+ key->dst_port = srvPort;
+
+ // FIXIT-M The key address_space_id is not currently being populated!
+
+ if (ctrlPkt->proto_bits & PROTO_BIT__GTP)
+ key->tunnel_type = DAQ_EFLOW_TUNNEL_TYPE_GTP_TUNNEL;
+ else if (ctrlPkt->proto_bits & PROTO_BIT__MPLS)
+ key->tunnel_type = DAQ_EFLOW_TUNNEL_TYPE_MPLS_TUNNEL;
+ // FIXIT-L Need to figure out the right way to determine "Other" encapsulation
+/*
+ else if ( ctrlPkt->encapsulated )
+ key->tunnel_type = DAQ_EFLOW_TUNNEL_TYPE_OTHER_TUNNEL;
+*/
+ else
+ key->tunnel_type = DAQ_EFLOW_TUNNEL_TYPE_NON_TUNNEL;
+
+ key->protocol = (uint8_t) protocol;
+ if (ctrlPkt->proto_bits & PROTO_BIT__VLAN)
+ key->vlan_id = layer::get_vlan_layer(ctrlPkt)->vid();
+ else
+ key->vlan_id = 0xFFFF;
+ key->vlan_cnots = 1;
+
+ d_cef.flags = 0;
+/*
+ if (flags & DAQ_DC_FLOAT)
+ d_cef.flags |= DAQ_EFLOW_FLOAT;
+ if (flags & DAQ_DC_ALLOW_MULTIPLE)
+ d_cef.flags |= DAQ_EFLOW_ALLOW_MULTIPLE;
+ if (flags & DAQ_DC_PERSIST)
+ d_cef.flags |= DAQ_EFLOW_PERSIST;
+*/
+ d_cef.timeout_ms = timeout_ms;
+ // Opaque data blob for expected flows is currently unused/unimplemented
+ d_cef.data = nullptr;
+ d_cef.length = 0;
+
+ return daq_instance_ioctl(instance, DIOCTL_CREATE_EXPECTED_FLOW, &d_cef, sizeof(d_cef));
+}
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2019 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2005-2013 Sourcefire, Inc.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// sfdaq.h author Michael Altizer <mialtize@cisco.com>
+
+#ifndef SFDAQ_INSTANCE_H
+#define SFDAQ_INSTANCE_H
+
+#include <daq_common.h>
+
+#include <string>
+
+#include "main/snort_types.h"
+#include "protocols/protocol_ids.h"
+
+struct SFDAQConfig;
+
+namespace snort
+{
+struct Packet;
+struct SfIp;
+
+class SFDAQInstance
+{
+public:
+ SFDAQInstance(const char* intf, const SFDAQConfig*);
+ ~SFDAQInstance();
+
+ bool init(DAQ_Config_h, const std::string& bpf_string);
+
+ bool start();
+ bool was_started();
+ bool stop();
+ void reload();
+ void abort();
+
+ DAQ_RecvStatus receive_messages(unsigned max_recv);
+ DAQ_Msg_h next_message()
+ {
+ if (curr_batch_idx < curr_batch_size)
+ return daq_msgs[curr_batch_idx++];
+ return nullptr;
+ }
+ int finalize_message(DAQ_Msg_h msg, DAQ_Verdict verdict);
+ const char* get_error();
+
+ int get_base_protocol();
+ uint32_t get_batch_size() { return batch_size; }
+ const char* get_input_spec();
+ const DAQ_Stats_t* get_stats();
+
+ bool can_inject();
+ bool can_inject_raw();
+ bool can_replace();
+ bool can_start_unprivileged();
+ SO_PUBLIC bool can_whitelist();
+
+ int inject(DAQ_Msg_h, int rev, const uint8_t* buf, uint32_t len);
+ bool interrupt();
+
+ SO_PUBLIC int ioctl(DAQ_IoctlCmd cmd, void *arg, size_t arglen);
+ SO_PUBLIC int modify_flow_opaque(DAQ_Msg_h, uint32_t opaque);
+ int modify_flow_pkt_trace(DAQ_Msg_h, uint8_t verdict_reason,
+ uint8_t* buff, uint32_t buff_len);
+ int add_expected(const Packet* ctrlPkt, const SfIp* cliIP, uint16_t cliPort,
+ const SfIp* srvIP, uint16_t srvPort, IpProtocol, unsigned timeout_ms,
+ unsigned /* flags */);
+ bool get_tunnel_bypass(uint8_t proto);
+
+private:
+ void get_tunnel_capabilities();
+
+ std::string input_spec;
+ DAQ_Instance_h instance = nullptr;
+ DAQ_Msg_h* daq_msgs;
+ unsigned curr_batch_size = 0;
+ unsigned curr_batch_idx = 0;
+ uint32_t batch_size;
+ uint32_t pool_size = 0;
+ uint32_t pool_available = 0;
+ int dlt = -1;
+ DAQ_Stats_t daq_stats = { };
+ uint8_t daq_tunnel_mask = 0;
+};
+}
+#endif
+
#define sfdaq_help "configure packet acquisition interface"
-struct DAQStats
+/*
+ * Module Configuration
+ */
+
+static const Parameter daqvar_list_param[] =
{
- PegCount pcaps;
- PegCount received;
- PegCount analyzed;
- PegCount dropped;
- PegCount filtered;
- PegCount outstanding;
- PegCount injected;
- PegCount verdicts[MAX_DAQ_VERDICT];
- PegCount internal_blacklist;
- PegCount internal_whitelist;
- PegCount skipped;
- PegCount idle;
- PegCount rx_bytes;
+ { "variable", Parameter::PT_STRING, nullptr, nullptr, "DAQ module variable (foo[=bar])" },
+
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
-const PegInfo daq_names[] =
+static const Parameter daq_module_param[] =
{
- { CountType::MAX, "pcaps", "total files and interfaces processed" },
- { CountType::SUM, "received", "total packets received from DAQ" },
- { CountType::SUM, "analyzed", "total packets analyzed from DAQ" },
- { CountType::SUM, "dropped", "packets dropped" },
- { CountType::SUM, "filtered", "packets filtered out" },
- { CountType::SUM, "outstanding", "packets unprocessed" },
- { CountType::SUM, "injected", "active responses or replacements" },
- { CountType::SUM, "allow", "total allow verdicts" },
- { CountType::SUM, "block", "total block verdicts" },
- { CountType::SUM, "replace", "total replace verdicts" },
- { CountType::SUM, "whitelist", "total whitelist verdicts" },
- { CountType::SUM, "blacklist", "total blacklist verdicts" },
- { CountType::SUM, "ignore", "total ignore verdicts" },
- { CountType::SUM, "retry", "total retry verdicts" },
+ { "name", Parameter::PT_STRING, nullptr, nullptr, "DAQ module name (required)" },
+ { "mode", Parameter::PT_ENUM, "passive | inline | read-file", "passive", "DAQ module mode" },
+ { "variables", Parameter::PT_LIST, daqvar_list_param, nullptr, "DAQ module variables" },
- // FIXIT-L these are not exactly DAQ counts - but they are related
- { CountType::SUM, "internal_blacklist",
- "packets blacklisted internally due to lack of DAQ support" },
- { CountType::SUM, "internal_whitelist",
- "packets whitelisted internally due to lack of DAQ support" },
- { CountType::SUM, "skipped", "packets skipped at startup" },
- { CountType::SUM, "idle", "attempts to acquire from DAQ without available packets" },
- { CountType::SUM, "rx_bytes", "total bytes received" },
- { CountType::END, nullptr, nullptr }
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
-static THREAD_LOCAL DAQStats stats;
-
-static const Parameter string_list_param[] =
+static const Parameter path_list_param[] =
{
- { "str", Parameter::PT_STRING, nullptr, nullptr, "string parameter" },
+ { "path", Parameter::PT_STRING, nullptr, nullptr, "directory path" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
-static const Parameter instance_params[] =
+static const Parameter input_list_param[] =
{
- { "id", Parameter::PT_INT, "0:max32", nullptr, "instance ID (required)" },
- { "input_spec", Parameter::PT_STRING, nullptr, nullptr, "input specification" },
- { "variables", Parameter::PT_LIST, string_list_param, nullptr, "DAQ variables" },
+ { "input", Parameter::PT_STRING, nullptr, nullptr, "input source" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
static const Parameter s_params[] =
{
- { "module_dirs", Parameter::PT_LIST, string_list_param, nullptr, "directories to search for DAQ modules" },
- { "input_spec", Parameter::PT_STRING, nullptr, nullptr, "input specification" },
- { "module", Parameter::PT_STRING, nullptr, nullptr, "DAQ module to use" },
- { "variables", Parameter::PT_LIST, string_list_param, nullptr, "DAQ variables" },
- { "instances", Parameter::PT_LIST, instance_params, nullptr, "DAQ instance overrides" },
- { "snaplen", Parameter::PT_INT, "0:65535", nullptr, "set snap length (same as -s)" },
- { "no_promisc", Parameter::PT_BOOL, nullptr, "false", "whether to put DAQ device into promiscuous mode" },
+ { "module_dirs", Parameter::PT_LIST, path_list_param, nullptr, "directories to search for dynamic DAQ modules" },
+ { "inputs", Parameter::PT_LIST, input_list_param, nullptr, "input sources" },
+ { "snaplen", Parameter::PT_INT, "0:65535", "1518", "set snap length (same as -s)" },
+ { "batch_size", Parameter::PT_INT, "1:", "64", "set receive batch size (same as --daq-batch-size)" },
+ { "modules", Parameter::PT_LIST, daq_module_param, nullptr, "DAQ modules to use" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
SFDAQModule::SFDAQModule() : Module("daq", sfdaq_help, s_params)
{
config = nullptr;
- instance_config = nullptr;
+ module_config = nullptr;
}
-
bool SFDAQModule::begin(const char* fqn, int idx, SnortConfig*)
{
if (!strcmp(fqn, "daq"))
config = new SFDAQConfig();
-
- else if (!strcmp(fqn, "daq.instances"))
+ else if (!strcmp(fqn, "daq.modules"))
{
if (idx == 0)
return true;
- assert(!instance_config);
- instance_config = new SFDAQInstanceConfig();
-
- instance_id = -1;
+ module_config = new SFDAQModuleConfig();
}
+
return true;
}
-bool SFDAQModule::set(const char* fqn, Value& v, SnortConfig* sc)
+bool SFDAQModule::set(const char* fqn, Value& v, SnortConfig*)
{
if (!strcmp(fqn, "daq.module_dirs"))
{
config->add_module_dir(v.get_string());
}
- else if (!strcmp(fqn, "daq.module"))
- {
- config->set_module_name(v.get_string());
- }
- else if (!strcmp(fqn, "daq.input_spec"))
+ else if (!strcmp(fqn, "daq.inputs"))
{
- config->set_input_spec(v.get_string());
- }
- else if (!strcmp(fqn, "daq.variables"))
- {
- config->set_variable(v.get_string());
+ config->add_input(v.get_string());
}
else if (!strcmp(fqn, "daq.snaplen"))
{
config->set_mru_size(v.get_uint16());
}
- else if (!strcmp(fqn, "daq.no_promisc"))
+ else if (!strcmp(fqn, "daq.batch_size"))
{
- v.update_mask(sc->run_flags, RUN_FLAG__NO_PROMISCUOUS);
+ config->set_batch_size(v.get_long());
}
- else if (!strcmp(fqn, "daq.instances.id"))
+ else if (!strcmp(fqn, "daq.modules.name"))
{
- instance_id = v.get_uint32();
+ module_config->name = v.get_string();
}
- else if (!strcmp(fqn, "daq.instances.input_spec"))
+ else if (!strcmp(fqn, "daq.modules.mode"))
{
- instance_config->set_input_spec(v.get_string());
+ module_config->mode = (SFDAQModuleConfig::SFDAQMode) (v.get_long() + 1);
}
- else if (!strcmp(fqn, "daq.instances.variables"))
+ else if (!strcmp(fqn, "daq.modules.variables"))
{
- instance_config->set_variable(v.get_string());
+ module_config->set_variable(v.get_string());
}
return true;
bool SFDAQModule::end(const char* fqn, int idx, SnortConfig* sc)
{
- if (!strcmp(fqn, "daq.instances"))
+ if (!strcmp(fqn, "daq.modules"))
{
if (idx == 0)
return true;
- if (instance_id < 0 or config->instances[instance_id])
+ if (module_config->name.empty())
{
- ParseError("%s - duplicate or no DAQ instance ID specified", fqn);
- delete instance_config;
- instance_config = nullptr;
+ ParseError("%s - No module name specified!", fqn);
+ delete module_config;
+ module_config = nullptr;
return false;
}
- config->instances[instance_id] = instance_config;
- instance_config = nullptr;
+ config->module_configs.push_back(module_config);
+ module_config = nullptr;
}
else if (!strcmp(fqn, "daq"))
{
return true;
}
+/*
+ * Module Counters
+ */
+
+struct DAQStats
+{
+ PegCount pcaps;
+ PegCount received;
+ PegCount analyzed;
+ PegCount dropped;
+ PegCount filtered;
+ PegCount outstanding;
+ PegCount injected;
+ PegCount verdicts[MAX_DAQ_VERDICT];
+ PegCount internal_blacklist;
+ PegCount internal_whitelist;
+ PegCount skipped;
+ PegCount idle;
+ PegCount rx_bytes;
+};
+
+const PegInfo daq_names[] =
+{
+ { CountType::MAX, "pcaps", "total files and interfaces processed" },
+ { CountType::SUM, "received", "total packets received from DAQ" },
+ { CountType::SUM, "analyzed", "total packets analyzed from DAQ" },
+ { CountType::SUM, "dropped", "packets dropped" },
+ { CountType::SUM, "filtered", "packets filtered out" },
+ { CountType::SUM, "outstanding", "packets unprocessed" },
+ { CountType::SUM, "injected", "active responses or replacements" },
+ { CountType::SUM, "allow", "total allow verdicts" },
+ { CountType::SUM, "block", "total block verdicts" },
+ { CountType::SUM, "replace", "total replace verdicts" },
+ { CountType::SUM, "whitelist", "total whitelist verdicts" },
+ { CountType::SUM, "blacklist", "total blacklist verdicts" },
+ { CountType::SUM, "ignore", "total ignore verdicts" },
+ { CountType::SUM, "retry", "total retry verdicts" },
+
+ // FIXIT-L these are not exactly DAQ counts - but they are related
+ { CountType::SUM, "internal_blacklist",
+ "packets blacklisted internally due to lack of DAQ support" },
+ { CountType::SUM, "internal_whitelist",
+ "packets whitelisted internally due to lack of DAQ support" },
+ { CountType::SUM, "skipped", "packets skipped at startup" },
+ { CountType::SUM, "idle", "attempts to acquire from DAQ without available packets" },
+ { CountType::SUM, "rx_bytes", "total bytes received" },
+ { CountType::END, nullptr, nullptr }
+};
+
+static THREAD_LOCAL DAQStats stats;
+
const PegInfo* SFDAQModule::get_pegs() const
{
return daq_names;
void SFDAQModule::prep_counts()
{
static THREAD_LOCAL DAQ_Stats_t sfdaq_stats;
- static THREAD_LOCAL PegCount last_skipped = 0;
static THREAD_LOCAL bool did_init = false;
if ( !did_init )
stats.internal_blacklist = aux_counts.internal_blacklist;
stats.internal_whitelist = aux_counts.internal_whitelist;
- stats.skipped = SnortConfig::get_conf()->pkt_skip - last_skipped;
+ stats.skipped = aux_counts.skipped;
stats.idle = aux_counts.idle;
stats.rx_bytes = aux_counts.rx_bytes;
memset(&aux_counts, 0, sizeof(AuxCount));
- last_skipped = stats.skipped;
sfdaq_stats = new_sfdaq_stats;
for ( unsigned i = 0; i < MAX_DAQ_VERDICT; i++ )
struct SnortConfig;
}
struct SFDAQConfig;
-struct SFDAQInstanceConfig;
+struct SFDAQModuleConfig;
class SFDAQModule : public snort::Module
{
private:
SFDAQConfig* config;
- SFDAQInstanceConfig* instance_config;
- int instance_id;
+ SFDAQModuleConfig* module_config;
};
#endif
--- /dev/null
+
+#include <daq_module_api.h>
+
+@DAQ_STATIC_MODULE_EXTERNS@
+
+static DAQ_Module_h static_daq_modules[] =
+{
+@DAQ_STATIC_MODULE_DATA_ARRAY@
+ nullptr
+};
+
using namespace snort;
-TEST_CASE("Kitchen Sink", "[SFDAQModule]")
+
+TEST_CASE("parse sfdaq config", "[SFDAQModule]")
{
- SFDAQModule sfdm;
SnortConfig sc;
+ SFDAQModule sfdm;
/* Generate the configuration */
sfdm.begin("daq", 0, &sc);
Value module_dir1("/test/dir/1");
- Value module_dir2("/test/dir/2");
CHECK(sfdm.set("daq.module_dirs", module_dir1, &sc));
+
+ Value module_dir2("/test/dir/2");
CHECK(sfdm.set("daq.module_dirs", module_dir2, &sc));
- Value module_name("test_module");
- CHECK(sfdm.set("daq.module", module_name, &sc));
+ Value input1("test_input1");
+ CHECK(sfdm.set("daq.inputs", input1, &sc));
- Value input_spec("test_input");
- CHECK(sfdm.set("daq.input_spec", input_spec, &sc));
+ Value input2("test_input2");
+ CHECK(sfdm.set("daq.inputs", input2, &sc));
- Value var1("foo=bar");
- Value var2("debug");
- Value var3("hello=world");
- CHECK(sfdm.set("daq.variables", var1, &sc));
- CHECK(sfdm.set("daq.variables", var2, &sc));
- CHECK(sfdm.set("daq.variables", var3, &sc));
+ Value input3("test_input3");
+ CHECK(sfdm.set("daq.inputs", input3, &sc));
Value snaplen(static_cast<double>(6666));
CHECK(sfdm.set("daq.snaplen", snaplen, &sc));
- Value no_promisc(true);
- CHECK(sfdm.set("daq.no_promisc", no_promisc, &sc));
+ Value batch_size(static_cast<double>(10));
+ CHECK(sfdm.set("daq.batch_size", batch_size, &sc));
- CHECK(sfdm.begin("daq.instances", 0, &sc));
- CHECK(sfdm.begin("daq.instances", 1, &sc));
+ CHECK(sfdm.begin("daq.modules", 0, &sc));
- CHECK_FALSE(sfdm.end("daq.instances", 1, &sc));
- CHECK(sfdm.begin("daq.instances", 2, &sc));
+ SECTION("empty module config")
+ {
+ // Empty module table entry should fail
+ CHECK(sfdm.begin("daq.modules", 1, &sc));
+ CHECK_FALSE(sfdm.end("daq.modules", 1, &sc));
+ }
+
+ CHECK(sfdm.begin("daq.modules", 2, &sc));
+
+ Value module_name("dump");
+ CHECK(sfdm.set("daq.modules.name", module_name, &sc));
- Value instance_id(static_cast<double>(5));
- CHECK(sfdm.set("daq.instances.id", instance_id, &sc));
+ Value mode_val("passive");
+ Parameter mode_param = { "mode", Parameter::PT_ENUM, "passive | inline | read-file", "passive", "DAQ module mode" };
+ mode_val.set(&mode_param);
+ CHECK(sfdm.set("daq.modules.mode", mode_val, &sc));
- Value instance_input_spec("instance_5_input");
- CHECK(sfdm.set("daq.instances.input_spec", instance_input_spec, &sc));
+ Value dump_var1("dump_var1=foo");
+ CHECK(sfdm.set("daq.modules.variables", dump_var1, &sc));
- Value instance_var1("instance5_var1=foo");
- Value instance_var2("instance5_var2");
- CHECK(sfdm.set("daq.instances.variables", instance_var1, &sc));
- CHECK(sfdm.set("daq.instances.variables", instance_var2, &sc));
+ Value dump_var2("dump_var2");
+ CHECK(sfdm.set("daq.modules.variables", dump_var2, &sc));
- CHECK(sfdm.end("daq.instances", 2, &sc));
- CHECK(sfdm.end("daq.instances", 0, &sc));
+ CHECK(sfdm.end("daq.modules", 2, &sc));
+ CHECK(sfdm.end("daq.modules", 0, &sc));
CHECK(sfdm.end("daq", 0, &sc));
- /* Validate the configuration */
- SFDAQConfig *cfg = sc.daq_config;
+ SECTION("validate sfdaq config")
+ {
+ /* Validate the configuration */
+ SFDAQConfig* cfg = sc.daq_config;
+ REQUIRE((cfg->module_dirs.size() == 2));
+ CHECK(cfg->module_dirs[0] == module_dir1.get_string());
+ CHECK(cfg->module_dirs[1] == module_dir2.get_string());
+
+ REQUIRE((cfg->inputs.size() == 3));
+ CHECK(cfg->inputs[0] == input1.get_string());
+ CHECK(cfg->inputs[1] == input2.get_string());
+ CHECK(cfg->inputs[2] == input3.get_string());
+
+ CHECK((cfg->mru_size == 6666));
+ CHECK((cfg->batch_size == 10));
+
+ REQUIRE(cfg->module_configs.size() == 1);
+ for (auto it : cfg->module_configs)
+ {
+ SFDAQModuleConfig* mcfg = it;
+ CHECK((mcfg->name == module_name.get_string()));
+ CHECK((mcfg->mode == SFDAQModuleConfig::SFDAQ_MODE_PASSIVE));
+ REQUIRE((mcfg->variables.size() == 2));
+ CHECK(mcfg->variables[0].first == "dump_var1");
+ CHECK(mcfg->variables[0].second == "foo");
+ CHECK(mcfg->variables[1].first == dump_var2.get_string());
+ CHECK(mcfg->variables[1].second.empty());
+ }
+ }
- REQUIRE((cfg->module_dirs.size() == 2));
- CHECK(cfg->module_dirs[0] == module_dir1.get_string());
- CHECK(cfg->module_dirs[1] == module_dir2.get_string());
+ SECTION("sfdaq command line config and overlay verification")
+ {
+ /* Secondary config to overlay from, for example, the command line */
+ SFDAQConfig overlay_cfg;
- CHECK(cfg->module_name == module_name.get_string());
+ overlay_cfg.add_module_dir("cli_module_dir");
+ overlay_cfg.add_input("cli_input");
+ overlay_cfg.set_mru_size(3333);
+ overlay_cfg.set_batch_size(12);
- CHECK(cfg->input_spec == input_spec.get_string());
+ SFDAQModuleConfig* cli_module_cfg = overlay_cfg.add_module_config("cli_module_name");
- REQUIRE((cfg->variables.size() == 3));
- CHECK(cfg->variables[0].first == "foo");
- CHECK(cfg->variables[0].second == "bar");
- CHECK(cfg->variables[1].first == "debug");
- CHECK(cfg->variables[1].second.empty());
- CHECK(cfg->variables[2].first == "hello");
- CHECK(cfg->variables[2].second == "world");
+ cli_module_cfg->set_variable("cli_module_variable=abc");
+ cli_module_cfg->mode = SFDAQModuleConfig::SFDAQ_MODE_READ_FILE;
- CHECK((cfg->mru_size == 6666));
+ SFDAQModuleConfig* cli_dump_cfg = overlay_cfg.add_module_config("dump");
- REQUIRE(cfg->instances.size() == 1);
- for (auto it : cfg->instances)
- {
- CHECK((it.first == 5));
- SFDAQInstanceConfig* icfg = it.second;
- CHECK(icfg->input_spec == instance_input_spec.get_string());
- REQUIRE((icfg->variables.size() == 2));
- CHECK(icfg->variables[0].first == "instance5_var1");
- CHECK(icfg->variables[0].second == "foo");
- CHECK(icfg->variables[1].first == instance_var2.get_string());
- CHECK(icfg->variables[1].second.empty());
- }
+ cli_dump_cfg->mode = SFDAQModuleConfig::SFDAQ_MODE_INLINE;
+ cli_dump_cfg->set_variable("dump_var3");
+ cli_dump_cfg->set_variable("dump_var4=bar");
+ cli_dump_cfg->set_variable("dump_var5=foo");
- /* Secondary config to overlay from, for example, the command line */
- SnortConfig sc2;
-
- sc2.daq_config->add_module_dir("cli_module_dir");
- sc2.daq_config->set_module_name("cli_module_name");
- sc2.daq_config->set_input_spec(nullptr);
- sc2.daq_config->set_input_spec("cli_input_spec");
- sc2.daq_config->set_variable("cli_global_variable=abc");
- sc2.daq_config->set_mru_size(3333);
- sc2.daq_config->set_input_spec(nullptr, 2);
- sc2.daq_config->set_input_spec("cli_instance_2_input", 2);
- sc2.daq_config->set_input_spec("cli_instance_5_input", 5);
- sc2.daq_config->set_variable("cli_instance_5_var1=def", 5);
-
- cfg->overlay(sc2.daq_config);
-
- REQUIRE(cfg->module_dirs.size() == 1);
- CHECK(cfg->module_dirs[0] == "cli_module_dir");
- CHECK(cfg->module_name == "cli_module_name");
- CHECK(cfg->input_spec == "cli_input_spec");
- REQUIRE(cfg->variables.size() == 1);
- CHECK(cfg->variables[0].first == "cli_global_variable");
- CHECK(cfg->variables[0].second == "abc");
- CHECK((cfg->mru_size == 3333));
- REQUIRE((cfg->instances.size() == 2));
- for (auto it : cfg->instances)
- {
- CHECK((it.first == 2 || it.first == 5));
- if (it.first == 2)
- {
- SFDAQInstanceConfig* icfg = it.second;
- CHECK(icfg->input_spec == "cli_instance_2_input");
- CHECK(icfg->variables.empty());
- }
- else if (it.first == 5)
+ SFDAQConfig* cfg = sc.daq_config;
+ cfg->overlay(&overlay_cfg);
+
+ REQUIRE(cfg->module_dirs.size() == 1);
+ CHECK(cfg->module_dirs[0] == "cli_module_dir");
+
+ REQUIRE((cfg->inputs.size() == 1));
+ CHECK(cfg->inputs[0] == "cli_input");
+
+ CHECK((cfg->mru_size == 3333));
+ CHECK((cfg->batch_size == 12));
+
+ REQUIRE(cfg->module_configs.size() == 2);
+ for (auto it : cfg->module_configs)
{
- SFDAQInstanceConfig* icfg = it.second;
- CHECK(icfg->input_spec == "cli_instance_5_input");
- REQUIRE(icfg->variables.size() == 1);
- CHECK(icfg->variables[0].first == "cli_instance_5_var1");
- CHECK(icfg->variables[0].second == "def");
+ SFDAQModuleConfig* mcfg = it;
+ CHECK((mcfg->name == "cli_module_name" or mcfg->name == "dump"));
+ if (mcfg->name == "cli_module_name")
+ {
+ CHECK(mcfg->mode == SFDAQModuleConfig::SFDAQ_MODE_READ_FILE);
+ REQUIRE((mcfg->variables.size() == 1));
+ CHECK(mcfg->variables[0].first == "cli_module_variable");
+ CHECK(mcfg->variables[0].second == "abc");
+ }
+ else if (mcfg->name == "dump")
+ {
+ CHECK(mcfg->mode == SFDAQModuleConfig::SFDAQ_MODE_INLINE);
+ REQUIRE((mcfg->variables.size() == 3));
+ CHECK(mcfg->variables[0].first == "dump_var3");
+ CHECK(mcfg->variables[0].second.empty());
+ CHECK(mcfg->variables[1].first == "dump_var4");
+ CHECK(mcfg->variables[1].second == "bar");
+ CHECK(mcfg->variables[2].first == "dump_var5");
+ CHECK(mcfg->variables[2].second == "foo");
+ }
}
}
}
-
#include "detection/detect.h"
#include "detection/detection_engine.h"
#include "log/messages.h"
-#include "main/snort.h"
+#include "main/analyzer.h"
#include "main/policy.h"
#include "mstring.h"
#define CHECKSUM_MODE_OPT__ICMP "icmp"
#define CHECKSUM_MODE_OPT__NO_ICMP "noicmp"
+using namespace snort;
+
static std::string lua_conf;
static std::string snort_conf_dir;
if (args == nullptr)
return CHECKSUM_FLAG__ALL;
- toks = snort::mSplit(args, " \t", 10, &num_toks, 0);
+ toks = mSplit(args, " \t", 10, &num_toks, 0);
for (i = 0; i < num_toks; i++)
{
if (strcasecmp(toks[i], CHECKSUM_MODE_OPT__ALL) == 0)
}
else
{
- snort::ParseError("unknown command line checksum option: %s.", toks[i]);
+ ParseError("unknown command line checksum option: %s.", toks[i]);
return ret_flags;
}
}
ret_flags = negative_flags;
}
- snort::mSplitFree(&toks, num_toks);
+ mSplitFree(&toks, num_toks);
return ret_flags;
}
void ConfigChecksumDrop(const char* args)
{
- NetworkPolicy* policy = snort::get_network_policy();
+ NetworkPolicy* policy = get_network_policy();
policy->checksum_drop = GetChecksumFlags(args);
}
void ConfigChecksumMode(const char* args)
{
- NetworkPolicy* policy = snort::get_network_policy();
+ NetworkPolicy* policy = get_network_policy();
policy->checksum_eval = GetChecksumFlags(args);
}
{
lua_conf = val;
SetSnortConfDir(lua_conf.c_str());
- snort::Snort::set_main_hook(snort::DetectionEngine::inspect);
+ Analyzer::set_main_hook(DetectionEngine::inspect);
}
void SetSnortConfDir(const char* file)
if ( RawBufferIface.is(L, 2) )
{
- RawData rd(&daq, get_data(RawBufferIface.get(L, 2)));
+ RawData rd(nullptr, &daq, get_data(RawBufferIface.get(L, 2)), get_data_length(RawBufferIface.get(L, 2)));
result = self.decode(rd, cd, dd);
}
else
{
size_t len = 0;
- RawData rd(
- &daq,
- reinterpret_cast<const uint8_t*>(
- luaL_checklstring(L, 2, &len)
- )
- );
+ const uint8_t* data = reinterpret_cast<const uint8_t*>(luaL_checklstring(L, 2, &len));
+ RawData rd(nullptr, &daq, data, len);
result = self.decode(rd, cd, dd);
}
#include "lua/lua_arg.h"
-static void set_fields(lua_State* L, int tindex, struct _daq_pkthdr& self)
+static void set_fields(lua_State* L, int tindex, DAQ_PktHdr_t& self)
{
Lua::Table table(L, tindex);
- table.get_field("caplen", self.caplen);
table.get_field("pktlen", self.pktlen);
table.get_field("ingress_index", self.ingress_index);
table.get_field("egress_index", self.egress_index);
// FIXIT-L do we want to be able to set the priv_ptr field?
}
-static void get_fields(lua_State* L, int tindex, struct _daq_pkthdr& self)
+static void get_fields(lua_State* L, int tindex, DAQ_PktHdr_t& self)
{
Lua::Table table(L, tindex);
- table.set_field("caplen", self.caplen);
table.set_field("pktlen", self.pktlen);
table.set_field("ingress_index", self.ingress_index);
table.set_field("egress_index", self.egress_index);
{ nullptr, nullptr }
};
-const struct Lua::TypeInterface<_daq_pkthdr> DAQHeaderIface =
+const struct Lua::TypeInterface<DAQ_PktHdr_t> DAQHeaderIface =
{
"DAQHeader",
methods,
#include "lua/lua_iface.h"
-struct _daq_pkthdr;
+struct _daq_pkt_hdr;
-extern const struct Lua::TypeInterface<_daq_pkthdr> DAQHeaderIface;
+extern const struct Lua::TypeInterface<_daq_pkt_hdr> DAQHeaderIface;
#endif
inline uint8_t* get_mutable_data(RawBuffer& rb)
{ return const_cast<uint8_t*>(get_data(rb)); }
+inline size_t get_data_length(RawBuffer& rb)
+{ return rb.size(); }
+
extern const struct Lua::TypeInterface<RawBuffer> RawBufferIface;
#endif
class IpsAction;
class IpsContext;
class Obfuscator;
+class SFDAQInstance;
/* packet status flags */
#define PKT_REBUILT_FRAG 0x00000001 /* is a rebuilt fragment */
#define PKT_FILE_EVENT_SET 0x00400000
#define PKT_IGNORE 0x00800000 /* this packet should be ignored, based on port */
#define PKT_RETRANSMIT 0x01000000 // packet is a re-transmitted pkt.
-#define PKT_UNUSED_FLAGS 0xfe000000
+#define PKT_RETRY 0x02000000 /* this packet is being re-evaluated from the internal retry queue */
+#define PKT_UNUSED_FLAGS 0xfc000000
#define PKT_TS_OFFLOADED 0x01
// FIXIT-M Consider moving ip_proto_next below `pkth`.
IpProtocol ip_proto_next; /* the protocol ID after IP and all IP6 extension */
bool disable_inspect;
- // nothing after this point is zeroed ...
+ // nothing after this point is zeroed by reset() ...
- // Everything beyond this point is set by PacketManager::decode()
- IpsContext* context; // set by control
+ IpsContext* context;
Active* active;
Active* active_inst;
IpsAction** action;
IpsAction* action_inst;
- const DAQ_PktHdr_t* pkth; // packet meta data
- const uint8_t* pkt; // raw packet data
+
+ DAQ_Msg_h daq_msg; // DAQ message this packet came from
+ SFDAQInstance* daq_instance; // DAQ instance the message came from
+
+ // Everything beyond this point is set by PacketManager::decode()
+ const DAQ_PktHdr_t* pkth; // packet meta data
+ const uint8_t* pkt; // raw packet data
+ uint32_t pktlen; // raw packet data length
// These are both set before PacketManager::decode() returns
const uint8_t* data; /* packet payload pointer */
bool is_rebuilt() const
{ return (packet_flags & (PKT_REBUILT_STREAM|PKT_REBUILT_FRAG)) != 0; }
+ bool is_retry() const
+ { return (packet_flags & PKT_RETRY) != 0; }
+
bool is_offloaded() const
{ return (ts_packet_flags & PKT_TS_OFFLOADED) != 0; }
"If this is an encapsulated layer, you must also set UNSURE_ENCAP"
" and SAVE_LAYER");
-RawData::RawData(const DAQ_PktHdr_t* h, const uint8_t* p)
-{
- pkth = h;
- data = p;
- len = h->caplen;
-}
-
//-------------------------------------------------------------------------
// Encode/Decode functions
//-------------------------------------------------------------------------
void PacketManager::decode(
- Packet* p, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt, bool cooked)
+ Packet* p, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt, uint32_t pktlen, bool cooked, bool retry)
{
Profile profile(decodePerfStats);
ProtocolIndex mapped_prot = CodecManager::grinder;
ProtocolId prev_prot_id = CodecManager::grinder_id;
- RawData raw(pkthdr, pkt);
+ RawData raw(p->daq_msg, pkthdr, pkt, pktlen);
CodecData codec_data(ProtocolId::FINISHED_DECODE);
if ( cooked )
p->reset();
p->pkth = pkthdr;
p->pkt = pkt;
+ p->pktlen = pktlen;
+ if (retry)
+ p->packet_flags |= PKT_RETRY;
layer::set_packet_pointer(p);
s_stats[total_processed]++;
// setup pkt capture header
DAQ_PktHdr_t* pkth = const_cast<DAQ_PktHdr_t*>(c->pkth);
- pkth->caplen = 0;
+ c->pktlen = 0;
pkth->pktlen = 0;
pkth->ts = p->pkth->ts;
// setup pkt capture header
DAQ_PktHdr_t* pkth = const_cast<DAQ_PktHdr_t*>(c->pkth);
- pkth->caplen = len;
+ c->pktlen = len;
pkth->pktlen = len;
pkth->ts = p->pkth->ts;
if ( !(p->packet_flags & PKT_MODIFIED) || (p->packet_flags & PKT_RESIZED) )
{
DAQ_PktHdr_t* pkth = const_cast<DAQ_PktHdr_t*>(p->pkth);
- pkth->caplen = len;
+ p->pktlen = len;
pkth->pktlen = len;
}
}
static void thread_term();
// decode this packet and set all relevant packet fields.
- static void decode(Packet*, const struct _daq_pkthdr*, const uint8_t*, bool cooked = false);
+ static void decode(Packet*, const struct _daq_pkt_hdr*, const uint8_t* pkt,
+ uint32_t pktlen, bool cooked = false, bool retry = false);
// update the packet's checksums and length variables. Call this function
// after Snort has changed any data in this packet
static void DCE2_SmbInjectDeletePdu(DCE2_SmbFileTracker* ftracker)
{
- Packet* inject_pkt = snort::Snort::get_packet();
+ Packet* inject_pkt = DetectionEngine::get_current_wire_packet();
Packet* p = DetectionEngine::get_current_packet();
if ( inject_pkt->flow != p->flow )
if (file_flows &&
file_flows->file_process(p, p->data, p->dsize, position(p), c->upload))
{
- const char* file_name = SFDAQ::get_interface_spec();
+ const char* file_name = SFDAQ::get_input_spec();
if (file_name)
file_flows->set_file_name((const uint8_t*)file_name, strlen(file_name));
}
#include "detection/detect.h"
#include "detection/detection_engine.h"
#include "log/messages.h"
-#include "main/snort.h"
+#include "main/analyzer.h"
#include "main/snort_config.h"
#include "memory/memory_cap.h"
#include "packet_io/active.h"
-#include "packet_io/sfdaq.h"
+#include "packet_io/sfdaq_config.h"
#include "profiler/profiler_defs.h"
#include "protocols/ipv4_options.h"
#include "time/timersub.h"
"Processing rebuilt packet:\n");
ip_stats.reassembles++;
- ip_stats.reassembled_bytes += dpkt->pkth->caplen;
+ ip_stats.reassembled_bytes += dpkt->pktlen;
#if defined(DEBUG_FRAG_EX) && defined(DEBUG_MSGS)
/*
DetectionEngine de;
de.set_encode_packet(p);
- snort::Snort::process_packet(dpkt, dpkt->pkth, dpkt->pkt, true);
+ Analyzer::get_local_analyzer()->process_rebuilt_packet(dpkt, dpkt->pkth, dpkt->pkt, dpkt->pktlen);
de.set_encode_packet(nullptr);
trace_log(stream_ip, "Done with rebuilt packet, marking rebuilt...\n");
}
ip_stats.total++;
- ip_stats.fragmented_bytes += p->pkth->caplen + 4; /* 4 for the CRC */
+ ip_stats.fragmented_bytes += p->pktlen + 4; /* 4 for the CRC */
DeepProfile profile(fragPerfStats);
}
}
- if ((uint16_t)fragLength > SFDAQ::get_snap_len())
+ if ((uint16_t)fragLength > SnortConfig::get_conf()->daq_config->get_mru_size())
{
trace_logf(stream_ip,
"Overly large fragment %d 0x%x 0x%x %d\n",
fragStart = p->data;
/* Just to double check */
- if (!fragLength or fragLength > SFDAQ::get_snap_len())
+ if (!fragLength or fragLength > SnortConfig::get_conf()->daq_config->get_mru_size())
{
trace_logf(stream_ip,
"Bad fragment length:%d(0x%x) off:0x%x(%d)\n",
if ( snort::PacketTracer::is_active() )
{
snort::PacketTracer::log("Packet was retransmitted and %s from the retry queue.\n",
- (p->pkth->flags & DAQ_PKT_FLAG_RETRY_PACKET) ? "is" : "is not");
+ p->is_retry() ? "is" : "is not");
}
// Mark the packet as being a re-transmit if it's not from the retry
// queue. That way we can avoid adding re-transmitted packets to
// the retry queue.
- if ( !(p->pkth->flags & DAQ_PKT_FLAG_RETRY_PACKET) )
+ if ( !p->is_retry() )
p->packet_flags |= PKT_RETRANSMIT;
}
{
if ( ( (int)( ( tsd.get_ts() - tns.peer_tracker->get_ts_last() ) + tns.paws_ts_fudge ) ) < 0 )
{
- if ( tsd.get_pkt()->pkth->flags & DAQ_PKT_FLAG_RETRY_PACKET )
+ if ( tsd.get_pkt()->is_retry() )
{
// Retry packets can legitimately have old timestamps
// in TCP options (if a re-transmit comes in before
#include "detection/detection_engine.h"
#include "log/log.h"
-#include "main/snort.h"
+#include "main/analyzer.h"
#include "memory/memory_cap.h"
#include "profiler/profiler.h"
#include "protocols/packet_manager.h"
NoProfile exclude(s5TcpFlushPerfStats);
- if ( !Snort::inspect(pdu) )
+ if ( !Analyzer::get_local_analyzer()->inspect_rebuilt(pdu) )
last_pdu = pdu;
else
last_pdu = nullptr;
show_rebuilt_packet(trs, pdu);
NoProfile profile_exclude(s5TcpFlushPerfStats);
- Snort::inspect(pdu);
+ Analyzer::get_local_analyzer()->inspect_rebuilt(pdu);
if ( trs.tracker->splitter )
trs.tracker->splitter->update();
memset(ph, 0, sizeof(*ph));
packet_gettimeofday(&ph->ts);
+ p->pktlen = 0;
p->data = nullptr;
p->dsize = 0;
#include "detection/detection_engine.h"
#include "detection/rules.h"
-#include "main/snort.h"
+#include "main/analyzer.h"
#include "memory/memory_cap.h"
#include "profiler/profiler_defs.h"
#include "protocols/packet.h"
up->packet_flags |= (p->packet_flags & (PKT_STREAM_EST|PKT_STREAM_UNEST_UNI));
trace_logf(stream_user, "detect[%d]\n", up->dsize);
- snort::Snort::inspect(up);
+ Analyzer::get_local_analyzer()->inspect_rebuilt(up);
}
int UserTracker::scan(Packet* p, uint32_t& flags)
void packet_time_update(const struct timeval* cur_tv)
{
- if ( !s_first_packet )
- s_first_packet = cur_tv->tv_sec;
+ if (timercmp(cur_tv, &s_recent_packet, >))
+ {
+ if ( !s_first_packet )
+ s_first_packet = cur_tv->tv_sec;
- s_recent_packet = *cur_tv;
+ s_recent_packet = *cur_tv;
+ }
}
uint32_t packet_first_time()
PegCount internal_whitelist;
PegCount idle;
PegCount rx_bytes;
+ PegCount skipped;
};
extern ProcessCount proc_stats;
else
{
const char* error = get_error(errno);
- ErrorMessage("Failed to create pid file %s, Error: %s",
+ ErrorMessage("Failed to create pid file %s, Error: %s\n",
SnortConfig::get_conf()->pid_filename.c_str(), error);
SnortConfig::get_conf()->pid_filename.clear();
}
if (group_id == -1 && user_id == -1)
return true;
- // FIXIT-L Move this check to Snort::drop_privileges()
- if (!SFDAQ::unprivileged())
- {
- ParseError("Cannot drop privileges - %s DAQ does not support unprivileged operation.\n", SFDAQ::get_type());
- return false;
- }
-
if (group_id != -1)
{
if (setgid(group_id) < 0)
config_binding.cc
config_checksums.cc
config_classification.cc
+ config_daq.cc
+ config_daq_mode.cc
+ config_daq_var.cc
config_decode_esp.cc
config_default_rule_state.cc
config_deleted.cc
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2018-2018 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// config_daq.cc author Carter Waxman <cwaxman@cisco.com>
+
+#include <sstream>
+#include <vector>
+
+#include "conversion_state.h"
+#include "helpers/converter.h"
+#include "helpers/s2l_util.h"
+
+namespace config
+{
+namespace
+{
+class Daq : public ConversionState
+{
+public:
+ Daq(Converter& c) : ConversionState(c) { }
+
+ bool convert(std::istringstream& data_stream) override;
+};
+} // namespace
+
+bool Daq::convert(std::istringstream& data_stream)
+{
+ bool retval = true;
+ std::string name;
+
+ if ( data_stream >> name )
+ {
+ table_api.open_top_level_table("daq");
+ table_api.open_table("modules");
+ table_api.open_table("");
+ table_api.add_option("name", name);
+ table_api.add_diff_option_comment("config daq:", "name");
+ table_api.close_table();
+ table_api.close_table();
+ table_api.close_table();
+ }
+
+ return retval;
+}
+
+/**************************
+ ******* A P I ***********
+ **************************/
+
+static ConversionState* ctor(Converter& c)
+{ return new Daq(c); }
+
+static const ConvertMap daq_api =
+{
+ "daq",
+ ctor,
+};
+
+const ConvertMap* daq_map = &daq_api;
+
+} // namespace config
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2018-2018 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// config_daq_mode.cc author Carter Waxman <cwaxman@cisco.com>
+
+#include <sstream>
+#include <vector>
+
+#include "conversion_state.h"
+#include "helpers/converter.h"
+#include "helpers/s2l_util.h"
+
+namespace config
+{
+namespace
+{
+class DaqMode : public ConversionState
+{
+public:
+ DaqMode(Converter& c) : ConversionState(c) { }
+ bool convert(std::istringstream& data_stream) override;
+};
+} // namespace
+
+bool DaqMode::convert(std::istringstream& data_stream)
+{
+ bool retval = true;
+ std::string mode;
+
+ if ( data_stream >> mode )
+ {
+ if ( mode == "read-file" or mode == "passive" or mode == "inline" )
+ {
+ table_api.open_top_level_table("daq");
+ table_api.open_table("modules");
+ table_api.open_table("");
+ table_api.add_option("mode", mode);
+ table_api.add_diff_option_comment("config daq_mode:", "mode");
+ table_api.close_table();
+ table_api.close_table();
+ table_api.close_table();
+ }
+ else
+ {
+ retval = false;
+ data_api.failed_conversion(data_stream, mode);
+ }
+ }
+
+ return retval;
+}
+
+/**************************
+ ******* A P I ***********
+ **************************/
+
+static ConversionState* ctor(Converter& c)
+{ return new DaqMode(c); }
+
+static const ConvertMap daq_mode_api =
+{
+ "daq_mode",
+ ctor,
+};
+
+const ConvertMap* daq_mode_map = &daq_mode_api;
+
+} // namespace config
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2018-2018 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// 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 along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// config_daq_var.cc author Carter Waxman <cwaxman@cisco.com>
+
+#include <sstream>
+
+#include "conversion_state.h"
+#include "helpers/converter.h"
+#include "helpers/s2l_util.h"
+
+namespace config
+{
+namespace
+{
+class DaqVar : public ConversionState
+{
+public:
+ DaqVar(Converter& c) : ConversionState(c) { }
+
+ bool convert(std::istringstream& data_stream) override;
+};
+} // namespace
+
+bool DaqVar::convert(std::istringstream& data_stream)
+{
+ bool retval = true;
+ std::string tmp, var;
+
+ while ( data_stream >> tmp )
+ var += tmp;
+
+ if ( !var.empty() )
+ {
+ table_api.open_top_level_table("daq");
+ table_api.open_table("modules");
+ table_api.open_table("");
+ table_api.open_table("variables");
+ table_api.add_option(var);
+ table_api.close_table();
+ table_api.add_diff_option_comment("config daq_var:", "variables");
+ table_api.close_table();
+ table_api.close_table();
+ table_api.close_table();
+ }
+
+ return retval;
+}
+
+/**************************
+ ******* A P I ***********
+ **************************/
+
+static ConversionState* ctor(Converter& c)
+{ return new DaqVar(c); }
+
+static const ConvertMap daq_var_api =
+{
+ "daq_var",
+ ctor,
+};
+
+const ConvertMap* daq_var_map = &daq_var_api;
+
+} // namespace config
+
const ConvertMap* disable_inline_init_failopen_map = &disable_inline_init_failopen_api;
-/*************************************************
- ***************** daq_mode *******************
- *************************************************/
-
-static const std::string daq_mode = "daq_mode";
-static const ConvertMap daq_mode_api =
-{
- daq_mode,
- deleted_ctor<& daq_mode>,
-};
-
-const ConvertMap* daq_mode_map = &daq_mode_api;
-
/*************************************************
************* decode_data_link ****************
*************************************************/
const ConvertMap* sidechannel_map = &sidechannel_api;
+/*************************************************
+ ***************** no_promisc *******************
+ *************************************************/
+
+static const std::string no_promisc = "no_promisc";
+static const ConvertMap no_promisc_api =
+{
+ no_promisc,
+ deleted_ctor<& no_promisc>,
+};
+
+const ConvertMap* no_promisc_map = &no_promisc_api;
+
} // namespace config
const ConvertMap* nopcre_map = &nopcre_api;
-/*************************************************
- ****************** no_promisc *****************
- *************************************************/
-
-static const std::string no_promisc = "no_promisc";
-static const ConvertMap no_promisc_api =
-{
- no_promisc,
- config_true_no_opt_ctor<& no_promisc, & daq>
-};
-
-const ConvertMap* no_promisc_map = &no_promisc_api;
-
/*************************************************
****************** obfuscate ******************
*************************************************/
*************************************************/
static const std::string alerts = "alerts";
-static const std::string daq = "daq";
static const std::string mode = "mode";
static const std::string packets = "packets";
static const std::string process = "process";
const ConvertMap* chroot_map = &chroot_api;
-/*************************************************
- ********************* daq *********************
- *************************************************/
-
-static const std::string module = "module";
-static const ConvertMap daq_api =
-{
- daq,
- config_string_ctor<& daq, & daq, & module>,
-};
-
-const ConvertMap* daq_map = &daq_api;
-
/*************************************************
******************* daq_dir *******************
*************************************************/
+static const std::string daq = "daq";
static const std::string daq_dir = "daq_dir";
static const std::string module_dirs = "module_dirs";
static const ConvertMap daq_dir_api =
const ConvertMap* daq_dir_map = &daq_dir_api;
-/*************************************************
- ******************* daq_var *******************
- *************************************************/
-
-static const std::string daq_var = "daq_var";
-static const std::string variables = "variables";
-static const ConvertMap daq_var_api =
-{
- daq_var,
- config_string_ctor<& daq_var, & daq, & variables, true>,
-};
-
-const ConvertMap* daq_var_map = &daq_var_api;
-
/*************************************************
******************* logdir ********************
*************************************************/
static inline Table* find_table(std::vector<Table*> vec, const std::string& name)
{
- if (name.empty())
- return nullptr;
-
for ( auto* t : vec)
if (name == t->get_name())
return t;