decode-pppoe.c decode-pppoe.h \
decode-raw.c decode-raw.h \
decode-sctp.c decode-sctp.h \
+decode-esp.c decode-esp.h \
decode-sll.c decode-sll.h \
decode-tcp.c decode-tcp.h \
decode-teredo.c decode-teredo.h \
--- /dev/null
+/* Copyright (C) 2020 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \ingroup decode
+ *
+ * @{
+ */
+
+/**
+ * \file
+ *
+ * Decode Encapsulating Security Payload (ESP)
+ */
+
+#include "suricata-common.h"
+#include "decode-esp.h"
+#include "flow.h"
+
+static int DecodeESPPacket(ThreadVars *tv, Packet *p, const uint8_t *pkt, uint16_t len)
+{
+ if (unlikely(len < ESP_HEADER_LEN)) {
+ ENGINE_SET_INVALID_EVENT(p, ESP_PKT_TOO_SMALL);
+ return -1;
+ }
+
+ p->esph = (ESPHdr *)pkt;
+
+ p->payload = (uint8_t *)pkt + sizeof(ESPHdr);
+ p->payload_len = len - sizeof(ESPHdr);
+
+ p->proto = IPPROTO_ESP;
+
+ return 0;
+}
+
+/**
+ * \brief Function to decode IPSEC-ESP packets
+ * \param tv thread vars
+ * \param dtv decoder thread vars
+ * \param p packet
+ * \param pkt raw packet data
+ * \param len length in bytes of pkt array
+ * \retval TM_ECODE_OK or TM_ECODE_FAILED on serious error
+ */
+int DecodeESP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
+{
+ StatsIncr(tv, dtv->counter_esp);
+
+ if (unlikely(DecodeESPPacket(tv, p, pkt, len) < 0)) {
+ CLEAR_ESP_PACKET(p);
+ return TM_ECODE_FAILED;
+ }
+
+ SCLogDebug("ESP spi: %" PRIu32 " sequence: %" PRIu32, ESP_GET_SPI(p), ESP_GET_SEQUENCE(p));
+
+ FlowSetupPacket(p);
+
+ return TM_ECODE_OK;
+}
+
+#ifdef UNITTESTS
+
+#include "util-unittest.h"
+
+/** \test Successful decoding */
+static int DecodeESPTest01(void)
+{
+ uint8_t raw_esp[] = { 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x08 };
+
+ Packet *p = PacketGetFromAlloc();
+ FAIL_IF_NULL(p);
+
+ ThreadVars tv;
+ DecodeThreadVars dtv;
+
+ memset(&tv, 0, sizeof(ThreadVars));
+ memset(&dtv, 0, sizeof(DecodeThreadVars));
+
+ int ret = DecodeESP(&tv, &dtv, p, raw_esp, sizeof(raw_esp));
+ FAIL_IF(ret != TM_ECODE_OK);
+
+ FAIL_IF(p->proto != IPPROTO_ESP);
+ FAIL_IF(p->payload_len != sizeof(raw_esp) - ESP_HEADER_LEN);
+ FAIL_IF(ESP_GET_SPI(p) != 0x7b);
+ FAIL_IF(ESP_GET_SEQUENCE(p) != 0x08);
+
+ SCFree(p);
+
+ PASS;
+}
+
+/** \test Successful decoding, with payload data */
+static int DecodeESPTest02(void)
+{
+ uint8_t raw_esp[] = { 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x08, 0xFF, 0xFF };
+
+ Packet *p = PacketGetFromAlloc();
+ FAIL_IF_NULL(p);
+
+ ThreadVars tv;
+ DecodeThreadVars dtv;
+
+ memset(&tv, 0, sizeof(ThreadVars));
+ memset(&dtv, 0, sizeof(DecodeThreadVars));
+
+ int ret = DecodeESP(&tv, &dtv, p, raw_esp, sizeof(raw_esp));
+ FAIL_IF(ret != TM_ECODE_OK);
+
+ FAIL_IF(p->proto != IPPROTO_ESP);
+ FAIL_IF(p->payload_len != sizeof(raw_esp) - ESP_HEADER_LEN);
+ FAIL_IF(memcmp(p->payload, raw_esp + ESP_HEADER_LEN, p->payload_len) != 0);
+ FAIL_IF(ESP_GET_SPI(p) != 0x7b);
+ FAIL_IF(ESP_GET_SEQUENCE(p) != 0x08);
+
+ SCFree(p);
+
+ PASS;
+}
+
+/** \test Failure decoding, not enough data */
+static int DecodeESPTest03(void)
+{
+ uint8_t raw_esp[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ Packet *p = PacketGetFromAlloc();
+ FAIL_IF_NULL(p);
+
+ ThreadVars tv;
+ DecodeThreadVars dtv;
+
+ memset(&tv, 0, sizeof(ThreadVars));
+ memset(&dtv, 0, sizeof(DecodeThreadVars));
+
+ int ret = DecodeESP(&tv, &dtv, p, raw_esp, sizeof(raw_esp));
+ FAIL_IF(ret != TM_ECODE_FAILED);
+
+ // expect ESP_PKT_TOO_SMALL
+ FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, ESP_PKT_TOO_SMALL));
+
+ SCFree(p);
+
+ PASS;
+}
+
+/** \test Failure decoding, no data */
+static int DecodeESPTest04(void)
+{
+ uint8_t raw_esp[] = {};
+
+ Packet *p = PacketGetFromAlloc();
+ FAIL_IF_NULL(p);
+
+ ThreadVars tv;
+ DecodeThreadVars dtv;
+
+ memset(&tv, 0, sizeof(ThreadVars));
+ memset(&dtv, 0, sizeof(DecodeThreadVars));
+
+ int ret = DecodeESP(&tv, &dtv, p, raw_esp, sizeof(raw_esp));
+ FAIL_IF(ret != TM_ECODE_FAILED);
+
+ // expect ESP_PKT_TOO_SMALL
+ FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, ESP_PKT_TOO_SMALL));
+
+ SCFree(p);
+
+ PASS;
+}
+#endif /* UNITTESTS */
+
+void DecodeESPRegisterTests(void)
+{
+#ifdef UNITTESTS
+ UtRegisterTest("DecodeESPTest01", DecodeESPTest01);
+ UtRegisterTest("DecodeESPTest02", DecodeESPTest02);
+ UtRegisterTest("DecodeESPTest03", DecodeESPTest03);
+ UtRegisterTest("DecodeESPTest04", DecodeESPTest04);
+#endif /* UNITTESTS */
+}
+
+/**
+ * @}
+ */
--- /dev/null
+/* Copyright (C) 2020 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ */
+
+#ifndef __DECODE_ESP_H__
+#define __DECODE_ESP_H__
+
+/** \brief size of the ESP header */
+#define ESP_HEADER_LEN 8
+
+#define ESP_GET_RAW_SPI(esph) SCNtohl((esph)->spi)
+#define ESP_GET_RAW_SEQUENCE(esph) SCNtohl((esph)->sequence)
+
+/** \brief Get the spi field off a packet */
+#define ESP_GET_SPI(p) ESP_GET_RAW_SPI(p->esph)
+
+/** \brief Get the sequence field off a packet */
+#define ESP_GET_SEQUENCE(p) ESP_GET_RAW_SEQUENCE(p->esph)
+
+/** \brief ESP Header */
+typedef struct ESPHdr_ {
+ uint32_t spi; /** < ESP Security Parameters Index */
+ uint32_t sequence; /** < ESP sequence number */
+} __attribute__((__packed__)) ESPHdr;
+
+#define CLEAR_ESP_PACKET(p) \
+ { \
+ (p)->esph = NULL; \
+ } \
+ while (0)
+
+void DecodeESPRegisterTests(void);
+
+#endif /* __DECODE_ESP_H__ */
SCTP_PKT_TOO_SMALL,
},
+ /* ESP EVENTS */
+ {
+ "decoder.esp.pkt_too_small",
+ ESP_PKT_TOO_SMALL,
+ },
+
/* Fragmentation reasembly events. */
{
"decoder.ipv4.frag_pkt_too_large",
/* SCTP EVENTS */
SCTP_PKT_TOO_SMALL, /**< sctp packet smaller than minimum size */
+ /* ESP EVENTS */
+ ESP_PKT_TOO_SMALL, /**< esp packet smaller than minimum size */
+
/* Fragmentation reasembly events. */
IPV4_FRAG_PKT_TOO_LARGE,
IPV6_FRAG_PKT_TOO_LARGE,
DecodeSCTP(tv, dtv, p, pkt + IPV4_GET_HLEN(p),
IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p));
break;
+
+ case IPPROTO_ESP:
+ DecodeESP(tv, dtv, p, pkt + IPV4_GET_HLEN(p), IPV4_GET_IPLEN(p) - IPV4_GET_HLEN(p));
+ break;
+
case IPPROTO_IPV6:
{
/* spawn off tunnel packet */
char exthdr_fh_done = 0;
int hh = 0;
int rh = 0;
- int eh = 0;
int ah = 0;
while(1)
case IPPROTO_ESP:
{
IPV6_SET_L4PROTO(p,nh);
- hdrextlen = sizeof(IPV6EspHdr);
- if (hdrextlen > plen) {
- ENGINE_SET_INVALID_EVENT(p, IPV6_TRUNC_EXTHDR);
- SCReturn;
- }
-
- if (eh) {
- ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_EH);
- SCReturn;
- }
-
- eh = 1;
-
- nh = IPPROTO_NONE;
- pkt += hdrextlen;
- plen -= hdrextlen;
- break;
+ DecodeESP(tv, dtv, p, pkt, plen);
+ SCReturn;
}
case IPPROTO_AH:
{
dtv->counter_tcp = StatsRegisterCounter("decoder.tcp", tv);
dtv->counter_udp = StatsRegisterCounter("decoder.udp", tv);
dtv->counter_sctp = StatsRegisterCounter("decoder.sctp", tv);
+ dtv->counter_esp = StatsRegisterCounter("decoder.esp", tv);
dtv->counter_icmpv4 = StatsRegisterCounter("decoder.icmpv4", tv);
dtv->counter_icmpv6 = StatsRegisterCounter("decoder.icmpv6", tv);
dtv->counter_ppp = StatsRegisterCounter("decoder.ppp", tv);
#include "decode-tcp.h"
#include "decode-udp.h"
#include "decode-sctp.h"
+#include "decode-esp.h"
#include "decode-raw.h"
#include "decode-null.h"
#include "decode-vlan.h"
} while (0)
-
#define GET_IPV4_SRC_ADDR_U32(p) ((p)->src.addr_data32[0])
#define GET_IPV4_DST_ADDR_U32(p) ((p)->dst.addr_data32[0])
#define GET_IPV4_SRC_ADDR_PTR(p) ((p)->src.addr_data32)
SCTPHdr *sctph;
+ ESPHdr *esph;
+
ICMPV4Hdr *icmpv4h;
ICMPV6Hdr *icmpv6h;
uint16_t counter_raw;
uint16_t counter_null;
uint16_t counter_sctp;
+ uint16_t counter_esp;
uint16_t counter_ppp;
uint16_t counter_geneve;
uint16_t counter_gre;
if ((p)->sctph != NULL) { \
CLEAR_SCTP_PACKET((p)); \
} \
+ if ((p)->esph != NULL) { \
+ CLEAR_ESP_PACKET((p)); \
+ } \
if ((p)->icmpv4h != NULL) { \
CLEAR_ICMPV4_PACKET((p)); \
} \
int DecodeTCP(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint16_t);
int DecodeUDP(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint16_t);
int DecodeSCTP(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint16_t);
+int DecodeESP(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint16_t);
int DecodeGRE(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeVLAN(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeIEEE8021ah(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
return 0;
}
+/**
+ * \brief See if a IP-ESP packet belongs to a flow by comparing the SPI
+ *
+ * \param f flow
+ * \param p ESP packet
+ *
+ * \retval 1 match
+ * \retval 0 no match
+ */
+static inline int FlowCompareESP(Flow *f, const Packet *p)
+{
+ const uint32_t *f_src = f->src.address.address_un_data32;
+ const uint32_t *f_dst = f->dst.address.address_un_data32;
+ const uint32_t *p_src = p->src.address.address_un_data32;
+ const uint32_t *p_dst = p->dst.address.address_un_data32;
+
+ return CmpAddrs(f_src, p_src) && CmpAddrs(f_dst, p_dst) && f->proto == p->proto &&
+ f->recursion_level == p->recursion_level && CmpVlanIds(f->vlan_id, p->vlan_id) &&
+ f->esp.spi == ESP_GET_SPI(p);
+}
+
void FlowSetupPacket(Packet *p)
{
p->flags |= PKT_WANTS_FLOW;
{
if (p->proto == IPPROTO_ICMP) {
return FlowCompareICMPv4(f, p);
+ } else if (p->proto == IPPROTO_ESP) {
+ return FlowCompareESP(f, p);
} else {
return CmpFlowPacket(f, p);
}
} else if (p->sctph != NULL) { /* XXX MACRO */
SET_SCTP_SRC_PORT(p,&f->sp);
SET_SCTP_DST_PORT(p,&f->dp);
+ } else if (p->esph != NULL) {
+ f->esp.spi = ESP_GET_SPI(p);
} /* XXX handle default */
#ifdef DEBUG
else {
uint8_t type; /**< icmp type */
uint8_t code; /**< icmp code */
} icmp_s;
+
+ struct {
+ uint32_t spi; /**< esp spi */
+ } esp;
};
union {
Port dp; /**< tcp/udp destination port */
jb_set_uint(jb, "response_icmp_code", f->icmp_d.code);
}
break;
+ case IPPROTO_ESP:
+ jb_set_uint(jb, "spi", f->esp.spi);
+ break;
}
return jb;
}
jb_set_uint(js, "icmp_code", code);
break;
}
+ case IPPROTO_ESP:
+ jb_set_uint(js, "spi", f->esp.spi);
+ break;
}
return js;
}
DecodeTCPRegisterTests();
DecodeUDPV4RegisterTests();
DecodeGRERegisterTests();
+ DecodeESPRegisterTests();
DecodeMPLSRegisterTests();
DecodeNSHRegisterTests();
AppLayerProtoDetectUnittestsRegister();
FatalError(SC_ERR_FATAL, "Unittests are not build-in");
#endif /* UNITTESTS */
}
-