aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/source-nfq.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/suricata/src/source-nfq.c')
-rw-r--r--framework/src/suricata/src/source-nfq.c1277
1 files changed, 0 insertions, 1277 deletions
diff --git a/framework/src/suricata/src/source-nfq.c b/framework/src/suricata/src/source-nfq.c
deleted file mode 100644
index 38770cb9..00000000
--- a/framework/src/suricata/src/source-nfq.c
+++ /dev/null
@@ -1,1277 +0,0 @@
-/* Copyright (C) 2007-2014 Open Information Security Foundation
- *
- * You can copy, redistribute or modify this Program under the terms of
- * the GNU General Public License version 2 as published by the Free
- * Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-/**
- * \file
- *
- * \author Victor Julien <victor@inliniac.net>
- * \author Eric Leblond <eric@regit.org>
- *
- * Netfilter's netfilter_queue support for reading packets from the
- * kernel and setting verdicts back to it (inline mode).
- * Supported on Linux and Windows.
- *
- * \todo test if Receive and Verdict if both are present
- */
-
-#include "suricata-common.h"
-#include "suricata.h"
-#include "decode.h"
-#include "packet-queue.h"
-
-#include "threads.h"
-#include "threadvars.h"
-#include "tm-threads.h"
-#include "tm-queuehandlers.h"
-#include "tmqh-packetpool.h"
-
-#include "conf.h"
-#include "config.h"
-#include "conf-yaml-loader.h"
-#include "source-nfq-prototypes.h"
-#include "action-globals.h"
-
-#include "util-debug.h"
-#include "util-error.h"
-#include "util-byte.h"
-#include "util-privs.h"
-#include "util-device.h"
-
-#include "runmodes.h"
-
-#include "source-nfq.h"
-
-#ifndef NFQ
-/** Handle the case where no NFQ support is compiled in.
- *
- */
-
-TmEcode NoNFQSupportExit(ThreadVars *, void *, void **);
-
-void TmModuleReceiveNFQRegister (void)
-{
- tmm_modules[TMM_RECEIVENFQ].name = "ReceiveNFQ";
- tmm_modules[TMM_RECEIVENFQ].ThreadInit = NoNFQSupportExit;
- tmm_modules[TMM_RECEIVENFQ].Func = NULL;
- tmm_modules[TMM_RECEIVENFQ].ThreadExitPrintStats = NULL;
- tmm_modules[TMM_RECEIVENFQ].ThreadDeinit = NULL;
- tmm_modules[TMM_RECEIVENFQ].RegisterTests = NULL;
- tmm_modules[TMM_RECEIVENFQ].cap_flags = SC_CAP_NET_ADMIN;
- tmm_modules[TMM_RECEIVENFQ].flags = TM_FLAG_RECEIVE_TM;
-}
-
-void TmModuleVerdictNFQRegister (void)
-{
- tmm_modules[TMM_VERDICTNFQ].name = "VerdictNFQ";
- tmm_modules[TMM_VERDICTNFQ].ThreadInit = NoNFQSupportExit;
- tmm_modules[TMM_VERDICTNFQ].Func = NULL;
- tmm_modules[TMM_VERDICTNFQ].ThreadExitPrintStats = NULL;
- tmm_modules[TMM_VERDICTNFQ].ThreadDeinit = NULL;
- tmm_modules[TMM_VERDICTNFQ].RegisterTests = NULL;
- tmm_modules[TMM_VERDICTNFQ].cap_flags = SC_CAP_NET_ADMIN;
-}
-
-void TmModuleDecodeNFQRegister (void)
-{
- tmm_modules[TMM_DECODENFQ].name = "DecodeNFQ";
- tmm_modules[TMM_DECODENFQ].ThreadInit = NoNFQSupportExit;
- tmm_modules[TMM_DECODENFQ].Func = NULL;
- tmm_modules[TMM_DECODENFQ].ThreadExitPrintStats = NULL;
- tmm_modules[TMM_DECODENFQ].ThreadDeinit = NULL;
- tmm_modules[TMM_DECODENFQ].RegisterTests = NULL;
- tmm_modules[TMM_DECODENFQ].cap_flags = 0;
- tmm_modules[TMM_DECODENFQ].flags = TM_FLAG_DECODE_TM;
-}
-
-TmEcode NoNFQSupportExit(ThreadVars *tv, void *initdata, void **data)
-{
- SCLogError(SC_ERR_NFQ_NOSUPPORT,"Error creating thread %s: you do not have support for nfqueue "
- "enabled please recompile with --enable-nfqueue", tv->name);
- exit(EXIT_FAILURE);
-}
-
-#else /* implied we do have NFQ support */
-
-extern int max_pending_packets;
-
-#define MAX_ALREADY_TREATED 5
-#define NFQ_VERDICT_RETRY_TIME 3
-static int already_seen_warning;
-static int runmode_workers;
-
-#define NFQ_BURST_FACTOR 4
-
-#ifndef SOL_NETLINK
-#define SOL_NETLINK 270
-#endif
-
-//#define NFQ_DFT_QUEUE_LEN NFQ_BURST_FACTOR * MAX_PENDING
-//#define NFQ_NF_BUFSIZE 1500 * NFQ_DFT_QUEUE_LEN
-
-typedef struct NFQThreadVars_
-{
- uint16_t nfq_index;
- ThreadVars *tv;
- TmSlot *slot;
-
- char *data; /** Per function and thread data */
- int datalen; /** Length of per function and thread data */
-
- CaptureStats stats;
-
-} NFQThreadVars;
-/* shared vars for all for nfq queues and threads */
-static NFQGlobalVars nfq_g;
-
-static NFQThreadVars nfq_t[NFQ_MAX_QUEUE];
-static NFQQueueVars nfq_q[NFQ_MAX_QUEUE];
-static uint16_t receive_queue_num = 0;
-static SCMutex nfq_init_lock;
-
-TmEcode ReceiveNFQLoop(ThreadVars *tv, void *data, void *slot);
-TmEcode ReceiveNFQThreadInit(ThreadVars *, void *, void **);
-TmEcode ReceiveNFQThreadDeinit(ThreadVars *, void *);
-void ReceiveNFQThreadExitStats(ThreadVars *, void *);
-
-TmEcode VerdictNFQ(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
-TmEcode VerdictNFQThreadInit(ThreadVars *, void *, void **);
-TmEcode VerdictNFQThreadDeinit(ThreadVars *, void *);
-
-TmEcode DecodeNFQ(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
-TmEcode DecodeNFQThreadInit(ThreadVars *, void *, void **);
-TmEcode DecodeNFQThreadDeinit(ThreadVars *tv, void *data);
-
-TmEcode NFQSetVerdict(Packet *p);
-
-typedef enum NFQMode_ {
- NFQ_ACCEPT_MODE,
- NFQ_REPEAT_MODE,
- NFQ_ROUTE_MODE,
-} NFQMode;
-
-#define NFQ_FLAG_FAIL_OPEN (1 << 0)
-
-typedef struct NFQCnf_ {
- NFQMode mode;
- uint32_t mark;
- uint32_t mask;
- uint32_t next_queue;
- uint32_t flags;
- uint8_t batchcount;
-} NFQCnf;
-
-NFQCnf nfq_config;
-
-void TmModuleReceiveNFQRegister (void)
-{
- /* XXX create a general NFQ setup function */
- memset(&nfq_g, 0, sizeof(nfq_g));
- SCMutexInit(&nfq_init_lock, NULL);
-
- tmm_modules[TMM_RECEIVENFQ].name = "ReceiveNFQ";
- tmm_modules[TMM_RECEIVENFQ].ThreadInit = ReceiveNFQThreadInit;
- tmm_modules[TMM_RECEIVENFQ].Func = NULL;
- tmm_modules[TMM_RECEIVENFQ].PktAcqLoop = ReceiveNFQLoop;
- tmm_modules[TMM_RECEIVENFQ].ThreadExitPrintStats = ReceiveNFQThreadExitStats;
- tmm_modules[TMM_RECEIVENFQ].ThreadDeinit = ReceiveNFQThreadDeinit;
- tmm_modules[TMM_RECEIVENFQ].RegisterTests = NULL;
- tmm_modules[TMM_RECEIVENFQ].flags = TM_FLAG_RECEIVE_TM;
-}
-
-void TmModuleVerdictNFQRegister (void)
-{
- tmm_modules[TMM_VERDICTNFQ].name = "VerdictNFQ";
- tmm_modules[TMM_VERDICTNFQ].ThreadInit = VerdictNFQThreadInit;
- tmm_modules[TMM_VERDICTNFQ].Func = VerdictNFQ;
- tmm_modules[TMM_VERDICTNFQ].ThreadExitPrintStats = NULL;
- tmm_modules[TMM_VERDICTNFQ].ThreadDeinit = VerdictNFQThreadDeinit;
- tmm_modules[TMM_VERDICTNFQ].RegisterTests = NULL;
-}
-
-void TmModuleDecodeNFQRegister (void)
-{
- tmm_modules[TMM_DECODENFQ].name = "DecodeNFQ";
- tmm_modules[TMM_DECODENFQ].ThreadInit = DecodeNFQThreadInit;
- tmm_modules[TMM_DECODENFQ].Func = DecodeNFQ;
- tmm_modules[TMM_DECODENFQ].ThreadExitPrintStats = NULL;
- tmm_modules[TMM_DECODENFQ].ThreadDeinit = DecodeNFQThreadDeinit;
- tmm_modules[TMM_DECODENFQ].RegisterTests = NULL;
- tmm_modules[TMM_DECODENFQ].flags = TM_FLAG_DECODE_TM;
-}
-
-/** \brief To initialize the NFQ global configuration data
- *
- * \param quiet It tells the mode of operation, if it is TRUE nothing will
- * be get printed.
- */
-void NFQInitConfig(char quiet)
-{
- intmax_t value = 0;
- char* nfq_mode = NULL;
- int boolval;
-
- SCLogDebug("Initializing NFQ");
-
- memset(&nfq_config, 0, sizeof(nfq_config));
-
- if ((ConfGet("nfq.mode", &nfq_mode)) == 0) {
- nfq_config.mode = NFQ_ACCEPT_MODE;
- } else {
- if (!strcmp("accept", nfq_mode)) {
- nfq_config.mode = NFQ_ACCEPT_MODE;
- } else if (!strcmp("repeat", nfq_mode)) {
- nfq_config.mode = NFQ_REPEAT_MODE;
- } else if (!strcmp("route", nfq_mode)) {
- nfq_config.mode = NFQ_ROUTE_MODE;
- } else {
- SCLogError(SC_ERR_INVALID_ARGUMENT, "Unknown nfq.mode");
- exit(EXIT_FAILURE);
- }
- }
-
- (void)ConfGetBool("nfq.fail-open", (int *)&boolval);
- if (boolval) {
-#ifdef HAVE_NFQ_SET_QUEUE_FLAGS
- SCLogInfo("Enabling fail-open on queue");
- nfq_config.flags |= NFQ_FLAG_FAIL_OPEN;
-#else
- SCLogError(SC_ERR_NFQ_NOSUPPORT,
- "nfq.%s set but NFQ library has no support for it.", "fail-open");
-#endif
- }
-
- if ((ConfGetInt("nfq.repeat-mark", &value)) == 1) {
- nfq_config.mark = (uint32_t)value;
- }
-
- if ((ConfGetInt("nfq.repeat-mask", &value)) == 1) {
- nfq_config.mask = (uint32_t)value;
- }
-
- if ((ConfGetInt("nfq.route-queue", &value)) == 1) {
- nfq_config.next_queue = ((uint32_t)value) << 16;
- }
-
- if ((ConfGetInt("nfq.batchcount", &value)) == 1) {
-#ifdef HAVE_NFQ_SET_VERDICT_BATCH
- if (value > 255) {
- SCLogWarning(SC_ERR_INVALID_ARGUMENT, "nfq.batchcount cannot exceed 255.");
- value = 255;
- }
- if (value > 1)
- nfq_config.batchcount = (uint8_t) (value - 1);
-#else
- SCLogWarning(SC_ERR_NFQ_NOSUPPORT,
- "nfq.%s set but NFQ library has no support for it.", "batchcount");
-#endif
- }
-
- if (!quiet) {
- switch (nfq_config.mode) {
- case NFQ_ACCEPT_MODE:
- SCLogInfo("NFQ running in standard ACCEPT/DROP mode");
- break;
- case NFQ_REPEAT_MODE:
- SCLogInfo("NFQ running in REPEAT mode with mark %"PRIu32"/%"PRIu32,
- nfq_config.mark, nfq_config.mask);
- break;
- case NFQ_ROUTE_MODE:
- SCLogInfo("NFQ running in route mode with next queue %"PRIu32,
- nfq_config.next_queue >> 16);
- break;
- }
- }
-
-}
-
-static uint8_t NFQVerdictCacheLen(NFQQueueVars *t)
-{
-#ifdef HAVE_NFQ_SET_VERDICT_BATCH
- return t->verdict_cache.len;
-#else
- return 0;
-#endif
-}
-
-static void NFQVerdictCacheFlush(NFQQueueVars *t)
-{
-#ifdef HAVE_NFQ_SET_VERDICT_BATCH
- int ret;
- int iter = 0;
-
- do {
- if (t->verdict_cache.mark_valid)
- ret = nfq_set_verdict_batch2(t->qh,
- t->verdict_cache.packet_id,
- t->verdict_cache.verdict,
- t->verdict_cache.mark);
- else
- ret = nfq_set_verdict_batch(t->qh,
- t->verdict_cache.packet_id,
- t->verdict_cache.verdict);
- } while ((ret < 0) && (iter++ < NFQ_VERDICT_RETRY_TIME));
-
- if (ret < 0) {
- SCLogWarning(SC_ERR_NFQ_SET_VERDICT, "nfq_set_verdict_batch failed: %s",
- strerror(errno));
- } else {
- t->verdict_cache.len = 0;
- t->verdict_cache.mark_valid = 0;
- }
-#endif
-}
-
-static int NFQVerdictCacheAdd(NFQQueueVars *t, Packet *p, uint32_t verdict)
-{
-#ifdef HAVE_NFQ_SET_VERDICT_BATCH
- if (t->verdict_cache.maxlen == 0)
- return -1;
-
- if (p->flags & PKT_STREAM_MODIFIED || verdict == NF_DROP)
- goto flush;
-
- if (p->flags & PKT_MARK_MODIFIED) {
- if (!t->verdict_cache.mark_valid) {
- if (t->verdict_cache.len)
- goto flush;
- t->verdict_cache.mark_valid = 1;
- t->verdict_cache.mark = p->nfq_v.mark;
- } else if (t->verdict_cache.mark != p->nfq_v.mark) {
- goto flush;
- }
- } else if (t->verdict_cache.mark_valid) {
- goto flush;
- }
-
- if (t->verdict_cache.len == 0) {
- t->verdict_cache.verdict = verdict;
- } else if (t->verdict_cache.verdict != verdict)
- goto flush;
-
- /* same verdict, mark not set or identical -> can cache */
- t->verdict_cache.packet_id = p->nfq_v.id;
-
- if (t->verdict_cache.len >= t->verdict_cache.maxlen)
- NFQVerdictCacheFlush(t);
- else
- t->verdict_cache.len++;
- return 0;
- flush:
- /* can't cache. Flush current cache and signal caller it should send single verdict */
- if (NFQVerdictCacheLen(t) > 0)
- NFQVerdictCacheFlush(t);
-#endif
- return -1;
-}
-
-static inline void NFQMutexInit(NFQQueueVars *nq)
-{
- char *active_runmode = RunmodeGetActive();
-
- if (active_runmode && !strcmp("workers", active_runmode)) {
- nq->use_mutex = 0;
- runmode_workers = 1;
- SCLogInfo("NFQ running in 'workers' runmode, will not use mutex.");
- } else {
- nq->use_mutex = 1;
- runmode_workers = 0;
- SCMutexInit(&nq->mutex_qh, NULL);
- }
-}
-
-#define NFQMutexLock(nq) do { \
- if ((nq)->use_mutex) \
- SCMutexLock(&(nq)->mutex_qh); \
-} while (0)
-
-#define NFQMutexUnlock(nq) do { \
- if ((nq)->use_mutex) \
- SCMutexUnlock(&(nq)->mutex_qh); \
-} while (0)
-
-/**
- * \brief Read data from nfq message and setup Packet
- *
- * \note
- * In case of error, this function verdict the packet
- * to avoid skb to get stuck in kernel.
- */
-int NFQSetupPkt (Packet *p, struct nfq_q_handle *qh, void *data)
-{
- struct nfq_data *tb = (struct nfq_data *)data;
- int ret;
- char *pktdata;
- struct nfqnl_msg_packet_hdr *ph;
-
- ph = nfq_get_msg_packet_hdr(tb);
- if (ph != NULL) {
- p->nfq_v.id = ntohl(ph->packet_id);
- //p->nfq_v.hw_protocol = ntohs(p->nfq_v.ph->hw_protocol);
- p->nfq_v.hw_protocol = ph->hw_protocol;
- }
- p->nfq_v.mark = nfq_get_nfmark(tb);
- if (nfq_config.mode == NFQ_REPEAT_MODE) {
- if ((nfq_config.mark & nfq_config.mask) ==
- (p->nfq_v.mark & nfq_config.mask)) {
- int iter = 0;
- if (already_seen_warning < MAX_ALREADY_TREATED)
- SCLogInfo("Packet seems already treated by suricata");
- already_seen_warning++;
- do {
- ret = nfq_set_verdict(qh, p->nfq_v.id, NF_ACCEPT, 0, NULL);
- } while ((ret < 0) && (iter++ < NFQ_VERDICT_RETRY_TIME));
- if (ret < 0) {
- SCLogWarning(SC_ERR_NFQ_SET_VERDICT,
- "nfq_set_verdict of %p failed %" PRId32 ": %s",
- p, ret, strerror(errno));
- }
- return -1 ;
- }
- }
- p->nfq_v.ifi = nfq_get_indev(tb);
- p->nfq_v.ifo = nfq_get_outdev(tb);
- p->nfq_v.verdicted = 0;
-
-#ifdef NFQ_GET_PAYLOAD_SIGNED
- ret = nfq_get_payload(tb, &pktdata);
-#else
- ret = nfq_get_payload(tb, (unsigned char **) &pktdata);
-#endif /* NFQ_GET_PAYLOAD_SIGNED */
- if (ret > 0) {
- /* nfq_get_payload returns a pointer to a part of memory
- * that is not preserved over the lifetime of our packet.
- * So we need to copy it. */
- if (ret > 65536) {
- /* Will not be able to copy data ! Set length to 0
- * to trigger an error in packet decoding.
- * This is unlikely to happen */
- SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "NFQ sent too big packet");
- SET_PKT_LEN(p, 0);
- } else if (runmode_workers) {
- PacketSetData(p, (uint8_t *)pktdata, ret);
- } else {
- PacketCopyData(p, (uint8_t *)pktdata, ret);
- }
- } else if (ret == -1) {
- /* unable to get pointer to data, ensure packet length is zero.
- * This will trigger an error in packet decoding */
- SET_PKT_LEN(p, 0);
- }
-
- ret = nfq_get_timestamp(tb, &p->ts);
- if (ret != 0) {
- memset (&p->ts, 0, sizeof(struct timeval));
- gettimeofday(&p->ts, NULL);
- }
-
- p->datalink = DLT_RAW;
- return 0;
-}
-
-static void NFQReleasePacket(Packet *p)
-{
- if (unlikely(!p->nfq_v.verdicted)) {
- PACKET_UPDATE_ACTION(p, ACTION_DROP);
- NFQSetVerdict(p);
- }
- PacketFreeOrRelease(p);
-}
-
-static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
- struct nfq_data *nfa, void *data)
-{
- NFQThreadVars *ntv = (NFQThreadVars *)data;
- ThreadVars *tv = ntv->tv;
- int ret;
-
- /* grab a packet */
- Packet *p = PacketGetFromQueueOrAlloc();
- if (p == NULL) {
- return -1;
- }
- PKT_SET_SRC(p, PKT_SRC_WIRE);
-
- p->nfq_v.nfq_index = ntv->nfq_index;
- ret = NFQSetupPkt(p, qh, (void *)nfa);
- if (ret == -1) {
-#ifdef COUNTERS
- NFQQueueVars *nfq_q = NFQGetQueue(ntv->nfq_index);
- nfq_q->errs++;
- nfq_q->pkts++;
- nfq_q->bytes += GET_PKT_LEN(p);
-#endif /* COUNTERS */
- /* NFQSetupPkt is issuing a verdict
- so we only recycle Packet and leave */
- TmqhOutputPacketpool(tv, p);
- return 0;
- }
-
- p->ReleasePacket = NFQReleasePacket;
-
-#ifdef COUNTERS
- NFQQueueVars *nfq_q = NFQGetQueue(ntv->nfq_index);
- nfq_q->pkts++;
- nfq_q->bytes += GET_PKT_LEN(p);
-#endif /* COUNTERS */
-
- if (ntv->slot) {
- if (TmThreadsSlotProcessPkt(tv, ntv->slot, p) != TM_ECODE_OK) {
- TmqhOutputPacketpool(ntv->tv, p);
- return -1;
- }
- } else {
- /* pass on... */
- tv->tmqh_out(tv, p);
- }
-
- return 0;
-}
-
-TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen)
-{
-#ifndef OS_WIN32
- struct timeval tv;
- int opt;
-#endif
- NFQQueueVars *nfq_q = NFQGetQueue(nfq_t->nfq_index);
- if (nfq_q == NULL) {
- SCLogError(SC_ERR_NFQ_OPEN, "no queue for given index");
- return TM_ECODE_FAILED;
- }
- SCLogDebug("opening library handle");
- nfq_q->h = nfq_open();
- if (!nfq_q->h) {
- SCLogError(SC_ERR_NFQ_OPEN, "nfq_open() failed");
- return TM_ECODE_FAILED;
- }
-
- if (nfq_g.unbind == 0)
- {
- /* VJ: on my Ubuntu Hardy system this fails the first time it's
- * run. Ignoring the error seems to have no bad effects. */
- SCLogDebug("unbinding existing nf_queue handler for AF_INET (if any)");
- if (nfq_unbind_pf(nfq_q->h, AF_INET) < 0) {
- SCLogError(SC_ERR_NFQ_UNBIND, "nfq_unbind_pf() for AF_INET failed");
- exit(EXIT_FAILURE);
- }
- if (nfq_unbind_pf(nfq_q->h, AF_INET6) < 0) {
- SCLogError(SC_ERR_NFQ_UNBIND, "nfq_unbind_pf() for AF_INET6 failed");
- exit(EXIT_FAILURE);
- }
- nfq_g.unbind = 1;
-
- SCLogDebug("binding nfnetlink_queue as nf_queue handler for AF_INET and AF_INET6");
-
- if (nfq_bind_pf(nfq_q->h, AF_INET) < 0) {
- SCLogError(SC_ERR_NFQ_BIND, "nfq_bind_pf() for AF_INET failed");
- exit(EXIT_FAILURE);
- }
- if (nfq_bind_pf(nfq_q->h, AF_INET6) < 0) {
- SCLogError(SC_ERR_NFQ_BIND, "nfq_bind_pf() for AF_INET6 failed");
- exit(EXIT_FAILURE);
- }
- }
-
- SCLogInfo("binding this thread %d to queue '%" PRIu32 "'", nfq_t->nfq_index, nfq_q->queue_num);
-
- /* pass the thread memory as a void ptr so the
- * callback function has access to it. */
- nfq_q->qh = nfq_create_queue(nfq_q->h, nfq_q->queue_num, &NFQCallBack, (void *)nfq_t);
- if (nfq_q->qh == NULL)
- {
- SCLogError(SC_ERR_NFQ_CREATE_QUEUE, "nfq_create_queue failed");
- return TM_ECODE_FAILED;
- }
-
- SCLogDebug("setting copy_packet mode");
-
- /* 05DC = 1500 */
- //if (nfq_set_mode(nfq_t->qh, NFQNL_COPY_PACKET, 0x05DC) < 0) {
- if (nfq_set_mode(nfq_q->qh, NFQNL_COPY_PACKET, 0xFFFF) < 0) {
- SCLogError(SC_ERR_NFQ_SET_MODE, "can't set packet_copy mode");
- return TM_ECODE_FAILED;
- }
-
-#ifdef HAVE_NFQ_MAXLEN
- if (queue_maxlen > 0) {
- SCLogInfo("setting queue length to %" PRId32 "", queue_maxlen);
-
- /* non-fatal if it fails */
- if (nfq_set_queue_maxlen(nfq_q->qh, queue_maxlen) < 0) {
- SCLogWarning(SC_ERR_NFQ_MAXLEN, "can't set queue maxlen: your kernel probably "
- "doesn't support setting the queue length");
- }
- }
-#endif /* HAVE_NFQ_MAXLEN */
-
-#ifndef OS_WIN32
- /* set netlink buffer size to a decent value */
- nfnl_rcvbufsiz(nfq_nfnlh(nfq_q->h), queue_maxlen * 1500);
- SCLogInfo("setting nfnl bufsize to %" PRId32 "", queue_maxlen * 1500);
-
- nfq_q->nh = nfq_nfnlh(nfq_q->h);
- nfq_q->fd = nfnl_fd(nfq_q->nh);
- NFQMutexInit(nfq_q);
-
- /* Set some netlink specific option on the socket to increase
- performance */
- opt = 1;
-#ifdef NETLINK_BROADCAST_SEND_ERROR
- if (setsockopt(nfq_q->fd, SOL_NETLINK,
- NETLINK_BROADCAST_SEND_ERROR, &opt, sizeof(int)) == -1) {
- SCLogWarning(SC_ERR_NFQ_SETSOCKOPT,
- "can't set netlink broadcast error: %s",
- strerror(errno));
- }
-#endif
- /* Don't send error about no buffer space available but drop the
- packets instead */
-#ifdef NETLINK_NO_ENOBUFS
- if (setsockopt(nfq_q->fd, SOL_NETLINK,
- NETLINK_NO_ENOBUFS, &opt, sizeof(int)) == -1) {
- SCLogWarning(SC_ERR_NFQ_SETSOCKOPT,
- "can't set netlink enobufs: %s",
- strerror(errno));
- }
-#endif
-
-#ifdef HAVE_NFQ_SET_QUEUE_FLAGS
- if (nfq_config.flags & NFQ_FLAG_FAIL_OPEN) {
- uint32_t flags = NFQA_CFG_F_FAIL_OPEN;
- uint32_t mask = NFQA_CFG_F_FAIL_OPEN;
- int r = nfq_set_queue_flags(nfq_q->qh, mask, flags);
-
- if (r == -1) {
- SCLogWarning(SC_ERR_NFQ_SET_MODE, "can't set fail-open mode: %s",
- strerror(errno));
- } else {
- SCLogInfo("fail-open mode should be set on queue");
- }
- }
-#endif
-
-#ifdef HAVE_NFQ_SET_VERDICT_BATCH
- if (runmode_workers) {
- nfq_q->verdict_cache.maxlen = nfq_config.batchcount;
- } else if (nfq_config.batchcount) {
- SCLogError(SC_ERR_INVALID_ARGUMENT, "nfq.batchcount is only valid in workers runmode.");
- }
-#endif
-
- /* set a timeout to the socket so we can check for a signal
- * in case we don't get packets for a longer period. */
- tv.tv_sec = 1;
- tv.tv_usec = 0;
-
- if(setsockopt(nfq_q->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
- SCLogWarning(SC_ERR_NFQ_SETSOCKOPT, "can't set socket timeout: %s", strerror(errno));
- }
-
- SCLogDebug("nfq_q->h %p, nfq_q->nh %p, nfq_q->qh %p, nfq_q->fd %" PRId32 "",
- nfq_q->h, nfq_q->nh, nfq_q->qh, nfq_q->fd);
-#else /* OS_WIN32 */
- NFQMutexInit(nfq_q);
- nfq_q->ovr.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- nfq_q->fd = nfq_fd(nfq_q->h);
- SCLogDebug("nfq_q->h %p, nfq_q->qh %p, nfq_q->fd %p", nfq_q->h, nfq_q->qh, nfq_q->fd);
-#endif /* OS_WIN32 */
-
- return TM_ECODE_OK;
-}
-
-TmEcode ReceiveNFQThreadInit(ThreadVars *tv, void *initdata, void **data)
-{
- SCMutexLock(&nfq_init_lock);
-
-#ifndef OS_WIN32
- sigset_t sigs;
- sigfillset(&sigs);
- pthread_sigmask(SIG_BLOCK, &sigs, NULL);
-#endif /* OS_WIN32 */
-
- NFQThreadVars *ntv = (NFQThreadVars *) initdata;
- /* store the ThreadVars pointer in our NFQ thread context
- * as we will need it in our callback function */
- ntv->tv = tv;
-
- int r = NFQInitThread(ntv, (max_pending_packets * NFQ_BURST_FACTOR));
- if (r < 0) {
- SCLogError(SC_ERR_NFQ_THREAD_INIT, "nfq thread failed to initialize");
-
- SCMutexUnlock(&nfq_init_lock);
- exit(EXIT_FAILURE);
- }
-
-#define T_DATA_SIZE 70000
- ntv->data = SCMalloc(T_DATA_SIZE);
- if (ntv->data == NULL) {
- SCMutexUnlock(&nfq_init_lock);
- return TM_ECODE_FAILED;
- }
- ntv->datalen = T_DATA_SIZE;
-#undef T_DATA_SIZE
-
- *data = (void *)ntv;
-
- SCMutexUnlock(&nfq_init_lock);
- return TM_ECODE_OK;
-}
-
-
-TmEcode ReceiveNFQThreadDeinit(ThreadVars *t, void *data)
-{
- NFQThreadVars *ntv = (NFQThreadVars *)data;
- NFQQueueVars *nq = NFQGetQueue(ntv->nfq_index);
-
- if (ntv->data != NULL) {
- SCFree(ntv->data);
- ntv->data = NULL;
- }
- ntv->datalen = 0;
-
- NFQMutexLock(nq);
- SCLogDebug("starting... will close queuenum %" PRIu32 "", nq->queue_num);
- if (nq->qh) {
- nfq_destroy_queue(nq->qh);
- nq->qh = NULL;
- }
- NFQMutexUnlock(nq);
-
- return TM_ECODE_OK;
-}
-
-
-TmEcode VerdictNFQThreadInit(ThreadVars *tv, void *initdata, void **data)
-{
- NFQThreadVars *ntv = (NFQThreadVars *) initdata;
-
- CaptureStatsSetup(tv, &ntv->stats);
-
- *data = (void *)ntv;
- return TM_ECODE_OK;
-}
-
-TmEcode VerdictNFQThreadDeinit(ThreadVars *tv, void *data)
-{
- NFQThreadVars *ntv = (NFQThreadVars *)data;
- NFQQueueVars *nq = NFQGetQueue(ntv->nfq_index);
-
- SCLogDebug("starting... will close queuenum %" PRIu32 "", nq->queue_num);
- NFQMutexLock(nq);
- if (nq->qh) {
- nfq_destroy_queue(nq->qh);
- nq->qh = NULL;
- }
- NFQMutexUnlock(nq);
-
- return TM_ECODE_OK;
-}
-
-/**
- * \brief Add a Netfilter queue
- *
- * \param string with the queue name
- *
- * \retval 0 on success.
- * \retval -1 on failure.
- */
-int NFQRegisterQueue(char *queue)
-{
- NFQThreadVars *ntv = NULL;
- NFQQueueVars *nq = NULL;
- /* Extract the queue number from the specified command line argument */
- uint16_t queue_num = 0;
- if ((ByteExtractStringUint16(&queue_num, 10, strlen(queue), queue)) < 0)
- {
- SCLogError(SC_ERR_INVALID_ARGUMENT, "specified queue number %s is not "
- "valid", queue);
- return -1;
- }
-
- SCMutexLock(&nfq_init_lock);
- if (receive_queue_num >= NFQ_MAX_QUEUE) {
- SCLogError(SC_ERR_INVALID_ARGUMENT,
- "too much Netfilter queue registered (%d)",
- receive_queue_num);
- SCMutexUnlock(&nfq_init_lock);
- return -1;
- }
- if (receive_queue_num == 0) {
- memset(&nfq_t, 0, sizeof(nfq_t));
- memset(&nfq_q, 0, sizeof(nfq_q));
- }
-
- ntv = &nfq_t[receive_queue_num];
- ntv->nfq_index = receive_queue_num;
-
- nq = &nfq_q[receive_queue_num];
- nq->queue_num = queue_num;
- receive_queue_num++;
- SCMutexUnlock(&nfq_init_lock);
- LiveRegisterDevice(queue);
-
- SCLogDebug("Queue \"%s\" registered.", queue);
- return 0;
-}
-
-
-
-/**
- * \brief Get a pointer to the NFQ queue at index
- *
- * \param number idx of the queue in our array
- *
- * \retval ptr pointer to the NFQThreadVars at index
- * \retval NULL on error
- */
-void *NFQGetQueue(int number)
-{
- if (number >= receive_queue_num)
- return NULL;
-
- return (void *)&nfq_q[number];
-}
-
-/**
- * \brief Get a pointer to the NFQ thread at index
- *
- * This function is temporary used as configuration parser.
- *
- * \param number idx of the queue in our array
- *
- * \retval ptr pointer to the NFQThreadVars at index
- * \retval NULL on error
- */
-void *NFQGetThread(int number)
-{
- if (number >= receive_queue_num)
- return NULL;
-
- return (void *)&nfq_t[number];
-}
-
-/**
- * \brief NFQ function to get a packet from the kernel
- *
- * \note separate functions for Linux and Win32 for readability.
- */
-#ifndef OS_WIN32
-void NFQRecvPkt(NFQQueueVars *t, NFQThreadVars *tv)
-{
- int rv, ret;
- int flag = NFQVerdictCacheLen(t) ? MSG_DONTWAIT : 0;
-
- /* XXX what happens on rv == 0? */
- rv = recv(t->fd, tv->data, tv->datalen, flag);
-
- if (rv < 0) {
- if (errno == EINTR || errno == EWOULDBLOCK) {
- /* no error on timeout */
- if (flag)
- NFQVerdictCacheFlush(t);
- } else {
-#ifdef COUNTERS
- NFQMutexLock(t);
- t->errs++;
- NFQMutexUnlock(t);
-#endif /* COUNTERS */
- }
- } else if(rv == 0) {
- SCLogWarning(SC_ERR_NFQ_RECV, "recv got returncode 0");
- } else {
-#ifdef DBG_PERF
- if (rv > t->dbg_maxreadsize)
- t->dbg_maxreadsize = rv;
-#endif /* DBG_PERF */
-
- //printf("NFQRecvPkt: t %p, rv = %" PRId32 "\n", t, rv);
-
- NFQMutexLock(t);
- if (t->qh != NULL) {
- ret = nfq_handle_packet(t->h, tv->data, rv);
- } else {
- SCLogWarning(SC_ERR_NFQ_HANDLE_PKT, "NFQ handle has been destroyed");
- ret = -1;
- }
- NFQMutexUnlock(t);
-
- if (ret != 0) {
- SCLogWarning(SC_ERR_NFQ_HANDLE_PKT, "nfq_handle_packet error %" PRId32 "", ret);
- }
- }
-}
-#else /* WIN32 version of NFQRecvPkt */
-void NFQRecvPkt(NFQQueueVars *t, NFQThreadVars *tv)
-{
- int rv, ret;
- static int timeouted = 0;
-
- if (timeouted) {
- if (WaitForSingleObject(t->ovr.hEvent, 1000) == WAIT_TIMEOUT) {
- rv = -1;
- errno = EINTR;
- goto process_rv;
- }
- timeouted = 0;
- }
-
-read_packet_again:
-
- if (!ReadFile(t->fd, tv->buf, sizeof(tv->buf), (DWORD*)&rv, &t->ovr)) {
- if (GetLastError() != ERROR_IO_PENDING) {
- rv = -1;
- errno = EIO;
- } else {
- if (WaitForSingleObject(t->ovr.hEvent, 1000) == WAIT_TIMEOUT) {
- rv = -1;
- errno = EINTR;
- timeouted = 1;
- } else {
- /* We needn't to call GetOverlappedResult() because it always
- * fail with our error code ERROR_MORE_DATA. */
- goto read_packet_again;
- }
- }
- }
-
-process_rv:
-
- if (rv < 0) {
- if (errno == EINTR) {
- /* no error on timeout */
- } else {
-#ifdef COUNTERS
- t->errs++;
-#endif /* COUNTERS */
- }
- } else if(rv == 0) {
- SCLogWarning(SC_ERR_NFQ_RECV, "recv got returncode 0");
- } else {
-#ifdef DBG_PERF
- if (rv > t->dbg_maxreadsize)
- t->dbg_maxreadsize = rv;
-#endif /* DBG_PERF */
-
- //printf("NFQRecvPkt: t %p, rv = %" PRId32 "\n", t, rv);
-
- NFQMutexLock(t);
- if (t->qh) {
- ret = nfq_handle_packet(t->h, buf, rv);
- } else {
- SCLogWarning(SC_ERR_NFQ_HANDLE_PKT, "NFQ handle has been destroyed");
- ret = -1;
- }
- NFQMutexUnlock(t);
-
- if (ret != 0) {
- SCLogWarning(SC_ERR_NFQ_HANDLE_PKT, "nfq_handle_packet error %" PRId32 "", ret);
- }
- }
-}
-#endif /* OS_WIN32 */
-
-/**
- * \brief Main NFQ reading Loop function
- */
-TmEcode ReceiveNFQLoop(ThreadVars *tv, void *data, void *slot)
-{
- SCEnter();
- NFQThreadVars *ntv = (NFQThreadVars *)data;
- NFQQueueVars *nq = NFQGetQueue(ntv->nfq_index);
-
- ntv->slot = ((TmSlot *) slot)->slot_next;
-
- while(1) {
- if (suricata_ctl_flags != 0) {
- NFQMutexLock(nq);
- if (nq->qh) {
- nfq_destroy_queue(nq->qh);
- nq->qh = NULL;
- }
- NFQMutexUnlock(nq);
- break;
- }
- NFQRecvPkt(nq, ntv);
-
- StatsSyncCountersIfSignalled(tv);
- }
- SCReturnInt(TM_ECODE_OK);
-}
-
-/**
- * \brief NFQ receive module stats printing function
- */
-void ReceiveNFQThreadExitStats(ThreadVars *tv, void *data)
-{
- NFQThreadVars *ntv = (NFQThreadVars *)data;
- NFQQueueVars *nq = NFQGetQueue(ntv->nfq_index);
-#ifdef COUNTERS
- SCLogNotice("(%s) Treated: Pkts %" PRIu32 ", Bytes %" PRIu64 ", Errors %" PRIu32 "",
- tv->name, nq->pkts, nq->bytes, nq->errs);
- SCLogNotice("(%s) Verdict: Accepted %"PRIu32", Dropped %"PRIu32", Replaced %"PRIu32,
- tv->name, nq->accepted, nq->dropped, nq->replaced);
-#endif
-}
-
-/**
- * \brief NFQ verdict function
- */
-TmEcode NFQSetVerdict(Packet *p)
-{
- int iter = 0;
- int ret = 0;
- uint32_t verdict = NF_ACCEPT;
- /* we could also have a direct pointer but we need to have a ref counf in this case */
- NFQQueueVars *t = nfq_q + p->nfq_v.nfq_index;
-
- /** \todo add a test on validity of the entry NFQQueueVars could have been
- * wipeout
- */
-
- p->nfq_v.verdicted = 1;
-
- /* can't verdict a "fake" packet */
- if (p->flags & PKT_PSEUDO_STREAM_END) {
- return TM_ECODE_OK;
- }
-
- //printf("%p verdicting on queue %" PRIu32 "\n", t, t->queue_num);
- NFQMutexLock(t);
-
- if (t->qh == NULL) {
- /* Somebody has started a clean-up, we leave */
- NFQMutexUnlock(t);
- return TM_ECODE_OK;
- }
-
- if (PACKET_TEST_ACTION(p, ACTION_DROP)) {
- verdict = NF_DROP;
-#ifdef COUNTERS
- t->dropped++;
-#endif /* COUNTERS */
- } else {
- switch (nfq_config.mode) {
- default:
- case NFQ_ACCEPT_MODE:
- verdict = NF_ACCEPT;
- break;
- case NFQ_REPEAT_MODE:
- verdict = NF_REPEAT;
- break;
- case NFQ_ROUTE_MODE:
- verdict = ((uint32_t) NF_QUEUE) | nfq_config.next_queue;
- break;
- }
-
- if (p->flags & PKT_STREAM_MODIFIED) {
-#ifdef COUNTERS
- t->replaced++;
-#endif /* COUNTERS */
- }
-
-#ifdef COUNTERS
- t->accepted++;
-#endif /* COUNTERS */
- }
-
- ret = NFQVerdictCacheAdd(t, p, verdict);
- if (ret == 0) {
- NFQMutexUnlock(t);
- return TM_ECODE_OK;
- }
-
- do {
- switch (nfq_config.mode) {
- default:
- case NFQ_ACCEPT_MODE:
- case NFQ_ROUTE_MODE:
- if (p->flags & PKT_MARK_MODIFIED) {
-#ifdef HAVE_NFQ_SET_VERDICT2
- if (p->flags & PKT_STREAM_MODIFIED) {
- ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict,
- p->nfq_v.mark,
- GET_PKT_LEN(p), GET_PKT_DATA(p));
- } else {
- ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict,
- p->nfq_v.mark,
- 0, NULL);
- }
-#else /* fall back to old function */
- if (p->flags & PKT_STREAM_MODIFIED) {
- ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict,
- htonl(p->nfq_v.mark),
- GET_PKT_LEN(p), GET_PKT_DATA(p));
- } else {
- ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict,
- htonl(p->nfq_v.mark),
- 0, NULL);
- }
-#endif /* HAVE_NFQ_SET_VERDICT2 */
- } else {
- if (p->flags & PKT_STREAM_MODIFIED) {
- ret = nfq_set_verdict(t->qh, p->nfq_v.id, verdict,
- GET_PKT_LEN(p), GET_PKT_DATA(p));
- } else {
- ret = nfq_set_verdict(t->qh, p->nfq_v.id, verdict, 0, NULL);
- }
-
- }
- break;
- case NFQ_REPEAT_MODE:
-#ifdef HAVE_NFQ_SET_VERDICT2
- if (p->flags & PKT_STREAM_MODIFIED) {
- ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict,
- (nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask),
- GET_PKT_LEN(p), GET_PKT_DATA(p));
- } else {
- ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict,
- (nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask),
- 0, NULL);
- }
-#else /* fall back to old function */
- if (p->flags & PKT_STREAM_MODIFIED) {
- ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict,
- htonl((nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask)),
- GET_PKT_LEN(p), GET_PKT_DATA(p));
- } else {
- ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict,
- htonl((nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask)),
- 0, NULL);
- }
-#endif /* HAVE_NFQ_SET_VERDICT2 */
- break;
- }
- } while ((ret < 0) && (iter++ < NFQ_VERDICT_RETRY_TIME));
-
- NFQMutexUnlock(t);
-
- if (ret < 0) {
- SCLogWarning(SC_ERR_NFQ_SET_VERDICT,
- "nfq_set_verdict of %p failed %" PRId32 ": %s",
- p, ret, strerror(errno));
- return TM_ECODE_FAILED;
- }
- return TM_ECODE_OK;
-}
-
-/**
- * \brief NFQ verdict module packet entry function
- */
-TmEcode VerdictNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq)
-{
- NFQThreadVars *ntv = (NFQThreadVars *)data;
- /* update counters */
- CaptureStatsUpdate(tv, &ntv->stats, p);
-
- int ret;
- /* if this is a tunnel packet we check if we are ready to verdict
- * already. */
- if (IS_TUNNEL_PKT(p)) {
- char verdict = 1;
- //printf("VerdictNFQ: tunnel pkt: %p %s\n", p, p->root ? "upper layer" : "root");
-
- SCMutex *m = p->root ? &p->root->tunnel_mutex : &p->tunnel_mutex;
- SCMutexLock(m);
-
- /* if there are more tunnel packets than ready to verdict packets,
- * we won't verdict this one */
- if (TUNNEL_PKT_TPR(p) > TUNNEL_PKT_RTV(p)) {
- SCLogDebug("not ready to verdict yet: TUNNEL_PKT_TPR(p) > "
- "TUNNEL_PKT_RTV(p) = %" PRId32 " > %" PRId32,
- TUNNEL_PKT_TPR(p), TUNNEL_PKT_RTV(p));
- verdict = 0;
- }
-
- SCMutexUnlock(m);
-
- /* don't verdict if we are not ready */
- if (verdict == 1) {
- //printf("VerdictNFQ: setting verdict\n");
- ret = NFQSetVerdict(p->root ? p->root : p);
- if (ret != TM_ECODE_OK)
- return ret;
- } else {
- TUNNEL_INCR_PKT_RTV(p);
- }
- } else {
- /* no tunnel, verdict normally */
- ret = NFQSetVerdict(p);
- if (ret != TM_ECODE_OK)
- return ret;
- }
- return TM_ECODE_OK;
-}
-
-/**
- * \brief Decode a packet coming from NFQ
- */
-TmEcode DecodeNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq)
-{
-
- IPV4Hdr *ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
- IPV6Hdr *ip6h = (IPV6Hdr *)GET_PKT_DATA(p);
- DecodeThreadVars *dtv = (DecodeThreadVars *)data;
-
- /* XXX HACK: flow timeout can call us for injected pseudo packets
- * see bug: https://redmine.openinfosecfoundation.org/issues/1107 */
- if (p->flags & PKT_PSEUDO_STREAM_END)
- return TM_ECODE_OK;
-
- DecodeUpdatePacketCounters(tv, dtv, p);
-
- if (IPV4_GET_RAW_VER(ip4h) == 4) {
- SCLogDebug("IPv4 packet");
- DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq);
- } else if(IPV6_GET_RAW_VER(ip6h) == 6) {
- SCLogDebug("IPv6 packet");
- DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq);
- } else {
- SCLogDebug("packet unsupported by NFQ, first byte: %02x", *GET_PKT_DATA(p));
- }
-
- PacketDecodeFinalize(tv, dtv, p);
-
- return TM_ECODE_OK;
-}
-
-/**
- * \brief Initialize the NFQ Decode threadvars
- */
-TmEcode DecodeNFQThreadInit(ThreadVars *tv, void *initdata, void **data)
-{
- DecodeThreadVars *dtv = NULL;
- dtv = DecodeThreadVarsAlloc(tv);
-
- if (dtv == NULL)
- SCReturnInt(TM_ECODE_FAILED);
-
- DecodeRegisterPerfCounters(dtv, tv);
-
- *data = (void *)dtv;
-
- return TM_ECODE_OK;
-}
-
-TmEcode DecodeNFQThreadDeinit(ThreadVars *tv, void *data)
-{
- if (data != NULL)
- DecodeThreadVarsFree(tv, data);
- SCReturnInt(TM_ECODE_OK);
-}
-
-#endif /* NFQ */
-