/** * \brief See if a ICMP packet belongs to a flow by comparing the embedded * packet in the ICMP error packet to the flow. * * \param f flow * \param p ICMP packet * * \retval 1 match * \retval 0 no match */ static inline int FlowCompareICMPv4(Flow *f, const Packet *p) { if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { /* first check the direction of the flow, in other words, the client -> * server direction as it's most likely the ICMP error will be a * response to the clients traffic */ if ((f->src.addr_data32[0] == IPV4_GET_RAW_IPSRC_U32( ICMPV4_GET_EMB_IPV4(p) )) && (f->dst.addr_data32[0] == IPV4_GET_RAW_IPDST_U32( ICMPV4_GET_EMB_IPV4(p) )) && f->sp == p->icmpv4vars.emb_sport && f->dp == p->icmpv4vars.emb_dport && f->proto == ICMPV4_GET_EMB_PROTO(p) && f->recursion_level == p->recursion_level && f->vlan_id[0] == p->vlan_id[0] && f->vlan_id[1] == p->vlan_id[1]) { return 1; /* check the less likely case where the ICMP error was a response to * a packet from the server. */ } else if ((f->dst.addr_data32[0] == IPV4_GET_RAW_IPSRC_U32( ICMPV4_GET_EMB_IPV4(p) )) && (f->src.addr_data32[0] == IPV4_GET_RAW_IPDST_U32( ICMPV4_GET_EMB_IPV4(p) )) && f->dp == p->icmpv4vars.emb_sport && f->sp == p->icmpv4vars.emb_dport && f->proto == ICMPV4_GET_EMB_PROTO(p) && f->recursion_level == p->recursion_level && f->vlan_id[0] == p->vlan_id[0] && f->vlan_id[1] == p->vlan_id[1]) { return 1; } /* no match, fall through */ } else { /* just treat ICMP as a normal proto for now */ return CMP_FLOW(f, p); } return 0; }
/* calculate the hash key for this packet * * we're using: * hash_rand -- set at init time * source port * destination port * source address * destination address * recursion level -- for tunnels, make sure different tunnel layers can * never get mixed up. * * For ICMP we only consider UNREACHABLE errors atm. */ static inline uint32_t FlowGetKey(const Packet *p) { uint32_t key; if (p->ip4h != NULL) { if (p->tcph != NULL || p->udph != NULL) { FlowHashKey4 fhk; if (p->src.addr_data32[0] > p->dst.addr_data32[0]) { fhk.src = p->src.addr_data32[0]; fhk.dst = p->dst.addr_data32[0]; } else { fhk.src = p->dst.addr_data32[0]; fhk.dst = p->src.addr_data32[0]; } if (p->sp > p->dp) { fhk.sp = p->sp; fhk.dp = p->dp; } else { fhk.sp = p->dp; fhk.dp = p->sp; } fhk.proto = (uint16_t)p->proto; fhk.recur = (uint16_t)p->recursion_level; fhk.vlan_id[0] = p->vlan_id[0]; fhk.vlan_id[1] = p->vlan_id[1]; uint32_t hash = hashword(fhk.u32, 5, flow_config.hash_rand); key = hash % flow_config.hash_size; } else if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { uint32_t psrc = IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p)); uint32_t pdst = IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p)); FlowHashKey4 fhk; if (psrc > pdst) { fhk.src = psrc; fhk.dst = pdst; } else { fhk.src = pdst; fhk.dst = psrc; } if (p->icmpv4vars.emb_sport > p->icmpv4vars.emb_dport) { fhk.sp = p->icmpv4vars.emb_sport; fhk.dp = p->icmpv4vars.emb_dport; } else { fhk.sp = p->icmpv4vars.emb_dport; fhk.dp = p->icmpv4vars.emb_sport; } fhk.proto = (uint16_t)ICMPV4_GET_EMB_PROTO(p); fhk.recur = (uint16_t)p->recursion_level; fhk.vlan_id[0] = p->vlan_id[0]; fhk.vlan_id[1] = p->vlan_id[1]; uint32_t hash = hashword(fhk.u32, 5, flow_config.hash_rand); key = hash % flow_config.hash_size; } else { FlowHashKey4 fhk; if (p->src.addr_data32[0] > p->dst.addr_data32[0]) { fhk.src = p->src.addr_data32[0]; fhk.dst = p->dst.addr_data32[0]; } else { fhk.src = p->dst.addr_data32[0]; fhk.dst = p->src.addr_data32[0]; } fhk.sp = 0xfeed; fhk.dp = 0xbeef; fhk.proto = (uint16_t)p->proto; fhk.recur = (uint16_t)p->recursion_level; fhk.vlan_id[0] = p->vlan_id[0]; fhk.vlan_id[1] = p->vlan_id[1]; uint32_t hash = hashword(fhk.u32, 5, flow_config.hash_rand); key = hash % flow_config.hash_size; } } else if (p->ip6h != NULL) { FlowHashKey6 fhk; if (FlowHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) { fhk.src[0] = p->src.addr_data32[0]; fhk.src[1] = p->src.addr_data32[1]; fhk.src[2] = p->src.addr_data32[2]; fhk.src[3] = p->src.addr_data32[3]; fhk.dst[0] = p->dst.addr_data32[0]; fhk.dst[1] = p->dst.addr_data32[1]; fhk.dst[2] = p->dst.addr_data32[2]; fhk.dst[3] = p->dst.addr_data32[3]; } else { fhk.src[0] = p->dst.addr_data32[0]; fhk.src[1] = p->dst.addr_data32[1]; fhk.src[2] = p->dst.addr_data32[2]; fhk.src[3] = p->dst.addr_data32[3]; fhk.dst[0] = p->src.addr_data32[0]; fhk.dst[1] = p->src.addr_data32[1]; fhk.dst[2] = p->src.addr_data32[2]; fhk.dst[3] = p->src.addr_data32[3]; } if (p->sp > p->dp) { fhk.sp = p->sp; fhk.dp = p->dp; } else { fhk.sp = p->dp; fhk.dp = p->sp; } fhk.proto = (uint16_t)p->proto; fhk.recur = (uint16_t)p->recursion_level; fhk.vlan_id[0] = p->vlan_id[0]; fhk.vlan_id[1] = p->vlan_id[1]; uint32_t hash = hashword(fhk.u32, 11, flow_config.hash_rand); key = hash % flow_config.hash_size; } else key = 0; return key; }
/** DecodeICMPV4 * \brief Main ICMPv4 decoding function */ int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { StatsIncr(tv, dtv->counter_icmpv4); if (len < ICMPV4_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, ICMPV4_PKT_TOO_SMALL); return TM_ECODE_FAILED; } p->icmpv4h = (ICMPV4Hdr *)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->payload = pkt + ICMPV4_HEADER_LEN; p->payload_len = len - ICMPV4_HEADER_LEN; ICMPV4ExtHdr* icmp4eh = (ICMPV4ExtHdr*) p->icmpv4h; switch (p->icmpv4h->type) { case ICMP_ECHOREPLY: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_DEST_UNREACH: if (p->icmpv4h->code > NR_ICMP_UNREACH) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } 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)) { FlowHandlePacket(tv, dtv, p); } } } } break; case ICMP_SOURCE_QUENCH: if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len >= ICMPV4_HEADER_PKT_OFFSET) DecodePartialIPV4( p, (uint8_t*) (pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); } break; case ICMP_REDIRECT: if (p->icmpv4h->code>ICMP_REDIR_HOSTTOS) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len > ICMPV4_HEADER_PKT_OFFSET) DecodePartialIPV4( p, (uint8_t*) (pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); } break; case ICMP_ECHO: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_TIME_EXCEEDED: if (p->icmpv4h->code>ICMP_EXC_FRAGTIME) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len > ICMPV4_HEADER_PKT_OFFSET) DecodePartialIPV4( p, (uint8_t*) (pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); } break; case ICMP_PARAMETERPROB: if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } else { // parse IP header plus 64 bytes if (len > ICMPV4_HEADER_PKT_OFFSET) DecodePartialIPV4( p, (uint8_t*) (pkt + ICMPV4_HEADER_PKT_OFFSET), len - ICMPV4_HEADER_PKT_OFFSET ); } break; case ICMP_TIMESTAMP: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_TIMESTAMPREPLY: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_INFO_REQUEST: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_INFO_REPLY: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_ADDRESS: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; case ICMP_ADDRESSREPLY: p->icmpv4vars.id=icmp4eh->id; p->icmpv4vars.seq=icmp4eh->seq; if (p->icmpv4h->code!=0) { ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } break; default: ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_TYPE); } return TM_ECODE_OK; }