flow: track flow for ICMP

Change packet layout to allow for expected counterpart type.
pull/3335/head
Victor Julien 7 years ago
parent 708aad3f4a
commit c662383b53

@ -166,11 +166,16 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt,
SCLogDebug("ICMPV4 TYPE %" PRIu32 " CODE %" PRIu32 "", p->icmpv4h->type, p->icmpv4h->code);
p->proto = IPPROTO_ICMP;
p->type = p->icmpv4h->type;
p->code = p->icmpv4h->code;
p->icmp_s.type = p->icmpv4h->type;
p->icmp_s.code = p->icmpv4h->code;
p->payload = pkt + ICMPV4_HEADER_LEN;
p->payload_len = len - ICMPV4_HEADER_LEN;
int ctype = ICMPv4GetCounterpart(p->icmp_s.type);
if (ctype != -1) {
p->icmp_d.type = (uint8_t)ctype;
}
ICMPV4ExtHdr* icmp4eh = (ICMPV4ExtHdr*) p->icmpv4h;
switch (p->icmpv4h->type)
@ -189,18 +194,10 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt,
} else {
/* parse IP header plus 64 bytes */
if (len > ICMPV4_HEADER_PKT_OFFSET) {
if (DecodePartialIPV4(p, (uint8_t *)(pkt + ICMPV4_HEADER_PKT_OFFSET),
len - ICMPV4_HEADER_PKT_OFFSET ) == 0)
{
/* ICMP ICMP_DEST_UNREACH influence TCP/UDP flows */
if (ICMPV4_DEST_UNREACH_IS_VALID(p)) {
FlowSetupPacket(p);
}
}
(void)DecodePartialIPV4(p, (uint8_t *)(pkt + ICMPV4_HEADER_PKT_OFFSET),
len - ICMPV4_HEADER_PKT_OFFSET );
}
}
break;
case ICMP_SOURCE_QUENCH:
@ -304,9 +301,26 @@ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt,
}
FlowSetupPacket(p);
return TM_ECODE_OK;
}
/** \retval type counterpart type or -1 */
int ICMPv4GetCounterpart(uint8_t type)
{
#define CASE_CODE(t,r) case (t): return r; case (r): return t;
switch (type) {
CASE_CODE(ICMP_ECHO, ICMP_ECHOREPLY);
CASE_CODE(ICMP_TIMESTAMP, ICMP_TIMESTAMPREPLY);
CASE_CODE(ICMP_INFO_REQUEST, ICMP_INFO_REPLY);
CASE_CODE(ICMP_ROUTERSOLICIT, ICMP_ROUTERADVERT);
CASE_CODE(ICMP_ADDRESS, ICMP_ADDRESSREPLY);
default:
return -1;
}
#undef CASE_CODE
}
#ifdef UNITTESTS
/** DecodeICMPV4test01

@ -46,6 +46,12 @@
#ifndef ICMP_ECHO
#define ICMP_ECHO 8 /* Echo Request */
#endif
#ifndef ICMP_ROUTERADVERT
#define ICMP_ROUTERADVERT 9
#endif
#ifndef ICMP_ROUTERSOLICIT
#define ICMP_ROUTERSOLICIT 10
#endif
#ifndef ICMP_TIME_EXCEEDED
#define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */
#endif
@ -319,5 +325,7 @@ static inline uint16_t ICMPV4CalculateChecksum(uint16_t *pkt, uint16_t tlen)
return (uint16_t) ~csum;
}
int ICMPv4GetCounterpart(uint8_t type);
#endif /* __DECODE_ICMPV4_H__ */

@ -152,6 +152,28 @@ static void DecodePartialIPV6(Packet *p, uint8_t *partial_packet, uint16_t len )
return;
}
/** \retval type counterpart type or -1 */
int ICMPv6GetCounterpart(uint8_t type)
{
#define CASE_CODE(t,r) case (t): return r; case (r): return t;
switch (type) {
CASE_CODE(ICMP6_ECHO_REQUEST, ICMP6_ECHO_REPLY);
CASE_CODE(ND_NEIGHBOR_SOLICIT, ND_NEIGHBOR_ADVERT);
CASE_CODE(ND_ROUTER_SOLICIT, ND_ROUTER_ADVERT);
CASE_CODE(MLD_LISTENER_QUERY, MLD_LISTENER_REPORT);
CASE_CODE(ICMP6_NI_QUERY, ICMP6_NI_REPLY);
CASE_CODE(HOME_AGENT_AD_REQUEST,HOME_AGENT_AD_REPLY);
CASE_CODE(MOBILE_PREFIX_SOLICIT,MOBILE_PREFIX_ADVERT);
CASE_CODE(CERT_PATH_SOLICIT, CERT_PATH_ADVERT);
CASE_CODE(MC_ROUTER_ADVERT, MC_ROUTER_SOLICIT);
CASE_CODE(DUPL_ADDR_REQUEST, DUPL_ADDR_CONFIRM);
default:
return -1;
}
#undef CASE_CODE
}
/**
* \brief Decode ICMPV6 packets and fill the Packet with the decoded info
*
@ -178,11 +200,16 @@ int DecodeICMPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
p->icmpv6h = (ICMPV6Hdr *)pkt;
p->proto = IPPROTO_ICMPV6;
p->type = p->icmpv6h->type;
p->code = p->icmpv6h->code;
p->icmp_s.type = p->icmpv6h->type;
p->icmp_s.code = p->icmpv6h->code;
p->payload_len = len - ICMPV6_HEADER_LEN;
p->payload = pkt + ICMPV6_HEADER_LEN;
int ctype = ICMPv6GetCounterpart(p->icmp_s.type);
if (ctype != -1) {
p->icmp_d.type = (uint8_t)ctype;
}
SCLogDebug("ICMPV6 TYPE %" PRIu32 " CODE %" PRIu32 "", p->icmpv6h->type,
p->icmpv6h->code);

@ -189,6 +189,8 @@ typedef struct ICMPV6Vars_ {
void DecodeICMPV6RegisterTests(void);
int ICMPv6GetCounterpart(uint8_t type);
/** -------- Inline functions --------- */
static inline uint16_t ICMPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t);

@ -411,11 +411,19 @@ typedef struct Packet_
Address dst;
union {
Port sp;
uint8_t type;
// icmp type and code of this packet
struct {
uint8_t type;
uint8_t code;
} icmp_s;
};
union {
Port dp;
uint8_t code;
// icmp type and code of the expected counterpart (for flows)
struct {
uint8_t type;
uint8_t code;
} icmp_d;
};
uint8_t proto;
/* make sure we can't be attacked on when the tunneled packet

@ -223,6 +223,17 @@ static inline uint32_t FlowGetHash(const Packet *p)
(f1)->recursion_level == (f2)->recursion_level && \
(f1)->vlan_id[0] == (f2)->vlan_id[0] && \
(f1)->vlan_id[1] == (f2)->vlan_id[1])
#define CMP_FLOW_ICMP(f1,f2) \
(((CMP_ADDR(&(f1)->src, &(f2)->src) && \
CMP_ADDR(&(f1)->dst, &(f2)->dst) && \
CMP_PORT((f1)->icmp_s.type, (f2)->icmp_s.type) && CMP_PORT((f1)->icmp_d.type, (f2)->icmp_d.type)) || \
(CMP_ADDR(&(f1)->src, &(f2)->dst) && \
CMP_ADDR(&(f1)->dst, &(f2)->src) && \
CMP_PORT((f1)->icmp_d.type, (f2)->icmp_s.type) && CMP_PORT((f1)->icmp_s.type, (f2)->icmp_d.type))) && \
(f1)->proto == (f2)->proto && \
(f1)->recursion_level == (f2)->recursion_level && \
(f1)->vlan_id[0] == (f2)->vlan_id[0] && \
(f1)->vlan_id[1] == (f2)->vlan_id[1])
/**
* \brief See if a ICMP packet belongs to a flow by comparing the embedded
@ -268,7 +279,7 @@ static inline int FlowCompareICMPv4(Flow *f, const Packet *p)
/* no match, fall through */
} else {
/* just treat ICMP as a normal proto for now */
return CMP_FLOW(f, p);
return CMP_FLOW_ICMP(f, p);
}
return 0;

@ -39,6 +39,8 @@
#include "detect.h"
#include "detect-engine-state.h"
#include "decode-icmpv4.h"
/** \brief allocate a flow
*
* We check against the memuse counter. If it passes that check we increment
@ -122,6 +124,24 @@ uint8_t FlowGetReverseProtoMapping(uint8_t rproto)
}
}
static inline void FlowSetICMPv4CounterPart(Flow *f)
{
int ctype = ICMPv4GetCounterpart(f->icmp_s.type);
if (ctype == -1)
return;
f->icmp_d.type = (uint8_t)ctype;
}
static inline void FlowSetICMPv6CounterPart(Flow *f)
{
int ctype = ICMPv6GetCounterpart(f->icmp_s.type);
if (ctype == -1)
return;
f->icmp_d.type = (uint8_t)ctype;
}
/* initialize the flow from the first packet
* we see from it. */
void FlowInit(Flow *f, const Packet *p)
@ -159,11 +179,13 @@ void FlowInit(Flow *f, const Packet *p)
SET_UDP_SRC_PORT(p,&f->sp);
SET_UDP_DST_PORT(p,&f->dp);
} else if (p->icmpv4h != NULL) {
f->type = p->type;
f->code = p->code;
f->icmp_s.type = p->icmp_s.type;
f->icmp_s.code = p->icmp_s.code;
FlowSetICMPv4CounterPart(f);
} else if (p->icmpv6h != NULL) {
f->type = p->type;
f->code = p->code;
f->icmp_s.type = p->icmp_s.type;
f->icmp_s.code = p->icmp_s.code;
FlowSetICMPv6CounterPart(f);
} else if (p->sctph != NULL) { /* XXX MACRO */
SET_SCTP_SRC_PORT(p,&f->sp);
SET_SCTP_DST_PORT(p,&f->dp);

@ -329,11 +329,17 @@ typedef struct Flow_
FlowAddress src, dst;
union {
Port sp; /**< tcp/udp source port */
uint8_t type; /**< icmp type */
struct {
uint8_t type; /**< icmp type */
uint8_t code; /**< icmp code */
} icmp_s;
};
union {
Port dp; /**< tcp/udp destination port */
uint8_t code; /**< icmp code */
struct {
uint8_t type; /**< icmp type */
uint8_t code; /**< icmp code */
} icmp_d;
};
uint8_t proto;
uint8_t recursion_level;

@ -163,9 +163,15 @@ static json_t *CreateJSONHeaderFromFlow(const Flow *f, const char *event_type)
case IPPROTO_ICMP:
case IPPROTO_ICMPV6:
json_object_set_new(js, "icmp_type",
json_integer(f->type));
json_integer(f->icmp_s.type));
json_object_set_new(js, "icmp_code",
json_integer(f->code));
json_integer(f->icmp_s.code));
if (f->tosrcpktcnt) {
json_object_set_new(js, "response_icmp_type",
json_integer(f->icmp_d.type));
json_object_set_new(js, "response_icmp_code",
json_integer(f->icmp_d.code));
}
break;
}
return js;

@ -177,12 +177,18 @@ static json_t *CreateJSONHeaderFromFlow(const Flow *f, const char *event_type, i
json_object_set_new(js, "proto", json_string(proto));
switch (f->proto) {
case IPPROTO_ICMP:
case IPPROTO_ICMPV6:
json_object_set_new(js, "icmp_type",
json_integer(f->type));
json_object_set_new(js, "icmp_code",
json_integer(f->code));
case IPPROTO_ICMPV6: {
uint8_t type = f->icmp_s.type;
uint8_t code = f->icmp_s.code;
if (dir == 1) {
type = f->icmp_d.type;
code = f->icmp_d.code;
}
json_object_set_new(js, "icmp_type", json_integer(type));
json_object_set_new(js, "icmp_code", json_integer(code));
break;
}
}
return js;
}

@ -357,8 +357,8 @@ static int LuaCallbackTuplePushToStackFromPacket(lua_State *luastate, const Pack
lua_pushnumber (luastate, p->dp);
} else if (p->proto == IPPROTO_ICMP || p->proto == IPPROTO_ICMPV6) {
lua_pushnumber (luastate, p->type);
lua_pushnumber (luastate, p->code);
lua_pushnumber (luastate, p->icmp_s.type);
lua_pushnumber (luastate, p->icmp_s.code);
} else {
lua_pushnumber (luastate, 0);
lua_pushnumber (luastate, 0);
@ -420,8 +420,8 @@ static int LuaCallbackTuplePushToStackFromFlow(lua_State *luastate, const Flow *
lua_pushnumber (luastate, f->dp);
} else if (f->proto == IPPROTO_ICMP || f->proto == IPPROTO_ICMPV6) {
lua_pushnumber (luastate, f->type);
lua_pushnumber (luastate, f->code);
lua_pushnumber (luastate, f->icmp_s.type);
lua_pushnumber (luastate, f->icmp_s.code);
} else {
lua_pushnumber (luastate, 0);
lua_pushnumber (luastate, 0);

Loading…
Cancel
Save