From: Giuseppe Longo Date: Sat, 2 Mar 2024 17:50:27 +0000 (+0100) Subject: decode/arp: implement decoder X-Git-Tag: suricata-8.0.0-beta1~1312 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5219a5da5f14c2eae8245fbbd5fddee61156c6e5;p=thirdparty%2Fsuricata.git decode/arp: implement decoder This adds a decoder for ARP. Ticket #6827 --- diff --git a/etc/schema.json b/etc/schema.json index 99946b0619..c9d61b9581 100644 --- a/etc/schema.json +++ b/etc/schema.json @@ -4579,6 +4579,33 @@ "event": { "type": "object", "properties": { + "arp": { + "type": "object", + "properties": { + "pkt_too_small": { + "type": "integer" + }, + "unsupported_hardware": { + "type": "integer" + }, + "unsupported_protocol": { + "type": "integer" + }, + "unsupported_pkt": { + "type": "integer" + }, + "invalid_hardware_size": { + "type": "integer" + }, + "invalid_protocol_size": { + "type": "integer" + }, + "unsupported_opcode": { + "type": "integer" + } + }, + "additionalProperties": false + }, "chdlc": { "type": "object", "properties": { diff --git a/src/Makefile.am b/src/Makefile.am index e26f5e826d..cbb781ccd0 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -56,6 +56,7 @@ noinst_HEADERS = \ datasets-reputation.h \ datasets-sha256.h \ datasets-string.h \ + decode-arp.h \ decode-chdlc.h \ decode-erspan.h \ decode-esp.h \ @@ -665,6 +666,7 @@ libsuricata_c_a_SOURCES = \ datasets-sha256.c \ datasets-string.c \ decode.c \ + decode-arp.c \ decode-chdlc.c \ decode-erspan.c \ decode-esp.c \ diff --git a/src/decode-arp.c b/src/decode-arp.c new file mode 100644 index 0000000000..224b901df9 --- /dev/null +++ b/src/decode-arp.c @@ -0,0 +1,89 @@ +/* Copyright (C) 2024 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. + */ + +/** + * + * \author Giuseppe Longo + * + */ + +#include "suricata-common.h" +#include "decode.h" +#include "decode-arp.h" +#include "decode-events.h" + +int DecodeARP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) +{ + StatsIncr(tv, dtv->counter_arp); + + if (unlikely(len < ARP_HEADER_MIN_LEN)) { + ENGINE_SET_INVALID_EVENT(p, ARP_PKT_TOO_SMALL); + return TM_ECODE_FAILED; + } + + if (!PacketIncreaseCheckLayers(p)) { + return TM_ECODE_FAILED; + } + + const ARPHdr *arph = PacketSetARP(p, pkt); + if (unlikely(arph == NULL)) + return TM_ECODE_FAILED; + + if (SCNtohs(arph->hw_type) != ARP_HW_TYPE_ETHERNET) { + ENGINE_SET_INVALID_EVENT(p, ARP_UNSUPPORTED_HARDWARE); + PacketClearL3(p); + return TM_ECODE_FAILED; + } + + if (SCNtohs(arph->proto_type) != ETHERNET_TYPE_IP) { + ENGINE_SET_INVALID_EVENT(p, ARP_UNSUPPORTED_PROTOCOL); + PacketClearL3(p); + return TM_ECODE_FAILED; + } + + if (unlikely(len < ARP_HEADER_LEN)) { + ENGINE_SET_INVALID_EVENT(p, ARP_INVALID_PKT); + PacketClearL3(p); + return TM_ECODE_FAILED; + } + + if (arph->hw_size != ARP_HW_SIZE) { + ENGINE_SET_INVALID_EVENT(p, ARP_INVALID_HARDWARE_SIZE); + PacketClearL3(p); + return TM_ECODE_FAILED; + } + + if (arph->proto_size != ARP_PROTO_SIZE) { + ENGINE_SET_INVALID_EVENT(p, ARP_INVALID_PROTOCOL_SIZE); + PacketClearL3(p); + return TM_ECODE_FAILED; + } + + switch (SCNtohs(arph->opcode)) { + case 1: + case 2: + case 3: + case 4: + break; + default: + ENGINE_SET_INVALID_EVENT(p, ARP_UNSUPPORTED_OPCODE); + PacketClearL3(p); + return TM_ECODE_FAILED; + } + + return TM_ECODE_OK; +} diff --git a/src/decode-arp.h b/src/decode-arp.h new file mode 100644 index 0000000000..56ad0ed57a --- /dev/null +++ b/src/decode-arp.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2024 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. + */ + +/** + * + * \author Giuseppe Longo + */ + +#ifndef SURICATA_DECODE_ARP_H +#define SURICATA_DECODE_ARP_H + +#define ARP_HEADER_MIN_LEN 8 +#define ARP_HEADER_LEN 28 +#define ARP_HW_TYPE_ETHERNET 0x01 +#define ARP_PROTO_TYPE_IP 0x0800 +#define ARP_HW_SIZE 6 +#define ARP_PROTO_SIZE 4 + +typedef struct ARPHdr_ { + uint16_t hw_type; + uint16_t proto_type; + uint8_t hw_size; + uint8_t proto_size; + uint16_t opcode; + uint8_t source_mac[6]; + uint8_t source_ip[4]; + uint8_t dest_mac[6]; + uint8_t dest_ip[4]; +} __attribute__((__packed__)) ARPHdr; + +#endif /* SURICATA_DECODE_ARP_H */ diff --git a/src/decode-events.c b/src/decode-events.c index 83f8b22efd..513969b0a7 100644 --- a/src/decode-events.c +++ b/src/decode-events.c @@ -873,5 +873,35 @@ const struct DecodeEvents_ DEvents[] = { STREAM_REASSEMBLY_INSERT_INVALID, }, + /* ARP EVENTS */ + { + "decoder.arp.pkt_too_small", + ARP_PKT_TOO_SMALL, + }, + { + "decoder.arp.unsupported_hardware", + ARP_UNSUPPORTED_HARDWARE, + }, + { + "decoder.arp.unsupported_protocol", + ARP_UNSUPPORTED_PROTOCOL, + }, + { + "decoder.arp.invalid_pkt", + ARP_INVALID_PKT, + }, + { + "decoder.arp.invalid_hardware_size", + ARP_INVALID_HARDWARE_SIZE, + }, + { + "decoder.arp.invalid_protocol_size", + ARP_INVALID_PROTOCOL_SIZE, + }, + { + "decoder.arp.unsupported_opcode", + ARP_UNSUPPORTED_OPCODE, + }, + { NULL, 0 }, }; diff --git a/src/decode-events.h b/src/decode-events.h index 27a2299cd6..e61668976d 100644 --- a/src/decode-events.h +++ b/src/decode-events.h @@ -297,6 +297,15 @@ enum { STREAM_REASSEMBLY_INSERT_LIMIT, STREAM_REASSEMBLY_INSERT_INVALID, + /* ARP EVENTS */ + ARP_PKT_TOO_SMALL, /**< arp packet smaller than minimum size */ + ARP_UNSUPPORTED_HARDWARE, /**< arp hw_type is not ethernet */ + ARP_UNSUPPORTED_PROTOCOL, /**< arp proto_type is not ipv4 */ + ARP_INVALID_PKT, /**< arp pkt len is not 28 */ + ARP_INVALID_HARDWARE_SIZE, /**< arp hw size is 6 */ + ARP_INVALID_PROTOCOL_SIZE, /**< arp proto size is not 4 */ + ARP_UNSUPPORTED_OPCODE, /**< arp opcode is not listed */ + /* should always be last! */ DECODE_EVENT_MAX, }; diff --git a/src/decode.h b/src/decode.h index 9175f6cc3c..168253750b 100644 --- a/src/decode.h +++ b/src/decode.h @@ -97,6 +97,7 @@ enum PktSrcEnum { #include "decode-esp.h" #include "decode-vlan.h" #include "decode-mpls.h" +#include "decode-arp.h" #include "util-validate.h" @@ -416,6 +417,7 @@ enum PacketL3Types { PACKET_L3_UNKNOWN = 0, PACKET_L3_IPV4, PACKET_L3_IPV6, + PACKET_L3_ARP, }; struct PacketL3 { @@ -426,6 +428,7 @@ struct PacketL3 { union Hdrs { IPV4Hdr *ip4h; IPV6Hdr *ip6h; + ARPHdr *arph; } hdrs; /* IPv4 and IPv6 are mutually exclusive */ union { @@ -928,6 +931,25 @@ static inline bool PacketIsESP(const Packet *p) return p->l4.type == PACKET_L4_ESP; } +static inline const ARPHdr *PacketGetARP(const Packet *p) +{ + DEBUG_VALIDATE_BUG_ON(p->l3.type != PACKET_L3_ARP); + return p->l3.hdrs.arph; +} + +static inline ARPHdr *PacketSetARP(Packet *p, const uint8_t *buf) +{ + DEBUG_VALIDATE_BUG_ON(p->l3.type != PACKET_L3_UNKNOWN); + p->l3.type = PACKET_L3_ARP; + p->l3.hdrs.arph = (ARPHdr *)buf; + return p->l3.hdrs.arph; +} + +static inline bool PacketIsARP(const Packet *p) +{ + return p->l3.type == PACKET_L3_ARP; +} + /** \brief Structure to hold thread specific data for all decode modules */ typedef struct DecodeThreadVars_ { @@ -1126,6 +1148,7 @@ int DecodeERSPANTypeI(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t int DecodeCHDLC(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t); int DecodeTEMPLATE(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t); int DecodeNSH(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t); +int DecodeARP(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t); #ifdef UNITTESTS void DecodeIPV6FragHeader(Packet *p, const uint8_t *pkt, @@ -1475,7 +1498,7 @@ static inline bool DecodeNetworkLayer(ThreadVars *tv, DecodeThreadVars *dtv, DecodeIEEE8021ah(tv, dtv, p, data, len); break; case ETHERNET_TYPE_ARP: - StatsIncr(tv, dtv->counter_arp); + DecodeARP(tv, dtv, p, data, len); break; case ETHERNET_TYPE_MPLS_UNICAST: case ETHERNET_TYPE_MPLS_MULTICAST: