Change packet layout to allow for expected counterpart type.
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)
} 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:
}
+ 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
#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
return (uint16_t) ~csum;
}
+int ICMPv4GetCounterpart(uint8_t type);
+
#endif /* __DECODE_ICMPV4_H__ */
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
*
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);
void DecodeICMPV6RegisterTests(void);
+int ICMPv6GetCounterpart(uint8_t type);
+
/** -------- Inline functions --------- */
static inline uint16_t ICMPV6CalculateChecksum(uint16_t *, uint16_t *, uint16_t);
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
(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
/* 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;
#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
}
}
+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)
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);
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;
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;
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;
}
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);
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);