output-json: add MAC address output

This commit adds MAC address output to the EVE-JSON format. We follow the
remarks made in Redmine ticket #962: for packets, log MAC src/dst as a
scalar field in EVE; for flows, log MAC src/dst as lists in EVE. Field names
are different between flow and packet context to avoid type confusion
(src_mac vs. src_macs). Configuration approach and JSON representation is
taken from previous GitHub PR #2700.
pull/5258/head
Sascha Steinbiss 6 years ago committed by Victor Julien
parent c42574169e
commit 4e1a41a17d

@ -14,6 +14,9 @@ where all these logs go into a single file.
Each alert, http log, etc will go into this one file: 'eve.json'. This file
can then be processed by 3rd party tools like Logstash (ELK) or jq.
If ``ethernet`` is set to yes, then ethernet headers will be added to events
if available.
Output types
~~~~~~~~~~~~
@ -33,6 +36,7 @@ Output types::
#facility: local5
#level: Info ## possible levels: Emergency, Alert, Critical,
## Error, Warning, Notice, Info, Debug
#ethernet: no # log ethernet header in events when available
#redis:
# server: 127.0.0.1
# port: 6379

@ -505,6 +505,7 @@ util-lua-tls.c util-lua-tls.h \
util-lua-ssh.c util-lua-ssh.h \
util-lua-hassh.c util-lua-hassh.h \
util-lua-smtp.c util-lua-smtp.h \
util-macset.c util-macset.h \
util-magic.c util-magic.h \
util-memcmp.c util-memcmp.h \
util-memcpy.h \

@ -506,6 +506,8 @@ void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv)
dtv->counter_mpls = StatsRegisterCounter("decoder.mpls", tv);
dtv->counter_avg_pkt_size = StatsRegisterAvgCounter("decoder.avg_pkt_size", tv);
dtv->counter_max_pkt_size = StatsRegisterMaxCounter("decoder.max_pkt_size", tv);
dtv->counter_max_mac_addrs_src = StatsRegisterMaxCounter("decoder.max_mac_addrs_src", tv);
dtv->counter_max_mac_addrs_dst = StatsRegisterMaxCounter("decoder.max_mac_addrs_dst", tv);
dtv->counter_erspan = StatsRegisterMaxCounter("decoder.erspan", tv);
dtv->counter_flow_memcap = StatsRegisterCounter("flow.memcap", tv);

@ -631,6 +631,8 @@ typedef struct DecodeThreadVars_
uint16_t counter_bytes;
uint16_t counter_avg_pkt_size;
uint16_t counter_max_pkt_size;
uint16_t counter_max_mac_addrs_src;
uint16_t counter_max_mac_addrs_dst;
uint16_t counter_invalid;

@ -197,6 +197,16 @@ void FlowInit(Flow *f, const Packet *p)
f->protomap = FlowGetProtoMapping(f->proto);
if (MacSetFlowStorageEnabled()) {
MacSet *ms = FlowGetStorageById(f, MacSetGetFlowStorageID());
if (ms != NULL) {
MacSetReset(ms);
} else {
ms = MacSetInit(10);
FlowSetStorageById(f, MacSetGetFlowStorageID(), ms);
}
}
SCReturn;
}

@ -115,6 +115,12 @@
(f)->sgh_toclient = NULL; \
GenericVarFree((f)->flowvar); \
(f)->flowvar = NULL; \
if (MacSetFlowStorageEnabled()) { \
MacSet *ms = FlowGetStorageById((f), MacSetGetFlowStorageID()); \
if (ms != NULL) { \
MacSetReset(ms); \
} \
} \
RESET_COUNTERS((f)); \
} while(0)

@ -75,7 +75,7 @@ typedef struct FlowWorkerThreadData_ {
*/
static inline TmEcode FlowUpdate(ThreadVars *tv, FlowWorkerThreadData *fw, Packet *p)
{
FlowHandlePacketUpdate(p->flow, p);
FlowHandlePacketUpdate(p->flow, p, tv, fw->dtv);
int state = SC_ATOMIC_GET(p->flow->flow_state);
switch (state) {

@ -402,6 +402,25 @@ static inline void FlowUpdateTTL(Flow *f, Packet *p, uint8_t ttl)
}
}
static inline void FlowUpdateEthernet(ThreadVars *tv, DecodeThreadVars *dtv,
Flow *f, EthernetHdr *ethh, bool toserver)
{
if (ethh && MacSetFlowStorageEnabled()) {
MacSet *ms = FlowGetStorageById(f, MacSetGetFlowStorageID());
if (ms != NULL) {
if (toserver) {
MacSetAddWithCtr(ms, ethh->eth_src, ethh->eth_dst, tv,
dtv->counter_max_mac_addrs_src,
dtv->counter_max_mac_addrs_dst);
} else {
MacSetAddWithCtr(ms, ethh->eth_dst, ethh->eth_src, tv,
dtv->counter_max_mac_addrs_dst,
dtv->counter_max_mac_addrs_src);
}
}
}
}
/** \brief Update Packet and Flow
*
* Updates packet and flow based on the new packet.
@ -411,7 +430,7 @@ static inline void FlowUpdateTTL(Flow *f, Packet *p, uint8_t ttl)
*
* \note overwrites p::flowflags
*/
void FlowHandlePacketUpdate(Flow *f, Packet *p)
void FlowHandlePacketUpdate(Flow *f, Packet *p, ThreadVars *tv, DecodeThreadVars *dtv)
{
SCLogDebug("packet %"PRIu64" -- flow %p", p->pcap_cnt, f);
@ -454,6 +473,7 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p)
f->flags &= ~FLOW_PROTO_DETECT_TS_DONE;
p->flags |= PKT_PROTO_DETECT_TS_DONE;
}
FlowUpdateEthernet(tv, dtv, f, p->ethh, true);
} else {
f->tosrcpktcnt++;
f->tosrcbytecnt += GET_PKT_LEN(p);
@ -469,6 +489,7 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p)
f->flags &= ~FLOW_PROTO_DETECT_TC_DONE;
p->flags |= PKT_PROTO_DETECT_TC_DONE;
}
FlowUpdateEthernet(tv, dtv, f, p->ethh, false);
}
if (SC_ATOMIC_GET(f->flow_state) == FLOW_STATE_ESTABLISHED) {
@ -498,7 +519,6 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p)
DecodeSetNoPayloadInspectionFlag(p);
}
/* update flow's ttl fields if needed */
if (PKT_IS_IPV4(p)) {
FlowUpdateTTL(f, p, IPV4_GET_IPTTL(p));

@ -29,6 +29,7 @@
#include "util-atomic.h"
#include "util-device.h"
#include "detect-tag.h"
#include "util-macset.h"
#include "util-optimize.h"
/* Part of the flow structure, so we declare it here.
@ -661,6 +662,6 @@ AppProto FlowGetAppProtocol(const Flow *f);
void *FlowGetAppState(const Flow *f);
uint8_t FlowGetDisruptionFlags(const Flow *f, uint8_t flags);
void FlowHandlePacketUpdate(Flow *f, Packet *p);
void FlowHandlePacketUpdate(Flow *f, Packet *p, ThreadVars *tv, DecodeThreadVars *dtv);
#endif /* __FLOW_H__ */

@ -63,6 +63,7 @@
#include "flow-var.h"
#include "flow-bit.h"
#include "flow-storage.h"
#include "source-pcap-file.h"
@ -435,12 +436,19 @@ static void EveAddMetadata(const Packet *p, const Flow *f, JsonBuilder *js)
}
}
int CreateJSONEther(JsonBuilder *parent, const Packet *p, const MacSet *ms);
void EveAddCommonOptions(const OutputJsonCommonSettings *cfg,
const Packet *p, const Flow *f, JsonBuilder *js)
{
if (cfg->include_metadata) {
EveAddMetadata(p, f, js);
}
if (cfg->include_ethernet) {
MacSet *ms = FlowGetStorageById((Flow*) f, MacSetGetFlowStorageID());
if (ms != NULL)
CreateJSONEther(js, p, ms);
}
if (cfg->include_community_id && f != NULL) {
CreateEveCommunityFlowId(js, f, cfg->community_id_seed);
}
@ -758,6 +766,80 @@ void CreateEveFlowId(JsonBuilder *js, const Flow *f)
}
}
static inline void JSONFormatAndAddMACAddr(JsonBuilder *js, const char *key,
uint8_t *val, bool is_array)
{
char eth_addr[19];
(void) snprintf(eth_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x",
val[0], val[1], val[2], val[3], val[4], val[5]);
if (is_array) {
jb_append_string(js, eth_addr);
} else {
jb_set_string(js, key, eth_addr);
}
}
/* only required to traverse the MAC address set */
typedef struct JSONMACAddrInfo {
JsonBuilder *src, *dst;
} JSONMACAddrInfo;
static int MacSetIterateToJSON(uint8_t *val, MacSetSide side, void *data)
{
JSONMACAddrInfo *info = (JSONMACAddrInfo*) data;
if (side == MAC_SET_DST) {
JSONFormatAndAddMACAddr(info->dst, NULL, val, true);
} else {
JSONFormatAndAddMACAddr(info->src, NULL, val, true);
}
return 0;
}
int CreateJSONEther(JsonBuilder *js, const Packet *p, const MacSet *ms)
{
jb_open_object(js, "ether");
if (unlikely(js == NULL))
return 0;
if (p == NULL) {
/* we are creating an ether object in a flow context, so we need to
append to arrays */
if (MacSetSize(ms) > 0) {
JSONMACAddrInfo info;
info.dst = jb_new_array();
info.src = jb_new_array();
int ret = MacSetForEach(ms, MacSetIterateToJSON, &info);
if (unlikely(ret != 0)) {
/* should not happen, JSONFlowAppendMACAddrs is sane */
jb_free(info.dst);
jb_free(info.src);
return ret;
}
jb_close(info.dst);
jb_close(info.src);
jb_set_object(js, "dest_macs", info.dst);
jb_set_object(js, "src_macs", info.src);
jb_free(info.dst);
jb_free(info.src);
}
} else {
/* this is a packet context, so we need to add scalar fields */
uint8_t *src, *dst;
if (p->ethh != NULL) {
if ((PKT_IS_TOCLIENT(p))) {
src = p->ethh->eth_dst;
dst = p->ethh->eth_src;
} else {
src = p->ethh->eth_src;
dst = p->ethh->eth_dst;
}
JSONFormatAndAddMACAddr(js, "src_mac", src, false);
JSONFormatAndAddMACAddr(js, "dest_mac", dst, false);
}
}
jb_close(js);
return 0;
}
JsonBuilder *CreateEveHeader(const Packet *p, enum OutputJsonLogDirection dir,
const char *event_type, JsonAddrInfo *addr)
{
@ -1115,6 +1197,15 @@ OutputInitResult OutputJsonInitCtx(ConfNode *conf)
json_ctx->cfg.include_metadata = true;
}
/* Check if ethernet information should be logged. */
const ConfNode *ethernet = ConfNodeLookupChild(conf, "ethernet");
if (ethernet && ethernet->val && ConfValIsTrue(ethernet->val)) {
SCLogConfig("Enabling Ethernet MAC address logging.");
json_ctx->cfg.include_ethernet = true;
} else {
json_ctx->cfg.include_ethernet = false;
}
/* See if we want to enable the community id */
const ConfNode *community_id = ConfNodeLookupChild(conf, "community-id");
if (community_id && community_id->val && ConfValIsTrue(community_id->val)) {
@ -1154,7 +1245,6 @@ OutputInitResult OutputJsonInitCtx(ConfNode *conf)
json_ctx->file_ctx->type = json_ctx->json_out;
}
SCLogDebug("returning output_ctx %p", output_ctx);
result.ctx = output_ctx;

@ -90,6 +90,7 @@ TmEcode JsonLogThreadDeinit(ThreadVars *t, void *data);
typedef struct OutputJsonCommonSettings_ {
bool include_metadata;
bool include_community_id;
bool include_ethernet;
uint16_t community_id_seed;
} OutputJsonCommonSettings;

@ -92,6 +92,7 @@
#include "util-pool.h"
#include "util-byte.h"
#include "util-proto-name.h"
#include "util-macset.h"
#include "util-memrchr.h"
#include "util-mpm-ac.h"
@ -198,6 +199,7 @@ static void RegisterUnittests(void)
AppLayerUnittestsRegister();
MimeDecRegisterTests();
StreamingBufferRegisterTests();
MacSetRegisterTests();
#ifdef OS_WIN32
Win32SyscallRegisterTests();
#endif

@ -2470,6 +2470,9 @@ int PostConfLoadedSetup(SCInstance *suri)
LiveDevRegisterExtension();
#endif
RegisterFlowBypassInfo();
MacSetRegisterFlowStorage();
AppLayerSetup();
/* Suricata will use this umask if provided. By default it will use the

@ -0,0 +1,449 @@
/* Copyright (C) 2020 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.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha.steinbiss@dcso.de>
*
* Set-like data store for MAC addresses. Implemented as array for memory
* locality reasons as the expected number of items is typically low.
*
*/
#include "suricata-common.h"
#include "suricata.h"
#include "flow-util.h"
#include "flow-private.h"
#include "flow-storage.h"
#include "util-macset.h"
#include "util-unittest.h"
#include "util-unittest-helper.h"
typedef uint8_t MacAddr[6];
typedef enum {
EMPTY_SET, /* no address inserted yet */
SINGLE_MAC, /* we have a single pair of addresses (likely) */
MULTI_MAC /* we have multiple addresses per flow */
} MacSetState;
struct MacSet_ {
/* static store for a single MAC address per side */
MacAddr singles[2];
/* state determines how addresses are stored per side:
- SINGLE_MAC uses static locations allocated with the MacSet
itself to store a single address (most likely case)
- MULTI_MAC is used when more than one distinct address
is detected (causes another allocation and linear-time add) */
MacSetState state[2];
/* buffer for multiple MACs per flow and direction */
MacAddr *buf[2];
int size,
last[2];
};
int g_macset_storage_id = -1;
void MacSetRegisterFlowStorage(void)
{
ConfNode *root = ConfGetNode("outputs");
ConfNode *node = NULL;
/* we only need to register if at least one enabled 'eve-log' output
has the ethernet setting enabled */
if (root != NULL) {
TAILQ_FOREACH(node, &root->head, next) {
if (strcmp(node->val, "eve-log") == 0) {
const char *enabled = ConfNodeLookupChildValue(node->head.tqh_first, "enabled");
if (enabled != NULL && ConfValIsTrue(enabled)) {
const char *ethernet = ConfNodeLookupChildValue(node->head.tqh_first, "ethernet");
if (ethernet != NULL && ConfValIsTrue(ethernet)) {
g_macset_storage_id = FlowStorageRegister("macset", sizeof(void *),
NULL, (void(*)(void *)) MacSetFree);
return;
}
}
}
}
}
}
bool MacSetFlowStorageEnabled(void)
{
return (g_macset_storage_id != -1);
}
MacSet *MacSetInit(int size)
{
MacSet *ms = NULL;
if (!FLOW_CHECK_MEMCAP(sizeof(ms))) {
return NULL;
}
ms = SCCalloc(1, sizeof(*ms));
if (unlikely(ms == NULL)) {
SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate MacSet memory");
return NULL;
}
(void) SC_ATOMIC_ADD(flow_memuse, (sizeof(*ms)));
ms->state[MAC_SET_SRC] = ms->state[MAC_SET_DST] = EMPTY_SET;
if (size < 3) {
/* we want to make sure we have at space for at least 3 items to
fit MACs during the initial extension to MULTI_MAC storage */
size = 3;
}
ms->size = size;
ms->last[MAC_SET_SRC] = ms->last[MAC_SET_DST] = 0;
return ms;
}
int MacSetGetFlowStorageID(void)
{
return g_macset_storage_id;
}
static inline void MacUpdateEntry(MacSet *ms, uint8_t *addr, int side, ThreadVars *tv, uint16_t ctr)
{
switch (ms->state[side]) {
case EMPTY_SET:
memcpy(ms->singles[side], addr, sizeof(MacAddr));;
ms->state[side] = SINGLE_MAC;
if (tv != NULL)
StatsSetUI64(tv, ctr, 1);
break;
case SINGLE_MAC:
if (unlikely(memcmp(addr, ms->singles[side], sizeof(MacAddr)) != 0)) {
if (ms->buf[side] == NULL) {
if (!FLOW_CHECK_MEMCAP(ms->size * sizeof(MacAddr))) {
/* in this case there is not much we can do */
return;
}
ms->buf[side] = SCCalloc(ms->size, sizeof(MacAddr));
if (unlikely(ms->buf[side] == NULL)) {
SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate "
"MacSet memory");
return;
}
(void) SC_ATOMIC_ADD(flow_memuse, (ms->size * sizeof(MacAddr)));
}
memcpy(ms->buf[side], ms->singles[side], sizeof(MacAddr));
memcpy(ms->buf[side] + 1, addr, sizeof(MacAddr));
ms->last[side] = 2;
if (tv != NULL)
StatsSetUI64(tv, ctr, 2);
ms->state[side] = MULTI_MAC;
}
break;
case MULTI_MAC:
if (unlikely(ms->last[side] == ms->size)) {
/* MacSet full, ignore item. We intentionally do not output
any warning in order not to stall packet processing */
return;
}
/* If the set is non-empty... */
if (ms->last[side] > 0) {
/* ...we search for duplicates in the set to decide whether
we need to insert the current item. We do this backwards,
since we expect the latest item to match more likely than
the first */
for (int i = ms->last[side] - 1; i >= 0; i--) {
uint8_t *addr2 = (uint8_t*) ((ms->buf[side]) + i);
/* If we find a match, we return early with no action */
if (likely(memcmp(addr2, addr, sizeof(MacAddr)) == 0)) {
return;
}
}
}
/* Otherwise, we insert the new address at the end */
memcpy(ms->buf[side] + ms->last[side], addr, sizeof(MacAddr));
ms->last[side]++;
if (tv != NULL)
StatsSetUI64(tv, ctr, ms->last[side]);
break;
}
}
void MacSetAddWithCtr(MacSet *ms, uint8_t *src_addr, uint8_t *dst_addr, ThreadVars *tv,
uint16_t ctr_src, uint16_t ctr_dst)
{
if (ms == NULL)
return;
MacUpdateEntry(ms, src_addr, MAC_SET_SRC, tv, ctr_src);
MacUpdateEntry(ms, dst_addr, MAC_SET_DST, tv, ctr_dst);
}
void MacSetAdd(MacSet *ms, uint8_t *src_addr, uint8_t *dst_addr)
{
MacSetAddWithCtr(ms, src_addr, dst_addr, NULL, 0, 0);
}
static inline int MacSetIterateSide(const MacSet *ms, MacSetIteratorFunc IterFunc,
MacSetSide side, void *data)
{
int ret = 0;
switch (ms->state[side]) {
case EMPTY_SET:
return 0;
case SINGLE_MAC:
ret = IterFunc((uint8_t*) ms->singles[side], side, data);
if (unlikely(ret != 0)) {
return ret;
}
break;
case MULTI_MAC:
for (int i = 0; i < ms->last[side]; i++) {
ret = IterFunc((uint8_t*) ms->buf[side][i], side, data);
if (unlikely(ret != 0)) {
return ret;
}
}
break;
}
return 0;
}
int MacSetForEach(const MacSet *ms, MacSetIteratorFunc IterFunc, void *data)
{
int ret = 0;
if (ms == NULL)
return 0;
ret = MacSetIterateSide(ms, IterFunc, MAC_SET_SRC, data);
if (ret != 0) {
return ret;
}
return MacSetIterateSide(ms, IterFunc, MAC_SET_DST, data);
}
int MacSetSize(const MacSet *ms)
{
int size = 0;
if (ms == NULL)
return 0;
switch(ms->state[MAC_SET_SRC]) {
case EMPTY_SET:
/* pass */
break;
case SINGLE_MAC:
size += 1;
break;
case MULTI_MAC:
size += ms->last[MAC_SET_SRC];
break;
}
switch(ms->state[MAC_SET_DST]) {
case EMPTY_SET:
/* pass */
break;
case SINGLE_MAC:
size += 1;
break;
case MULTI_MAC:
size += ms->last[MAC_SET_DST];
break;
}
return size;
}
void MacSetReset(MacSet *ms)
{
if (ms == NULL)
return;
ms->state[MAC_SET_SRC] = ms->state[MAC_SET_DST] = EMPTY_SET;
ms->last[MAC_SET_SRC] = ms->last[MAC_SET_DST] = 0;
}
void MacSetFree(MacSet *ms)
{
size_t total_free = 0;
if (ms == NULL)
return;
if (ms->buf[MAC_SET_SRC] != NULL) {
SCFree(ms->buf[MAC_SET_SRC]);
total_free += ms->size * sizeof(MacAddr);
}
if (ms->buf[MAC_SET_DST] != NULL) {
SCFree(ms->buf[MAC_SET_DST]);
total_free += ms->size * sizeof(MacAddr);
}
SCFree(ms);
total_free += sizeof(*ms);
(void) SC_ATOMIC_SUB(flow_memuse, total_free);
}
#ifdef UNITTESTS
static int CheckTest1Membership(uint8_t *addr, MacSetSide side, void *data)
{
int *i = (int*) data;
switch (*i) {
case 0:
if (addr[5] != 1) return 1;
break;
case 1:
if (addr[5] != 2) return 1;
break;
case 2:
if (addr[5] != 3) return 1;
break;
}
(*i)++;
return 0;
}
static int MacSetTest01(void)
{
MacSet *ms = NULL;
int ret = 0, i = 0;
MacAddr addr1 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x1},
addr2 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x2},
addr3 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x3};
SC_ATOMIC_SET(flow_config.memcap, 10000);
ms = MacSetInit(10);
FAIL_IF_NULL(ms);
FAIL_IF_NOT(MacSetSize(ms) == 0);
ret = MacSetForEach(ms, CheckTest1Membership, &i);
FAIL_IF_NOT(ret == 0);
MacSetAdd(ms, addr1, addr2);
FAIL_IF_NOT(MacSetSize(ms) == 2);
ret = MacSetForEach(ms, CheckTest1Membership, &i);
FAIL_IF_NOT(ret == 0);
MacSetAdd(ms, addr1, addr3);
FAIL_IF_NOT(MacSetSize(ms) == 3);
i = 0;
ret = MacSetForEach(ms, CheckTest1Membership, &i);
FAIL_IF_NOT(ret == 0);
MacSetReset(ms);
FAIL_IF_NOT(MacSetSize(ms) == 0);
MacSetAdd(ms, addr2, addr3);
FAIL_IF_NOT(MacSetSize(ms) == 2);
i = 1;
ret = MacSetForEach(ms, CheckTest1Membership, &i);
FAIL_IF_NOT(ret == 0);
MacSetFree(ms);
PASS;
}
static int MacSetTest02(void)
{
MacSet *ms = NULL;
int ret = 0, i = 0;
SC_ATOMIC_SET(flow_config.memcap, 10000);
ms = MacSetInit(10);
FAIL_IF_NULL(ms);
FAIL_IF_NOT(MacSetSize(ms) == 0);
for (i = 1; i < 100; i++) {
MacAddr addr1 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x1},
addr2 = {0x1, 0x0, 0x0, 0x0, 0x0, 0x2};
MacSetAdd(ms, addr1, addr2);
}
FAIL_IF_NOT(MacSetSize(ms) == 2);
ret = MacSetForEach(ms, CheckTest1Membership, &i);
FAIL_IF_NOT(ret == 0);
MacSetFree(ms);
PASS;
}
static int MacSetTest03(void)
{
MacSet *ms = NULL;
int i = 0;
SC_ATOMIC_SET(flow_config.memcap, 10000);
ms = MacSetInit(10);
FAIL_IF_NULL(ms);
FAIL_IF_NOT(MacSetSize(ms) == 0);
for (i = 1; i < 100; i++) {
MacAddr addr1 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x1},
addr2 = {0x1, 0x0, 0x0, 0x0, 0x0, 0x1};
addr1[5] = i;
addr2[5] = i;
MacSetAdd(ms, addr1, addr2);
}
FAIL_IF_NOT(MacSetSize(ms) == 20);
MacSetFree(ms);
PASS;
}
static int MacSetTest04(void)
{
MacSet *ms = NULL;
SC_ATOMIC_SET(flow_config.memcap, 2);
ms = MacSetInit(10);
FAIL_IF_NOT_NULL(ms);
PASS;
}
static int MacSetTest05(void)
{
MacSet *ms = NULL;
int ret = 0, i = 0;
SC_ATOMIC_SET(flow_config.memcap, 10);
ms = MacSetInit(10);
FAIL_IF_NULL(ms);
FAIL_IF_NOT(MacSetSize(ms) == 0);
for (i = 1; i < 100; i++) {
MacAddr addr1 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x1},
addr2 = {0x1, 0x0, 0x0, 0x0, 0x0, 0x1};
addr1[5] = i;
addr2[5] = i;
MacSetAdd(ms, addr1, addr2);
}
FAIL_IF_NOT(MacSetSize(ms) == 2);
ret = MacSetForEach(ms, CheckTest1Membership, &i);
FAIL_IF_NOT(ret == 0);
MacSetFree(ms);
PASS;
}
#endif /* UNITTESTS */
void MacSetRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("MacSetTest01", MacSetTest01);
UtRegisterTest("MacSetTest02", MacSetTest02);
UtRegisterTest("MacSetTest03", MacSetTest03);
UtRegisterTest("MacSetTest04", MacSetTest04);
UtRegisterTest("MacSetTest04", MacSetTest05);
#endif
return;
}

@ -0,0 +1,48 @@
/* Copyright (C) 2020 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.
*/
/**
* \file
*
* \author Sascha Steinbiss <sascha.steinbiss@dcso.de>
*/
#ifndef __UTIL_MACSET_H__
#define __UTIL_MACSET_H__
typedef struct MacSet_ MacSet;
typedef enum {
MAC_SET_SRC = 0,
MAC_SET_DST
} MacSetSide;
typedef int (*MacSetIteratorFunc)(uint8_t *addr, MacSetSide side, void*);
MacSet *MacSetInit(int size);
void MacSetAdd(MacSet*, uint8_t *src_addr, uint8_t *dst_addr);
void MacSetAddWithCtr(MacSet*, uint8_t *src_addr, uint8_t *dst_addr, ThreadVars *tv,
uint16_t ctr_src, uint16_t ctr_dst);
int MacSetForEach(const MacSet*, MacSetIteratorFunc, void*);
int MacSetSize(const MacSet*);
void MacSetReset(MacSet*);
void MacSetFree(MacSet*);
void MacSetRegisterFlowStorage(void);
int MacSetGetFlowStorageID(void);
bool MacSetFlowStorageEnabled(void);
void MacSetRegisterTests(void);
#endif /* __UTIL_MACSET_H__ */

@ -93,6 +93,7 @@ outputs:
#facility: local5
#level: Info ## possible levels: Emergency, Alert, Critical,
## Error, Warning, Notice, Info, Debug
#ethernet: no # log ethernet header in events when available
#redis:
# server: 127.0.0.1
# port: 6379

Loading…
Cancel
Save