This adds a decoder for ARP.
Ticket #6827
"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": {
datasets-reputation.h \
datasets-sha256.h \
datasets-string.h \
+ decode-arp.h \
decode-chdlc.h \
decode-erspan.h \
decode-esp.h \
datasets-sha256.c \
datasets-string.c \
decode.c \
+ decode-arp.c \
decode-chdlc.c \
decode-erspan.c \
decode-esp.c \
--- /dev/null
+/* 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 <giuseppe@glongo.it>
+ *
+ */
+
+#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;
+}
--- /dev/null
+/* 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 <giuseppe@glongo.it>
+ */
+
+#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 */
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 },
};
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,
};
#include "decode-esp.h"
#include "decode-vlan.h"
#include "decode-mpls.h"
+#include "decode-arp.h"
#include "util-validate.h"
PACKET_L3_UNKNOWN = 0,
PACKET_L3_IPV4,
PACKET_L3_IPV6,
+ PACKET_L3_ARP,
};
struct PacketL3 {
union Hdrs {
IPV4Hdr *ip4h;
IPV6Hdr *ip6h;
+ ARPHdr *arph;
} hdrs;
/* IPv4 and IPv6 are mutually exclusive */
union {
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_
{
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,
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: