/** * \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; }
static int packet_input(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) { divert_cb cb = (divert_cb) data; char *d; int len; int rc; unsigned int id; struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr(nfa); struct ip *ip; int flags = 0; struct timeval tv; int rlen = 0; void *rdata = NULL; len = nfq_get_payload(nfa, &d); if (len < 0) err(1, "nfq_get_payload()"); if (nfq_get_indev(nfa)) flags |= DF_IN; if (nfq_get_timestamp(nfa, &tv) == 0) set_time(&tv); else { static int warn = 0; if (!warn && !_conf.cf_disable_timers) xprintf(XP_ALWAYS, "No timestamp provided in packet" " - expect low performance due to" " calls to gettimeofday\n"); warn = 1; } rc = cb(d, len, flags); id = ntohl(ph->packet_id); switch (rc) { case DIVERT_MODIFY: ip = (struct ip*) d; rlen = ntohs(ip->ip_len); rdata = d; /* fallthrough */ case DIVERT_ACCEPT: if (_mark) { unsigned int mark = 0; assert((mark & _mark) == 0); nfq_set_verdict_mark(qh, id, NF_REPEAT, htonl(_mark | mark), rlen, rdata); } else nfq_set_verdict(qh, id, NF_ACCEPT, rlen, rdata); break; case DIVERT_DROP: nfq_set_verdict(qh, id, NF_DROP, 0, NULL); break; default: printf("Unknown verdict %d\n", rc); abort(); } return 0; }