diff --git a/configure.in b/configure.in index 3700df6adf84..4ec3575a3f99 100644 --- a/configure.in +++ b/configure.in @@ -553,6 +553,7 @@ AC_INIT(configure.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]) + AC_CHECK_LIB([netfilter_queue], [nfq_set_queue_flags],AC_DEFINE_UNQUOTED([HAVE_NFQ_SET_QUEUE_FLAGS],[1],[Found nfq_set_queue_flags function in netfilter_queue]) ,,[-lnfnetlink]) # check if the argument to nfq_get_payload is signed or unsigned AC_MSG_CHECKING([for signed nfq_get_payload payload argument]) diff --git a/src/source-nfq.c b/src/source-nfq.c index 9b3018acb6d9..78a8893d0590 100644 --- a/src/source-nfq.c +++ b/src/source-nfq.c @@ -156,11 +156,14 @@ typedef enum NFQMode_ { 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; } NFQCnf; NFQCnf nfq_config; @@ -208,6 +211,7 @@ void NFQInitConfig(char quiet) { intmax_t value = 0; char* nfq_mode = NULL; + int boolval; SCLogDebug("Initializing NFQ"); @@ -228,6 +232,17 @@ void NFQInitConfig(char quiet) } } + (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.fail-open set but NFQ library has no support for it."); +#endif + } + if ((ConfGetInt("nfq.repeat-mark", &value)) == 1) { nfq_config.mark = (uint32_t)value; } @@ -497,6 +512,21 @@ TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) setsockopt(nfq_q->fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(int)); #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 + /* 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; diff --git a/suricata.yaml.in b/suricata.yaml.in index 4d3261b20685..065a0f333844 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -189,11 +189,14 @@ magic-file: @e_magic_file@ # 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. +# On linux >= 3.6, you can set the fail-open option to yes to have the kernel +# accept the packet if suricata is not able to keep pace. nfq: # mode: accept # repeat-mark: 1 # repeat-mask: 1 # route-queue: 2 +# fail-open: yes # af-packet support # Set threads to > 1 to use PACKET_FANOUT support