/** * \brief Checks if the packet sent as the argument, has a valid or invalid * icmpv6 checksum, based on whether icmpv6-csum option for this rule * has been supplied with "valid" or "invalid" argument * * \param t Pointer to the tv for this detection module instance * \param det_ctx Pointer to the detection engine thread context * \param p Pointer to the Packet currently being matched * \param s Pointer to the Signature, the packet is being currently * matched with * \param m Pointer to the keyword_structure(SigMatch) from the above * Signature, the Packet is being currently matched with * * \retval 1 if the Packet contents match the keyword option; 0 otherwise */ static int DetectICMPV6CsumMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { const DetectCsumData *cd = (const DetectCsumData *)ctx; if (p->ip6h == NULL || p->icmpv6h == NULL || p->proto != IPPROTO_ICMPV6 || PKT_IS_PSEUDOPKT(p) || (GET_PKT_LEN(p) - ((uint8_t *)p->icmpv6h - GET_PKT_DATA(p))) <= 0) { return 0; } if (p->flags & PKT_IGNORE_CHECKSUM) { return cd->valid; } if (p->level4_comp_csum == -1) { uint16_t len = IPV6_GET_RAW_PLEN(p->ip6h) - ((uint8_t *)p->icmpv6h - (uint8_t *)p->ip6h - IPV6_HEADER_LEN); p->level4_comp_csum = ICMPV6CalculateChecksum(p->ip6h->s_ip6_addrs, (uint16_t *)p->icmpv6h, len); } if (p->level4_comp_csum == p->icmpv6h->csum && cd->valid == 1) return 1; else if (p->level4_comp_csum != p->icmpv6h->csum && cd->valid == 0) return 1; else return 0; }
/** * \brief Get variables and do some checks of the embedded IPV6 packet * * \param p Pointer to the packet we are filling * \param partial_packet Pointer to the raw packet buffer * \param len the len of the rest of the packet not processed yet * * \retval void No return value */ void DecodePartialIPV6(Packet *p, uint8_t *partial_packet, uint16_t len ) { /** Check the sizes, the header must fit at least */ if (len < IPV6_HEADER_LEN) { SCLogDebug("ICMPV6_IPV6_TRUNC_PKT"); ENGINE_SET_EVENT(p, ICMPV6_IPV6_TRUNC_PKT); return; } IPV6Hdr *icmp6_ip6h = (IPV6Hdr*)partial_packet; /** Check the embedded version */ if(((icmp6_ip6h->s_ip6_vfc & 0xf0) >> 4) != 6) { SCLogDebug("ICMPv6 contains Unknown IPV6 version " "ICMPV6_IPV6_UNKNOWN_VER"); ENGINE_SET_EVENT(p, ICMPV6_IPV6_UNKNOWN_VER); return; } /** We need to fill icmpv6vars */ p->icmpv6vars.emb_ipv6h = icmp6_ip6h; /** Get the IP6 address */ p->icmpv6vars.emb_ip6_src[0] = icmp6_ip6h->s_ip6_src[0]; p->icmpv6vars.emb_ip6_src[1] = icmp6_ip6h->s_ip6_src[1]; p->icmpv6vars.emb_ip6_src[2] = icmp6_ip6h->s_ip6_src[2]; p->icmpv6vars.emb_ip6_src[3] = icmp6_ip6h->s_ip6_src[3]; p->icmpv6vars.emb_ip6_dst[0] = icmp6_ip6h->s_ip6_dst[0]; p->icmpv6vars.emb_ip6_dst[1] = icmp6_ip6h->s_ip6_dst[1]; p->icmpv6vars.emb_ip6_dst[2] = icmp6_ip6h->s_ip6_dst[2]; p->icmpv6vars.emb_ip6_dst[3] = icmp6_ip6h->s_ip6_dst[3]; /** Get protocol and ports inside the embedded ipv6 packet and set the pointers */ p->icmpv6vars.emb_ip6_proto_next = icmp6_ip6h->s_ip6_nxt; switch (icmp6_ip6h->s_ip6_nxt) { case IPPROTO_TCP: if (len >= IPV6_HEADER_LEN + TCP_HEADER_LEN ) { p->icmpv6vars.emb_tcph = (TCPHdr*)(partial_packet + IPV6_HEADER_LEN); p->icmpv6vars.emb_sport = p->icmpv6vars.emb_tcph->th_sport; p->icmpv6vars.emb_dport = p->icmpv6vars.emb_tcph->th_dport; SCLogDebug("ICMPV6->IPV6->TCP header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv6vars.emb_sport, p->icmpv6vars.emb_dport); } else { SCLogDebug("Warning, ICMPV6->IPV6->TCP " "header Didn't fit in the packet!"); p->icmpv6vars.emb_sport = 0; p->icmpv6vars.emb_dport = 0; } break; case IPPROTO_UDP: if (len >= IPV6_HEADER_LEN + UDP_HEADER_LEN ) { p->icmpv6vars.emb_udph = (UDPHdr*)(partial_packet + IPV6_HEADER_LEN); p->icmpv6vars.emb_sport = p->icmpv6vars.emb_udph->uh_sport; p->icmpv6vars.emb_dport = p->icmpv6vars.emb_udph->uh_dport; SCLogDebug("ICMPV6->IPV6->UDP header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv6vars.emb_sport, p->icmpv6vars.emb_dport); } else { SCLogDebug("Warning, ICMPV6->IPV6->UDP " "header Didn't fit in the packet!"); p->icmpv6vars.emb_sport = 0; p->icmpv6vars.emb_dport = 0; } break; case IPPROTO_ICMPV6: p->icmpv6vars.emb_icmpv6h = (ICMPV6Hdr*)(partial_packet + IPV6_HEADER_LEN); p->icmpv6vars.emb_sport = 0; p->icmpv6vars.emb_dport = 0; SCLogDebug("ICMPV6->IPV6->ICMP header"); break; } /* debug print */ #ifdef DEBUG char s[46], d[46]; PrintInet(AF_INET6, (const void *)p->icmpv6vars.emb_ip6_src, s, sizeof(s)); PrintInet(AF_INET6, (const void *)p->icmpv6vars.emb_ip6_dst, d, sizeof(d)); SCLogDebug("ICMPv6 embedding IPV6 %s->%s - CLASS: %" PRIu32 " FLOW: " "%" PRIu32 " NH: %" PRIu32 " PLEN: %" PRIu32 " HLIM: %" PRIu32, s, d, IPV6_GET_RAW_CLASS(icmp6_ip6h), IPV6_GET_RAW_FLOW(icmp6_ip6h), IPV6_GET_RAW_NH(icmp6_ip6h), IPV6_GET_RAW_PLEN(icmp6_ip6h), IPV6_GET_RAW_HLIM(icmp6_ip6h)); #endif return; }
/** * \brief Function to decode Teredo packets * * \retval 0 if packet is not a Teredo packet, 1 if it is */ int DecodeTeredo(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { uint8_t *start = pkt; /* Is this packet to short to contain an IPv6 packet ? */ if (len < IPV6_HEADER_LEN) return 0; /* Teredo encapsulate IPv6 in UDP and can add some custom message * part before the IPv6 packet. In our case, we just want to get * over an ORIGIN indication. So we just make one offset if needed. */ if (start[0] == 0x0) { switch (start[1]) { /* origin indication: compatible with tunnel */ case 0x0: /* offset is coherent with len and presence of an IPv6 header */ if (len >= TEREDO_ORIG_INDICATION_LENGTH + IPV6_HEADER_LEN) start += TEREDO_ORIG_INDICATION_LENGTH; else return 0; break; /* authentication: negotiation not real tunnel */ case 0x1: return 0; /* this case is not possible in Teredo: not that protocol */ default: return 0; } } /* There is no specific field that we can check to prove that the packet * is a Teredo packet. We've zapped here all the possible Teredo header * and we should have an IPv6 packet at the start pointer. * We then can only do two checks before sending the encapsulated packets * to decoding: * - The packet has a protocol version which is IPv6. * - The IPv6 length of the packet matches what remains in buffer. */ if (IP_GET_RAW_VER(start) == 6) { IPV6Hdr *thdr = (IPV6Hdr *)start; if (len == IPV6_HEADER_LEN + IPV6_GET_RAW_PLEN(thdr) + (start - pkt)) { if (pq != NULL) { int blen = len - (start - pkt); /* spawn off tunnel packet */ Packet *tp = PacketPseudoPktSetup(p, start, blen, IPPROTO_IPV6); if (tp != NULL) { PKT_SET_SRC(tp, PKT_SRC_DECODER_TEREDO); /* send that to the Tunnel decoder */ DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, IPPROTO_IPV6); /* add the tp to the packet queue. */ PacketEnqueue(pq,tp); SCPerfCounterIncr(dtv->counter_teredo, tv->sc_perf_pca); return 1; } } } return 0; } return 0; }