Go to the documentation of this file.
92 FatalError(
"Error creating thread %s: you do not "
93 "have support for nfqueue enabled please recompile with "
102 #define MAX_ALREADY_TREATED 5
103 #define NFQ_VERDICT_RETRY_COUNT 3
104 static int already_seen_warning;
105 static int runmode_workers;
107 #define NFQ_BURST_FACTOR 4
110 #define SOL_NETLINK 270
129 static uint16_t receive_queue_num = 0;
135 static void ReceiveNFQThreadExitStats(
ThreadVars *,
void *);
145 static TmEcode NFQSetVerdict(
Packet *p,
const uint32_t mark_value,
const bool mark_modified);
146 static void NFQReleasePacket(
Packet *p);
154 #define NFQ_FLAG_FAIL_OPEN (1 << 0)
172 memset(&nfq_g, 0,
sizeof(nfq_g));
209 const char *nfq_mode = NULL;
216 if ((
ConfGet(
"nfq.mode", &nfq_mode)) == 0) {
219 if (!strcmp(
"accept", nfq_mode)) {
221 }
else if (!strcmp(
"repeat", nfq_mode)) {
223 }
else if (!strcmp(
"route", nfq_mode)) {
232 #ifdef HAVE_NFQ_SET_QUEUE_FLAGS
233 SCLogInfo(
"Enabling fail-open on queue");
236 SCLogError(
"nfq.%s set but NFQ library has no support for it.",
"fail-open");
240 if ((
ConfGetInt(
"nfq.repeat-mark", &value)) == 1) {
244 if ((
ConfGetInt(
"nfq.repeat-mask", &value)) == 1) {
248 if ((
ConfGetInt(
"nfq.bypass-mark", &value)) == 1) {
252 if ((
ConfGetInt(
"nfq.bypass-mask", &value)) == 1) {
256 if ((
ConfGetInt(
"nfq.route-queue", &value)) == 1) {
260 if ((
ConfGetInt(
"nfq.batchcount", &value)) == 1) {
261 #ifdef HAVE_NFQ_SET_VERDICT_BATCH
269 SCLogWarning(
"nfq.%s set but NFQ library has no support for it.",
"batchcount");
276 SCLogInfo(
"NFQ running in standard ACCEPT/DROP mode");
279 SCLogInfo(
"NFQ running in REPEAT mode with mark %"PRIu32
"/%"PRIu32,
283 SCLogInfo(
"NFQ running in route mode with next queue %"PRIu32,
293 #ifdef HAVE_NFQ_SET_VERDICT_BATCH
302 #ifdef HAVE_NFQ_SET_VERDICT_BATCH
308 ret = nfq_set_verdict_batch2(t->
qh,
313 ret = nfq_set_verdict_batch(t->
qh,
319 SCLogWarning(
"nfq_set_verdict_batch failed: %s", strerror(errno));
328 const uint32_t mark_value,
const bool mark_modified)
330 #ifdef HAVE_NFQ_SET_VERDICT_BATCH
359 NFQVerdictCacheFlush(t);
365 if (NFQVerdictCacheLen(t) > 0)
366 NFQVerdictCacheFlush(t);
375 if (active_runmode && !strcmp(
"workers", active_runmode)) {
378 SCLogDebug(
"NFQ running in 'workers' runmode, will not use mutex.");
386 #define NFQMutexLock(nq) do { \
387 if ((nq)->use_mutex) \
388 SCMutexLock(&(nq)->mutex_qh); \
391 #define NFQMutexUnlock(nq) do { \
392 if ((nq)->use_mutex) \
393 SCMutexUnlock(&(nq)->mutex_qh); \
403 static int NFQSetupPkt (
Packet *p,
struct nfq_q_handle *qh,
void *data)
405 struct nfq_data *tb = (
struct nfq_data *)data;
408 struct nfqnl_msg_packet_hdr *ph;
414 ph = nfq_get_msg_packet_hdr(tb);
426 SCLogInfo(
"Packet seems already treated by suricata");
427 already_seen_warning++;
429 ret = nfq_set_verdict(qh, p->
nfq_v.
id, NF_ACCEPT, 0, NULL);
433 "nfq_set_verdict of %p failed %" PRId32
": %s", p, ret, strerror(errno));
446 #ifdef NFQ_GET_PAYLOAD_SIGNED
447 ret = nfq_get_payload(tb, &pktdata);
449 ret = nfq_get_payload(tb, (
unsigned char **) &pktdata);
461 }
else if (runmode_workers) {
466 }
else if (ret == -1) {
473 ret = nfq_get_timestamp(tb, &
tv);
474 if (ret != 0 ||
tv.tv_sec == 0) {
475 memset(&
tv, 0,
sizeof(
tv));
476 gettimeofday(&
tv, NULL);
484 static void NFQReleasePacket(
Packet *p)
486 if (PacketIsNotTunnel(p)) {
501 const uint32_t mark_value = root_p->
nfq_v.
mark;
506 NFQSetVerdict(p, mark_value, mark_modified);
518 static int NFQBypassCallback(
Packet *p)
520 if (PacketIsTunnel(p)) {
544 static int NFQCallBack(
struct nfq_q_handle *qh,
struct nfgenmsg *nfmsg,
545 struct nfq_data *nfa,
void *data)
564 ret = NFQSetupPkt(p, qh, (
void *)nfa);
614 SCLogDebug(
"unbinding existing nf_queue handler for AF_INET (if any)");
615 if (nfq_unbind_pf(q->
h, AF_INET) < 0) {
616 FatalError(
"nfq_unbind_pf() for AF_INET failed: %s", strerror(errno));
618 if (nfq_unbind_pf(q->
h, AF_INET6) < 0) {
619 FatalError(
"nfq_unbind_pf() for AF_INET6 failed");
623 SCLogDebug(
"binding nfnetlink_queue as nf_queue handler for AF_INET and AF_INET6");
625 if (nfq_bind_pf(q->
h, AF_INET) < 0) {
626 FatalError(
"nfq_bind_pf() for AF_INET failed");
628 if (nfq_bind_pf(q->
h, AF_INET6) < 0) {
629 FatalError(
"nfq_bind_pf() for AF_INET6 failed");
637 q->
qh = nfq_create_queue(q->
h, q->
queue_num, &NFQCallBack, (
void *)t);
647 if (nfq_set_mode(q->
qh, NFQNL_COPY_PACKET, 0xFFFF) < 0) {
652 #ifdef HAVE_NFQ_MAXLEN
653 if (queue_maxlen > 0) {
654 SCLogInfo(
"setting queue length to %" PRId32
"", queue_maxlen);
657 if (nfq_set_queue_maxlen(q->
qh, queue_maxlen) < 0) {
658 SCLogWarning(
"can't set queue maxlen: your kernel probably "
659 "doesn't support setting the queue length");
665 nfnl_rcvbufsiz(nfq_nfnlh(q->
h), queue_maxlen * 1500);
666 SCLogInfo(
"setting nfnl bufsize to %" PRId32
"", queue_maxlen * 1500);
668 q->
nh = nfq_nfnlh(q->
h);
669 q->
fd = nfnl_fd(q->
nh);
675 #ifdef NETLINK_BROADCAST_SEND_ERROR
677 NETLINK_BROADCAST_SEND_ERROR, &opt,
sizeof(
int)) == -1) {
678 SCLogWarning(
"can't set netlink broadcast error: %s", strerror(errno));
683 #ifdef NETLINK_NO_ENOBUFS
685 NETLINK_NO_ENOBUFS, &opt,
sizeof(
int)) == -1) {
686 SCLogWarning(
"can't set netlink enobufs: %s", strerror(errno));
690 #ifdef HAVE_NFQ_SET_QUEUE_FLAGS
692 uint32_t
flags = NFQA_CFG_F_FAIL_OPEN;
693 uint32_t mask = NFQA_CFG_F_FAIL_OPEN;
694 int r = nfq_set_queue_flags(q->
qh, mask,
flags);
697 SCLogWarning(
"can't set fail-open mode: %s", strerror(errno));
699 SCLogInfo(
"fail-open mode should be set on queue");
704 #ifdef HAVE_NFQ_SET_VERDICT_BATCH
705 if (runmode_workers) {
708 SCLogError(
"nfq.batchcount is only valid in workers runmode.");
717 if(setsockopt(q->
fd, SOL_SOCKET, SO_RCVTIMEO, &
tv,
sizeof(
tv)) == -1) {
718 SCLogWarning(
"can't set socket timeout: %s", strerror(errno));
721 SCLogDebug(
"nfq_q->h %p, nfq_q->nh %p, nfq_q->qh %p, nfq_q->fd %" PRId32
"",
733 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
742 SCLogError(
"nfq thread failed to initialize");
748 #define T_DATA_SIZE 70000
750 if (ntv->
data == NULL) {
773 if (nq->
qh != NULL) {
774 nfq_destroy_queue(nq->
qh);
787 if (ntv->
data != NULL) {
827 char queue[10] = { 0 };
828 static bool many_queues_warned =
false;
831 if (g_nfq_t == NULL || g_nfq_q == NULL) {
837 if (!many_queues_warned && (receive_queue_num >= num_cpus)) {
838 SCLogWarning(
"using more Netfilter queues than %hu available CPU core(s) "
839 "may degrade performance",
841 many_queues_warned =
true;
849 ntv = &g_nfq_t[receive_queue_num];
852 nq = &g_nfq_q[receive_queue_num];
853 memset(nq, 0,
sizeof(*nq));
857 snprintf(queue,
sizeof(queue) - 1,
"NFQ#%hu", number);
881 uint16_t queue_start = 0;
882 uint16_t queue_end = 0;
883 uint16_t num_queues = 1;
886 int count = sscanf(queues,
"%hu:%hu", &queue_start, &queue_end);
889 SCLogError(
"specified queue(s) argument '%s' is not "
890 "valid (allowed queue numbers are 0-65535)",
898 if (queue_start > queue_end) {
899 SCLogError(
"start queue's number %d is greater than "
901 queue_start, queue_end);
905 num_queues = queue_end - queue_start + 1;
911 SCLogError(
"Unable to allocate NFQThreadVars");
920 SCLogError(
"Unable to allocate NFQQueueVars");
931 }
while (++queue_start <= queue_end);
946 if (
unlikely(number < 0 || number >= receive_queue_num || g_nfq_q == NULL))
949 return (
void *)&g_nfq_q[number];
964 if (
unlikely(number < 0 || number >= receive_queue_num || g_nfq_t == NULL))
967 return (
void *)&g_nfq_t[number];
976 int flag = NFQVerdictCacheLen(t) ? MSG_DONTWAIT : 0;
978 int rv = recv(t->
fd,
tv->data,
tv->datalen, flag);
980 if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) {
983 NFQVerdictCacheFlush(t);
986 TmThreadsCaptureHandleTimeout(
tv->tv, NULL);
998 if (rv > t->dbg_maxreadsize)
999 t->dbg_maxreadsize = rv;
1003 if (t->
qh != NULL) {
1004 ret = nfq_handle_packet(t->
h,
tv->data, rv);
1011 SCLogDebug(
"nfq_handle_packet error %"PRId32, ret);
1033 NFQDestroyQueue(nq);
1036 NFQRecvPkt(nq, ntv);
1046 void ReceiveNFQThreadExitStats(
ThreadVars *
tv,
void *data)
1051 SCLogNotice(
"(%s) Treated: Pkts %" PRIu32
", Bytes %" PRIu64
", Errors %" PRIu32
"",
1053 SCLogNotice(
"(%s) Verdict: Accepted %"PRIu32
", Dropped %"PRIu32
", Replaced %"PRIu32,
1058 static inline uint32_t GetVerdict(
const Packet *p)
1060 uint32_t verdict = NF_ACCEPT;
1068 verdict = NF_ACCEPT;
1071 verdict = NF_REPEAT;
1100 static TmEcode NFQSetVerdict(
Packet *p,
const uint32_t mark_value,
const bool mark_modified)
1114 if (t->
qh == NULL) {
1120 uint32_t verdict = GetVerdict(p);
1122 UpdateCounters(t, p);
1125 int ret = NFQVerdictCacheAdd(t, p, verdict, mark_value, mark_modified);
1136 if (mark_modified) {
1137 #ifdef HAVE_NFQ_SET_VERDICT2
1139 ret = nfq_set_verdict2(t->
qh, p->
nfq_v.
id, verdict, mark_value,
1142 ret = nfq_set_verdict2(t->
qh, p->
nfq_v.
id, verdict, mark_value, 0, NULL);
1146 ret = nfq_set_verdict_mark(t->
qh, p->
nfq_v.
id, verdict, htonl(mark_value),
1149 ret = nfq_set_verdict_mark(
1150 t->
qh, p->
nfq_v.
id, verdict, htonl(mark_value), 0, NULL);
1155 ret = nfq_set_verdict(t->
qh, p->
nfq_v.
id, verdict,
1158 ret = nfq_set_verdict(t->
qh, p->
nfq_v.
id, verdict, 0, NULL);
1163 #ifdef HAVE_NFQ_SET_VERDICT2
1165 ret = nfq_set_verdict2(t->
qh, p->
nfq_v.
id, verdict,
1169 ret = nfq_set_verdict2(t->
qh, p->
nfq_v.
id, verdict,
1175 ret = nfq_set_verdict_mark(t->
qh, p->
nfq_v.
id, verdict,
1180 ret = nfq_set_verdict_mark(t->
qh, p->
nfq_v.
id, verdict,
1193 SCLogWarning(
"nfq_set_verdict of %p failed %" PRId32
": %s", p, ret, strerror(errno));
1206 if (PacketIsTunnel(p)) {
1213 const bool do_verdict = VerdictTunnelPacketInternal(p);
1216 const uint32_t mark_value = root_p->
nfq_v.
mark;
1220 if (do_verdict ==
true) {
1221 int ret = NFQSetVerdict(root_p, mark_value, mark_modified);
1286 *data = (
void *)
dtv;
1302 if (g_nfq_q != NULL) {
1307 if (g_nfq_t != NULL) {
bool PacketCheckAction(const Packet *p, const uint8_t a)
int ConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
void * NFQGetThread(int number)
Get a pointer to the NFQ thread at index.
int LiveRegisterDevice(const char *dev)
Add a pcap device for monitoring and create structure.
#define IPV6_GET_RAW_VER(ip6h)
void PacketFreeOrRelease(Packet *p)
Return a packet to where it was allocated.
struct NFQThreadVars_ NFQThreadVars
int PacketCopyData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Copy data to Packet payload and set packet length.
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
int ConfGetBool(const char *name, int *val)
Retrieve a configuration value as a boolean.
struct Packet_::@35 persistent
#define PKT_STREAM_MODIFIED
void TmThreadsSetFlag(ThreadVars *tv, uint32_t flag)
Set a thread flag.
#define NFQ_FLAG_FAIL_OPEN
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
Finalize decoding of a packet.
char * RunmodeGetActive(void)
void NFQInitConfig(bool quiet)
To initialize the NFQ global configuration data.
void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
int(* BypassPacketsFlow)(struct Packet_ *)
#define NFQMutexUnlock(nq)
TmEcode(* PktAcqLoop)(ThreadVars *, void *, void *)
TmEcode(* ThreadDeinit)(ThreadVars *, void *)
#define PKT_SET_SRC(p, src_val)
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv)
int NFQParseAndRegisterQueues(const char *queues)
Parses and adds Netfilter queue(s).
#define SET_PKT_LEN(p, len)
void TmModuleVerdictNFQRegister(void)
void * NFQGetQueue(int number)
Get a pointer to the NFQ queue at index.
TmEcode(* PktAcqBreakLoop)(ThreadVars *, void *)
#define SCMutexUnlock(mut)
LiveDevice * LiveGetDevice(const char *name)
Get a pointer to the device at idx.
Per thread variable structure.
#define SCTIME_FROM_TIMEVAL(tv)
#define NFQ_VERDICT_RETRY_COUNT
TmEcode(* Func)(ThreadVars *, Packet *, void *)
#define SCLogWarning(...)
Macro used to log WARNING messages.
#define TM_FLAG_DECODE_TM
TmModule tmm_modules[TMM_SIZE]
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
#define IPV4_GET_RAW_VER(ip4h)
uint32_t max_pending_packets
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
#define SCMutexInit(mut, mutattrs)
#define TM_FLAG_RECEIVE_TM
#define SCRealloc(ptr, sz)
void(* ReleasePacket)(struct Packet_ *)
void DecodeThreadVarsFree(ThreadVars *tv, DecodeThreadVars *dtv)
struct NFQQueueVars_::@133 verdict_cache
@ PKT_DROP_REASON_NFQ_ERROR
TmEcode(* ThreadInit)(ThreadVars *, const void *, void **)
void TmModuleReceiveNFQRegister(void)
#define MAX_ALREADY_TREATED
void(* ThreadExitPrintStats)(ThreadVars *, void *)
#define PKT_REBUILT_FRAGMENT
#define SCLogError(...)
Macro used to log ERROR messages.
void DatalinkSetGlobalType(int datalink)
Structure to hold thread specific data for all decode modules.
DecodeThreadVars * DecodeThreadVarsAlloc(ThreadVars *tv)
Alloc and setup DecodeThreadVars.
int PacketSetData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Set data for Packet and set length when zero copy is used.
void PacketDrop(Packet *p, const uint8_t action, enum PacketDropReason r)
issue drop action
struct TmSlot_ * slot_next
void StatsSyncCountersIfSignalled(ThreadVars *tv)
uint16_t UtilCpuGetNumProcessorsOnline(void)
Get the number of cpus online in the system.
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
#define SCLogNotice(...)
Macro used to log NOTICE messages.
void NFQContextsClean(void)
Clean global contexts. Must be called on exit.
Packet * PacketGetFromQueueOrAlloc(void)
Get a packet. We try to get a packet from the packetpool first, but if that is empty we alloc a packe...
void TmModuleDecodeNFQRegister(void)
void DecodeUpdatePacketCounters(ThreadVars *tv, const DecodeThreadVars *dtv, const Packet *p)
volatile uint8_t suricata_ctl_flags
int NFQRegisterQueue(const uint16_t number)
Add a single Netfilter queue.