/** * \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 | 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(); /* 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); } SCPerfSyncCountersIfSignalled(tv); } PcapDumpCounters(ptv); SCPerfSyncCountersIfSignalled(tv); SCReturnInt(TM_ECODE_OK); }
/* same as 'simple' */ Packet *TmqhInputFlow(ThreadVars *tv) { PacketQueue *q = &trans_q[tv->inq->id]; SCPerfSyncCountersIfSignalled(tv, 0); SCMutexLock(&q->mutex_q); if (q->len == 0) { /* if we have no packets in queue, wait... */ #ifdef __tile__ for (;;) { if (q->len > 0 || q->cond_q) break; SCMutexUnlock(&q->mutex_q); SCMutexLock(&q->mutex_q); } #else SCCondWait(&q->cond_q, &q->mutex_q); #endif } if (q->len > 0) { Packet *p = PacketDequeue(q); SCMutexUnlock(&q->mutex_q); return p; } else { /* return NULL if we have no pkt. Should only happen on signals. */ SCMutexUnlock(&q->mutex_q); return NULL; } }
Packet *TmqhInputRingBufferMrSw(ThreadVars *t) { RingBuffer8 *rb = ringbuffers[t->inq->id]; Packet *p = (Packet *)RingBufferMrSw8Get(rb); SCPerfSyncCountersIfSignalled(t); return p; }
/** * \brief Main PCAP file reading Loop function */ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); uint16_t packet_q_len = 0; PcapFileThreadVars *ptv = (PcapFileThreadVars *)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 | 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 */ do { packet_q_len = PacketPoolSize(); if (unlikely(packet_q_len == 0)) { PacketPoolWait(); } } while (packet_q_len == 0); /* Right now we just support reading packets one at a time. */ r = pcap_dispatch(pcap_g.pcap_handle, (int)packet_q_len, (pcap_handler)PcapFileCallbackLoop, (u_char *)ptv); if (unlikely(r == -1)) { SCLogError(SC_ERR_PCAP_DISPATCH, "error code %" PRId32 " %s", r, pcap_geterr(pcap_g.pcap_handle)); /* in the error state we just kill the engine */ EngineKill(); SCReturnInt(TM_ECODE_FAILED); } else if (unlikely(r == 0)) { SCLogInfo("pcap file end of file reached (pcap err code %" PRId32 ")", r); EngineStop(); break; } else if (ptv->cb_result == TM_ECODE_FAILED) { SCLogError(SC_ERR_PCAP_DISPATCH, "Pcap callback PcapFileCallbackLoop failed"); EngineKill(); SCReturnInt(TM_ECODE_FAILED); } SCPerfSyncCountersIfSignalled(tv, 0); } SCReturnInt(TM_ECODE_OK); }
/** * \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) { break; } NFQRecvPkt(nq, ntv); SCPerfSyncCountersIfSignalled(tv, 0); } SCReturnInt(TM_ECODE_OK); }
/** * \brief Receives packets from a DAG interface. * * \param tv pointer to ThreadVars * \param data pointer to ErfDagThreadVars * \param slot slot containing task information * * \retval TM_ECODE_OK on success * \retval TM_ECODE_FAILED on failure */ TmEcode ReceiveErfDagLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); ErfDagThreadVars *dtv = (ErfDagThreadVars *)data; uint32_t diff = 0; int err; uint8_t *top = NULL; uint32_t pkts_read = 0; TmSlot *s = (TmSlot *)slot; dtv->slot = s->slot_next; while (1) { if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) { SCReturnInt(TM_ECODE_OK); } top = dag_advance_stream(dtv->dagfd, dtv->dagstream, &(dtv->btm)); if (top == NULL) { if (errno == EAGAIN) { if (dtv->dagstream & 0x1) { usleep(10 * 1000); dtv->btm = dtv->top; } continue; } else { SCLogError(SC_ERR_ERF_DAG_STREAM_READ_FAILED, "Failed to read from stream: %d, DAG: %s when " "using dag_advance_stream", dtv->dagstream, dtv->dagname); SCReturnInt(TM_ECODE_FAILED); } } diff = top - dtv->btm; if (diff == 0) { continue; } assert(diff >= dag_record_size); err = ProcessErfDagRecords(dtv, top, &pkts_read); if (err == TM_ECODE_FAILED) { SCLogError(SC_ERR_ERF_DAG_STREAM_READ_FAILED, "Failed to read from stream: %d, DAG: %s", dtv->dagstream, dtv->dagname); ReceiveErfDagCloseStream(dtv->dagfd, dtv->dagstream); SCReturnInt(TM_ECODE_FAILED); } SCPerfSyncCountersIfSignalled(tv); SCLogDebug("Read %d records from stream: %d, DAG: %s", pkts_read, dtv->dagstream, dtv->dagname); } SCReturnInt(TM_ECODE_OK); }
/** * \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(); uint16_t packet_q_len = 0; PfringThreadVars *ptv = (PfringThreadVars *)data; Packet *p = NULL; struct pfring_pkthdr hdr; TmSlot *s = (TmSlot *)slot; time_t last_dump = 0; struct timeval current_time; ptv->slot = s->slot_next; 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 */ do { packet_q_len = PacketPoolSize(); if (unlikely(packet_q_len == 0)) { PacketPoolWait(); } } while (packet_q_len == 0); 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; /* Depending on what compile time options are used for pfring we either return 0 or -1 on error and always 1 for success */ #ifdef HAVE_PFRING_RECV_UCHAR u_char *pkt_buffer = GET_PKT_DIRECT_DATA(p); u_int buffer_size = GET_PKT_DIRECT_MAX_SIZE(p); int r = pfring_recv(ptv->pd, &pkt_buffer, buffer_size, &hdr, LIBPFRING_WAIT_FOR_INCOMING); /* Check for Zero-copy if buffer size is zero */ if (buffer_size == 0) { PacketSetData(p, pkt_buffer, hdr.caplen); } #else int r = pfring_recv(ptv->pd, (char *)GET_PKT_DIRECT_DATA(p), (u_int)GET_PKT_DIRECT_MAX_SIZE(p), &hdr, LIBPFRING_WAIT_FOR_INCOMING); #endif /* HAVE_PFRING_RECV_UCHAR */ if (r == 1) { //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 */ TimeGet(¤t_time); if (current_time.tv_sec != last_dump) { PfringDumpCounters(ptv); last_dump = current_time.tv_sec; } } else { SCLogError(SC_ERR_PF_RING_RECV,"pfring_recv error %" PRId32 "", r); TmqhOutputPacketpool(ptv->tv, p); SCReturnInt(TM_ECODE_FAILED); } SCPerfSyncCountersIfSignalled(tv); } return TM_ECODE_OK; }
TmEcode ReceiveIPFWLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); IPFWThreadVars *ptv = (IPFWThreadVars *)data; IPFWQueueVars *nq = NULL; uint8_t pkt[IP_MAXPACKET]; int pktlen=0; struct pollfd IPFWpoll; struct timeval IPFWts; Packet *p = NULL; uint16_t packet_q_len = 0; nq = IPFWGetQueue(ptv->ipfw_index); if (nq == NULL) { SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Can't get thread variable"); SCReturnInt(TM_ECODE_FAILED); } SCLogInfo("Thread '%s' will run on port %d (item %d)", tv->name, nq->port_num, ptv->ipfw_index); while (1) { if (suricata_ctl_flags & (SURICATA_STOP || SURICATA_KILL)) { SCReturnInt(TM_ECODE_OK); } IPFWpoll.fd = nq->fd; IPFWpoll.events = POLLRDNORM; /* Poll the socket for status */ if ( (poll(&IPFWpoll, 1, IPFW_SOCKET_POLL_MSEC)) > 0) { if (!(IPFWpoll.revents & (POLLRDNORM | POLLERR))) continue; } if ((pktlen = recvfrom(nq->fd, pkt, sizeof(pkt), 0, (struct sockaddr *)&nq->ipfw_sin, &nq->ipfw_sinlen)) == -1) { /* We received an error on socket read */ if (errno == EINTR || errno == EWOULDBLOCK) { /* Nothing for us to process */ continue; } else { SCLogWarning(SC_WARN_IPFW_RECV, "Read from IPFW divert socket failed: %s", strerror(errno)); SCReturnInt(TM_ECODE_FAILED); } } /* We have a packet to process */ memset (&IPFWts, 0, sizeof(struct timeval)); gettimeofday(&IPFWts, NULL); /* make sure we have at least one packet in the packet pool, to prevent * us from alloc'ing packets at line rate */ do { packet_q_len = PacketPoolSize(); if (unlikely(packet_q_len == 0)) { PacketPoolWait(); } } while (packet_q_len == 0); p = PacketGetFromQueueOrAlloc(); if (p == NULL) { SCReturnInt(TM_ECODE_FAILED); } PKT_SET_SRC(p, PKT_SRC_WIRE); SCLogDebug("Received Packet Len: %d", pktlen); p->ts.tv_sec = IPFWts.tv_sec; p->ts.tv_usec = IPFWts.tv_usec; ptv->pkts++; ptv->bytes += pktlen; p->datalink = ptv->datalink; p->ipfw_v.ipfw_index = ptv->ipfw_index; PacketCopyData(p, pkt, pktlen); SCLogDebug("Packet info: pkt_len: %" PRIu32 " (pkt %02x, pkt_data %02x)", GET_PKT_LEN(p), *pkt, GET_PKT_DATA(p)); if (TmThreadsSlotProcessPkt(tv, ((TmSlot *) slot)->slot_next, p) != TM_ECODE_OK) { TmqhOutputPacketpool(tv, p); SCReturnInt(TM_ECODE_FAILED); } SCPerfSyncCountersIfSignalled(tv, 0); } SCReturnInt(TM_ECODE_OK); }
/** * \brief Main Napatech reading Loop function */ TmEcode NapatechStreamLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); int32_t status; char errbuf[100]; uint16_t packet_q_len = 0; uint64_t pkt_ts; NtNetBuf_t packet_buffer; NapatechThreadVars *ntv = (NapatechThreadVars *)data; NtNetRx_t stat_cmd; SCLogInfo("Opening NAPATECH Stream: %lu for processing", ntv->stream_id); if ((status = NT_NetRxOpen(&(ntv->rx_stream), "SuricataStream", NT_NET_INTERFACE_PACKET, ntv->stream_id, ntv->hba)) != NT_SUCCESS) { NT_ExplainError(status, errbuf, sizeof(errbuf)); SCLogError(SC_ERR_NAPATECH_OPEN_FAILED, "Failed to open NAPATECH Stream: %lu - %s", ntv->stream_id, errbuf); SCFree(ntv); SCReturnInt(TM_ECODE_FAILED); } stat_cmd.cmd = NT_NETRX_READ_CMD_STREAM_DROP; SCLogInfo("Napatech Packet Stream Loop Started for Stream ID: %lu", ntv->stream_id); TmSlot *s = (TmSlot *)slot; ntv->slot = s->slot_next; while (!(suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL))) { /* make sure we have at least one packet in the packet pool, to prevent * us from alloc'ing packets at line rate */ do { packet_q_len = PacketPoolSize(); if (unlikely(packet_q_len == 0)) { PacketPoolWait(); } } while (packet_q_len == 0); /* * Napatech returns packets 1 at a time */ status = NT_NetRxGet(ntv->rx_stream, &packet_buffer, 1000); if (unlikely(status == NT_STATUS_TIMEOUT || status == NT_STATUS_TRYAGAIN)) { /* * no frames currently available */ continue; } else if (unlikely(status != NT_SUCCESS)) { SCLogError(SC_ERR_NAPATECH_STREAM_NEXT_FAILED, "Failed to read from Napatech Stream: %lu", ntv->stream_id); SCReturnInt(TM_ECODE_FAILED); } Packet *p = PacketGetFromQueueOrAlloc(); if (unlikely(p == NULL)) { NT_NetRxRelease(ntv->rx_stream, packet_buffer); SCReturnInt(TM_ECODE_FAILED); } pkt_ts = NT_NET_GET_PKT_TIMESTAMP(packet_buffer); /* * Handle the different timestamp forms that the napatech cards could use * - NT_TIMESTAMP_TYPE_NATIVE is not supported due to having an base of 0 as opposed to NATIVE_UNIX which has a base of 1/1/1970 */ switch(NT_NET_GET_PKT_TIMESTAMP_TYPE(packet_buffer)) { case NT_TIMESTAMP_TYPE_NATIVE_UNIX: p->ts.tv_sec = pkt_ts / 100000000; p->ts.tv_usec = ((pkt_ts % 100000000) / 100) + (pkt_ts % 100) > 50 ? 1 : 0; break; case NT_TIMESTAMP_TYPE_PCAP: p->ts.tv_sec = pkt_ts >> 32; p->ts.tv_usec = pkt_ts & 0xFFFFFFFF; break; case NT_TIMESTAMP_TYPE_PCAP_NANOTIME: p->ts.tv_sec = pkt_ts >> 32; p->ts.tv_usec = ((pkt_ts & 0xFFFFFFFF) / 1000) + (pkt_ts % 1000) > 500 ? 1 : 0; break; case NT_TIMESTAMP_TYPE_NATIVE_NDIS: /* number of seconds between 1/1/1601 and 1/1/1970 */ p->ts.tv_sec = (pkt_ts / 100000000) - 11644473600; p->ts.tv_usec = ((pkt_ts % 100000000) / 100) + (pkt_ts % 100) > 50 ? 1 : 0; break; default: SCLogError(SC_ERR_NAPATECH_TIMESTAMP_TYPE_NOT_SUPPORTED, "Packet from Napatech Stream: %lu does not have a supported timestamp format", ntv->stream_id); NT_NetRxRelease(ntv->rx_stream, packet_buffer); SCReturnInt(TM_ECODE_FAILED); } SCLogDebug("p->ts.tv_sec %"PRIuMAX"", (uintmax_t)p->ts.tv_sec); p->datalink = LINKTYPE_ETHERNET; ntv->pkts++; ntv->bytes += NT_NET_GET_PKT_WIRE_LENGTH(packet_buffer); // Update drop counter if (unlikely((status = NT_NetRxRead(ntv->rx_stream, &stat_cmd)) != NT_SUCCESS)) { NT_ExplainError(status, errbuf, sizeof(errbuf)); SCLogWarning(SC_ERR_NAPATECH_STAT_DROPS_FAILED, "Couldn't retrieve drop statistics from the RX stream: %lu - %s", ntv->stream_id, errbuf); } else { ntv->drops += stat_cmd.u.streamDrop.pktsDropped; } if (unlikely(PacketCopyData(p, (uint8_t *)NT_NET_GET_PKT_L2_PTR(packet_buffer), NT_NET_GET_PKT_WIRE_LENGTH(packet_buffer)))) { TmqhOutputPacketpool(ntv->tv, p); NT_NetRxRelease(ntv->rx_stream, packet_buffer); SCReturnInt(TM_ECODE_FAILED); } if (unlikely(TmThreadsSlotProcessPkt(ntv->tv, ntv->slot, p) != TM_ECODE_OK)) { TmqhOutputPacketpool(ntv->tv, p); NT_NetRxRelease(ntv->rx_stream, packet_buffer); SCReturnInt(TM_ECODE_FAILED); } NT_NetRxRelease(ntv->rx_stream, packet_buffer); SCPerfSyncCountersIfSignalled(tv); } SCReturnInt(TM_ECODE_OK); }