From: Victor Julien Date: Wed, 6 Dec 2017 16:08:44 +0000 (+0100) Subject: flow: track flow for ICMP X-Git-Tag: suricata-4.1.0-rc1~136 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c662383b53f059dc221d74841228adda2c9a200f;p=thirdparty%2Fsuricata.git flow: track flow for ICMP Change packet layout to allow for expected counterpart type. --- diff --git a/src/decode-icmpv4.c b/src/decode-icmpv4.c index 20cb6e91fe..2e567b7557 100644 --- a/src/decode-icmpv4.c +++ b/src/decode-icmpv4.c @@ -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 diff --git a/src/decode-icmpv4.h b/src/decode-icmpv4.h index b0f69dd5d9..5f9946f0a3 100644 --- a/src/decode-icmpv4.h +++ b/src/decode-icmpv4.h @@ -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__ */ diff --git a/src/decode-icmpv6.c b/src/decode-icmpv6.c index 24617d356b..d035e133b0 100644 --- a/src/decode-icmpv6.c +++ b/src/decode-icmpv6.c @@ -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); diff --git a/src/decode-icmpv6.h b/src/decode-icmpv6.h index 105d0ffb4b..07bc957cf2 100644 --- a/src/decode-icmpv6.h +++ b/src/decode-icmpv6.h @@ -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); diff --git a/src/decode.h b/src/decode.h index 239704bec0..3fc8adfb83 100644 --- a/src/decode.h +++ b/src/decode.h @@ -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 diff --git a/src/flow-hash.c b/src/flow-hash.c index ff94df89a3..5db87a637f 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -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; diff --git a/src/flow-util.c b/src/flow-util.c index 161d1feed5..b819f6a5bf 100644 --- a/src/flow-util.c +++ b/src/flow-util.c @@ -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); diff --git a/src/flow.h b/src/flow.h index 4c8e0bfb14..039cc906fa 100644 --- a/src/flow.h +++ b/src/flow.h @@ -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; diff --git a/src/output-json-flow.c b/src/output-json-flow.c index 2a963622e3..f3672facab 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -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; diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index 097fea567e..f13a837a25 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -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; } diff --git a/src/util-lua-common.c b/src/util-lua-common.c index 06a43f6863..c45c9b1355 100644 --- a/src/util-lua-common.c +++ b/src/util-lua-common.c @@ -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);