]> git.ipfire.org Git - people/ms/suricata.git/commitdiff
GRE support
authorBreno Silva <breno.silva@gmail.com>
Sun, 23 Aug 2009 03:24:13 +0000 (00:24 -0300)
committerVictor Julien <victor@inliniac.net>
Sun, 23 Aug 2009 10:01:22 +0000 (12:01 +0200)
src/Makefile.am
src/decode-events.h
src/decode-gre.c [new file with mode: 0644]
src/decode-gre.h [new file with mode: 0644]
src/decode.c
src/decode.h
src/detect-decode-event.h
src/eidps.c

index 359f8f475914a289c8ba0b2ef32c86f052315a6d..c86d9d96c6b1e13c8a80bc05a4bcff7d89636bcb 100644 (file)
@@ -8,6 +8,7 @@ source-pcap-file.c source-pcap-file.h \
 decode.c decode.h \
 decode-ethernet.c decode-ethernet.h \
 decode-sll.c decode-sll.h \
+decode-gre.c decode-gre.h \
 decode-ppp.c decode-ppp.h \
 decode-pppoe.c decode-pppoe.h \
 decode-ipv4.c decode-ipv4.h \
index e64070d6e83fd9bb71df1cd1435fb669d4d33e6a..f7c4f8b8e46526f07c35a2f360385823cd3f346d 100644 (file)
@@ -62,6 +62,23 @@ enum {
 
     /* PPPOE EVENTS */
     PPPOE_PKT_TOO_SMALL,
+
+    /* GRE EVENTS */
+    GRE_PKT_TOO_SMALL,
+    GRE_WRONG_VERSION,
+    GRE_VERSION0_RECUR,
+    GRE_VERSION0_FLAGS,
+    GRE_VERSION0_HDR_TOO_BIG,
+    GRE_VERSION1_CHKSUM,
+    GRE_VERSION1_ROUTE,
+    GRE_VERSION1_SSR,
+    GRE_VERSION1_RECUR,
+    GRE_VERSION1_FLAGS,
+    GRE_VERSION1_NO_KEY,
+    GRE_VERSION1_WRONG_PROTOCOL,
+    GRE_VERSION1_MALFORMED_SRE_HDR,
+    GRE_VERSION1_HDR_TOO_BIG,
+
 };
 
 #endif /* __DECODE_EVENTS_H__ */
diff --git a/src/decode-gre.c b/src/decode-gre.c
new file mode 100644 (file)
index 0000000..9badc59
--- /dev/null
@@ -0,0 +1,327 @@
+/** Copyright (c) 2009 Open Information Security Foundation
+ *
+ *  \author Breno Silva <breno.silva@gmail.com>
+ */
+
+
+#include "eidps.h"
+#include "decode.h"
+#include "decode-events.h"
+#include "decode-gre.h"
+
+#include "util-unittest.h"
+
+/**
+ * \brief Function to decode GRE packets
+ */
+
+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;
+
+    if(len < GRE_HDR_LEN)    {
+        DECODER_SET_EVENT(p,GRE_PKT_TOO_SMALL);
+        return;
+    }
+
+    p->greh = (GREHdr *)pkt;
+    if(p->greh == NULL)
+        return;
+
+#ifdef DEBUG
+    printf("DecodeGRE: p %p pkt %p GRE protocol %04x Len: %d GRE version %x\n", p, pkt, GRE_GET_PROTO(p->greh), len,GRE_GET_VERSION(p->greh));
+#endif
+
+    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)) {
+                DECODER_SET_EVENT(p,GRE_VERSION0_RECUR);
+                return;
+            }
+
+            if (GREV1_FLAG_ISSET_FLAGS(p->greh))   {
+                DECODER_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)   {
+                DECODER_SET_EVENT(p,GRE_VERSION0_HDR_TOO_BIG);
+                return;
+            }
+
+            if (GRE_FLAG_ISSET_ROUTE(p->greh))
+            {
+
+                gsre = (GRESreHdr *)(pkt + header_len);
+
+                if(gsre == NULL)
+                    return;
+
+                while (1)
+                {
+                    if ((header_len+GRE_SRE_HDR_LEN) > len) {
+                        DECODER_SET_EVENT(p,GRE_VERSION1_MALFORMED_SRE_HDR);
+                        break;
+                    }
+
+                    header_len += GRE_SRE_HDR_LEN;
+
+                    if (gsre && (ntohs(gsre->af) == 0) && (gsre->sre_length == 0))
+                        break;
+
+                    header_len += gsre->sre_length;
+                    gsre = (GRESreHdr *)(pkt + header_len);
+
+                }
+            }
+            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))    {
+                DECODER_SET_EVENT(p,GRE_VERSION1_CHKSUM);
+                return;
+            }
+
+            if (GRE_FLAG_ISSET_ROUTE(p->greh)) {
+                DECODER_SET_EVENT(p,GRE_VERSION1_ROUTE);
+                return;
+            }
+
+            if (GRE_FLAG_ISSET_SSR(p->greh))   {
+                DECODER_SET_EVENT(p,GRE_VERSION1_SSR);
+                return;
+            }
+
+            if (GRE_FLAG_ISSET_RECUR(p->greh)) {
+                DECODER_SET_EVENT(p,GRE_VERSION1_RECUR);
+                return;
+            }
+
+            if (GREV1_FLAG_ISSET_FLAGS(p->greh))   {
+                DECODER_SET_EVENT(p,GRE_VERSION1_FLAGS);
+                return;
+            }
+
+            if (GRE_GET_PROTO(p->greh) != GRE_PROTO_PPP)  {
+                DECODER_SET_EVENT(p,GRE_VERSION1_WRONG_PROTOCOL);
+                return;
+            }
+
+            if (!(GRE_FLAG_ISSET_KY(p->greh))) {
+                DECODER_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)   {
+                DECODER_SET_EVENT(p,GRE_VERSION1_HDR_TOO_BIG);
+                return;
+            }
+
+            break;
+        default:
+            DECODER_SET_EVENT(p,GRE_WRONG_VERSION);
+            return;
+    }
+
+    switch (GRE_GET_PROTO(p->greh))
+    {
+        case ETHERNET_TYPE_IP:
+            {
+                PerfCounterIncr(dtv->counter_gre, tv->pca);
+                if (pq != NULL) {
+
+                    Packet *tp = TunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, GRE_GET_PROTO(p->greh));
+                    DecodeTunnel(tv, dtv, tp, tp->pkt, tp->pktlen, pq);
+                    PacketEnqueue(pq,tp);
+
+                    SET_TUNNEL_PKT(p);
+                }
+                break;
+            }
+
+        case GRE_PROTO_PPP:
+            {
+                PerfCounterIncr(dtv->counter_gre, tv->pca);
+                if (pq != NULL) {
+
+                    Packet *tp = TunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, GRE_GET_PROTO(p->greh));
+                    DecodeTunnel(tv, dtv, tp, tp->pkt, tp->pktlen, pq);
+                    PacketEnqueue(pq,tp);
+
+                    SET_TUNNEL_PKT(p);
+                }
+                break;
+            }
+
+        case ETHERNET_TYPE_IPV6:
+            {
+                PerfCounterIncr(dtv->counter_gre, tv->pca);
+                if (pq != NULL) {
+
+                    Packet *tp = TunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, GRE_GET_PROTO(p->greh));
+                    DecodeTunnel(tv, dtv, tp, tp->pkt, tp->pktlen, pq);
+                    PacketEnqueue(pq,tp);
+
+                    SET_TUNNEL_PKT(p);
+                }
+                break;
+            }
+        default:
+            return;
+    }
+
+}
+
+
+/**
+ * \test DecodeGRETest01 is a test for small gre packet
+ */
+
+static int DecodeGREtest01 (void)   {
+
+    uint8_t raw_gre[] = { 0x00 ,0x6e ,0x62 };
+    Packet p;
+    ThreadVars tv;
+    DecodeThreadVars dtv;
+
+    memset(&tv, 0, sizeof(ThreadVars));
+    memset(&p, 0, sizeof(Packet));
+    memset(&dtv, 0, sizeof(DecodeThreadVars));
+
+    DecodeGRE(&tv, &dtv, &p, raw_gre, sizeof(raw_gre), NULL);
+
+    if(DECODER_ISSET_EVENT(&p,GRE_PKT_TOO_SMALL))  {
+        return 1;
+    }
+
+    return 0;
+}
+
+/**
+ * \test DecodeGRETest02 is a test for wrong gre version
+ */
+
+static int DecodeGREtest02 (void)   {
+    uint8_t raw_gre[] = {
+        0x00, 0x6e, 0x62, 0xac, 0x40, 0x00, 0x40, 0x2f,
+        0xc2, 0xc7, 0x0a, 0x00, 0x00, 0x64, 0x0a, 0x00,
+        0x00, 0x8a, 0x30, 0x01, 0x0b, 0x00, 0x4e, 0x00,
+        0x00, 0x00, 0x18, 0x4a, 0x50, 0xff, 0x03, 0x00,
+        0x21, 0x45, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x40,
+        0x00, 0x40, 0x11, 0x94, 0x22, 0x50, 0x7e, 0x2b,
+        0x2d, 0xc2, 0x6d, 0x68, 0x68, 0x80, 0x0e, 0x00,
+        0x35, 0x00, 0x36, 0x9f, 0x18, 0xdb, 0xc4, 0x01,
+        0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x01, 0x03, 0x73, 0x31, 0x36, 0x09, 0x73, 0x69,
+        0x74, 0x65, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x03,
+        0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
+        0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00 };
+    Packet p;
+    ThreadVars tv;
+    DecodeThreadVars dtv;
+
+    memset(&tv, 0, sizeof(ThreadVars));
+    memset(&p, 0, sizeof(Packet));
+    memset(&dtv, 0, sizeof(DecodeThreadVars));
+
+    DecodeGRE(&tv, &dtv, &p, raw_gre, sizeof(raw_gre), NULL);
+
+    if(DECODER_ISSET_EVENT(&p,GRE_WRONG_VERSION))  {
+        return 1;
+    }
+
+    return 0;
+}
+
+
+/**
+ * \test DecodeGRETest03 is a test for valid gre packet
+ */
+
+static int DecodeGREtest03 (void)   {
+    uint8_t raw_gre[] = {
+        0x00, 0x6e, 0x62, 0xac, 0x40, 0x00, 0x40, 0x2f,
+        0xc2, 0xc7, 0x0a, 0x00, 0x00, 0x64, 0x0a, 0x00,
+        0x00, 0x8a, 0x30, 0x01, 0x88, 0x0b, 0x00, 0x4e,
+        0x00, 0x00, 0x00, 0x18, 0x4a, 0x50, 0xff, 0x03,
+        0x00, 0x21, 0x45, 0x00, 0x00, 0x4a, 0x00, 0x00,
+        0x40, 0x00, 0x40, 0x11, 0x94, 0x22, 0x50, 0x7e,
+        0x2b, 0x2d, 0xc2, 0x6d, 0x68, 0x68, 0x80, 0x0e,
+        0x00, 0x35, 0x00, 0x36, 0x9f, 0x18, 0xdb, 0xc4,
+        0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x01, 0x03, 0x73, 0x31, 0x36, 0x09, 0x73,
+        0x69, 0x74, 0x65, 0x6d, 0x65, 0x74, 0x65, 0x72,
+        0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00,
+        0x01, 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00 };
+    Packet p;
+    ThreadVars tv;
+    DecodeThreadVars dtv;
+
+    memset(&tv, 0, sizeof(ThreadVars));
+    memset(&p, 0, sizeof(Packet));
+    memset(&dtv, 0, sizeof(DecodeThreadVars));
+
+    DecodeGRE(&tv, &dtv, &p, raw_gre, sizeof(raw_gre), NULL);
+
+    if(p.greh == NULL) {
+        return 0;
+    }
+
+
+    return 1;
+}
+
+/**
+ * \brief this function registers unit tests for DecodeEvent
+ */
+
+void DecodeGRERegisterTests(void) {
+    UtRegisterTest("DecodeGREtest01", DecodeGREtest01, 1);
+    UtRegisterTest("DecodeGREtest02", DecodeGREtest02, 1);
+    UtRegisterTest("DecodeGREtest03", DecodeGREtest03, 1);
+}
diff --git a/src/decode-gre.h b/src/decode-gre.h
new file mode 100644 (file)
index 0000000..ccb1efa
--- /dev/null
@@ -0,0 +1,61 @@
+/** Copyright (c) 2009 Open Information Security Foundation
+ *
+ *  \author Breno Silva <breno.silva@gmail.com>
+ */
+
+#ifndef __DECODE_GRE_H__
+#define __DECODE_GRE_H__
+
+#ifndef IPPROTO_GRE
+#define IPPROTO_GRE 47
+#endif
+
+#include "decode.h"
+#include "threadvars.h"
+
+typedef struct _GREHdr
+{
+    uint8_t flags;
+    uint8_t version;
+    uint16_t ether_type;
+
+} GREHdr;
+
+typedef struct _GRESreHdr
+{
+    uint16_t af;  /* address familly */
+    uint8_t sre_offset;
+    uint8_t sre_length;
+    uint8_t *routing;
+} GRESreHdr;
+
+#define GRE_VERSION_0           0x0000
+#define GRE_VERSION_1           0x0001
+
+#define GRE_HDR_LEN             4
+#define GRE_CHKSUM_LEN          2
+#define GRE_OFFSET_LEN          2
+#define GRE_KEY_LEN             4
+#define GRE_SEQ_LEN             4
+#define GRE_SRE_HDR_LEN         4
+#define GRE_PROTO_PPP           0x880b
+
+#define GRE_FLAG_ISSET_CHKSUM(r)    (r->flags & 0x80)
+#define GRE_FLAG_ISSET_ROUTE(r)     (r->flags & 0x40)
+#define GRE_FLAG_ISSET_KY(r)        (r->flags & 0x20)
+#define GRE_FLAG_ISSET_SQ(r)        (r->flags & 0x10)
+#define GRE_FLAG_ISSET_SSR(r)       (r->flags & 0x08)
+#define GRE_FLAG_ISSET_RECUR(r)     (r->flags & 0x07)
+#define GRE_GET_VERSION(r)   (r->version & 0x07)
+#define GRE_GET_FLAGS(r)     (r->version & 0xF8)
+#define GRE_GET_PROTO(r)     ntohs(r->ether_type)
+
+#define GREV1_HDR_LEN           8
+#define GREV1_ACK_LEN           4
+#define GREV1_FLAG_ISSET_FLAGS(r)  (r->version & 0x78)
+#define GREV1_FLAG_ISSET_ACK(r)    (r->version & 0x80)
+
+void DecodeGRERegisterTests(void);
+
+#endif /* __DECODE_GRE_H__ */
+
index 720129fd551619f1f138d2cc3a6d1d47ee5da7b9..fdd8d6a7e957f6dd9877298cba3f5f221a264199 100644 (file)
@@ -8,6 +8,9 @@
 void DecodeTunnel(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq)
 {
     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:
index 7d79a19946ed487d0186613234259e7c1845ad53..1a3233246509c40ea6ab294667bf8895f66f5166 100644 (file)
@@ -32,6 +32,7 @@
 #include "action-globals.h"
 
 #include "decode-ethernet.h"
+#include "decode-gre.h"
 #include "decode-ppp.h"
 #include "decode-pppoe.h"
 #include "decode-sll.h"
@@ -241,6 +242,7 @@ typedef struct Packet_
     EthernetHdr *ethh;
     PPPHdr *ppph;
     PPPoEHdr *pppoeh;
+    GREHdr *greh;
 
     IPV4Hdr *ip4h;
     IPV4Vars ip4vars;
@@ -314,6 +316,7 @@ typedef struct DecodeThreadVars_
     uint16_t counter_icmpv4;
     uint16_t counter_icmpv6;
     uint16_t counter_ppp;
+    uint16_t counter_gre;
     uint16_t counter_pppoe;
     uint16_t counter_avg_pkt_size;
     uint16_t counter_max_pkt_size;
@@ -328,6 +331,7 @@ typedef struct DecodeThreadVars_
     } \
     (p)->ethh = NULL; \
     (p)->ppph = NULL; \
+    (p)->greh = NULL; \
     (p)->ip4h = NULL; \
     (p)->ip6h = NULL; \
     (p)->action = 0; \
@@ -419,6 +423,7 @@ Packet *TunnelPktSetup(ThreadVars *, DecodeThreadVars *, Packet *, uint8_t *, ui
 #define LINKTYPE_ETHERNET   DLT_EN10MB
 #define LINKTYPE_LINUX_SLL  113
 #define LINKTYPE_PPP   9
+#define PPP_OVER_GRE    11
 
 #endif /* __DECODE_H__ */
 
index 651f806e7a2b18d6eaa80f74a8ae0b809b53545f..0b3c6a9ba73a686670ba530fecc7628a5a6c9d65 100644 (file)
@@ -59,6 +59,20 @@ struct DetectDecodeEvents_ {
     { "ppp.ip6_pkt_too_small", PPPIPV6_PKT_TOO_SMALL, },
     { "ppp.wrong_type", PPP_WRONG_TYPE, }, /** unknown & invalid protocol */
     { "ppp.unsup_proto", PPP_UNSUP_PROTO, }, /** unsupported but valid protocol */
+    { "gre.pkt_too_small", GRE_PKT_TOO_SMALL, },
+    { "gre.wrong_version", GRE_WRONG_VERSION, },
+    { "gre.version0_recur", GRE_VERSION0_RECUR, },
+    { "gre.version0_flags", GRE_VERSION0_FLAGS, },
+    { "gre.version0_hdr_too_big", GRE_VERSION0_HDR_TOO_BIG, },
+    { "gre.version1_chksum", GRE_VERSION1_CHKSUM, },
+    { "gre.version1_route", GRE_VERSION1_ROUTE, },
+    { "gre.version1_ssr", GRE_VERSION1_SSR, },
+    { "gre.version1_recur", GRE_VERSION1_RECUR, },
+    { "gre.version1_flags", GRE_VERSION1_FLAGS, },
+    { "gre.version1_no_key", GRE_VERSION1_NO_KEY, },
+    { "gre.version1_wrong_protocol", GRE_VERSION1_WRONG_PROTOCOL, },
+    { "gre.version1_malformed_sre_hdr", GRE_VERSION1_MALFORMED_SRE_HDR, },
+    { "gre.version1_hdr_too_big", GRE_VERSION1_HDR_TOO_BIG, },
     { NULL, 0 },
 };
 #endif /* DETECT_EVENTS */
index 96ab2547ad1d6356634df15daa8ed7e06e9150c2..25b10c7fa7606d84df3a636c3f20dd8f8ff831f3 100644 (file)
@@ -972,6 +972,7 @@ int main(int argc, char **argv)
         DecodePPPoERegisterTests();
         DecodeICMPV4RegisterTests();
         DecodeIPV4RegisterTests();
+        DecodeGRERegisterTests();
         AlpDetectRegisterTests();
         ConfRegisterTests();
         UtRunTests();