/** * \brief NFQ function to get a packet from the kernel * * \note separate functions for Linux and Win32 for readability. */ static void NFQRecvPkt(NFQQueueVars *t, NFQThreadVars *tv) { int rv, ret; int flag = NFQVerdictCacheLen(t) ? MSG_DONTWAIT : 0; /* XXX what happens on rv == 0? */ rv = recv(t->fd, tv->data, tv->datalen, flag); if (rv < 0) { if (errno == EINTR || errno == EWOULDBLOCK) { /* no error on timeout */ if (flag) NFQVerdictCacheFlush(t); /* inject a fake packet on timeout */ TmThreadsCaptureInjectPacket(tv->tv, tv->slot, NULL); } else { #ifdef COUNTERS NFQMutexLock(t); t->errs++; NFQMutexUnlock(t); #endif /* COUNTERS */ } } else if(rv == 0) { SCLogWarning(SC_ERR_NFQ_RECV, "recv got returncode 0"); } else { #ifdef DBG_PERF if (rv > t->dbg_maxreadsize) t->dbg_maxreadsize = rv; #endif /* DBG_PERF */ //printf("NFQRecvPkt: t %p, rv = %" PRId32 "\n", t, rv); NFQMutexLock(t); if (t->qh != NULL) { ret = nfq_handle_packet(t->h, tv->data, rv); } else { SCLogWarning(SC_ERR_NFQ_HANDLE_PKT, "NFQ handle has been destroyed"); ret = -1; } NFQMutexUnlock(t); if (ret != 0) { SCLogWarning(SC_ERR_NFQ_HANDLE_PKT, "nfq_handle_packet error %"PRId32" %s", ret, strerror(errno)); } } }
static int NFQVerdictCacheAdd(NFQQueueVars *t, Packet *p, uint32_t verdict) { #ifdef HAVE_NFQ_SET_VERDICT_BATCH if (t->verdict_cache.maxlen == 0) return -1; if (p->flags & PKT_STREAM_MODIFIED || verdict == NF_DROP) goto flush; if (p->flags & PKT_MARK_MODIFIED) { if (!t->verdict_cache.mark_valid) { if (t->verdict_cache.len) goto flush; t->verdict_cache.mark_valid = 1; t->verdict_cache.mark = p->nfq_v.mark; } else if (t->verdict_cache.mark != p->nfq_v.mark) { goto flush; } } else if (t->verdict_cache.mark_valid) { goto flush; } if (t->verdict_cache.len == 0) { t->verdict_cache.verdict = verdict; } else if (t->verdict_cache.verdict != verdict) goto flush; /* same verdict, mark not set or identical -> can cache */ t->verdict_cache.packet_id = p->nfq_v.id; if (t->verdict_cache.len >= t->verdict_cache.maxlen) NFQVerdictCacheFlush(t); else t->verdict_cache.len++; return 0; flush: /* can't cache. Flush current cache and signal caller it should send single verdict */ if (NFQVerdictCacheLen(t) > 0) NFQVerdictCacheFlush(t); #endif return -1; }