]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
flow: track flow for ICMP
authorVictor Julien <victor@inliniac.net>
Wed, 6 Dec 2017 16:08:44 +0000 (17:08 +0100)
committerVictor Julien <victor@inliniac.net>
Thu, 5 Apr 2018 10:40:59 +0000 (12:40 +0200)
Change packet layout to allow for expected counterpart type.

src/decode-icmpv4.c
src/decode-icmpv4.h
src/decode-icmpv6.c
src/decode-icmpv6.h
src/decode.h
src/flow-hash.c
src/flow-util.c
src/flow.h
src/output-json-flow.c
src/output-json-netflow.c
src/util-lua-common.c

index 20cb6e91fe98659c8095dbcb47b72c90ece32b9a..2e567b7557d3c50fb3e5aa9f325928942b1ff54f 100644 (file)
@@ -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
index b0f69dd5d9b03354454bdd9f6e4ddc9eff8f7269..5f9946f0a3ec2b2f9d4b4f8667ea3308f413ea50 100644 (file)
 #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__ */
 
index 24617d356bc1c6045b7eedd9a5e003218cdbed76..d035e133b0f3cbc82922cce5d45a83954dd3e821 100644 (file)
@@ -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);
 
index 105d0ffb4b63c5982e76fbba242c734b21d91288..07bc957cf22b7d5df3ff4b3923800cfa2a372b08 100644 (file)
@@ -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);
 
index 239704bec0be9fec83f1837a6f958b5ef77cbf83..3fc8adfb83473efde21139131909a654caf02cfc 100644 (file)
@@ -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
index ff94df89a31e41f230f6c9a7b0e2d1f6017f5abf..5db87a637f178f51ca7f79eb4ece9a1028ec60d2 100644 (file)
@@ -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;
index 161d1feed5704d1aacc1f8cfb95eec10214b0e72..b819f6a5bf80471ea2a810e408e6c930e65b9c19 100644 (file)
@@ -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);
index 4c8e0bfb14e63c9a90dc9d962f0074f148c56c9f..039cc906fa1d0b536e444de072e539af405f47e9 100644 (file)
@@ -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;
index 2a963622e36237840c0c154167228f60d3797957..f3672facab440b26f5ab1e81ed7e9851463e60bf 100644 (file)
@@ -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;
index 097fea567e1aee55733390f17e9efd7e9c6ee62a..f13a837a25bf9ceef0c8e61268411b2d567dcb33 100644 (file)
@@ -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;
 }
index 06a43f68635838d2273b7c2c7b364e8760af7c96..c45c9b1355cbbab8b50d6f1cf72c4610fce29d0e 100644 (file)
@@ -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);