int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { StatsIncr(tv, dtv->counter_eth); if (unlikely(len < ETHERNET_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, ETHERNET_PKT_TOO_SMALL); return TM_ECODE_FAILED; } p->ethh = (EthernetHdr *)pkt; if (unlikely(p->ethh == NULL)) return TM_ECODE_FAILED; SCLogDebug("p %p pkt %p ether type %04x", p, pkt, ntohs(p->ethh->eth_type)); switch (ntohs(p->ethh->eth_type)) { case ETHERNET_TYPE_IP: //printf("DecodeEthernet ip4\n"); DecodeIPV4(tv, dtv, p, pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, pq); break; case ETHERNET_TYPE_IPV6: //printf("DecodeEthernet ip6\n"); DecodeIPV6(tv, dtv, p, pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, pq); break; case ETHERNET_TYPE_PPPOE_SESS: //printf("DecodeEthernet PPPOE Session\n"); DecodePPPOESession(tv, dtv, p, pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, pq); break; case ETHERNET_TYPE_PPPOE_DISC: //printf("DecodeEthernet PPPOE Discovery\n"); DecodePPPOEDiscovery(tv, dtv, p, pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, pq); break; case ETHERNET_TYPE_VLAN: case ETHERNET_TYPE_8021QINQ: DecodeVLAN(tv, dtv, p, pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, pq); break; case ETHERNET_TYPE_MPLS_UNICAST: case ETHERNET_TYPE_MPLS_MULTICAST: DecodeMPLS(tv, dtv, p, pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, pq); break; default: SCLogDebug("p %p pkt %p ether type %04x not supported", p, pkt, ntohs(p->ethh->eth_type)); } return 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; }
/** DecodePPPOEtest02 * \brief Valid PPPOE packet - check the invalid ICMP type encapsulated is flagged * \retval 0 Expected test value */ static int DecodePPPOEtest02 (void) { uint8_t raw_pppoe[] = { 0x11, 0x00, 0x00, 0x01, 0x00, 0x40, 0x00, 0x21, 0x45, 0x00, 0x00, 0x3c, 0x05, 0x5c, 0x00, 0x00, 0x20, 0x01, 0xff, 0x30, 0xc0, 0xa8, 0x0a, 0x7f, 0xc0, 0xa8, 0x0a, 0x65, 0xab, 0xcd, 0x16, 0x5e, 0x02, 0x00, 0x37, 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (p == NULL) return 0; ThreadVars tv; DecodeThreadVars dtv; int ret = 0; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); FlowInitConfig(FLOW_QUIET); DecodePPPOESession(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL); if(DECODER_ISSET_EVENT(p,PPPOE_PKT_TOO_SMALL)) { goto end; } // and we insist that the invalid ICMP encapsulated (type 0xab, code 0xcd) is flagged if(! DECODER_ISSET_EVENT(p,ICMPV4_UNKNOWN_TYPE)) { goto end; } ret = 1; end: FlowShutdown(); SCFree(p); return ret; }
/** DecodePPPOEtest01 * \brief Decode malformed PPPOE packet (too short) * \retval 1 Expected test value */ static int DecodePPPOEtest01 (void) { uint8_t raw_pppoe[] = { 0x11, 0x00, 0x00, 0x00, 0x00 }; Packet *p = PacketGetFromAlloc(); if (unlikely(p == NULL)) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodePPPOESession(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL); if (ENGINE_ISSET_EVENT(p,PPPOE_PKT_TOO_SMALL)) { SCFree(p); return 1; } SCFree(p); return 0; }
/** DecodePPPOEtest01 * \brief Decode malformed PPPOE packet (too short) * \retval 1 Expected test value */ static int DecodePPPOEtest01 (void) { uint8_t raw_pppoe[] = { 0x11, 0x00, 0x00, 0x00, 0x00 }; Packet *p = SCMalloc(SIZE_OF_PACKET); if (p == NULL) return 0; ThreadVars tv; DecodeThreadVars dtv; memset(&tv, 0, sizeof(ThreadVars)); memset(p, 0, SIZE_OF_PACKET); p->pkt = (uint8_t *)(p + 1); memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodePPPOESession(&tv, &dtv, p, raw_pppoe, sizeof(raw_pppoe), NULL); if (DECODER_ISSET_EVENT(p,PPPOE_PKT_TOO_SMALL)) { SCFree(p); return 1; } SCFree(p); return 0; }
/** * \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; }