[Oisf-devel] [PATCH 2/2] source-nfq: add simulated non-terminal NFQUEUE verdict

Eric Leblond eric at regit.org
Sun Jan 16 16:18:38 UTC 2011


This patch adds a new mode for NFQ inline mode. The idea is to
simulate a non final NFQUEUE rules.
This permit to do send all needed packets to suricata via a simple
FORWARD rule:
    iptables -I FORWARD -m mark ! --mark $MARK/$MASK -j NFQUEUE
And below, we have a standard filtering ruleset.

To do so, suricata issues a NF_REPEAT instead of a NF_ACCEPT verdict and
put a mark ($MARK) with respect to a mask ($MASK) on the handled packet.

NF_REPEAT verdict has for effect to have the packet reinjected at start
of the hook after the verdict. As it has been marked by suricata during
the verdict it will not rematch the initial rules and make his way to
the following classical ruleset.

Mode, mark and mask can be configured via suricata.yaml file with the
following syntax:
   nfq:
     repeat_mode: (false|true)
     mark: $MARK
     mask: $MASK
Default is false to preserve backward compatibility.

Signed-off-by: Eric Leblond <eric at regit.org>
---
 configure.in     |    1 +
 src/source-nfq.c |   65 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/source-nfq.h |    1 +
 src/suricata.c   |    3 ++
 suricata.yaml    |   10 ++++++++
 5 files changed, 78 insertions(+), 2 deletions(-)

diff --git a/configure.in b/configure.in
index 8277773..d42a6f7 100644
--- a/configure.in
+++ b/configure.in
@@ -413,6 +413,7 @@ case $host in
 *)
     AC_CHECK_LIB(netfilter_queue, nfq_open,, NFQ="no",)
     AC_CHECK_LIB([netfilter_queue], [nfq_set_queue_maxlen],AC_DEFINE_UNQUOTED([HAVE_NFQ_MAXLEN],[1],[Found queue max length support in netfilter_queue]) ,,[-lnfnetlink])
+    AC_CHECK_LIB([netfilter_queue], [nfq_set_verdict2],AC_DEFINE_UNQUOTED([HAVE_NFQ_SET_VERDICT2],[1],[Found nfq_set_verdict2 function in netfilter_queue]) ,,[-lnfnetlink])
 
 
 ;;
diff --git a/src/source-nfq.c b/src/source-nfq.c
index 977dd01..ead99d3 100644
--- a/src/source-nfq.c
+++ b/src/source-nfq.c
@@ -32,6 +32,8 @@
 #include "decode.h"
 #include "packet-queue.h"
 #include "threads.h"
+#include "conf.h"
+#include "conf-yaml-loader.h"
 #include "threadvars.h"
 #include "tm-queuehandlers.h"
 #include "tm-modules.h"
@@ -122,6 +124,14 @@ TmEcode VerdictNFQThreadDeinit(ThreadVars *, void *);
 TmEcode DecodeNFQ(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
 TmEcode DecodeNFQThreadInit(ThreadVars *, void *, void **);
 
+typedef struct NFQCnf_ {
+    int repeat_mode;
+    uint32_t mark;
+    uint32_t mask;
+} NFQCnf;
+
+NFQCnf nfq_config;
+
 void TmModuleReceiveNFQRegister (void) {
     /* XXX create a general NFQ setup function */
     memset(&nfq_g, 0, sizeof(nfq_g));
@@ -153,6 +163,41 @@ void TmModuleDecodeNFQRegister (void) {
     tmm_modules[TMM_DECODENFQ].RegisterTests = NULL;
 }
 
+/** \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;
+
+    SCLogDebug("Initializing NFQ");
+
+    memset(&nfq_config,  0, sizeof(nfq_config));
+    if ((ConfGetBool("nfq.repeat_mode", &nfq_config.repeat_mode)) == 0) {
+        nfq_config.repeat_mode = FALSE;
+    }
+
+    if ((ConfGetInt("nfq.mark", &value)) == 1) {
+        nfq_config.mark = (uint32_t)value;
+    }
+
+    if ((ConfGetInt("nfq.mask", &value)) == 1) {
+        nfq_config.mask = (uint32_t)value;
+    }
+
+    if (!quiet) {
+        if (nfq_config.repeat_mode == TRUE) {
+            SCLogInfo("NFQ running in REPEAT mode with mark %"PRIu32"/%"PRIu32,
+                    nfq_config.mark, nfq_config.mask);
+        } else {
+            SCLogInfo("NFQ running in standard ACCEPT/DROP mode");
+        }
+    }
+
+}
+
 void NFQSetupPkt (Packet *p, void *data)
 {
     struct nfq_data *tb = (struct nfq_data *)data;
@@ -656,13 +701,29 @@ void NFQSetVerdict(Packet *p) {
         t->dropped++;
 #endif /* COUNTERS */
     } else {
-        verdict = NF_ACCEPT;
+        if (nfq_config.repeat_mode == FALSE) {
+            verdict = NF_ACCEPT;
+        } else {
+            verdict = NF_REPEAT;
+        }
 #ifdef COUNTERS
         t->accepted++;
 #endif /* COUNTERS */
     }
 
-    ret = nfq_set_verdict(t->qh, p->nfq_v.id, verdict, 0, NULL);
+    if (nfq_config.repeat_mode == FALSE) {
+        ret = nfq_set_verdict(t->qh, p->nfq_v.id, verdict, 0, NULL);
+    } else {
+#ifdef HAVE_NFQ_SET_VERDICT2
+        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 */
+        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
+    }
     SCMutexUnlock(&t->mutex_qh);
 
     if (ret < 0) {
diff --git a/src/source-nfq.h b/src/source-nfq.h
index 354a0c7..02f1e1c 100644
--- a/src/source-nfq.h
+++ b/src/source-nfq.h
@@ -95,6 +95,7 @@ typedef struct NFQGlobalVars_
     char unbind;
 } NFQGlobalVars;
 
+void NFQInitConfig(char quiet);
 int NFQRegisterQueue(char *queue);
 int NFQGetQueueCount(void);
 void *NFQGetQueue(int number);
diff --git a/src/suricata.c b/src/suricata.c
index 2588c1c..28656af 100644
--- a/src/suricata.c
+++ b/src/suricata.c
@@ -836,6 +836,9 @@ int main(int argc, char **argv)
     }
     SCLogDebug("Default packet size set to %"PRIiMAX, default_packet_size);
 
+    if (run_mode == MODE_NFQ)
+        NFQInitConfig(FALSE);
+
     /* Since our config is now loaded we can finish configurating the
      * logging module. */
     SCLogLoadConfig();
diff --git a/suricata.yaml b/suricata.yaml
index 08c91ac..55f3b1e 100644
--- a/suricata.yaml
+++ b/suricata.yaml
@@ -96,6 +96,16 @@ outputs:
       filename: stats.log
       interval: 8
 
+# When running in NFQ inline mode, it is possible to use a simulated
+# non-terminal NFQUEUE verdict.
+# This permit to do send all needed packet to suricata via this a rule:
+#        iptables -I FORWARD -m mark ! --mark $MARK/$MASK -j NFQUEUE
+# And below, you can have your standard filtering ruleset.
+nfq:
+#  repeat_mode: true
+#  mark: 1
+#  mask: 1
+
 defrag:
   max-frags: 65535
   prealloc: yes
-- 
1.7.2.3




More information about the Oisf-devel mailing list