예제 #1
0
파일: source-pcap.c 프로젝트: norg/suricata
/**
 *  \brief Main PCAP reading Loop function
 */
TmEcode ReceivePcapLoop(ThreadVars *tv, void *data, void *slot)
{
    SCEnter();

    int packet_q_len = 64;
    PcapThreadVars *ptv = (PcapThreadVars *)data;
    int r;
    TmSlot *s = (TmSlot *)slot;

    ptv->slot = s->slot_next;
    ptv->cb_result = TM_ECODE_OK;

    while (1) {
        if (suricata_ctl_flags & SURICATA_STOP) {
            SCReturnInt(TM_ECODE_OK);
        }

        /* make sure we have at least one packet in the packet pool, to prevent
         * us from alloc'ing packets at line rate */
        PacketPoolWait();

        /* Right now we just support reading packets one at a time. */
        r = pcap_dispatch(ptv->pcap_handle, packet_q_len,
                          (pcap_handler)PcapCallbackLoop, (u_char *)ptv);
        if (unlikely(r < 0)) {
            int dbreak = 0;
            SCLogError(SC_ERR_PCAP_DISPATCH, "error code %" PRId32 " %s",
                       r, pcap_geterr(ptv->pcap_handle));
#ifdef PCAP_ERROR_BREAK
            if (r == PCAP_ERROR_BREAK) {
                SCReturnInt(ptv->cb_result);
            }
#endif
            do {
                usleep(PCAP_RECONNECT_TIMEOUT);
                if (suricata_ctl_flags != 0) {
                    dbreak = 1;
                    break;
                }
                r = PcapTryReopen(ptv);
            } while (r < 0);
            if (dbreak) {
                break;
            }
        } else if (ptv->cb_result == TM_ECODE_FAILED) {
            SCLogError(SC_ERR_PCAP_DISPATCH, "Pcap callback PcapCallbackLoop failed");
            SCReturnInt(TM_ECODE_FAILED);
        } else if (unlikely(r == 0)) {
            TmThreadsCaptureInjectPacket(tv, ptv->slot, NULL);
        }

        StatsSyncCountersIfSignalled(tv);
    }

    PcapDumpCounters(ptv);
    StatsSyncCountersIfSignalled(tv);
    SCReturnInt(TM_ECODE_OK);
}
예제 #2
0
/**
 * \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));
        }
    }
}
예제 #3
0
/**
 * \brief Recieves packets from an interface via libpfring.
 *
 *  This function recieves packets from an interface and passes
 *  the packet on to the pfring callback function.
 *
 * \param tv pointer to ThreadVars
 * \param data pointer that gets cast into PfringThreadVars for ptv
 * \param slot slot containing task information
 * \retval TM_ECODE_OK on success
 * \retval TM_ECODE_FAILED on failure
 */
TmEcode ReceivePfringLoop(ThreadVars *tv, void *data, void *slot)
{
    SCEnter();

    PfringThreadVars *ptv = (PfringThreadVars *)data;
    Packet *p = NULL;
    struct pfring_pkthdr hdr;
    TmSlot *s = (TmSlot *)slot;
    time_t last_dump = 0;
    u_int buffer_size;
    u_char *pkt_buffer;

    ptv->slot = s->slot_next;

    /* we have to enable the ring here as we need to do it after all
     * the threads have called pfring_set_cluster(). */
    int rc = pfring_enable_ring(ptv->pd);
    if (rc != 0) {
        SCLogError(SC_ERR_PF_RING_OPEN, "pfring_enable_ring failed returned %d ", rc);
        SCReturnInt(TM_ECODE_FAILED);
    }

    while(1) {
        if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) {
            SCReturnInt(TM_ECODE_OK);
        }

        /* make sure we have at least one packet in the packet pool, to prevent
         * us from alloc'ing packets at line rate */
        PacketPoolWait();

        p = PacketGetFromQueueOrAlloc();
        if (p == NULL) {
            SCReturnInt(TM_ECODE_FAILED);
        }
        PKT_SET_SRC(p, PKT_SRC_WIRE);

        /* Some flavours of PF_RING may fail to set timestamp - see PF-RING-enabled libpcap code*/
        hdr.ts.tv_sec = hdr.ts.tv_usec = 0;

        /* Check for Zero-copy mode */
        if (ptv->flags & PFRING_FLAGS_ZERO_COPY) {
            buffer_size = 0;
            pkt_buffer = NULL;
        } else {
            buffer_size = GET_PKT_DIRECT_MAX_SIZE(p);
            pkt_buffer = GET_PKT_DIRECT_DATA(p);
        }

        int r = pfring_recv(ptv->pd, &pkt_buffer,
                buffer_size,
                &hdr,
                LIBPFRING_WAIT_FOR_INCOMING);
        if (likely(r == 1)) {
            /* profiling started before blocking pfring_recv call, so
             * reset it here */
            PACKET_PROFILING_RESTART(p);

            /* Check for Zero-copy mode */
            if (ptv->flags & PFRING_FLAGS_ZERO_COPY) {
                PacketSetData(p, pkt_buffer, hdr.caplen);
            }

            //printf("RecievePfring src %" PRIu32 " sport %" PRIu32 " dst %" PRIu32 " dstport %" PRIu32 "\n",
            //        hdr.parsed_pkt.ipv4_src,hdr.parsed_pkt.l4_src_port, hdr.parsed_pkt.ipv4_dst,hdr.parsed_pkt.l4_dst_port);

            PfringProcessPacket(ptv, &hdr, p);

            if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) {
                TmqhOutputPacketpool(ptv->tv, p);
                SCReturnInt(TM_ECODE_FAILED);
            }

            /* Trigger one dump of stats every second */
            if (p->ts.tv_sec != last_dump) {
                PfringDumpCounters(ptv);
                last_dump = p->ts.tv_sec;
            }
        } else if (unlikely(r == 0)) {
            if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) {
                SCReturnInt(TM_ECODE_OK);
            }

            /* pfring didn't use the packet yet */
            TmThreadsCaptureInjectPacket(tv, ptv->slot, p);

        } else {
            SCLogError(SC_ERR_PF_RING_RECV,"pfring_recv error  %" PRId32 "", r);
            TmqhOutputPacketpool(ptv->tv, p);
            SCReturnInt(TM_ECODE_FAILED);
        }
        StatsSyncCountersIfSignalled(tv);
    }

    return TM_ECODE_OK;
}