/** * \brief Function to decode IPv4 in IPv6 packets * */ static void DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t plen, PacketQueue *pq) { if (unlikely(plen < IPV6_HEADER_LEN)) { ENGINE_SET_EVENT(p, IPV6_IN_IPV6_PKT_TOO_SMALL); return; } if (IP_GET_RAW_VER(pkt) == 6) { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt, plen, IPPROTO_IPV6); if (tp != NULL) { DecodeTunnel(tv, dtv, tp, pkt, plen, pq, IPPROTO_IPV6); PacketEnqueue(pq,tp); return; } } } else { ENGINE_SET_EVENT(p, IPV6_IN_IPV6_WRONG_IP_VER); } return; }
/** * \brief Function to decode IPv4 in IPv6 packets * */ static void DecodeIPv4inIPv6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t plen, PacketQueue *pq) { if (unlikely(plen < IPV4_HEADER_LEN)) { ENGINE_SET_EVENT(p, IPV4_IN_IPV6_PKT_TOO_SMALL); return; } if (IP_GET_RAW_VER(pkt) == 4) { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt, plen, IPPROTO_IP); if (tp != NULL) { DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, IPPROTO_IP); PacketEnqueue(pq,tp); SCPerfCounterIncr(dtv->counter_ipv4inipv6, tv->sc_perf_pca); return; } } } else { ENGINE_SET_EVENT(p, IPV4_IN_IPV6_WRONG_IP_VER); } return; }
void DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { uint16_t header_len = GRE_HDR_LEN; GRESreHdr *gsre = NULL; SCPerfCounterIncr(dtv->counter_gre, tv->sc_perf_pca); if(len < GRE_HDR_LEN) { ENGINE_SET_EVENT(p,GRE_PKT_TOO_SMALL); return; } p->greh = (GREHdr *)pkt; if(p->greh == NULL) return; SCLogDebug("p %p pkt %p GRE protocol %04x Len: %d GRE version %x", p, pkt, GRE_GET_PROTO(p->greh), len,GRE_GET_VERSION(p->greh)); switch (GRE_GET_VERSION(p->greh)) { case GRE_VERSION_0: /* GRE version 0 doenst support the fields below RFC 1701 */ /** * \todo We need to make sure this does not allow bypassing * inspection. A server may just ignore these and * continue processing the packet, but we will not look * further into it. */ if (GRE_FLAG_ISSET_RECUR(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION0_RECUR); return; } if (GREV1_FLAG_ISSET_FLAGS(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION0_FLAGS); return; } /* Adjust header length based on content */ if (GRE_FLAG_ISSET_KY(p->greh)) header_len += GRE_KEY_LEN; if (GRE_FLAG_ISSET_SQ(p->greh)) header_len += GRE_SEQ_LEN; if (GRE_FLAG_ISSET_CHKSUM(p->greh) || GRE_FLAG_ISSET_ROUTE(p->greh)) header_len += GRE_CHKSUM_LEN + GRE_OFFSET_LEN; if (header_len > len) { ENGINE_SET_EVENT(p,GRE_VERSION0_HDR_TOO_BIG); return; } if (GRE_FLAG_ISSET_ROUTE(p->greh)) { while (1) { if ((header_len + GRE_SRE_HDR_LEN) > len) { ENGINE_SET_EVENT(p, GRE_VERSION0_MALFORMED_SRE_HDR); return; } gsre = (GRESreHdr *)(pkt + header_len); header_len += GRE_SRE_HDR_LEN; if ((ntohs(gsre->af) == 0) && (gsre->sre_length == 0)) break; header_len += gsre->sre_length; if (header_len > len) { ENGINE_SET_EVENT(p, GRE_VERSION0_MALFORMED_SRE_HDR); return; } } } break; case GRE_VERSION_1: /* GRE version 1 doenst support the fields below RFC 1701 */ /** * \todo We need to make sure this does not allow bypassing * inspection. A server may just ignore these and * continue processing the packet, but we will not look * further into it. */ if (GRE_FLAG_ISSET_CHKSUM(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION1_CHKSUM); return; } if (GRE_FLAG_ISSET_ROUTE(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION1_ROUTE); return; } if (GRE_FLAG_ISSET_SSR(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION1_SSR); return; } if (GRE_FLAG_ISSET_RECUR(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION1_RECUR); return; } if (GREV1_FLAG_ISSET_FLAGS(p->greh)) { ENGINE_SET_EVENT(p,GRE_VERSION1_FLAGS); return; } if (GRE_GET_PROTO(p->greh) != GRE_PROTO_PPP) { ENGINE_SET_EVENT(p,GRE_VERSION1_WRONG_PROTOCOL); return; } if (!(GRE_FLAG_ISSET_KY(p->greh))) { ENGINE_SET_EVENT(p,GRE_VERSION1_NO_KEY); return; } header_len += GRE_KEY_LEN; /* Adjust header length based on content */ if (GRE_FLAG_ISSET_SQ(p->greh)) header_len += GRE_SEQ_LEN; if (GREV1_FLAG_ISSET_ACK(p->greh)) header_len += GREV1_ACK_LEN; if (header_len > len) { ENGINE_SET_EVENT(p,GRE_VERSION1_HDR_TOO_BIG); return; } break; default: ENGINE_SET_EVENT(p,GRE_WRONG_VERSION); return; } switch (GRE_GET_PROTO(p->greh)) { case ETHERNET_TYPE_IP: { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt + header_len, len - header_len, IPPROTO_IP); if (tp != NULL) { DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, IPPROTO_IP); PacketEnqueue(pq,tp); } } break; } case GRE_PROTO_PPP: { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt + header_len, len - header_len, PPP_OVER_GRE); if (tp != NULL) { DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, PPP_OVER_GRE); PacketEnqueue(pq,tp); } } break; } case ETHERNET_TYPE_IPV6: { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt + header_len, len - header_len, IPPROTO_IPV6); if (tp != NULL) { DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, IPPROTO_IPV6); PacketEnqueue(pq,tp); } } break; } case ETHERNET_TYPE_VLAN: { if (pq != NULL) { Packet *tp = PacketPseudoPktSetup(p, pkt + header_len, len - header_len, VLAN_OVER_GRE); if (tp != NULL) { DecodeTunnel(tv, dtv, tp, GET_PKT_DATA(tp), GET_PKT_LEN(tp), pq, VLAN_OVER_GRE); PacketEnqueue(pq,tp); } } break; } default: 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; }