]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
decode/arp: implement decoder
authorGiuseppe Longo <giuseppe@glongo.it>
Sat, 2 Mar 2024 17:50:27 +0000 (18:50 +0100)
committerVictor Julien <victor@inliniac.net>
Thu, 16 May 2024 05:09:27 +0000 (07:09 +0200)
This adds a decoder for ARP.

Ticket #6827

etc/schema.json
src/Makefile.am
src/decode-arp.c [new file with mode: 0644]
src/decode-arp.h [new file with mode: 0644]
src/decode-events.c
src/decode-events.h
src/decode.h

index 99946b061913ab8e866d3573e1bc32bbdbc28e7f..c9d61b95813a66d7dbcba7117aeba13edf6d6425 100644 (file)
                         "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": {
index e26f5e826daab3ed2ae9d877546b16088d7d9fa8..cbb781ccd071736fe276b7d63e72c2a75792888f 100755 (executable)
@@ -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 (file)
index 0000000..224b901
--- /dev/null
@@ -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 <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;
+}
diff --git a/src/decode-arp.h b/src/decode-arp.h
new file mode 100644 (file)
index 0000000..56ad0ed
--- /dev/null
@@ -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 <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 */
index 83f8b22efd93f5fe1000fbcf752b613766747ddf..513969b0a75d2d745bd42c3ea756c97514ece390 100644 (file)
@@ -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 },
 };
index 27a2299cd679fdff36776b52084a3cb76eb40fab..e61668976d1d9274a7331f8a63b44b818bae92e6 100644 (file)
@@ -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,
 };
index 9175f6cc3ce6dbe14aacff67702efe54fec4cb54..168253750b90d70478571c55ae44e9fde9abd0eb 100644 (file)
@@ -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: