static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) { NFQThreadVars *ntv = (NFQThreadVars *)data; ThreadVars *tv = ntv->tv; int ret; /* grab a packet */ Packet *p = PacketGetFromQueueOrAlloc(); if (p == NULL) { return -1; } PKT_SET_SRC(p, PKT_SRC_WIRE); p->nfq_v.nfq_index = ntv->nfq_index; /* if bypass mask is set then we may want to bypass so set pointer */ if (nfq_config.bypass_mask) { p->BypassPacketsFlow = NFQBypassCallback; } ret = NFQSetupPkt(p, qh, (void *)nfa); if (ret == -1) { #ifdef COUNTERS NFQQueueVars *q = NFQGetQueue(ntv->nfq_index); q->errs++; q->pkts++; q->bytes += GET_PKT_LEN(p); #endif /* COUNTERS */ (void) SC_ATOMIC_ADD(ntv->livedev->pkts, 1); /* NFQSetupPkt is issuing a verdict so we only recycle Packet and leave */ TmqhOutputPacketpool(tv, p); return 0; } p->ReleasePacket = NFQReleasePacket; #ifdef COUNTERS NFQQueueVars *q = NFQGetQueue(ntv->nfq_index); q->pkts++; q->bytes += GET_PKT_LEN(p); #endif /* COUNTERS */ (void) SC_ATOMIC_ADD(ntv->livedev->pkts, 1); if (ntv->slot) { if (TmThreadsSlotProcessPkt(tv, ntv->slot, p) != TM_ECODE_OK) { TmqhOutputPacketpool(ntv->tv, p); return -1; } } else { /* pass on... */ tv->tmqh_out(tv, p); } return 0; }
void PcapFileCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt) { SCEnter(); PcapFileThreadVars *ptv = (PcapFileThreadVars *)user; Packet *p = PacketGetFromQueueOrAlloc(); if (unlikely(p == NULL)) { SCReturn; } PACKET_PROFILING_TMM_START(p, TMM_RECEIVEPCAPFILE); p->ts.tv_sec = h->ts.tv_sec; p->ts.tv_usec = h->ts.tv_usec; SCLogDebug("p->ts.tv_sec %"PRIuMAX"", (uintmax_t)p->ts.tv_sec); p->datalink = pcap_g.datalink; p->pcap_cnt = ++pcap_g.cnt; ptv->pkts++; ptv->bytes += h->caplen; if (unlikely(PacketCopyData(p, pkt, h->caplen))) { TmqhOutputPacketpool(ptv->tv, p); PACKET_PROFILING_TMM_END(p, TMM_RECEIVEPCAPFILE); SCReturn; } PACKET_PROFILING_TMM_END(p, TMM_RECEIVEPCAPFILE); if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { pcap_breakloop(pcap_g.pcap_handle); ptv->cb_result = TM_ECODE_FAILED; } SCReturn; }
static void PcapCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt) { SCEnter(); PcapThreadVars *ptv = (PcapThreadVars *)user; Packet *p = PacketGetFromQueueOrAlloc(); struct timeval current_time; if (unlikely(p == NULL)) { SCReturn; } PKT_SET_SRC(p, PKT_SRC_WIRE); p->ts.tv_sec = h->ts.tv_sec; p->ts.tv_usec = h->ts.tv_usec; SCLogDebug("p->ts.tv_sec %"PRIuMAX"", (uintmax_t)p->ts.tv_sec); p->datalink = ptv->datalink; ptv->pkts++; ptv->bytes += h->caplen; (void) SC_ATOMIC_ADD(ptv->livedev->pkts, 1); p->livedev = ptv->livedev; if (unlikely(PacketCopyData(p, pkt, h->caplen))) { TmqhOutputPacketpool(ptv->tv, p); SCReturn; } switch (ptv->checksum_mode) { case CHECKSUM_VALIDATION_AUTO: if (ptv->livedev->ignore_checksum) { p->flags |= PKT_IGNORE_CHECKSUM; } else if (ChecksumAutoModeCheck(ptv->pkts, SC_ATOMIC_GET(ptv->livedev->pkts), SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) { ptv->livedev->ignore_checksum = 1; p->flags |= PKT_IGNORE_CHECKSUM; } break; case CHECKSUM_VALIDATION_DISABLE: p->flags |= PKT_IGNORE_CHECKSUM; break; default: break; } if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { pcap_breakloop(ptv->pcap_handle); ptv->cb_result = TM_ECODE_FAILED; } /* Trigger one dump of stats every second */ TimeGet(¤t_time); if (current_time.tv_sec != ptv->last_stats_dump) { PcapDumpCounters(ptv); ptv->last_stats_dump = current_time.tv_sec; } SCReturn; }
static int NFQCallBack(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) { NFQThreadVars *ntv = (NFQThreadVars *)data; ThreadVars *tv = ntv->tv; int ret; /* grab a packet */ Packet *p = PacketGetFromQueueOrAlloc(); if (p == NULL) { return -1; } PKT_SET_SRC(p, PKT_SRC_WIRE); p->nfq_v.nfq_index = ntv->nfq_index; ret = NFQSetupPkt(p, qh, (void *)nfa); if (ret == -1) { #ifdef COUNTERS NFQQueueVars *nfq_q = NFQGetQueue(ntv->nfq_index); nfq_q->errs++; nfq_q->pkts++; nfq_q->bytes += GET_PKT_LEN(p); #endif /* COUNTERS */ /* recycle Packet and leave */ TmqhOutputPacketpool(tv, p); return 0; } #ifdef COUNTERS NFQQueueVars *nfq_q = NFQGetQueue(ntv->nfq_index); nfq_q->pkts++; nfq_q->bytes += GET_PKT_LEN(p); #endif /* COUNTERS */ if (ntv->slot) { if (TmThreadsSlotProcessPkt(tv, ntv->slot, p) != TM_ECODE_OK) { TmqhOutputPacketpool(ntv->tv, p); return -1; } } else { /* pass on... */ tv->tmqh_out(tv, p); } return 0; }
/** * \brief ERF file reading loop. */ TmEcode ReceiveErfFileLoop(ThreadVars *tv, void *data, void *slot) { Packet *p = NULL; uint16_t packet_q_len = 0; ErfFileThreadVars *etv = (ErfFileThreadVars *)data; etv->slot = ((TmSlot *)slot)->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 { #ifdef __tile__ packet_q_len = PacketPoolSize(0); #else packet_q_len = PacketPoolSize(); #endif if (unlikely(packet_q_len == 0)) { #ifdef __tile__ PacketPoolWait(0); #else PacketPoolWait(); #endif } } while (packet_q_len == 0); #ifdef __tile__ p = PacketGetFromQueueOrAlloc(0); #else p = PacketGetFromQueueOrAlloc(); #endif if (unlikely(p == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate a packet."); EngineStop(); SCReturnInt(TM_ECODE_FAILED); } PKT_SET_SRC(p, PKT_SRC_WIRE); if (ReadErfRecord(tv, p, data) != TM_ECODE_OK) { TmqhOutputPacketpool(etv->tv, p); EngineStop(); SCReturnInt(TM_ECODE_FAILED); } if (TmThreadsSlotProcessPkt(etv->tv, etv->slot, p) != TM_ECODE_OK) { EngineStop(); SCReturnInt(TM_ECODE_FAILED); } } SCReturnInt(TM_ECODE_FAILED); }
/** * \brief Setup a pseudo packet (tunnel) * * \param parent parent packet for this pseudo pkt * \param pkt raw packet data * \param len packet data length * \param proto protocol of the tunneled packet * * \retval p the pseudo packet or NULL if out of memory */ Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *parent, uint8_t *pkt, uint16_t len, enum DecodeTunnelProto proto, PacketQueue *pq) { int ret; SCEnter(); /* get us a packet */ Packet *p = PacketGetFromQueueOrAlloc(); if (unlikely(p == NULL)) { SCReturnPtr(NULL, "Packet"); } /* copy packet and set lenght, proto */ PacketCopyData(p, pkt, len); p->recursion_level = parent->recursion_level + 1; p->ts.tv_sec = parent->ts.tv_sec; p->ts.tv_usec = parent->ts.tv_usec; p->datalink = DLT_RAW; p->tenant_id = parent->tenant_id; /* set the root ptr to the lowest layer */ if (parent->root != NULL) p->root = parent->root; else p->root = parent; /* tell new packet it's part of a tunnel */ SET_TUNNEL_PKT(p); ret = DecodeTunnel(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq, proto); if (unlikely(ret != TM_ECODE_OK)) { /* Not a tunnel packet, just a pseudo packet */ p->root = NULL; UNSET_TUNNEL_PKT(p); TmqhOutputPacketpool(tv, p); SCReturnPtr(NULL, "Packet"); } /* tell parent packet it's part of a tunnel */ SET_TUNNEL_PKT(parent); /* increment tunnel packet refcnt in the root packet */ TUNNEL_INCR_PKT_TPR(p); /* disable payload (not packet) inspection on the parent, as the payload * is the packet we will now run through the system separately. We do * check it against the ip/port/other header checks though */ DecodeSetNoPayloadInspectionFlag(parent); SCReturnPtr(p, "Packet"); }
/** * \brief Release all the packets in the queue back to the packetpool. Mainly * used by threads that have failed, and wants to return the packets back * to the packetpool. * * \param pq Pointer to the packetqueue from which the packets have to be * returned back to the packetpool * * \warning this function assumes that the pq does not use locking */ void TmqhReleasePacketsToPacketPool(PacketQueue *pq) { Packet *p = NULL; if (pq == NULL) return; while ( (p = PacketDequeue(pq)) != NULL) TmqhOutputPacketpool(NULL, p); return; }
void PcapFileCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt) { SCEnter(); PcapFileFileVars *ptv = (PcapFileFileVars *)user; Packet *p = PacketGetFromQueueOrAlloc(); if (unlikely(p == NULL)) { SCReturn; } PACKET_PROFILING_TMM_START(p, TMM_RECEIVEPCAPFILE); PKT_SET_SRC(p, PKT_SRC_WIRE); p->ts.tv_sec = h->ts.tv_sec; p->ts.tv_usec = h->ts.tv_usec; SCLogDebug("p->ts.tv_sec %"PRIuMAX"", (uintmax_t)p->ts.tv_sec); p->datalink = ptv->datalink; p->pcap_cnt = ++pcap_g.cnt; p->pcap_v.tenant_id = ptv->shared->tenant_id; ptv->shared->pkts++; ptv->shared->bytes += h->caplen; if (unlikely(PacketCopyData(p, pkt, h->caplen))) { TmqhOutputPacketpool(ptv->shared->tv, p); PACKET_PROFILING_TMM_END(p, TMM_RECEIVEPCAPFILE); SCReturn; } /* We only check for checksum disable */ if (pcap_g.checksum_mode == CHECKSUM_VALIDATION_DISABLE) { p->flags |= PKT_IGNORE_CHECKSUM; } else if (pcap_g.checksum_mode == CHECKSUM_VALIDATION_AUTO) { if (ChecksumAutoModeCheck(ptv->shared->pkts, p->pcap_cnt, SC_ATOMIC_GET(pcap_g.invalid_checksums))) { pcap_g.checksum_mode = CHECKSUM_VALIDATION_DISABLE; p->flags |= PKT_IGNORE_CHECKSUM; } } PACKET_PROFILING_TMM_END(p, TMM_RECEIVEPCAPFILE); if (TmThreadsSlotProcessPkt(ptv->shared->tv, ptv->shared->slot, p) != TM_ECODE_OK) { pcap_breakloop(ptv->pcap_handle); ptv->shared->cb_result = TM_ECODE_FAILED; } SCReturn; }
/** \brief separate run function so we can call it recursively * * \todo deal with post_pq for slots beyond the first */ static inline TmEcode TmThreadsSlotVarRun (ThreadVars *tv, Packet *p, TmSlot *slot) { TmEcode r = TM_ECODE_OK; TmSlot *s = NULL; for (s = slot; s != NULL; s = s->slot_next) { if (s->id == 0) { r = s->SlotFunc(tv, p, s->slot_data, &s->slot_pre_pq, &s->slot_post_pq); } else { r = s->SlotFunc(tv, p, s->slot_data, &s->slot_pre_pq, NULL); } /* handle error */ if (r == TM_ECODE_FAILED) { /* Encountered error. Return packets to packetpool and return */ TmqhReleasePacketsToPacketPool(&s->slot_pre_pq); TmqhReleasePacketsToPacketPool(&s->slot_post_pq); TmThreadsSetFlag(tv, THV_FAILED); return TM_ECODE_FAILED; } /* handle new packets */ while (s->slot_pre_pq.top != NULL) { Packet *extra_p = PacketDequeue(&s->slot_pre_pq); if (extra_p == NULL) continue; /* see if we need to process the packet */ if (s->slot_next != NULL) { r = TmThreadsSlotVarRun(tv, extra_p, s->slot_next); /* XXX handle error */ if (r == TM_ECODE_FAILED) { //printf("TmThreadsSlotVarRun: recursive TmThreadsSlotVarRun returned 1\n"); TmqhReleasePacketsToPacketPool(&s->slot_pre_pq); TmqhReleasePacketsToPacketPool(&s->slot_post_pq); TmqhOutputPacketpool(tv, extra_p); TmThreadsSetFlag(tv, THV_FAILED); return TM_ECODE_FAILED; } } tv->tmqh_out(tv, extra_p); } /** \todo post pq */ } return 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; }
/** * \todo only the first "slot" currently makes the "post_pq" available * to the thread module. */ void *TmThreadsSlotVar(void *td) { ThreadVars *tv = (ThreadVars *)td; TmVarSlot *s = (TmVarSlot *)tv->tm_slots; Packet *p = NULL; char run = 1; TmEcode r = TM_ECODE_OK; TmSlot *slot = NULL; /* Set the thread name */ SCSetThreadName(tv->name); /* Drop the capabilities for this thread */ SCDropCaps(tv); if (tv->thread_setup_flags != 0) TmThreadSetupOptions(tv); /* check if we are setup properly */ if (s == NULL || s->s == NULL || tv->tmqh_in == NULL || tv->tmqh_out == NULL) { EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) -1); } for (slot = s->s; slot != NULL; slot = slot->slot_next) { if (slot->SlotThreadInit != NULL) { r = slot->SlotThreadInit(tv, slot->slot_initdata, &slot->slot_data); if (r != TM_ECODE_OK) { EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) -1); } } memset(&slot->slot_pre_pq, 0, sizeof(PacketQueue)); memset(&slot->slot_post_pq, 0, sizeof(PacketQueue)); } TmThreadsSetFlag(tv, THV_INIT_DONE); while(run) { TmThreadTestThreadUnPaused(tv); /* input a packet */ p = tv->tmqh_in(tv); if (p != NULL) { /* run the thread module(s) */ r = TmThreadsSlotVarRun(tv, p, s->s); if (r == TM_ECODE_FAILED) { TmqhOutputPacketpool(tv, p); TmThreadsSetFlag(tv, THV_FAILED); break; } /* output the packet */ tv->tmqh_out(tv, p); /* now handle the post_pq packets */ while (s->s->slot_post_pq.top != NULL) { Packet *extra_p = PacketDequeue(&s->s->slot_post_pq); if (extra_p == NULL) continue; if (s->s->slot_next != NULL) { r = TmThreadsSlotVarRun(tv, extra_p, s->s->slot_next); if (r == TM_ECODE_FAILED) { TmqhOutputPacketpool(tv, extra_p); TmThreadsSetFlag(tv, THV_FAILED); break; } } /* output the packet */ tv->tmqh_out(tv, extra_p); } } if (TmThreadsCheckFlag(tv, THV_KILL)) { run = 0; } } SCPerfUpdateCounterArray(tv->sc_perf_pca, &tv->sc_perf_pctx, 0); for (slot = s->s; slot != NULL; slot = slot->slot_next) { if (slot->SlotThreadExitPrintStats != NULL) { slot->SlotThreadExitPrintStats(tv, slot->slot_data); } if (slot->SlotThreadDeinit != NULL) { r = slot->SlotThreadDeinit(tv, slot->slot_data); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) -1); } } } SCLogDebug("%s ending", tv->name); TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 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; }
/** * \internal * \brief Forces reassembly for flow if it needs it. * * The function requires flow to be locked beforehand. * * \param f Pointer to the flow. * \param server action required for server: 1 or 2 * \param client action required for client: 1 or 2 * * \retval 0 This flow doesn't need any reassembly processing; 1 otherwise. */ int FlowForceReassemblyForFlow(Flow *f, int server, int client) { Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; TcpSession *ssn; /* looks like we have no flows in this queue */ if (f == NULL) { return 0; } /* Get the tcp session for the flow */ ssn = (TcpSession *)f->protoctx; if (ssn == NULL) { return 0; } /* The packets we use are based on what segments in what direction are * unprocessed. * p1 if we have client segments for reassembly purpose only. If we * have no server segments p2 can be a toserver packet with dummy * seq/ack, and if we have server segments p2 has to carry out reassembly * for server segment as well, in which case we will also need a p3 in the * toclient which is now dummy since all we need it for is detection */ /* insert a pseudo packet in the toserver direction */ if (client == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY) { p1 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 0); if (p1 == NULL) { goto done; } PKT_SET_SRC(p1, PKT_SRC_FFR); if (server == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY) { p2 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 0); if (p2 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); goto done; } PKT_SET_SRC(p2, PKT_SRC_FFR); p3 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p3 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); FlowDeReference(&p2->flow); TmqhOutputPacketpool(NULL, p2); goto done; } PKT_SET_SRC(p3, PKT_SRC_FFR); } else { p2 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1); if (p2 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); goto done; } PKT_SET_SRC(p2, PKT_SRC_FFR); } } else if (client == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION) { if (server == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY) { p1 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 0); if (p1 == NULL) { goto done; } PKT_SET_SRC(p1, PKT_SRC_FFR); p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p2 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); goto done; } PKT_SET_SRC(p2, PKT_SRC_FFR); } else { p1 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1); if (p1 == NULL) { goto done; } PKT_SET_SRC(p1, PKT_SRC_FFR); if (server == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION) { p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p2 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); goto done; } PKT_SET_SRC(p2, PKT_SRC_FFR); } } } else { if (server == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY) { p1 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 0); if (p1 == NULL) { goto done; } PKT_SET_SRC(p1, PKT_SRC_FFR); p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p2 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); goto done; } PKT_SET_SRC(p2, PKT_SRC_FFR); } else if (server == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION) { p1 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p1 == NULL) { goto done; } PKT_SET_SRC(p1, PKT_SRC_FFR); } else { /* impossible */ BUG_ON(1); } } /* inject the packet(s) into the appropriate thread */ int thread_id = (int)f->thread_id; Packet *packets[4] = { p1, p2 ? p2 : p3, p2 ? p3 : NULL, NULL }; /**< null terminated array of packets */ if (unlikely(!(TmThreadsInjectPacketsById(packets, thread_id)))) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); if (p2) { FlowDeReference(&p2->flow); TmqhOutputPacketpool(NULL, p2); } if (p3) { FlowDeReference(&p3->flow); TmqhOutputPacketpool(NULL, p3); } } /* done, in case of error (no packet) we still tag flow as complete * as we're probably resource stress if we couldn't get packets */ done: f->flags |= FLOW_TIMEOUT_REASSEMBLY_DONE; return 1; }
/** * \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); }
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); }
/** * \internal * \brief Forces reassembly for flows that need it. * * When this function is called we're running in virtually dead engine, * so locking the flows is not strictly required. The reasons it is still * done are: * - code consistency * - silence complaining profilers * - allow us to aggressively check using debug valdation assertions * - be robust in case of future changes * - locking overhead if neglectable when no other thread fights us * * \param q The queue to process flows from. */ static inline void FlowForceReassemblyForHash(void) { Flow *f; TcpSession *ssn; int client_ok; int server_ok; int tcp_needs_inspection; uint32_t idx = 0; /* We use this packet just for reassembly purpose */ Packet *reassemble_p = PacketGetFromAlloc(); if (reassemble_p == NULL) return; for (idx = 0; idx < flow_config.hash_size; idx++) { FlowBucket *fb = &flow_hash[idx]; FBLOCK_LOCK(fb); /* get the topmost flow from the QUEUE */ f = fb->head; /* we need to loop through all the flows in the queue */ while (f != NULL) { PACKET_RECYCLE(reassemble_p); FLOWLOCK_WRLOCK(f); /* Get the tcp session for the flow */ ssn = (TcpSession *)f->protoctx; /* \todo Also skip flows that shouldn't be inspected */ if (ssn == NULL) { FLOWLOCK_UNLOCK(f); f = f->hnext; continue; } /* ah ah! We have some unattended toserver segments */ if ((client_ok = StreamHasUnprocessedSegments(ssn, 0)) == 1) { StreamTcpThread *stt = SC_ATOMIC_GET(stream_pseudo_pkt_stream_tm_slot->slot_data); ssn->client.last_ack = (ssn->client.seg_list_tail->seq + ssn->client.seg_list_tail->payload_len); FlowForceReassemblyPseudoPacketSetup(reassemble_p, 1, f, ssn, 1); StreamTcpReassembleHandleSegment(stream_pseudo_pkt_stream_TV, stt->ra_ctx, ssn, &ssn->server, reassemble_p, NULL); FlowDeReference(&reassemble_p->flow); if (StreamTcpReassembleProcessAppLayer(stt->ra_ctx) < 0) { SCLogDebug("shutdown flow timeout " "StreamTcpReassembleProcessAppLayer() erroring " "over something"); } } /* oh oh! We have some unattended toclient segments */ if ((server_ok = StreamHasUnprocessedSegments(ssn, 1)) == 1) { StreamTcpThread *stt = SC_ATOMIC_GET(stream_pseudo_pkt_stream_tm_slot->slot_data); ssn->server.last_ack = (ssn->server.seg_list_tail->seq + ssn->server.seg_list_tail->payload_len); FlowForceReassemblyPseudoPacketSetup(reassemble_p, 0, f, ssn, 1); StreamTcpReassembleHandleSegment(stream_pseudo_pkt_stream_TV, stt->ra_ctx, ssn, &ssn->client, reassemble_p, NULL); FlowDeReference(&reassemble_p->flow); if (StreamTcpReassembleProcessAppLayer(stt->ra_ctx) < 0) { SCLogDebug("shutdown flow timeout " "StreamTcpReassembleProcessAppLayer() erroring " "over something"); } } if (ssn->state >= TCP_ESTABLISHED && ssn->state != TCP_CLOSED) tcp_needs_inspection = 1; else tcp_needs_inspection = 0; FLOWLOCK_UNLOCK(f); /* insert a pseudo packet in the toserver direction */ if (client_ok || tcp_needs_inspection) { FLOWLOCK_WRLOCK(f); Packet *p = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1); FLOWLOCK_UNLOCK(f); if (p == NULL) { TmqhOutputPacketpool(NULL, reassemble_p); FBLOCK_UNLOCK(fb); return; } PKT_SET_SRC(p, PKT_SRC_FFR_SHUTDOWN); if (stream_pseudo_pkt_detect_prev_TV != NULL) { stream_pseudo_pkt_detect_prev_TV-> tmqh_out(stream_pseudo_pkt_detect_prev_TV, p); } else { TmSlot *s = stream_pseudo_pkt_detect_tm_slot; while (s != NULL) { TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); SlotFunc(NULL, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, &s->slot_post_pq); s = s->slot_next; } if (stream_pseudo_pkt_detect_TV != NULL) { stream_pseudo_pkt_detect_TV-> tmqh_out(stream_pseudo_pkt_detect_TV, p); } else { TmqhOutputPacketpool(NULL, p); } } } /* if (ssn->client.seg_list != NULL) */ if (server_ok || tcp_needs_inspection) { FLOWLOCK_WRLOCK(f); Packet *p = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); FLOWLOCK_UNLOCK(f); if (p == NULL) { TmqhOutputPacketpool(NULL, reassemble_p); FBLOCK_UNLOCK(fb); return; } PKT_SET_SRC(p, PKT_SRC_FFR_SHUTDOWN); if (stream_pseudo_pkt_detect_prev_TV != NULL) { stream_pseudo_pkt_detect_prev_TV-> tmqh_out(stream_pseudo_pkt_detect_prev_TV, p); } else { TmSlot *s = stream_pseudo_pkt_detect_tm_slot; while (s != NULL) { TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); SlotFunc(NULL, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, &s->slot_post_pq); s = s->slot_next; } if (stream_pseudo_pkt_detect_TV != NULL) { stream_pseudo_pkt_detect_TV-> tmqh_out(stream_pseudo_pkt_detect_TV, p); } else { TmqhOutputPacketpool(NULL, p); } } } /* if (ssn->server.seg_list != NULL) */ /* next flow in the queue */ f = f->hnext; } /* while (f != NULL) */ FBLOCK_UNLOCK(fb); } PKT_SET_SRC(reassemble_p, PKT_SRC_FFR_SHUTDOWN); TmqhOutputPacketpool(NULL, reassemble_p); return; }
/** * \internal * \brief Forces reassembly for flow if it needs it. * * The function requires flow to be locked beforehand. * * \param f Pointer to the flow. * \param server action required for server: 1 or 2 * \param client action required for client: 1 or 2 * * \retval 0 This flow doesn't need any reassembly processing; 1 otherwise. */ int FlowForceReassemblyForFlowV2(Flow *f, int server, int client) { Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; TcpSession *ssn; /* looks like we have no flows in this queue */ if (f == NULL) { return 0; } /* Get the tcp session for the flow */ ssn = (TcpSession *)f->protoctx; if (ssn == NULL) { return 0; } /* The packets we use are based on what segments in what direction are * unprocessed. * p1 if we have client segments for reassembly purpose only. If we * have no server segments p2 can be a toserver packet with dummy * seq/ack, and if we have server segments p2 has to carry out reassembly * for server segment as well, in which case we will also need a p3 in the * toclient which is now dummy since all we need it for is detection */ /* insert a pseudo packet in the toserver direction */ if (client == 1) { p1 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 0); if (p1 == NULL) { return 1; } PKT_SET_SRC(p1, PKT_SRC_FFR_V2); if (server == 1) { p2 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 0); if (p2 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); return 1; } PKT_SET_SRC(p2, PKT_SRC_FFR_V2); p3 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p3 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); FlowDeReference(&p2->flow); TmqhOutputPacketpool(NULL, p2); return 1; } PKT_SET_SRC(p3, PKT_SRC_FFR_V2); } else { p2 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1); if (p2 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); return 1; } PKT_SET_SRC(p2, PKT_SRC_FFR_V2); } } else if (client == 2) { if (server == 1) { p1 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 0); if (p1 == NULL) { return 1; } PKT_SET_SRC(p1, PKT_SRC_FFR_V2); p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p2 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); return 1; } PKT_SET_SRC(p2, PKT_SRC_FFR_V2); } else { p1 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1); if (p1 == NULL) { return 1; } PKT_SET_SRC(p1, PKT_SRC_FFR_V2); if (server == 2) { p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p2 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); return 1; } PKT_SET_SRC(p2, PKT_SRC_FFR_V2); } } } else { if (server == 1) { p1 = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 0); if (p1 == NULL) { return 1; } PKT_SET_SRC(p1, PKT_SRC_FFR_V2); p2 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p2 == NULL) { FlowDeReference(&p1->flow); TmqhOutputPacketpool(NULL, p1); return 1; } PKT_SET_SRC(p2, PKT_SRC_FFR_V2); } else if (server == 2) { p1 = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); if (p1 == NULL) { return 1; } PKT_SET_SRC(p1, PKT_SRC_FFR_V2); } else { /* impossible */ BUG_ON(1); } } f->flags |= FLOW_TIMEOUT_REASSEMBLY_DONE; SCMutexLock(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq.mutex_q); PacketEnqueue(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq, p1); if (p2 != NULL) PacketEnqueue(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq, p2); if (p3 != NULL) PacketEnqueue(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq, p3); SCMutexUnlock(&stream_pseudo_pkt_decode_tm_slot->slot_post_pq.mutex_q); if (stream_pseudo_pkt_decode_TV->inq != NULL) { SCCondSignal(&trans_q[stream_pseudo_pkt_decode_TV->inq->id].cond_q); } return 1; }
/** * \internal * \brief Forces reassembly for flows that need it. * * When this function is called we're running in virtually dead engine, * so locking the flows is not strictly required. The reasons it is still * done are: * - code consistency * - silence complaining profilers * - allow us to aggressively check using debug valdation assertions * - be robust in case of future changes * - locking overhead if neglectable when no other thread fights us * * \param q The queue to process flows from. */ static inline void FlowForceReassemblyForHash(void) { Flow *f; TcpSession *ssn; int client_ok; int server_ok; uint32_t idx = 0; /* We use this packet just for reassembly purpose */ Packet *reassemble_p = PacketGetFromAlloc(); if (reassemble_p == NULL) return; for (idx = 0; idx < flow_config.hash_size; idx++) { FlowBucket *fb = &flow_hash[idx]; FBLOCK_LOCK(fb); /* get the topmost flow from the QUEUE */ f = fb->head; /* we need to loop through all the flows in the queue */ while (f != NULL) { PACKET_RECYCLE(reassemble_p); FLOWLOCK_WRLOCK(f); /* Get the tcp session for the flow */ ssn = (TcpSession *)f->protoctx; /* \todo Also skip flows that shouldn't be inspected */ if (ssn == NULL) { FLOWLOCK_UNLOCK(f); f = f->hnext; continue; } (void)FlowForceReassemblyNeedReassembly(f, &server_ok, &client_ok); /* ah ah! We have some unattended toserver segments */ if (client_ok == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY) { StreamTcpThread *stt = SC_ATOMIC_GET(stream_pseudo_pkt_stream_tm_slot->slot_data); ssn->client.last_ack = (ssn->client.seg_list_tail->seq + ssn->client.seg_list_tail->payload_len); FlowForceReassemblyPseudoPacketSetup(reassemble_p, 1, f, ssn, 1); StreamTcpReassembleHandleSegment(stream_pseudo_pkt_stream_TV, stt->ra_ctx, ssn, &ssn->server, reassemble_p, NULL); FlowDeReference(&reassemble_p->flow); } /* oh oh! We have some unattended toclient segments */ if (server_ok == STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY) { StreamTcpThread *stt = SC_ATOMIC_GET(stream_pseudo_pkt_stream_tm_slot->slot_data); ssn->server.last_ack = (ssn->server.seg_list_tail->seq + ssn->server.seg_list_tail->payload_len); FlowForceReassemblyPseudoPacketSetup(reassemble_p, 0, f, ssn, 1); StreamTcpReassembleHandleSegment(stream_pseudo_pkt_stream_TV, stt->ra_ctx, ssn, &ssn->client, reassemble_p, NULL); FlowDeReference(&reassemble_p->flow); } FLOWLOCK_UNLOCK(f); /* insert a pseudo packet in the toserver direction */ if (client_ok) { FLOWLOCK_WRLOCK(f); Packet *p = FlowForceReassemblyPseudoPacketGet(0, f, ssn, 1); FLOWLOCK_UNLOCK(f); if (p == NULL) { TmqhOutputPacketpool(NULL, reassemble_p); FBLOCK_UNLOCK(fb); return; } PKT_SET_SRC(p, PKT_SRC_FFR_SHUTDOWN); if (stream_pseudo_pkt_detect_prev_TV != NULL) { stream_pseudo_pkt_detect_prev_TV-> tmqh_out(stream_pseudo_pkt_detect_prev_TV, p); } else { TmSlot *s = stream_pseudo_pkt_detect_tm_slot; while (s != NULL) { TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); SlotFunc(NULL, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, &s->slot_post_pq); s = s->slot_next; } if (stream_pseudo_pkt_detect_TV != NULL) { stream_pseudo_pkt_detect_TV-> tmqh_out(stream_pseudo_pkt_detect_TV, p); } else { TmqhOutputPacketpool(NULL, p); } } } if (server_ok) { FLOWLOCK_WRLOCK(f); Packet *p = FlowForceReassemblyPseudoPacketGet(1, f, ssn, 1); FLOWLOCK_UNLOCK(f); if (p == NULL) { TmqhOutputPacketpool(NULL, reassemble_p); FBLOCK_UNLOCK(fb); return; } PKT_SET_SRC(p, PKT_SRC_FFR_SHUTDOWN); if (stream_pseudo_pkt_detect_prev_TV != NULL) { stream_pseudo_pkt_detect_prev_TV-> tmqh_out(stream_pseudo_pkt_detect_prev_TV, p); } else { TmSlot *s = stream_pseudo_pkt_detect_tm_slot; while (s != NULL) { TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc); SlotFunc(NULL, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, &s->slot_post_pq); s = s->slot_next; } if (stream_pseudo_pkt_detect_TV != NULL) { stream_pseudo_pkt_detect_TV-> tmqh_out(stream_pseudo_pkt_detect_TV, p); } else { TmqhOutputPacketpool(NULL, p); } } } /* next flow in the queue */ f = f->hnext; } FBLOCK_UNLOCK(fb); } PKT_SET_SRC(reassemble_p, PKT_SRC_FFR_SHUTDOWN); TmqhOutputPacketpool(NULL, reassemble_p); return; }
void *TmThreadsSlot1NoOut(void *td) { ThreadVars *tv = (ThreadVars *)td; Tm1Slot *s = (Tm1Slot *)tv->tm_slots; Packet *p = NULL; char run = 1; TmEcode r = TM_ECODE_OK; /* Set the thread name */ SCSetThreadName(tv->name); /* Drop the capabilities for this thread */ SCDropCaps(tv); if (tv->thread_setup_flags != 0) TmThreadSetupOptions(tv); if (s->s.SlotThreadInit != NULL) { r = s->s.SlotThreadInit(tv, s->s.slot_initdata, &s->s.slot_data); if (r != TM_ECODE_OK) { EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) -1); } } memset(&s->s.slot_pre_pq, 0, sizeof(PacketQueue)); memset(&s->s.slot_post_pq, 0, sizeof(PacketQueue)); TmThreadsSetFlag(tv, THV_INIT_DONE); while(run) { TmThreadTestThreadUnPaused(tv); p = tv->tmqh_in(tv); r = s->s.SlotFunc(tv, p, s->s.slot_data, /* no outqh no pq */NULL, /* no outqh no pq */NULL); /* handle error */ if (r == TM_ECODE_FAILED) { TmqhOutputPacketpool(tv, p); TmThreadsSetFlag(tv, THV_FAILED); break; } if (TmThreadsCheckFlag(tv, THV_KILL)) { SCPerfUpdateCounterArray(tv->sc_perf_pca, &tv->sc_perf_pctx, 0); run = 0; } } if (s->s.SlotThreadExitPrintStats != NULL) { s->s.SlotThreadExitPrintStats(tv, s->s.slot_data); } if (s->s.SlotThreadDeinit != NULL) { r = s->s.SlotThreadDeinit(tv, s->s.slot_data); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) -1); } } TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); }
void *TmThreadsSlot1(void *td) { ThreadVars *tv = (ThreadVars *)td; Tm1Slot *s = (Tm1Slot *)tv->tm_slots; Packet *p = NULL; char run = 1; TmEcode r = TM_ECODE_OK; /* Set the thread name */ SCSetThreadName(tv->name); /* Drop the capabilities for this thread */ SCDropCaps(tv); if (tv->thread_setup_flags != 0) TmThreadSetupOptions(tv); SCLogDebug("%s starting", tv->name); if (s->s.SlotThreadInit != NULL) { r = s->s.SlotThreadInit(tv, s->s.slot_initdata, &s->s.slot_data); if (r != TM_ECODE_OK) { EngineKill(); TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) -1); } } memset(&s->s.slot_pre_pq, 0, sizeof(PacketQueue)); memset(&s->s.slot_post_pq, 0, sizeof(PacketQueue)); TmThreadsSetFlag(tv, THV_INIT_DONE); while(run) { TmThreadTestThreadUnPaused(tv); /* input a packet */ p = tv->tmqh_in(tv); if (p == NULL) { //printf("%s: TmThreadsSlot1: p == NULL\n", tv->name); } else { r = s->s.SlotFunc(tv, p, s->s.slot_data, &s->s.slot_pre_pq, &s->s.slot_post_pq); /* handle error */ if (r == TM_ECODE_FAILED) { TmqhReleasePacketsToPacketPool(&s->s.slot_pre_pq); TmqhReleasePacketsToPacketPool(&s->s.slot_post_pq); TmqhOutputPacketpool(tv, p); TmThreadsSetFlag(tv, THV_FAILED); break; } while (s->s.slot_pre_pq.top != NULL) { /* handle new packets from this func */ Packet *extra_p = PacketDequeue(&s->s.slot_pre_pq); if (extra_p != NULL) { tv->tmqh_out(tv, extra_p); } } /* output the packet */ tv->tmqh_out(tv, p); while (s->s.slot_post_pq.top != NULL) { /* handle new packets from this func */ Packet *extra_p = PacketDequeue(&s->s.slot_post_pq); if (extra_p != NULL) { tv->tmqh_out(tv, extra_p); } } } if (TmThreadsCheckFlag(tv, THV_KILL)) { //printf("%s: TmThreadsSlot1: KILL is set\n", tv->name); SCPerfUpdateCounterArray(tv->sc_perf_pca, &tv->sc_perf_pctx, 0); run = 0; } } if (s->s.SlotThreadExitPrintStats != NULL) { s->s.SlotThreadExitPrintStats(tv, s->s.slot_data); } if (s->s.SlotThreadDeinit != NULL) { r = s->s.SlotThreadDeinit(tv, s->s.slot_data); if (r != TM_ECODE_OK) { TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) -1); } } SCLogDebug("%s ending", tv->name); TmThreadsSetFlag(tv, THV_CLOSED); pthread_exit((void *) 0); }
/** * \brief Process a DAG record into a TM packet buffer. * \param prec pointer to a DAG record. * \param */ static inline TmEcode ProcessErfDagRecord(ErfDagThreadVars *ewtn, char *prec) { SCEnter(); int wlen = 0; int rlen = 0; int hdr_num = 0; char hdr_type = 0; dag_record_t *dr = (dag_record_t*)prec; erf_payload_t *pload; Packet *p; hdr_type = dr->type; wlen = ntohs(dr->wlen); rlen = ntohs(dr->rlen); /* count extension headers */ while (hdr_type & 0x80) { if (rlen < (dag_record_size + (hdr_num * 8))) { SCLogError(SC_ERR_UNIMPLEMENTED, "Insufficient captured packet length."); SCReturnInt(TM_ECODE_FAILED); } hdr_type = prec[(dag_record_size + (hdr_num * 8))]; hdr_num++; } /* Check that the whole frame was captured */ if (rlen < (dag_record_size + (8 * hdr_num) + 2 + wlen)) { SCLogInfo("Incomplete frame captured."); SCReturnInt(TM_ECODE_OK); } /* skip over extension headers */ pload = (erf_payload_t *)(prec + dag_record_size + (8 * hdr_num)); p = PacketGetFromQueueOrAlloc(); if (p == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate a Packet on stream: %d, DAG: %s", ewtn->dagstream, ewtn->dagname); SCReturnInt(TM_ECODE_FAILED); } PKT_SET_SRC(p, PKT_SRC_WIRE); SET_PKT_LEN(p, wlen); p->datalink = LINKTYPE_ETHERNET; /* Take into account for link type Ethernet ETH frame starts * after ther ERF header + pad. */ if (unlikely(PacketCopyData(p, pload->eth.dst, GET_PKT_LEN(p)))) { TmqhOutputPacketpool(ewtn->tv, p); SCReturnInt(TM_ECODE_FAILED); } /* Convert ERF time to timeval - from libpcap. */ uint64_t ts = dr->ts; p->ts.tv_sec = ts >> 32; ts = (ts & 0xffffffffULL) * 1000000; ts += 0x80000000; /* rounding */ p->ts.tv_usec = ts >> 32; if (p->ts.tv_usec >= 1000000) { p->ts.tv_usec -= 1000000; p->ts.tv_sec++; } SCPerfCounterIncr(ewtn->packets, ewtn->tv->sc_perf_pca); ewtn->bytes += wlen; if (TmThreadsSlotProcessPkt(ewtn->tv, ewtn->slot, p) != TM_ECODE_OK) { TmqhOutputPacketpool(ewtn->tv, p); SCReturnInt(TM_ECODE_FAILED); } SCReturnInt(TM_ECODE_OK); }
/** * \brief Main Napatech reading Loop function */ TmEcode NapatechFeedLoop(ThreadVars *tv, void *data, void *slot) { SCEnter(); int32_t status; int32_t caplen; PCAP_HEADER *header; uint8_t *frame; uint16_t packet_q_len = 0; NapatechThreadVars *ntv = (NapatechThreadVars *)data; int r; TmSlot *s = (TmSlot *)slot; ntv->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); /* * Napatech returns frames in segment chunks. Function ntci_next_frame * returns 1 for a frame, 0 if the segment is empty, and -1 on error */ status = napatech_next_frame (ntv->feed, &header, &frame); if (status == 0) { /* * no frames currently available */ continue; } else if (status < 0) { SCLogError(SC_ERR_NAPATECH_FEED_NEXT_FAILED, "Failed to read from Napatech feed %d:%d", ntv->adapter_number, ntv->feed_number); SCReturnInt(TM_ECODE_FAILED); } // beware that storelen is aligned; therefore, it may be larger than "caplen" caplen = (header->wireLen < header->storeLen) ? header->wireLen : header->storeLen; Packet *p = PacketGetFromQueueOrAlloc(); if (unlikely(p == NULL)) { SCReturnInt(TM_ECODE_FAILED); } p->ts.tv_sec = header->ts.tv_sec; p->ts.tv_usec = header->ts.tv_usec; SCLogDebug("p->ts.tv_sec %"PRIuMAX"", (uintmax_t)p->ts.tv_sec); p->datalink = LINKTYPE_ETHERNET; ntv->pkts++; ntv->bytes += caplen; if (unlikely(PacketCopyData(p, frame, caplen))) { TmqhOutputPacketpool(ntv->tv, p); SCReturnInt(TM_ECODE_FAILED); } if (TmThreadsSlotProcessPkt(ntv->tv, ntv->slot, p) != TM_ECODE_OK) { TmqhOutputPacketpool(ntv->tv, p); SCReturnInt(TM_ECODE_FAILED); } } SCReturnInt(TM_ECODE_OK); }