diff --git a/src/Makefile.am b/src/Makefile.am index b078c99f53..609539a806 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,6 +14,7 @@ source-pfring.c source-pfring.h \ source-ipfw.c source-ipfw.h \ decode.c decode.h \ decode-ethernet.c decode-ethernet.h \ +decode-vlan.c decode-vlan.h \ decode-sll.c decode-sll.h \ decode-gre.c decode-gre.h \ decode-ppp.c decode-ppp.h \ diff --git a/src/decode-ethernet.c b/src/decode-ethernet.c index d95e4f75f8..daab991aa9 100644 --- a/src/decode-ethernet.c +++ b/src/decode-ethernet.c @@ -44,6 +44,10 @@ void DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *p DecodePPPOEDiscovery(tv, dtv, p, pkt + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, pq); break; + case ETHERNET_TYPE_VLAN: + DecodeVLAN(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)); diff --git a/src/decode-events.h b/src/decode-events.h index 7ca811e503..b34c14d0c3 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -97,6 +97,10 @@ enum { GRE_VERSION1_MALFORMED_SRE_HDR, GRE_VERSION1_HDR_TOO_BIG, + /* VLAN EVENTS */ + VLAN_HEADER_TOO_SMALL, + VLAN_UNKNOWN_TYPE, + /* RAW EVENTS */ IPRAW_INVALID_IPV, }; diff --git a/src/decode-gre.c b/src/decode-gre.c index f4180bea65..a126b45613 100644 --- a/src/decode-gre.c +++ b/src/decode-gre.c @@ -174,7 +174,7 @@ void DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u { if (pq != NULL) { - Packet *tp = TunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, GRE_GET_PROTO(p->greh)); + Packet *tp = TunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, IPPROTO_IP); DecodeTunnel(tv, dtv, tp, tp->pkt, tp->pktlen, pq); PacketEnqueue(pq,tp); @@ -187,7 +187,7 @@ void DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u { if (pq != NULL) { - Packet *tp = TunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, GRE_GET_PROTO(p->greh)); + Packet *tp = TunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, PPP_OVER_GRE); DecodeTunnel(tv, dtv, tp, tp->pkt, tp->pktlen, pq); PacketEnqueue(pq,tp); @@ -200,7 +200,7 @@ void DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u { if (pq != NULL) { - Packet *tp = TunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, GRE_GET_PROTO(p->greh)); + Packet *tp = TunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, IPPROTO_IPV6); DecodeTunnel(tv, dtv, tp, tp->pkt, tp->pktlen, pq); PacketEnqueue(pq,tp); @@ -208,6 +208,20 @@ void DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u } break; } + + case ETHERNET_TYPE_VLAN: + { + if (pq != NULL) { + + Packet *tp = TunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, VLAN_OVER_GRE); + DecodeTunnel(tv, dtv, tp, tp->pkt, tp->pktlen, pq); + PacketEnqueue(pq,tp); + + SET_TUNNEL_PKT(p); + } + break; + } + default: return; } diff --git a/src/decode-sll.c b/src/decode-sll.c index 44e1b838d9..0db7927fa5 100644 --- a/src/decode-sll.c +++ b/src/decode-sll.c @@ -21,12 +21,21 @@ void DecodeSll(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, u SCLogDebug("p %p pkt %p sll_protocol %04x", p, pkt, ntohs(sllh->sll_protocol)); - if (ntohs(sllh->sll_protocol) == ETHERNET_TYPE_IP) { - //printf("DecodeSll ip4\n"); - DecodeIPV4(tv, dtv, p, pkt + SLL_HEADER_LEN, len - SLL_HEADER_LEN, pq); - } else if(ntohs(sllh->sll_protocol) == ETHERNET_TYPE_IPV6) { - //printf("DecodeSll ip6\n"); - DecodeIPV6(tv, dtv, p, pkt + SLL_HEADER_LEN, len - SLL_HEADER_LEN, pq); + 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)); } } - diff --git a/src/decode-vlan.c b/src/decode-vlan.c new file mode 100644 index 0000000000..544bcb1af2 --- /dev/null +++ b/src/decode-vlan.c @@ -0,0 +1,190 @@ +/* Copyright (c) 2009 Open Information Security Foundation */ + +/** \file + * \author Breno Silva + */ + +#include "suricata-common.h" +#include "decode.h" +#include "decode-vlan.h" +#include "decode-events.h" + +#include "flow.h" + +#include "util-unittest.h" +#include "util-debug.h" + +/** + * \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; +} + +#ifdef UNITTESTS +/** \todo Must GRE+VLAN and Multi-Vlan packets to + * create more tests + */ + +/** + * \test DecodeVLANTest01 test if vlan header is too small. + * + * \retval 1 on success + * \retval 0 on failure + */ +static int DecodeVLANtest01 (void) { + uint8_t raw_vlan[] = { 0x00, 0x20, 0x08 }; + Packet p; + ThreadVars tv; + DecodeThreadVars dtv; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&p, 0, sizeof(Packet)); + memset(&dtv, 0, sizeof(DecodeThreadVars)); + + DecodeVLAN(&tv, &dtv, &p, raw_vlan, sizeof(raw_vlan), NULL); + + if(DECODER_ISSET_EVENT(&p,VLAN_HEADER_TOO_SMALL)) { + return 1; + } + + return 0; +} + +/** + * \test DecodeVLANTest02 test if vlan header has unknown type. + * + * \retval 1 on success + * \retval 0 on failure + */ +static int DecodeVLANtest02 (void) { + uint8_t raw_vlan[] = { + 0x00, 0x20, 0x01, 0x00, 0x45, 0x00, 0x00, 0x34, + 0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9, + 0x83, 0x97, 0x20, 0x81, 0x83, 0x97, 0x20, 0x15, + 0x04, 0x8a, 0x17, 0x70, 0x4e, 0x14, 0xdf, 0x55, + 0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50, + 0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, + 0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3}; + Packet p; + ThreadVars tv; + DecodeThreadVars dtv; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&p, 0, sizeof(Packet)); + memset(&dtv, 0, sizeof(DecodeThreadVars)); + + DecodeVLAN(&tv, &dtv, &p, raw_vlan, sizeof(raw_vlan), NULL); + + + if(DECODER_ISSET_EVENT(&p,VLAN_UNKNOWN_TYPE)) { + return 1; + } + + return 0; +} + +/** + * \test DecodeVLANTest02 test a good vlan header. + * + * \retval 1 on success + * \retval 0 on failure + */ +static int DecodeVLANtest03 (void) { + uint8_t raw_vlan[] = { + 0x00, 0x20, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34, + 0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9, + 0x83, 0x97, 0x20, 0x81, 0x83, 0x97, 0x20, 0x15, + 0x04, 0x8a, 0x17, 0x70, 0x4e, 0x14, 0xdf, 0x55, + 0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50, + 0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, + 0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3}; + Packet p; + ThreadVars tv; + DecodeThreadVars dtv; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&p, 0, sizeof(Packet)); + memset(&dtv, 0, sizeof(DecodeThreadVars)); + + FlowInitConfig(FLOW_QUIET); + + DecodeVLAN(&tv, &dtv, &p, raw_vlan, sizeof(raw_vlan), NULL); + + FlowShutdown(); + + if(p.vlanh == NULL) { + return 0; + } + + if(DECODER_ISSET_EVENT(&p,VLAN_HEADER_TOO_SMALL)) { + return 0; + } + + if(DECODER_ISSET_EVENT(&p,VLAN_UNKNOWN_TYPE)) { + return 0; + } + + return 1; +} +#endif /* UNITTESTS */ + +void DecodeVLANRegisterTests(void) { +#ifdef UNITTESTS + UtRegisterTest("DecodeVLANtest01", DecodeVLANtest01, 1); + UtRegisterTest("DecodeVLANtest02", DecodeVLANtest02, 1); + UtRegisterTest("DecodeVLANtest03", DecodeVLANtest03, 1); +#endif /* UNITTESTS */ +} + diff --git a/src/decode-vlan.h b/src/decode-vlan.h new file mode 100644 index 0000000000..05244acc41 --- /dev/null +++ b/src/decode-vlan.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2009 Open Information Security Foundation */ + +/** \file + * \author Breno Silva + */ + + +#ifndef __DECODE_VLAN_H__ +#define __DECODE_VLAN_H__ + +/** Vlan type */ +#define ETHERNET_TYPE_VLAN 0x8100 + +/** Vlan macros to access Vlan priority, Vlan CFI and VID */ +#define GET_VLAN_PRIORITY(vlanh) ((ntohs((vlanh)->vlan_cfi) & 0xe000) >> 13) +#define GET_VLAN_CFI(vlanh) ((ntohs((vlanh)->vlan_cfi) & 0x0100) >> 12) +#define GET_VLAN_ID(vlanh) ((unsigned short)(ntohs((vlanh)->vlan_cfi) & 0x0FFF)) +#define GET_VLAN_PROTO(vlanh) ((ntohs((vlanh)->protocol))) + +/** Vlan header struct */ +typedef struct _VLANHdr { + uint16_t vlan_cfi; + uint16_t protocol; /** protocol field */ +}VLANHdr; + +/** VLAN header length */ +#define VLAN_HEADER_LEN 4 + +void DecodeVLANRegisterTests(void); + +#endif /* __DECODE_VLAN_H__ */ diff --git a/src/decode.c b/src/decode.c index e12d3dca5d..26a685883d 100644 --- a/src/decode.c +++ b/src/decode.c @@ -11,11 +11,12 @@ void DecodeTunnel(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt switch (p->tunnel_proto) { case PPP_OVER_GRE: return DecodePPP(tv, dtv, p, pkt, len, pq); - break; case IPPROTO_IP: return DecodeIPV4(tv, dtv, p, pkt, len, pq); case IPPROTO_IPV6: return DecodeIPV6(tv, dtv, p, pkt, len, pq); + case VLAN_OVER_GRE: + return DecodeVLAN(tv, dtv, p, pkt, len, pq); default: SCLogInfo("FIXME: DecodeTunnel: protocol %" PRIu32 " not supported.", p->tunnel_proto); break; @@ -82,6 +83,8 @@ void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_gre = SCPerfTVRegisterCounter("decoder.gre", tv, SC_PERF_TYPE_UINT64, "NULL"); + dtv->counter_vlan = SCPerfTVRegisterCounter("decoder.vlan", tv, + SC_PERF_TYPE_UINT64, "NULL"); dtv->counter_avg_pkt_size = SCPerfTVRegisterAvgCounter("decoder.avg_pkt_size", tv, SC_PERF_TYPE_DOUBLE, "NULL"); dtv->counter_max_pkt_size = SCPerfTVRegisterMaxCounter("decoder.max_pkt_size", tv, diff --git a/src/decode.h b/src/decode.h index d6fe753410..7bbce4d70f 100644 --- a/src/decode.h +++ b/src/decode.h @@ -32,6 +32,7 @@ #include "decode-tcp.h" #include "decode-udp.h" #include "decode-raw.h" +#include "decode-vlan.h" /* Address */ typedef struct Address_ @@ -263,6 +264,7 @@ typedef struct Packet_ PPPOESessionHdr *pppoesh; PPPOEDiscoveryHdr *pppoedh; GREHdr *greh; + VLANHdr *vlanh; IPV4Hdr *ip4h; IPV4Vars ip4vars; @@ -348,6 +350,7 @@ typedef struct DecodeThreadVars_ uint16_t counter_icmpv6; uint16_t counter_ppp; uint16_t counter_gre; + uint16_t counter_vlan; uint16_t counter_pppoe; uint16_t counter_avg_pkt_size; uint16_t counter_max_pkt_size; @@ -373,6 +376,7 @@ typedef struct DecodeThreadVars_ (p)->ethh = NULL; \ (p)->ppph = NULL; \ (p)->greh = NULL; \ + (p)->vlanh = NULL; \ (p)->ip4h = NULL; \ (p)->ip6h = NULL; \ (p)->action = 0; \ @@ -467,6 +471,7 @@ void DecodeICMPV6(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_ void DecodeTCP(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodeUDP(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); void DecodeGRE(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); +void DecodeVLAN(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, PacketQueue *); Packet *SetupPkt (void); Packet *TunnelPktSetup(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, uint16_t, uint8_t); @@ -507,6 +512,7 @@ inline void DecodeSetNoPacketInspectionFlag(Packet *); #define LINKTYPE_PPP 9 #define LINKTYPE_RAW DLT_RAW #define PPP_OVER_GRE 11 +#define VLAN_OVER_GRE 13 /*Packet Flags*/ #define PKT_NOPACKET_INSPECTION 0x01 /**< Flag to indicate that packet header or contents should not be inspected*/ diff --git a/src/detect-decode-event.h b/src/detect-decode-event.h index 74a658c59b..7438dd1e76 100644 --- a/src/detect-decode-event.h +++ b/src/detect-decode-event.h @@ -81,6 +81,8 @@ struct DetectDecodeEvents_ { { "gre.version1_malformed_sre_hdr", GRE_VERSION1_MALFORMED_SRE_HDR, }, { "gre.version1_hdr_too_big", GRE_VERSION1_HDR_TOO_BIG, }, { "ipraw.wrong_ip_version",IPRAW_INVALID_IPV, }, + { "vlan.hlen_too_small",VLAN_HEADER_TOO_SMALL, }, + { "vlan.unknown_type",VLAN_UNKNOWN_TYPE, }, { NULL, 0 }, }; #endif /* DETECT_EVENTS */ diff --git a/src/suricata.c b/src/suricata.c index 86799d7eb7..4a69059b9c 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -683,6 +683,7 @@ int main(int argc, char **argv) FlowAlertSidRegisterTests(); SCPerfRegisterTests(); DecodePPPRegisterTests(); + DecodeVLANRegisterTests(); HTPParserRegisterTests(); TLSParserRegisterTests(); SMBParserRegisterTests();