source-nfq: improve nfq option system

This patch modifies the NFQ option system to avoid implicit
choice. 'nfq.mode' is now a string which can take a value
in the 'accept', 'repeat' and 'route' set.

Signed-off-by: Eric Leblond <eric@regit.org>
remotes/origin/master-1.1.x
Eric Leblond 16 years ago committed by Victor Julien
parent 94596ff282
commit c74116949c

@ -33,6 +33,7 @@
#include "packet-queue.h" #include "packet-queue.h"
#include "threads.h" #include "threads.h"
#include "conf.h" #include "conf.h"
#include "config.h"
#include "conf-yaml-loader.h" #include "conf-yaml-loader.h"
#include "threadvars.h" #include "threadvars.h"
#include "tm-queuehandlers.h" #include "tm-queuehandlers.h"
@ -127,8 +128,14 @@ TmEcode VerdictNFQThreadDeinit(ThreadVars *, void *);
TmEcode DecodeNFQ(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); TmEcode DecodeNFQ(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
TmEcode DecodeNFQThreadInit(ThreadVars *, void *, void **); TmEcode DecodeNFQThreadInit(ThreadVars *, void *, void **);
typedef enum NFQMode_ {
NFQ_ACCEPT_MODE,
NFQ_REPEAT_MODE,
NFQ_ROUTE_MODE,
} NFQMode;
typedef struct NFQCnf_ { typedef struct NFQCnf_ {
int repeat_mode; NFQMode mode;
uint32_t mark; uint32_t mark;
uint32_t mask; uint32_t mask;
uint32_t next_queue; uint32_t next_queue;
@ -175,32 +182,52 @@ void TmModuleDecodeNFQRegister (void) {
void NFQInitConfig(char quiet) void NFQInitConfig(char quiet)
{ {
intmax_t value = 0; intmax_t value = 0;
char* nfq_mode = NULL;
SCLogDebug("Initializing NFQ"); SCLogDebug("Initializing NFQ");
memset(&nfq_config, 0, sizeof(nfq_config)); memset(&nfq_config, 0, sizeof(nfq_config));
if ((ConfGetBool("nfq.repeat_mode", &nfq_config.repeat_mode)) == 0) {
nfq_config.repeat_mode = FALSE; 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_LOG_ERROR, "Unknown nfq.mode");
exit(EXIT_FAILURE);
}
} }
if ((ConfGetInt("nfq.mark", &value)) == 1) { if ((ConfGetInt("nfq.repeat_mark", &value)) == 1) {
nfq_config.mark = (uint32_t)value; nfq_config.mark = (uint32_t)value;
} }
if ((ConfGetInt("nfq.mask", &value)) == 1) { if ((ConfGetInt("nfq.repeat_mask", &value)) == 1) {
nfq_config.mask = (uint32_t)value; nfq_config.mask = (uint32_t)value;
} }
if ((ConfGetInt("nfq.next_queue", &value)) == 1) { if ((ConfGetInt("nfq.route_queue", &value)) == 1) {
nfq_config.next_queue = ((uint32_t)value) << 16; nfq_config.next_queue = ((uint32_t)value) << 16;
} }
if (!quiet) { if (!quiet) {
if (nfq_config.repeat_mode == TRUE) { switch (nfq_config.mode) {
SCLogInfo("NFQ running in REPEAT mode with mark %"PRIu32"/%"PRIu32, case NFQ_ACCEPT_MODE:
nfq_config.mark, nfq_config.mask); SCLogInfo("NFQ running in standard ACCEPT/DROP mode");
} else { break;
SCLogInfo("NFQ running in standard ACCEPT/DROP mode"); 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);
break;
} }
} }
@ -220,7 +247,7 @@ int NFQSetupPkt (Packet *p, struct nfq_q_handle *qh, void *data)
p->nfq_v.hw_protocol = ph->hw_protocol; p->nfq_v.hw_protocol = ph->hw_protocol;
} }
p->nfq_v.mark = nfq_get_nfmark(tb); p->nfq_v.mark = nfq_get_nfmark(tb);
if (nfq_config.repeat_mode == TRUE) { if (nfq_config.mode == NFQ_REPEAT_MODE) {
if ((nfq_config.mark & nfq_config.mask) == if ((nfq_config.mark & nfq_config.mask) ==
(p->nfq_v.mark & nfq_config.mask)) { (p->nfq_v.mark & nfq_config.mask)) {
if (already_seen_warning < MAX_ALREADY_TREATED) if (already_seen_warning < MAX_ALREADY_TREATED)
@ -286,7 +313,7 @@ static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
nfq_q->bytes += GET_PKT_LEN(p); nfq_q->bytes += GET_PKT_LEN(p);
#endif /* COUNTERS */ #endif /* COUNTERS */
/* recycle Packet and leave */ /* recycle Packet and leave */
PACKET_RECYCLE(p); TmqhOutputPacketpool(tv, p);
return 0; return 0;
} }
@ -715,8 +742,8 @@ void ReceiveNFQThreadExitStats(ThreadVars *tv, void *data) {
* \brief NFQ verdict function * \brief NFQ verdict function
*/ */
void NFQSetVerdict(Packet *p) { void NFQSetVerdict(Packet *p) {
int ret; int ret = 0;
uint32_t verdict; uint32_t verdict = NF_ACCEPT;
NFQQueueVars *t = nfq_q + p->nfq_v.nfq_index; NFQQueueVars *t = nfq_q + p->nfq_v.nfq_index;
//printf("%p verdicting on queue %" PRIu32 "\n", t, t->queue_num); //printf("%p verdicting on queue %" PRIu32 "\n", t, t->queue_num);
@ -729,52 +756,62 @@ void NFQSetVerdict(Packet *p) {
t->dropped++; t->dropped++;
#endif /* COUNTERS */ #endif /* COUNTERS */
} else { } else {
if (nfq_config.repeat_mode == FALSE) { switch (nfq_config.mode) {
if (nfq_config.next_queue) { case NFQ_ACCEPT_MODE:
verdict = ((uint32_t) NF_QUEUE) | nfq_config.next_queue;
} else {
verdict = NF_ACCEPT; verdict = NF_ACCEPT;
} break;
} else { case NFQ_REPEAT_MODE:
verdict = NF_REPEAT; verdict = NF_REPEAT;
break;
case NFQ_ROUTE_MODE:
verdict = ((uint32_t) NF_QUEUE) | nfq_config.next_queue;
break;
} }
#ifdef COUNTERS #ifdef COUNTERS
t->accepted++; t->accepted++;
#endif /* COUNTERS */ #endif /* COUNTERS */
} }
SCMutexLock(&t->mutex_qh); switch (nfq_config.mode) {
if (nfq_config.repeat_mode == FALSE) { case NFQ_ACCEPT_MODE:
if (p->flags & PKT_STREAM_MODIFIED) { case NFQ_ROUTE_MODE:
ret = nfq_set_verdict(t->qh, p->nfq_v.id, verdict, GET_PKT_LEN(p), GET_PKT_DATA(p)); 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 #ifdef COUNTERS
t->replaced++; t->replaced++;
#endif /* COUNTERS */ #endif /* COUNTERS */
} else { } else {
ret = nfq_set_verdict(t->qh, p->nfq_v.id, verdict, 0, NULL); ret = nfq_set_verdict(t->qh, p->nfq_v.id, verdict, 0, NULL);
} }
} else { break;
case NFQ_REPEAT_MODE:
#ifdef HAVE_NFQ_SET_VERDICT2 #ifdef HAVE_NFQ_SET_VERDICT2
if (p->flags & PKT_STREAM_MODIFIED) { if (p->flags & PKT_STREAM_MODIFIED) {
ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict, ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict,
(nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask), (nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask),
GET_PKT_LEN(p), GET_PKT_DATA(p)); GET_PKT_LEN(p), GET_PKT_DATA(p));
} else { #ifdef COUNTERS
ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict, t->replaced++;
(nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask), #endif /* COUNTERS */
0, NULL); } 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 */ #else /* fall back to old function */
if (p->flags & PKT_STREAM_MODIFIED) { if (p->flags & PKT_STREAM_MODIFIED) {
ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict, 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)), htonl((nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask)),
GET_PKT_LEN(p), GET_PKT_DATA(p)); GET_PKT_LEN(p), GET_PKT_DATA(p));
} else { #ifdef COUNTERS
ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict, t->replaced++;
htonl((nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask)), #endif /* COUNTERS */
0, NULL); } else {
} ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict,
#endif htonl((nfq_config.mark & nfq_config.mask) | (p->nfq_v.mark & ~nfq_config.mask)),
0, NULL);
}
#endif /* HAVE_NFQ_SET_VERDICT2 */
} }
SCMutexUnlock(&t->mutex_qh); SCMutexUnlock(&t->mutex_qh);

@ -100,11 +100,15 @@ outputs:
# non-terminal NFQUEUE verdict. # non-terminal NFQUEUE verdict.
# This permit to do send all needed packet to suricata via this a rule: # This permit to do send all needed packet to suricata via this a rule:
# iptables -I FORWARD -m mark ! --mark $MARK/$MASK -j NFQUEUE # iptables -I FORWARD -m mark ! --mark $MARK/$MASK -j NFQUEUE
# And below, you can have your standard filtering ruleset. # And below, you can have your standard filtering ruleset. To activate
# this mode, you need to set mode to 'repeat'
# If you want packet to be sent to another queue after an ACCEPT decision
# set mode to 'route' and set next_queue value.
nfq: nfq:
# repeat_mode: true # mode: accept
# mark: 1 # repeat_mark: 1
# mask: 1 # repeat_mask: 1
# route_queue: 2
defrag: defrag:
max-frags: 65535 max-frags: 65535

Loading…
Cancel
Save