TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); DecodeThreadVars *dtv = (DecodeThreadVars *)data; /* update counters */ SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, (GET_PKT_LEN(p) * 8)/1000000.0 ); #endif SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); double curr_ts = p->ts.tv_sec + p->ts.tv_usec / 1000.0; if (curr_ts < prev_signaled_ts || (curr_ts - prev_signaled_ts) > 60.0) { prev_signaled_ts = curr_ts; FlowWakeupFlowManagerThread(); } /* update the engine time representation based on the timestamp * of the packet. */ TimeSet(&p->ts); /* call the decoder */ pcap_g.Decoder(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); SCReturnInt(TM_ECODE_OK); }
/** * \brief This function passes off to link type decoders. * * DecodeErfDag reads packets from the PacketQueue and passes * them off to the proper link type decoder. * * \param t pointer to ThreadVars * \param p pointer to the current packet * \param data pointer that gets cast into PcapThreadVars for ptv * \param pq pointer to the current PacketQueue */ TmEcode DecodeErfDag(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); DecodeThreadVars *dtv = (DecodeThreadVars *)data; /* update counters */ SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, (GET_PKT_LEN(p) * 8)/1000000.0); #endif SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); /* call the decoder */ switch(p->datalink) { case LINKTYPE_ETHERNET: DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; default: SCLogError(SC_ERR_DATALINK_UNIMPLEMENTED, "Error: datalink type %" PRId32 " not yet supported in module DecodeErfDag", p->datalink); break; } SCReturnInt(TM_ECODE_OK); }
/** * \brief This function passes off to link type decoders. * \todo Unit tests are needed for this module. * * DecodeIPFW reads packets from the PacketQueue and passes * them off to the proper link type decoder. * * \param tv pointer to ThreadVars * \param p pointer to the current packet * \param data pointer that gets cast into IPFWThreadVars for ptv * \param pq pointer to the PacketQueue */ TmEcode DecodeIPFW(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { IPV4Hdr *ip4h = (IPV4Hdr *)GET_PKT_DATA(p); IPV6Hdr *ip6h = (IPV6Hdr *)GET_PKT_DATA(p); DecodeThreadVars *dtv = (DecodeThreadVars *)data; SCEnter(); /* update counters */ SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); /* Process IP packets */ if (IPV4_GET_RAW_VER(ip4h) == 4) { SCLogDebug("DecodeIPFW ip4 processing"); DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else if(IPV6_GET_RAW_VER(ip6h) == 6) { SCLogDebug("DecodeIPFW ip6 processing"); DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else { /* We don't support anything besides IP packets for now, bridged packets? */ SCLogInfo("IPFW unknown protocol support %02x", *GET_PKT_DATA(p)); SCReturnInt(TM_ECODE_FAILED); } SCReturnInt(TM_ECODE_OK); }
int DecodeUDP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_udp, tv->sc_perf_pca); if (unlikely(DecodeUDPPacket(tv, p,pkt,len) < 0)) { p->udph = NULL; return TM_ECODE_FAILED; } SCLogDebug("UDP sp: %" PRIu32 " -> dp: %" PRIu32 " - HLEN: %" PRIu32 " LEN: %" PRIu32 "", UDP_GET_SRC_PORT(p), UDP_GET_DST_PORT(p), UDP_HEADER_LEN, p->payload_len); if (unlikely(DecodeTeredo(tv, dtv, p, p->payload, p->payload_len, pq) == TM_ECODE_OK)) { /* Here we have a Teredo packet and don't need to handle app * layer */ FlowHandlePacket(tv, p); return TM_ECODE_OK; } /* Flow is an integral part of us */ FlowHandlePacket(tv, p); /* handle the app layer part of the UDP packet payload */ if (unlikely(p->flow != NULL)) { AppLayerHandleUdp(&dtv->udp_dp_ctx, p->flow, p); } return TM_ECODE_OK; }
void DecodeSll(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_sll, tv->sc_perf_pca); if (len < SLL_HEADER_LEN) { DECODER_SET_EVENT(p,SLL_PKT_TOO_SMALL); return; } SllHdr *sllh = (SllHdr *)pkt; if (sllh == NULL) return; SCLogDebug("p %p pkt %p sll_protocol %04x", p, pkt, ntohs(sllh->sll_protocol)); switch (ntohs(sllh->sll_protocol)) { case ETHERNET_TYPE_IP: DecodeIPV4(tv, dtv, p, pkt + SLL_HEADER_LEN, len - SLL_HEADER_LEN, pq); break; case ETHERNET_TYPE_IPV6: DecodeIPV6(tv, dtv, p, pkt + SLL_HEADER_LEN, len - SLL_HEADER_LEN, pq); break; case ETHERNET_TYPE_VLAN: DecodeVLAN(tv, dtv, p, pkt + SLL_HEADER_LEN, len - SLL_HEADER_LEN, pq); break; default: SCLogDebug("p %p pkt %p sll type %04x not supported", p, pkt, ntohs(sllh->sll_protocol)); } }
/** * \brief Decode a packet coming from NFQ */ TmEcode DecodeNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { IPV4Hdr *ip4h = (IPV4Hdr *)GET_PKT_DATA(p); IPV6Hdr *ip6h = (IPV6Hdr *)GET_PKT_DATA(p); DecodeThreadVars *dtv = (DecodeThreadVars *)data; SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, (GET_PKT_LEN(p) * 8)/1000000.0); #endif if (IPV4_GET_RAW_VER(ip4h) == 4) { SCLogDebug("IPv4 packet"); DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else if(IPV6_GET_RAW_VER(ip6h) == 6) { SCLogDebug("IPv6 packet"); DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else { SCLogDebug("packet unsupported by NFQ, first byte: %02x", *GET_PKT_DATA(p)); } return TM_ECODE_OK; }
/** * \brief This function passes off to link type decoders. * * NapatechDecode reads packets from the PacketQueue and passes * them off to the proper link type decoder. * * \param t pointer to ThreadVars * \param p pointer to the current packet * \param data pointer that gets cast into PcapThreadVars for ptv * \param pq pointer to the current PacketQueue */ TmEcode NapatechDecode(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); DecodeThreadVars *dtv = (DecodeThreadVars *)data; /* XXX HACK: flow timeout can call us for injected pseudo packets * see bug: https://redmine.openinfosecfoundation.org/issues/1107 */ if (p->flags & PKT_PSEUDO_STREAM_END) return TM_ECODE_OK; /* update counters */ SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); // SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); switch (p->datalink) { case LINKTYPE_ETHERNET: DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); break; default: SCLogError(SC_ERR_DATALINK_UNIMPLEMENTED, "Error: datalink type %" PRId32 " not yet supported in module NapatechDecode", p->datalink); break; } PacketDecodeFinalize(tv, dtv, p); SCReturnInt(TM_ECODE_OK); }
void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) { if (p->flags & PKT_IS_INVALID) SCPerfCounterIncr(dtv->counter_invalid, tv->sc_perf_pca); #ifdef __SC_CUDA_SUPPORT__ if (dtv->cuda_vars.mpm_is_cuda) CudaBufferPacket(&dtv->cuda_vars, p); #endif }
/** * \brief Decode the ERF file. * * This function ups the decoder counters and then passes the packet * off to the ethernet decoder. */ TmEcode DecodeErfFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); DecodeThreadVars *dtv = (DecodeThreadVars *)data; /* Update counters. */ SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, (GET_PKT_LEN(p) * 8)/1000000.0 ); #endif SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); DecodeEthernet(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); SCReturnInt(TM_ECODE_OK); }
/** * \internal * \brief this function is used to decode IEEE802.1q packets * * \param tv pointer to the thread vars * \param dtv pointer code thread vars * \param p pointer to the packet struct * \param pkt pointer to the raw packet * \param len packet len * \param pq pointer to the packet queue * */ void DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_vlan, tv->sc_perf_pca); if(len < VLAN_HEADER_LEN) { DECODER_SET_EVENT(p,VLAN_HEADER_TOO_SMALL); return; } p->vlanh = (VLANHdr *)pkt; if(p->vlanh == NULL) return; SCLogDebug("p %p pkt %p VLAN protocol %04x VLAN PRI %d VLAN CFI %d VLAN ID %d Len: %" PRId32 "", p, pkt, GET_VLAN_PROTO(p->vlanh), GET_VLAN_PRIORITY(p->vlanh), GET_VLAN_CFI(p->vlanh), GET_VLAN_ID(p->vlanh), len); switch (GET_VLAN_PROTO(p->vlanh)) { case ETHERNET_TYPE_IP: DecodeIPV4(tv, dtv, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, pq); break; case ETHERNET_TYPE_IPV6: DecodeIPV6(tv, dtv, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, pq); break; case ETHERNET_TYPE_PPPOE_SESS: DecodePPPOESession(tv, dtv, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, pq); break; case ETHERNET_TYPE_PPPOE_DISC: DecodePPPOEDiscovery(tv, dtv, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, pq); break; case ETHERNET_TYPE_VLAN: DecodeVLAN(tv, dtv, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, pq); break; default: SCLogDebug("unknown VLAN type: %" PRIx32 "",GET_VLAN_PROTO(p->vlanh)); DECODER_SET_EVENT(p,VLAN_UNKNOWN_TYPE); return; } return; }
TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { SCEnter(); DecodeThreadVars *dtv = (DecodeThreadVars *)data; /* XXX HACK: flow timeout can call us for injected pseudo packets * see bug: https://redmine.openinfosecfoundation.org/issues/1107 */ if (p->flags & PKT_PSEUDO_STREAM_END) return TM_ECODE_OK; /* update counters */ SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); // SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, (GET_PKT_LEN(p) * 8)/1000000.0 ); #endif SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); double curr_ts = p->ts.tv_sec + p->ts.tv_usec / 1000.0; if (curr_ts < prev_signaled_ts || (curr_ts - prev_signaled_ts) > 60.0) { prev_signaled_ts = curr_ts; FlowWakeupFlowManagerThread(); } /* update the engine time representation based on the timestamp * of the packet. */ TimeSet(&p->ts); /* call the decoder */ pcap_g.Decoder(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); #ifdef DEBUG BUG_ON(p->pkt_src != PKT_SRC_WIRE && p->pkt_src != PKT_SRC_FFR_V2); #endif PacketDecodeFinalize(tv, dtv, p); SCReturnInt(TM_ECODE_OK); }
void DecodeRaw(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_raw, tv->sc_perf_pca); /* If it is ipv4 or ipv6 it should at least be the size of ipv4 */ if (len < IPV4_HEADER_LEN) { ENGINE_SET_EVENT(p,IPV4_PKT_TOO_SMALL); return; } if (IP_GET_RAW_VER(pkt) == 4) { SCLogDebug("IPV4 Packet"); DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else if (IP_GET_RAW_VER(pkt) == 6) { SCLogDebug("IPV6 Packet"); DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else { SCLogDebug("Unknown ip version %" PRIu8 "", IP_GET_RAW_VER(pkt)); ENGINE_SET_EVENT(p,IPRAW_INVALID_IPV); } return; }
/** * \brief This function passes off to link type decoders. * \todo Unit tests are needed for this module. * * DecodeIPFW reads packets from the PacketQueue and passes * them off to the proper link type decoder. * * \param tv pointer to ThreadVars * \param p pointer to the current packet * \param data pointer that gets cast into IPFWThreadVars for ptv * \param pq pointer to the PacketQueue */ TmEcode DecodeIPFW(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { IPV4Hdr *ip4h = (IPV4Hdr *)GET_PKT_DATA(p); IPV6Hdr *ip6h = (IPV6Hdr *)GET_PKT_DATA(p); DecodeThreadVars *dtv = (DecodeThreadVars *)data; SCEnter(); /* XXX HACK: flow timeout can call us for injected pseudo packets * see bug: https://redmine.openinfosecfoundation.org/issues/1107 */ if (p->flags & PKT_PSEUDO_STREAM_END) return TM_ECODE_OK; /* update counters */ SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); /* Process IP packets */ if (IPV4_GET_RAW_VER(ip4h) == 4) { SCLogDebug("DecodeIPFW ip4 processing"); DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else if(IPV6_GET_RAW_VER(ip6h) == 6) { SCLogDebug("DecodeIPFW ip6 processing"); DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else { /* We don't support anything besides IP packets for now, bridged packets? */ SCLogInfo("IPFW unknown protocol support %02x", *GET_PKT_DATA(p)); SCReturnInt(TM_ECODE_FAILED); } PacketDecodeFinalize(tv, dtv, p); SCReturnInt(TM_ECODE_OK); }
void DecodeTCP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_tcp, tv->sc_perf_pca); if (unlikely(DecodeTCPPacket(tv, p,pkt,len) < 0)) { SCLogDebug("invalid TCP packet"); p->tcph = NULL; return; } #ifdef DEBUG SCLogDebug("TCP sp: %" PRIu32 " -> dp: %" PRIu32 " - HLEN: %" PRIu32 " LEN: %" PRIu32 " %s%s%s%s%s", GET_TCP_SRC_PORT(p), GET_TCP_DST_PORT(p), TCP_GET_HLEN(p), len, p->tcpvars.sackok ? "SACKOK " : "", p->tcpvars.sack ? "SACK " : "", p->tcpvars.ws ? "WS " : "", p->tcpvars.ts ? "TS " : "", p->tcpvars.mss ? "MSS " : ""); #endif /* Flow is an integral part of us */ FlowHandlePacket(tv, p); return; }
/** * \brief Function to decode IPv4 in IPv6 packets * */ static void DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t plen, PacketQueue *pq) { if (unlikely(plen < IPV6_HEADER_LEN)) { ENGINE_SET_EVENT(p, IPV6_IN_IPV6_PKT_TOO_SMALL); return; } if (IP_GET_RAW_VER(pkt) == 6) { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt, plen, IPPROTO_IPV6); if (tp != NULL) { DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, IPPROTO_IP); PacketEnqueue(pq,tp); SCPerfCounterIncr(dtv->counter_ipv6inipv6, tv->sc_perf_pca); return; } } } else { ENGINE_SET_EVENT(p, IPV6_IN_IPV6_WRONG_IP_VER); } return; }
/** * \brief Decode a packet coming from NFQ */ TmEcode DecodeNFQ(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) { IPV4Hdr *ip4h = (IPV4Hdr *)GET_PKT_DATA(p); IPV6Hdr *ip6h = (IPV6Hdr *)GET_PKT_DATA(p); DecodeThreadVars *dtv = (DecodeThreadVars *)data; /* XXX HACK: flow timeout can call us for injected pseudo packets * see bug: https://redmine.openinfosecfoundation.org/issues/1107 */ if (p->flags & PKT_PSEUDO_STREAM_END) return TM_ECODE_OK; SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p)); #if 0 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p)); SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, (GET_PKT_LEN(p) * 8)/1000000.0); #endif if (IPV4_GET_RAW_VER(ip4h) == 4) { SCLogDebug("IPv4 packet"); DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else if(IPV6_GET_RAW_VER(ip6h) == 6) { SCLogDebug("IPv6 packet"); DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else { SCLogDebug("packet unsupported by NFQ, first byte: %02x", *GET_PKT_DATA(p)); } PacketDecodeFinalize(tv, dtv, p); return TM_ECODE_OK; }
/** * \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 Process a chunk of records read from a DAG interface. * * This function takes a pointer to buffer read from the DAG interface * and processes it individual records. */ static inline TmEcode ProcessErfDagRecords(ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read) { SCEnter(); int err = 0; dag_record_t *dr = NULL; char *prec = NULL; int rlen; char hdr_type = 0; int processed = 0; int packet_q_len = 0; *pkts_read = 0; while (((top - ewtn->btm) >= dag_record_size) && ((processed + dag_record_size) < 4*1024*1024)) { /* 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); prec = (char *)ewtn->btm; dr = (dag_record_t*)prec; rlen = ntohs(dr->rlen); hdr_type = dr->type; /* If we don't have enough data to finsih processing this ERF record * return and maybe next time we will. */ if ((top - ewtn->btm) < rlen) SCReturnInt(TM_ECODE_OK); ewtn->btm += rlen; processed += rlen; /* Only support ethernet at this time. */ switch (hdr_type & 0x7f) { case TYPE_PAD: /* Skip. */ continue; case TYPE_DSM_COLOR_ETH: case TYPE_COLOR_ETH: case TYPE_COLOR_HASH_ETH: /* In these types the color value overwrites the lctr * (drop count). */ break; case TYPE_ETH: if (dr->lctr) { SCPerfCounterIncr(ewtn->drops, ewtn->tv->sc_perf_pca); } break; default: SCLogError(SC_ERR_UNIMPLEMENTED, "Processing of DAG record type: %d not implemented.", dr->type); SCReturnInt(TM_ECODE_FAILED); } err = ProcessErfDagRecord(ewtn, prec); if (err != TM_ECODE_OK) { SCReturnInt(TM_ECODE_FAILED); } (*pkts_read)++; } SCReturnInt(TM_ECODE_OK); }
/** * \brief Function to decode Teredo packets * * \retval 0 if packet is not a Teredo packet, 1 if it is */ int DecodeTeredo(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { uint8_t *start = pkt; /* Is this packet to short to contain an IPv6 packet ? */ if (len < IPV6_HEADER_LEN) return 0; /* Teredo encapsulate IPv6 in UDP and can add some custom message * part before the IPv6 packet. In our case, we just want to get * over an ORIGIN indication. So we just make one offset if needed. */ if (start[0] == 0x0) { switch (start[1]) { /* origin indication: compatible with tunnel */ case 0x0: /* offset is coherent with len and presence of an IPv6 header */ if (len >= TEREDO_ORIG_INDICATION_LENGTH + IPV6_HEADER_LEN) start += TEREDO_ORIG_INDICATION_LENGTH; else return 0; break; /* authentication: negotiation not real tunnel */ case 0x1: return 0; /* this case is not possible in Teredo: not that protocol */ default: return 0; } } /* There is no specific field that we can check to prove that the packet * is a Teredo packet. We've zapped here all the possible Teredo header * and we should have an IPv6 packet at the start pointer. * We then can only do two checks before sending the encapsulated packets * to decoding: * - The packet has a protocol version which is IPv6. * - The IPv6 length of the packet matches what remains in buffer. */ if (IP_GET_RAW_VER(start) == 6) { IPV6Hdr *thdr = (IPV6Hdr *)start; if (len == IPV6_HEADER_LEN + IPV6_GET_RAW_PLEN(thdr) + (start - pkt)) { if (pq != NULL) { int blen = len - (start - pkt); /* spawn off tunnel packet */ Packet *tp = PacketPseudoPktSetup(p, start, blen, IPPROTO_IPV6); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_TEREDO); /* send that to the Tunnel decoder */ DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, IPPROTO_IPV6); /* add the tp to the packet queue. */ PacketEnqueue(pq,tp); SCPerfCounterIncr(dtv->counter_teredo, tv->sc_perf_pca); return 1; } } } return 0; } return 0; }
/** * \brief Decode ICMPV6 packets and fill the Packet with the decoded info * * \param tv Pointer to the thread variables * \param dtv Pointer to the decode thread variables * \param p Pointer to the packet we are filling * \param pkt Pointer to the raw packet buffer * \param len the len of the rest of the packet not processed yet * \param pq the packet queue were this packet go * * \retval void No return value */ void DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { int error_msg = 0; SCPerfCounterIncr(dtv->counter_icmpv6, tv->sc_perf_pca); if (len < ICMPV6_HEADER_LEN) { SCLogDebug("ICMPV6_PKT_TOO_SMALL"); ENGINE_SET_EVENT(p, ICMPV6_PKT_TOO_SMALL); return; } p->icmpv6h = (ICMPV6Hdr *)pkt; p->proto = IPPROTO_ICMPV6; p->type = p->icmpv6h->type; p->code = p->icmpv6h->code; p->payload_len = len - ICMPV6_HEADER_LEN; p->payload = pkt + ICMPV6_HEADER_LEN; SCLogDebug("ICMPV6 TYPE %" PRIu32 " CODE %" PRIu32 "", p->icmpv6h->type, p->icmpv6h->code); switch (ICMPV6_GET_TYPE(p)) { case ICMP6_DST_UNREACH: SCLogDebug("ICMP6_DST_UNREACH"); if (ICMPV6_GET_CODE(p) > ICMP6_DST_UNREACH_REJECTROUTE) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } else { DecodePartialIPV6(p, (uint8_t*) (pkt + ICMPV6_HEADER_LEN), len - ICMPV6_HEADER_LEN ); } error_msg = 1; break; case ICMP6_PACKET_TOO_BIG: SCLogDebug("ICMP6_PACKET_TOO_BIG"); if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } else { p->icmpv6vars.mtu = ICMPV6_GET_MTU(p); DecodePartialIPV6(p, (uint8_t*) (pkt + ICMPV6_HEADER_LEN), len - ICMPV6_HEADER_LEN ); } error_msg = 1; break; case ICMP6_TIME_EXCEEDED: SCLogDebug("ICMP6_TIME_EXCEEDED"); if (ICMPV6_GET_CODE(p) > ICMP6_TIME_EXCEED_REASSEMBLY) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } else { DecodePartialIPV6(p, (uint8_t*) (pkt + ICMPV6_HEADER_LEN), len - ICMPV6_HEADER_LEN ); } error_msg = 1; break; case ICMP6_PARAM_PROB: SCLogDebug("ICMP6_PARAM_PROB"); if (ICMPV6_GET_CODE(p) > ICMP6_PARAMPROB_OPTION) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } else { p->icmpv6vars.error_ptr= ICMPV6_GET_ERROR_PTR(p); DecodePartialIPV6(p, (uint8_t*) (pkt + ICMPV6_HEADER_LEN), len - ICMPV6_HEADER_LEN ); } error_msg = 1; break; case ICMP6_ECHO_REQUEST: SCLogDebug("ICMP6_ECHO_REQUEST id: %u seq: %u", p->icmpv6h->icmpv6b.icmpv6i.id, p->icmpv6h->icmpv6b.icmpv6i.seq); if (ICMPV6_GET_CODE(p) != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } else { p->icmpv6vars.id = p->icmpv6h->icmpv6b.icmpv6i.id; p->icmpv6vars.seq = p->icmpv6h->icmpv6b.icmpv6i.seq; } break; case ICMP6_ECHO_REPLY: SCLogDebug("ICMP6_ECHO_REPLY id: %u seq: %u", p->icmpv6h->icmpv6b.icmpv6i.id, p->icmpv6h->icmpv6b.icmpv6i.seq); if (p->icmpv6h->code != 0) { ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_CODE); } else { p->icmpv6vars.id = p->icmpv6h->icmpv6b.icmpv6i.id; p->icmpv6vars.seq = p->icmpv6h->icmpv6b.icmpv6i.seq; } break; default: SCLogDebug("ICMPV6 Message type %" PRIu8 " not " "implemented yet", ICMPV6_GET_TYPE(p)); ENGINE_SET_EVENT(p, ICMPV6_UNKNOWN_TYPE); } /* for a info message the header is just 4 bytes */ if (!error_msg) { if (p->payload_len >= 4) { p->payload_len -= 4; p->payload = pkt + 4; } else { p->payload_len = 0; p->payload = NULL; } } #ifdef DEBUG if (ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_CODE)) SCLogDebug("Unknown Code, ICMPV6_UNKNOWN_CODE"); if (ENGINE_ISSET_EVENT(p, ICMPV6_UNKNOWN_TYPE)) SCLogDebug("Unknown Type, ICMPV6_UNKNOWN_TYPE"); #endif /* Flow is an integral part of us */ FlowHandlePacket(tv, p); return; }
/** * \internal * \brief this function is used to decode IEEE802.1q packets * * \param tv pointer to the thread vars * \param dtv pointer code thread vars * \param p pointer to the packet struct * \param pkt pointer to the raw packet * \param len packet len * \param pq pointer to the packet queue * */ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { uint32_t proto; SCPerfCounterIncr(dtv->counter_vlan, tv->sc_perf_pca); if(len < VLAN_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, VLAN_HEADER_TOO_SMALL); return TM_ECODE_FAILED; } if (p->vlan_idx >= 2) { ENGINE_SET_EVENT(p,VLAN_HEADER_TOO_MANY_LAYERS); return TM_ECODE_FAILED; } p->vlanh[p->vlan_idx] = (VLANHdr *)pkt; if(p->vlanh[p->vlan_idx] == NULL) return TM_ECODE_FAILED; proto = GET_VLAN_PROTO(p->vlanh[p->vlan_idx]); SCLogDebug("p %p pkt %p VLAN protocol %04x VLAN PRI %d VLAN CFI %d VLAN ID %d Len: %" PRId32 "", p, pkt, proto, GET_VLAN_PRIORITY(p->vlanh[p->vlan_idx]), GET_VLAN_CFI(p->vlanh[p->vlan_idx]), GET_VLAN_ID(p->vlanh[p->vlan_idx]), len); /* only store the id for flow hashing if it's not disabled. */ if (dtv->vlan_disabled == 0) p->vlan_id[p->vlan_idx] = (uint16_t)GET_VLAN_ID(p->vlanh[p->vlan_idx]); p->vlan_idx++; switch (proto) { case ETHERNET_TYPE_IP: DecodeIPV4(tv, dtv, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, pq); break; case ETHERNET_TYPE_IPV6: DecodeIPV6(tv, dtv, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, pq); break; case ETHERNET_TYPE_PPPOE_SESS: DecodePPPOESession(tv, dtv, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, pq); break; case ETHERNET_TYPE_PPPOE_DISC: DecodePPPOEDiscovery(tv, dtv, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, pq); break; case ETHERNET_TYPE_VLAN: if (p->vlan_idx >= 2) { ENGINE_SET_EVENT(p,VLAN_HEADER_TOO_MANY_LAYERS); return TM_ECODE_OK; } else { DecodeVLAN(tv, dtv, p, pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, pq); } break; default: SCLogDebug("unknown VLAN type: %" PRIx32 "", proto); ENGINE_SET_INVALID_EVENT(p, VLAN_UNKNOWN_TYPE); return TM_ECODE_OK; } return TM_ECODE_OK; }
void DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { int ret; SCPerfCounterIncr(dtv->counter_ipv6, tv->sc_perf_pca); /* do the actual decoding */ ret = DecodeIPV6Packet (tv, dtv, p, pkt, len); if (ret < 0) { p->ip6h = NULL; return; } #ifdef DEBUG if (SCLogDebugEnabled()) { /* only convert the addresses if debug is really enabled */ /* debug print */ char s[46], d[46]; PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), s, sizeof(s)); PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), d, sizeof(d)); SCLogDebug("IPV6 %s->%s - CLASS: %" PRIu32 " FLOW: %" PRIu32 " NH: %" PRIu32 " PLEN: %" PRIu32 " HLIM: %" PRIu32 "", s,d, IPV6_GET_CLASS(p), IPV6_GET_FLOW(p), IPV6_GET_NH(p), IPV6_GET_PLEN(p), IPV6_GET_HLIM(p)); } #endif /* DEBUG */ /* now process the Ext headers and/or the L4 Layer */ switch(IPV6_GET_NH(p)) { case IPPROTO_TCP: IPV6_SET_L4PROTO (p, IPPROTO_TCP); return DecodeTCP(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); case IPPROTO_UDP: IPV6_SET_L4PROTO (p, IPPROTO_UDP); return DecodeUDP(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); break; case IPPROTO_ICMPV6: IPV6_SET_L4PROTO (p, IPPROTO_ICMPV6); return DecodeICMPV6(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); case IPPROTO_SCTP: IPV6_SET_L4PROTO (p, IPPROTO_SCTP); return DecodeSCTP(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); case IPPROTO_IPIP: IPV6_SET_L4PROTO(p, IPPROTO_IPIP); return DecodeIPv4inIPv6(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); case IPPROTO_IPV6: return DecodeIP6inIP6(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); case IPPROTO_FRAGMENT: case IPPROTO_HOPOPTS: case IPPROTO_ROUTING: case IPPROTO_NONE: case IPPROTO_DSTOPTS: case IPPROTO_AH: case IPPROTO_ESP: DecodeIPV6ExtHdrs(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); break; default: p->proto = IPV6_GET_NH(p); break; } /* Pass to defragger if a fragment. */ if (IPV6_EXTHDR_ISSET_FH(p)) { Packet *rp = Defrag(tv, dtv, NULL, p); if (rp != NULL) { DecodeIPV6(tv, dtv, rp, (uint8_t *)rp->ip6h, IPV6_GET_PLEN(rp) + IPV6_HEADER_LEN, pq); PacketEnqueue(pq, rp); /* Not really a tunnel packet, but we're piggybacking that * functionality for now. */ SET_TUNNEL_PKT(p); } } #ifdef DEBUG if (IPV6_EXTHDR_ISSET_FH(p)) { SCLogDebug("IPV6 FRAG - HDRLEN: %" PRIuMAX " NH: %" PRIu32 " OFFSET: %" PRIu32 " ID: %" PRIu32 "", (uintmax_t)IPV6_EXTHDR_GET_FH_HDRLEN(p), IPV6_EXTHDR_GET_FH_NH(p), IPV6_EXTHDR_GET_FH_OFFSET(p), IPV6_EXTHDR_GET_FH_ID(p)); } if (IPV6_EXTHDR_ISSET_RH(p)) { SCLogDebug("IPV6 ROUTE - HDRLEN: %" PRIu32 " NH: %" PRIu32 " TYPE: %" PRIu32 "", IPV6_EXTHDR_GET_RH_HDRLEN(p), IPV6_EXTHDR_GET_RH_NH(p), IPV6_EXTHDR_GET_RH_TYPE(p)); } if (IPV6_EXTHDR_ISSET_HH(p)) { SCLogDebug("IPV6 HOPOPT - HDRLEN: %" PRIu32 " NH: %" PRIu32 "", IPV6_EXTHDR_GET_HH_HDRLEN(p), IPV6_EXTHDR_GET_HH_NH(p)); } if (IPV6_EXTHDR_ISSET_DH1(p)) { SCLogDebug("IPV6 DSTOPT1 - HDRLEN: %" PRIu32 " NH: %" PRIu32 "", IPV6_EXTHDR_GET_DH1_HDRLEN(p), IPV6_EXTHDR_GET_DH1_NH(p)); } if (IPV6_EXTHDR_ISSET_DH2(p)) { SCLogDebug("IPV6 DSTOPT2 - HDRLEN: %" PRIu32 " NH: %" PRIu32 "", IPV6_EXTHDR_GET_DH2_HDRLEN(p), IPV6_EXTHDR_GET_DH2_NH(p)); } #endif return; }
/** DecodeICMPV4 * \brief Main ICMPv4 decoding function */ void DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_icmpv4, tv->sc_perf_pca); if (len < ICMPV4_HEADER_LEN) { ENGINE_SET_EVENT(p,ICMPV4_PKT_TOO_SMALL); return; } p->icmpv4h = (ICMPV4Hdr *)pkt; SCLogDebug("ICMPV4 TYPE %" PRIu32 " CODE %" PRIu32 "", p->icmpv4h->type, p->icmpv4h->code); p->proto = IPPROTO_ICMP; p->type = p->icmpv4h->type; p->code = p->icmpv4h->code; p->payload = pkt + ICMPV4_HEADER_LEN; p->payload_len = len - ICMPV4_HEADER_LEN; ICMPV4ExtHdr* icmp4eh = (ICMPV4ExtHdr*) p->icmpv4h; switch (p->icmpv4h->type) { case ICMP_ECHOREPLY: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_DEST_UNREACH: if (p->icmpv4h->code > NR_ICMP_UNREACH) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } else { /* parse IP header plus 64 bytes */ if (len > ICMPV4_HEADER_PKT_OFFSET) { DecodePartialIPV4( p, (uint8_t *)(pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); /* ICMP ICMP_DEST_UNREACH influence TCP/UDP flows */ if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { FlowHandlePacket(tv, p); } } } break; case ICMP_SOURCE_QUENCH: if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len >= ICMPV4_HEADER_PKT_OFFSET) DecodePartialIPV4( p, (uint8_t*) (pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); } break; case ICMP_REDIRECT: if (p->icmpv4h->code>ICMP_REDIR_HOSTTOS) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len > ICMPV4_HEADER_PKT_OFFSET) DecodePartialIPV4( p, (uint8_t*) (pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); } break; case ICMP_ECHO: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_TIME_EXCEEDED: if (p->icmpv4h->code>ICMP_EXC_FRAGTIME) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len > ICMPV4_HEADER_PKT_OFFSET) DecodePartialIPV4( p, (uint8_t*) (pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); } break; case ICMP_PARAMETERPROB: if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len > ICMPV4_HEADER_PKT_OFFSET) DecodePartialIPV4( p, (uint8_t*) (pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); } break; case ICMP_TIMESTAMP: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_TIMESTAMPREPLY: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_INFO_REQUEST: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_INFO_REPLY: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_ADDRESS: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_ADDRESSREPLY: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; default: ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_TYPE); } return; }
/** * \brief Main decoding function for PPPOE Session packets */ int DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_pppoe, tv->sc_perf_pca); if (len < PPPOE_SESSION_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, PPPOE_PKT_TOO_SMALL); return TM_ECODE_FAILED; } p->pppoesh = (PPPOESessionHdr *)pkt; if (p->pppoesh == NULL) return TM_ECODE_FAILED; SCLogDebug("PPPOE VERSION %" PRIu32 " TYPE %" PRIu32 " CODE %" PRIu32 " SESSIONID %" PRIu32 " LENGTH %" PRIu32 "", PPPOE_SESSION_GET_VERSION(p->pppoesh), PPPOE_SESSION_GET_TYPE(p->pppoesh), p->pppoesh->pppoe_code, ntohs(p->pppoesh->session_id), ntohs(p->pppoesh->pppoe_length)); /* can't use DecodePPP() here because we only get a single 2-byte word to indicate protocol instead of the full PPP header */ if (ntohs(p->pppoesh->pppoe_length) > 0) { /* decode contained PPP packet */ switch (ntohs(p->pppoesh->protocol)) { case PPP_VJ_COMP: case PPP_IPX: case PPP_OSI: case PPP_NS: case PPP_DECNET: case PPP_APPLE: case PPP_BRPDU: case PPP_STII: case PPP_VINES: case PPP_HELLO: case PPP_LUXCOM: case PPP_SNS: case PPP_MPLS_UCAST: case PPP_MPLS_MCAST: case PPP_IPCP: case PPP_OSICP: case PPP_NSCP: case PPP_DECNETCP: case PPP_APPLECP: case PPP_IPXCP: case PPP_STIICP: case PPP_VINESCP: case PPP_IPV6CP: case PPP_MPLSCP: case PPP_LCP: case PPP_PAP: case PPP_LQM: case PPP_CHAP: ENGINE_SET_EVENT(p,PPP_UNSUP_PROTO); break; case PPP_VJ_UCOMP: if(len < (PPPOE_SESSION_HEADER_LEN + IPV4_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, PPPVJU_PKT_TOO_SMALL); return TM_ECODE_OK; } if(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + PPPOE_SESSION_HEADER_LEN)) == 4) { DecodeIPV4(tv, dtv, p, pkt + PPPOE_SESSION_HEADER_LEN, len - PPPOE_SESSION_HEADER_LEN, pq ); } break; case PPP_IP: if(len < (PPPOE_SESSION_HEADER_LEN + IPV4_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, PPPIPV4_PKT_TOO_SMALL); return TM_ECODE_OK; } DecodeIPV4(tv, dtv, p, pkt + PPPOE_SESSION_HEADER_LEN, len - PPPOE_SESSION_HEADER_LEN, pq ); break; /* PPP IPv6 was not tested */ case PPP_IPV6: if(len < (PPPOE_SESSION_HEADER_LEN + IPV6_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, PPPIPV6_PKT_TOO_SMALL); return TM_ECODE_OK; } DecodeIPV6(tv, dtv, p, pkt + PPPOE_SESSION_HEADER_LEN, len - PPPOE_SESSION_HEADER_LEN, pq ); break; default: SCLogDebug("unknown PPP protocol: %" PRIx32 "",ntohs(p->ppph->protocol)); ENGINE_SET_INVALID_EVENT(p, PPP_WRONG_TYPE); return TM_ECODE_OK; } } return TM_ECODE_OK; }
/** * \brief Main decoding function for PPPOE Discovery packets */ int DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_pppoe, tv->sc_perf_pca); if (len < PPPOE_DISCOVERY_HEADER_MIN_LEN) { ENGINE_SET_INVALID_EVENT(p, PPPOE_PKT_TOO_SMALL); return TM_ECODE_FAILED; } p->pppoedh = (PPPOEDiscoveryHdr *)pkt; if (p->pppoedh == NULL) return TM_ECODE_FAILED; /* parse the PPPOE code */ switch (p->pppoedh->pppoe_code) { case PPPOE_CODE_PADI: break; case PPPOE_CODE_PADO: break; case PPPOE_CODE_PADR: break; case PPPOE_CODE_PADS: break; case PPPOE_CODE_PADT: break; default: SCLogDebug("unknown PPPOE code: 0x%0"PRIX8"", p->pppoedh->pppoe_code); ENGINE_SET_INVALID_EVENT(p, PPPOE_WRONG_CODE); return TM_ECODE_OK; } /* parse any tags we have in the packet */ uint16_t tag_length = 0; PPPOEDiscoveryTag* pppoedt = (PPPOEDiscoveryTag*) (p->pppoedh + PPPOE_DISCOVERY_HEADER_MIN_LEN); uint16_t pppoe_length = ntohs(p->pppoedh->pppoe_length); uint16_t packet_length = len - PPPOE_DISCOVERY_HEADER_MIN_LEN ; SCLogDebug("pppoe_length %"PRIu16", packet_length %"PRIu16"", pppoe_length, packet_length); if (pppoe_length > packet_length) { SCLogDebug("malformed PPPOE tags"); ENGINE_SET_INVALID_EVENT(p, PPPOE_MALFORMED_TAGS); return TM_ECODE_OK; } while (pppoedt < (PPPOEDiscoveryTag*) (pkt + (len - sizeof(PPPOEDiscoveryTag))) && pppoe_length >=4 && packet_length >=4) { #ifdef DEBUG uint16_t tag_type = ntohs(pppoedt->pppoe_tag_type); #endif tag_length = ntohs(pppoedt->pppoe_tag_length); SCLogDebug ("PPPoE Tag type %x, length %u", tag_type, tag_length); if (pppoe_length >= (4 + tag_length)) { pppoe_length -= (4 + tag_length); } else { pppoe_length = 0; // don't want an underflow } if (packet_length >= 4 + tag_length) { packet_length -= (4 + tag_length); } else { packet_length = 0; // don't want an underflow } pppoedt = pppoedt + (4 + tag_length); } return TM_ECODE_OK; }
void DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { uint16_t header_len = GRE_HDR_LEN; GRESreHdr *gsre = NULL; SCPerfCounterIncr(dtv->counter_gre, tv->sc_perf_pca); if(len < GRE_HDR_LEN) { ENGINE_SET_EVENT(p,GRE_PKT_TOO_SMALL); return; } p->greh = (GREHdr *)pkt; if(p->greh == NULL) return; SCLogDebug("p %p pkt %p GRE protocol %04x Len: %d GRE version %x", p, pkt, GRE_GET_PROTO(p->greh), len,GRE_GET_VERSION(p->greh)); switch (GRE_GET_VERSION(p->greh)) { case GRE_VERSION_0: /* GRE version 0 doenst support the fields below RFC 1701 */ /** * \todo We need to make sure this does not allow bypassing * inspection. A server may just ignore these and * continue processing the packet, but we will not look * further into it. */ if (GRE_FLAG_ISSET_RECUR(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION0_RECUR); return; } if (GREV1_FLAG_ISSET_FLAGS(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION0_FLAGS); return; } /* Adjust header length based on content */ if (GRE_FLAG_ISSET_KY(p->greh)) header_len += GRE_KEY_LEN; if (GRE_FLAG_ISSET_SQ(p->greh)) header_len += GRE_SEQ_LEN; if (GRE_FLAG_ISSET_CHKSUM(p->greh) || GRE_FLAG_ISSET_ROUTE(p->greh)) header_len += GRE_CHKSUM_LEN + GRE_OFFSET_LEN; if (header_len > len) { ENGINE_SET_EVENT(p,GRE_VERSION0_HDR_TOO_BIG); return; } if (GRE_FLAG_ISSET_ROUTE(p->greh)) { while (1) { if ((header_len + GRE_SRE_HDR_LEN) > len) { ENGINE_SET_EVENT(p, GRE_VERSION0_MALFORMED_SRE_HDR); return; } gsre = (GRESreHdr *)(pkt + header_len); header_len += GRE_SRE_HDR_LEN; if ((ntohs(gsre->af) == 0) && (gsre->sre_length == 0)) break; header_len += gsre->sre_length; if (header_len > len) { ENGINE_SET_EVENT(p, GRE_VERSION0_MALFORMED_SRE_HDR); return; } } } break; case GRE_VERSION_1: /* GRE version 1 doenst support the fields below RFC 1701 */ /** * \todo We need to make sure this does not allow bypassing * inspection. A server may just ignore these and * continue processing the packet, but we will not look * further into it. */ if (GRE_FLAG_ISSET_CHKSUM(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION1_CHKSUM); return; } if (GRE_FLAG_ISSET_ROUTE(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION1_ROUTE); return; } if (GRE_FLAG_ISSET_SSR(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION1_SSR); return; } if (GRE_FLAG_ISSET_RECUR(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION1_RECUR); return; } if (GREV1_FLAG_ISSET_FLAGS(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION1_FLAGS); return; } if (GRE_GET_PROTO(p->greh) != GRE_PROTO_PPP) { ENGINE_SET_EVENT(p,GRE_VERSION1_WRONG_PROTOCOL); return; } if (!(GRE_FLAG_ISSET_KY(p->greh))) { ENGINE_SET_EVENT(p,GRE_VERSION1_NO_KEY); return; } header_len += GRE_KEY_LEN; /* Adjust header length based on content */ if (GRE_FLAG_ISSET_SQ(p->greh)) header_len += GRE_SEQ_LEN; if (GREV1_FLAG_ISSET_ACK(p->greh)) header_len += GREV1_ACK_LEN; if (header_len > len) { ENGINE_SET_EVENT(p,GRE_VERSION1_HDR_TOO_BIG); return; } break; default: ENGINE_SET_EVENT(p,GRE_WRONG_VERSION); return; } switch (GRE_GET_PROTO(p->greh)) { case ETHERNET_TYPE_IP: { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt + header_len, len - header_len, IPPROTO_IP); if (tp != NULL) { DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, IPPROTO_IP); PacketEnqueue(pq,tp); } } break; } case GRE_PROTO_PPP: { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt + header_len, len - header_len, PPP_OVER_GRE); if (tp != NULL) { DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, PPP_OVER_GRE); PacketEnqueue(pq,tp); } } break; } case ETHERNET_TYPE_IPV6: { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt + header_len, len - header_len, IPPROTO_IPV6); if (tp != NULL) { DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, IPPROTO_IPV6); PacketEnqueue(pq,tp); } } break; } case ETHERNET_TYPE_VLAN: { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt + header_len, len - header_len, VLAN_OVER_GRE); if (tp != NULL) { DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, VLAN_OVER_GRE); PacketEnqueue(pq,tp); } } break; } default: return; } }
void DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCPerfCounterIncr(dtv->counter_ppp, tv->sc_perf_pca); if (unlikely(len < PPP_HEADER_LEN)) { ENGINE_SET_EVENT(p,PPP_PKT_TOO_SMALL); return; } p->ppph = (PPPHdr *)pkt; if (unlikely(p->ppph == NULL)) return; SCLogDebug("p %p pkt %p PPP protocol %04x Len: %" PRId32 "", p, pkt, ntohs(p->ppph->protocol), len); switch (ntohs(p->ppph->protocol)) { case PPP_VJ_UCOMP: if (unlikely(len < (PPP_HEADER_LEN + IPV4_HEADER_LEN))) { ENGINE_SET_EVENT(p,PPPVJU_PKT_TOO_SMALL); return; } if (likely(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + PPP_HEADER_LEN)) == 4)) { DecodeIPV4(tv, dtv, p, pkt + PPP_HEADER_LEN, len - PPP_HEADER_LEN, pq); } break; case PPP_IP: if (unlikely(len < (PPP_HEADER_LEN + IPV4_HEADER_LEN))) { ENGINE_SET_EVENT(p,PPPIPV4_PKT_TOO_SMALL); return; } DecodeIPV4(tv, dtv, p, pkt + PPP_HEADER_LEN, len - PPP_HEADER_LEN, pq); break; /* PPP IPv6 was not tested */ case PPP_IPV6: if (unlikely(len < (PPP_HEADER_LEN + IPV6_HEADER_LEN))) { ENGINE_SET_EVENT(p,PPPIPV6_PKT_TOO_SMALL); return; } DecodeIPV6(tv, dtv, p, pkt + PPP_HEADER_LEN, len - PPP_HEADER_LEN, pq); break; case PPP_VJ_COMP: case PPP_IPX: case PPP_OSI: case PPP_NS: case PPP_DECNET: case PPP_APPLE: case PPP_BRPDU: case PPP_STII: case PPP_VINES: case PPP_HELLO: case PPP_LUXCOM: case PPP_SNS: case PPP_MPLS_UCAST: case PPP_MPLS_MCAST: case PPP_IPCP: case PPP_OSICP: case PPP_NSCP: case PPP_DECNETCP: case PPP_APPLECP: case PPP_IPXCP: case PPP_STIICP: case PPP_VINESCP: case PPP_IPV6CP: case PPP_MPLSCP: case PPP_LCP: case PPP_PAP: case PPP_LQM: case PPP_CHAP: ENGINE_SET_EVENT(p,PPP_UNSUP_PROTO); break; default: SCLogDebug("unknown PPP protocol: %" PRIx32 "",ntohs(p->ppph->protocol)); ENGINE_SET_EVENT(p,PPP_WRONG_TYPE); return; } return; }