GRE support

remotes/origin/master-1.0.x
Breno Silva 16 years ago committed by Victor Julien
parent f5fe190b45
commit 9528e02e46

@ -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 \

@ -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__ */

@ -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);
}

@ -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__ */

@ -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:

@ -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__ */

@ -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 */

@ -972,6 +972,7 @@ int main(int argc, char **argv)
DecodePPPoERegisterTests();
DecodeICMPV4RegisterTests();
DecodeIPV4RegisterTests();
DecodeGRERegisterTests();
AlpDetectRegisterTests();
ConfRegisterTests();
UtRunTests();

Loading…
Cancel
Save