From a29722515701a243b1d5c43b884da7a59e3222c5 Mon Sep 17 00:00:00 2001 From: Jamie Date: Mon, 14 Sep 2009 20:40:10 +0100 Subject: [PATCH] victor must be getting sick of PPPoE and ICMP --- src/decode-events.h | 7 ++ src/decode-icmpv4.c | 237 ++++++++++++++++++++++++++++++++++++++++++-- src/decode-icmpv4.h | 25 ++++- src/decode-pppoe.c | 120 ++++++++++++++++++++-- src/decode-pppoe.h | 3 +- src/decode.h | 2 + 6 files changed, 373 insertions(+), 21 deletions(-) diff --git a/src/decode-events.h b/src/decode-events.h index f7c4f8b8e4..cc00d25848 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -19,6 +19,11 @@ enum { IPV4_OPT_DUPLICATE, IPV4_OPT_UNKNOWN, + /* ICMP EVENTS */ + ICMPV4_PKT_TOO_SMALL, + ICMPV4_UNKNOWN_TYPE, + ICMPV4_UNKNOWN_CODE, + /* IPV6 EVENTS */ IPV6_PKT_TOO_SMALL, IPV6_TRUNC_PKT, @@ -62,6 +67,8 @@ enum { /* PPPOE EVENTS */ PPPOE_PKT_TOO_SMALL, + PPPOE_WRONG_CODE, + PPPOE_MALFORMED_TAGS, /* GRE EVENTS */ GRE_PKT_TOO_SMALL, diff --git a/src/decode-icmpv4.c b/src/decode-icmpv4.c index 258f0428e0..be6c8477ac 100644 --- a/src/decode-icmpv4.c +++ b/src/decode-icmpv4.c @@ -2,6 +2,7 @@ #include "eidps-common.h" #include "decode.h" +#include "decode-events.h" #include "decode-icmpv4.h" #include "util-unittest.h" @@ -57,6 +58,14 @@ inline uint16_t ICMPV4CalculateChecksum(uint16_t *pkt, uint16_t tlen) return (uint16_t) ~csum; } +/** + * \todo + * Note, this is the IP header, plus a bit of the original packet, not the whole thing! + */ +void DecodePartialIPV4( uint8_t* partial_packet, uint16_t len ) +{ +} + /** DecodeICMPV4 * \brief Main ICMPv4 decoding function */ @@ -65,7 +74,7 @@ void DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt PerfCounterIncr(dtv->counter_icmpv4, tv->pca); if (len < ICMPV4_HEADER_LEN) { - /** \todo decode event */ + DECODER_SET_EVENT(p,ICMPV4_PKT_TOO_SMALL); return; } @@ -77,6 +86,129 @@ void DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt p->proto = IPPROTO_ICMP; + 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) { + DECODER_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + } + break; + + case ICMP_DEST_UNREACH: + if (p->icmpv4h->code>ICMP_SR_FAILED) { + DECODER_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + } else { + // parse IP header plus 64 bytes + if (len >= ICMPV4_HEADER_PKT_OFFSET) + DecodePartialIPV4( (uint8_t*) (p->icmpv4h + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); + } + break; + + case ICMP_SOURCE_QUENCH: + if (p->icmpv4h->code!=0) { + DECODER_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + } else { + // parse IP header plus 64 bytes + if (len >= ICMPV4_HEADER_PKT_OFFSET) + DecodePartialIPV4( (uint8_t*) (p->icmpv4h + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); + } + break; + + case ICMP_REDIRECT: + if (p->icmpv4h->code>ICMP_REDIR_HOSTTOS) { + DECODER_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + } else { + // parse IP header plus 64 bytes + if (len >= ICMPV4_HEADER_PKT_OFFSET) + DecodePartialIPV4( (uint8_t*) (p->icmpv4h + 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) { + DECODER_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + } + break; + + case ICMP_TIME_EXCEEDED: + if (p->icmpv4h->code>ICMP_EXC_FRAGTIME) { + DECODER_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + } else { + // parse IP header plus 64 bytes + if (len >= ICMPV4_HEADER_PKT_OFFSET) + DecodePartialIPV4( (uint8_t*) (p->icmpv4h + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); + } + break; + + case ICMP_PARAMETERPROB: + if (p->icmpv4h->code!=0) { + DECODER_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + } else { + // parse IP header plus 64 bytes + if (len >= ICMPV4_HEADER_PKT_OFFSET) + DecodePartialIPV4( (uint8_t*) (p->icmpv4h + 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) { + DECODER_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) { + DECODER_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) { + DECODER_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) { + DECODER_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) { + DECODER_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) { + DECODER_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); + } + break; + + default: + DECODER_SET_EVENT(p,ICMPV4_UNKNOWN_TYPE); + + } + return; } @@ -84,7 +216,7 @@ void DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt /** DecodeICMPV4test01 * \brief - * \retval 0 Expected test value + * \retval 1 Expected test value */ static int DecodeICMPV4test01(void) { uint8_t raw_icmpv4[] = { @@ -104,12 +236,19 @@ static int DecodeICMPV4test01(void) { memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodeICMPV4(&tv, &dtv, &p, raw_icmpv4, sizeof(raw_icmpv4), NULL); + + if (NULL!=p.icmpv4h) { + if (p.icmpv4h->type==8 && p.icmpv4h->code==0) { + return 1; + } + } + return 0; } /** DecodeICMPV4test02 * \brief - * \retval 0 Expected test value + * \retval 1 Expected test value */ static int DecodeICMPV4test02(void) { uint8_t raw_icmpv4[] = { @@ -129,12 +268,20 @@ static int DecodeICMPV4test02(void) { memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodeICMPV4(&tv, &dtv, &p, raw_icmpv4, sizeof(raw_icmpv4), NULL); + + if (NULL!=p.icmpv4h) { + if (p.icmpv4h->type==0 && p.icmpv4h->code==0) { + return 1; + } + } + + return 0; } /** DecodeICMPV4test03 * \brief TTL exceeded - * \retval Expected test value: 0 + * \retval Expected test value: 1 */ static int DecodeICMPV4test03(void) { uint8_t raw_icmpv4[] = { @@ -152,12 +299,19 @@ static int DecodeICMPV4test03(void) { memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodeICMPV4(&tv, &dtv, &p, raw_icmpv4, sizeof(raw_icmpv4), NULL); + + if (NULL!=p.icmpv4h) { + if (p.icmpv4h->type==11 && p.icmpv4h->code==0) { + return 1; + } + } + return 0; } /** DecodeICMPV4test04 * \brief dest. unreachable, administratively prohibited - * \retval 0 Expected test value + * \retval 1 Expected test value */ static int DecodeICMPV4test04(void) { uint8_t raw_icmpv4[] = { @@ -177,6 +331,13 @@ static int DecodeICMPV4test04(void) { memset(&dtv, 0, sizeof(DecodeThreadVars)); DecodeICMPV4(&tv, &dtv, &p, raw_icmpv4, sizeof(raw_icmpv4), NULL); + + if (NULL!=p.icmpv4h) { + if (p.icmpv4h->type==3 && p.icmpv4h->code==10) { + return 1; + } + } + return 0; } @@ -214,19 +375,77 @@ static int ICMPV4CalculateInvalidChecksumtest06(void) { return (csum == ICMPV4CalculateChecksum((uint16_t *)raw_icmpv4, sizeof(raw_icmpv4))); } +static int ICMPV4InvalidType07(void) { + + uint8_t raw_icmpv4[] = { + 0xff, 0x00, 0xab, 0x9b, 0x7f, 0x2b, 0x05, 0x2c, + 0x3f, 0x72, 0x93, 0x4a, 0x00, 0x4d, 0x0a, 0x00, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38}; + + Packet p; + ThreadVars tv; + DecodeThreadVars dtv; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&p, 0, sizeof(Packet)); + memset(&dtv, 0, sizeof(DecodeThreadVars)); + + DecodeICMPV4(&tv, &dtv, &p, raw_icmpv4, sizeof(raw_icmpv4), NULL); + + if(DECODER_ISSET_EVENT(&p,ICMPV4_UNKNOWN_TYPE)) { + return 1; + } + + return 0; +} + +/** DecodeICMPV4test08 + * \brief + * \retval 1 Expected test value - what we really want is not to segfault + */ +static int DecodeICMPV4test08(void) { + uint8_t raw_icmpv4[] = { + 0x08, 0x00, 0x78, 0x47, 0xfc, 0x55, 0x00, 0x00 + }; + Packet p; + ThreadVars tv; + DecodeThreadVars dtv; + + memset(&tv, 0, sizeof(ThreadVars)); + memset(&p, 0, sizeof(Packet)); + memset(&dtv, 0, sizeof(DecodeThreadVars)); + + DecodeICMPV4(&tv, &dtv, &p, raw_icmpv4, sizeof(raw_icmpv4), NULL); + + if (NULL!=p.icmpv4h) { + if (p.icmpv4h->type==8 && p.icmpv4h->code==0) { + return 1; + } + } + + return 0; +} + /** * \brief Registers ICMPV4 unit test * \todo More ICMPv4 tests */ void DecodeICMPV4RegisterTests(void) { - UtRegisterTest("DecodeICMPV4ttest01", DecodeICMPV4test01, 0); - UtRegisterTest("DecodeICMPV4ttest02", DecodeICMPV4test02, 0); - UtRegisterTest("DecodeICMPV4ttest03", DecodeICMPV4test03, 0); - UtRegisterTest("DecodeICMPV4ttest04", DecodeICMPV4test04, 0); + UtRegisterTest("DecodeICMPV4ttest01", DecodeICMPV4test01, 1); + UtRegisterTest("DecodeICMPV4ttest02", DecodeICMPV4test02, 1); + UtRegisterTest("DecodeICMPV4ttest03", DecodeICMPV4test03, 1); + UtRegisterTest("DecodeICMPV4ttest04", DecodeICMPV4test04, 1); UtRegisterTest("ICMPV4CalculateValidChecksumtest05", ICMPV4CalculateValidChecksumtest05, 1); UtRegisterTest("ICMPV4CalculateInvalidChecksumtest06", ICMPV4CalculateInvalidChecksumtest06, 0); + UtRegisterTest("DecodeICMPV4InvalidType", ICMPV4InvalidType07, 1); + UtRegisterTest("DecodeICMPV4ttest08", DecodeICMPV4test08, 1); } #endif /* UNITTESTS */ diff --git a/src/decode-icmpv4.h b/src/decode-icmpv4.h index 91a47c43eb..a649970c1c 100644 --- a/src/decode-icmpv4.h +++ b/src/decode-icmpv4.h @@ -3,7 +3,8 @@ #ifndef __DECODE_ICMPV4_H__ #define __DECODE_ICMPV4_H__ -#define ICMPV4_HEADER_LEN 4 +#define ICMPV4_HEADER_LEN 8 + #ifndef ICMP_ECHOREPLY #define ICMP_ECHOREPLY 0 /* Echo Reply */ #endif @@ -93,6 +94,7 @@ #endif #ifndef ICMP_PREC_VIOLATION #define ICMP_PREC_VIOLATION 14 /* Precedence violation */ + #endif #ifndef ICMP_PREC_CUTOFF #define ICMP_PREC_CUTOFF 15 /* Precedence cut off */ @@ -128,22 +130,39 @@ /** marco for icmpv4 code access */ #define ICMPV4_GET_CODE(p) (p)->icmpv4h->code +typedef struct ICMPV4Vars_ +{ + uint8_t id; + uint8_t seq; +} ICMPV4Vars; + /* ICMPv4 header structure */ typedef struct ICMPV4Hdr_ { uint8_t type; uint8_t code; uint16_t checksum; - - /* XXX incomplete */ } ICMPV4Hdr; +/* ICMPv4 header structure */ +typedef struct ICMPV4ExtHdr_ +{ + uint8_t type; + uint8_t code; + uint16_t checksum; + uint16_t id; + uint16_t seq; +} ICMPV4ExtHdr; + +#define ICMPV4_HEADER_PKT_OFFSET 8 + typedef struct ICMPV4Cache_ { /* checksum computed over the icmpv4 packet */ int32_t comp_csum; } ICMPV4Cache; inline uint16_t ICMPV4CalculateChecksum(uint16_t *, uint16_t); + void DecodeICMPV4RegisterTests(void); #endif /* __DECODE_ICMPV4_H__ */ diff --git a/src/decode-pppoe.c b/src/decode-pppoe.c index ea912d9cdb..073c2c9dda 100644 --- a/src/decode-pppoe.c +++ b/src/decode-pppoe.c @@ -21,7 +21,77 @@ */ void DecodePPPOEDiscovery(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { - // TODO + PerfCounterIncr(dtv->counter_pppoe, tv->pca); + + if (len < PPPOE_DISCOVERY_HEADER_MIN_LEN) { + DECODER_SET_EVENT(p, PPPOE_PKT_TOO_SMALL); + return; + } + + p->pppoedh = (PPPOEDiscoveryHdr *)pkt; + if (p->pppoedh == NULL) + return; + + /* parse the PPPOE code */ + switch (ntohs(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: +#ifdef DEBUG + printf("Unknown PPPOE code: %" PRIx32 "\n",ntohs(p->pppoedh->pppoe_code)); +#endif + DECODER_SET_EVENT(p,PPPOE_WRONG_CODE); + } + + /* parse any tags we have in the packet */ + + uint16_t tag_type, tag_length; + 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 ; + + if (pppoe_length>packet_length) { +#ifdef DEBUG + printf("Malformed PPPOE tags\n"); +#endif + DECODER_SET_EVENT(p,PPPOE_MALFORMED_TAGS); + } + + while (pppoe_length>=4 && packet_length>=4) + { + tag_type = ntohs(pppoedt->pppoe_tag_type); + tag_length = ntohs(pppoedt->pppoe_tag_length); + +#ifdef DEBUG + printf ("PPPoE Tag type %x, length %u\n", tag_type, tag_length); +#endif + + 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); + } + } /** @@ -45,6 +115,8 @@ void DecodePPPOESession(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_ p->pppoesh->pppoe_version, p->pppoesh->pppoe_type, p->pppoesh->pppoe_code, ntohs(p->pppoesh->session_id), ntohs(p->pppoesh->pppoe_length)); #endif + /* 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 */ @@ -211,14 +283,14 @@ static int DecodePPPOEtest03 (void) { } /** DecodePPPOEtest04 - * \brief Valid exaple PADI PPPOE packet taken from RFC2516 - * \retval 0 Expected test value + * \brief Valid example PPPOE packet taken from RFC2516 - but with wrong PPPOE code + * \retval 1 Expected test value */ static int DecodePPPOEtest04 (void) { - /* example PADI packet taken from RFC2516 */ + /* example PADI packet taken from RFC2516, but with wrong code */ uint8_t raw_pppoe[] = { - 0x11, 0x09, 0x00, 0x00, 0x00, 0x04, 0x01, 0x01, + 0x11, 0xbb, 0x00, 0x00, 0x00, 0x04, 0x01, 0x01, 0x00, 0x00 }; @@ -228,9 +300,42 @@ static int DecodePPPOEtest04 (void) { DecodePPPOEDiscovery(&tv, &dtv, &p, raw_pppoe, sizeof(raw_pppoe), NULL); - return 0; // TODO + if(DECODER_ISSET_EVENT(&p,PPPOE_WRONG_CODE)) { + return 1; + } + + return 0; +} + +/** DecodePPPOEtest05 + * \brief Valid exaple PADO PPPOE packet taken from RFC2516, but too short for given length + * \retval 0 Expected test value + */ +static int DecodePPPOEtest05 (void) { + + /* example PADI packet taken from RFC2516 */ + uint8_t raw_pppoe[] = { + 0x11, 0x07, 0x00, 0x00, 0x00, 0x20, 0x01, 0x01, + 0x00, 0x00, 0x01, 0x02, 0x00, 0x18, 0x47, 0x6f, + 0x20, 0x52, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, + 0x20, 0x2d, 0x20, 0x65, 0x73, 0x68, 0x73, 0x68 + }; + + Packet p; + ThreadVars tv; + DecodeThreadVars dtv; + + DecodePPPOEDiscovery(&tv, &dtv, &p, raw_pppoe, sizeof(raw_pppoe), NULL); + + if(DECODER_ISSET_EVENT(&p,PPPOE_MALFORMED_TAGS)) { + return 1; + } + + return 0; } + + /** * \brief Registers PPPOE unit tests * \todo More PPPOE tests @@ -239,6 +344,7 @@ void DecodePPPOERegisterTests(void) { UtRegisterTest("DecodePPPOEtest01", DecodePPPOEtest01, 1); UtRegisterTest("DecodePPPOEtest02", DecodePPPOEtest02, 0); UtRegisterTest("DecodePPPOEtest03", DecodePPPOEtest03, 0); - UtRegisterTest("DecodePPPOEtest04", DecodePPPOEtest04, 0); + UtRegisterTest("DecodePPPOEtest04", DecodePPPOEtest04, 1); + UtRegisterTest("DecodePPPOEtest05", DecodePPPOEtest05, 1); } diff --git a/src/decode-pppoe.h b/src/decode-pppoe.h index d27c5997dd..22025d6cf0 100644 --- a/src/decode-pppoe.h +++ b/src/decode-pppoe.h @@ -18,6 +18,7 @@ #include "threadvars.h" #define PPPOE_SESSION_HEADER_LEN 8 +#define PPPOE_DISCOVERY_HEADER_MIN_LEN 6 typedef struct PPPOESessionHdr_ { @@ -33,7 +34,6 @@ typedef struct PPPOEDiscoveryTag_ { uint16_t pppoe_tag_type; uint16_t pppoe_tag_length; - uint8_t pppoe_tag_value[]; } PPPOEDiscoveryTag; typedef struct PPPOEDiscoveryHdr_ @@ -43,7 +43,6 @@ typedef struct PPPOEDiscoveryHdr_ uint8_t pppoe_code; uint16_t discovery_id; uint16_t pppoe_length; - PPPOEDiscoveryTag pppoe_tag_list[]; } PPPOEDiscoveryHdr; /* see RFC 2516 - discovery codes */ diff --git a/src/decode.h b/src/decode.h index 8f6fbca33e..b6a34b6153 100644 --- a/src/decode.h +++ b/src/decode.h @@ -242,6 +242,7 @@ typedef struct Packet_ EthernetHdr *ethh; PPPHdr *ppph; PPPOESessionHdr *pppoesh; + PPPOEDiscoveryHdr *pppoedh; GREHdr *greh; IPV4Hdr *ip4h; @@ -255,6 +256,7 @@ typedef struct Packet_ ICMPV4Hdr *icmpv4h; ICMPV4Cache icmpv4c; + ICMPV4Vars icmpv4vars; ICMPV6Hdr *icmpv6h; ICMPV6Cache icmpv6c;