From patchwork Tue May 20 13:56:10 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxim Uvarov X-Patchwork-Id: 30450 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ig0-f200.google.com (mail-ig0-f200.google.com [209.85.213.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 2DE64202FE for ; Tue, 20 May 2014 13:56:55 +0000 (UTC) Received: by mail-ig0-f200.google.com with SMTP id uy17sf2262922igb.11 for ; Tue, 20 May 2014 06:56:54 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:date:message-id:subject :precedence:list-id:list-unsubscribe:list-archive:list-post :list-help:list-subscribe:mime-version:errors-to:sender :x-original-sender:x-original-authentication-results:mailing-list :content-type:content-transfer-encoding; bh=Ak+EaIagvqZC9kJmElWw1sw3jIZzBiqzqxIVROZuUMw=; b=fDz+yPiUxdpr5i7FGNTNh4vfxXLaQb4NOk3BBkw1NDTUIN0EZ1yn2j89vt+Gz9K/jA WWX+taenu+MXmwH7fawzfhzJ/gjH4ImWQIt53Xmn8NE6xHlGKJsgNk305AbQQnJUKk/s 337E8dMo/BA3Xd4osnlBqZieknxw3ohAGIhnRQXyxgE5pG7yZF2e+bw120InbocH88xe 2ekLm9Jw6TTZrftIfeUq/WdNrZ2JI4Wsvq7XUjSv5aO5BdIyMwVUzY8fA3GiAoRzzYzt h13EOIgQk7Qm27DIkaHf4XuDaoeN0jN7cQ+RmEuvD9O6qnbXtdTwci1iC+YkRbwOQLYq ysKw== X-Gm-Message-State: ALoCoQms0n3tb1OBxaXNb32Rl7nvMHmhSuBzC7hYYrX1QcRUomHwbwhxzZyhu0uKM/MUvvT3DiEY X-Received: by 10.182.176.8 with SMTP id ce8mr12556850obc.7.1400594214619; Tue, 20 May 2014 06:56:54 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.105.54 with SMTP id b51ls262917qgf.48.gmail; Tue, 20 May 2014 06:56:54 -0700 (PDT) X-Received: by 10.58.126.4 with SMTP id mu4mr37992414veb.0.1400594214305; Tue, 20 May 2014 06:56:54 -0700 (PDT) Received: from mail-ve0-f176.google.com (mail-ve0-f176.google.com [209.85.128.176]) by mx.google.com with ESMTPS id bz6si4357534vdb.180.2014.05.20.06.56.54 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 20 May 2014 06:56:54 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.128.176 as permitted sender) client-ip=209.85.128.176; Received: by mail-ve0-f176.google.com with SMTP id jz11so626985veb.7 for ; Tue, 20 May 2014 06:56:54 -0700 (PDT) X-Received: by 10.58.34.72 with SMTP id x8mr615092vei.61.1400594214063; Tue, 20 May 2014 06:56:54 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.221.72 with SMTP id ib8csp32725vcb; Tue, 20 May 2014 06:56:49 -0700 (PDT) X-Received: by 10.229.83.131 with SMTP id f3mr43125749qcl.19.1400594208947; Tue, 20 May 2014 06:56:48 -0700 (PDT) Received: from ip-10-141-164-156.ec2.internal (lists.linaro.org. [54.225.227.206]) by mx.google.com with ESMTPS id v10si10596174qat.70.2014.05.20.06.56.47 for (version=TLSv1 cipher=RC4-SHA bits=128/128); Tue, 20 May 2014 06:56:48 -0700 (PDT) Received-SPF: none (google.com: lng-odp-bounces@lists.linaro.org does not designate permitted sender hosts) client-ip=54.225.227.206; Received: from localhost ([127.0.0.1] helo=ip-10-141-164-156.ec2.internal) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1WmkWA-0004eB-F2; Tue, 20 May 2014 13:55:46 +0000 Received: from mail-lb0-f179.google.com ([209.85.217.179]) by ip-10-141-164-156.ec2.internal with esmtp (Exim 4.76) (envelope-from ) id 1WmkVn-0004e6-So for lng-odp@lists.linaro.org; Tue, 20 May 2014 13:55:24 +0000 Received: by mail-lb0-f179.google.com with SMTP id c11so413945lbj.24 for ; Tue, 20 May 2014 06:56:18 -0700 (PDT) X-Received: by 10.112.33.83 with SMTP id p19mr1573427lbi.90.1400594177776; Tue, 20 May 2014 06:56:17 -0700 (PDT) Received: from maxim-lap.localhost.onion ([92.39.133.154]) by mx.google.com with ESMTPSA id x9sm1477981lal.21.2014.05.20.06.56.15 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 20 May 2014 06:56:16 -0700 (PDT) From: root To: lng-odp@lists.linaro.org Date: Tue, 20 May 2014 17:56:10 +0400 Message-Id: <1400594170-32523-1-git-send-email-maxim.uvarov@linaro.org> X-Mailer: git-send-email 1.8.5.1.163.gd7aced9 X-Topics: patch Subject: [lng-odp] [APPS/PATCH] odp snort support initial version X-BeenThere: lng-odp@lists.linaro.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: , List-Help: , List-Subscribe: , MIME-Version: 1.0 Errors-To: lng-odp-bounces@lists.linaro.org Sender: lng-odp-bounces@lists.linaro.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: maxim.uvarov@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.128.176 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 From: Maxim Uvarov Signed-off-by: Maxim Uvarov --- Looke like it's not easy to understand and review this patch in mailing list. I filtered our original apps from patch. And merged it to the repo: https://git.linaro.org/lng/odp-apps.git/commit/4da44db4b18d8f2d4ada64727088333ff045df83 If there will suggestions and comments I will renew this commit. Initial work with smaller commits was done here: https://git.linaro.org/people/maxim.uvarov/odp-snort.git maybe my public tree is more clean for review then odp-apps.git. Best regards, Maxim. Makefile | 7 +- snort/Makefile | 65 + snort/README | 37 + .../0001-implement-odp-daq-module.patch | 477 ++ snort/download/daq-2.0.2.tar.gz | Bin 0 -> 474447 bytes snort/download/daq-2.0.2.tar.gz.md5 | 1 + snort/download/libdnet-1.11.tar.gz | Bin 0 -> 446233 bytes snort/download/snort-2.9.6.0.tar.gz | Bin 0 -> 5189146 bytes .../0001-Compile-Snort-as-static-library.patch | 114 + .../0002-remove-static-from-needed-functions.patch | 73 + .../0001-implement-odp_timer_disarm_all.patch | 63 + snort/odpsnort/Makefile | 47 + snort/odpsnort/odp_pktio.c | 673 +++ snort/odpsnort/odp_pktio.h | 1 + snort/odpsnort/snort.c | 5095 ++++++++++++++++++++ .../0001-add-dependancy-for-lrt.patch | 30 + 16 files changed, 6682 insertions(+), 1 deletion(-) create mode 100644 snort/Makefile create mode 100644 snort/README create mode 100644 snort/daq-patches/0001-implement-odp-daq-module.patch create mode 100644 snort/download/daq-2.0.2.tar.gz create mode 100644 snort/download/daq-2.0.2.tar.gz.md5 create mode 100644 snort/download/libdnet-1.11.tar.gz create mode 100644 snort/download/snort-2.9.6.0.tar.gz create mode 100644 snort/lib-patches/0001-Compile-Snort-as-static-library.patch create mode 100644 snort/lib-patches/0002-remove-static-from-needed-functions.patch create mode 100644 snort/odp-patches/0001-implement-odp_timer_disarm_all.patch create mode 100644 snort/odpsnort/Makefile create mode 100644 snort/odpsnort/odp_pktio.c create mode 100644 snort/odpsnort/odp_pktio.h create mode 100644 snort/odpsnort/snort.c create mode 100644 snort/snort-patches/0001-add-dependancy-for-lrt.patch --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: libpcap openvpn -all: openvpn libpcap +all: openvpn libpcap snort libpcap: odp make -C libpcap ODP_DIR=$(PWD)/odp.git @@ -8,10 +8,15 @@ libpcap: odp openvpn: odp make -C openvpn +snort: odp + make -C snort + odp: if [ ! -d odp.git ]; \ then git clone http://git.linaro.org/git/lng/odp.git odp.git; \ fi + cd odp.git; git reset --hard HEAD + cd odp.git; patch -N -p1 < ../snort/odp-patches/0001-implement-odp_timer_disarm_all.patch cd odp.git; make libs_install CFLAGS="-fPIC" distclean: --- /dev/null +++ b/snort/Makefile @@ -0,0 +1,65 @@ +.PHONY: all odp daq snort odpsnort +all: snort + +DAQ="daq-2.0.2" +daqprep: + rm -rf ${DAQ} + tar xpvfz ./download/daq-2.0.2.tar.gz + cd ${DAQ}; patch -p1 < ../daq-patches/0001-implement-odp-daq-module.patch + + +daq: daqprep libdnet + cd ${DAQ}; autoreconf + cd ${DAQ}; ./configure CFLAGS="-I${PWD}/../odp.git/build/include -g -O0" LDFLAGS="-g -L${PWD}/../odp.git/build/lib" + cd ${DAQ}; make + cd ${DAQ}; make install + + +snortprep: + rm -rf snort-2.9.6.0 + tar xpfz download/snort-2.9.6.0.tar.gz + +SNORT="snort-2.9.6.1-odp" +snort: snortprep daq + rm -rf $(SNORT) + cp -a snort-2.9.6.0 $(SNORT) + cd ${SNORT}; patch -p2 < ../snort-patches/0001-add-dependancy-for-lrt.patch + cd ${SNORT}; ./configure --disable-static-daq LDFLAGS="-lrt" + cd ${SNORT}; make + cd ${SNORT}; make install + +LIBDNET="libdnet-1.11" +libdnet: + #wget http://prdownloads.sourceforge.net/libdnet/libdnet-1.11.tar.gz + tar xpfz ./download/libdnet-1.11.tar.gz + cd ${LIBDNET}; ./configure + cd ${LIBDNET}; make + cd ${LIBDNET}; make install + +run: + export LD_LIBRARY_PATH="/usr/local/lib"; snort --daq-dir=${PWD}/daq-2.0.2/os-daq-modules/.libs/ --daq=odp -i eth0 -n 10 + +SNORT-lib="snort-2.9.6.0-lib" +snortlib: snortprep daq + rm -rf ${SNORT-lib} + cp -a snort-2.9.6.0 ${SNORT-lib} + cd ${SNORT-lib}; patch -p2 < ../snort-patches/0001-add-dependancy-for-lrt.patch + cd ${SNORT-lib}; patch -p1 < ../lib-patches/0001-Compile-Snort-as-static-library.patch + cd ${SNORT-lib}; patch -p1 < ../lib-patches/0002-remove-static-from-needed-functions.patch + cd ${SNORT-lib}; autoreconf + cd ${SNORT-lib}; ./configure --disable-static-daq LDFLAGS="-lrt" + cd ${SNORT-lib}; make + +odpsnort: snortlib + cd odpsnort; make + +all: libdnet daq snort odpsnort + +distclean: + rm -rf ${DAQ} + rm -rf ${SNORT} + rm -rf ${SNORT-lib} + rm -rf snort-2.9.6.1 + rm -rf snort-2.9.6.0 + rm -rf libdnet-1.11 + make -C odpsnort clean --- /dev/null +++ b/snort/README @@ -0,0 +1,37 @@ +--- Snort on Open Data Plane --- + +Directory has 2 different demos: + +1. Data Acquisition Module (DAQ) with ODP support. + +All magic happens inside shared library daq-odp.so which provides packet I/O to Snort application. DAQ module loaded as plug-in so no snort modification is needed. +(Because of odp uses lib rt I added librt to dependencies.). + +Compile: +make +Run: +make run + +Make run will execute following command (odp daq module, interface eth0, and 10 packets to capture): +snort --daq-dir=${PWD}/daq-2.0.2/os-daq-modules/.libs/ --daq=odp -i eth0 -n 10 + +2. Snort analyze function used in Open Data Plane applications. + +This example is opposite to the first one. I.e. it adds snort functionality to odp apps. For that Snort was built as static library with exported needed functions. +As base test/packet_io example was taken. Main thread does snort initialization then it starts several odp threads which do packet processing and feed Snort. +So this test has to scale across number of cpus and have some performance benefits according to regular single threaded snort. + +Compile: +make odpsnort +Run: +odpsnort/odp-snort + +Configuration: +Selection of number of threads and interfaces can be done in source code: +odpsnort/odp_pktio.c + args->appl.core_count = 1; + args->appl.if_count = 1; + args->appl.if_names = calloc(args->appl.if_count, sizeof(char *)); + args->appl.if_names[0] = strdup("eth0"); + + --- /dev/null +++ b/snort/daq-patches/0001-implement-odp-daq-module.patch @@ -0,0 +1,477 @@ +From 98f7d2a6eb53a17c855a40573300437ec8a3fe83 Mon Sep 17 00:00:00 2001 +From: root +Date: Mon, 19 May 2014 18:04:58 +0400 +Subject: [PATCH] implement odp daq module + +Signed-off-by: root +--- + configure.ac | 7 + + os-daq-modules/Makefile.am | 12 ++ + os-daq-modules/daq_odp.c | 409 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 428 insertions(+) + create mode 100644 os-daq-modules/daq_odp.c + +diff --git a/configure.ac b/configure.ac +index ae4f77f..5689dd3 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -107,6 +107,12 @@ else + DEFAULT_ENABLE=no + fi + ++# OpenDataPlane ++AC_ARG_ENABLE(odp-module, ++ AC_HELP_STRING([--disable-odp-module],[don't build the bundled OpenDataPlane module]), ++ [enable_odp_module="$enableval"], [enable_odp_module="$DEFAULT_ENABLE"]) ++AM_CONDITIONAL([BUILD_ODP_MODULE], [test "$enable_odp_module" = yes]) ++ + # AFPacket Module + AC_ARG_ENABLE(afpacket-module, + AC_HELP_STRING([--disable-afpacket-module],[don't build the bundled AFPacket module]), +@@ -276,4 +282,5 @@ echo "Build IPFW DAQ module...... : $enable_ipfw_module" + echo "Build IPQ DAQ module....... : $enable_ipq_module" + echo "Build NFQ DAQ module....... : $enable_nfq_module" + echo "Build PCAP DAQ module...... : $enable_pcap_module" ++echo "Build ODP DAQ module...... : $enable_odp_module" + echo +diff --git a/os-daq-modules/Makefile.am b/os-daq-modules/Makefile.am +index 37d6df3..cc61354 100644 +--- a/os-daq-modules/Makefile.am ++++ b/os-daq-modules/Makefile.am +@@ -14,6 +14,18 @@ libdaq_static_modules_la_CFLAGS = + libdaq_static_modules_la_LDFLAGS = -static -avoid-version + libdaq_static_modules_la_LIBADD = + ++if BUILD_ODP_MODULE ++if BUILD_SHARED_MODULES ++ pkglib_LTLIBRARIES += daq_odp.la ++ daq_odp_la_SOURCES = daq_odp.c ++ daq_odp_la_CFLAGS = -DBUILDING_SO ++ daq_odp_la_LDFLAGS = -module -export-dynamic -avoid-version -lrt -lodp -shared @XCCFLAGS@ ++ daq_odp_la_LIBADD = $(top_builddir)/sfbpf/libsfbpf.la ++endif ++ libdaq_static_modules_la_SOURCES += daq_odp.c ++ libdaq_static_modules_la_CFLAGS += -DBUILD_ODP_MODULE ++endif ++ + if BUILD_AFPACKET_MODULE + if BUILD_SHARED_MODULES + pkglib_LTLIBRARIES += daq_afpacket.la +diff --git a/os-daq-modules/daq_odp.c b/os-daq-modules/daq_odp.c +new file mode 100644 +index 0000000..aa6639e +--- /dev/null ++++ b/os-daq-modules/daq_odp.c +@@ -0,0 +1,409 @@ ++/* ++ ** Copyright (c) 2014, Linaro Limited ++ ** All rights reserved. ++ ** ++ ** SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "daq_api.h" ++#include "sfbpf.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_WORKERS 1 ++#define SHM_PKT_POOL_SIZE (512*2048) ++#define SHM_PKT_POOL_BUF_SIZE 1856 ++#define MAX_PKT_BURST 16 ++#define ODP_DEBUG 1 ++ ++static unsigned long debug_cnt = 0; ++ ++typedef struct _odp_context ++{ ++ volatile int break_loop; ++ DAQ_Stats_t stats; ++ DAQ_State state; ++ odp_queue_t inq_def; ++ odp_pktio_t pktio; ++ int snaplen; ++ char *device; ++ char errbuf[256]; ++} ODP_Context_t; ++ ++static int odp_daq_initialize(const DAQ_Config_t *config, void **ctxt_ptr, char *errbuf, size_t errlen) ++{ ++ ODP_Context_t *odpc; ++ int rval = DAQ_ERROR; ++ int thr_id; ++ int i; ++ ++ odp_buffer_pool_t pkt_pool; ++ odp_buffer_pool_t pool; ++ odp_pktio_t pktio; ++ odp_pktio_params_t params; ++ socket_params_t *sock_params = ¶ms.sock_params; ++ odp_queue_param_t qparam; ++ char inq_name[ODP_QUEUE_NAME_LEN]; ++ odp_packet_t pkt; ++ odp_buffer_t buf; ++ int ret; ++ void *pool_base; ++ ++ rval = DAQ_ERROR; ++ ++ printf("%s()\n", __func__); ++ odpc = calloc(1, sizeof(ODP_Context_t)); ++ if (!odpc) ++ { ++ snprintf(errbuf, errlen, "%s: Couldn't allocate memory for the new ODP context!", __FUNCTION__); ++ rval = DAQ_ERROR_NOMEM; ++ goto err; ++ } ++ ++ odpc->device = strdup(config->name); ++ if (!odpc->device) ++ { ++ snprintf(errbuf, errlen, "%s: Couldn't allocate memory for the device string!", __FUNCTION__); ++ rval = DAQ_ERROR_NOMEM; ++ goto err; ++ } ++ ++ *ctxt_ptr = odpc; ++ ++ /* Init ODP before calling anything else */ ++ if (odp_init_global()) { ++ ODP_ERR("Error: ODP global init failed.\n"); ++ goto err; ++ } ++ ++ /* Init this thread */ ++ thr_id = odp_thread_create(0); ++ odp_init_local(thr_id); ++ ++ /* Create packet pool */ ++ pool_base = odp_shm_reserve("shm_packet_pool", ++ SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE); ++ if (pool_base == NULL) { ++ ODP_ERR("Error: packet pool mem alloc failed.\n"); ++ goto err; ++ } ++ ++ pool = odp_buffer_pool_create("packet_pool", pool_base, ++ SHM_PKT_POOL_SIZE, ++ SHM_PKT_POOL_BUF_SIZE, ++ ODP_CACHE_LINE_SIZE, ++ ODP_BUFFER_TYPE_PACKET); ++ if (pool == ODP_BUFFER_POOL_INVALID) { ++ ODP_ERR("Error: packet pool create failed.\n"); ++ exit(EXIT_FAILURE); ++ } ++ odpc->snaplen = SHM_PKT_POOL_BUF_SIZE; ++ odp_buffer_pool_print(pool); ++ ++ /* Open a packet IO instance for this thread */ ++ sock_params->type = ODP_PKTIO_TYPE_SOCKET_MMAP; ++ sock_params->fanout = 0; ++ ++ odpc->pktio = odp_pktio_open(odpc->device, pool, ¶ms); ++ if (odpc->pktio == ODP_PKTIO_INVALID) { ++ ODP_ERR(" [%02i] Error: pktio create failed\n", 1 /*thr*/); ++ goto err; ++ } ++ ++ /* ++ * Create and set the default INPUT queue associated with the 'pktio' ++ * resource ++ */ ++ qparam.sched.prio = ODP_SCHED_PRIO_DEFAULT; ++ qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC; ++ qparam.sched.group = ODP_SCHED_GROUP_DEFAULT; ++ snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", (int)odpc->pktio); ++ inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0'; ++ ++ odpc->inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, &qparam); ++ if (odpc->inq_def == ODP_QUEUE_INVALID) { ++ ODP_ERR(" [%02i] Error: pktio queue creation failed\n", 1 /*thr*/); ++ goto err; ++ } ++ ++ ret = odp_pktio_inq_setdef(odpc->pktio, odpc->inq_def); ++ if (ret != 0) { ++ ODP_ERR(" [%02i] Error: default input-Q setup\n", 1 /*thr*/); ++ goto err; ++ } ++ ++ odpc->state = DAQ_STATE_INITIALIZED; ++ ++ printf("%s() DAQ_SUCCESS.\n\n", __func__); ++ return DAQ_SUCCESS; ++err: ++ ++ return rval; ++} ++ ++static int odp_daq_set_filter(void *handle, const char *filter) ++{ ++ printf("%s()\n", __func__); ++ return DAQ_SUCCESS; ++} ++ ++static int odp_daq_start(void *handle) ++{ ++ ODP_Context_t *odpc = (ODP_Context_t *) handle; ++ if (!odpc) ++ return DAQ_ERROR_NOCTX; ++ ++ odpc->state = DAQ_STATE_STARTED; ++ return DAQ_SUCCESS; ++} ++ ++static const DAQ_Verdict verdict_translation_table[MAX_DAQ_VERDICT] = { ++ DAQ_VERDICT_PASS, /* DAQ_VERDICT_PASS */ ++ DAQ_VERDICT_BLOCK, /* DAQ_VERDICT_BLOCK */ ++ DAQ_VERDICT_PASS, /* DAQ_VERDICT_REPLACE */ ++ DAQ_VERDICT_PASS, /* DAQ_VERDICT_WHITELIST */ ++ DAQ_VERDICT_BLOCK, /* DAQ_VERDICT_BLACKLIST */ ++ DAQ_VERDICT_PASS /* DAQ_VERDICT_IGNORE */ ++}; ++ ++static int odp_daq_acquire(void *handle, int cnt, DAQ_Analysis_Func_t callback, DAQ_Meta_Func_t metaback, void *user) ++{ ++ ODP_Context_t *odpc; ++ DAQ_PktHdr_t daqhdr; ++ DAQ_Verdict verdict; ++ const uint8_t *data; ++ ++ int thr_id; ++ odp_packet_t pkt; ++ odp_buffer_t buf; ++ int ret; ++ odp_buffer_pool_t pkt_pool; ++ odp_pktio_params_t params; ++ odp_pktio_t pktio; ++ ++ int i; ++ odp_packet_t pkt_tbl[MAX_PKT_BURST]; ++ int pkts; ++ ++ odpc = (ODP_Context_t *) handle; ++ if (!odpc) ++ return 0; ++ ++ if (odpc->state != DAQ_STATE_STARTED) ++ return 0; ++ ++ while (1) ++ { ++ /* Has breakloop() been called? */ ++ if (odpc->break_loop) ++ { ++ odpc->break_loop = 0; ++ printf("%s() BREAK LOOP\n", __func__); ++ return 0; ++ } ++ ++ pkts = odp_pktio_recv(odpc->pktio, pkt_tbl, MAX_PKT_BURST); ++ if (pkts <= 0) { ++ return; ++ } ++ ++ printf("got %d packets\n", pkts); ++ ++ for (i = 0; i < pkts; ++i) { ++ pkt = pkt_tbl[i]; ++ ++ data = odp_packet_l2(pkt); ++ if (!data) { ++ printf("no l2 offset, packet dropped\n"); ++ continue; ++ } ++ ++ verdict = DAQ_VERDICT_PASS; ++ ++ gettimeofday(&daqhdr.ts, NULL); ++ daqhdr.caplen = odp_buffer_size(pkt); ++ ++ printf("%s() odp recieved packet len %d.\n", __func__, odp_packet_get_len(pkt)); ++ ++ daqhdr.pktlen = odp_packet_get_len(pkt); ++ daqhdr.ingress_index = 0; ++ daqhdr.egress_index = DAQ_PKTHDR_UNKNOWN; ++ daqhdr.ingress_group = DAQ_PKTHDR_UNKNOWN; ++ daqhdr.egress_group = DAQ_PKTHDR_UNKNOWN; ++ daqhdr.flags = 0; ++ daqhdr.opaque = 0; ++ daqhdr.priv_ptr = NULL; ++ daqhdr.address_space_id = 0; ++ ++ if (callback) ++ { ++ verdict = callback(user, &daqhdr, data); // call back with pointer to data and daqhdr ++ if (verdict >= MAX_DAQ_VERDICT) ++ verdict = DAQ_VERDICT_PASS; ++ odpc->stats.verdicts[verdict]++; ++ verdict = verdict_translation_table[verdict]; ++ printf("opd processed packet %ld\n", odpc->stats.verdicts[verdict]); ++ } ++ } ++ ++ if (pkts > 0) { ++ printf("pkts > 0, return\n"); ++ return 0; ++ } ++ } ++ return 0; ++} ++ ++static int odp_daq_inject(void *handle, const DAQ_PktHdr_t *hdr, const uint8_t *packet_data, uint32_t len, int reverse) ++{ ++ return DAQ_SUCCESS; ++} ++ ++static int odp_daq_breakloop(void *handle) ++{ ++ ODP_Context_t *odpc = (ODP_Context_t *) handle; ++ ++ odpc->break_loop = 1; ++ return DAQ_SUCCESS; ++} ++ ++static int odp_daq_stop(void *handle) ++{ ++ ODP_Context_t *odpc = (ODP_Context_t *) handle; ++ ++ odpc->break_loop = 1; ++ odp_timer_disarm_all(); ++ ++ return DAQ_SUCCESS; ++} ++ ++static void odp_daq_shutdown(void *handle) ++{ ++ odp_timer_disarm_all(); ++} ++ ++static DAQ_State odp_daq_check_status(void *handle) ++{ ++ ODP_Context_t *odpc = (ODP_Context_t *) handle; ++ ++ if (!odpc) { ++ printf("%s() odpc is not allocated\n"); ++ return DAQ_STATE_UNINITIALIZED; ++ } ++ ++ //printf("%s()\n", __func__); ++ return odpc->state; ++} ++ ++static int odp_daq_get_stats(void *handle, DAQ_Stats_t *stats) ++{ ++ ODP_Context_t *odpc = (ODP_Context_t *) handle; ++ ++ memcpy(stats, &odpc->stats, sizeof(DAQ_Stats_t)); ++ return DAQ_SUCCESS; ++} ++ ++static void odp_daq_reset_stats(void *handle) ++{ ++ //ODP_Context_t *odpc = (ODP_Context_t *) handle; ++} ++ ++static int odp_daq_get_snaplen(void *handle) ++{ ++ ODP_Context_t *odpc = (ODP_Context_t *) handle; ++ ++ if (odpc) ++ return odpc->snaplen; ++ ++ return 1500; ++} ++ ++static uint32_t odp_daq_get_capabilities(void *handle) ++{ ++ return DAQ_CAPA_BLOCK | DAQ_CAPA_REPLACE | DAQ_CAPA_INJECT | /*DAQ_CAPA_UNPRIV_START |*/ DAQ_CAPA_BREAKLOOP | DAQ_CAPA_BPF | DAQ_CAPA_DEVICE_INDEX; ++} ++ ++static int odp_daq_get_datalink_type(void *handle) ++{ ++ return DLT_EN10MB; ++} ++ ++static const char *odp_daq_get_errbuf(void *handle) ++{ ++ ODP_Context_t *odpc = (ODP_Context_t *) handle; ++ ++ return odpc->errbuf; ++} ++ ++static void odp_daq_set_errbuf(void *handle, const char *string) ++{ ++ ODP_Context_t *odpc = (ODP_Context_t *) handle; ++ ++ if (!string) ++ return; ++ ++ DPE(odpc->errbuf, "%s", string); ++ return; ++} ++ ++static int odp_daq_get_device_index(void *handle, const char *string) ++{ ++ return DAQ_ERROR_NOTSUP; ++} ++ ++#ifdef BUILDING_SO ++DAQ_SO_PUBLIC const DAQ_Module_t DAQ_MODULE_DATA = ++#else ++const DAQ_Module_t afpacket_daq_module_data = ++#endif ++{ ++ .api_version = DAQ_API_VERSION, ++ .module_version = 1, ++ .name = "odp", ++ .type = DAQ_TYPE_INTF_CAPABLE | DAQ_TYPE_INLINE_CAPABLE | DAQ_TYPE_MULTI_INSTANCE, ++ .initialize = odp_daq_initialize, ++ .set_filter = odp_daq_set_filter, ++ .start = odp_daq_start, ++ .acquire = odp_daq_acquire, ++ .inject = odp_daq_inject, ++ .breakloop = odp_daq_breakloop, ++ .stop = odp_daq_stop, ++ .shutdown = odp_daq_shutdown, ++ .check_status = odp_daq_check_status, ++ .get_stats = odp_daq_get_stats, ++ .reset_stats = odp_daq_reset_stats, ++ .get_snaplen = odp_daq_get_snaplen, ++ .get_capabilities = odp_daq_get_capabilities, ++ .get_datalink_type = odp_daq_get_datalink_type, ++ .get_errbuf = odp_daq_get_errbuf, ++ .set_errbuf = odp_daq_set_errbuf, ++ .get_device_index = odp_daq_get_device_index, ++ .modify_flow = NULL, ++ .hup_prep = NULL, ++ .hup_apply = NULL, ++ .hup_post = NULL, ++}; +-- +1.8.5.1.163.gd7aced9 + --- /dev/null +++ b/snort/download/daq-2.0.2.tar.gz.md5 @@ -0,0 +1 @@ +865bf9b750a2a2ca632591a3c70b0ea0 \ No newline at end of file --- /dev/null +++ b/snort/lib-patches/0001-Compile-Snort-as-static-library.patch @@ -0,0 +1,114 @@ +From 3e23b5c31acc1759b1ed2aabd518964390f16c89 Mon Sep 17 00:00:00 2001 +From: Maxim Uvarov +Date: Wed, 16 Apr 2014 18:15:29 +0400 +Subject: [PATCH 1/2] Compile Snort as static library + +Compile Snort as static library to use it's analyze functions +in other applications. +Signed-off-by: Maxim Uvarov +--- + src/Makefile.am | 40 +++++++++++++++++++++------------------- + src/snort.c | 8 ++------ + 2 files changed, 23 insertions(+), 25 deletions(-) + +diff --git a/src/Makefile.am b/src/Makefile.am +index 1c1f826..f683dee 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -1,13 +1,13 @@ + ## $Id$ + AUTOMAKE_OPTIONS=foreign no-dependencies + +-bin_PROGRAMS = snort ++noinst_LIBRARIES = libsnort.a + + if BUILD_SNPRINTF + SNPRINTF_SOURCES = snprintf.c snprintf.h + endif + +-snort_SOURCES = cdefs.h \ ++libsnort_a_SOURCES = cdefs.h \ + event.h \ + generators.h \ + sf_protocols.h \ +@@ -62,20 +62,6 @@ rule_option_types.h \ + sfdaq.c sfdaq.h \ + idle_processing.c idle_processing.h idle_processing_funcs.h + +-snort_LDADD = output-plugins/libspo.a \ +-detection-plugins/libspd.a \ +-dynamic-plugins/libdynamic.a \ +-dynamic-output/plugins/liboutput.a \ +-preprocessors/libspp.a \ +-parser/libparser.a \ +-target-based/libtarget_based.a \ +-preprocessors/HttpInspect/libhttp_inspect.a \ +-preprocessors/Stream5/libstream5.a \ +-sfutil/libsfutil.a \ +-control/libsfcontrol.a \ +-file-process/libfileAPI.a \ +-file-process/libs/libfile.a +- + if BUILD_DYNAMIC_EXAMPLES + EXAMPLES_DIR = dynamic-examples + endif +@@ -85,9 +71,25 @@ SUBDIRS = sfutil win32 output-plugins detection-plugins dynamic-plugins preproce + + INCLUDES = @INCLUDES@ + ++libsnort_a_LIBADD = $(wildcard output-plugins/*.o) \ ++$(wildcard detection-plugins/*.o) \ ++$(wildcard dynamic-plugins/*.o) \ ++$(wildcard dynamic-output/plugins/*.o) \ ++$(wildcard dynamic-output/*/*.o) \ ++$(wildcard preprocessors/*.o) \ ++$(wildcard parser/*.o) \ ++$(wildcard target-based/*.o) \ ++$(wildcard preprocessors/HttpInspect/*/*.o) \ ++$(wildcard preprocessors/Stream5/*.o) \ ++$(wildcard sfutil/*.o) \ ++$(wildcard control/*.o) \ ++$(wildcard file-process/*.o) \ ++$(wildcard file-process/libs/*.o) ++ ++ + if BUILD_SIDE_CHANNEL +-snort_LDADD += \ +-side-channel/libsidechannel.a \ +-side-channel/plugins/libsscm.a ++libsnort_a_LIBADD += \ ++$(wildcard side-channel/*.o) \ ++$(wildcard side-channel/plugins/*.o) + SUBDIRS += side-channel + endif +diff --git a/src/snort.c b/src/snort.c +index 0280107..ce5c52e 100644 +--- a/src/snort.c ++++ b/src/snort.c +@@ -775,14 +775,9 @@ static int InlineFailOpen (void) + * Returns: 0 => normal exit, 1 => exit on error + * + */ ++#if 0 + int main(int argc, char *argv[]) + { +- /* hack to add deps to -lrt for timer_create() and friends from odp */ +- static volatile int link_rt = 0; +- timer_t timerid = 0; +- if (link_rt) +- timer_settime(timerid, 0, NULL, NULL); +- + #if defined(WIN32) && defined(ENABLE_WIN32_SERVICE) + /* Do some sanity checking, because some people seem to forget to + * put spaces between their parameters +@@ -808,6 +803,7 @@ int main(int argc, char *argv[]) + + return SnortMain(argc, argv); + } ++#endif + + /* + * +-- +1.7.9.5 + --- /dev/null +++ b/snort/lib-patches/0002-remove-static-from-needed-functions.patch @@ -0,0 +1,73 @@ +From 71aeb1a6bbda6464b717565aa4a1e3126cb59f1c Mon Sep 17 00:00:00 2001 +From: Maxim Uvarov +Date: Wed, 16 Apr 2014 18:16:57 +0400 +Subject: [PATCH 2/2] remove static from needed functions + +Signed-off-by: Maxim Uvarov +--- + src/snort.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/src/snort.c b/src/snort.c +index ce5c52e..5e5060a 100644 +--- a/src/snort.c ++++ b/src/snort.c +@@ -485,7 +485,7 @@ static void InitProtoNames(void); + static const char* GetPacketSource(char**); + + static void CleanExit(int); +-static void SnortInit(int, char **); ++void SnortInit(int, char **); + static void InitPidChrootAndPrivs(pid_t); + static void ParseCmdLine(int, char **); + static int ShowUsage(char *); +@@ -515,8 +515,8 @@ static void FreeReferences(ReferenceSystemNode *); + static void FreePlugins(SnortConfig *); + static void FreePreprocessors(SnortConfig *); + +-static void SnortUnprivilegedInit(void); +-static int SetPktProcessor(void); ++void SnortUnprivilegedInit(void); ++int SetPktProcessor(void); + static void PacketLoop(void); + #if 0 + static char * ConfigFileSearch(void); +@@ -1618,7 +1618,7 @@ static Packet s_packet; + static DAQ_PktHdr_t s_pkth; + static uint8_t s_data[65536]; + +-static DAQ_Verdict PacketCallback( ++/*static*/ DAQ_Verdict PacketCallback( + void* user, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt) + { + int inject = 0; +@@ -1779,7 +1779,7 @@ static DAQ_Verdict PacketCallback( + return verdict; + } + +-static void PrintPacket(Packet *p) ++void PrintPacket(Packet *p) + { + if (p->iph != NULL) + { +@@ -2989,7 +2989,7 @@ static void ParseCmdLine(int argc, char **argv) + */ + // TBD add GetDecoder(dlt) to decode module and hide all + // protocol decoder functions. +-static int SetPktProcessor(void) ++int SetPktProcessor(void) + { + const char* slink = NULL; + const char* extra = NULL; +@@ -5162,7 +5162,7 @@ static DAQ_Verdict IgnoreCallback ( + // packet passing is done by the driver/hardware. the goal then is to put as + // much initialization stuff in SnortInit() as possible and to restrict this + // function to those things that depend on DAQ startup or non-root user/group. +-static void SnortUnprivilegedInit(void) ++void SnortUnprivilegedInit(void) + { + #ifdef ACTIVE_RESPONSE + // this depends on instantiated daq capabilities +-- +1.7.9.5 + --- /dev/null +++ b/snort/odp-patches/0001-implement-odp_timer_disarm_all.patch @@ -0,0 +1,63 @@ +From 943e815797f886580354f050e7316306c032335c Mon Sep 17 00:00:00 2001 +From: Maxim Uvarov +Date: Wed, 9 Apr 2014 20:38:13 +0400 +Subject: [ODP/PATCH] implement odp_timer_disarm_all() + +Implement function to disarm all timers. Needed in case of +normal exit from application. +Signed-off-by: Maxim Uvarov +--- + platform/linux-generic/include/odp_internal.h | 1 + + platform/linux-generic/source/odp_timer.c | 24 ++++++++++++++++++++++++ + 2 files changed, 25 insertions(+) + +diff --git a/platform/linux-generic/include/odp_internal.h b/platform/linux-generic/include/odp_internal.h +index fb3be79..9b0769e 100644 +--- a/platform/linux-generic/include/odp_internal.h ++++ b/platform/linux-generic/include/odp_internal.h +@@ -38,6 +38,7 @@ int odp_schedule_init_global(void); + int odp_schedule_init_local(void); + + int odp_timer_init_global(void); ++int odp_timer_disarm_all(void); + + #ifdef __cplusplus + } +diff --git a/platform/linux-generic/source/odp_timer.c b/platform/linux-generic/source/odp_timer.c +index 6fb5025..98ffde3 100644 +--- a/platform/linux-generic/source/odp_timer.c ++++ b/platform/linux-generic/source/odp_timer.c +@@ -217,6 +217,30 @@ int odp_timer_init_global(void) + return 0; + } + ++int odp_timer_disarm_all(void) ++{ ++ int timers; ++ struct itimerspec ispec; ++ ++ timers = odp_atomic_load_int(&odp_timer.num_timers); ++ ++ ispec.it_interval.tv_sec = 0; ++ ispec.it_interval.tv_nsec = 0; ++ ispec.it_value.tv_sec = 0; ++ ispec.it_value.tv_nsec = 0; ++ ++ for (; timers >= 0; timers--) { ++ if (timer_settime(odp_timer.timer[timers].timerid, ++ 0, &ispec, NULL)) { ++ ODP_DBG("Timer reset failed\n"); ++ return -1; ++ } ++ odp_atomic_fetch_sub_int(&odp_timer.num_timers, 1); ++ } ++ ++ return 0; ++} ++ + odp_timer_t odp_timer_create(const char *name, odp_buffer_pool_t pool, + uint64_t resolution, uint64_t min_tmo, + uint64_t max_tmo) +-- +1.8.5.1.163.gd7aced9 + --- /dev/null +++ b/snort/odpsnort/Makefile @@ -0,0 +1,47 @@ +SNORT=$(PWD)/../snort-2.9.6.0-lib +CFLAGS += -I/$(SNORT)/src +LDFLAGS += -L/$(SNORT)/src +LDFLAGS += -L/$(SNORT)/src/dynamic-plugins + +DAQ=$(PWD)/../daq-2.0.2 +DAQ_LIB_DIR = "$(DAQ)/api/.libs" +LDFLAGS += "-L$(DAQ_LIB_DIR)" + +DAQ_LIB = "$(DAQ)/api/.libs/libdaq.a" + +DNET_LIB_DIR = "/usr/local/lib" +LDFLAGS += "-L$(DNET_LIB_DIR)" + +INC = "-I$(SNORT)/src/sfutil" +INC += "-I$(SNORT)/src/preprocessors" +INC += "-I$(SNORT)/src/dynamic-preprocessors/include" +INC += "-I$(SNORT)/src/detection-plugins" +INC += "-I$(SNORT)/src/target-based" +INC += "-I$(SNORT)/src/control" +INC += "-I$(SNORT)/src/file-process" +INC += "-I$(SNORT)/src/file-process/libs" +INC += "-I$(SNORT)/src/preprocessors/Stream5" +INC += "-I$(SNORT)" + +ODP_DIR = $(PWD)/../../odp.git +ODP_LIB = $(ODP_DIR)/build/lib/libodp.a +ODP_CFLAGS += -I$(ODP_DIR)/include +ODP_CFLAGS += -I$(ODP_DIR)/platform/linux-generic/include +ODP_CFLAGS += -I$(ODP_DIR)/platform/linux-generic/include/api + +LDFLAGS += $(ODP_LIB) + +DAQ = $(PWD)/../daq-2.0.2 +ODP_CFLAGS += -I$(DAQ) + +all: + gcc -c -O0 -g snort.c ${CFLAGS} ${LDFLAGS} $(INC) -o snort.o + gcc -c -O0 -g -pthread $(ODP_CFLAGS) odp_pktio.c -o odp_pktio.o + gcc snort.o odp_pktio.o ${CFLAGS} ${LDFLAGS} $(INC) -g -O0 -lsnort -lz -lpcap -pthread -lpcre -lssl -lcrypto -lm -ldnet ${DAQ_LIB} -lrt -o odp-snort + +clean: + rm -rf odp-snort *.o +run: + export LD_LIBRARY_PATH="/usr/local/lib";./odp-snort -i eth0 + + --- /dev/null +++ b/snort/odpsnort/odp_pktio.c @@ -0,0 +1,673 @@ +/* Copyright (c) 2013, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file + * + * @example odp_example_pktio.c ODP basic packet IO loopback test application + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Snort */ +#include + +#define MAX_WORKERS 32 +#define SHM_PKT_POOL_SIZE (512*2048) +#define SHM_PKT_POOL_BUF_SIZE 1856 +#define MAX_PKT_BURST 16 + +#define APPL_MODE_PKT_BURST 0 +#define APPL_MODE_PKT_QUEUE 1 + +#define PRINT_APPL_MODE(x) printf("%s(%i)\n", #x, (x)) + +/** Get rid of path in filename - only for unix-type paths using '/' */ +#define NO_PATH(file_name) (strrchr((file_name), '/') ? \ + strrchr((file_name), '/') + 1 : (file_name)) +/** + * Parsed command line application arguments + */ +typedef struct { + int core_count; + int if_count; /**< Number of interfaces to be used */ + char **if_names; /**< Array of pointers to interface names */ + int mode; /**< Packet IO mode */ + int type; /**< Packet IO type */ + int fanout; /**< Packet IO fanout */ + odp_buffer_pool_t pool; /**< Buffer pool for packet IO */ +} appl_args_t; + +/** + * Thread specific arguments + */ +typedef struct { + char *pktio_dev; /**< Interface name to use */ + odp_buffer_pool_t pool; /**< Buffer pool for packet IO */ + int mode; /**< Thread mode */ + int type; /**< Thread i/o type */ + int fanout; /**< Thread i/o fanout */ +} thread_args_t; + +/** + * Grouping of both parsed CL args and thread specific args - alloc together + */ +typedef struct { + /** Application (parsed) arguments */ + appl_args_t appl; + /** Thread specific arguments */ + thread_args_t thread[MAX_WORKERS]; +} args_t; + +/** Global pointer to args */ +static args_t *args; + +/* helper funcs */ +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len); +static void swap_pkt_addrs(odp_packet_t pkt_tbl[], unsigned len); +static void parse_args(int argc, char *argv[], appl_args_t *appl_args); +static void print_info(char *progname, appl_args_t *appl_args); +static void usage(char *progname); + +static void analyze_packet_in_snort(odp_packet_t pkt, int thr) +{ + DAQ_PktHdr_t daqhdr; + const uint8_t *data; + DAQ_Verdict verd; + + data = odp_packet_l2(pkt); + if (!data) { + printf("no l2 offset, packet dropped\n"); + return; + } + + gettimeofday(&daqhdr.ts, NULL); + daqhdr.caplen = odp_buffer_size(pkt); + printf("%s() odp recieved packet len %d. thread %d\n", __func__, odp_packet_get_len(pkt), thr); + daqhdr.pktlen = odp_packet_get_len(pkt); + daqhdr.ingress_index = 0; + daqhdr.egress_index = DAQ_PKTHDR_UNKNOWN; + daqhdr.ingress_group = DAQ_PKTHDR_UNKNOWN; + daqhdr.egress_group = DAQ_PKTHDR_UNKNOWN; + daqhdr.flags = 0; + daqhdr.opaque = 0; + daqhdr.priv_ptr = NULL; + daqhdr.address_space_id = 0; + + /* Pass packet to Snort */ + verd = PacketCallback( "NULL", daqhdr, data); + return; +} + +/** + * Packet IO loopback worker thread using ODP queues + * + * @param arg thread arguments of type 'thread_args_t *' + */ +static void *pktio_queue_thread(void *arg) +{ + int thr; + odp_buffer_pool_t pkt_pool; + odp_pktio_t pktio; + thread_args_t *thr_args; + odp_queue_t outq_def; + odp_queue_t inq_def; + char inq_name[ODP_QUEUE_NAME_LEN]; + odp_queue_param_t qparam; + odp_packet_t pkt; + odp_buffer_t buf; + int ret; + unsigned long pkt_cnt = 0; + unsigned long err_cnt = 0; + odp_pktio_params_t params; + socket_params_t *sock_params = ¶ms.sock_params; + + thr = odp_thread_id(); + thr_args = arg; + + printf("Pktio thread [%02i] starts, pktio_dev:%s\n", thr, + thr_args->pktio_dev); + + /* Lookup the packet pool */ + pkt_pool = odp_buffer_pool_lookup("packet_pool"); + if (pkt_pool == ODP_BUFFER_POOL_INVALID) { + ODP_ERR(" [%02i] Error: pkt_pool not found\n", thr); + return NULL; + } + + /* Open a packet IO instance for this thread */ + sock_params->type = ODP_PKTIO_TYPE_SOCKET_BASIC; + sock_params->fanout = 0; + pktio = odp_pktio_open(thr_args->pktio_dev, pkt_pool, ¶ms); + if (pktio == ODP_PKTIO_INVALID) { + ODP_ERR(" [%02i] Error: pktio create failed\n", thr); + return NULL; + } + + /* + * Create and set the default INPUT queue associated with the 'pktio' + * resource + */ + qparam.sched.prio = ODP_SCHED_PRIO_DEFAULT; + qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC; + qparam.sched.group = ODP_SCHED_GROUP_DEFAULT; + snprintf(inq_name, sizeof(inq_name), "%i-pktio_inq_def", (int)pktio); + inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0'; + + inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, &qparam); + if (inq_def == ODP_QUEUE_INVALID) { + ODP_ERR(" [%02i] Error: pktio queue creation failed\n", thr); + return NULL; + } + + ret = odp_pktio_inq_setdef(pktio, inq_def); + if (ret != 0) { + ODP_ERR(" [%02i] Error: default input-Q setup\n", thr); + return NULL; + } + + printf(" [%02i] created pktio:%02i, queue mode (ATOMIC queues)\n" + " default pktio%02i-INPUT queue:%u\n", + thr, pktio, pktio, inq_def); + + /* Loop packets */ + for (;;) { + odp_pktio_t pktio_tmp; + +#if 1 + /* Use schedule to get buf from any input queue */ + buf = odp_schedule(NULL, ODP_SCHED_WAIT); +#else + /* Always dequeue from the same input queue */ + buf = odp_queue_deq(inq_def); +#endif + + if (!odp_buffer_is_valid(buf)) + continue; + + pkt = odp_packet_from_buffer(buf); + + analyze_packet_in_snort(pkt, thr); + +#if 0 + /* Print packet counts every once in a while */ + if (odp_unlikely(pkt_cnt++ % 100000 == 0)) { + printf(" [%02i] pkt_cnt:%lu\n", thr, pkt_cnt); + fflush(NULL); + } +#endif + } + +/* unreachable */ +} + +/** + * Packet IO loopback worker thread using bursts from/to IO resources + * + * @param arg thread arguments of type 'thread_args_t *' + */ +static void *pktio_ifburst_thread(void *arg) +{ + int thr; + odp_buffer_pool_t pkt_pool; + odp_pktio_t pktio; + thread_args_t *thr_args; + int pkts, pkts_ok; + odp_packet_t pkt_tbl[MAX_PKT_BURST]; + unsigned long pkt_cnt = 0; + unsigned long err_cnt = 0; + unsigned long tmp = 0; + odp_pktio_params_t params; + socket_params_t *sock_params = ¶ms.sock_params; + + thr = odp_thread_id(); + thr_args = arg; + + printf("Pktio thread [%02i] starts, pktio_dev:%s\n", thr, + thr_args->pktio_dev); + + /* Lookup the packet pool */ + pkt_pool = odp_buffer_pool_lookup("packet_pool"); + if (pkt_pool == ODP_BUFFER_POOL_INVALID || pkt_pool != thr_args->pool) { + ODP_ERR(" [%02i] Error: pkt_pool not found\n", thr); + return NULL; + } + + /* Open a packet IO instance for this thread */ + sock_params->type = thr_args->type; + sock_params->fanout = thr_args->fanout; + pktio = odp_pktio_open(thr_args->pktio_dev, pkt_pool, ¶ms); + if (pktio == ODP_PKTIO_INVALID) { + ODP_ERR(" [%02i] Error: pktio create failed.\n", thr); + return NULL; + } + + printf(" [%02i] created pktio:%02i, burst mode\n", + thr, pktio); + + /* Loop packets */ + for (;;) { + pkts = odp_pktio_recv(pktio, pkt_tbl, MAX_PKT_BURST); + if (pkts > 0) { + /* Drop packets with errors */ + pkts_ok = drop_err_pkts(pkt_tbl, pkts); + if (pkts_ok > 0) { + /* Swap Eth MACs and IP-addrs */ + swap_pkt_addrs(pkt_tbl, pkts_ok); + odp_pktio_send(pktio, pkt_tbl, pkts_ok); + } + + if (odp_unlikely(pkts_ok != pkts)) + ODP_ERR("Dropped frames:%u - err_cnt:%lu\n", + pkts-pkts_ok, ++err_cnt); + + /* Print packet counts every once in a while */ + tmp += pkts_ok; + if (odp_unlikely((tmp >= 100000) || /* OR first print:*/ + ((pkt_cnt == 0) && ((tmp-1) < MAX_PKT_BURST)))) { + pkt_cnt += tmp; + printf(" [%02i] pkt_cnt:%lu\n", thr, pkt_cnt); + fflush(NULL); + tmp = 0; + } + } + } + +/* unreachable */ +} + +/** + * ODP packet example main function + */ +int do_odp_init(int argc, char *argv[]) +{ + + odp_buffer_pool_t pool; + int thr_id; + void *pool_base; + int i; + int first_core; + + + /* Init ODP before calling anything else */ + if (odp_init_global()) { + ODP_ERR("Error: ODP global init failed.\n"); + exit(EXIT_FAILURE); + } + + /* Reserve memory for args from shared mem */ + args = odp_shm_reserve("shm_args", sizeof(args_t), ODP_CACHE_LINE_SIZE); + if (args == NULL) { + ODP_ERR("Error: shared mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + memset(args, 0, sizeof(*args)); + + /* Parse and store the application arguments */ + //parse_args(argc, argv, &args->appl); + args->appl.core_count = 1; + args->appl.if_count = 1; + args->appl.if_names = calloc(args->appl.if_count, sizeof(char *)); + args->appl.if_names[0] = strdup("eth0"); + + args->appl.fanout = 0; + args->appl.mode = APPL_MODE_PKT_QUEUE; + + /* Print both system and application information */ + print_info(NO_PATH(argv[0]), &args->appl); + + /* Init this thread */ + thr_id = odp_thread_create(0); + odp_init_local(thr_id); + + /* Create packet pool */ + pool_base = odp_shm_reserve("shm_packet_pool", + SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE); + if (pool_base == NULL) { + ODP_ERR("Error: packet pool mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + + pool = odp_buffer_pool_create("packet_pool", pool_base, + SHM_PKT_POOL_SIZE, + SHM_PKT_POOL_BUF_SIZE, + ODP_CACHE_LINE_SIZE, + ODP_BUFFER_TYPE_PACKET); + if (pool == ODP_BUFFER_POOL_INVALID) { + ODP_ERR("Error: packet pool create failed.\n"); + exit(EXIT_FAILURE); + } + odp_buffer_pool_print(pool); + + return 0; +} + +void odp_snort_run_threads(void) +{ + odp_linux_pthread_t thread_tbl[MAX_WORKERS]; + int i; + int core_count; + int num_workers; + int first_core; + + core_count = odp_sys_core_count(); + num_workers = core_count; + + /* + * By default core #0 runs Linux kernel background tasks. + * Start mapping thread from core #1 + */ + first_core = 1; + + if (core_count == 1) + first_core = 0; + + printf("First core: %i\n\n", first_core); + + if (args->appl.core_count) + num_workers = args->appl.core_count; + + if (num_workers > MAX_WORKERS) + num_workers = MAX_WORKERS; + + printf("Num worker threads: %i\n", num_workers); + + /* Create and init worker threads */ + memset(thread_tbl, 0, sizeof(thread_tbl)); + for (i = 0; i < num_workers; ++i) { + void *(*thr_run_func) (void *); + int core; + int if_idx; + + core = (first_core + i) % core_count; + + if_idx = i % args->appl.if_count; + + args->thread[i].pktio_dev = args->appl.if_names[if_idx]; + args->thread[i].mode = args->appl.mode; + args->thread[i].type = args->appl.type; + args->thread[i].fanout = args->appl.fanout; + + if (args->appl.mode == APPL_MODE_PKT_BURST) + thr_run_func = pktio_ifburst_thread; + else /* APPL_MODE_PKT_QUEUE */ + thr_run_func = pktio_queue_thread; + /* + * Create threads one-by-one instead of all-at-once, + * because each thread might get different arguments. + * Calls odp_thread_create(cpu) for each thread + */ + odp_linux_pthread_create(thread_tbl, 1, core, thr_run_func, + &args->thread[i]); + } + + /* Master thread waits for other threads to exit */ + odp_linux_pthread_join(thread_tbl, num_workers); + printf("Exit\n\n"); +} + + +/** + * Drop packets which input parsing marked as containing errors. + * + * Frees packets with error and modifies pkt_tbl[] to only contain packets with + * no detected errors. + * + * @param pkt_tbl Array of packet + * @param len Length of pkt_tbl[] + * + * @return Number of packets with no detected error + */ +static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len) +{ + odp_packet_t pkt; + unsigned pkt_cnt = len; + unsigned i, j; + + for (i = 0, j = 0; i < len; ++i) { + pkt = pkt_tbl[i]; + + if (odp_unlikely(odp_packet_error(pkt))) { + odp_packet_free(pkt); /* Drop */ + pkt_cnt--; + } else if (odp_unlikely(i != j++)) { + pkt_tbl[j] = pkt; + } + } + + return pkt_cnt; +} + +/** + * Swap eth src<->dst and IP src<->dst addresses + * + * @param pkt_tbl Array of packets + * @param len Length of pkt_tbl[] + */ + +static void swap_pkt_addrs(odp_packet_t pkt_tbl[], unsigned len) +{ + odp_packet_t pkt; + odp_ethhdr_t *eth; + odp_ethaddr_t tmp_addr; + odp_ipv4hdr_t *ip; + uint32be_t ip_tmp_addr; /* tmp ip addr */ + unsigned i; + + for (i = 0; i < len; ++i) { + pkt = pkt_tbl[i]; + if (odp_packet_inflag_eth(pkt)) { + eth = (odp_ethhdr_t *)odp_packet_l2(pkt); + + tmp_addr = eth->dst; + eth->dst = eth->src; + eth->src = tmp_addr; + + if (odp_packet_inflag_ipv4(pkt)) { + /* IPv4 */ + ip = (odp_ipv4hdr_t *)odp_packet_l3(pkt); + + ip_tmp_addr = ip->src_addr; + ip->src_addr = ip->dst_addr; + ip->dst_addr = ip_tmp_addr; + } + } + } +} + +/** + * Parse and store the command line arguments + * + * @param argc argument count + * @param argv[] argument vector + * @param appl_args Store application arguments here + */ +static void parse_args(int argc, char *argv[], appl_args_t *appl_args) +{ + int opt; + int long_index; + char *names, *str, *token, *save; + size_t len; + int i; + static struct option longopts[] = { + {"count", required_argument, NULL, 'c'}, + {"interface", required_argument, NULL, 'i'}, /* return 'i' */ + {"mode", required_argument, NULL, 'm'}, /* return 'm' */ + {"help", no_argument, NULL, 'h'}, /* return 'h' */ + {NULL, 0, NULL, 0} + }; + + appl_args->mode = -1; /* Invalid, must be changed by parsing */ + appl_args->type = 3; /* 3: ODP_PKTIO_TYPE_SOCKET_MMAP */ + appl_args->fanout = 1; /* turn off fanout by default for mmap */ + + for (i = 0; i < argc; i++) + printf("argv %s\n", argv[i]); + + while (1) { + opt = getopt_long(argc, argv, "+c:i:m:t:f:h", + longopts, &long_index); + + printf("opt %d\n", opt); + if (opt == -1) + break; /* No more options */ + + switch (opt) { + case 'c': + appl_args->core_count = atoi(optarg); + break; + /* parse packet-io interface names */ + case 'i': + len = strlen(optarg); + if (len == 0) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + len += 1; /* add room for '\0' */ + + names = malloc(len); + if (names == NULL) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + /* count the number of tokens separated by ',' */ + strcpy(names, optarg); + for (str = names, i = 0;; str = NULL, i++) { + token = strtok_r(str, ",", &save); + if (token == NULL) + break; + } + appl_args->if_count = i; + + if (appl_args->if_count == 0) { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + /* allocate storage for the if names */ + appl_args->if_names = + calloc(appl_args->if_count, sizeof(char *)); + + /* store the if names (reset names string) */ + strcpy(names, optarg); + for (str = names, i = 0;; str = NULL, i++) { + token = strtok_r(str, ",", &save); + if (token == NULL) + break; + appl_args->if_names[i] = token; + } + break; + + case 'm': + i = atoi(optarg); + if (i == 0) + appl_args->mode = APPL_MODE_PKT_BURST; + else + appl_args->mode = APPL_MODE_PKT_QUEUE; + break; + + case 't': + appl_args->type = atoi(optarg); + break; + + case 'f': + appl_args->fanout = atoi(optarg); + break; + + case 'h': + usage(argv[0]); + exit(EXIT_SUCCESS); + break; + + default: + break; + } + } + + if (appl_args->if_count == 0 || appl_args->mode == -1) { + usage(argv[0]); + printf("unable to parse odp args if_count %d mode %d\n", + appl_args->if_count, appl_args->mode); + exit(EXIT_FAILURE); + } + + optind = 1; /* reset 'extern optind' from the getopt lib */ +} + +/** + * Print system and application info + */ +static void print_info(char *progname, appl_args_t *appl_args) +{ + int i; + + printf("\n" + "ODP system info\n" + "---------------\n" + "ODP API version: %s\n" + "CPU model: %s\n" + "CPU freq (hz): %"PRIu64"\n" + "Cache line size: %i\n" + "Core count: %i\n" + "\n", + odp_version_api_str(), odp_sys_cpu_model_str(), odp_sys_cpu_hz(), + odp_sys_cache_line_size(), odp_sys_core_count()); + + printf("Running ODP appl: \"%s\"\n" + "-----------------\n" + "IF-count: %i\n" + "Using IFs: ", + progname, appl_args->if_count); + for (i = 0; i < appl_args->if_count; ++i) + printf(" %s", appl_args->if_names[i]); + printf("\n" + "Mode: "); + if (appl_args->mode == APPL_MODE_PKT_BURST) + PRINT_APPL_MODE(APPL_MODE_PKT_BURST); + else + PRINT_APPL_MODE(APPL_MODE_PKT_QUEUE); + printf("\n\n"); + fflush(NULL); +} + +/** + * Prinf usage information + */ +static void usage(char *progname) +{ + printf("\n" + "Usage: %s OPTIONS\n" + " E.g. %s -i eth1,eth2,eth3 -m 0\n" + "\n" + "OpenDataPlane example application.\n" + "\n" + "Mandatory OPTIONS:\n" + " -i, --interface Eth interfaces (comma-separated, no spaces)\n" + " -m, --mode 0: Burst send&receive packets (no queues)\n" + " 1: Send&receive packets through ODP queues.\n" + " -t, --type 1: ODP_PKTIO_TYPE_SOCKET_BASIC\n" + " 2: ODP_PKTIO_TYPE_SOCKET_MMSG\n" + " 3: ODP_PKTIO_TYPE_SOCKET_MMAP\n" + " 4: ODP_PKTIO_TYPE_NETMAP\n" + " Default: 3: ODP_PKTIO_TYPE_SOCKET_MMAP\n" + " -f, --fanout 0: off 1: on (Default 1: on)\n" + "\n" + "Optional OPTIONS\n" + " -c, --count Core count.\n" + " -h, --help Display help and exit.\n" + "\n", NO_PATH(progname), NO_PATH(progname) + ); +} --- /dev/null +++ b/snort/odpsnort/odp_pktio.h @@ -0,0 +1 @@ +int do_odp_init(int argc, char *argv[]); --- /dev/null +++ b/snort/odpsnort/snort.c @@ -0,0 +1,5095 @@ +/* $Id$ */ +/* +** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. +** Copyright (C) 2002-2013 Sourcefire, Inc. +** Copyright (C) 1998-2002 Martin Roesch +** +** 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. +*/ + +/* + * + * Program: Snort + * + * Purpose: Check out the README file for info on what you can do + * with Snort. + * + * Author: Martin Roesch (roesch@clark.net) + * + * Comments: Ideas and code stolen liberally from Mike Borella's IP Grab + * program. Check out his stuff at http://www.borella.net. I + * also have ripped some util functions from TCPdump, plus Mike's + * prog is derived from it as well. All hail TCPdump.... + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_MALLOC_TRIM +#include +#endif + +#ifndef WIN32 +#include +#else +#include +#endif + +#ifdef HAVE_GETOPT_LONG +//#define _GNU_SOURCE +/* A GPL copy of getopt & getopt_long src code is now in sfutil */ +# undef HAVE_GETOPT_LONG +#endif +#include + +#ifdef HAVE_STRINGS_H +# include +#endif + +#ifndef WIN32 +# include +# include +# include +# include +# include +#endif /* !WIN32 */ + +#if !defined(CATCH_SEGV) && !defined(WIN32) +# include +#endif +#include + +#include "decode.h" +#include "encode.h" +#include "sfdaq.h" +#include "active.h" +#include "snort.h" +#include "rules.h" +#include "treenodes.h" +#include "plugbase.h" +#include "snort_debug.h" +#include "util.h" +#include "parser.h" +#include "tag.h" +#include "log.h" +#include "detect.h" +#include "mstring.h" +#include "fpcreate.h" +#include "fpdetect.h" +#include "sfthreshold.h" +#include "rate_filter.h" +#include "packet_time.h" +#include "detection-plugins/sp_flowbits.h" +#include "preprocessors/spp_perfmonitor.h" +#include "preprocessors/perf-base.h" +#include "preprocessors/perf.h" +#include "mempool.h" +#include "strlcpyu.h" +#include "sflsq.h" +#include "sp_replace.h" +#include "output-plugins/spo_log_tcpdump.h" +#include "event_queue.h" +#include "asn1.h" +#include "mpse.h" +#include "generators.h" +#include "ppm.h" +#include "profiler.h" +#include "dynamic-plugins/sp_dynamic.h" +#include "dynamic-plugins/sf_dynamic_define.h" +#include "dynamic-output/plugins/output.h" +#include "sfutil/strvec.h" +#include "detection_util.h" +#include "sfcontrol_funcs.h" +#include "idle_processing_funcs.h" +#include "file_service.h" +#ifdef SIDE_CHANNEL +# include "sidechannel.h" +#endif + +#include "dynamic-plugins/sf_dynamic_engine.h" +#include "dynamic-plugins/sf_dynamic_detection.h" +#define PROFILE_PREPROCS_NOREDEF +#include "dynamic-plugins/sf_dynamic_preprocessor.h" +#include "dynamic-plugins/sp_preprocopt.h" +#ifdef SIDE_CHANNEL +# include "dynamic-plugins/sf_dynamic_side_channel.h" +#endif + +#ifdef TARGET_BASED +# include "target-based/sftarget_reader.h" +#endif + +#ifdef EXIT_CHECK +# include "cpuclock.h" +#endif +#include "sfActionQueue.h" + +#ifdef INTEL_SOFT_CPM +#include "sfutil/intel-soft-cpm.h" +#endif + +#include "stream5_common.h" +#include "stream5_ha.h" + +#include "odp_pktio.h" + +/* Macros *********************************************************************/ +#ifndef DLT_LANE8023 +/* + * Old OPEN BSD Log format is 17. + * Define DLT_OLDPFLOG unless DLT_LANE8023 (Suse 6.3) is already + * defined in bpf.h. + */ +# define DLT_OLDPFLOG 17 +#endif + +#define ALERT_MODE_OPT__NONE "none" +#define ALERT_MODE_OPT__PKT_CNT "packet-count" +#define ALERT_MODE_OPT__FULL "full" +#define ALERT_MODE_OPT__FAST "fast" +#define ALERT_MODE_OPT__CONSOLE "console" +#define ALERT_MODE_OPT__CMG "cmg" +#define ALERT_MODE_OPT__JH "jh" +#define ALERT_MODE_OPT__DJR "djr" +#define ALERT_MODE_OPT__AJK "ajk" +#define ALERT_MODE_OPT__UNIX_SOCK "unsock" +#define ALERT_MODE_OPT__TEST "test" + +#define LOG_MODE_OPT__NONE "none" +#define LOG_MODE_OPT__PCAP "pcap" +#define LOG_MODE_OPT__ASCII "ascii" + +#ifdef MPLS +# define MPLS_PAYLOAD_OPT__IPV4 "ipv4" +# define MPLS_PAYLOAD_OPT__IPV6 "ipv6" +# define MPLS_PAYLOAD_OPT__ETHERNET "ethernet" +#endif + +#define DEFAULT_PAF_MAX 16384 + +/* Data types *****************************************************************/ + +typedef enum _GetOptArgType +{ + LONGOPT_ARG_NONE = 0, + LONGOPT_ARG_REQUIRED, + LONGOPT_ARG_OPTIONAL + +} GetOptArgType; + +/* Externs *******************************************************************/ +extern void PrintPacket(Packet *p); + +/* Undefine the one from sf_dynamic_preprocessor.h */ +#ifdef PERF_PROFILING +extern PreprocStats detectPerfStats, decodePerfStats, metaPerfStats, + totalPerfStats, eventqPerfStats, rulePerfStats, mpsePerfStats; +extern PreprocStats ruleCheckBitPerfStats, ruleSetBitPerfStats, ruleFailedFlowbitsPerfStats; +extern PreprocStats ruleRTNEvalPerfStats, ruleOTNEvalPerfStats, ruleHeaderNoMatchPerfStats; +extern PreprocStats ruleAddEventQPerfStats, ruleNQEventQPerfStats; +extern PreprocStats preprocRuleOptionPerfStats; +#endif + +/* for getopt */ +extern char *optarg; +extern int optind; +extern int opterr; +extern int optopt; + +extern ListHead *head_tmp; + +/* Globals/Public *************************************************************/ +extern PacketCount pc; /* packet count information */ +extern uint32_t *netmasks; /* precalculated netmask array */ +extern char **protocol_names; +extern char *snort_conf_file; /* -c */ +extern char *snort_conf_dir; + +extern SnortConfig *snort_cmd_line_conf; +extern SnortConfig *snort_conf; +extern tSfPolicyId runtimePolicyId; +extern tSfPolicyId parserPolicyId; + +#if defined(SNORT_RELOAD) && !defined(WIN32) +SnortConfig *snort_conf_new = NULL; +SnortConfig *snort_conf_old = NULL; +#endif + +extern tSfActionQueueId decoderActionQ; +extern MemPool decoderAlertMemPool; + +extern VarNode *cmd_line_var_list; + +#ifdef TARGET_BASED +pthread_t attribute_reload_thread_id; +pid_t attribute_reload_thread_pid; +volatile int attribute_reload_thread_running = 0; +volatile int attribute_reload_thread_stop = 0; +int reload_attribute_table_flags = 0; +#endif + +extern volatile bool snort_initializing; +static volatile int snort_exiting = 0; +static pid_t snort_main_thread_pid = 0; +#ifndef WIN32 +static pthread_t snort_main_thread_id = 0; +#endif + +#if defined(SNORT_RELOAD) && !defined(WIN32) +static volatile int snort_reload = 0; +static volatile int snort_swapped = 0; +static volatile int snort_reload_thread_created = 0; +static pthread_t snort_reload_thread_id; +static pid_t snort_reload_thread_pid; +#ifdef CONTROL_SOCKET +static volatile int reloadInProgress = 0; +#endif +#endif + +extern const struct timespec thread_sleep; +#ifdef OPENBSD +const struct timespec packet_sleep = { 0, 1 }; +#endif + +#ifdef HAVE_PCAP_LEX_DESTROY +extern void pcap_lex_destroy(void); +#endif + +extern PreprocConfigFuncNode *preproc_config_funcs; +extern OutputConfigFuncNode *output_config_funcs; +extern RuleOptConfigFuncNode *rule_opt_config_funcs; +extern RuleOptOverrideInitFuncNode *rule_opt_override_init_funcs; +extern RuleOptParseCleanupNode *rule_opt_parse_cleanup_list; +extern RuleOptByteOrderFuncNode *rule_opt_byte_order_funcs; + +extern PreprocSignalFuncNode *preproc_clean_exit_funcs; +extern PreprocSignalFuncNode *preproc_shutdown_funcs; +extern PreprocSignalFuncNode *preproc_reset_funcs; +extern PreprocSignalFuncNode *preproc_reset_stats_funcs; +extern PreprocStatsFuncNode *preproc_stats_funcs; + +extern PluginSignalFuncNode *plugin_shutdown_funcs; +extern PluginSignalFuncNode *plugin_clean_exit_funcs; +#ifdef SNORT_RELOAD +PostConfigFuncNode *plugin_reload_funcs = NULL; +#endif + +extern OutputFuncNode *AlertList; /* Alert function list */ +extern OutputFuncNode *LogList; /* Log function list */ + +extern PeriodicCheckFuncNode *periodic_check_funcs; +extern DynamicRuleNode *dynamic_rules; +extern grinder_t grinder; + +#ifdef SIDE_CHANNEL +pthread_mutex_t snort_process_lock; +static bool snort_process_lock_held = false; +#endif + +/* Locals/Private ************************************************************/ +static long int pcap_loop_count = 0; +static SF_QUEUE *pcap_save_queue = NULL; + +#if defined(INLINE_FAILOPEN) && !defined(WIN32) +static pthread_t inline_failopen_thread_id; +static pid_t inline_failopen_thread_pid; +static volatile int inline_failopen_thread_running = 0; +static volatile int inline_failopen_initialized = 0; +static int inline_failopen_pass_pkt_cnt = 0; +static void * SnortPostInitThread(void *); +static DAQ_Verdict IgnoreCallback (void*, const DAQ_PktHdr_t*, const uint8_t*); +#endif + +static char signal_error_msg[STD_BUF]; +static int exit_signal = 0; +static bool dump_stats_signal = false; +static bool rotate_stats_signal = false; +#ifdef TARGET_BASED +static bool no_attr_table_signal = false; +#endif + +#ifndef SNORT_RELOAD +static volatile bool reload_signal = false; +#else +/* reload_signal is incremented in the signal handler for SIGNAL_SNORT_RELOAD + * which is handled in the main thread. The reload thread compares the + * reload_signal count to reload_total which it increments after an equality + * test between reload_signal and reload_total fails (which means we got a new + * SIGNAL_SNORT_RELOAD). They need to be the same type and size to do this + * comparison. See ReloadConfigThread() */ +typedef uint32_t snort_reload_t; +static volatile snort_reload_t reload_signal = 0; +static snort_reload_t reload_total = 0; +#endif + +static int done_processing = 0; +static int exit_logged = 0; + +static SF_LIST *pcap_object_list = NULL; +static SF_QUEUE *pcap_queue = NULL; +static char* pcap_filter = NULL; + +static int snort_argc = 0; +static char **snort_argv = NULL; + +/* command line options for getopt */ +static char *valid_options = + "?A:bB:c:CdDeEfF:" +#ifndef WIN32 + "g:" +#endif + "G:h:Hi:Ik:K:l:L:" +#ifndef WIN32 + "m:" +#endif + "Mn:NOpP:q" +#ifndef WIN32 + "Q" +#endif + "r:R:sS:" +#ifndef WIN32 + "t:" +#endif + "T" +#ifndef WIN32 + "u:" +#endif + "UvVw:" +#ifdef WIN32 + "W" +#endif + "XxyZ:" +; + +static struct option long_options[] = +{ + {"logid", LONGOPT_ARG_REQUIRED, NULL, 'G'}, + {"perfmon-file", LONGOPT_ARG_REQUIRED, NULL, 'Z'}, + {"snaplen", LONGOPT_ARG_REQUIRED, NULL, 'P'}, + {"version", LONGOPT_ARG_NONE, NULL, 'V'}, + {"help", LONGOPT_ARG_NONE, NULL, '?'}, + {"conf-error-out", LONGOPT_ARG_NONE, NULL,'x'}, + {"dynamic-engine-lib", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_ENGINE_FILE}, + {"dynamic-engine-lib-dir", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_ENGINE_DIRECTORY}, + {"dynamic-detection-lib", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_LIBRARY_FILE}, + {"dynamic-detection-lib-dir", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_LIBRARY_DIRECTORY}, + {"dump-dynamic-rules", LONGOPT_ARG_REQUIRED, NULL, DUMP_DYNAMIC_RULES}, + {"dynamic-preprocessor-lib", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_PREPROC_FILE}, + {"dynamic-preprocessor-lib-dir", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_PREPROC_DIRECTORY}, + {"dynamic-output-lib", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_OUTPUT_FILE}, + {"dynamic-output-lib-dir", LONGOPT_ARG_REQUIRED, NULL, DYNAMIC_OUTPUT_DIRECTORY}, + {"alert-before-pass", LONGOPT_ARG_NONE, NULL, ALERT_BEFORE_PASS}, + {"treat-drop-as-alert", LONGOPT_ARG_NONE, NULL, TREAT_DROP_AS_ALERT}, + {"treat-drop-as-ignore", LONGOPT_ARG_NONE, NULL, TREAT_DROP_AS_IGNORE}, + {"process-all-events", LONGOPT_ARG_NONE, NULL, PROCESS_ALL_EVENTS}, + {"pid-path", LONGOPT_ARG_REQUIRED, NULL, PID_PATH}, + {"create-pidfile", LONGOPT_ARG_NONE, NULL, CREATE_PID_FILE}, + {"nolock-pidfile", LONGOPT_ARG_NONE, NULL, NOLOCK_PID_FILE}, + {"no-interface-pidfile", LONGOPT_ARG_NONE, NULL, NO_IFACE_PID_FILE}, + +#ifdef INLINE_FAILOPEN + {"disable-inline-init-failopen", LONGOPT_ARG_NONE, NULL, DISABLE_INLINE_FAILOPEN}, +#endif + + {"nostamps", LONGOPT_ARG_NONE, NULL, NO_LOGGING_TIMESTAMPS}, + +#ifdef TARGET_BASED + {"disable-attribute-reload-thread", LONGOPT_ARG_NONE, NULL, DISABLE_ATTRIBUTE_RELOAD}, +#endif + + {"pcap-single", LONGOPT_ARG_REQUIRED, NULL, PCAP_SINGLE}, + {"pcap-file", LONGOPT_ARG_REQUIRED, NULL, PCAP_FILE_LIST}, + {"pcap-list", LONGOPT_ARG_REQUIRED, NULL, PCAP_LIST}, + +#ifndef WIN32 + {"pcap-dir", LONGOPT_ARG_REQUIRED, NULL, PCAP_DIR}, + {"pcap-filter", LONGOPT_ARG_REQUIRED, NULL, PCAP_FILTER}, + {"pcap-no-filter", LONGOPT_ARG_NONE, NULL, PCAP_NO_FILTER}, +#endif + + {"pcap-loop", LONGOPT_ARG_REQUIRED, NULL, PCAP_LOOP}, + {"pcap-reload", LONGOPT_ARG_NONE, NULL, PCAP_RELOAD}, + {"pcap-reset", LONGOPT_ARG_NONE, NULL, PCAP_RESET}, + {"pcap-show", LONGOPT_ARG_NONE, NULL, PCAP_SHOW}, + +#ifdef EXIT_CHECK + {"exit-check", LONGOPT_ARG_REQUIRED, NULL, ARG_EXIT_CHECK}, +#endif + + {"search-method", LONGOPT_ARG_REQUIRED, NULL, DETECTION_SEARCH_METHOD}, + {"man", LONGOPT_ARG_REQUIRED, NULL, DETECTION_SEARCH_METHOD}, + +#ifdef MPLS + {"enable-mpls-multicast", LONGOPT_ARG_NONE, NULL, ENABLE_MPLS_MULTICAST}, + {"enable-mpls-overlapping-ip", LONGOPT_ARG_NONE, NULL, ENABLE_OVERLAPPING_IP}, + {"max-mpls-labelchain-len", LONGOPT_ARG_REQUIRED, NULL, MAX_MPLS_LABELCHAIN_LEN}, + {"mpls-payload-type", LONGOPT_ARG_REQUIRED, NULL, MPLS_PAYLOAD_TYPE}, +#endif + + {"require-rule-sid", LONGOPT_ARG_NONE, NULL, REQUIRE_RULE_SID}, + + {"daq", LONGOPT_ARG_REQUIRED, NULL, ARG_DAQ_TYPE}, + {"daq-mode", LONGOPT_ARG_REQUIRED, NULL, ARG_DAQ_MODE}, + {"daq-var", LONGOPT_ARG_REQUIRED, NULL, ARG_DAQ_VAR}, + {"daq-dir", LONGOPT_ARG_REQUIRED, NULL, ARG_DAQ_DIR}, + {"daq-list", LONGOPT_ARG_OPTIONAL, NULL, ARG_DAQ_LIST}, + {"dirty-pig", LONGOPT_ARG_NONE, NULL, ARG_DIRTY_PIG}, + + {"enable-inline-test", LONGOPT_ARG_NONE, NULL, ENABLE_INLINE_TEST}, + + {"cs-dir", LONGOPT_ARG_REQUIRED, NULL, ARG_CS_DIR}, + {"ha-peer", LONGOPT_ARG_NONE, NULL, ARG_HA_PEER}, + {"ha-out", LONGOPT_ARG_REQUIRED, NULL, ARG_HA_OUT}, + {"ha-in", LONGOPT_ARG_REQUIRED, NULL, ARG_HA_IN}, + + {0, 0, 0, 0} +}; + +typedef void (*log_func_t)(Packet*); +static void LogPacket (Packet* p) +{ + pc.log_pkts++; + CallLogPlugins(p, NULL, NULL); +} +static void IgnorePacket (Packet* p) { } +static log_func_t log_func = IgnorePacket; + +/* Private function prototypes ************************************************/ +static void InitNetmasks(void); +static void InitProtoNames(void); +static const char* GetPacketSource(char**); + +static void CleanExit(int); +//static void SnortInit(int, char **); +static void InitPidChrootAndPrivs(pid_t); +static void ParseCmdLine(int, char **); +static int ShowUsage(char *); +static void PrintVersion(void); +static void SetSnortConfDir(void); +static void InitGlobals(void); +static SnortConfig * MergeSnortConfs(SnortConfig *, SnortConfig *); +static void InitSignals(void); +#if defined(NOCOREFILE) && !defined(WIN32) +static void SetNoCores(void); +#endif +static void SnortCleanup(int); + +static void ParseCmdLineDynamicLibInfo(SnortConfig *, int, char *); +static DynamicLibInfo * DupDynamicLibInfo(DynamicLibInfo *); +static void FreeDynamicLibInfo(DynamicLibInfo *); +static void FreeDynamicLibInfos(SnortConfig *); + +static void FreeOutputConfigs(OutputConfig *); +#ifdef SIDE_CHANNEL +static void FreeSideChannelModuleConfigs(SideChannelModuleConfig *); +#endif +static void FreePreprocConfigs(SnortConfig *); +static void FreeRuleStateList(RuleState *); +static void FreeClassifications(ClassType *); +static void FreeReferences(ReferenceSystemNode *); +static void FreePlugins(SnortConfig *); +static void FreePreprocessors(SnortConfig *); + +extern void SnortUnprivilegedInit(void); +static int SetPktProcessor(void); +static void PacketLoop(void); +extern void odp_snort_run_threads(void); +#if 0 +static char * ConfigFileSearch(void); +#endif +static void SnortReset(void); + +static void LoadDynamicPlugins(SnortConfig *); + +static void SnortIdle(void); +#ifndef WIN32 +static void SnortStartThreads(void); +#endif + +/* Signal handler declarations ************************************************/ +static void SigDumpStatsHandler(int); +static void SigExitHandler(int); +static void SigReloadHandler(int); +static void SigRotateStatsHandler(int); +#ifdef CONTROL_SOCKET +static void SigPipeHandler(int); +#endif +static void SigOopsHandler(int); + +#ifdef TARGET_BASED +static void SigNoAttributeTableHandler(int); +#endif + +#if defined(SNORT_RELOAD) && !defined(WIN32) +static SnortConfig * ReloadConfig(void); +static void * ReloadConfigThread(void *); +static int VerifyReload(SnortConfig *); +static int VerifyOutputs(SnortConfig *, SnortConfig *); +static int VerifyLibInfos(DynamicLibInfo *, DynamicLibInfo *); +#endif /* SNORT_RELOAD */ + +static int IsProcessingPackets(uint16_t type, const uint8_t *data, uint32_t length, void **new_config, + char *statusBuf, int statusBuf_len) +{ + return (!snort_initializing && !snort_exiting && !exit_signal) ? 0 : -1; +} + +#if defined(SNORT_RELOAD) && !defined(WIN32) && defined(CONTROL_SOCKET) + +static pthread_mutex_t reload_mutex = PTHREAD_MUTEX_INITIALIZER; + +static int ControlSocketReloadConfig(uint16_t type, const uint8_t *data, uint32_t length, void **new_config, + char *statusBuf, int statusBuf_len) +{ + SnortConfig *new_sc; + + pthread_mutex_lock(&reload_mutex); + while (reloadInProgress) + { + sleep(1); + } + reloadInProgress = 1; + pthread_mutex_unlock(&reload_mutex); + + LogMessage("\n"); + LogMessage(" --== Reloading Snort ==--\n"); + LogMessage("\n"); + + new_sc = ReloadConfig(); + if (new_sc == NULL) + { + reloadInProgress = 0; + return -1; + } + *new_config = (void *)new_sc; + return 0; +} + +static int ControlSocketReloadSwap(uint16_t type, void *new_config, void **old_config) +{ + PostConfigFuncNode *idxPlugin = NULL; + + *old_config = (void *)snort_conf; + snort_conf = (SnortConfig *)new_config; + SwapPreprocConfigurations(snort_conf); + + FreeSwappedPreprocConfigurations(snort_conf); + +#ifdef INTEL_SOFT_CPM + if (snort_conf->fast_pattern_config->search_method == MPSE_INTEL_CPM) + IntelPmActivate(snort_conf); +#endif + + /* Do any reload for plugin data */ + idxPlugin = plugin_reload_funcs; + while(idxPlugin) + { + idxPlugin->func(snort_conf, SIGHUP, idxPlugin->arg); + idxPlugin = idxPlugin->next; + } + return 0; +} + +static void ControlSocketReloadFree(uint16_t type, void *old_config, struct _THREAD_ELEMENT *te, ControlDataSendFunc f) +{ + SnortConfig *old_sc = (SnortConfig *)old_config; + + SnortConfFree(old_sc); + +#ifdef INTEL_SOFT_CPM + if (snort_conf->fast_pattern_config->search_method != MPSE_INTEL_CPM) + IntelPmStopInstance(); +#endif + + LogMessage("\n"); + LogMessage(" --== Reload Complete ==--\n"); + LogMessage("\n"); + + reloadInProgress = 0; +} +#endif + +static inline void CheckForReload(void) +{ +#if defined(SNORT_RELOAD) && !defined(WIN32) + /* Check for a new configuration */ + if (snort_reload) + { + PostConfigFuncNode *idxPlugin = NULL; + snort_reload = 0; + + /* There was an error reloading. A non-reloadable configuration + * option changed */ + if (snort_conf_new == NULL) + { +#ifdef RELOAD_ERROR_FATAL + CleanExit(1); +#else + Restart(); +#endif + } + + snort_conf_old = snort_conf; + snort_conf = snort_conf_new; + snort_conf_new = NULL; + SwapPreprocConfigurations(snort_conf); + + /* Need to do this here because there is potentially outstanding + * state data pointing to the previous configuration. A race + * condition is created if these are free'd in the reload thread + * where a double free could occur. */ + FreeSwappedPreprocConfigurations(snort_conf); + +#ifdef INTEL_SOFT_CPM + if (snort_conf->fast_pattern_config->search_method == MPSE_INTEL_CPM) + IntelPmActivate(snort_conf); +#endif + + snort_swapped = 1; + + /* Do any reload for plugin data */ + idxPlugin = plugin_reload_funcs; + while(idxPlugin) + { + idxPlugin->func(snort_conf, SIGHUP, idxPlugin->arg); + idxPlugin = idxPlugin->next; + } + } +#endif +} + +/* F U N C T I O N D E F I N I T I O N S **********************************/ + +static int InlineFailOpen (void) +{ +#if defined(INLINE_FAILOPEN) && !defined(WIN32) + if (ScAdapterInlineMode() && + !ScReadMode() && !ScDisableInlineFailopen()) + { + /* If in inline mode, start a thread to handle the rest of snort + * initialization, then dispatch packets until that initialization + * is complete. */ + LogMessage("Fail Open Thread starting..\n"); + + printf("%s()%d chreate new thread\n", __func__, __LINE__); + if (pthread_create(&inline_failopen_thread_id, NULL, SnortPostInitThread, NULL)) + { + ErrorMessage("Failed to start Fail Open Thread. " + "Starting normally\n"); + } + else + { + while (!inline_failopen_thread_running) + nanosleep(&thread_sleep, NULL); + + LogMessage("Fail Open Thread started tid=%p (pid=%u)\n", + (void*)inline_failopen_thread_id, inline_failopen_thread_pid); + +# ifdef DEBUG + { + FILE *tmp = fopen("/var/tmp/fo_threadid", "w"); + if ( tmp ) + { + fprintf(tmp, "Fail Open Thread PID: %u\n", inline_failopen_thread_pid); + fclose(tmp); + } + } +# endif + DAQ_Start(); + SetPktProcessor(); + inline_failopen_initialized = 1; + + /* Passing packets is in the main thread because some systems + * may have to refer to packet passing thread via process id + * (linuxthreads) */ + while (snort_initializing) + { + int error = DAQ_Acquire(1, IgnoreCallback, NULL); + + if (error) + break; + } + + pthread_join(inline_failopen_thread_id, NULL); + inline_failopen_thread_running = 0; + + LogMessage("Fail Open Thread terminated, passed %d packets.\n", + inline_failopen_pass_pkt_cnt); + + return 1; + } + } +#endif + return 0; +} + +/* + * + * Function: main(int, char *) + * + * Purpose: Handle program entry and exit, call main prog sections + * This can handle both regular (command-line) style + * startup, as well as Win32 Service style startup. + * + * Arguments: See command line args in README file + * + * Returns: 0 => normal exit, 1 => exit on error + * + */ +int main(int argc, char *argv[]) +{ + /* hack to add deps to -lrt for timer_create() and friends from odp */ + static volatile int link_rt = 0; + timer_t timerid = 0; + if (link_rt) + timer_settime(timerid, 0, NULL, NULL); + +#if defined(WIN32) && defined(ENABLE_WIN32_SERVICE) + /* Do some sanity checking, because some people seem to forget to + * put spaces between their parameters + */ + if ((argc > 1) && + ((_stricmp(argv[1], (SERVICE_CMDLINE_PARAM SERVICE_INSTALL_CMDLINE_PARAM)) == 0) || + (_stricmp(argv[1], (SERVICE_CMDLINE_PARAM SERVICE_UNINSTALL_CMDLINE_PARAM)) == 0) || + (_stricmp(argv[1], (SERVICE_CMDLINE_PARAM SERVICE_SHOW_CMDLINE_PARAM)) == 0))) + { + FatalError("You must have a space after the '%s' command-line parameter\n", + SERVICE_CMDLINE_PARAM); + } + + /* If the first parameter is "/SERVICE", then start Snort as a Win32 service */ + if((argc > 1) && (_stricmp(argv[1],SERVICE_CMDLINE_PARAM) == 0)) + { + return SnortServiceMain(argc, argv); + } +#endif /* WIN32 && ENABLE_WIN32_SERVICE */ + + snort_argc = argc; + snort_argv = argv; + + return ODP_SnortMain(argc, argv); +} + +/* + * + * Function: SnortMain(int, char *) + * + * Purpose: The real place that the program handles entry and exit. Called + * called by main(), or by SnortServiceMain(). + * + * Arguments: See command line args in README file + * + * Returns: 0 => normal exit, 1 => exit on error + * + */ +int ODP_SnortMain(int argc, char *argv[]) +{ + char* tmp_ptr = NULL; + const char* intf; + int daqInit; + + + do_odp_init(argc, argv); + +#ifndef WIN32 + // must be done now in case of fatal error + // and again after daemonization + snort_main_thread_id = pthread_self(); +#endif + + SnortInit(argc, argv); + + intf = GetPacketSource(&tmp_ptr); + daqInit = intf || snort_conf->daq_type; + + if ( daqInit ) + { + //DAQ_Init(snort_conf); + //DAQ_New(snort_conf, intf); + } + if ( tmp_ptr ) + free(tmp_ptr); + + if ( ScDaemonMode() ) + { + GoDaemon(); + } + + // this must follow daemonization + snort_main_thread_pid = gettid(); +#ifndef WIN32 + snort_main_thread_id = pthread_self(); +#endif + +#ifndef WIN32 + /* Change groups */ + InitGroups(ScUid(), ScGid()); +#endif + +#if !defined(HAVE_LINUXTHREADS) && !defined(WIN32) + // this could be moved to linux threads location + // and only done there + SnortStartThreads(); +#endif + +#if defined(SNORT_RELOAD) && !defined(WIN32) && defined(CONTROL_SOCKET) + if (ControlSocketRegisterHandler(CS_TYPE_RELOAD, &ControlSocketReloadConfig, &ControlSocketReloadSwap, &ControlSocketReloadFree)) + { + LogMessage("Failed to register the reload control handler.\n"); + } +#endif + + if (ControlSocketRegisterHandler(CS_TYPE_IS_PROCESSING, &IsProcessingPackets, NULL, NULL)) + { + LogMessage("Failed to register the is processing control handler.\n"); + } + + if ( ScTestMode() ) + { + if ( daqInit && DAQ_UnprivilegedStart() ) + SetPktProcessor(); + SnortUnprivilegedInit(); + } + else if ( DAQ_UnprivilegedStart() ) + { + SnortUnprivilegedInit(); + SetPktProcessor(); + //DAQ_Start(); + } + else if ( !InlineFailOpen() ) + { + //DAQ_Start(); + SetPktProcessor(); + SnortUnprivilegedInit(); + } + + printf("going to packet loop\n"); + odp_snort_run_threads(); + + //PacketLoop(); + + // DAQ is shutdown in CleanExit() since we don't always return here + CleanExit(0); + + return 0; +} + +#ifndef WIN32 +/* All threads need to be created after daemonizing. If created in + * the parent thread, when it goes away, so will all of the threads. + * The child does not "inherit" threads created in the parent. */ +static void SnortStartThreads(void) +{ +# ifdef SNORT_RELOAD + if (ScIdsMode()) + { + LogMessage("Reload thread starting...\n"); + printf("%s()%d chreate new thread\n", __func__, __LINE__); + if (pthread_create(&snort_reload_thread_id, NULL, ReloadConfigThread, NULL) != 0) + { + ErrorMessage("Could not create configuration reload thread.\n"); + CleanExit(1); + } + + while (!snort_reload_thread_created) + nanosleep(&thread_sleep, NULL); + + LogMessage("Reload thread started, thread %p (%u)\n", + (void*)snort_reload_thread_id, snort_reload_thread_pid); + } +# endif + +# ifdef TARGET_BASED + SFAT_StartReloadThread(); +# endif +} +#else /* WIN32 */ +//------------------------------------------------------------------------------ +// interface stuff +//------------------------------------------------------------------------------ + +static void PrintAllInterfaces (void) +{ + char errorbuf[PCAP_ERRBUF_SIZE]; + pcap_if_t *alldevs; + pcap_if_t *dev; + int j = 1; + MIB_IFTABLE *iftable = NULL; + unsigned int len = 0; + unsigned int ret, i; + + if (pcap_findalldevs(&alldevs, errorbuf) == -1) + FatalError("Could not get device list: %s.", errorbuf); + + /* max of two iterations here -- first to get the + * correct length if not big enough. Second to + * get the data. */ + for (len = sizeof(iftable[0]); ; ) { + if (iftable) + free(iftable); + iftable = SnortAlloc(len); + ret = GetIfTable(iftable, &len, TRUE); + if (ret == NO_ERROR) + break; + else if (ret != ERROR_INSUFFICIENT_BUFFER) + FatalError("Could not get device list: %s.", errorbuf);; + } + + printf("Index\tPhysical Address\tIP Address\tDevice Name\tDescription\n"); + printf("-----\t----------------\t----------\t-----------\t-----------\n"); + + for (dev = alldevs; dev != NULL; dev = dev->next, j++) + { + uint8_t *mac_addr = NULL; + for (i = 0; idwNumEntries; i++) + { + if (strncmp(dev->description, iftable->table[i].bDescr, iftable->table[i].dwDescrLen) == 0) + { + mac_addr = iftable->table[i].bPhysAddr; + break; + } + } + printf("%5d\t", j); + if (mac_addr) + { + printf("%02X:%02X:%02X:%02X:%02X:%02X\t", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5]); + } + else + { + printf("00:00:00:00:00:00\t"); + } + if (dev->addresses) + { + struct sockaddr_in* saddr = (struct sockaddr_in*)dev->addresses->addr; + sfip_t dev_ip; + if ((saddr->sin_family == AF_INET) || (saddr->sin_family == AF_INET6)) + { + sfip_set_raw(&dev_ip, &saddr->sin_addr, saddr->sin_family); + printf("%s\t", inet_ntoa(&dev_ip)); + } + else + { + printf("disabled\t"); + } + printf("%s\t%s\n", dev->name, dev->description); + } + else + { + printf("disabled\t%s\t%s\n", dev->name, dev->description); + } + + } + pcap_freealldevs(alldevs); + free(iftable); +} +#endif /* WIN32 */ + +// pcap list stuff ... + +static void PQ_SetFilter (const char* f) +{ + if (pcap_filter != NULL) + free(pcap_filter); + + pcap_filter = f ? SnortStrdup(f) : NULL; +} + +static void PQ_Single (const char* pcap) +{ + PcapReadObject* pro; + + if (pcap_object_list == NULL) + { + pcap_object_list = sflist_new(); + if (pcap_object_list == NULL) + FatalError("Could not allocate list to store pcap\n"); + } + + pro = (PcapReadObject *)SnortAlloc(sizeof(PcapReadObject)); + pro->type = PCAP_SINGLE; + pro->arg = SnortStrdup(pcap); + pro->filter = NULL; + + if (sflist_add_tail(pcap_object_list, (NODE_DATA)pro) == -1) + FatalError("Could not add pcap object to list: %s\n", pcap); +} + +static void PQ_Multi (char type, const char* list) +{ + PcapReadObject* pro; + + if (pcap_object_list == NULL) + { + pcap_object_list = sflist_new(); + if (pcap_object_list == NULL) + FatalError("Could not allocate list to store pcaps\n"); + } + + pro = (PcapReadObject *)SnortAlloc(sizeof(PcapReadObject)); + pro->type = type; + pro->arg = SnortStrdup(list); + if (pcap_filter != NULL) + pro->filter = SnortStrdup(pcap_filter); + else + pro->filter = NULL; + + if (sflist_add_tail(pcap_object_list, (NODE_DATA)pro) == -1) + FatalError("Could not add pcap object to list: %s\n", list); +} + +static void PQ_SetUp (void) +{ + if (pcap_object_list != NULL) + { + if (sflist_count(pcap_object_list) == 0) + { + sflist_free_all(pcap_object_list, NULL); + FatalError("No pcaps specified.\n"); + } + + pcap_queue = sfqueue_new(); + pcap_save_queue = sfqueue_new(); + if ((pcap_queue == NULL) || (pcap_save_queue == NULL)) + FatalError("Could not allocate pcap queues.\n"); + + if (GetPcaps(pcap_object_list, pcap_queue) == -1) + FatalError("Error getting pcaps.\n"); + + if (sfqueue_count(pcap_queue) == 0) + FatalError("No pcaps found.\n"); + + /* free pcap list used to get params */ + while (sflist_count(pcap_object_list) > 0) + { + PcapReadObject *pro = (PcapReadObject *)sflist_remove_head(pcap_object_list); + if (pro == NULL) + FatalError("Failed to remove pcap item from list.\n"); + + if (pro->arg != NULL) + free(pro->arg); + + if (pro->filter != NULL) + free(pro->filter); + + free(pro); + } + + sflist_free_all(pcap_object_list, NULL); + pcap_object_list = NULL; + } + if (pcap_filter != NULL) + { + free(pcap_filter); + pcap_filter = NULL; + } +} + +static int PQ_CleanUp (void) +{ + /* clean up pcap queues */ + if (pcap_queue != NULL) + sfqueue_free_all(pcap_queue, free); + + if (pcap_save_queue != NULL) + sfqueue_free_all(pcap_save_queue, free); + + return 0; +} + +static void PQ_Show (const char* pcap) +{ + if ( !ScPcapShow() ) + return; + + if ( !strcmp(pcap, "-") ) pcap = "stdin"; + + fprintf(stdout, + "Reading network traffic from \"%s\" with snaplen = %d\n", + pcap, DAQ_GetSnapLen()); +} + +static const char* PQ_First (void) +{ + const char* pcap = (char*)sfqueue_remove(pcap_queue); + + if ( !pcap ) + return pcap; + + if ( sfqueue_add(pcap_save_queue, (NODE_DATA)pcap) == -1 ) + FatalError("Could not add pcap to saved list\n"); + + return pcap; +} + +// this must follow 2nd or later start and not stop because we force a +// reset when the dlt changes even if not enabled with --pcap-reset to +// avoid eventually flushing stream packets through a different grinder +// than the one they were queued with. +static void PQ_Reset () +{ + static int dlt = -1; + int new_dlt = DAQ_GetBaseProtocol(); + + if ( ScPcapReset() || ((dlt != new_dlt) && (dlt != -1)) ) + SnortReset(); + + dlt = new_dlt; + + /* open a new tcpdump file - necessary because the snaplen and + * datalink could be different between pcaps */ + if (snort_conf->log_tcpdump) + { + /* this sleep is to ensure we get a new log file since it has a + * time stamp with resolution to the second */ +#ifdef WIN32 + Sleep(1000); +#else + sleep(1); +#endif + LogTcpdumpReset(); + } +} + +static int PQ_Next (void) +{ + char reopen_pcap = 0; + + if (sfqueue_count(pcap_queue) > 0) + { + reopen_pcap = 1; + } + else if (pcap_loop_count) + { + if (pcap_loop_count > 0) + pcap_loop_count--; + + if (pcap_loop_count != 0) + { + SF_QUEUE *tmp; + + /* switch pcap lists */ + tmp = pcap_queue; + pcap_queue = pcap_save_queue; + pcap_save_queue = tmp; + + reopen_pcap = 1; + } + } + + if (reopen_pcap) + { + /* reinitialize pcap */ + const char* pcap = PQ_First(); + + if ( !pcap ) + FatalError("Could not get pcap from list\n"); + + DAQ_Stop(); + DAQ_Delete(); + + DAQ_New(snort_conf, pcap); + DAQ_Start(); + + PQ_Reset(); + PQ_Show(pcap); + SetPktProcessor(); + + SetSampleTime(perfmon_config, NULL); + +#if defined(SNORT_RELOAD) && !defined(WIN32) + if ( snort_conf->run_flags & RUN_FLAG__PCAP_RELOAD && ScIdsMode()) + { + /* Awaiting user confirmation */ + printf("Hit return to continue.\n"); + fflush(stdout); + while(getc(stdin) != '\n'); + + SigReloadHandler(SIGNAL_SNORT_RELOAD); + + while (!snort_reload) + sleep(1); + } +#endif + + return 1; + } + return 0; +} + +static char* GetFirstInterface (void) +{ + char *iface = NULL; + char errorbuf[PCAP_ERRBUF_SIZE]; +#ifdef WIN32 + pcap_if_t *alldevs; + + if ( (pcap_findalldevs(&alldevs, errorbuf) == -1) || !alldevs ) + { + FatalError( "Failed to lookup interface: %s. " + "Please specify one with -i switch\n", errorbuf); + } + + /* Pick first interface */ + iface = SnortStrdup(alldevs->name); + pcap_freealldevs(alldevs); +#else + DEBUG_WRAP(DebugMessage( + DEBUG_INIT, "interface is NULL, looking up interface....");); + + /* look up the device and get the handle */ + iface = pcap_lookupdev(errorbuf); + + if ( !iface ) + { + FatalError( "Failed to lookup interface: %s. " + "Please specify one with -i switch\n", errorbuf); + } + + DEBUG_WRAP(DebugMessage(DEBUG_INIT, "found interface %s\n", + PRINT_INTERFACE(iface));); + + iface = SnortStrdup(iface); +#endif + return iface; +} + +static const char* GetPacketSource (char** sptr) +{ + const char* intf = "other"; + + if ( ScReadMode() ) + { + intf = PQ_First(); + PQ_Show(intf); + } + else if ( !ScVersionMode() && !ScRuleDumpMode() ) + { + intf = snort_conf->interface; + + // don't get interface if daq is explicitly configured + // since we can't assume that an interface is compatible + if ( !intf && !ScTestMode() && + (!snort_conf->daq_type || + // but we make execptions for these: + // TBD make selection based on DAQ_TYPE_XXX + !strcasecmp(snort_conf->daq_type, "afpacket") || + !strcasecmp(snort_conf->daq_type, "pcap") || + !strcasecmp(snort_conf->daq_type, "dump")) ) + { + intf = GetFirstInterface(); + *sptr = (char*)intf; + } + } + return intf; +} + +static void InitPidChrootAndPrivs(pid_t pid) +{ + /* create the PID file */ + if ( !ScReadMode() && + (ScDaemonMode() || *snort_conf->pidfile_suffix || ScCreatePidFile())) + { + CreatePidFile(DAQ_GetInterfaceSpec(), pid); + } + +#ifndef WIN32 + /* Drop the Chrooted Settings */ + if (snort_conf->chroot_dir) + SetChroot(snort_conf->chroot_dir, &snort_conf->log_dir); +#endif + +#ifndef WIN32 + /* Drop privileges if requested, when initialization is done */ + SetUidGid(ScUid(), ScGid()); +#endif +} + +static void LoadDynamicPlugins(SnortConfig *sc) +{ + unsigned i; + + if (sc == NULL) + return; + + if (sc->dyn_engines != NULL) + { + /* Load the dynamic engines */ + for (i = 0; i < sc->dyn_engines->count; i++) + { + switch (sc->dyn_engines->lib_paths[i]->ptype) + { + case PATH_TYPE__FILE: + LoadDynamicEngineLib(sc->dyn_engines->lib_paths[i]->path, 0); + break; + + case PATH_TYPE__DIRECTORY: + LoadAllDynamicEngineLibs(sc->dyn_engines->lib_paths[i]->path); + break; + } + } + } + + if (sc->dyn_rules != NULL) + { + /* Load the dynamic detection libs */ + for (i = 0; i < sc->dyn_rules->count; i++) + { + switch (sc->dyn_rules->lib_paths[i]->ptype) + { + case PATH_TYPE__FILE: + LoadDynamicDetectionLib(sc->dyn_rules->lib_paths[i]->path, 0); + break; + + case PATH_TYPE__DIRECTORY: + LoadAllDynamicDetectionLibs(sc->dyn_rules->lib_paths[i]->path); + break; + } + } + } + + if (sc->dyn_preprocs != NULL) + { + /* Load the dynamic preprocessors */ + for (i = 0; i < sc->dyn_preprocs->count; i++) + { + switch (sc->dyn_preprocs->lib_paths[i]->ptype) + { + case PATH_TYPE__FILE: + LoadDynamicPreprocessor(sc->dyn_preprocs->lib_paths[i]->path, 0); + break; + + case PATH_TYPE__DIRECTORY: + LoadAllDynamicPreprocessors(sc->dyn_preprocs->lib_paths[i]->path); + break; + } + } + } + +# ifdef SIDE_CHANNEL + if (sc->dyn_side_channels != NULL) + { + /* Load the dynamic side channels */ + for (i = 0; i < sc->dyn_side_channels->count; i++) + { + switch (sc->dyn_side_channels->lib_paths[i]->ptype) + { + case PATH_TYPE__FILE: + LoadDynamicSideChannelLib(sc->dyn_side_channels->lib_paths[i]->path, 0); + break; + + case PATH_TYPE__DIRECTORY: + LoadAllDynamicSideChannelLibs(sc->dyn_side_channels->lib_paths[i]->path); + break; + } + } + } +# endif /* SIDE_CHANNEL */ + + ValidateDynamicEngines(); +} + +static void DisplayDynamicPluginVersions(void) +{ + void *lib = NULL; + DynamicPluginMeta *meta; + + RemoveDuplicateEngines(); + RemoveDuplicateDetectionPlugins(); + RemoveDuplicatePreprocessorPlugins(); +#ifdef SIDE_CHANNEL + RemoveDuplicateSideChannelPlugins(); +#endif /* SIDE_CHANNEL */ + + lib = GetNextEnginePluginVersion(NULL); + while ( lib != NULL ) + { + meta = GetDetectionPluginMetaData(lib); + + LogMessage(" Rules Engine: %s Version %d.%d \n", + meta->uniqueName, meta->major, meta->minor, meta->build); + lib = GetNextEnginePluginVersion(lib); + } + + lib = GetNextDetectionPluginVersion(NULL); + while ( lib != NULL ) + { + meta = GetEnginePluginMetaData(lib); + + LogMessage(" Rules Object: %s Version %d.%d \n", + meta->uniqueName, meta->major, meta->minor, meta->build); + lib = GetNextDetectionPluginVersion(lib); + } + + lib = GetNextPreprocessorPluginVersion(NULL); + while ( lib != NULL ) + { + meta = GetPreprocessorPluginMetaData(lib); + + LogMessage(" Preprocessor Object: %s Version %d.%d \n", + meta->uniqueName, meta->major, meta->minor, meta->build); + lib = GetNextPreprocessorPluginVersion(lib); + } + +#ifdef SIDE_CHANNEL + lib = GetNextSideChannelPluginVersion(NULL); + while ( lib != NULL ) + { + meta = GetSideChannelPluginMetaData(lib); + + LogMessage(" Side Channel Object: %s Version %d.%d \n", + meta->uniqueName, meta->major, meta->minor, meta->build); + lib = GetNextSideChannelPluginVersion(lib); + } +#endif /* SIDE_CHANNEL */ + + lib = GetNextOutputModule(NULL); + while ( lib != NULL ) + { + LogMessage(" Output Module: %s Version %u\n", + GetOutputModuleName(lib), GetOutputModuleVersion(lib)); + lib = GetNextOutputModule(lib); + } +} + +/* + * This function will print versioning information regardless of whether or + * not the quiet flag is set. If the quiet flag has been set and we want + * to honor it, check it before calling this function. + */ +static void PrintVersion(void) +{ + /* Unset quiet flag so LogMessage will print, then restore just + * in case anything other than exiting after this occurs */ + int save_quiet_flag = snort_conf->logging_flags & LOGGING_FLAG__QUIET; + + snort_conf->logging_flags &= ~LOGGING_FLAG__QUIET; + DisplayBanner(); + + // Get and print out library versions + DisplayDynamicPluginVersions(); + + snort_conf->logging_flags |= save_quiet_flag; +} + +static void PrintDaqModules (SnortConfig* sc, char* dir) +{ + if ( dir ) + ConfigDaqDir(sc, dir); + + DAQ_Load(snort_conf); + DAQ_PrintTypes(stdout); + DAQ_Unload(); +} + +#ifdef EXIT_CHECK +static uint64_t exitTime = 0; + +static void ExitCheckStart (void) +{ + if ( exitTime ) + { + return; + } + LogMessage("Exit Check: signaling at " STDu64 "callback\n", (long long unsigned int)pc.total_from_daq); + get_clockticks(exitTime); +#ifndef WIN32 + kill(0, SIGINT); // send to all processes in my process group +#else + raise(SIGINT); +#endif +} + +static void ExitCheckEnd (void) +{ + uint64_t now = 0; + double usecs = 0.0; + + if ( !exitTime ) + { + LogMessage( + "Exit Check: callbacks = " STDu64 "(limit not reached)\n", + (long long unsigned int)pc.total_from_daq + ); + return; + } + get_clockticks(now); + exitTime = now - exitTime; + usecs = exitTime / get_ticks_per_usec(); + + LogMessage("Exit Check: usecs = %f\n", usecs); +} +#endif + +#ifdef HAVE_DAQ_ACQUIRE_WITH_META +static int MetaCallback( + void* user, const DAQ_MetaHdr_t *metahdr, const uint8_t* data) +{ + tSfPolicyId policy_id = getDefaultPolicy(); + SnortPolicy *policy; + PreprocMetaEvalFuncNode *idx; + PROFILE_VARS; + +#ifdef SIDE_CHANNEL + if (ScSideChannelEnabled() && !snort_process_lock_held) + { + pthread_mutex_lock(&snort_process_lock); + snort_process_lock_held = true; + } +#endif + + /* First thing we do is process a Usr signal that we caught */ + if (SignalCheck()) + { +#ifndef SNORT_RELOAD + /* Got SIGNAL_SNORT_RELOAD */ + Restart(); +#endif + } + + CheckForReload(); + + PREPROC_PROFILE_START(metaPerfStats); + + policy = snort_conf->targeted_policies[policy_id]; + idx = policy->preproc_meta_eval_funcs; + while (idx != NULL) + { + idx->func(metahdr->type, data); + idx = idx->next; + } + + PREPROC_PROFILE_END(metaPerfStats); + +#if defined(WIN32) && defined(ENABLE_WIN32_SERVICE) + if (ScTerminateService() || ScPauseService()) + { + return 0; // time to go + } +#endif + + ControlSocketDoWork(0); +#ifdef SIDE_CHANNEL + SideChannelDrainRX(0); +#endif + + return 0; +} +#endif + +// non-local for easy access from core +static Packet s_packet; +static DAQ_PktHdr_t s_pkth; +static uint8_t s_data[65536]; + +static DAQ_Verdict PacketCallback( + void* user, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt) +{ + int inject = 0; + DAQ_Verdict verdict = DAQ_VERDICT_PASS; + PROFILE_VARS; + + PREPROC_PROFILE_START(totalPerfStats); + +#ifdef SIDE_CHANNEL + if (ScSideChannelEnabled() && !snort_process_lock_held) + { + pthread_mutex_lock(&snort_process_lock); + snort_process_lock_held = true; + } +#endif + +#ifdef EXIT_CHECK + if (snort_conf->exit_check && (pc.total_from_daq >= snort_conf->exit_check)) + ExitCheckStart(); +#endif + + /* First thing we do is process a Usr signal that we caught */ + if (SignalCheck()) + { +#ifndef SNORT_RELOAD + /* Got SIGNAL_SNORT_RELOAD */ + PREPROC_PROFILE_END(totalPerfStats); + Restart(); +#endif + } + + pc.total_from_daq++; + + /* Increment counter that we're evaling rules for caching results */ + rule_eval_pkt_count++; + +#ifdef TARGET_BASED + /* Load in a new attribute table if we need to... */ + AttributeTableReloadCheck(); +#endif + + CheckForReload(); + + /* Save off the time of each and every packet */ + packet_time_update(&pkthdr->ts); + +#ifdef REG_TEST + if ( snort_conf->pkt_skip && pc.total_from_daq <= snort_conf->pkt_skip ) + { + PREPROC_PROFILE_END(totalPerfStats); + return verdict; + } +#endif + +#if defined(WIN32) && defined(ENABLE_WIN32_SERVICE) + if (ScTerminateService() || ScPauseService()) + { + PREPROC_PROFILE_END(totalPerfStats); + return verdict; // time to go + } +#endif + + /* reset the thresholding subsystem checks for this packet */ + sfthreshold_reset(); + + PREPROC_PROFILE_START(eventqPerfStats); + SnortEventqReset(); + Replace_ResetQueue(); +#ifdef ACTIVE_RESPONSE + Active_ResetQueue(); +#endif + PREPROC_PROFILE_END(eventqPerfStats); + + verdict = ProcessPacket(&s_packet, pkthdr, pkt, NULL); + +#ifdef ACTIVE_RESPONSE + if ( Active_ResponseQueued() ) + { + Active_SendResponses(&s_packet); + } +#endif + if ( Active_PacketWasDropped() ) + { + if ( verdict == DAQ_VERDICT_PASS ) + verdict = DAQ_VERDICT_BLOCK; + } + else + { + Replace_ModifyPacket(&s_packet); + + if ( s_packet.packet_flags & PKT_MODIFIED ) + { + // this packet was normalized and/or has replacements + Encode_Update(&s_packet); + verdict = DAQ_VERDICT_REPLACE; + } +#ifdef NORMALIZER + else if ( s_packet.packet_flags & PKT_RESIZED ) + { + // we never increase, only trim, but + // daq doesn't support resizing wire packet + if ( !DAQ_Inject(s_packet.pkth, 0, s_packet.pkt, s_packet.pkth->pktlen) ) + { + verdict = DAQ_VERDICT_BLOCK; + inject = 1; + } + } +#endif + else + { + if ((s_packet.packet_flags & PKT_IGNORE) || + (stream_api && (stream_api->get_ignore_direction(s_packet.ssnptr) == SSN_DIR_BOTH))) + { + if ( !Active_GetTunnelBypass() ) + { + verdict = DAQ_VERDICT_WHITELIST; + } + else + { + verdict = DAQ_VERDICT_PASS; + pc.internal_whitelist++; + } + } + else if ( s_packet.packet_flags & PKT_TRUST ) + { + if (stream_api) + stream_api->set_ignore_direction(s_packet.ssnptr, SSN_DIR_BOTH); + + verdict = DAQ_VERDICT_WHITELIST; + } + else + { + verdict = DAQ_VERDICT_PASS; + } + } + } +#ifdef ENABLE_HA + // This needs to be called here since the session could + // have been updated anywhere up to this point. :( + if (stream_api) + stream_api->process_ha(s_packet.ssnptr); +#endif + + /* Collect some "on the wire" stats about packet size, etc */ + UpdateWireStats(&sfBase, pkthdr->caplen, Active_PacketWasDropped(), inject); + Active_Reset(); + Encode_Reset(); + + checkLWSessionTimeout(4, pkthdr->ts.tv_sec); + ControlSocketDoWork(0); +#ifdef SIDE_CHANNEL + SideChannelDrainRX(0); +#endif + + s_packet.pkth = NULL; // no longer avail on segv + + PREPROC_PROFILE_END(totalPerfStats); + return verdict; +} + +/* + * Function: ShowUsage(char *) + * + * Purpose: Display the program options and exit + * + * Arguments: argv[0] => name of the program (argv[0]) + * + * Returns: 0 => success + */ +static int ShowUsage(char *program_name) +{ + fprintf(stdout, "USAGE: %s [-options] \n", program_name); +#if defined(WIN32) && defined(ENABLE_WIN32_SERVICE) + fprintf(stdout, " %s %s %s [-options] \n", program_name + , SERVICE_CMDLINE_PARAM + , SERVICE_INSTALL_CMDLINE_PARAM); + fprintf(stdout, " %s %s %s\n", program_name + , SERVICE_CMDLINE_PARAM + , SERVICE_UNINSTALL_CMDLINE_PARAM); + fprintf(stdout, " %s %s %s\n", program_name + , SERVICE_CMDLINE_PARAM + , SERVICE_SHOW_CMDLINE_PARAM); +#endif + +#ifdef WIN32 +# define FPUTS_WIN32(msg) fputs(msg,stdout) +# define FPUTS_UNIX(msg) NULL +# define FPUTS_BOTH(msg) fputs(msg,stdout) +#else +# define FPUTS_WIN32(msg) +# define FPUTS_UNIX(msg) fputs(msg,stdout) +# define FPUTS_BOTH(msg) fputs(msg,stdout) +#endif + + FPUTS_BOTH ("Options:\n"); + FPUTS_BOTH (" -A Set alert mode: fast, full, console, test or none " + " (alert file alerts only)\n"); + FPUTS_UNIX (" \"unsock\" enables UNIX socket logging (experimental).\n"); + FPUTS_BOTH (" -b Log packets in tcpdump format (much faster!)\n"); + FPUTS_BOTH (" -B Obfuscated IP addresses in alerts and packet dumps using CIDR mask\n"); + FPUTS_BOTH (" -c Use Rules File \n"); + FPUTS_BOTH (" -C Print out payloads with character data only (no hex)\n"); + FPUTS_BOTH (" -d Dump the Application Layer\n"); + FPUTS_UNIX (" -D Run Snort in background (daemon) mode\n"); + FPUTS_BOTH (" -e Display the second layer header info\n"); + FPUTS_WIN32(" -E Log alert messages to NT Eventlog. (Win32 only)\n"); + FPUTS_BOTH (" -f Turn off fflush() calls after binary log writes\n"); + FPUTS_BOTH (" -F Read BPF filters from file \n"); + FPUTS_UNIX (" -g Run snort gid as group (or gid) after initialization\n"); + FPUTS_BOTH (" -G <0xid> Log Identifier (to uniquely id events for multiple snorts)\n"); + FPUTS_BOTH (" -h Set home network = \n" + " (for use with -l or -B, does NOT change $HOME_NET in IDS mode)\n"); + FPUTS_BOTH (" -H Make hash tables deterministic.\n"); + FPUTS_BOTH (" -i Listen on interface \n"); + FPUTS_BOTH (" -I Add Interface name to alert output\n"); + FPUTS_BOTH (" -k Checksum mode (all,noip,notcp,noudp,noicmp,none)\n"); + FPUTS_BOTH (" -K Logging mode (pcap[default],ascii,none)\n"); + FPUTS_BOTH (" -l Log to directory \n"); + FPUTS_BOTH (" -L Log to this tcpdump file\n"); + FPUTS_UNIX (" -M Log messages to syslog (not alerts)\n"); + FPUTS_UNIX (" -m Set umask = \n"); + FPUTS_BOTH (" -n Exit after receiving packets\n"); + FPUTS_BOTH (" -N Turn off logging (alerts still work)\n"); + FPUTS_BOTH (" -O Obfuscate the logged IP addresses\n"); + FPUTS_BOTH (" -p Disable promiscuous mode sniffing\n"); + printf (" -P Set explicit snaplen of packet (default: %d)\n", + DAQ_GetSnapLen()); + FPUTS_BOTH (" -q Quiet. Don't show banner and status report\n"); +#ifndef WIN32 + FPUTS_BOTH (" -Q Enable inline mode operation.\n"); +#endif + FPUTS_BOTH (" -r Read and process tcpdump file \n"); + FPUTS_BOTH (" -R Include 'id' in snort_intf.pid file name\n"); + FPUTS_BOTH (" -s Log alert messages to syslog\n"); + FPUTS_BOTH (" -S Set rules file variable n equal to value v\n"); + FPUTS_UNIX (" -t Chroots process to after initialization\n"); + FPUTS_BOTH (" -T Test and report on the current Snort configuration\n"); + FPUTS_UNIX (" -u Run snort uid as user (or uid) after initialization\n"); + FPUTS_BOTH (" -U Use UTC for timestamps\n"); + FPUTS_BOTH (" -v Be verbose\n"); + FPUTS_BOTH (" -V Show version number\n"); + FPUTS_WIN32(" -W Lists available interfaces. (Win32 only)\n"); +#if defined(NON_ETHER_DECODER) && defined(DLT_IEEE802_11) + FPUTS_BOTH (" -w Dump 802.11 management and control frames\n"); +#endif + FPUTS_BOTH (" -X Dump the raw packet data starting at the link layer\n"); + FPUTS_BOTH (" -x Exit if Snort configuration problems occur\n"); + FPUTS_BOTH (" -y Include year in timestamp in the alert and log files\n"); + FPUTS_BOTH (" -Z Set the performonitor preprocessor file path and name\n"); + FPUTS_BOTH (" -? Show this information\n"); + FPUTS_BOTH (" are standard BPF options, as seen in TCPDump\n"); + + FPUTS_BOTH ("Longname options and their corresponding single char version\n"); + FPUTS_BOTH (" --logid <0xid> Same as -G\n"); + FPUTS_BOTH (" --perfmon-file Same as -Z\n"); + FPUTS_BOTH (" --pid-path Specify the directory for the Snort PID file\n"); + FPUTS_BOTH (" --snaplen Same as -P\n"); + FPUTS_BOTH (" --help Same as -?\n"); + FPUTS_BOTH (" --version Same as -V\n"); + FPUTS_BOTH (" --alert-before-pass Process alert, drop, sdrop, or reject before pass, default is pass before alert, drop,...\n"); + FPUTS_BOTH (" --treat-drop-as-alert Converts drop, sdrop, and reject rules into alert rules during startup\n"); + FPUTS_BOTH (" --treat-drop-as-ignore Use drop, sdrop, and reject rules to ignore session traffic when not inline.\n"); + FPUTS_BOTH (" --process-all-events Process all queued events (drop, alert,...), default stops after 1st action group\n"); + FPUTS_BOTH (" --enable-inline-test Enable Inline-Test Mode Operation\n"); + FPUTS_BOTH (" --dynamic-engine-lib Load a dynamic detection engine\n"); + FPUTS_BOTH (" --dynamic-engine-lib-dir Load all dynamic engines from directory\n"); + FPUTS_BOTH (" --dynamic-detection-lib Load a dynamic rules library\n"); + FPUTS_BOTH (" --dynamic-detection-lib-dir Load all dynamic rules libraries from directory\n"); + FPUTS_BOTH (" --dump-dynamic-rules Creates stub rule files of all loaded rules libraries\n"); + FPUTS_BOTH (" --dynamic-preprocessor-lib Load a dynamic preprocessor library\n"); + FPUTS_BOTH (" --dynamic-preprocessor-lib-dir Load all dynamic preprocessor libraries from directory\n"); + FPUTS_BOTH (" --dynamic-output-lib Load a dynamic output library\n"); + FPUTS_BOTH (" --dynamic-output-lib-dir Load all dynamic output libraries from directory\n"); + FPUTS_UNIX (" --create-pidfile Create PID file, even when not in Daemon mode\n"); + FPUTS_UNIX (" --nolock-pidfile Do not try to lock Snort PID file\n"); + FPUTS_UNIX (" --no-interface-pidfile Do not include the interface name in Snort PID file\n"); +#ifdef INLINE_FAILOPEN + FPUTS_UNIX (" --disable-inline-init-failopen Do not fail open and pass packets while initializing with inline mode.\n"); +#endif +#ifdef TARGET_BASED + FPUTS_UNIX (" --disable-attribute-reload-thread Do not create a thread to reload the attribute table\n"); +#endif + FPUTS_BOTH (" --pcap-single Same as -r.\n"); + FPUTS_BOTH (" --pcap-file file that contains a list of pcaps to read - read mode is implied.\n"); + FPUTS_BOTH (" --pcap-list \"\" a space separated list of pcaps to read - read mode is implied.\n"); + FPUTS_UNIX (" --pcap-dir a directory to recurse to look for pcaps - read mode is implied.\n"); + FPUTS_UNIX (" --pcap-filter filter to apply when getting pcaps from file or directory.\n"); + FPUTS_UNIX (" --pcap-no-filter reset to use no filter when getting pcaps from file or directory.\n"); + FPUTS_BOTH (" --pcap-loop this option will read the pcaps specified on command line continuously.\n" + " for times. A value of 0 will read until Snort is terminated.\n"); + FPUTS_BOTH (" --pcap-reset if reading multiple pcaps, reset snort to post-configuration state before reading next pcap.\n"); +#if defined(SNORT_RELOAD) && !defined(WIN32) + FPUTS_BOTH (" --pcap-reload if reading multiple pcaps, reload snort config between pcaps.\n"); +#endif + FPUTS_BOTH (" --pcap-show print a line saying what pcap is currently being read.\n"); + FPUTS_BOTH (" --exit-check Signal termination after callbacks from DAQ_Acquire(), showing the time it\n" + " takes from signaling until DAQ_Stop() is called.\n"); + FPUTS_BOTH (" --conf-error-out Same as -x\n"); +#ifdef MPLS + FPUTS_BOTH (" --enable-mpls-multicast Allow multicast MPLS\n"); + FPUTS_BOTH (" --enable-mpls-overlapping-ip Handle overlapping IPs within MPLS clouds\n"); + FPUTS_BOTH (" --max-mpls-labelchain-len Specify the max MPLS label chain\n"); + FPUTS_BOTH (" --mpls-payload-type Specify the protocol (ipv4, ipv6, ethernet) that is encapsulated by MPLS\n"); +#endif + FPUTS_BOTH (" --require-rule-sid Require that all snort rules have SID specified.\n"); + FPUTS_BOTH (" --daq Select packet acquisition module (default is pcap).\n"); + FPUTS_BOTH (" --daq-mode Select the DAQ operating mode.\n"); + FPUTS_BOTH (" --daq-var Specify extra DAQ configuration variable.\n"); + FPUTS_BOTH (" --daq-dir Tell snort where to find desired DAQ.\n"); + FPUTS_BOTH (" --daq-list[=] List packet acquisition modules available in dir. Default is static modules only.\n"); + FPUTS_BOTH (" --dirty-pig Don't flush packets and release memory on shutdown.\n"); + FPUTS_BOTH (" --cs-dir Directory to use for control socket.\n"); + FPUTS_BOTH (" --ha-peer Activate live high-availability state sharing with peer.\n"); + FPUTS_BOTH (" --ha-out Write high-availability events to this file.\n"); + FPUTS_BOTH (" --ha-in Read high-availability events from this file on startup (warm-start).\n"); +#undef FPUTS_WIN32 +#undef FPUTS_UNIX +#undef FPUTS_BOTH + return 0; +} + +static void ParseCmdLineDynamicLibInfo(SnortConfig *sc, int type, char *path) +{ + DynamicLibInfo *dli = NULL; + DynamicLibPath *dlp = NULL; + + if ((sc == NULL) || (path == NULL)) + FatalError("%s(%d) NULL arguments.\n", __FILE__, __LINE__); + + switch (type) + { + case DYNAMIC_PREPROC_FILE: + case DYNAMIC_PREPROC_DIRECTORY: + DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Dynamic preprocessor specifier\n");); + if (sc->dyn_preprocs == NULL) + { + sc->dyn_preprocs = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo)); + sc->dyn_preprocs->type = DYNAMIC_TYPE__PREPROCESSOR; + } + else if (sc->dyn_preprocs->count >= MAX_DYNAMIC_LIBS) + { + FatalError("Maximum number of loaded Dynamic Preprocessor Libs " + "(%d) exceeded.\n", MAX_DYNAMIC_LIBS); + } + + dli = sc->dyn_preprocs; + break; + + case DYNAMIC_LIBRARY_FILE: + case DYNAMIC_LIBRARY_DIRECTORY: + DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Dynamic detection specifier\n");); + if (sc->dyn_rules == NULL) + { + sc->dyn_rules = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo)); + sc->dyn_rules->type = DYNAMIC_TYPE__DETECTION; + } + else if (sc->dyn_rules->count >= MAX_DYNAMIC_LIBS) + { + FatalError("Maximum number of loaded Dynamic Detection Libs " + "(%d) exceeded.\n", MAX_DYNAMIC_LIBS); + } + + dli = sc->dyn_rules; + break; + + case DYNAMIC_ENGINE_FILE: + case DYNAMIC_ENGINE_DIRECTORY: + DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Dynamic engine specifier\n");); + if (sc->dyn_engines == NULL) + { + sc->dyn_engines = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo)); + sc->dyn_engines->type = DYNAMIC_TYPE__ENGINE; + } + else if (sc->dyn_engines->count >= MAX_DYNAMIC_LIBS) + { + FatalError("Maximum number of loaded Dynamic Engine Libs " + "(%d) exceeded.\n", MAX_DYNAMIC_LIBS); + } + + dli = sc->dyn_engines; + break; + case DYNAMIC_OUTPUT_FILE: + output_load_module(path); + return; + break; + case DYNAMIC_OUTPUT_DIRECTORY: + output_load(path); + return; + break; + + + default: + FatalError("%s(%d) Invalid dynamic type: %d\n", __FILE__, __LINE__, type); + break; + } + + dlp = (DynamicLibPath *)SnortAlloc(sizeof(DynamicLibPath)); + switch (type) + { + case DYNAMIC_PREPROC_FILE: + case DYNAMIC_LIBRARY_FILE: + case DYNAMIC_ENGINE_FILE: + case DYNAMIC_OUTPUT_FILE: + dlp->ptype = PATH_TYPE__FILE; + break; + + case DYNAMIC_PREPROC_DIRECTORY: + case DYNAMIC_LIBRARY_DIRECTORY: + case DYNAMIC_ENGINE_DIRECTORY: + case DYNAMIC_OUTPUT_DIRECTORY: + dlp->ptype = PATH_TYPE__DIRECTORY; + break; + + default: + FatalError("%s(%d) Invalid dynamic type: %d\n", __FILE__, __LINE__, type); + break; + } + + dlp->path = SnortStrdup(path); + dli->lib_paths[dli->count] = dlp; + dli->count++; +} + +/* + * Function: ParseCmdLine(int, char **) + * + * Parses command line arguments + * + * Arguments: + * int + * count of arguments passed to the routine + * char ** + * 2-D character array, contains list of command line args + * + * Returns: None + * + */ + +static void ParseCmdLine(int argc, char **argv) +{ + int ch; + int option_index = -1; + char *endptr; /* for SnortStrtol calls */ + SnortConfig *sc; + int output_logging = 0; + int output_alerting = 0; + int syslog_configured = 0; +#ifndef WIN32 + int daemon_configured = 0; +#endif + + DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Parsing command line...\n");); + + if (snort_cmd_line_conf != NULL) + { + FatalError("%s(%d) Trying to parse the command line again.\n", + __FILE__, __LINE__); + } + + snort_cmd_line_conf = SnortConfNew(); + snort_conf = snort_cmd_line_conf; /* Set the global for log messages */ + sc = snort_cmd_line_conf; + + optind = 1; + + /* Look for a -D and/or -M switch so we can start logging to syslog + * with "snort" tag right away */ + while ((ch = getopt_long(argc, argv, valid_options, long_options, &option_index)) != -1) + { + switch (ch) + { + case 'M': + if (syslog_configured) + break; + + /* If daemon or logging to syslog use "snort" as identifier and + * start logging there now */ + openlog("snort", LOG_PID | LOG_CONS, LOG_DAEMON); + + sc->logging_flags |= LOGGING_FLAG__SYSLOG; + syslog_configured = 1; + break; + +#ifndef WIN32 + case 'E': + sc->run_flags |= RUN_FLAG__DAEMON_RESTART; + /* Fall through */ + case 'D': + if (daemon_configured) + break; + + /* If daemon or logging to syslog use "snort" as identifier and + * start logging there now */ + openlog("snort", LOG_PID | LOG_CONS, LOG_DAEMON); + + ConfigDaemon(sc, optarg); + daemon_configured = 1; + break; +#endif + + case 'q': + /* Turn on quiet mode if configured so any log messages that may + * be printed while parsing the command line before the quiet option + * is read won't be printed */ + ConfigQuiet(sc, NULL); + break; + + case '?': /* show help and exit with 1 */ + PrintVersion(); + ShowUsage(argv[0]); + exit(1); + break; + + default: + break; + } + } + + /* + ** Set this so we know whether to return 1 on invalid input. + ** Snort uses '?' for help and getopt uses '?' for telling us there + ** was an invalid option, so we can't use that to tell invalid input. + ** Instead, we check optopt and it will tell us. + */ + optopt = 0; + optind = 1; + + /* loop through each command line var and process it */ + while ((ch = getopt_long(argc, argv, valid_options, long_options, &option_index)) != -1) + { + DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Processing cmd line switch: %c\n", ch);); + + switch (ch) + { + case DYNAMIC_ENGINE_FILE: /* Load dynamic engine specified */ + case DYNAMIC_ENGINE_DIRECTORY: /* Load dynamic engine specified */ + case DYNAMIC_PREPROC_FILE: /* Load dynamic preprocessor lib specified */ + case DYNAMIC_PREPROC_DIRECTORY: + case DYNAMIC_LIBRARY_FILE: /* Load dynamic detection lib specified */ + case DYNAMIC_LIBRARY_DIRECTORY: + case DYNAMIC_OUTPUT_FILE: /* Load dynamic output lib specified */ + case DYNAMIC_OUTPUT_DIRECTORY: + ParseCmdLineDynamicLibInfo(sc, ch, optarg); + break; + + case DUMP_DYNAMIC_RULES: + ConfigDumpDynamicRulesPath(sc, optarg); + break; + + case ALERT_BEFORE_PASS: + ConfigAlertBeforePass(sc, NULL); + break; + + case PROCESS_ALL_EVENTS: + ConfigProcessAllEvents(sc, NULL); + break; + + case TREAT_DROP_AS_ALERT: + ConfigTreatDropAsAlert(sc, NULL); + break; + + case TREAT_DROP_AS_IGNORE: + ConfigTreatDropAsIgnore(sc, NULL); + break; + + case PID_PATH: + ConfigPidPath(sc, optarg); + break; + + case CREATE_PID_FILE: + ConfigCreatePidFile(sc, NULL); + break; + + case NOLOCK_PID_FILE: + sc->run_flags |= RUN_FLAG__NO_LOCK_PID_FILE; + break; + + case NO_IFACE_PID_FILE: + sc->run_flags |= RUN_FLAG__NO_IFACE_PID_FILE; + break; + +#ifdef INLINE_FAILOPEN + case DISABLE_INLINE_FAILOPEN: + ConfigDisableInlineFailopen(sc, NULL); + break; +#endif + case NO_LOGGING_TIMESTAMPS: + ConfigNoLoggingTimestamps(sc, NULL); + break; + +#ifdef EXIT_CHECK + case ARG_EXIT_CHECK: + { + char* endPtr; + + sc->exit_check = SnortStrtoul(optarg, &endPtr, 0); + if ((errno == ERANGE) || (*endPtr != '\0')) + FatalError("--exit-check value must be non-negative integer\n"); + + LogMessage("Exit Check: limit = "STDu64" callbacks\n", (long long unsigned int)sc->exit_check); + } + + break; +#endif + +#ifdef TARGET_BASED + case DISABLE_ATTRIBUTE_RELOAD: + ConfigDisableAttributeReload(sc, NULL); + break; +#endif + case DETECTION_SEARCH_METHOD: + if (sc->fast_pattern_config != NULL) + FatalError("Can only configure search method once.\n"); + + sc->fast_pattern_config = FastPatternConfigNew(); + + if (fpSetDetectSearchMethod(sc->fast_pattern_config, optarg) == -1) + FatalError("Invalid search method: %s.\n", optarg); + + break; + + case ARG_DAQ_TYPE: + ConfigDaqType(sc, optarg); + break; + + case ARG_DAQ_MODE: + ConfigDaqMode(sc, optarg); + break; + + case ARG_DAQ_VAR: + ConfigDaqVar(sc, optarg); + break; + + case ARG_DAQ_DIR: + ConfigDaqDir(sc, optarg); + break; + + case ARG_DAQ_LIST: + PrintDaqModules(sc, optarg); + exit(0); + break; + + case ARG_DIRTY_PIG: + ConfigDirtyPig(sc, optarg); + break; + + case 'A': /* alert mode */ + output_alerting = 1; + + if (strcasecmp(optarg, ALERT_MODE_OPT__NONE) == 0) + { + sc->no_alert = 1; + } + else if (strcasecmp(optarg, ALERT_MODE_OPT__PKT_CNT) == 0) + { + /* print packet count at start of alert */ + sc->output_flags |= OUTPUT_FLAG__ALERT_PKT_CNT; + } + else if (strcasecmp(optarg, ALERT_MODE_OPT__FULL) == 0) + { + ParseOutput(sc, NULL, "alert_full"); + } + else if (strcasecmp(optarg, "console:" ALERT_MODE_OPT__FULL) == 0) + { + ParseOutput(sc, NULL, "alert_full: stdout"); + } + else if (strcasecmp(optarg, ALERT_MODE_OPT__FAST) == 0) + { + ParseOutput(sc, NULL, "alert_fast"); + } + else if ( + strcasecmp(optarg, "console:" ALERT_MODE_OPT__FAST) == 0 || + strcasecmp(optarg, ALERT_MODE_OPT__CONSOLE) == 0 ) + { + ParseOutput(sc, NULL, "alert_fast: stdout"); + } + else if ((strcasecmp(optarg, ALERT_MODE_OPT__CMG) == 0) || + (strcasecmp(optarg, ALERT_MODE_OPT__JH) == 0) || + (strcasecmp(optarg, ALERT_MODE_OPT__DJR) == 0)) + { + ParseOutput(sc, NULL, "alert_fast: stdout packet"); + sc->no_log = 1; + /* turn on layer2 headers */ + sc->output_flags |= OUTPUT_FLAG__SHOW_DATA_LINK; + /* turn on data dump */ + sc->output_flags |= OUTPUT_FLAG__APP_DATA; + } + else if (strcasecmp(optarg, ALERT_MODE_OPT__AJK) == 0) + { + ParseOutput(sc, NULL, "unified2"); + } + else if (strcasecmp(optarg, ALERT_MODE_OPT__UNIX_SOCK) == 0) + { + ParseOutput(sc, NULL, "alert_unixsock"); + } + else if (strcasecmp(optarg, ALERT_MODE_OPT__TEST) == 0) + { + ParseOutput(sc, NULL, "alert_test"); + sc->no_log = 1; + } + else if (strcasecmp(optarg, "console:" ALERT_MODE_OPT__TEST) == 0) + { + ParseOutput(sc, NULL, "alert_test: stdout"); + sc->no_log = 1; + } + else + { + FatalError("Unknown command line alert option: %s\n", optarg); + } + + break; + + case 'b': /* log packets in binary format for post-processing */ + ParseOutput(sc, NULL, "log_tcpdump"); + output_logging = 1; + break; + + case 'B': /* obfuscate with a substitution mask */ + ConfigObfuscationMask(sc, optarg); + break; + + case 'c': /* use configuration file x */ + sc->run_mode_flags |= RUN_MODE_FLAG__IDS; + snort_conf_file = SnortStrdup(optarg); + break; + + case 'C': /* dump the application layer as text only */ + ConfigDumpCharsOnly(sc, NULL); + break; + + case 'd': /* dump the application layer data */ + ConfigDumpPayload(sc, NULL); + break; + +#ifndef WIN32 + case 'E': /* Restarting from daemon mode */ + case 'D': /* daemon mode */ + /* These are parsed at the beginning so as to start logging + * to syslog right away */ + break; +#endif + + case 'e': /* show second level header info */ + ConfigDecodeDataLink(sc, NULL); + break; +#ifdef WIN32 + case 'E': /* log alerts to Event Log */ + ParseOutput(sc, NULL, "alert_syslog"); + sc->logging_flags &= ~LOGGING_FLAG__SYSLOG_REMOTE; + output_alerting = 1; + break; +#endif + case 'f': + sc->output_flags |= OUTPUT_FLAG__LINE_BUFFER; + break; + + case 'F': /* read BPF filter in from a file */ + ConfigBpfFile(sc, optarg); + break; + +#ifndef WIN32 + case 'g': /* setgid */ + ConfigSetGid(sc, optarg); + break; +#endif + + case 'G': /* snort loG identifier */ + sc->event_log_id = SnortStrtoul(optarg, &endptr, 0); + if ((errno == ERANGE) || (*endptr != '\0') || + (sc->event_log_id > UINT16_MAX)) + { + FatalError("Snort log identifier invalid: %s. It must " + "be between 0 and %u.\n", optarg, UINT16_MAX); + } + + /* Forms upper 2 bytes. Lower two bytes are the event id */ + sc->event_log_id <<= 16; + + break; + + case 'h': + /* set home network to x, this will help determine what to set + * logging diectories to */ + ConfigReferenceNet(sc, optarg); + break; + + case 'H': + sc->run_flags |= RUN_FLAG__STATIC_HASH; + break; + + case 'i': + ConfigInterface(sc, optarg); + break; + + case 'I': /* add interface name to alert string */ + ConfigAlertWithInterfaceName(sc, NULL); + break; + + case 'k': /* set checksum mode */ + ConfigChecksumMode(sc, optarg); + break; + + case 'K': /* log mode */ + if (strcasecmp(optarg, LOG_MODE_OPT__NONE) == 0) + { + sc->no_log = 1; + } + else if (strcasecmp(optarg, LOG_MODE_OPT__PCAP) == 0) + { + ParseOutput(sc, NULL, "log_tcpdump"); + } + else if (strcasecmp(optarg, LOG_MODE_OPT__ASCII) == 0) + { + ParseOutput(sc, NULL, "log_ascii"); + } + else + { + FatalError("Unknown command line log option: %s\n", optarg); + } + + output_logging = 1; + break; + + case 'l': /* use log dir */ + ConfigLogDir(sc, optarg); + break; + + case 'L': /* set BinLogFile name */ + /* implies tcpdump format logging + * 256 is kind of arbitrary but should be more than enough */ + if (strlen(optarg) < 256) + { + ParseOutput(sc, NULL, "log_tcpdump"); + sc->pcap_log_file = SnortStrdup(optarg); + } + else + { + FatalError("log_tcpdump file name \"%s\" has to be less " + "than or equal to 256 characters.\n", optarg); + } + + output_logging = 1; + break; + + case 'M': + /* This is parsed at the beginning so as to start logging + * to syslog right away */ + break; + +#ifndef WIN32 + case 'm': /* set the umask for the output files */ + ConfigUmask(sc, optarg); + break; +#endif + + case 'n': /* grab x packets and exit */ + ConfigPacketCount(sc, optarg); + break; + + case 'N': /* no logging mode */ + ConfigNoLog(sc, NULL); + break; + + case 'O': /* obfuscate the logged IP addresses for privacy */ + ConfigObfuscate(sc, NULL); + break; + + case 'p': /* disable explicit promiscuous mode */ + ConfigNoPromiscuous(sc, NULL); + break; + + case 'P': /* explicitly define snaplength of packets */ + ConfigPacketSnaplen(sc, optarg); + break; + + case 'q': /* no stdout output mode */ + /* This is parsed at the beginning so as to start logging + * in quiet mode right away */ + break; + +#ifndef WIN32 + case 'Q': + LogMessage("Enabling inline operation\n"); + sc->run_flags |= RUN_FLAG__INLINE; + break; +#endif + case ENABLE_INLINE_TEST: + LogMessage("Enable Inline Test Mode\n"); + sc->run_flags |= RUN_FLAG__INLINE_TEST; + break; + + + case 'r': /* read packets from a TCPdump file instead of the net */ + case PCAP_SINGLE: + PQ_Single(optarg); + sc->run_flags |= RUN_FLAG__READ; + break; + + case 'R': /* augment pid file name suffix */ + if ((strlen(optarg) >= MAX_PIDFILE_SUFFIX) || (strlen(optarg) <= 0) || + (strstr(optarg, "..") != NULL) || (strstr(optarg, "/") != NULL)) + { + FatalError("Invalid pidfile suffix: %s. Suffix must " + "less than %u characters and not have " + "\"..\" or \"/\" in the name.\n", optarg, + MAX_PIDFILE_SUFFIX); + } + + SnortStrncpy(sc->pidfile_suffix, optarg, sizeof(sc->pidfile_suffix)); + break; + + case 's': /* log alerts to syslog */ +#ifndef WIN32 + ParseOutput(sc, NULL, "alert_syslog"); +#else + sc->logging_flags |= LOGGING_FLAG__SYSLOG_REMOTE; +#endif + output_alerting = 1; + break; + + case 'S': /* set a rules file variable */ + { + char *equal_ptr = strchr(optarg, '='); + VarNode *node; + + if (equal_ptr == NULL) + { + FatalError("Format for command line variable definitions " + "is:\n -S var=value\n"); + } + + /* Save these and parse when snort conf is parsed so + * they can be added to the snort conf configuration */ + node = (VarNode *)SnortAlloc(sizeof(VarNode)); + node->name = SnortStrndup(optarg, equal_ptr - optarg); + + /* Make sure it's not already in the list */ + if (cmd_line_var_list != NULL) + { + VarNode *tmp = cmd_line_var_list; + + while (tmp != NULL) + { + if (strcasecmp(tmp->name, node->name) == 0) + { + FreeVarList(cmd_line_var_list); + FatalError("Duplicate variable name: %s.\n", + tmp->name); + } + + tmp = tmp->next; + } + } + + node->value = SnortStrdup(equal_ptr + 1); + node->line = SnortStrdup(optarg); + node->next = cmd_line_var_list; + cmd_line_var_list = node; + + /* Put line in a parser parsable form - we know the + * equals is already there */ + equal_ptr = strchr(node->line, '='); + *equal_ptr = ' '; + } + + break; + +#ifndef WIN32 + case 't': /* chroot to the user specified directory */ + ConfigChrootDir(sc, optarg); + break; +#endif + + case 'T': /* test mode, verify that the rules load properly */ + sc->run_mode_flags |= RUN_MODE_FLAG__TEST; + break; + +#ifndef WIN32 + case 'u': /* setuid */ + ConfigSetUid(sc, optarg); + break; +#endif + + case 'U': /* use UTC */ + ConfigUtc(sc, NULL); + break; + + case 'v': /* be verbose */ + ConfigVerbose(sc, NULL); + break; + + case 'V': /* prog ver already gets printed out, so we just exit */ + sc->run_mode_flags |= RUN_MODE_FLAG__VERSION; + sc->logging_flags |= LOGGING_FLAG__QUIET; + break; + +#ifdef WIN32 + case 'W': + PrintVersion(); + PrintAllInterfaces(); + exit(0); /* XXX Should maybe use CleanExit here? */ + break; +#endif + +#if !defined(NO_NON_ETHER_DECODER) && defined(DLT_IEEE802_11) + case 'w': /* show 802.11 all frames info */ + sc->output_flags |= OUTPUT_FLAG__SHOW_WIFI_MGMT; + break; +#endif + case 'X': /* display verbose packet bytecode dumps */ + ConfigDumpPayloadVerbose(sc, NULL); + break; + + case 'x': + sc->run_flags |= RUN_FLAG__CONF_ERROR_OUT; + break; + + case 'y': /* Add year to timestamp in alert and log files */ + ConfigShowYear(sc, NULL); + break; + + case 'Z': /* Set preprocessor perfmon file path/filename */ + ConfigPerfFile(sc, optarg); + break; + + case PCAP_FILE_LIST: + case PCAP_LIST: +#ifndef WIN32 + case PCAP_DIR: +#endif + PQ_Multi((char)ch, optarg); + sc->run_flags |= RUN_FLAG__READ; + break; + + case PCAP_LOOP: + { + long int loop_count = SnortStrtol(optarg, &endptr, 0); + + if ((errno == ERANGE) || (*endptr != '\0') || + (loop_count < 0) || (loop_count > 2147483647)) + { + FatalError("Valid values for --pcap-loop are between 0 and 2147483647\n"); + } + + if (loop_count == 0) + pcap_loop_count = -1; + else + pcap_loop_count = loop_count; + } + + break; + + case PCAP_RESET: + sc->run_flags |= RUN_FLAG__PCAP_RESET; + break; + +#if defined(SNORT_RELOAD) && !defined(WIN32) + case PCAP_RELOAD: + sc->run_flags |= RUN_FLAG__PCAP_RELOAD; + break; +#endif + +#ifndef WIN32 + case PCAP_FILTER: + PQ_SetFilter(optarg); + break; + + case PCAP_NO_FILTER: + PQ_SetFilter(NULL); + break; +#endif + + case PCAP_SHOW: + sc->run_flags |= RUN_FLAG__PCAP_SHOW; + break; +#ifdef MPLS + case ENABLE_MPLS_MULTICAST: + ConfigEnableMplsMulticast(sc, NULL); + break; + + case ENABLE_OVERLAPPING_IP: + ConfigEnableMplsOverlappingIp(sc, NULL); + break; + + case MAX_MPLS_LABELCHAIN_LEN: + ConfigMaxMplsLabelChain(sc, optarg); + break; + + case MPLS_PAYLOAD_TYPE: + ConfigMplsPayloadType(sc, optarg); + break; +#endif + case REQUIRE_RULE_SID: + sc->run_flags |= RUN_FLAG__REQUIRE_RULE_SID; + break; + + case ARG_CS_DIR: + if ( optarg != NULL ) + sc->cs_dir = SnortStrdup(optarg); + break; +#ifdef REG_TEST + case ARG_HA_PEER: + sc->ha_peer = true; + break; + + case ARG_HA_OUT: + sc->ha_out = SnortStrdup(optarg); + break; + + case ARG_HA_IN: + sc->ha_in = SnortStrdup(optarg); + break; +#endif + + case '?': /* show help and exit with 1 */ + PrintVersion(); + ShowUsage(argv[0]); + /* XXX Should do a clean exit */ + exit(1); + break; + + default: + FatalError("Invalid option: %c.\n", ch); + break; + } + } + + sc->bpf_filter = copy_argv(&argv[optind]); + + if ((sc->run_mode_flags & RUN_MODE_FLAG__TEST) && + (sc->run_flags & RUN_FLAG__DAEMON)) + { + FatalError("Cannot use test mode and daemon mode together.\n" + "To verify configuration, run first in test " + "mode and then restart in daemon mode.\n"); + } + + if ((sc->run_flags & RUN_FLAG__INLINE) && + (sc->run_flags & RUN_FLAG__INLINE_TEST)) + { + FatalError("Cannot use inline adapter mode and inline test " + "mode together. \n"); + } + + // TBD no reason why command line args only can't be checked + // marginally useful, perhaps, but why do we go out of our way + // to make things hard on the user? + if ((sc->run_mode_flags & RUN_MODE_FLAG__TEST) && + (snort_conf_file == NULL)) + { + FatalError("Test mode must be run with a snort configuration " + "file. Use the '-c' option on the command line to " + "specify a configuration file.\n"); + } + if (pcap_loop_count && !(sc->run_flags & RUN_FLAG__READ)) + { + FatalError("--pcap-loop can only be used in combination with pcaps " + "on the command line.\n"); + } + +#if defined(SNORT_RELOAD) && !defined(WIN32) + if ((sc->run_flags & RUN_FLAG__PCAP_RELOAD) && + !(sc->run_flags & RUN_FLAG__READ)) + { + FatalError("--pcap-reload can only be used in combination with pcaps " + "on the command line.\n"); + } +#endif + + /* Set the run mode based on what we've got from command line */ + + /* Version overrides all */ + if (sc->run_mode_flags & RUN_MODE_FLAG__VERSION) + { + sc->run_mode = RUN_MODE__VERSION; + } + /* Next dumping so rule stubs */ + else if (sc->run_mode_flags & RUN_MODE_FLAG__RULE_DUMP) + { + sc->run_mode = RUN_MODE__RULE_DUMP; + } + /* Next if we want to test a snort conf */ + else if (sc->run_mode_flags & RUN_MODE_FLAG__TEST) + { + sc->run_mode = RUN_MODE__TEST; + } + /* Now if there is a snort conf. If a snort conf wasn't given on the + * command line, we'll look in a default place if the next ones + * don't match */ + else if ((sc->run_mode_flags & RUN_MODE_FLAG__IDS) && (snort_conf_file != NULL)) + { + sc->run_mode = RUN_MODE__IDS; + } + /* If logging but not alerting or log directory is set */ + else if ((output_logging && !output_alerting) || (sc->log_dir != NULL)) + { + sc->no_alert = 1; + sc->run_mode = RUN_MODE__PACKET_LOG; + } + /* If none of the above and not logging or alerting and verbose */ + else if ((!output_logging && !output_alerting) && + (sc->logging_flags & LOGGING_FLAG__VERBOSE)) + { + sc->no_alert = 1; + sc->no_log = 1; + sc->run_mode = RUN_MODE__PACKET_DUMP; + } + +#if 1 + if (!sc->run_mode) + { + sc->no_alert = 1; + sc->no_log = 1; + sc->run_mode = RUN_MODE__PACKET_DUMP; + } +#else + if (!sc->run_mode) + sc->run_mode = RUN_MODE__IDS; + + /* If mode mandates a conf and we don't have one, check for default. */ + if (((sc->run_mode == RUN_MODE__IDS) || (sc->run_mode == RUN_MODE__TEST)) && + (snort_conf_file == NULL)) + { + snort_conf_file = ConfigFileSearch(); + if (snort_conf_file == NULL) + { + DisplayBanner(); + ShowUsage(argv[0]); + FatalError("\n\nUh, you need to tell me to do something..."); + } + } +#endif + + if ((sc->run_mode == RUN_MODE__PACKET_LOG) && + (sc->output_configs == NULL)) + { + ParseOutput(sc, NULL, "log_tcpdump"); + } + + switch ( snort_conf->run_mode ) + { + case RUN_MODE__IDS: + if (ScLogVerbose()) + log_func = PrintPacket; + break; + + case RUN_MODE__PACKET_LOG: + log_func = LogPacket; + break; + + case RUN_MODE__PACKET_DUMP: + log_func = PrintPacket; + break; + + default: + break; + } + SetSnortConfDir(); +} + +/* + * Function: SetPktProcessor() + * + * Purpose: Set root decoder based on datalink + */ +// TBD add GetDecoder(dlt) to decode module and hide all +// protocol decoder functions. +static int SetPktProcessor(void) +{ + const char* slink = NULL; + const char* extra = NULL; + int dlt = DLT_EN10MB; + + switch ( dlt ) + { + case DLT_EN10MB: + slink = "Ethernet"; + grinder = DecodeEthPkt; + break; + default: + /* oops, don't know how to handle this one */ + FatalError("Cannot decode data link type %d\n", dlt); + break; + } + if ( !ScReadMode() || ScPcapShow() ) + { + LogMessage("Decoding %s\n", slink); + } + if (extra && ScOutputDataLink()) + { + LogMessage("%s\n", extra); + snort_conf->output_flags &= ~OUTPUT_FLAG__SHOW_DATA_LINK; + } +#ifdef ACTIVE_RESPONSE + Encode_Init(); +#endif + return 0; +} +/* + * Handle idle time checks in snort packet processing loop + */ +static void SnortIdle(void) +{ + /* Rollover of performance log */ + if (IsSetRotatePerfFileFlag()) + { + sfRotateBaseStatsFile(perfmon_config); + sfRotateFlowStatsFile(perfmon_config); + ClearRotatePerfFileFlag(); + } +#ifdef OPENBSD + else if (reload_signal != reload_total) + nanosleep(&packet_sleep, NULL); +#endif + + checkLWSessionTimeout(16384, time(NULL)); + ControlSocketDoWork(1); +#ifdef SIDE_CHANNEL + SideChannelDrainRX(0); +#endif + IdleProcessingExecute(); +} + +void PacketLoop (void) +{ + int error; + int pkts_to_read = (int)snort_conf->pkt_cnt; + + TimeStart(); + + while ( !exit_logged ) + { + error = DAQ_Acquire(pkts_to_read, PacketCallback, NULL); + +#ifdef SIDE_CHANNEL + /* If we didn't manage to lock the process lock in a DAQ acquire callback, lock it now. */ + if (ScSideChannelEnabled() && !snort_process_lock_held) + { + pthread_mutex_lock(&snort_process_lock); + snort_process_lock_held = true; + } +#endif + + if ( error ) + { + if ( !ScReadMode() || !PQ_Next() ) + { + /* If not read-mode or no next pcap, we're done */ + break; + } + } + /* Check for any pending signals when no packets are read*/ + else + { + // TBD SnortIdle() only checks for perf file rotation + // and that can only be done after calling SignalCheck() + // so either move SnortIdle() to SignalCheck() or directly + // set the flag in the signal handler (and then clear it + // in SnortIdle()). + + // check for signals + if ( SignalCheck() ) + { +#ifndef SNORT_RELOAD + // Got SIGNAL_SNORT_RELOAD + Restart(); +#endif + } + CheckForReload(); + } + if ( pkts_to_read > 0 ) + { + if ( snort_conf->pkt_cnt <= pc.total_from_daq ) + break; + else + pkts_to_read = (int)(snort_conf->pkt_cnt - pc.total_from_daq); + } + // idle time processing..quick things to check or do ... + // TBD fix this per above ... and if it stays here, should + // prolly change the name if acquire breaks due to a signal + // (since in that case we aren't idle here) + SnortIdle(); + +#ifdef SIDE_CHANNEL + /* Unlock the Snort process lock once we've hit the DAQ acquire timeout. */ + if (snort_process_lock_held) + { + snort_process_lock_held = false; + pthread_mutex_unlock(&snort_process_lock); + } +#endif + } + +#ifdef SIDE_CHANNEL + /* Error conditions can lead to exiting the packet loop prior to unlocking the process lock. */ + if (snort_process_lock_held) + { + snort_process_lock_held = false; + pthread_mutex_unlock(&snort_process_lock); + } +#endif + + if ( !exit_logged && error ) + { + if ( error == DAQ_READFILE_EOF ) + error = 0; + else if ( error > 0 ) + { + DAQ_Abort(); + exit(1); + } + CleanExit(error); + } + done_processing = 1; +} + +/* Resets Snort to a post-configuration state */ +static void SnortReset(void) +{ + PreprocSignalFuncNode *idxPreprocReset; + PreprocSignalFuncNode *idxPreprocResetStats; + + /* reset preprocessors */ + idxPreprocReset = preproc_reset_funcs; + while (idxPreprocReset != NULL) + { + idxPreprocReset->func(-1, idxPreprocReset->arg); + idxPreprocReset = idxPreprocReset->next; + } + + SnortEventqReset(); + Replace_ResetQueue(); +#ifdef ACTIVE_RESPONSE + Active_ResetQueue(); +#endif + + sfthreshold_reset_active(); + RateFilter_ResetActive(); + TagCacheReset(); + +#ifdef PERF_PROFILING + ShowPreprocProfiles(); + ShowRuleProfiles(); +#endif + + DropStats(0); + + /* zero out packet count */ + memset(&pc, 0, sizeof(pc)); + +#ifdef PERF_PROFILING + ResetRuleProfiling(); + ResetPreprocProfiling(); +#endif + + /* reset preprocessor stats */ + idxPreprocResetStats = preproc_reset_stats_funcs; + while (idxPreprocResetStats != NULL) + { + idxPreprocResetStats->func(-1, idxPreprocResetStats->arg); + idxPreprocResetStats = idxPreprocResetStats->next; + } +} + + +#if 0 +/* locate one of the possible default config files */ +/* allocates memory to hold filename */ +static char *ConfigFileSearch(void) +{ + struct stat st; + int i; + char *conf_files[]={"/etc/snort.conf", "./snort.conf", NULL}; + char *fname = NULL; + char *rval = NULL; + + i = 0; + + /* search the default set of config files */ + while(conf_files[i]) + { + fname = conf_files[i]; + + if(stat(fname, &st) != -1) + { + rval = SnortStrdup(fname); + break; + } + i++; + } + + /* search for .snortrc in the HOMEDIR */ + if(!rval) + { + char *home_dir = NULL; + + if((home_dir = getenv("HOME")) != NULL) + { + char *snortrc = "/.snortrc"; + int path_len; + + path_len = strlen(home_dir) + strlen(snortrc) + 1; + + /* create the full path */ + fname = (char *)SnortAlloc(path_len); + + SnortSnprintf(fname, path_len, "%s%s", home_dir, snortrc); + + if(stat(fname, &st) != -1) + rval = fname; + else + free(fname); + } + } + + return rval; +} +#endif + +/* Signal Handlers ************************************************************/ +static void SigExitHandler(int signal) +{ + if (exit_signal != 0) + return; + + /* Don't want to have to wait to start processing packets before + * getting out of dodge */ + if (snort_initializing) + _exit(0); + + exit_signal = signal; +} + +static void SigDumpStatsHandler(int signal) +{ + dump_stats_signal = true; +} + +static void SigRotateStatsHandler(int signal) +{ + rotate_stats_signal = true; +} + +static void SigReloadHandler(int signal) +{ +#if defined(SNORT_RELOAD) && !defined(WIN32) + reload_signal++; +#else + reload_signal = true; +#endif +} + +#ifdef CONTROL_SOCKET +static void SigPipeHandler(int signal) +{ +} +#endif + +#ifdef TARGET_BASED +static void SigNoAttributeTableHandler(int signal) +{ + no_attr_table_signal = true; +} +#endif + +static void SigOopsHandler(int signal) +{ + if ( s_packet.pkth ) + { + s_pkth = *s_packet.pkth; + + if ( s_packet.pkt ) + memcpy(s_data, s_packet.pkt, 0xFFFF & s_packet.pkth->caplen); + } + SnortAddSignal(signal, SIG_DFL, 0); + + raise(signal); +} + + +static void PrintStatistics (void) +{ + if ( ScTestMode() || ScVersionMode() || ScRuleDumpMode() ) + return; + + fpShowEventStats(snort_conf); + +#ifdef PERF_PROFILING + { + int save_quiet_flag = snort_conf->logging_flags & LOGGING_FLAG__QUIET; + + snort_conf->logging_flags &= ~LOGGING_FLAG__QUIET; + + ShowPreprocProfiles(); + ShowRuleProfiles(); + + snort_conf->logging_flags |= save_quiet_flag; + } +#endif + + DropStats(2); + print_thresholding(snort_conf->threshold_config, 1); +} + +/**************************************************************************** + * + * Function: CleanExit() + * + * Purpose: Clean up misc file handles and such and exit + * + * Arguments: exit value; + * + * Returns: void function + * + ****************************************************************************/ +static void CleanExit(int exit_val) +{ + SnortConfig tmp; + +#ifdef TARGET_BASED +#ifdef DEBUG +#if 0 + SFLAT_dump(); +#endif +#endif +#endif + + /* Have to trick LogMessage to log correctly after snort_conf + * is freed */ + memset(&tmp, 0, sizeof(tmp)); + + if (snort_conf != NULL) + { + tmp.logging_flags |= + (snort_conf->logging_flags & LOGGING_FLAG__QUIET); + + tmp.run_flags |= (snort_conf->run_flags & RUN_FLAG__DAEMON); + + tmp.logging_flags |= + (snort_conf->logging_flags & LOGGING_FLAG__SYSLOG); + } + + SnortCleanup(exit_val); + snort_conf = &tmp; + + LogMessage("Snort exiting\n"); +#ifndef WIN32 + closelog(); +#endif + if ( !done_processing ) + exit(exit_val); +} + +static void SnortCleanup(int exit_val) +{ + PreprocSignalFuncNode *idxPreproc = NULL; + PluginSignalFuncNode *idxPlugin = NULL; + + /* This function can be called more than once. For example, + * once from the SIGINT signal handler, and once recursively + * as a result of calling pcap_close() below. We only need + * to perform the cleanup once, however. So the static + * variable already_exiting will act as a flag to prevent + * double-freeing any memory. Not guaranteed to be + * thread-safe, but it will prevent the simple cases. + */ + static int already_exiting = 0; + if( already_exiting != 0 ) + { + return; + } + already_exiting = 1; + snort_exiting = 1; + snort_initializing = false; /* just in case we cut out early */ + + Active_Suspend(); // rules that fire now can't actually block + +#if 0 + if ( DAQ_WasStarted() ) + { +#ifdef EXIT_CHECK + if (snort_conf->exit_check) + ExitCheckEnd(); +#endif + DAQ_Stop(); + } +#endif + + ControlSocketCleanUp(); +#ifdef SIDE_CHANNEL + SideChannelStopTXThread(); + SideChannelCleanUp(); +#endif + IdleProcessingCleanUp(); + + if ( snort_conf->dirty_pig ) + { + //DAQ_Delete(); + //DAQ_Term(); + //PrintStatistics(); + return; + } +#if defined(SNORT_RELOAD) && !defined(WIN32) + /* Setting snort_exiting will cause the thread to break out + * of it's loop and exit */ + if (snort_reload_thread_created) + pthread_join(snort_reload_thread_id, NULL); +#endif + +#if defined(INLINE_FAILOPEN) && !defined(WIN32) + if (inline_failopen_thread_running) + pthread_kill(inline_failopen_thread_id, SIGKILL); +#endif + +#if defined(TARGET_BASED) && !defined(WIN32) + if (attribute_reload_thread_running) + { + /* Set the flag to stop the attribute reload thread and + * send VTALRM signal to pull it out of the idle sleep. + * Thread exits normally on next iteration through its + * loop. + * + * If its doing other processing, that continues post + * interrupt and thread exits normally. + */ + attribute_reload_thread_stop = 1; + pthread_kill(attribute_reload_thread_id, SIGVTALRM); + while (attribute_reload_thread_running) + nanosleep(&thread_sleep, NULL); + pthread_join(attribute_reload_thread_id, NULL); + } +#endif + + /* Do some post processing on any incomplete Preprocessor Data */ + idxPreproc = preproc_shutdown_funcs; + while (idxPreproc) + { + idxPreproc->func(SIGQUIT, idxPreproc->arg); + idxPreproc = idxPreproc->next; + } + + /* Do some post processing on any incomplete Plugin Data */ + idxPlugin = plugin_shutdown_funcs; + while(idxPlugin) + { + idxPlugin->func(SIGQUIT, idxPlugin->arg); + idxPlugin = idxPlugin->next; + } + + if (!ScTestMode() && !ScVersionMode() && !ScRuleDumpMode() ) + { + if ( !exit_val ) + TimeStop(); + } + + /* Exit preprocessors */ + idxPreproc = preproc_clean_exit_funcs; + while(idxPreproc) + { + idxPreproc->func(SIGQUIT, idxPreproc->arg); + idxPreproc = idxPreproc->next; + } + + /* Do some post processing on any incomplete Plugin Data */ + idxPlugin = plugin_clean_exit_funcs; + while(idxPlugin) + { + idxPlugin->func(SIGQUIT, idxPlugin->arg); + idxPlugin = idxPlugin->next; + } + + if (decoderActionQ != NULL) + { + sfActionQueueDestroy (decoderActionQ); + mempool_destroy (&decoderAlertMemPool); + decoderActionQ = NULL; + memset(&decoderAlertMemPool, 0, sizeof(decoderAlertMemPool)); + } + + //DAQ_Delete(); + //DAQ_Term(); + //PrintStatistics(); + +#ifdef ACTIVE_RESPONSE + Active_Term(); + Encode_Term(); +#endif + + + CleanupProtoNames(); + +#ifdef TARGET_BASED + SFAT_Cleanup(); +#endif + + PQ_CleanUp(); + + ClosePidFile(); + + /* remove pid file */ + if (SnortStrnlen(snort_conf->pid_filename, sizeof(snort_conf->pid_filename)) > 0) + { + int ret; + + ret = unlink(snort_conf->pid_filename); + + if (ret != 0) + { + ErrorMessage("Could not remove pid file %s: %s\n", + snort_conf->pid_filename, strerror(errno)); + } + } + +#ifdef INTEL_SOFT_CPM + //IntelPmPrintBufferStats(); +#endif + + /* free allocated memory */ + if (snort_conf == snort_cmd_line_conf) + { + SnortConfFree(snort_cmd_line_conf); + snort_cmd_line_conf = NULL; + snort_conf = NULL; + } + else + { + SnortConfFree(snort_cmd_line_conf); + snort_cmd_line_conf = NULL; + SnortConfFree(snort_conf); + snort_conf = NULL; + } + +#ifdef SNORT_RELOAD + if (snort_conf_new != NULL) + { + /* If main thread is exiting, it won't swap in the new configuration, + * so free it here, really just to quiet valgrind. Note this needs to + * be done here since some preprocessors, will potentially need access + * to the data here since stream5 flushes out its cache and potentially + * sends reassembled packets back through Preprocess */ + SnortConfFree(snort_conf_new); + snort_conf_new = NULL; + } +#endif + + EventTrace_Term(); + + detection_filter_cleanup(); + sfthreshold_free(); + RateFilter_Cleanup(); + asn1_free_mem(); + FreeOutputConfigFuncs(); + FreePreprocConfigFuncs(); + + FreeRuleOptConfigFuncs(rule_opt_config_funcs); + rule_opt_config_funcs = NULL; + + FreeRuleOptOverrideInitFuncs(rule_opt_override_init_funcs); + rule_opt_override_init_funcs = NULL; + + FreeRuleOptByteOrderFuncs(rule_opt_byte_order_funcs); + rule_opt_byte_order_funcs = NULL; + + FreeRuleOptParseCleanupList(rule_opt_parse_cleanup_list); + rule_opt_parse_cleanup_list = NULL; + + FreeOutputList(AlertList); + AlertList = NULL; + + FreeOutputList(LogList); + LogList = NULL; + + /* Global lists */ + FreePreprocStatsFuncs(preproc_stats_funcs); + preproc_stats_funcs = NULL; + + FreePreprocSigFuncs(preproc_shutdown_funcs); + preproc_shutdown_funcs = NULL; + + FreePreprocSigFuncs(preproc_clean_exit_funcs); + preproc_clean_exit_funcs = NULL; + + FreePreprocSigFuncs(preproc_reset_funcs); + preproc_reset_funcs = NULL; + + FreePreprocSigFuncs(preproc_reset_stats_funcs); + preproc_reset_stats_funcs = NULL; + + FreePluginSigFuncs(plugin_shutdown_funcs); + plugin_shutdown_funcs = NULL; + + FreePluginSigFuncs(plugin_clean_exit_funcs); + plugin_clean_exit_funcs = NULL; + +#ifdef SNORT_RELOAD + FreePluginPostConfigFuncs(plugin_reload_funcs); + plugin_reload_funcs = NULL; +#endif + + FreePeriodicFuncs(periodic_check_funcs); + periodic_check_funcs = NULL; + + ParserCleanup(); + + /* Stuff from plugbase */ + DynamicRuleListFree(dynamic_rules); + dynamic_rules = NULL; + + CloseDynamicPreprocessorLibs(); + CloseDynamicDetectionLibs(); + CloseDynamicEngineLibs(); +#ifdef SIDE_CHANNEL + CloseDynamicSideChannelLibs(); +#endif + output_unload(); + + CleanupTag(); + ClearDumpBuf(); + +#ifdef PERF_PROFILING + CleanupPreprocStatsNodeList(); +#endif + + if (netmasks != NULL) + { + free(netmasks); + netmasks = NULL; + } + + if (protocol_names != NULL) + { + int i; + + for (i = 0; i < NUM_IP_PROTOS; i++) + { + if (protocol_names[i] != NULL) + free(protocol_names[i]); + } + + free(protocol_names); + protocol_names = NULL; + } + +#ifdef INTEL_SOFT_CPM + IntelPmStopInstance(); +#endif + + SynToMulticastDstIpDestroy(); + + FreeVarList(cmd_line_var_list); + + if (snort_conf_file != NULL) + free(snort_conf_file); + + if (snort_conf_dir != NULL) + free(snort_conf_dir); + + close_fileAPI(); +} + +static void InitGlobals(void) +{ + memset(&pc, 0, sizeof(pc)); + + InitNetmasks(); + InitProtoNames(); +#ifdef SIDE_CHANNEL + pthread_mutex_init(&snort_process_lock, NULL); +#endif +} + +/**************************************************************************** + * + * Function: InitNetMasks() + * + * Purpose: Loads the netmask struct in network order. Yes, I know I could + * just load the array when I define it, but this is what occurred + * to me when I wrote this at 3:00 AM. + * + * Arguments: None. + * + * Returns: void function + * + ****************************************************************************/ +static void InitNetmasks(void) +{ + if (netmasks == NULL) + netmasks = (uint32_t *)SnortAlloc(33 * sizeof(uint32_t)); + + netmasks[0] = 0x00000000; + netmasks[1] = 0x80000000; + netmasks[2] = 0xC0000000; + netmasks[3] = 0xE0000000; + netmasks[4] = 0xF0000000; + netmasks[5] = 0xF8000000; + netmasks[6] = 0xFC000000; + netmasks[7] = 0xFE000000; + netmasks[8] = 0xFF000000; + netmasks[9] = 0xFF800000; + netmasks[10] = 0xFFC00000; + netmasks[11] = 0xFFE00000; + netmasks[12] = 0xFFF00000; + netmasks[13] = 0xFFF80000; + netmasks[14] = 0xFFFC0000; + netmasks[15] = 0xFFFE0000; + netmasks[16] = 0xFFFF0000; + netmasks[17] = 0xFFFF8000; + netmasks[18] = 0xFFFFC000; + netmasks[19] = 0xFFFFE000; + netmasks[20] = 0xFFFFF000; + netmasks[21] = 0xFFFFF800; + netmasks[22] = 0xFFFFFC00; + netmasks[23] = 0xFFFFFE00; + netmasks[24] = 0xFFFFFF00; + netmasks[25] = 0xFFFFFF80; + netmasks[26] = 0xFFFFFFC0; + netmasks[27] = 0xFFFFFFE0; + netmasks[28] = 0xFFFFFFF0; + netmasks[29] = 0xFFFFFFF8; + netmasks[30] = 0xFFFFFFFC; + netmasks[31] = 0xFFFFFFFE; + netmasks[32] = 0xFFFFFFFF; +} + +/**************************************************************************** + * + * Function: InitProtoNames() + * + * Purpose: Initializes the protocol names + * + * Arguments: None. + * + * Returns: void function + * + ****************************************************************************/ +static void InitProtoNames(void) +{ + int i; + + if (protocol_names == NULL) + protocol_names = (char **)SnortAlloc(sizeof(char *) * NUM_IP_PROTOS); + + for (i = 0; i < NUM_IP_PROTOS; i++) + { + struct protoent *pt = getprotobynumber(i); + + if (pt != NULL) + { + size_t j; + + protocol_names[i] = SnortStrdup(pt->p_name); + for (j = 0; j < strlen(protocol_names[i]); j++) + protocol_names[i][j] = toupper(protocol_names[i][j]); + } + else + { + char protoname[10]; + + SnortSnprintf(protoname, sizeof(protoname), "PROTO:%03d", i); + protocol_names[i] = SnortStrdup(protoname); + } + } +} + + +static void SetSnortConfDir(void) +{ + /* extract the config directory from the config filename */ + if (snort_conf_file != NULL) + { +#ifndef WIN32 + char *path_sep = strrchr(snort_conf_file, '/'); +#else + char *path_sep = strrchr(snort_conf_file, '\\'); +#endif + + /* is there a directory seperator in the filename */ + if (path_sep != NULL) + { + path_sep++; /* include path separator */ + snort_conf_dir = SnortStrndup(snort_conf_file, path_sep - snort_conf_file); + } + else + { + snort_conf_dir = SnortStrdup("./"); + } + + DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Config file = %s, config dir = " + "%s\n", snort_conf_file, snort_conf_dir);); + } +} + +static void FreePlugins(SnortConfig *sc) +{ + if (sc == NULL) + return; + + FreePreprocessors(sc); + + FreePluginPostConfigFuncs(sc->plugin_post_config_funcs); + sc->plugin_post_config_funcs = NULL; +} + +static void FreePreprocessors(SnortConfig *sc) +{ + tSfPolicyId i; + + if (sc == NULL) + return; + + FreePreprocCheckConfigFuncs(sc->preproc_config_check_funcs); + sc->preproc_config_check_funcs = NULL; + + for (i = 0; i < sc->num_policies_allocated; i++) + { + SnortPolicy *p = sc->targeted_policies[i]; + + if (p == NULL) + continue; + + FreePreprocEvalFuncs(p->preproc_eval_funcs); + p->preproc_eval_funcs = NULL; + p->num_preprocs = 0; + + FreePreprocEvalFuncs(p->unused_preproc_eval_funcs); + p->unused_preproc_eval_funcs = NULL; + + FreePreprocMetaEvalFuncs(p->preproc_meta_eval_funcs); + p->preproc_meta_eval_funcs = NULL; + p->num_meta_preprocs = 0; + + FreeDetectionEvalFuncs(p->detect_eval_funcs); + p->detect_eval_funcs = NULL; + p->num_detects = 0; + } + + FreePreprocPostConfigFuncs(sc->preproc_post_config_funcs); + sc->preproc_post_config_funcs = NULL; +} + +static SnortConfig * MergeSnortConfs(SnortConfig *cmd_line, SnortConfig *config_file) +{ + unsigned int i; + + /* Move everything from the command line config over to the + * config_file config */ + + if (cmd_line == NULL) + { + FatalError("%s(%d) Merging snort configs: snort conf is NULL.\n", + __FILE__, __LINE__); + } + + ResolveOutputPlugins(cmd_line, config_file); + + if (config_file == NULL) + { + if (cmd_line->log_dir == NULL) + cmd_line->log_dir = SnortStrdup(DEFAULT_LOG_DIR); + } + else if ((cmd_line->log_dir == NULL) && (config_file->log_dir == NULL)) + { + config_file->log_dir = SnortStrdup(DEFAULT_LOG_DIR); + } + else if (cmd_line->log_dir != NULL) + { + if (config_file->log_dir != NULL) + free(config_file->log_dir); + + config_file->log_dir = SnortStrdup(cmd_line->log_dir); + } + + if (config_file == NULL) + return cmd_line; + + /* Used because of a potential chroot */ + config_file->orig_log_dir = SnortStrdup(config_file->log_dir); + + config_file->run_mode = cmd_line->run_mode; + config_file->run_mode_flags |= cmd_line->run_mode_flags; + + if ((cmd_line->run_mode == RUN_MODE__TEST) && + (config_file->run_flags & RUN_FLAG__DAEMON)) + { + /* Just ignore deamon setting in conf file */ + config_file->run_flags &= ~RUN_FLAG__DAEMON; + } + + config_file->run_flags |= cmd_line->run_flags; + config_file->output_flags |= cmd_line->output_flags; + config_file->logging_flags |= cmd_line->logging_flags; + + /* Merge checksum flags. If command line modified them, use from the + * command line, else just use from config_file. */ + for (i = 0; i < config_file->num_policies_allocated; i++) + { + if (config_file->targeted_policies[i] != NULL) + { + if (cmd_line->checksum_flags_modified) + config_file->targeted_policies[i]->checksum_flags = cmd_line->checksum_flags; + + if (cmd_line->checksum_drop_flags_modified) + config_file->targeted_policies[i]->checksum_drop_flags = cmd_line->checksum_drop_flags; + } + } + + config_file->event_log_id = cmd_line->event_log_id; + + if (cmd_line->dynamic_rules_path != NULL) + { + if(strcmp(cmd_line->dynamic_rules_path, "") != 0) + { + if( config_file->dynamic_rules_path != NULL ) + free(config_file->dynamic_rules_path); + config_file->dynamic_rules_path = SnortStrdup(cmd_line->dynamic_rules_path); + } + } + + if (cmd_line->dyn_engines != NULL) + { + FreeDynamicLibInfo(config_file->dyn_engines); + config_file->dyn_engines = DupDynamicLibInfo(cmd_line->dyn_engines); + } + + if (cmd_line->dyn_rules != NULL) + { + FreeDynamicLibInfo(config_file->dyn_rules); + config_file->dyn_rules = DupDynamicLibInfo(cmd_line->dyn_rules); + } + + if (cmd_line->dyn_preprocs != NULL) + { + FreeDynamicLibInfo(config_file->dyn_preprocs); + config_file->dyn_preprocs = DupDynamicLibInfo(cmd_line->dyn_preprocs); + } + + if (cmd_line->pid_path[0] != '\0') + ConfigPidPath(config_file, cmd_line->pid_path); + + config_file->exit_check = cmd_line->exit_check; + + /* Command line only configures search method */ + if (cmd_line->fast_pattern_config != NULL) + config_file->fast_pattern_config->search_method = cmd_line->fast_pattern_config->search_method; + + if (cmd_line->obfuscation_net.family != 0) + memcpy(&config_file->obfuscation_net, &cmd_line->obfuscation_net, sizeof(sfip_t)); + + if (cmd_line->homenet.family != 0) + memcpy(&config_file->homenet, &cmd_line->homenet, sizeof(sfip_t)); + + if (cmd_line->interface != NULL) + { + if (config_file->interface != NULL) + free(config_file->interface); + config_file->interface = SnortStrdup(cmd_line->interface); + } + + if (cmd_line->bpf_file != NULL) + { + if (config_file->bpf_file != NULL) + free(config_file->bpf_file); + config_file->bpf_file = SnortStrdup(cmd_line->bpf_file); + } + + if (cmd_line->bpf_filter != NULL) + config_file->bpf_filter = SnortStrdup(cmd_line->bpf_filter); + + if (cmd_line->pkt_snaplen != -1) + config_file->pkt_snaplen = cmd_line->pkt_snaplen; + + if (cmd_line->pkt_cnt != 0) + config_file->pkt_cnt = cmd_line->pkt_cnt; + +#ifdef REG_TEST + if (cmd_line->pkt_skip != 0) + config_file->pkt_skip = cmd_line->pkt_skip; +#endif + + if (cmd_line->group_id != -1) + config_file->group_id = cmd_line->group_id; + + if (cmd_line->user_id != -1) + config_file->user_id = cmd_line->user_id; + + /* Only configurable on command line */ + if (cmd_line->pcap_log_file != NULL) + config_file->pcap_log_file = SnortStrdup(cmd_line->pcap_log_file); + + if (cmd_line->file_mask != 0) + config_file->file_mask = cmd_line->file_mask; + + if (cmd_line->pidfile_suffix[0] != '\0') + { + SnortStrncpy(config_file->pidfile_suffix, cmd_line->pidfile_suffix, + sizeof(config_file->pidfile_suffix)); + } + + if (cmd_line->chroot_dir != NULL) + { + if (config_file->chroot_dir != NULL) + free(config_file->chroot_dir); + config_file->chroot_dir = SnortStrdup(cmd_line->chroot_dir); + } + + if (cmd_line->perf_file != NULL) + { + if (config_file->perf_file != NULL) + free(config_file->perf_file); + config_file->perf_file = SnortStrdup(cmd_line->perf_file); + } + + if ( cmd_line->daq_type ) + config_file->daq_type = SnortStrdup(cmd_line->daq_type); + + if ( cmd_line->daq_mode ) + config_file->daq_mode = SnortStrdup(cmd_line->daq_mode); + + if ( cmd_line->dirty_pig ) + config_file->dirty_pig = cmd_line->dirty_pig; + + if ( cmd_line->daq_vars ) + { + /* Command line overwrites daq_vars */ + if (config_file->daq_vars) + StringVector_Delete(config_file->daq_vars); + + config_file->daq_vars = StringVector_New(); + StringVector_AddVector(config_file->daq_vars, cmd_line->daq_vars); + } + if ( cmd_line->daq_dirs ) + { + /* Command line overwrites daq_dirs */ + if (config_file->daq_dirs) + StringVector_Delete(config_file->daq_dirs); + + config_file->daq_dirs = StringVector_New(); + StringVector_AddVector(config_file->daq_dirs, cmd_line->daq_dirs); + } +#ifdef MPLS + if (cmd_line->mpls_stack_depth != DEFAULT_LABELCHAIN_LENGTH) + config_file->mpls_stack_depth = cmd_line->mpls_stack_depth; + + /* Set MPLS payload type here if it hasn't been defined */ + if ((cmd_line->mpls_payload_type == 0) && + (config_file->mpls_payload_type == 0)) + { + config_file->mpls_payload_type = DEFAULT_MPLS_PAYLOADTYPE; + } + else if (cmd_line->mpls_payload_type != 0) + { + config_file->mpls_payload_type = cmd_line->mpls_payload_type; + } +#endif + + if (cmd_line->run_flags & RUN_FLAG__PROCESS_ALL_EVENTS) + config_file->event_queue_config->process_all_events = 1; + + if (cmd_line->cs_dir != NULL) + { + if (config_file->cs_dir != NULL) + free(config_file->cs_dir); + config_file->cs_dir = SnortStrdup(cmd_line->cs_dir); + } + if (config_file->cs_dir) + { + +#ifndef WIN32 + /* + * If an absolute path is specified, then use that. + * otherwise, relative to pid path + */ + if ((config_file->cs_dir[0] != '/') && config_file->pid_path[0]) + { + + char fullpath[PATH_MAX]; + + if (config_file->pid_path[strlen(config_file->pid_path) - 1] == '/') + { + SnortSnprintf(fullpath, sizeof(fullpath), + "%s%s", config_file->pid_path, config_file->cs_dir); + } + else + { + SnortSnprintf(fullpath, sizeof(fullpath), + "%s/%s", config_file->pid_path, config_file->cs_dir); + } + free (config_file->cs_dir); + config_file->cs_dir = SnortStrdup(fullpath); + + } +#else + /*Not supported in WINDOWS*/ + free (config_file->cs_dir); + config_file->cs_dir = NULL; +#endif + ControlSocketConfigureDirectory(config_file->cs_dir); + } + +#ifdef REG_TEST + config_file->ha_peer = cmd_line->ha_peer; + + if ( cmd_line->ha_out ) + { + if(config_file->ha_out != NULL) + free(config_file->ha_out); + config_file->ha_out = strdup(cmd_line->ha_out); + } + + if ( cmd_line->ha_in ) + { + if(config_file->ha_in != NULL) + free(config_file->ha_in); + config_file->ha_in = strdup(cmd_line->ha_in); + } +#endif + + return config_file; +} + +static void FreeDynamicLibInfos(SnortConfig *sc) +{ + if (sc == NULL) + return; + + if (sc->dyn_engines != NULL) + { + FreeDynamicLibInfo(sc->dyn_engines); + sc->dyn_engines = NULL; + } + + if (sc->dyn_rules != NULL) + { + FreeDynamicLibInfo(sc->dyn_rules); + sc->dyn_rules = NULL; + } + + if (sc->dyn_preprocs != NULL) + { + FreeDynamicLibInfo(sc->dyn_preprocs); + sc->dyn_preprocs = NULL; + } + +#ifdef SIDE_CHANNEL + if (sc->dyn_side_channels != NULL) + { + FreeDynamicLibInfo(sc->dyn_side_channels); + sc->dyn_side_channels = NULL; + } +#endif +} + +static void FreeDynamicLibInfo(DynamicLibInfo *lib_info) +{ + unsigned i; + + if (lib_info == NULL) + return; + + for (i = 0; i < lib_info->count; i++) + { + free(lib_info->lib_paths[i]->path); + free(lib_info->lib_paths[i]); + } + + free(lib_info); +} + +static DynamicLibInfo * DupDynamicLibInfo(DynamicLibInfo *src) +{ + DynamicLibInfo *dst; + unsigned i; + + if (src == NULL) + return NULL; + + dst = (DynamicLibInfo *)SnortAlloc(sizeof(DynamicLibInfo)); + dst->type = src->type; + dst->count = src->count; + + for (i = 0; i < src->count; i++) + { + DynamicLibPath *dylib_path = (DynamicLibPath *)SnortAlloc(sizeof(DynamicLibPath)); + + dylib_path->ptype = src->lib_paths[i]->ptype; + dylib_path->path = SnortStrdup(src->lib_paths[i]->path); + + dst->lib_paths[i] = dylib_path; + } + + return dst; +} + +#if defined(INLINE_FAILOPEN) && !defined(WIN32) +static void * SnortPostInitThread(void *data) +{ + sigset_t mtmask; + + inline_failopen_thread_pid = gettid(); + inline_failopen_thread_running = 1; + + /* Don't handle any signals here */ + sigfillset(&mtmask); + pthread_sigmask(SIG_BLOCK, &mtmask, NULL); + + while (!inline_failopen_initialized) + nanosleep(&thread_sleep, NULL); + + SnortUnprivilegedInit(); + + pthread_exit((void *)NULL); +} + +static DAQ_Verdict IgnoreCallback ( + void *user, const DAQ_PktHdr_t* pkthdr, const uint8_t* pkt) +{ + /* Empty function -- do nothing with the packet we just read */ + inline_failopen_pass_pkt_cnt++; + +#ifdef DEBUG + { + FILE *tmp = fopen("/var/tmp/fo_threadid", "a"); + if ( tmp ) + { + fprintf(tmp, "Packet Count %d\n", inline_failopen_pass_pkt_cnt); + fclose(tmp); + } + } +#endif + return DAQ_VERDICT_PASS; +} +#endif /* defined(INLINE_FAILOPEN) && !defined(WIN32) */ + + +#if defined(NOCOREFILE) && !defined(WIN32) +static void SetNoCores(void) +{ + struct rlimit rlim; + + getrlimit(RLIMIT_CORE, &rlim); + rlim.rlim_max = 0; + setrlimit(RLIMIT_CORE, &rlim); +} +#endif + +static void InitSignals(void) +{ + +#ifndef WIN32 +# if defined(LINUX) || defined(FREEBSD) || defined(OPENBSD) || \ + defined(SOLARIS) || defined(BSD) || defined(MACOS) + sigset_t set; + + sigemptyset(&set); +# if defined(INLINE_FAILOPEN) || \ + defined(TARGET_BASED) || defined(SNORT_RELOAD) + pthread_sigmask(SIG_SETMASK, &set, NULL); +# else + sigprocmask(SIG_SETMASK, &set, NULL); +# endif /* INLINE_FAILOPEN */ +# else + sigsetmask(0); +# endif /* LINUX, BSD, SOLARIS */ +#endif /* !WIN32 */ + + /* Make this prog behave nicely when signals come along. + * Windows doesn't like all of these signals, and will + * set errno for some. Ignore/reset this error so it + * doesn't interfere with later checks of errno value. */ + signal_error_msg[0] = '\0'; + SnortAddSignal(SIGTERM, SigExitHandler, 1); + SnortAddSignal(SIGINT, SigExitHandler, 1); +#ifndef WIN32 + SnortAddSignal(SIGQUIT, SigExitHandler, 1); + SnortAddSignal(SIGNAL_SNORT_DUMP_STATS, SigDumpStatsHandler, 1); + SnortAddSignal(SIGNAL_SNORT_RELOAD, SigReloadHandler, 1); + SnortAddSignal(SIGNAL_SNORT_ROTATE_STATS, SigRotateStatsHandler, 1); +#endif + +#ifdef CONTROL_SOCKET + SnortAddSignal(SIGPIPE, SigPipeHandler, 1); +#endif + +#ifdef TARGET_BASED +#ifndef WIN32 + /* Used to print warning if attribute table is not configured + * When it is, it will set new signal handler */ + SnortAddSignal(SIGNAL_SNORT_READ_ATTR_TBL, SigNoAttributeTableHandler, 1); +#endif +#endif + + SnortAddSignal(SIGABRT, SigOopsHandler, 1); + SnortAddSignal(SIGSEGV, SigOopsHandler, 1); +#ifndef WIN32 + SnortAddSignal(SIGBUS, SigOopsHandler, 1); +#endif + + errno = 0; +} + +static void FreeOutputConfigs(OutputConfig *head) +{ + while (head != NULL) + { + OutputConfig *tmp = head; + + head = head->next; + + if (tmp->keyword != NULL) + free(tmp->keyword); + + if (tmp->opts != NULL) + free(tmp->opts); + + if (tmp->file_name != NULL) + free(tmp->file_name); + + /* Don't free listhead as it's just a pointer to the user defined + * rule's rule list node's list head */ + + free(tmp); + } +} + +#ifdef SIDE_CHANNEL +static void FreeSideChannelModuleConfigs(SideChannelModuleConfig *head) +{ + while (head != NULL) + { + SideChannelModuleConfig *tmp = head; + + head = head->next; + + if (tmp->keyword != NULL) + free(tmp->keyword); + + if (tmp->opts != NULL) + free(tmp->opts); + + if (tmp->file_name != NULL) + free(tmp->file_name); + + free(tmp); + } +} +#endif + +static void FreePreprocConfigs(SnortConfig *sc) +{ + tSfPolicyId i; + + if (sc == NULL) + return; + + for (i = 0; i < sc->num_policies_allocated; i++) + { + SnortPolicy *p = sc->targeted_policies[i]; + PreprocConfig *head; + + if (p == NULL) + continue; + + head = p->preproc_configs; + + while (head != NULL) + { + PreprocConfig *tmp = head; + + head = head->next; + + if (tmp->keyword != NULL) + free(tmp->keyword); + + if (tmp->opts != NULL) + free(tmp->opts); + + if (tmp->file_name != NULL) + free(tmp->file_name); + + free(tmp); + } + } +} + +static void FreeRuleStateList(RuleState *head) +{ + while (head != NULL) + { + RuleState *tmp = head; + + head = head->next; + + free(tmp); + } +} + +static void FreeClassifications(ClassType *head) +{ + while (head != NULL) + { + ClassType *tmp = head; + + head = head->next; + + if (tmp->name != NULL) + free(tmp->name); + + if (tmp->type != NULL) + free(tmp->type); + + free(tmp); + } +} + +static void FreeReferences(ReferenceSystemNode *head) +{ + while (head != NULL) + { + ReferenceSystemNode *tmp = head; + + head = head->next; + + if (tmp->name != NULL) + free(tmp->name); + + if (tmp->url != NULL) + free(tmp->url); + + free(tmp); + } +} + +#if defined(SNORT_RELOAD) && !defined(WIN32) +static void updatePeriodicCheck() +{ + PeriodicCheckFuncNode *checkFunc; + + /* reset preprocessors */ + checkFunc = periodic_check_funcs; + while (checkFunc != NULL) + { + if ( 0 == checkFunc->time_left ) + { + checkFunc->func(-1, checkFunc->arg); + checkFunc->time_left = checkFunc->period; + //LogMessage(" --== Share Memory! ==--\n"); + } + else + checkFunc->time_left--; + + checkFunc = checkFunc->next; + } + +} + +static void * ReloadConfigThread(void *data) +{ + sigset_t mtmask; + + /* Don't handle any signals here */ + sigfillset(&mtmask); + pthread_sigmask(SIG_BLOCK, &mtmask, NULL); + + snort_reload_thread_pid = gettid(); + snort_reload_thread_created = 1; + + while (snort_initializing) + nanosleep(&thread_sleep, NULL); + + while (!snort_exiting) + { + if (reload_signal != reload_total) + { + int reload_failed = 0; + +#ifdef CONTROL_SOCKET + pthread_mutex_lock(&reload_mutex); + if (!reloadInProgress) + { + reloadInProgress = 1; + pthread_mutex_unlock(&reload_mutex); +#endif + reload_total++; + + LogMessage("\n"); + LogMessage(" --== Reloading Snort ==--\n"); + LogMessage("\n"); + + snort_conf_new = ReloadConfig(); + if (snort_conf_new == NULL) + reload_failed = 1; + snort_reload = 1; + + while (!snort_swapped && !snort_exiting) + nanosleep(&thread_sleep, NULL); + + snort_swapped = 0; + + SnortConfFree(snort_conf_old); + snort_conf_old = NULL; + +#ifdef INTEL_SOFT_CPM + if (snort_conf->fast_pattern_config->search_method != MPSE_INTEL_CPM) + IntelPmStopInstance(); +#endif + + if (snort_exiting && !reload_failed) + { + /* This will load the new preprocessor configurations and + * free the old ones, so any preprocessor cleanup that + * requires a configuration will be using the new one + * unless it relies on old configurations that are still + * attached to existing sessions. */ + SwapPreprocConfigurations(snort_conf); + FreeSwappedPreprocConfigurations(snort_conf); + +#ifdef CONTROL_SOCKET + reloadInProgress = 0; +#endif + /* Get out of the loop and exit */ + break; + } + + if (!reload_failed) + { + LogMessage("\n"); + LogMessage(" --== Reload Complete ==--\n"); + LogMessage("\n"); + } +#ifdef CONTROL_SOCKET + reloadInProgress = 0; + } + else + pthread_mutex_unlock(&reload_mutex); +#endif + } + /* Use the maintenance thread for periodic check*/ + updatePeriodicCheck(); + + sleep(1); + } + + pthread_exit((void *)0); +} + +static SnortConfig * ReloadConfig(void) +{ + SnortConfig *sc; + +#ifdef HAVE_MALLOC_TRIM + malloc_trim(0); +#endif + + sc = ParseSnortConf(); + + sc = MergeSnortConfs(snort_cmd_line_conf, sc); + + sc->reloadPolicyFlag = 1; + +#ifdef PERF_PROFILING + /* Parse profiling here because of file option and potential + * dependence on log directory */ + { + char *opts = NULL; + int in_table; + + in_table = sfghash_find2(sc->config_table, + CONFIG_OPT__PROFILE_PREPROCS, (void *)&opts); + if (in_table) + ConfigProfilePreprocs(sc, opts); + + in_table = sfghash_find2(sc->config_table, + CONFIG_OPT__PROFILE_RULES, (void *)&opts); + if (in_table) + ConfigProfileRules(sc, opts); + } +#endif + + if (VerifyReload(sc) == -1) + { + SnortConfFree(sc); + return NULL; + } + + if (sc->output_flags & OUTPUT_FLAG__USE_UTC) + sc->thiszone = 0; + else + sc->thiszone = gmt2local(0); + + /* Preprocessors will have a reload callback */ + ConfigurePreprocessors(sc, 1); + + FlowbitResetCounts(); + ParseRules(sc); + RuleOptParseCleanup(); + + ReloadDynamicRules(sc); + + /* Handles Fatal Errors itself. */ + SnortEventqNew(sc->event_queue_config, sc->event_queue); + + detection_filter_print_config(sc->detection_filter_config); + RateFilter_PrintConfig(sc->rate_filter_config); + print_thresholding(sc->threshold_config, 0); + PrintRuleOrder(sc->rule_lists); + + SetRuleStates(sc); + + if (file_sevice_config_verify(snort_conf, sc) == -1) + { + SnortConfFree(sc); + return NULL; + } + + if (VerifyReloadedPreprocessors(sc) == -1) + { + SnortConfFree(sc); + return NULL; + } + + if (CheckPreprocessorsConfig(sc)) + { + SnortConfFree(sc); + return NULL; + } + + FilterConfigPreprocessors(sc); + PostConfigPreprocessors(sc); + + /* Need to do this after dynamic detection stuff is initialized, too */ + FlowBitsVerify(); + + if ((sc->file_mask != 0) && (sc->file_mask != snort_conf->file_mask)) + umask(sc->file_mask); + + /* Transfer any user defined rule type outputs to the new rule list */ + { + RuleListNode *cur = snort_conf->rule_lists; + + for (; cur != NULL; cur = cur->next) + { + RuleListNode *new = sc->rule_lists; + + for (; new != NULL; new = new->next) + { + if (strcasecmp(cur->name, new->name) == 0) + { + OutputFuncNode *alert_list = cur->RuleList->AlertList; + OutputFuncNode *log_list = cur->RuleList->LogList; + + sc->head_tmp = new->RuleList; + + for (; alert_list != NULL; alert_list = alert_list->next) + { + AddFuncToOutputList(sc, alert_list->func, + OUTPUT_TYPE__ALERT, alert_list->arg); + } + + for (; log_list != NULL; log_list = log_list->next) + { + AddFuncToOutputList(sc, log_list->func, + OUTPUT_TYPE__LOG, log_list->arg); + } + + sc->head_tmp = NULL; + break; + } + } + } + } + + /* XXX XXX Can't do any output plugins */ + //PostConfigInitPlugins(sc->plugin_post_config_funcs); + + fpCreateFastPacketDetection(sc); + +#ifdef PPM_MGR + PPM_PRINT_CFG(&sc->ppm_cfg); +#endif + + return sc; +} + +static int VerifyReload(SnortConfig *sc) +{ + if (sc == NULL) + return -1; + +#ifdef TARGET_BASED + { + SnortPolicy *p1 = sc->targeted_policies[getDefaultPolicy()]; + SnortPolicy *p2 = snort_conf->targeted_policies[getDefaultPolicy()]; + + if ((p1->target_based_config.args != NULL) && + (p2->target_based_config.args != NULL)) + { + if (strcasecmp(p1->target_based_config.args, + p2->target_based_config.args) != 0) + { + ErrorMessage("Snort Reload: Changing the attribute table " + "configuration requires a restart.\n"); + return -1; + } + } + else if (p1->target_based_config.args != + p2->target_based_config.args) + { + /* Covers one being NULL and not the other */ + ErrorMessage("Snort Reload: Changing the attribute table " + "configuration requires a restart.\n"); + return -1; + } + } +#endif + + if ((snort_conf->alert_file != NULL) && (sc->alert_file != NULL)) + { + if (strcasecmp(snort_conf->alert_file, sc->alert_file) != 0) + { + ErrorMessage("Snort Reload: Changing the alert file " + "configuration requires a restart.\n"); + return -1; + } + } + else if (snort_conf->alert_file != sc->alert_file) + { + ErrorMessage("Snort Reload: Changing the alert file " + "configuration requires a restart.\n"); + return -1; + } + + if (snort_conf->asn1_mem != sc->asn1_mem) + { + ErrorMessage("Snort Reload: Changing the asn1 memory configuration " + "requires a restart.\n"); + return -1; + } + + if ((sc->bpf_filter == NULL) && (sc->bpf_file != NULL)) + sc->bpf_filter = read_infile(sc->bpf_file); + + if ((sc->bpf_filter != NULL) && (snort_conf->bpf_filter != NULL)) + { + if (strcasecmp(snort_conf->bpf_filter, sc->bpf_filter) != 0) + { + ErrorMessage("Snort Reload: Changing the bpf filter configuration " + "requires a restart.\n"); + return -1; + } + } + else if (sc->bpf_filter != snort_conf->bpf_filter) + { + ErrorMessage("Snort Reload: Changing the bpf filter configuration " + "requires a restart.\n"); + return -1; + } + +#ifdef ACTIVE_RESPONSE + if ( sc->respond_attempts != snort_conf->respond_attempts || + sc->respond_device != snort_conf->respond_device ) + { + ErrorMessage("Snort Reload: Changing config response " + "requires a restart.\n"); + return -1; + } +#endif + + if ((snort_conf->chroot_dir != NULL) && + (sc->chroot_dir != NULL)) + { + if (strcasecmp(snort_conf->chroot_dir, sc->chroot_dir) != 0) + { + ErrorMessage("Snort Reload: Changing the chroot directory " + "configuration requires a restart.\n"); + return -1; + } + } + else if (snort_conf->chroot_dir != sc->chroot_dir) + { + ErrorMessage("Snort Reload: Changing the chroot directory " + "configuration requires a restart.\n"); + return -1; + } + + if ((snort_conf->run_flags & RUN_FLAG__DAEMON) != + (sc->run_flags & RUN_FLAG__DAEMON)) + { + ErrorMessage("Snort Reload: Changing to or from daemon mode " + "requires a restart.\n"); + return -1; + } + + if ((snort_conf->interface != NULL) && (sc->interface != NULL)) + { + if (strcasecmp(snort_conf->interface, sc->interface) != 0) + { + ErrorMessage("Snort Reload: Changing the interface " + "configuration requires a restart.\n"); + return -1; + } + } + else if (snort_conf->interface != sc->interface) + { + ErrorMessage("Snort Reload: Changing the interface " + "configuration requires a restart.\n"); + return -1; + } + + /* Orig log dir because a chroot might have changed it */ + if ((snort_conf->orig_log_dir != NULL) && + (sc->orig_log_dir != NULL)) + { + if (strcasecmp(snort_conf->orig_log_dir, sc->orig_log_dir) != 0) + { + ErrorMessage("Snort Reload: Changing the log directory " + "configuration requires a restart.\n"); + return -1; + } + } + else if (snort_conf->orig_log_dir != sc->orig_log_dir) + { + ErrorMessage("Snort Reload: Changing the log directory " + "configuration requires a restart.\n"); + return -1; + } + +#ifdef TARGET_BASED + if (snort_conf->max_attribute_hosts != sc->max_attribute_hosts) + { + ErrorMessage("Snort Reload: Changing max_attribute_hosts " + "configuration requires a restart.\n"); + return -1; + } + if (snort_conf->max_attribute_services_per_host != sc->max_attribute_services_per_host) + { + ErrorMessage("Snort Reload: Changing max_attribute_services_per_host " + "configuration requires a restart.\n"); + return -1; + } +#endif + + if (snort_conf->no_log != sc->no_log) + { + ErrorMessage("Snort Reload: Changing from log to no log or vice " + "versa requires a restart.\n"); + return -1; + } + + if ((snort_conf->run_flags & RUN_FLAG__NO_PROMISCUOUS) != + (sc->run_flags & RUN_FLAG__NO_PROMISCUOUS)) + { + ErrorMessage("Snort Reload: Changing to or from promiscuous mode " + "requires a restart.\n"); + return -1; + } + +#ifdef PPM_MGR + /* XXX XXX Not really sure we need to disallow this */ + if (snort_conf->ppm_cfg.rule_log != sc->ppm_cfg.rule_log) + { + ErrorMessage("Snort Reload: Changing the ppm rule_log " + "configuration requires a restart.\n"); + return -1; + } +#endif + +#ifdef PERF_PROFILING + if ((snort_conf->profile_rules.num != sc->profile_rules.num) || + (snort_conf->profile_rules.sort != sc->profile_rules.sort) || + (snort_conf->profile_rules.append != sc->profile_rules.append)) + { + ErrorMessage("Snort Reload: Changing rule profiling number, sort " + "or append configuration requires a restart.\n"); + return -1; + } + + if ((snort_conf->profile_rules.filename != NULL) && + (sc->profile_rules.filename != NULL)) + { + if (strcasecmp(snort_conf->profile_rules.filename, + sc->profile_rules.filename) != 0) + { + ErrorMessage("Snort Reload: Changing the rule profiling filename " + "configuration requires a restart.\n"); + return -1; + } + } + else if (snort_conf->profile_rules.filename != + sc->profile_rules.filename) + { + ErrorMessage("Snort Reload: Changing the rule profiling filename " + "configuration requires a restart.\n"); + return -1; + } + + if ((snort_conf->profile_preprocs.num != sc->profile_preprocs.num) || + (snort_conf->profile_preprocs.sort != sc->profile_preprocs.sort) || + (snort_conf->profile_preprocs.append != sc->profile_preprocs.append)) + { + ErrorMessage("Snort Reload: Changing preprocessor profiling number, " + "sort or append configuration requires a restart.\n"); + return -1; + } + + if ((snort_conf->profile_preprocs.filename != NULL) && + (sc->profile_preprocs.filename != NULL)) + { + if (strcasecmp(snort_conf->profile_preprocs.filename, + sc->profile_preprocs.filename) != 0) + { + ErrorMessage("Snort Reload: Changing the preprocessor profiling " + "filename configuration requires a restart.\n"); + return -1; + } + } + else if (snort_conf->profile_preprocs.filename != + sc->profile_preprocs.filename) + { + ErrorMessage("Snort Reload: Changing the preprocessor profiling " + "filename configuration requires a restart.\n"); + return -1; + } +#endif + + if (snort_conf->group_id != sc->group_id) + { + ErrorMessage("Snort Reload: Changing the group id " + "configuration requires a restart.\n"); + return -1; + } + + if (snort_conf->user_id != sc->user_id) + { + ErrorMessage("Snort Reload: Changing the user id " + "configuration requires a restart.\n"); + return -1; + } + + if (snort_conf->pkt_snaplen != sc->pkt_snaplen) + { + ErrorMessage("Snort Reload: Changing the packet snaplen " + "configuration requires a restart.\n"); + return -1; + } + + if (snort_conf->threshold_config->memcap != + sc->threshold_config->memcap) + { + ErrorMessage("Snort Reload: Changing the threshold memcap " + "configuration requires a restart.\n"); + return -1; + } + + if (snort_conf->rate_filter_config->memcap != + sc->rate_filter_config->memcap) + { + ErrorMessage("Snort Reload: Changing the rate filter memcap " + "configuration requires a restart.\n"); + return -1; + } + + if (snort_conf->detection_filter_config->memcap != + sc->detection_filter_config->memcap) + { + ErrorMessage("Snort Reload: Changing the detection filter memcap " + "configuration requires a restart.\n"); + return -1; + } + + if (VerifyLibInfos(snort_conf->dyn_engines, sc->dyn_engines) == -1) + { + ErrorMessage("Snort Reload: Any change to the dynamic engine " + "configuration requires a restart.\n"); + return -1; + } + + if (VerifyLibInfos(snort_conf->dyn_rules, sc->dyn_rules) == -1) + { + ErrorMessage("Snort Reload: Any change to the dynamic detection " + "configuration requires a restart.\n"); + return -1; + } + + if (VerifyLibInfos(snort_conf->dyn_preprocs, sc->dyn_preprocs) == -1) + { + ErrorMessage("Snort Reload: Any change to the dynamic preprocessor " + "configuration requires a restart.\n"); + return -1; + } + + if (snort_conf->so_rule_memcap != sc->so_rule_memcap) + { + ErrorMessage("Snort Reload: Changing the so rule memcap " + "configuration requires a restart.\n"); + return -1; + } + + if (VerifyOutputs(snort_conf, sc) == -1) + return -1; + +#ifdef SIDE_CHANNEL + if (SideChannelVerifyConfig(sc) != 0) + { + ErrorMessage("Snort Reload: Changing the side channel configuration requires a restart.\n"); + return -1; + } +#endif + + return 0; +} + +static int VerifyOutputs(SnortConfig *old_config, SnortConfig *new_config) +{ + OutputConfig *old_output_config, *new_output_config; + int old_outputs = 0, new_outputs = 0; + + /* Get from output_configs to see if output has changed */ + for (old_output_config = old_config->output_configs; + old_output_config != NULL; + old_output_config = old_output_config->next) + { + old_outputs++; + } + + for (new_output_config = new_config->output_configs; + new_output_config != NULL; + new_output_config = new_output_config->next) + { + new_outputs++; + } + + if (new_outputs != old_outputs) + { + ErrorMessage("Snort Reload: Any change to any output " + "configurations requires a restart.\n"); + return -1; + } + + for (old_output_config = old_config->output_configs; + old_output_config != NULL; + old_output_config = old_output_config->next) + { + + for (new_output_config = new_config->output_configs; + new_output_config != NULL; + new_output_config = new_output_config->next) + { + if (strcasecmp(old_output_config->keyword, new_output_config->keyword) == 0) + { + if ((old_output_config->opts != NULL) && + (new_output_config->opts != NULL) && + (strcasecmp(old_output_config->opts, new_output_config->opts) == 0)) + { + new_outputs++; + break; + } + else if (old_output_config->opts == NULL && + new_output_config->opts == NULL) + { + new_outputs++; + break; + } + } + + } + + old_outputs++; + } + + if (new_outputs != old_outputs) + { + ErrorMessage("Snort Reload: Any change to any output " + "configurations requires a restart.\n"); + return -1; + } + + /* Check user defined rule type outputs */ + for (old_output_config = old_config->rule_type_output_configs; + old_output_config != NULL; + old_output_config = old_output_config->next) + { + old_outputs++; + } + + for (new_output_config = new_config->rule_type_output_configs; + new_output_config != NULL; + new_output_config = new_output_config->next) + { + new_outputs++; + } + + if (new_outputs != old_outputs) + { + ErrorMessage("Snort Reload: Any change to any output " + "configurations requires a restart.\n"); + return -1; + } + + /* Do user defined rule type outputs as well */ + for (old_output_config = old_config->rule_type_output_configs; + old_output_config != NULL; + old_output_config = old_output_config->next) + { + for (new_output_config = new_config->rule_type_output_configs; + new_output_config != NULL; + new_output_config = new_output_config->next) + { + if (strcasecmp(old_output_config->keyword, + new_output_config->keyword) == 0) + { + if (strcasecmp(old_output_config->opts, + new_output_config->opts) == 0) + { + new_outputs++; + break; + } + } + } + + old_outputs++; + } + + if (new_outputs != old_outputs) + { + ErrorMessage("Snort Reload: Any change to any output " + "configurations requires a restart.\n"); + return -1; + } + + return 0; +} + +static int VerifyLibInfos(DynamicLibInfo *old_info, DynamicLibInfo *new_info) +{ + if ((old_info != NULL) && (new_info != NULL)) + { + unsigned i; + + if (old_info->type != new_info->type) + { + FatalError("%s(%d) Incompatible library types.\n", + __FILE__, __LINE__); + } + + if (old_info->count != new_info->count) + return -1; + + for (i = 0; i < old_info->count; i++) + { + unsigned j; + DynamicLibPath *old_path = old_info->lib_paths[i]; + + for (j = 0; j < new_info->count; j++) + { + DynamicLibPath *new_path = new_info->lib_paths[j]; + + if ((strcmp(old_path->path, new_path->path) == 0) && + (old_path->ptype == new_path->ptype)) + { + if (old_path->last_mod_time != new_path->last_mod_time) + return -1; + + break; + } + } + + if (j == new_info->count) + return -1; + } + } + else if (old_info != new_info) + { + return -1; + } + + return 0; +} +#endif /* SNORT_RELOAD */ + --- /dev/null +++ b/snort/snort-patches/0001-add-dependancy-for-lrt.patch @@ -0,0 +1,30 @@ +From 1cc044fb3b00c290afcacab3ca044d371bb039be Mon Sep 17 00:00:00 2001 +From: Maxim Uvarov +Date: Wed, 9 Apr 2014 18:42:29 +0400 +Subject: [PATCH] add dependancy for -lrt + +Signed-off-by: Maxim Uvarov +--- + snort-2.9.6.0/src/snort.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/snort-2.9.6.0/src/snort.c b/snort-2.9.6.0/src/snort.c +index 1481d4f..0280107 100644 +--- a/snort-2.9.6.0/src/snort.c ++++ b/snort-2.9.6.0/src/snort.c +@@ -777,6 +777,12 @@ static int InlineFailOpen (void) + */ + int main(int argc, char *argv[]) + { ++ /* hack to add deps to -lrt for timer_create() and friends from odp */ ++ static volatile int link_rt = 0; ++ timer_t timerid = 0; ++ if (link_rt) ++ timer_settime(timerid, 0, NULL, NULL); ++ + #if defined(WIN32) && defined(ENABLE_WIN32_SERVICE) + /* Do some sanity checking, because some people seem to forget to + * put spaces between their parameters +-- +1.7.9.5 +