static int DecodeIPV6Packet (ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len) { if (unlikely(len < IPV6_HEADER_LEN)) { return -1; } if (unlikely(IP_GET_RAW_VER(pkt) != 6)) { SCLogDebug("wrong ip version %" PRIu8 "",IP_GET_RAW_VER(pkt)); ENGINE_SET_INVALID_EVENT(p, IPV6_WRONG_IP_VER); return -1; } p->ip6h = (IPV6Hdr *)pkt; if (unlikely(len < (IPV6_HEADER_LEN + IPV6_GET_PLEN(p)))) { ENGINE_SET_INVALID_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_INVALID_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_INVALID_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_INVALID_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; }
static int DecodeUDPPacket(ThreadVars *t, Packet *p, uint8_t *pkt, uint16_t len) { if (unlikely(len < UDP_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, UDP_HLEN_TOO_SMALL); return -1; } p->udph = (UDPHdr *)pkt; if (unlikely(len < UDP_GET_LEN(p))) { ENGINE_SET_INVALID_EVENT(p, UDP_PKT_TOO_SMALL); return -1; } if (unlikely(len != UDP_GET_LEN(p))) { ENGINE_SET_INVALID_EVENT(p, UDP_HLEN_INVALID); return -1; } SET_UDP_SRC_PORT(p,&p->sp); SET_UDP_DST_PORT(p,&p->dp); p->payload = pkt + UDP_HEADER_LEN; p->payload_len = len - UDP_HEADER_LEN; p->proto = IPPROTO_UDP; 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; }
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; }
static int DecodeSCTPPacket(ThreadVars *tv, Packet *p, uint8_t *pkt, uint16_t len) { if (unlikely(len < SCTP_HEADER_LEN)) { ENGINE_SET_INVALID_EVENT(p, SCTP_PKT_TOO_SMALL); return -1; } p->sctph = (SCTPHdr *)pkt; SET_SCTP_SRC_PORT(p,&p->sp); SET_SCTP_DST_PORT(p,&p->dp); p->payload = pkt + sizeof(SCTPHdr); p->payload_len = len - sizeof(SCTPHdr); p->proto = IPPROTO_SCTP; 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; }
/** * Note, this is the IP header, plus a bit of the original packet, not the whole thing! */ int 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_INVALID_EVENT(p, ICMPV4_IPV4_TRUNC_PKT); return -1; } 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_INVALID_EVENT(p, ICMPV4_IPV4_UNKNOWN_VER); return -1; } /** 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: if (len >= IPV4_HEADER_LEN + ICMPV4_HEADER_LEN ) { 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 0; }
/** 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 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; StatsIncr(tv, dtv->counter_gre); if(len < GRE_HDR_LEN) { ENGINE_SET_INVALID_EVENT(p, GRE_PKT_TOO_SMALL); return TM_ECODE_FAILED; } p->greh = (GREHdr *)pkt; if(p->greh == NULL) return TM_ECODE_FAILED; 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_INVALID_EVENT(p, GRE_VERSION0_RECUR); return TM_ECODE_OK; } if (GREV1_FLAG_ISSET_FLAGS(p->greh)) { ENGINE_SET_INVALID_EVENT(p, GRE_VERSION0_FLAGS); return TM_ECODE_OK; } /* 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_INVALID_EVENT(p, GRE_VERSION0_HDR_TOO_BIG); return TM_ECODE_OK; } if (GRE_FLAG_ISSET_ROUTE(p->greh)) { while (1) { if ((header_len + GRE_SRE_HDR_LEN) > len) { ENGINE_SET_INVALID_EVENT(p, GRE_VERSION0_MALFORMED_SRE_HDR); return TM_ECODE_OK; } 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_INVALID_EVENT(p, GRE_VERSION0_MALFORMED_SRE_HDR); return TM_ECODE_OK; } } } 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_INVALID_EVENT(p,GRE_VERSION1_CHKSUM); return TM_ECODE_OK; } if (GRE_FLAG_ISSET_ROUTE(p->greh)) { ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_ROUTE); return TM_ECODE_OK; } if (GRE_FLAG_ISSET_SSR(p->greh)) { ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_SSR); return TM_ECODE_OK; } if (GRE_FLAG_ISSET_RECUR(p->greh)) { ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_RECUR); return TM_ECODE_OK; } if (GREV1_FLAG_ISSET_FLAGS(p->greh)) { ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_FLAGS); return TM_ECODE_OK; } if (GRE_GET_PROTO(p->greh) != GRE_PROTO_PPP) { ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_WRONG_PROTOCOL); return TM_ECODE_OK; } if (!(GRE_FLAG_ISSET_KY(p->greh))) { ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_NO_KEY); return TM_ECODE_OK; } 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_INVALID_EVENT(p, GRE_VERSION1_HDR_TOO_BIG); return TM_ECODE_OK; } break; default: ENGINE_SET_INVALID_EVENT(p, GRE_WRONG_VERSION); return TM_ECODE_OK; } switch (GRE_GET_PROTO(p->greh)) { case ETHERNET_TYPE_IP: { if (pq != NULL) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, DECODE_TUNNEL_IPV4, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); PacketEnqueue(pq,tp); } } break; } case GRE_PROTO_PPP: { if (pq != NULL) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, DECODE_TUNNEL_PPP, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); PacketEnqueue(pq,tp); } } break; } case ETHERNET_TYPE_IPV6: { if (pq != NULL) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, DECODE_TUNNEL_IPV6, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); PacketEnqueue(pq,tp); } } break; } case ETHERNET_TYPE_VLAN: { if (pq != NULL) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, DECODE_TUNNEL_VLAN, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); PacketEnqueue(pq,tp); } } break; } case ETHERNET_TYPE_ERSPAN: { if (pq != NULL) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, DECODE_TUNNEL_ERSPAN, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); PacketEnqueue(pq,tp); } } break; } case ETHERNET_TYPE_BRIDGE: { if (pq != NULL) { Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, DECODE_TUNNEL_ETHERNET, pq); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); PacketEnqueue(pq,tp); } } break; } default: return TM_ECODE_OK; } return TM_ECODE_OK; }
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 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; }
/** * \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; }
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_INVALID_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 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; }
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; } }
/** * \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; }
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; }