static int DecodeIPV6Packet (ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len) { if (len < IPV6_HEADER_LEN) { return -1; } if (IP_GET_RAW_VER(pkt) != 6) { SCLogDebug("wrong ip version %" PRIu8 "",IP_GET_RAW_VER(pkt)); ENGINE_SET_EVENT(p,IPV6_WRONG_IP_VER); return -1; } p->ip6h = (IPV6Hdr *)pkt; if (len < (IPV6_HEADER_LEN + IPV6_GET_PLEN(p))) { ENGINE_SET_EVENT(p,IPV6_TRUNC_PKT); return -1; } SET_IPV6_SRC_ADDR(p,&p->src); SET_IPV6_DST_ADDR(p,&p->dst); return 0; }
static int DecodeTCPPacket(ThreadVars *tv, Packet *p, uint8_t *pkt, uint16_t len) { if (unlikely(len < TCP_HEADER_LEN)) { ENGINE_SET_EVENT(p, TCP_PKT_TOO_SMALL); return -1; } p->tcph = (TCPHdr *)pkt; uint8_t hlen = TCP_GET_HLEN(p); if (unlikely(len < hlen)) { ENGINE_SET_EVENT(p, TCP_HLEN_TOO_SMALL); return -1; } uint8_t tcp_opt_len = hlen - TCP_HEADER_LEN; if (unlikely(tcp_opt_len > TCP_OPTLENMAX)) { ENGINE_SET_EVENT(p, TCP_INVALID_OPTLEN); return -1; } if (likely(tcp_opt_len > 0)) { DecodeTCPOptions(p, pkt + TCP_HEADER_LEN, tcp_opt_len); } SET_TCP_SRC_PORT(p,&p->sp); SET_TCP_DST_PORT(p,&p->dp); p->proto = IPPROTO_TCP; p->payload = pkt + hlen; p->payload_len = len - hlen; return 0; }
int DecodeRaw(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint32_t len, PacketQueue *pq) { StatsIncr(tv, dtv->counter_raw); /* If it is ipv4 or ipv6 it should at least be the size of ipv4 */ if (unlikely(len < IPV4_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, IPV4_PKT_TOO_SMALL); return TM_ECODE_FAILED; } if (IP_GET_RAW_VER(pkt) == 4) { if (unlikely(GET_PKT_LEN(p) > USHRT_MAX)) { return TM_ECODE_FAILED; } SCLogDebug("IPV4 Packet"); DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); } else if (IP_GET_RAW_VER(pkt) == 6) { if (unlikely(GET_PKT_LEN(p) > USHRT_MAX)) { return TM_ECODE_FAILED; } 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 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 (unlikely(len < SLL_HEADER_LEN)) { ENGINE_SET_EVENT(p,SLL_PKT_TOO_SMALL); return; } SllHdr *sllh = (SllHdr *)pkt; if (unlikely(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 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, pkt, plen, pq, IPPROTO_IPV6); PacketEnqueue(pq,tp); return; } } } else { ENGINE_SET_EVENT(p, IPV6_IN_IPV6_WRONG_IP_VER); } return; }
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 Function to decode IPv4 in IPv6 packets * */ static void DecodeIPv4inIPv6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t plen, PacketQueue *pq) { if (unlikely(plen < IPV4_HEADER_LEN)) { ENGINE_SET_EVENT(p, IPV4_IN_IPV6_PKT_TOO_SMALL); return; } if (IP_GET_RAW_VER(pkt) == 4) { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt, plen, IPPROTO_IP); if (tp != NULL) { DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, IPPROTO_IP); PacketEnqueue(pq,tp); SCPerfCounterIncr(dtv->counter_ipv4inipv6, tv->sc_perf_pca); return; } } } else { ENGINE_SET_EVENT(p, IPV4_IN_IPV6_WRONG_IP_VER); } return; }
/** * \test EngineEventTestParse06 is a test for match function with valid decode-event value */ int EngineEventTestParse06 (void) { Packet *p = SCMalloc(SIZE_OF_PACKET); if (unlikely(p == NULL)) return 0; ThreadVars tv; int ret = 0; DetectEngineEventData *de = NULL; SigMatch *sm = NULL; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); ENGINE_SET_EVENT(p,PPP_PKT_TOO_SMALL); de = DetectEngineEventParse("ppp.pkt_too_small"); if (de == NULL) goto error; de->event = PPP_PKT_TOO_SMALL; sm = SigMatchAlloc(); if (sm == NULL) goto error; sm->type = DETECT_DECODE_EVENT; sm->ctx = (SigMatchCtx *)de; ret = DetectEngineEventMatch(&tv,NULL,p,NULL,sm->ctx); if(ret) { SCFree(p); return 1; } error: if (de) SCFree(de); if (sm) SCFree(sm); SCFree(p); return 0; }
/** * \brief Function to decode IPv6 in IPv6 packets * */ static int DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t plen, PacketQueue *pq) { if (unlikely(plen < IPV6_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, IPV6_IN_IPV6_PKT_TOO_SMALL); return TM_ECODE_FAILED; } if (IP_GET_RAW_VER(pkt) == 6) { if (unlikely(pq != NULL)) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt, plen, DECODE_TUNNEL_IPV6, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); PacketEnqueue(pq,tp); StatsIncr(tv, dtv->counter_ipv6inipv6); } } } else { ENGINE_SET_EVENT(p, IPV6_IN_IPV6_WRONG_IP_VER); } return TM_ECODE_OK; }
/** * \brief Function to decode IPv4 in IPv6 packets * */ static void DecodeIPv4inIPv6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t plen, PacketQueue *pq) { if (unlikely(plen < IPV4_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, IPV4_IN_IPV6_PKT_TOO_SMALL); return; } if (IP_GET_RAW_VER(pkt) == 4) { if (pq != NULL) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt, plen, DECODE_TUNNEL_IPV4, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6); /* add the tp to the packet queue. */ PacketEnqueue(pq,tp); StatsIncr(tv, dtv->counter_ipv4inipv6); return; } } } else { ENGINE_SET_EVENT(p, IPV4_IN_IPV6_WRONG_IP_VER); } return; }
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; case IPPROTO_ICMP: ENGINE_SET_EVENT(p,IPV6_WITH_ICMPV4); break; default: IPV6_SET_L4PROTO (p, IPV6_GET_NH(p)); break; } p->proto = IPV6_GET_L4PROTO (p); /* Pass to defragger if a fragment. */ if (IPV6_EXTHDR_ISSET_FH(p)) { Packet *rp = Defrag(tv, dtv, 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; }
/** * \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; }
int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint32_t len, PacketQueue *pq) { uint32_t shim; int label; int event = 0; StatsIncr(tv, dtv->counter_mpls); do { if (len < MPLS_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, MPLS_HEADER_TOO_SMALL); return TM_ECODE_FAILED; } memcpy(&shim, pkt, sizeof(shim)); pkt += MPLS_HEADER_LEN; len -= MPLS_HEADER_LEN; } while (MPLS_BOTTOM(shim) == 0); label = MPLS_LABEL(shim); if (label == MPLS_LABEL_IPV4) { if (len > USHRT_MAX) { return TM_ECODE_FAILED; } return DecodeIPV4(tv, dtv, p, pkt, len, pq); } else if (label == MPLS_LABEL_ROUTER_ALERT) { /* Not valid at the bottom of the stack. */ event = MPLS_BAD_LABEL_ROUTER_ALERT; } else if (label == MPLS_LABEL_IPV6) { if (len > USHRT_MAX) { return TM_ECODE_FAILED; } return DecodeIPV6(tv, dtv, p, pkt, len, pq); } else if (label == MPLS_LABEL_NULL) { /* Shouldn't appear on the wire. */ event = MPLS_BAD_LABEL_IMPLICIT_NULL; } else if (label < MPLS_MAX_RESERVED_LABEL) { event = MPLS_BAD_LABEL_RESERVED; } if (event) { goto end; } // Make sure we still have enough data. While we only need 1 byte to test // for IPv4 and IPv4, we need for to check for ethernet. if (len < MPLS_PW_LEN) { ENGINE_SET_INVALID_EVENT(p, MPLS_PKT_TOO_SMALL); return TM_ECODE_FAILED; } /* Best guess at inner packet. */ switch (pkt[0] >> 4) { case MPLS_PROTO_IPV4: if (len > USHRT_MAX) { return TM_ECODE_FAILED; } DecodeIPV4(tv, dtv, p, pkt, len, pq); break; case MPLS_PROTO_IPV6: if (len > USHRT_MAX) { return TM_ECODE_FAILED; } DecodeIPV6(tv, dtv, p, pkt, len, pq); break; case MPLS_PROTO_ETHERNET_PW: DecodeEthernet(tv, dtv, p, pkt + MPLS_PW_LEN, len - MPLS_PW_LEN, pq); break; default: ENGINE_SET_INVALID_EVENT(p, MPLS_UNKNOWN_PAYLOAD_TYPE); return TM_ECODE_OK; } end: if (event) { ENGINE_SET_EVENT(p, event); } return TM_ECODE_OK; }
static void DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCEnter(); uint8_t *orig_pkt = pkt; uint8_t nh; uint16_t hdrextlen; uint16_t plen; char dstopts = 0; char exthdr_fh_done = 0; nh = IPV6_GET_NH(p); plen = len; while(1) { if (plen < 2) { /* minimal needed in a hdr */ SCReturn; } switch(nh) { case IPPROTO_TCP: IPV6_SET_L4PROTO(p,nh); DecodeTCP(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_UDP: IPV6_SET_L4PROTO(p,nh); DecodeUDP(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_ICMPV6: IPV6_SET_L4PROTO(p,nh); DecodeICMPV6(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_SCTP: IPV6_SET_L4PROTO(p,nh); DecodeSCTP(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_ROUTING: IPV6_SET_L4PROTO(p,nh); hdrextlen = 8 + (*(pkt+1) * 8); /* 8 bytes + length in 8 octet units */ SCLogDebug("hdrextlen %"PRIu8, hdrextlen); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } if (p->IPV6_EH_CNT < IPV6_MAX_OPT) { p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh; p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt; p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen; p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2; p->IPV6_EH_CNT++; } if (IPV6_EXTHDR_ISSET_RH(p)) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_RH); /* skip past this extension so we can continue parsing the rest * of the packet */ nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } IPV6_EXTHDR_SET_RH(p, pkt); IPV6_EXTHDR_RH(p)->ip6rh_len = hdrextlen; /** \todo move into own function and load on demand */ if (IPV6_EXTHDR_RH(p)->ip6rh_type == 0) { uint8_t i; uint8_t n = IPV6_EXTHDR_RH(p)->ip6rh_len / 2; /* because we devide the header len by 2 (as rfc 2460 tells us to) * we devide the result by 8 and not 16 as the header fields are * sized */ for (i = 0; i < (n/8) && i < sizeof(IPV6_EXTHDR_RH(p)->ip6rh0_addr)/sizeof(struct in6_addr); ++i) { /* the address header fields are 16 bytes in size */ /** \todo do this without memcpy since it's expensive */ memcpy(&IPV6_EXTHDR_RH(p)->ip6rh0_addr[i], pkt+(i*16)+8, sizeof(IPV6_EXTHDR_RH(p)->ip6rh0_addr[i])); } IPV6_EXTHDR_RH(p)->ip6rh0_num_addrs = i; } nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; case IPPROTO_HOPOPTS: case IPPROTO_DSTOPTS: { IPV6OptHAO *hao = NULL; IPV6OptRA *ra = NULL; IPV6OptJumbo *jumbo = NULL; uint8_t optslen = 0; IPV6_SET_L4PROTO(p,nh); hdrextlen = (*(pkt+1) + 1) << 3; if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } if (p->IPV6_EH_CNT < IPV6_MAX_OPT) { p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh; p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt; p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen; p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2; p->IPV6_EH_CNT++; } uint8_t *ptr = pkt + 2; /* +2 to go past nxthdr and len */ /* point the pointers to right structures * in Packet. */ if (nh == IPPROTO_HOPOPTS) { if (IPV6_EXTHDR_ISSET_HH(p)) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_HH); /* skip past this extension so we can continue parsing the rest * of the packet */ nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } IPV6_EXTHDR_SET_HH(p, pkt); hao = &IPV6_EXTHDR_HH_HAO(p); ra = &IPV6_EXTHDR_HH_RA(p); jumbo = &IPV6_EXTHDR_HH_JUMBO(p); optslen = ((IPV6_EXTHDR_HH(p)->ip6hh_len+1)<<3)-2; } else if (nh == IPPROTO_DSTOPTS) { if (dstopts == 0) { IPV6_EXTHDR_SET_DH1(p, pkt); hao = &IPV6_EXTHDR_DH1_HAO(p); ra = &IPV6_EXTHDR_DH1_RA(p); jumbo = &IPV6_EXTHDR_DH2_JUMBO(p); optslen = ((IPV6_EXTHDR_DH1(p)->ip6dh_len+1)<<3)-2; dstopts = 1; } else if (dstopts == 1) { IPV6_EXTHDR_SET_DH2(p, pkt); hao = &IPV6_EXTHDR_DH2_HAO(p); ra = &IPV6_EXTHDR_DH2_RA(p); jumbo = &IPV6_EXTHDR_DH2_JUMBO(p); optslen = ((IPV6_EXTHDR_DH2(p)->ip6dh_len+1)<<3)-2; dstopts = 2; } else { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_DH); /* skip past this extension so we can continue parsing the rest * of the packet */ nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } } if (optslen > plen) { /* since the packet is long enough (we checked * plen against hdrlen, the optlen must be malformed. */ ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); /* skip past this extension so we can continue parsing the rest * of the packet */ nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } /** \todo move into own function to loaded on demand */ uint16_t offset = 0; while(offset < optslen) { if (*ptr == IPV6OPT_PADN) /* PadN */ { //printf("PadN option\n"); } else if (*ptr == IPV6OPT_RA) /* RA */ { ra->ip6ra_type = *(ptr); ra->ip6ra_len = *(ptr + 1); memcpy(&ra->ip6ra_value, (ptr + 2), sizeof(ra->ip6ra_value)); ra->ip6ra_value = ntohs(ra->ip6ra_value); //printf("RA option: type %" PRIu32 " len %" PRIu32 " value %" PRIu32 "\n", // ra->ip6ra_type, ra->ip6ra_len, ra->ip6ra_value); } else if (*ptr == IPV6OPT_JUMBO) /* Jumbo */ { jumbo->ip6j_type = *(ptr); jumbo->ip6j_len = *(ptr+1); memcpy(&jumbo->ip6j_payload_len, (ptr+2), sizeof(jumbo->ip6j_payload_len)); jumbo->ip6j_payload_len = ntohl(jumbo->ip6j_payload_len); //printf("Jumbo option: type %" PRIu32 " len %" PRIu32 " payload len %" PRIu32 "\n", // jumbo->ip6j_type, jumbo->ip6j_len, jumbo->ip6j_payload_len); } else if (*ptr == IPV6OPT_HAO) /* HAO */ { hao->ip6hao_type = *(ptr); hao->ip6hao_len = *(ptr+1); memcpy(&hao->ip6hao_hoa, (ptr+2), sizeof(hao->ip6hao_hoa)); //printf("HAO option: type %" PRIu32 " len %" PRIu32 " ", // hao->ip6hao_type, hao->ip6hao_len); //char addr_buf[46]; //PrintInet(AF_INET6, (char *)&(hao->ip6hao_hoa), // addr_buf,sizeof(addr_buf)); //printf("home addr %s\n", addr_buf); } uint16_t optlen = (*(ptr + 1) + 2); ptr += optlen; /* +2 for opt type and opt len fields */ offset += optlen; } nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } case IPPROTO_FRAGMENT: IPV6_SET_L4PROTO(p,nh); /* store the offset of this extension into the packet * past the ipv6 header. We use it in defrag for creating * a defragmented packet without the frag header */ if (exthdr_fh_done == 0) { p->ip6eh.fh_offset = pkt - orig_pkt; exthdr_fh_done = 1; } hdrextlen = sizeof(IPV6FragHdr); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } if(p->IPV6_EH_CNT<IPV6_MAX_OPT) { p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh; p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt; p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen; p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2; p->IPV6_EH_CNT++; } if (IPV6_EXTHDR_ISSET_FH(p)) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_FH); nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } /* set the header ptr first */ IPV6_EXTHDR_SET_FH(p, pkt); /* if FH has offset 0 and no more fragments are coming, we * parse this packet further right away, no defrag will be * needed. It is a useless FH then though, so we do set an * decoder event. */ if (IPV6_EXTHDR_GET_FH_FLAG(p) == 0 && IPV6_EXTHDR_GET_FH_OFFSET(p) == 0) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_USELESS_FH); nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } /* the rest is parsed upon reassembly */ SCReturn; case IPPROTO_ESP: { IPV6_SET_L4PROTO(p,nh); hdrextlen = sizeof(IPV6EspHdr); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } if(p->IPV6_EH_CNT<IPV6_MAX_OPT) { p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh; p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = IPPROTO_NONE; p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen; p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2; p->IPV6_EH_CNT++; } if (IPV6_EXTHDR_ISSET_EH(p)) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_EH); SCReturn; } IPV6_EXTHDR_SET_EH(p, pkt); nh = IPPROTO_NONE; pkt += hdrextlen; plen -= hdrextlen; break; } case IPPROTO_AH: { IPV6_SET_L4PROTO(p,nh); /* we need the header as a minimum */ hdrextlen = sizeof(IPV6AuthHdr); /* the payload len field is the number of extra 4 byte fields, * IPV6AuthHdr already contains the first */ if (*(pkt+1) > 0) hdrextlen += ((*(pkt+1) - 1) * 4); SCLogDebug("hdrextlen %"PRIu8, hdrextlen); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } IPV6AuthHdr *ahhdr = (IPV6AuthHdr *)pkt; if (ahhdr->ip6ah_reserved != 0x0000) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_AH_RES_NOT_NULL); } if(p->IPV6_EH_CNT < IPV6_MAX_OPT) { p->IPV6_EXTHDRS[p->IPV6_EH_CNT].type = nh; p->IPV6_EXTHDRS[p->IPV6_EH_CNT].next = *pkt; p->IPV6_EXTHDRS[p->IPV6_EH_CNT].len = hdrextlen; p->IPV6_EXTHDRS[p->IPV6_EH_CNT].data = pkt+2; p->IPV6_EH_CNT++; } if (IPV6_EXTHDR_ISSET_AH(p)) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_AH); nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } IPV6_EXTHDR_SET_AH(p, pkt); nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } case IPPROTO_IPIP: IPV6_SET_L4PROTO(p,nh); DecodeIPv4inIPv6(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_NONE: IPV6_SET_L4PROTO(p,nh); SCReturn; default: IPV6_SET_L4PROTO(p,nh); SCReturn; } } SCReturn; }
static void DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCEnter(); uint8_t *orig_pkt = pkt; uint8_t nh = 0; /* careful, 0 is actually a real type */ uint16_t hdrextlen = 0; uint16_t plen; char dstopts = 0; char exthdr_fh_done = 0; int hh = 0; int rh = 0; int eh = 0; int ah = 0; nh = IPV6_GET_NH(p); plen = len; while(1) { /* No upper layer, but we do have data. Suspicious. */ if (nh == IPPROTO_NONE && plen > 0) { ENGINE_SET_EVENT(p, IPV6_DATA_AFTER_NONE_HEADER); SCReturn; } if (plen < 2) { /* minimal needed in a hdr */ SCReturn; } switch(nh) { case IPPROTO_TCP: IPV6_SET_L4PROTO(p,nh); DecodeTCP(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_UDP: IPV6_SET_L4PROTO(p,nh); DecodeUDP(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_ICMPV6: IPV6_SET_L4PROTO(p,nh); DecodeICMPV6(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_SCTP: IPV6_SET_L4PROTO(p,nh); DecodeSCTP(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_ROUTING: IPV6_SET_L4PROTO(p,nh); hdrextlen = 8 + (*(pkt+1) * 8); /* 8 bytes + length in 8 octet units */ SCLogDebug("hdrextlen %"PRIu8, hdrextlen); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } if (rh) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_RH); /* skip past this extension so we can continue parsing the rest * of the packet */ nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } rh = 1; IPV6_EXTHDR_SET_RH(p); uint8_t ip6rh_type = *(pkt + 2); if (ip6rh_type == 0) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_RH_TYPE_0); } p->ip6eh.rh_type = ip6rh_type; nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; case IPPROTO_HOPOPTS: case IPPROTO_DSTOPTS: { IPV6OptHAO hao_s, *hao = &hao_s; IPV6OptRA ra_s, *ra = &ra_s; IPV6OptJumbo jumbo_s, *jumbo = &jumbo_s; uint16_t optslen = 0; IPV6_SET_L4PROTO(p,nh); hdrextlen = (*(pkt+1) + 1) << 3; if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } uint8_t *ptr = pkt + 2; /* +2 to go past nxthdr and len */ /* point the pointers to right structures * in Packet. */ if (nh == IPPROTO_HOPOPTS) { if (hh) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_HH); /* skip past this extension so we can continue parsing the rest * of the packet */ nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } hh = 1; optslen = ((*(pkt + 1) + 1 ) << 3) - 2; } else if (nh == IPPROTO_DSTOPTS) { if (dstopts == 0) { optslen = ((*(pkt + 1) + 1 ) << 3) - 2; dstopts = 1; } else if (dstopts == 1) { optslen = ((*(pkt + 1) + 1 ) << 3) - 2; dstopts = 2; } else { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_DH); /* skip past this extension so we can continue parsing the rest * of the packet */ nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } } if (optslen > plen) { /* since the packet is long enough (we checked * plen against hdrlen, the optlen must be malformed. */ ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); /* skip past this extension so we can continue parsing the rest * of the packet */ nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } /** \todo move into own function to loaded on demand */ uint16_t padn_cnt = 0; uint16_t other_cnt = 0; uint16_t offset = 0; while(offset < optslen) { if (*ptr == IPV6OPT_PAD1) { padn_cnt++; offset++; ptr++; continue; } if (offset + 1 >= optslen) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); break; } /* length field for each opt */ uint8_t ip6_optlen = *(ptr + 1); /* see if the optlen from the packet fits the total optslen */ if ((offset + 1 + ip6_optlen) > optslen) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); break; } if (*ptr == IPV6OPT_PADN) /* PadN */ { //printf("PadN option\n"); padn_cnt++; /* a zero padN len would be weird */ if (ip6_optlen == 0) ENGINE_SET_EVENT(p, IPV6_EXTHDR_ZERO_LEN_PADN); } else if (*ptr == IPV6OPT_RA) /* RA */ { ra->ip6ra_type = *(ptr); ra->ip6ra_len = ip6_optlen; if (ip6_optlen < sizeof(ra->ip6ra_value)) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); break; } memcpy(&ra->ip6ra_value, (ptr + 2), sizeof(ra->ip6ra_value)); ra->ip6ra_value = SCNtohs(ra->ip6ra_value); //printf("RA option: type %" PRIu32 " len %" PRIu32 " value %" PRIu32 "\n", // ra->ip6ra_type, ra->ip6ra_len, ra->ip6ra_value); other_cnt++; } else if (*ptr == IPV6OPT_JUMBO) /* Jumbo */ { jumbo->ip6j_type = *(ptr); jumbo->ip6j_len = ip6_optlen; if (ip6_optlen < sizeof(jumbo->ip6j_payload_len)) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); break; } memcpy(&jumbo->ip6j_payload_len, (ptr+2), sizeof(jumbo->ip6j_payload_len)); jumbo->ip6j_payload_len = SCNtohl(jumbo->ip6j_payload_len); //printf("Jumbo option: type %" PRIu32 " len %" PRIu32 " payload len %" PRIu32 "\n", // jumbo->ip6j_type, jumbo->ip6j_len, jumbo->ip6j_payload_len); } else if (*ptr == IPV6OPT_HAO) /* HAO */ { hao->ip6hao_type = *(ptr); hao->ip6hao_len = ip6_optlen; if (ip6_optlen < sizeof(hao->ip6hao_hoa)) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); break; } memcpy(&hao->ip6hao_hoa, (ptr+2), sizeof(hao->ip6hao_hoa)); //printf("HAO option: type %" PRIu32 " len %" PRIu32 " ", // hao->ip6hao_type, hao->ip6hao_len); //char addr_buf[46]; //PrintInet(AF_INET6, (char *)&(hao->ip6hao_hoa), // addr_buf,sizeof(addr_buf)); //printf("home addr %s\n", addr_buf); other_cnt++; } else { if (nh == IPPROTO_HOPOPTS) ENGINE_SET_EVENT(p, IPV6_HOPOPTS_UNKNOWN_OPT); else ENGINE_SET_EVENT(p, IPV6_DSTOPTS_UNKNOWN_OPT); other_cnt++; } uint16_t optlen = (*(ptr + 1) + 2); ptr += optlen; /* +2 for opt type and opt len fields */ offset += optlen; } /* flag packets that have only padding */ if (padn_cnt > 0 && other_cnt == 0) { if (nh == IPPROTO_HOPOPTS) ENGINE_SET_EVENT(p, IPV6_HOPOPTS_ONLY_PADDING); else ENGINE_SET_EVENT(p, IPV6_DSTOPTS_ONLY_PADDING); } nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } case IPPROTO_FRAGMENT: { IPV6_SET_L4PROTO(p,nh); /* store the offset of this extension into the packet * past the ipv6 header. We use it in defrag for creating * a defragmented packet without the frag header */ if (exthdr_fh_done == 0) { p->ip6eh.fh_offset = pkt - orig_pkt; exthdr_fh_done = 1; } uint16_t prev_hdrextlen = hdrextlen; hdrextlen = sizeof(IPV6FragHdr); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } /* for the frag header, the length field is reserved */ if (*(pkt + 1) != 0) { ENGINE_SET_EVENT(p, IPV6_FH_NON_ZERO_RES_FIELD); /* non fatal, lets try to continue */ } if (IPV6_EXTHDR_ISSET_FH(p)) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_FH); nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } /* set the header flag first */ IPV6_EXTHDR_SET_FH(p); /* parse the header and setup the vars */ DecodeIPV6FragHeader(p, pkt, hdrextlen, plen, prev_hdrextlen); /* if FH has offset 0 and no more fragments are coming, we * parse this packet further right away, no defrag will be * needed. It is a useless FH then though, so we do set an * decoder event. */ if (p->ip6eh.fh_more_frags_set == 0 && p->ip6eh.fh_offset == 0) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_USELESS_FH); nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } /* the rest is parsed upon reassembly */ p->flags |= PKT_IS_FRAGMENT; SCReturn; } case IPPROTO_ESP: { IPV6_SET_L4PROTO(p,nh); hdrextlen = sizeof(IPV6EspHdr); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } if (eh) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_EH); SCReturn; } eh = 1; nh = IPPROTO_NONE; pkt += hdrextlen; plen -= hdrextlen; break; } case IPPROTO_AH: { IPV6_SET_L4PROTO(p,nh); /* we need the header as a minimum */ hdrextlen = sizeof(IPV6AuthHdr); /* the payload len field is the number of extra 4 byte fields, * IPV6AuthHdr already contains the first */ if (*(pkt+1) > 0) hdrextlen += ((*(pkt+1) - 1) * 4); SCLogDebug("hdrextlen %"PRIu8, hdrextlen); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } IPV6AuthHdr *ahhdr = (IPV6AuthHdr *)pkt; if (ahhdr->ip6ah_reserved != 0x0000) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_AH_RES_NOT_NULL); } if (ah) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_AH); nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } ah = 1; nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } case IPPROTO_IPIP: IPV6_SET_L4PROTO(p,nh); DecodeIPv4inIPv6(tv, dtv, p, pkt, plen, pq); SCReturn; /* none, last header */ case IPPROTO_NONE: IPV6_SET_L4PROTO(p,nh); SCReturn; case IPPROTO_ICMP: ENGINE_SET_EVENT(p,IPV6_WITH_ICMPV4); SCReturn; /* no parsing yet, just skip it */ case IPPROTO_MH: case IPPROTO_HIP: case IPPROTO_SHIM6: hdrextlen = 8 + (*(pkt+1) * 8); /* 8 bytes + length in 8 octet units */ if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; default: ENGINE_SET_EVENT(p, IPV6_UNKNOWN_NEXT_HEADER); IPV6_SET_L4PROTO(p,nh); SCReturn; } } SCReturn; }
static int DecodeTCPOptions(Packet *p, uint8_t *pkt, uint16_t len) { uint16_t plen = len; while (plen) { /* single byte options */ if (*pkt == TCP_OPT_EOL) { break; } else if (*pkt == TCP_OPT_NOP) { pkt++; plen--; /* multibyte options */ } else { if (plen < 2) { break; } /* we already know that the total options len is valid, * so here the len of the specific option must be bad. * Also check for invalid lengths 0 and 1. */ if (unlikely(*(pkt+1) > plen || *(pkt+1) < 2)) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); return -1; } p->TCP_OPTS[p->TCP_OPTS_CNT].type = *pkt; p->TCP_OPTS[p->TCP_OPTS_CNT].len = *(pkt+1); if (plen > 2) p->TCP_OPTS[p->TCP_OPTS_CNT].data = (pkt+2); else p->TCP_OPTS[p->TCP_OPTS_CNT].data = NULL; /* we are parsing the most commonly used opts to prevent * us from having to walk the opts list for these all the * time. */ switch (p->TCP_OPTS[p->TCP_OPTS_CNT].type) { case TCP_OPT_WS: if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_WS_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.ws != NULL) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { p->tcpvars.ws = &p->TCP_OPTS[p->TCP_OPTS_CNT]; } } break; case TCP_OPT_MSS: if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_MSS_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.mss != NULL) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { p->tcpvars.mss = &p->TCP_OPTS[p->TCP_OPTS_CNT]; } } break; case TCP_OPT_SACKOK: if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_SACKOK_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.sackok != NULL) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { p->tcpvars.sackok = &p->TCP_OPTS[p->TCP_OPTS_CNT]; } } break; case TCP_OPT_TS: if (p->TCP_OPTS[p->TCP_OPTS_CNT].len != TCP_OPT_TS_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.ts != NULL) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { p->tcpvars.ts = &p->TCP_OPTS[p->TCP_OPTS_CNT]; } } break; case TCP_OPT_SACK: SCLogDebug("SACK option, len %u", p->TCP_OPTS[p->TCP_OPTS_CNT].len); if (p->TCP_OPTS[p->TCP_OPTS_CNT].len < TCP_OPT_SACK_MIN_LEN || p->TCP_OPTS[p->TCP_OPTS_CNT].len > TCP_OPT_SACK_MAX_LEN || !((p->TCP_OPTS[p->TCP_OPTS_CNT].len - 2) % 8 == 0)) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.sack != NULL) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { p->tcpvars.sack = &p->TCP_OPTS[p->TCP_OPTS_CNT]; } } break; } pkt += p->TCP_OPTS[p->TCP_OPTS_CNT].len; plen -= (p->TCP_OPTS[p->TCP_OPTS_CNT].len); p->TCP_OPTS_CNT++; } } return 0; }
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { int ret; StatsIncr(tv, dtv->counter_ipv6); /* do the actual decoding */ ret = DecodeIPV6Packet (tv, dtv, p, pkt, len); if (unlikely(ret < 0)) { p->ip6h = NULL; return TM_ECODE_FAILED; } #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); DecodeTCP(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); return TM_ECODE_OK; case IPPROTO_UDP: IPV6_SET_L4PROTO (p, IPPROTO_UDP); DecodeUDP(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); return TM_ECODE_OK; case IPPROTO_ICMPV6: IPV6_SET_L4PROTO (p, IPPROTO_ICMPV6); DecodeICMPV6(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); return TM_ECODE_OK; case IPPROTO_SCTP: IPV6_SET_L4PROTO (p, IPPROTO_SCTP); DecodeSCTP(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); return TM_ECODE_OK; case IPPROTO_IPIP: IPV6_SET_L4PROTO(p, IPPROTO_IPIP); DecodeIPv4inIPv6(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); return TM_ECODE_OK; case IPPROTO_IPV6: DecodeIP6inIP6(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); return TM_ECODE_OK; case IPPROTO_FRAGMENT: case IPPROTO_HOPOPTS: case IPPROTO_ROUTING: case IPPROTO_NONE: case IPPROTO_DSTOPTS: case IPPROTO_AH: case IPPROTO_ESP: case IPPROTO_MH: case IPPROTO_HIP: case IPPROTO_SHIM6: DecodeIPV6ExtHdrs(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq); break; case IPPROTO_ICMP: ENGINE_SET_EVENT(p,IPV6_WITH_ICMPV4); break; default: ENGINE_SET_EVENT(p, IPV6_UNKNOWN_NEXT_HEADER); IPV6_SET_L4PROTO (p, IPV6_GET_NH(p)); break; } p->proto = IPV6_GET_L4PROTO (p); /* Pass to defragger if a fragment. */ if (IPV6_EXTHDR_ISSET_FH(p)) { Packet *rp = Defrag(tv, dtv, p, pq); if (rp != NULL) { PacketEnqueue(pq,rp); } } 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; } }
/** * \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; }
static int DecodeTCPOptions(Packet *p, uint8_t *pkt, uint16_t len) { uint8_t tcp_opt_cnt = 0; TCPOpt tcp_opts[TCP_OPTMAX]; uint16_t plen = len; while (plen) { /* single byte options */ if (*pkt == TCP_OPT_EOL) { break; } else if (*pkt == TCP_OPT_NOP) { pkt++; plen--; /* multibyte options */ } else { if (plen < 2) { break; } /* we already know that the total options len is valid, * so here the len of the specific option must be bad. * Also check for invalid lengths 0 and 1. */ if (unlikely(*(pkt+1) > plen || *(pkt+1) < 2)) { ENGINE_SET_INVALID_EVENT(p, TCP_OPT_INVALID_LEN); return -1; } tcp_opts[tcp_opt_cnt].type = *pkt; tcp_opts[tcp_opt_cnt].len = *(pkt+1); if (plen > 2) tcp_opts[tcp_opt_cnt].data = (pkt+2); else tcp_opts[tcp_opt_cnt].data = NULL; /* we are parsing the most commonly used opts to prevent * us from having to walk the opts list for these all the * time. */ switch (tcp_opts[tcp_opt_cnt].type) { case TCP_OPT_WS: if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_WS_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.ws.type != 0) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { SET_OPTS(p->tcpvars.ws, tcp_opts[tcp_opt_cnt]); } } break; case TCP_OPT_MSS: if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_MSS_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.mss.type != 0) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { SET_OPTS(p->tcpvars.mss, tcp_opts[tcp_opt_cnt]); } } break; case TCP_OPT_SACKOK: if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_SACKOK_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.sackok.type != 0) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { SET_OPTS(p->tcpvars.sackok, tcp_opts[tcp_opt_cnt]); } } break; case TCP_OPT_TS: if (tcp_opts[tcp_opt_cnt].len != TCP_OPT_TS_LEN) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.ts_set) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { uint32_t values[2]; memcpy(&values, tcp_opts[tcp_opt_cnt].data, sizeof(values)); p->tcpvars.ts_val = ntohl(values[0]); p->tcpvars.ts_ecr = ntohl(values[1]); p->tcpvars.ts_set = TRUE; } } break; case TCP_OPT_SACK: SCLogDebug("SACK option, len %u", tcp_opts[tcp_opt_cnt].len); if (tcp_opts[tcp_opt_cnt].len < TCP_OPT_SACK_MIN_LEN || tcp_opts[tcp_opt_cnt].len > TCP_OPT_SACK_MAX_LEN || !((tcp_opts[tcp_opt_cnt].len - 2) % 8 == 0)) { ENGINE_SET_EVENT(p,TCP_OPT_INVALID_LEN); } else { if (p->tcpvars.sack.type != 0) { ENGINE_SET_EVENT(p,TCP_OPT_DUPLICATE); } else { SET_OPTS(p->tcpvars.sack, tcp_opts[tcp_opt_cnt]); } } break; } pkt += tcp_opts[tcp_opt_cnt].len; plen -= (tcp_opts[tcp_opt_cnt].len); tcp_opt_cnt++; } } return 0; }
/** * \brief Get variables and do some checks of the embedded IPV6 packet * * \param p Pointer to the packet we are filling * \param partial_packet Pointer to the raw packet buffer * \param len the len of the rest of the packet not processed yet * * \retval void No return value */ void DecodePartialIPV6(Packet *p, uint8_t *partial_packet, uint16_t len ) { /** Check the sizes, the header must fit at least */ if (len < IPV6_HEADER_LEN) { SCLogDebug("ICMPV6_IPV6_TRUNC_PKT"); ENGINE_SET_EVENT(p, ICMPV6_IPV6_TRUNC_PKT); return; } IPV6Hdr *icmp6_ip6h = (IPV6Hdr*)partial_packet; /** Check the embedded version */ if(((icmp6_ip6h->s_ip6_vfc & 0xf0) >> 4) != 6) { SCLogDebug("ICMPv6 contains Unknown IPV6 version " "ICMPV6_IPV6_UNKNOWN_VER"); ENGINE_SET_EVENT(p, ICMPV6_IPV6_UNKNOWN_VER); return; } /** We need to fill icmpv6vars */ p->icmpv6vars.emb_ipv6h = icmp6_ip6h; /** Get the IP6 address */ p->icmpv6vars.emb_ip6_src[0] = icmp6_ip6h->s_ip6_src[0]; p->icmpv6vars.emb_ip6_src[1] = icmp6_ip6h->s_ip6_src[1]; p->icmpv6vars.emb_ip6_src[2] = icmp6_ip6h->s_ip6_src[2]; p->icmpv6vars.emb_ip6_src[3] = icmp6_ip6h->s_ip6_src[3]; p->icmpv6vars.emb_ip6_dst[0] = icmp6_ip6h->s_ip6_dst[0]; p->icmpv6vars.emb_ip6_dst[1] = icmp6_ip6h->s_ip6_dst[1]; p->icmpv6vars.emb_ip6_dst[2] = icmp6_ip6h->s_ip6_dst[2]; p->icmpv6vars.emb_ip6_dst[3] = icmp6_ip6h->s_ip6_dst[3]; /** Get protocol and ports inside the embedded ipv6 packet and set the pointers */ p->icmpv6vars.emb_ip6_proto_next = icmp6_ip6h->s_ip6_nxt; switch (icmp6_ip6h->s_ip6_nxt) { case IPPROTO_TCP: if (len >= IPV6_HEADER_LEN + TCP_HEADER_LEN ) { p->icmpv6vars.emb_tcph = (TCPHdr*)(partial_packet + IPV6_HEADER_LEN); p->icmpv6vars.emb_sport = p->icmpv6vars.emb_tcph->th_sport; p->icmpv6vars.emb_dport = p->icmpv6vars.emb_tcph->th_dport; SCLogDebug("ICMPV6->IPV6->TCP header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv6vars.emb_sport, p->icmpv6vars.emb_dport); } else { SCLogDebug("Warning, ICMPV6->IPV6->TCP " "header Didn't fit in the packet!"); p->icmpv6vars.emb_sport = 0; p->icmpv6vars.emb_dport = 0; } break; case IPPROTO_UDP: if (len >= IPV6_HEADER_LEN + UDP_HEADER_LEN ) { p->icmpv6vars.emb_udph = (UDPHdr*)(partial_packet + IPV6_HEADER_LEN); p->icmpv6vars.emb_sport = p->icmpv6vars.emb_udph->uh_sport; p->icmpv6vars.emb_dport = p->icmpv6vars.emb_udph->uh_dport; SCLogDebug("ICMPV6->IPV6->UDP header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv6vars.emb_sport, p->icmpv6vars.emb_dport); } else { SCLogDebug("Warning, ICMPV6->IPV6->UDP " "header Didn't fit in the packet!"); p->icmpv6vars.emb_sport = 0; p->icmpv6vars.emb_dport = 0; } break; case IPPROTO_ICMPV6: p->icmpv6vars.emb_icmpv6h = (ICMPV6Hdr*)(partial_packet + IPV6_HEADER_LEN); p->icmpv6vars.emb_sport = 0; p->icmpv6vars.emb_dport = 0; SCLogDebug("ICMPV6->IPV6->ICMP header"); break; } /* debug print */ #ifdef DEBUG char s[46], d[46]; PrintInet(AF_INET6, (const void *)p->icmpv6vars.emb_ip6_src, s, sizeof(s)); PrintInet(AF_INET6, (const void *)p->icmpv6vars.emb_ip6_dst, d, sizeof(d)); SCLogDebug("ICMPv6 embedding IPV6 %s->%s - CLASS: %" PRIu32 " FLOW: " "%" PRIu32 " NH: %" PRIu32 " PLEN: %" PRIu32 " HLIM: %" PRIu32, s, d, IPV6_GET_RAW_CLASS(icmp6_ip6h), IPV6_GET_RAW_FLOW(icmp6_ip6h), IPV6_GET_RAW_NH(icmp6_ip6h), IPV6_GET_RAW_PLEN(icmp6_ip6h), IPV6_GET_RAW_HLIM(icmp6_ip6h)); #endif return; }
/** DecodeICMPV4 * \brief Main ICMPv4 decoding function */ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { StatsIncr(tv, dtv->counter_icmpv4); if (len < ICMPV4_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, ICMPV4_PKT_TOO_SMALL); return TM_ECODE_FAILED; } 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) { if (DecodePartialIPV4(p, (uint8_t *)(pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ) == 0) { /* ICMP ICMP_DEST_UNREACH influence TCP/UDP flows */ if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { FlowHandlePacket(tv, dtv, 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 TM_ECODE_OK; }
int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { StatsIncr(tv, dtv->counter_ppp); if (unlikely(len < PPP_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, PPP_PKT_TOO_SMALL); return TM_ECODE_FAILED; } p->ppph = (PPPHdr *)pkt; if (unlikely(p->ppph == NULL)) return TM_ECODE_FAILED; 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_INVALID_EVENT(p,PPPVJU_PKT_TOO_SMALL); p->ppph = NULL; return TM_ECODE_FAILED; } if (likely(IPV4_GET_RAW_VER((IPV4Hdr *)(pkt + PPP_HEADER_LEN)) == 4)) { return DecodeIPV4(tv, dtv, p, pkt + PPP_HEADER_LEN, len - PPP_HEADER_LEN, pq); } else return TM_ECODE_FAILED; break; case PPP_IP: if (unlikely(len < (PPP_HEADER_LEN + IPV4_HEADER_LEN))) { ENGINE_SET_INVALID_EVENT(p,PPPIPV4_PKT_TOO_SMALL); p->ppph = NULL; return TM_ECODE_FAILED; } return DecodeIPV4(tv, dtv, p, pkt + PPP_HEADER_LEN, len - PPP_HEADER_LEN, pq); /* PPP IPv6 was not tested */ case PPP_IPV6: if (unlikely(len < (PPP_HEADER_LEN + IPV6_HEADER_LEN))) { ENGINE_SET_INVALID_EVENT(p,PPPIPV6_PKT_TOO_SMALL); p->ppph = NULL; return TM_ECODE_FAILED; } return DecodeIPV6(tv, dtv, p, pkt + PPP_HEADER_LEN, len - PPP_HEADER_LEN, pq); 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); return TM_ECODE_OK; default: SCLogDebug("unknown PPP protocol: %" PRIx32 "",ntohs(p->ppph->protocol)); ENGINE_SET_INVALID_EVENT(p, PPP_WRONG_TYPE); return TM_ECODE_OK; } }
int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { uint32_t shim; int label; int event = 0; StatsIncr(tv, dtv->counter_mpls); do { if (len < MPLS_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, MPLS_HEADER_TOO_SMALL); return TM_ECODE_FAILED; } shim = *(uint32_t *)pkt; pkt += MPLS_HEADER_LEN; len -= MPLS_HEADER_LEN; } while (MPLS_BOTTOM(shim) == 0); label = MPLS_LABEL(shim); if (label == MPLS_LABEL_IPV4) { return DecodeIPV4(tv, dtv, p, pkt, len, pq); } else if (label == MPLS_LABEL_ROUTER_ALERT) { /* Not valid at the bottom of the stack. */ event = MPLS_BAD_LABEL_ROUTER_ALERT; } else if (label == MPLS_LABEL_IPV6) { return DecodeIPV6(tv, dtv, p, pkt, len, pq); } else if (label == MPLS_LABEL_NULL) { /* Shouldn't appear on the wire. */ event = MPLS_BAD_LABEL_IMPLICIT_NULL; } else if (label < MPLS_MAX_RESERVED_LABEL) { event = MPLS_BAD_LABEL_RESERVED; } if (event) { goto end; } /* Best guess at inner packet. */ switch (pkt[0] >> 4) { case MPLS_PROTO_IPV4: DecodeIPV4(tv, dtv, p, pkt, len, pq); break; case MPLS_PROTO_IPV6: DecodeIPV6(tv, dtv, p, pkt, len, pq); break; case MPLS_PROTO_ETHERNET_PW: DecodeEthernet(tv, dtv, p, pkt + MPLS_PW_LEN, len - MPLS_PW_LEN, pq); break; default: ENGINE_SET_INVALID_EVENT(p, MPLS_UNKNOWN_PAYLOAD_TYPE); return TM_ECODE_OK; } end: if (event) { ENGINE_SET_EVENT(p, event); } return TM_ECODE_OK; }
/** * Note, this is the IP header, plus a bit of the original packet, not the whole thing! */ void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) { /** Check the sizes, the header must fit at least */ if (len < IPV4_HEADER_LEN) { SCLogDebug("DecodePartialIPV4: ICMPV4_IPV4_TRUNC_PKT"); ENGINE_SET_EVENT(p, ICMPV4_IPV4_TRUNC_PKT); return; } IPV4Hdr *icmp4_ip4h = (IPV4Hdr*)partial_packet; /** Check the embedded version */ if (IPV4_GET_RAW_VER(icmp4_ip4h) != 4) { /** Check the embedded version */ SCLogDebug("DecodePartialIPV4: ICMPv4 contains Unknown IPV4 version " "ICMPV4_IPV4_UNKNOWN_VER"); ENGINE_SET_EVENT(p, ICMPV4_IPV4_UNKNOWN_VER); return; } /** We need to fill icmpv4vars */ p->icmpv4vars.emb_ipv4h = icmp4_ip4h; /** Get the IP address from the contained packet */ p->icmpv4vars.emb_ip4_src = IPV4_GET_RAW_IPSRC(icmp4_ip4h); p->icmpv4vars.emb_ip4_dst = IPV4_GET_RAW_IPDST(icmp4_ip4h); p->icmpv4vars.emb_ip4_hlen=IPV4_GET_RAW_HLEN(icmp4_ip4h) << 2; switch (IPV4_GET_RAW_IPPROTO(icmp4_ip4h)) { case IPPROTO_TCP: if (len >= IPV4_HEADER_LEN + TCP_HEADER_LEN ) { p->icmpv4vars.emb_tcph = (TCPHdr*)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_sport = ntohs(p->icmpv4vars.emb_tcph->th_sport); p->icmpv4vars.emb_dport = ntohs(p->icmpv4vars.emb_tcph->th_dport); p->icmpv4vars.emb_ip4_proto = IPPROTO_TCP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->TCP header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv4vars.emb_sport, p->icmpv4vars.emb_dport); } else if (len >= IPV4_HEADER_LEN + 4) { /* only access th_sport and th_dport */ TCPHdr *emb_tcph = (TCPHdr*)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_tcph = NULL; p->icmpv4vars.emb_sport = ntohs(emb_tcph->th_sport); p->icmpv4vars.emb_dport = ntohs(emb_tcph->th_dport); p->icmpv4vars.emb_ip4_proto = IPPROTO_TCP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->TCP partial header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv4vars.emb_sport, p->icmpv4vars.emb_dport); } else { SCLogDebug("DecodePartialIPV4: Warning, ICMPV4->IPV4->TCP " "header Didn't fit in the packet!"); p->icmpv4vars.emb_sport = 0; p->icmpv4vars.emb_dport = 0; } break; case IPPROTO_UDP: if (len >= IPV4_HEADER_LEN + UDP_HEADER_LEN ) { p->icmpv4vars.emb_udph = (UDPHdr*)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_sport = ntohs(p->icmpv4vars.emb_udph->uh_sport); p->icmpv4vars.emb_dport = ntohs(p->icmpv4vars.emb_udph->uh_dport); p->icmpv4vars.emb_ip4_proto = IPPROTO_UDP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->UDP header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv4vars.emb_sport, p->icmpv4vars.emb_dport); } else { SCLogDebug("DecodePartialIPV4: Warning, ICMPV4->IPV4->UDP " "header Didn't fit in the packet!"); p->icmpv4vars.emb_sport = 0; p->icmpv4vars.emb_dport = 0; } break; case IPPROTO_ICMP: p->icmpv4vars.emb_icmpv4h = (ICMPV4Hdr*)(partial_packet + IPV4_HEADER_LEN); p->icmpv4vars.emb_sport = 0; p->icmpv4vars.emb_dport = 0; p->icmpv4vars.emb_ip4_proto = IPPROTO_ICMP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->ICMP header"); break; } /* debug print */ #ifdef DEBUG char s[16], d[16]; PrintInet(AF_INET, &(p->icmpv4vars.emb_ip4_src), s, sizeof(s)); PrintInet(AF_INET, &(p->icmpv4vars.emb_ip4_dst), d, sizeof(d)); SCLogDebug("ICMPv4 embedding IPV4 %s->%s - PROTO: %" PRIu32 " ID: %" PRIu32 "", s,d, IPV4_GET_RAW_IPPROTO(icmp4_ip4h), IPV4_GET_RAW_IPID(icmp4_ip4h)); #endif 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; }
/** * \brief Main decoding function for PPPOE Discovery packets */ void 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_EVENT(p, PPPOE_PKT_TOO_SMALL); return; } p->pppoedh = NULL; p->pppoedh = (PPPOEDiscoveryHdr *)pkt; if (p->pppoedh == NULL) return; /* 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_EVENT(p,PPPOE_WRONG_CODE); return; } /* 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_EVENT(p,PPPOE_MALFORMED_TAGS); return; } 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; }