Example #1
0
/**
 * \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;
}
Example #2
0
/**
 * \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;
}
Example #3
0
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;
    }

}
Example #4
0
/**
 * \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;
}