/** * \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)); } } }
void NFQRecvPkt(NFQQueueVars *t, NFQThreadVars *tv) { int rv, ret; /* XXX what happens on rv == 0? */ rv = recv(t->fd, tv->data, tv->datalen, 0); if (rv < 0) { if (errno == EINTR || errno == EWOULDBLOCK) { /* no error on timeout */ } 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 "", ret); } } }
TmEcode VerdictNFQThreadDeinit(ThreadVars *tv, void *data) { NFQThreadVars *ntv = (NFQThreadVars *)data; NFQQueueVars *nq = NFQGetQueue(ntv->nfq_index); SCLogDebug("starting... will close queuenum %" PRIu32 "", nq->queue_num); NFQMutexLock(nq); if (nq->qh) { nfq_destroy_queue(nq->qh); nq->qh = NULL; } NFQMutexUnlock(nq); return TM_ECODE_OK; }
static void NFQDestroyQueue(NFQQueueVars *nq) { if (unlikely(nq == NULL)) { return; } SCLogDebug("starting... will close queuenum %" PRIu32 "", nq->queue_num); NFQMutexLock(nq); if (nq->qh != NULL) { nfq_destroy_queue(nq->qh); nq->qh = NULL; nfq_close(nq->h); nq->h = NULL; } NFQMutexUnlock(nq); }
/** * \brief Main NFQ reading Loop function */ TmEcode ReceiveNFQLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); NFQThreadVars *ntv = (NFQThreadVars *)data; NFQQueueVars *nq = NFQGetQueue(ntv->nfq_index); ntv->slot = ((TmSlot *) slot)->slot_next; while(1) { if (suricata_ctl_flags != 0) { NFQMutexLock(nq); if (nq->qh) { nfq_destroy_queue(nq->qh); nq->qh = NULL; } NFQMutexUnlock(nq); break; } NFQRecvPkt(nq, ntv); StatsSyncCountersIfSignalled(tv); } SCReturnInt(TM_ECODE_OK); }
/** * \brief NFQ verdict function */ TmEcode NFQSetVerdict(Packet *p) { int iter = 0; int ret = 0; uint32_t verdict = NF_ACCEPT; /* we could also have a direct pointer but we need to have a ref counf in this case */ NFQQueueVars *t = nfq_q + p->nfq_v.nfq_index; /** \todo add a test on validity of the entry NFQQueueVars could have been * wipeout */ /* can't verdict a "fake" packet */ if (p->flags & PKT_PSEUDO_STREAM_END) { return TM_ECODE_OK; } //printf("%p verdicting on queue %" PRIu32 "\n", t, t->queue_num); NFQMutexLock(t); if (t->qh == NULL) { /* Somebody has started a clean-up, we leave */ NFQMutexUnlock(t); return TM_ECODE_OK; } if (p->action & ACTION_DROP) { verdict = NF_DROP; #ifdef COUNTERS t->dropped++; #endif /* COUNTERS */ } else { switch (nfq_config.mode) { default: case NFQ_ACCEPT_MODE: verdict = NF_ACCEPT; break; case NFQ_REPEAT_MODE: verdict = NF_REPEAT; break; case NFQ_ROUTE_MODE: verdict = ((uint32_t) NF_QUEUE) | nfq_config.next_queue; break; } if (p->flags & PKT_STREAM_MODIFIED) { #ifdef COUNTERS t->replaced++; #endif /* COUNTERS */ } #ifdef COUNTERS t->accepted++; #endif /* COUNTERS */ } do { switch (nfq_config.mode) { default: case NFQ_ACCEPT_MODE: case NFQ_ROUTE_MODE: if (p->flags & PKT_MARK_MODIFIED) { #ifdef HAVE_NFQ_SET_VERDICT2 if (p->flags & PKT_STREAM_MODIFIED) { ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict, p->nfq_v.mark, GET_PKT_LEN(p), GET_PKT_DATA(p)); } else { ret = nfq_set_verdict2(t->qh, p->nfq_v.id, verdict, p->nfq_v.mark, 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(p->nfq_v.mark), GET_PKT_LEN(p), GET_PKT_DATA(p)); } else { ret = nfq_set_verdict_mark(t->qh, p->nfq_v.id, verdict, htonl(p->nfq_v.mark), 0, NULL); } #endif /* HAVE_NFQ_SET_VERDICT2 */ } else { 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)); } else { ret = nfq_set_verdict(t->qh, p->nfq_v.id, verdict, 0, NULL); } } break; case NFQ_REPEAT_MODE: #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 /* HAVE_NFQ_SET_VERDICT2 */ break; } } while ((ret < 0) && (iter++ < NFQ_VERDICT_RETRY_TIME)); NFQMutexUnlock(t); if (ret < 0) { SCLogWarning(SC_ERR_NFQ_SET_VERDICT, "nfq_set_verdict of %p failed %" PRId32 "", p, ret); return TM_ECODE_FAILED; } return TM_ECODE_OK; }
/* no error on timeout */ } 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 "", ret); } } } #else /* WIN32 version of NFQRecvPkt */ void NFQRecvPkt(NFQQueueVars *t, NFQThreadVars *tv) { int rv, ret; static int timeouted = 0; if (timeouted) { if (WaitForSingleObject(t->ovr.hEvent, 1000) == WAIT_TIMEOUT) { rv = -1; errno = EINTR; goto process_rv; } timeouted = 0; } read_packet_again: if (!ReadFile(t->fd, tv->buf, sizeof(tv->buf), (DWORD*)&rv, &t->ovr)) { if (GetLastError() != ERROR_IO_PENDING) { rv = -1; errno = EIO; } else { if (WaitForSingleObject(t->ovr.hEvent, 1000) == WAIT_TIMEOUT) { rv = -1; errno = EINTR; timeouted = 1; } else { /* We needn't to call GetOverlappedResult() because it always * fail with our error code ERROR_MORE_DATA. */ goto read_packet_again; } } } process_rv: if (rv < 0) { if (errno == EINTR) { /* no error on timeout */ } else { #ifdef COUNTERS t->errs++; #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) { ret = nfq_handle_packet(t->h, buf, 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 "", ret); } } }