source-nfq: add simulated non-terminal NFQUEUE verdict

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@regit.org>
remotes/origin/master-1.1.x
Eric Leblond 14 years ago committed by Victor Julien
parent 72ec56ab23
commit 1e600c1054

@ -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])
;;

@ -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,20 +701,48 @@ 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 */
}
SCMutexLock(&t->mutex_qh);
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));
if (nfq_config.repeat_mode == FALSE) {
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));
#ifdef COUNTERS
t->replaced++;
t->replaced++;
#endif /* COUNTERS */
} else {
ret = nfq_set_verdict(t->qh, p->nfq_v.id, verdict, 0, NULL);
}
} else {
ret = nfq_set_verdict(t->qh, p->nfq_v.id, verdict, 0, NULL);
#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
}
SCMutexUnlock(&t->mutex_qh);

@ -96,6 +96,7 @@ typedef struct NFQGlobalVars_
char unbind;
} NFQGlobalVars;
void NFQInitConfig(char quiet);
int NFQRegisterQueue(char *queue);
int NFQGetQueueCount(void);
void *NFQGetQueue(int number);

@ -836,6 +836,11 @@ int main(int argc, char **argv)
}
SCLogDebug("Default packet size set to %"PRIiMAX, default_packet_size);
#ifdef NFQ
if (run_mode == MODE_NFQ)
NFQInitConfig(FALSE);
#endif
/* Since our config is now loaded we can finish configurating the
* logging module. */
SCLogLoadConfig();

@ -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

Loading…
Cancel
Save