decode/arp: implement decoder

This adds a decoder for ARP.

Ticket #6827
pull/11086/head
Giuseppe Longo 2 years ago committed by Victor Julien
parent 12d027f6a2
commit 5219a5da5f

@ -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": {

@ -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 \

@ -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;
}

@ -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 */

@ -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 },
};

@ -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,
};

@ -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:

Loading…
Cancel
Save