diff --git a/doc/userguide/upgrade.rst b/doc/userguide/upgrade.rst index 1673d0db8a..ed84e8b20a 100644 --- a/doc/userguide/upgrade.rst +++ b/doc/userguide/upgrade.rst @@ -46,6 +46,9 @@ Major Changes - Default value for ``stream.reassembly.depth`` when the value is not specified in suricata.yaml is now 1 MiB instead of 0/unlimited. - LLMNR protocol parser, logger and sticky buffers are implemented. +- ERSPAN Type III (GRE protocol type ``0x22EB``) is now decoded. Only + Ethernet frames are supported; other frame types set the + ``erspan.unsupported_encapsulation`` decoder event. - ``pgsql`` is no longer enabled by default. Previously, if the ``app-layer.protocols.pgsql`` section was absent from suricata.yaml, the parser would be enabled. It's now disabled by default. Simply enabling its EVE diff --git a/etc/schema.json b/etc/schema.json index 4cff77cefb..fab5361eea 100644 --- a/etc/schema.json +++ b/etc/schema.json @@ -7109,6 +7109,10 @@ "type": "integer", "description": "Number of packets with too many VLAN layers for ERSPAN" }, + "unsupported_encapsulation": { + "type": "integer", + "description": "Number of packets with unsupported encapsulation for ERSPAN" + }, "unsupported_version": { "type": "integer", "description": "Number of packets with unsupported version for ERSPAN" diff --git a/rules/decoder-events.rules b/rules/decoder-events.rules index fe3b0027b6..8f5a03f818 100644 --- a/rules/decoder-events.rules +++ b/rules/decoder-events.rules @@ -148,6 +148,7 @@ alert pkthdr any any -> any any (msg:"SURICATA ERSPAN pkt too small"; decode-eve # packet has type not supported by Suricata's decoders alert pkthdr any any -> any any (msg:"SURICATA ERSPAN unsupported version"; decode-event:erspan.unsupported_version; classtype:protocol-command-decode; sid:2200106; rev:2;) alert pkthdr any any -> any any (msg:"SURICATA ERSPAN too many vlan layers"; decode-event:erspan.too_many_vlan_layers; classtype:protocol-command-decode; sid:2200107; rev:2;) +alert pkthdr any any -> any any (msg:"SURICATA ERSPAN unsupported encapsulation"; decode-event:erspan.unsupported_encapsulation; classtype:protocol-command-decode; sid:2200130; rev:1;) # Cisco Fabric Path/DCE alert pkthdr any any -> any any (msg:"SURICATA DCE packet too small"; decode-event:dce.pkt_too_small; classtype:protocol-command-decode; sid:2200110; rev:2;) @@ -166,5 +167,5 @@ alert igmp any any -> any any (msg:"SURICATA IGMPv3 packet too small"; decode-ev alert igmp any any -> any any (msg:"SURICATA IGMP malformed packet"; decode-event:igmp.malformed; classtype:protocol-command-decode; sid:2200129; rev:1;) alert ipv4 any any -> any any (msg:"SURICATA IPv4 unknown protocol"; decode-event:ipv4.unknown_protocol; threshold: type limit, track by_src, seconds 60, count 1;classtype:protocol-command-decode; sid:2200125;) -# next sid is 2200130 +# next sid is 2200131 diff --git a/src/decode-erspan.c b/src/decode-erspan.c index 839cb5230a..1f05abd8bf 100644 --- a/src/decode-erspan.c +++ b/src/decode-erspan.c @@ -40,6 +40,20 @@ #include "util-debug.h" #include "conf.h" +typedef struct ErspanHdr_ { + uint16_t ver_vlan; + uint16_t flags_spanid; + uint32_t padding; +} __attribute__((__packed__)) ErspanHdr; + +typedef struct Erspan3Hdr_ { + uint16_t ver_vlan; + uint16_t flags_spanid; + uint32_t timestamp; + uint16_t sgt; + uint16_t flags; +} __attribute__((__packed__)) Erspan3Hdr; + /** * \brief Functions to decode ERSPAN Type I and II packets */ @@ -110,6 +124,69 @@ int DecodeERSPAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t return DecodeEthernet(tv, dtv, p, pkt + sizeof(ErspanHdr), len - sizeof(ErspanHdr)); } +/** + * \brief ERSPAN Type III + */ +int DecodeERSPANTypeIII( + ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) +{ + DEBUG_VALIDATE_BUG_ON(pkt == NULL); + + StatsCounterIncr(&tv->stats, dtv->counter_erspan); + + if (len < sizeof(Erspan3Hdr)) { + ENGINE_SET_EVENT(p, ERSPAN_HEADER_TOO_SMALL); + return TM_ECODE_FAILED; + } + if (!PacketIncreaseCheckLayers(p)) { + return TM_ECODE_FAILED; + } + + const Erspan3Hdr *ehdr = (const Erspan3Hdr *)pkt; + uint16_t version = SCNtohs(ehdr->ver_vlan) >> 12; + uint16_t vlan_id = SCNtohs(ehdr->ver_vlan) & 0x0fff; + uint16_t flags = SCNtohs(ehdr->flags); + + pkt += sizeof(Erspan3Hdr); + len -= sizeof(Erspan3Hdr); + + if (version != 2) { + ENGINE_SET_EVENT(p, ERSPAN_UNSUPPORTED_VERSION); + return TM_ECODE_FAILED; + } + + /* If O flag is set, then the optional platform specific header is present. + * We need to skip past it. + */ +#define PLATFORM_SPECIFIC_HDR_SIZE 8 + if (flags & 0x0001) { + if (len < PLATFORM_SPECIFIC_HDR_SIZE) { + ENGINE_SET_EVENT(p, ERSPAN_HEADER_TOO_SMALL); + return TM_ECODE_FAILED; + } + + pkt += PLATFORM_SPECIFIC_HDR_SIZE; + len -= PLATFORM_SPECIFIC_HDR_SIZE; + } + + if (vlan_id > 0) { + if (p->vlan_idx > VLAN_MAX_LAYER_IDX) { + ENGINE_SET_EVENT(p, ERSPAN_TOO_MANY_VLAN_LAYERS); + return TM_ECODE_FAILED; + } + p->vlan_id[p->vlan_idx] = vlan_id; + p->vlan_idx++; + } + + switch ((flags & 0x7c00) >> 10) { + case 0x00: /* ethernet */ + return DecodeEthernet(tv, dtv, p, pkt, len); + default: + ENGINE_SET_EVENT(p, ERSPAN_UNSUPPORTED_ENCAPSULATION); + return TM_ECODE_FAILED; + } +} + /** * @} */ diff --git a/src/decode-erspan.h b/src/decode-erspan.h index 350eb5ef30..62de969e67 100644 --- a/src/decode-erspan.h +++ b/src/decode-erspan.h @@ -25,11 +25,6 @@ #ifndef SURICATA_DECODE_ERSPAN_H #define SURICATA_DECODE_ERSPAN_H -typedef struct ErspanHdr_ { - uint16_t ver_vlan; - uint16_t flags_spanid; - uint32_t padding; -} __attribute__((__packed__)) ErspanHdr; - void DecodeERSPANConfig(void); + #endif /* SURICATA_DECODE_ERSPAN_H */ diff --git a/src/decode-ethernet.h b/src/decode-ethernet.h index 992f7530bf..7b98c3f110 100644 --- a/src/decode-ethernet.h +++ b/src/decode-ethernet.h @@ -46,6 +46,7 @@ #define ETHERNET_TYPE_LOOP 0x9000 #define ETHERNET_TYPE_8021QINQ 0x9100 #define ETHERNET_TYPE_ERSPAN 0x88BE +#define ETHERNET_TYPE_ERSPAN_III 0x22EB /* ERSPAN III */ #define ETHERNET_TYPE_DCE 0x8903 /* Data center ethernet, * Cisco Fabric Path */ #define ETHERNET_TYPE_ETAG 0x893F /* 802.1BR */ diff --git a/src/decode-events.c b/src/decode-events.c index 3f37713dd3..c6cda0c93b 100644 --- a/src/decode-events.c +++ b/src/decode-events.c @@ -603,6 +603,10 @@ const struct DecodeEvents_ DEvents[] = { "decoder.erspan.too_many_vlan_layers", ERSPAN_TOO_MANY_VLAN_LAYERS, }, + { + "decoder.erspan.unsupported_encapsulation", + ERSPAN_UNSUPPORTED_ENCAPSULATION, + }, /* Cisco Fabric Path/DCE events. */ { diff --git a/src/decode-events.h b/src/decode-events.h index 45602235d5..15f2483edd 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -221,6 +221,7 @@ enum { ERSPAN_HEADER_TOO_SMALL, ERSPAN_UNSUPPORTED_VERSION, ERSPAN_TOO_MANY_VLAN_LAYERS, + ERSPAN_UNSUPPORTED_ENCAPSULATION, /* Cisco Fabric Path/DCE events. */ DCE_PKT_TOO_SMALL, diff --git a/src/decode-gre.c b/src/decode-gre.c index e97c1554a5..5cf7245d56 100644 --- a/src/decode-gre.c +++ b/src/decode-gre.c @@ -261,6 +261,15 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p } break; } + case ETHERNET_TYPE_ERSPAN_III: { + Packet *tp = PacketTunnelPktSetup( + tv, dtv, p, pkt + header_len, len - header_len, DECODE_TUNNEL_ERSPANIII); + if (tp != NULL) { + PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); + PacketEnqueueNoLock(&tv->decode_pq, tp); + } + break; + } case ETHERNET_TYPE_BRIDGE: { diff --git a/src/decode.c b/src/decode.c index 9d7b2df244..32d7c4b2ab 100644 --- a/src/decode.c +++ b/src/decode.c @@ -198,6 +198,8 @@ static int DecodeTunnel(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const return DecodeVLAN(tv, dtv, p, pkt, len); case DECODE_TUNNEL_ETHERNET: return DecodeEthernet(tv, dtv, p, pkt, len); + case DECODE_TUNNEL_ERSPANIII: + return DecodeERSPANTypeIII(tv, dtv, p, pkt, len); case DECODE_TUNNEL_ERSPANII: return DecodeERSPAN(tv, dtv, p, pkt, len); case DECODE_TUNNEL_ERSPANI: diff --git a/src/decode.h b/src/decode.h index fb7b1466ef..b9878ced7b 100644 --- a/src/decode.h +++ b/src/decode.h @@ -1142,6 +1142,7 @@ static inline void PacketTunnelSetVerdicted(Packet *p) enum DecodeTunnelProto { DECODE_TUNNEL_ETHERNET, + DECODE_TUNNEL_ERSPANIII, DECODE_TUNNEL_ERSPANII, DECODE_TUNNEL_ERSPANI, DECODE_TUNNEL_VXLAN, @@ -1206,6 +1207,7 @@ int DecodeIEEE8021ah(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t * int DecodeGeneve(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t); int DecodeVXLAN(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t); int DecodeMPLS(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t); +int DecodeERSPANTypeIII(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t); int DecodeERSPAN(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t); int DecodeERSPANTypeI(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t); int DecodeCHDLC(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);