/** * \brief Compares 2 addresses(address ranges) and returns the relationship * between the 2 addresses. * * \param a Pointer to the first address instance to be compared. * \param b Pointer to the second address instance to be compared. * * \retval ADDRESS_EQ If the 2 address ranges a and b, are equal. * \retval ADDRESS_ES b encapsulates a. b_ip1[...a_ip1...a_ip2...]b_ip2. * \retval ADDRESS_EB a encapsulates b. a_ip1[...b_ip1....b_ip2...]a_ip2. * \retval ADDRESS_LE a_ip1(...b_ip1==a_ip2...)b_ip2 * \retval ADDRESS_LT a_ip1(...b_ip1...a_ip2...)b_ip2 * \retval ADDRESS_GE b_ip1(...a_ip1==b_ip2...)a_ip2 * \retval ADDRESS_GT a_ip1 > b_ip2, i.e. the address range for 'a' starts only * after the end of the address range for 'b' */ int DetectAddressCmpIPv4(DetectAddress *a, DetectAddress *b) { uint32_t a_ip1 = SCNtohl(a->ip.addr_data32[0]); uint32_t a_ip2 = SCNtohl(a->ip2.addr_data32[0]); uint32_t b_ip1 = SCNtohl(b->ip.addr_data32[0]); uint32_t b_ip2 = SCNtohl(b->ip2.addr_data32[0]); if (a_ip1 == b_ip1 && a_ip2 == b_ip2) { SCLogDebug("ADDRESS_EQ"); return ADDRESS_EQ; } else if (a_ip1 >= b_ip1 && a_ip1 <= b_ip2 && a_ip2 <= b_ip2) { SCLogDebug("ADDRESS_ES"); return ADDRESS_ES; } else if (a_ip1 <= b_ip1 && a_ip2 >= b_ip2) { SCLogDebug("ADDRESS_EB"); return ADDRESS_EB; } else if (a_ip1 < b_ip1 && a_ip2 < b_ip2 && a_ip2 >= b_ip1) { SCLogDebug("ADDRESS_LE"); return ADDRESS_LE; } else if (a_ip1 < b_ip1 && a_ip2 < b_ip2) { SCLogDebug("ADDRESS_LT"); return ADDRESS_LT; } else if (a_ip1 > b_ip1 && a_ip1 <= b_ip2 && a_ip2 > b_ip2) { SCLogDebug("ADDRESS_GE"); return ADDRESS_GE; } else if (a_ip1 > b_ip2) { SCLogDebug("ADDRESS_GT"); return ADDRESS_GT; } else { /* should be unreachable */ SCLogDebug("Internal Error: should be unreachable"); } return ADDRESS_ER; }
/** * \brief Check if the address group list covers the complete IPv4 IP space. * * \param ag Pointer to a DetectAddress list head, which has to be checked to * see if the address ranges in it, cover the entire IPv4 IP space. * * \retval 1 Yes, it covers the entire IPv4 address range. * \retval 0 No, it doesn't cover the entire IPv4 address range. */ int DetectAddressIsCompleteIPSpaceIPv4(DetectAddress *ag) { uint32_t next_ip = 0; if (ag == NULL) return 0; /* if we don't start with 0.0.0.0 we know we're good */ if (SCNtohl(ag->ip.addr_data32[0]) != 0x00000000) return 0; /* if we're ending with 255.255.255.255 while we know we started with * 0.0.0.0 it's the complete space */ if (SCNtohl(ag->ip2.addr_data32[0]) == 0xFFFFFFFF) return 1; next_ip = htonl(SCNtohl(ag->ip2.addr_data32[0]) + 1); ag = ag->next; for ( ; ag != NULL; ag = ag->next) { if (ag->ip.addr_data32[0] != next_ip) return 0; if (SCNtohl(ag->ip2.addr_data32[0]) == 0xFFFFFFFF) return 1; next_ip = htonl(SCNtohl(ag->ip2.addr_data32[0]) + 1); } return 0; }
/** * \brief Extends a target address range if the the source address range is * wider than the target address range on either sides. * * Every address is a range, i.e. address->ip1....address->ip2. For * example 1.2.3.4 to 192.168.1.1. * if source->ip1 is smaller than target->ip1, it indicates that the * source's left address limit is greater(range wise) than the target's * left address limit, and hence we reassign the target's left address * limit to source's left address limit. * Similary if source->ip2 is greater than target->ip2, it indicates that * the source's right address limit is greater(range wise) than the * target's right address limit, and hence we reassign the target's right * address limit to source's right address limit. * * \param de_ctx Pointer to the detection engine context. * \param target Pointer to the target DetectAddress instance that has to be * updated. * \param source Pointer to the source DetectAddress instance that is used * to decided whether we extend the target's address range. * * \retval 0 On success. * \retval -1 On failure. */ int DetectAddressJoinIPv4(DetectEngineCtx *de_ctx, DetectAddress *target, DetectAddress *source) { if (source == NULL || target == NULL) return -1; if (SCNtohl(source->ip.addr_data32[0]) < SCNtohl(target->ip.addr_data32[0])) target->ip.addr_data32[0] = source->ip.addr_data32[0]; if (SCNtohl(source->ip2.addr_data32[0]) > SCNtohl(target->ip2.addr_data32[0])) target->ip2.addr_data32[0] = source->ip2.addr_data32[0]; return 0; }
/** * \brief Cuts and returns an address range, which is the complement of the * address range that is supplied as the argument. * * For example: * * If a = 0.0.0.0-1.2.3.4, * then a = 1.2.3.4-255.255.255.255 and b = NULL * If a = 1.2.3.4-255.255.255.255, * then a = 0.0.0.0-1.2.3.4 and b = NULL * If a = 1.2.3.4-192.168.1.1, * then a = 0.0.0.0-1.2.3.3 and b = 192.168.1.2-255.255.255.255 * * \param a Pointer to an address range (DetectAddress) instance whose complement * has to be returned in a and b. * \param b Pointer to DetectAddress pointer, that will be supplied back with a * new DetectAddress instance, if the complement demands so. * * \retval 0 On success. * \retval -1 On failure. */ int DetectAddressCutNotIPv4(DetectAddress *a, DetectAddress **b) { uint32_t a_ip1 = SCNtohl(a->ip.addr_data32[0]); uint32_t a_ip2 = SCNtohl(a->ip2.addr_data32[0]); DetectAddress *tmp_b = NULL; /* default to NULL */ *b = NULL; if (a_ip1 != 0x00000000 && a_ip2 != 0xFFFFFFFF) { a->ip.addr_data32[0] = htonl(0x00000000); a->ip2.addr_data32[0] = htonl(a_ip1 - 1); tmp_b = DetectAddressInit(); if (tmp_b == NULL) goto error; tmp_b->ip.family = AF_INET; tmp_b->ip.addr_data32[0] = htonl(a_ip2 + 1); tmp_b->ip2.addr_data32[0] = htonl(0xFFFFFFFF); *b = tmp_b; } else if (a_ip1 == 0x00000000 && a_ip2 != 0xFFFFFFFF) { a->ip.addr_data32[0] = htonl(a_ip2 + 1); a->ip2.addr_data32[0] = htonl(0xFFFFFFFF); } else if (a_ip1 != 0x00000000 && a_ip2 == 0xFFFFFFFF) { a->ip.addr_data32[0] = htonl(0x00000000); a->ip2.addr_data32[0] = htonl(a_ip1 - 1); } else { goto error; } return 0; error: return -1; }
static inline #endif void DecodeIPV6FragHeader(Packet *p, uint8_t *pkt, uint16_t hdrextlen, uint16_t plen, uint16_t prev_hdrextlen) { uint16_t frag_offset = (*(pkt + 2) << 8 | *(pkt + 3)) & 0xFFF8; int frag_morefrags = (*(pkt + 2) << 8 | *(pkt + 3)) & 0x0001; p->ip6eh.fh_offset = frag_offset; p->ip6eh.fh_more_frags_set = frag_morefrags ? TRUE : FALSE; p->ip6eh.fh_nh = *pkt; uint32_t fh_id; memcpy(&fh_id, pkt+4, 4); p->ip6eh.fh_id = SCNtohl(fh_id); SCLogDebug("IPV6 FH: offset %u, mf %s, nh %u, id %u/%x", p->ip6eh.fh_offset, p->ip6eh.fh_more_frags_set ? "true" : "false", p->ip6eh.fh_nh, p->ip6eh.fh_id, p->ip6eh.fh_id); // store header offset, data offset uint16_t frag_hdr_offset = (uint16_t)(pkt - GET_PKT_DATA(p)); uint16_t data_offset = (uint16_t)(frag_hdr_offset + hdrextlen); uint16_t data_len = plen - hdrextlen; p->ip6eh.fh_header_offset = frag_hdr_offset; p->ip6eh.fh_data_offset = data_offset; p->ip6eh.fh_data_len = data_len; /* if we have a prev hdr, store the type and offset of it */ if (prev_hdrextlen) { p->ip6eh.fh_prev_hdr_offset = frag_hdr_offset - prev_hdrextlen; } SCLogDebug("IPV6 FH: frag_hdr_offset %u, data_offset %u, data_len %u", p->ip6eh.fh_header_offset, p->ip6eh.fh_data_offset, p->ip6eh.fh_data_len); }
/** * \brief Cut groups and merge sigs * * a = 1.2.3.4, b = 1.2.3.4-1.2.3.5 * must result in: a == 1.2.3.4, b == 1.2.3.5, c == NULL * * a = 1.2.3.4, b = 1.2.3.3-1.2.3.5 * must result in: a == 1.2.3.3, b == 1.2.3.4, c == 1.2.3.5 * * a = 1.2.3.0/24 b = 1.2.3.128-1.2.4.10 * must result in: a == 1.2.3.0/24, b == 1.2.4.0-1.2.4.10, c == NULL * * a = 1.2.3.4, b = 1.2.3.0/24 * must result in: a == 1.2.3.0-1.2.3.3, b == 1.2.3.4, c == 1.2.3.5-1.2.3.255 * * \retval 0 On success. * \retval -1 On failure. */ int DetectAddressCutIPv4(DetectEngineCtx *de_ctx, DetectAddress *a, DetectAddress *b, DetectAddress **c) { uint32_t a_ip1 = SCNtohl(a->ip.addr_data32[0]); uint32_t a_ip2 = SCNtohl(a->ip2.addr_data32[0]); uint32_t b_ip1 = SCNtohl(b->ip.addr_data32[0]); uint32_t b_ip2 = SCNtohl(b->ip2.addr_data32[0]); DetectAddress *tmp = NULL; DetectAddress *tmp_c = NULL; int r = 0; /* default to NULL */ *c = NULL; r = DetectAddressCmpIPv4(a, b); if (r != ADDRESS_ES && r != ADDRESS_EB && r != ADDRESS_LE && r != ADDRESS_GE) { SCLogDebug("we shouldn't be here"); goto error; } /* get a place to temporary put sigs lists */ tmp = DetectAddressInit(); if (tmp == NULL) goto error; /* we have 3 parts: [aaa[abab)bbb] * part a: a_ip1 <-> b_ip1 - 1 * part b: b_ip1 <-> a_ip2 * part c: a_ip2 + 1 <-> b_ip2 */ if (r == ADDRESS_LE) { SCLogDebug("DetectAddressCutIPv4: r == ADDRESS_LE"); a->ip.addr_data32[0] = htonl(a_ip1); a->ip2.addr_data32[0] = htonl(b_ip1 - 1); b->ip.addr_data32[0] = htonl(b_ip1); b->ip2.addr_data32[0] = htonl(a_ip2); tmp_c = DetectAddressInit(); if (tmp_c == NULL) goto error; tmp_c->ip.family = AF_INET; tmp_c->ip.addr_data32[0] = htonl(a_ip2 + 1); tmp_c->ip2.addr_data32[0] = htonl(b_ip2); *c = tmp_c; /* we have 3 parts: [bbb[baba]aaa] * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> b_ip2 * part c: b_ip2 + 1 <-> a_ip2 */ } else if (r == ADDRESS_GE) { SCLogDebug("DetectAddressCutIPv4: r == ADDRESS_GE"); a->ip.addr_data32[0] = htonl(b_ip1); a->ip2.addr_data32[0] = htonl(a_ip1 - 1); b->ip.addr_data32[0] = htonl(a_ip1); b->ip2.addr_data32[0] = htonl(b_ip2); tmp_c = DetectAddressInit(); if (tmp_c == NULL) goto error; tmp_c->ip.family = AF_INET; tmp_c->ip.addr_data32[0] = htonl(b_ip2 + 1); tmp_c->ip2.addr_data32[0] = htonl(a_ip2); *c = tmp_c; /* we have 2 or three parts: * * 2 part: [[abab]bbb] or [bbb[baba]] * part a: a_ip1 <-> a_ip2 * part b: a_ip2 + 1 <-> b_ip2 * * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> a_ip2 * * 3 part [bbb[aaa]bbb] * becomes[aaa[bbb]ccc] * * part a: b_ip1 <-> a_ip1 - 1 * part b: a_ip1 <-> a_ip2 * part c: a_ip2 + 1 <-> b_ip2 */ } else if (r == ADDRESS_ES) { SCLogDebug("DetectAddressCutIPv4: r == ADDRESS_ES"); if (a_ip1 == b_ip1) { SCLogDebug("DetectAddressCutIPv4: 1"); a->ip.addr_data32[0] = htonl(a_ip1); a->ip2.addr_data32[0] = htonl(a_ip2); b->ip.addr_data32[0] = htonl(a_ip2 + 1); b->ip2.addr_data32[0] = htonl(b_ip2); } else if (a_ip2 == b_ip2) { SCLogDebug("DetectAddressCutIPv4: 2"); a->ip.addr_data32[0] = htonl(b_ip1); a->ip2.addr_data32[0] = htonl(a_ip1 - 1); b->ip.addr_data32[0] = htonl(a_ip1); b->ip2.addr_data32[0] = htonl(a_ip2); } else { SCLogDebug("3"); a->ip.addr_data32[0] = htonl(b_ip1); a->ip2.addr_data32[0] = htonl(a_ip1 - 1); b->ip.addr_data32[0] = htonl(a_ip1); b->ip2.addr_data32[0] = htonl(a_ip2); tmp_c = DetectAddressInit(); if (tmp_c == NULL) goto error; tmp_c->ip.family = AF_INET; tmp_c->ip.addr_data32[0] = htonl(a_ip2 + 1); tmp_c->ip2.addr_data32[0] = htonl(b_ip2); *c = tmp_c; } /* we have 2 or three parts: * * 2 part: [[baba]aaa] or [aaa[abab]] * part a: b_ip1 <-> b_ip2 * part b: b_ip2 + 1 <-> a_ip2 * * part a: a_ip1 <-> b_ip1 - 1 * part b: b_ip1 <-> b_ip2 * * 3 part [aaa[bbb]aaa] * becomes[aaa[bbb]ccc] * * part a: a_ip1 <-> b_ip2 - 1 * part b: b_ip1 <-> b_ip2 * part c: b_ip2 + 1 <-> a_ip2 */ } else if (r == ADDRESS_EB) { SCLogDebug("DetectAddressCutIPv4: r == ADDRESS_EB"); if (a_ip1 == b_ip1) { SCLogDebug("DetectAddressCutIPv4: 1"); a->ip.addr_data32[0] = htonl(b_ip1); a->ip2.addr_data32[0] = htonl(b_ip2); b->ip.addr_data32[0] = htonl(b_ip2 + 1); b->ip2.addr_data32[0] = htonl(a_ip2); } else if (a_ip2 == b_ip2) { SCLogDebug("DetectAddressCutIPv4: 2"); a->ip.addr_data32[0] = htonl(a_ip1); a->ip2.addr_data32[0] = htonl(b_ip1 - 1); b->ip.addr_data32[0] = htonl(b_ip1); b->ip2.addr_data32[0] = htonl(b_ip2); } else { SCLogDebug("DetectAddressCutIPv4: 3"); a->ip.addr_data32[0] = htonl(a_ip1); a->ip2.addr_data32[0] = htonl(b_ip1 - 1); b->ip.addr_data32[0] = htonl(b_ip1); b->ip2.addr_data32[0] = htonl(b_ip2); tmp_c = DetectAddressInit(); if (tmp_c == NULL) goto error; tmp_c->ip.family = AF_INET; tmp_c->ip.addr_data32[0] = htonl(b_ip2 + 1); tmp_c->ip2.addr_data32[0] = htonl(a_ip2); *c = tmp_c; } } if (tmp != NULL) DetectAddressFree(tmp); return 0; error: if (tmp != NULL) DetectAddressFree(tmp); return -1; }
/** * \brief Read data from nfq message and setup Packet * * \note * In case of error, this function verdict the packet * to avoid skb to get stuck in kernel. */ static int NFQSetupPkt (Packet *p, struct nfq_q_handle *qh, void *data) { struct nfq_data *tb = (struct nfq_data *)data; int ret; char *pktdata; struct nfqnl_msg_packet_hdr *ph; ph = nfq_get_msg_packet_hdr(tb); if (ph != NULL) { p->nfq_v.id = SCNtohl(ph->packet_id); //p->nfq_v.hw_protocol = SCNtohs(p->nfq_v.ph->hw_protocol); p->nfq_v.hw_protocol = ph->hw_protocol; } /* coverity[missing_lock] */ p->nfq_v.mark = nfq_get_nfmark(tb); if (nfq_config.mode == NFQ_REPEAT_MODE) { if ((nfq_config.mark & nfq_config.mask) == (p->nfq_v.mark & nfq_config.mask)) { int iter = 0; if (already_seen_warning < MAX_ALREADY_TREATED) SCLogInfo("Packet seems already treated by suricata"); already_seen_warning++; do { ret = nfq_set_verdict(qh, p->nfq_v.id, NF_ACCEPT, 0, NULL); } while ((ret < 0) && (iter++ < NFQ_VERDICT_RETRY_TIME)); if (ret < 0) { SCLogWarning(SC_ERR_NFQ_SET_VERDICT, "nfq_set_verdict of %p failed %" PRId32 ": %s", p, ret, strerror(errno)); } return -1 ; } } p->nfq_v.ifi = nfq_get_indev(tb); p->nfq_v.ifo = nfq_get_outdev(tb); p->nfq_v.verdicted = 0; #ifdef NFQ_GET_PAYLOAD_SIGNED ret = nfq_get_payload(tb, &pktdata); #else ret = nfq_get_payload(tb, (unsigned char **) &pktdata); #endif /* NFQ_GET_PAYLOAD_SIGNED */ if (ret > 0) { /* nfq_get_payload returns a pointer to a part of memory * that is not preserved over the lifetime of our packet. * So we need to copy it. */ if (ret > 65536) { /* Will not be able to copy data ! Set length to 0 * to trigger an error in packet decoding. * This is unlikely to happen */ SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "NFQ sent too big packet"); SET_PKT_LEN(p, 0); } else if (runmode_workers) { PacketSetData(p, (uint8_t *)pktdata, ret); } else { PacketCopyData(p, (uint8_t *)pktdata, ret); } } else if (ret == -1) { /* unable to get pointer to data, ensure packet length is zero. * This will trigger an error in packet decoding */ SET_PKT_LEN(p, 0); } ret = nfq_get_timestamp(tb, &p->ts); if (ret != 0 || p->ts.tv_sec == 0) { memset (&p->ts, 0, sizeof(struct timeval)); gettimeofday(&p->ts, NULL); } p->datalink = DLT_RAW; return 0; }
static void DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { SCEnter(); uint8_t *orig_pkt = pkt; uint8_t nh = 0; /* careful, 0 is actually a real type */ uint16_t hdrextlen = 0; uint16_t plen; char dstopts = 0; char exthdr_fh_done = 0; int hh = 0; int rh = 0; int eh = 0; int ah = 0; nh = IPV6_GET_NH(p); plen = len; while(1) { /* No upper layer, but we do have data. Suspicious. */ if (nh == IPPROTO_NONE && plen > 0) { ENGINE_SET_EVENT(p, IPV6_DATA_AFTER_NONE_HEADER); SCReturn; } if (plen < 2) { /* minimal needed in a hdr */ SCReturn; } switch(nh) { case IPPROTO_TCP: IPV6_SET_L4PROTO(p,nh); DecodeTCP(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_UDP: IPV6_SET_L4PROTO(p,nh); DecodeUDP(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_ICMPV6: IPV6_SET_L4PROTO(p,nh); DecodeICMPV6(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_SCTP: IPV6_SET_L4PROTO(p,nh); DecodeSCTP(tv, dtv, p, pkt, plen, pq); SCReturn; case IPPROTO_ROUTING: IPV6_SET_L4PROTO(p,nh); hdrextlen = 8 + (*(pkt+1) * 8); /* 8 bytes + length in 8 octet units */ SCLogDebug("hdrextlen %"PRIu8, hdrextlen); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } if (rh) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_RH); /* skip past this extension so we can continue parsing the rest * of the packet */ nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } rh = 1; IPV6_EXTHDR_SET_RH(p); uint8_t ip6rh_type = *(pkt + 2); if (ip6rh_type == 0) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_RH_TYPE_0); } p->ip6eh.rh_type = ip6rh_type; nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; case IPPROTO_HOPOPTS: case IPPROTO_DSTOPTS: { IPV6OptHAO hao_s, *hao = &hao_s; IPV6OptRA ra_s, *ra = &ra_s; IPV6OptJumbo jumbo_s, *jumbo = &jumbo_s; uint16_t optslen = 0; IPV6_SET_L4PROTO(p,nh); hdrextlen = (*(pkt+1) + 1) << 3; if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } uint8_t *ptr = pkt + 2; /* +2 to go past nxthdr and len */ /* point the pointers to right structures * in Packet. */ if (nh == IPPROTO_HOPOPTS) { if (hh) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_HH); /* skip past this extension so we can continue parsing the rest * of the packet */ nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } hh = 1; optslen = ((*(pkt + 1) + 1 ) << 3) - 2; } else if (nh == IPPROTO_DSTOPTS) { if (dstopts == 0) { optslen = ((*(pkt + 1) + 1 ) << 3) - 2; dstopts = 1; } else if (dstopts == 1) { optslen = ((*(pkt + 1) + 1 ) << 3) - 2; dstopts = 2; } else { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_DH); /* skip past this extension so we can continue parsing the rest * of the packet */ nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } } if (optslen > plen) { /* since the packet is long enough (we checked * plen against hdrlen, the optlen must be malformed. */ ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); /* skip past this extension so we can continue parsing the rest * of the packet */ nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } /** \todo move into own function to loaded on demand */ uint16_t padn_cnt = 0; uint16_t other_cnt = 0; uint16_t offset = 0; while(offset < optslen) { if (*ptr == IPV6OPT_PAD1) { padn_cnt++; offset++; ptr++; continue; } if (offset + 1 >= optslen) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); break; } /* length field for each opt */ uint8_t ip6_optlen = *(ptr + 1); /* see if the optlen from the packet fits the total optslen */ if ((offset + 1 + ip6_optlen) > optslen) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); break; } if (*ptr == IPV6OPT_PADN) /* PadN */ { //printf("PadN option\n"); padn_cnt++; /* a zero padN len would be weird */ if (ip6_optlen == 0) ENGINE_SET_EVENT(p, IPV6_EXTHDR_ZERO_LEN_PADN); } else if (*ptr == IPV6OPT_RA) /* RA */ { ra->ip6ra_type = *(ptr); ra->ip6ra_len = ip6_optlen; if (ip6_optlen < sizeof(ra->ip6ra_value)) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); break; } memcpy(&ra->ip6ra_value, (ptr + 2), sizeof(ra->ip6ra_value)); ra->ip6ra_value = SCNtohs(ra->ip6ra_value); //printf("RA option: type %" PRIu32 " len %" PRIu32 " value %" PRIu32 "\n", // ra->ip6ra_type, ra->ip6ra_len, ra->ip6ra_value); other_cnt++; } else if (*ptr == IPV6OPT_JUMBO) /* Jumbo */ { jumbo->ip6j_type = *(ptr); jumbo->ip6j_len = ip6_optlen; if (ip6_optlen < sizeof(jumbo->ip6j_payload_len)) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); break; } memcpy(&jumbo->ip6j_payload_len, (ptr+2), sizeof(jumbo->ip6j_payload_len)); jumbo->ip6j_payload_len = SCNtohl(jumbo->ip6j_payload_len); //printf("Jumbo option: type %" PRIu32 " len %" PRIu32 " payload len %" PRIu32 "\n", // jumbo->ip6j_type, jumbo->ip6j_len, jumbo->ip6j_payload_len); } else if (*ptr == IPV6OPT_HAO) /* HAO */ { hao->ip6hao_type = *(ptr); hao->ip6hao_len = ip6_optlen; if (ip6_optlen < sizeof(hao->ip6hao_hoa)) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN); break; } memcpy(&hao->ip6hao_hoa, (ptr+2), sizeof(hao->ip6hao_hoa)); //printf("HAO option: type %" PRIu32 " len %" PRIu32 " ", // hao->ip6hao_type, hao->ip6hao_len); //char addr_buf[46]; //PrintInet(AF_INET6, (char *)&(hao->ip6hao_hoa), // addr_buf,sizeof(addr_buf)); //printf("home addr %s\n", addr_buf); other_cnt++; } else { if (nh == IPPROTO_HOPOPTS) ENGINE_SET_EVENT(p, IPV6_HOPOPTS_UNKNOWN_OPT); else ENGINE_SET_EVENT(p, IPV6_DSTOPTS_UNKNOWN_OPT); other_cnt++; } uint16_t optlen = (*(ptr + 1) + 2); ptr += optlen; /* +2 for opt type and opt len fields */ offset += optlen; } /* flag packets that have only padding */ if (padn_cnt > 0 && other_cnt == 0) { if (nh == IPPROTO_HOPOPTS) ENGINE_SET_EVENT(p, IPV6_HOPOPTS_ONLY_PADDING); else ENGINE_SET_EVENT(p, IPV6_DSTOPTS_ONLY_PADDING); } nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } case IPPROTO_FRAGMENT: { IPV6_SET_L4PROTO(p,nh); /* store the offset of this extension into the packet * past the ipv6 header. We use it in defrag for creating * a defragmented packet without the frag header */ if (exthdr_fh_done == 0) { p->ip6eh.fh_offset = pkt - orig_pkt; exthdr_fh_done = 1; } uint16_t prev_hdrextlen = hdrextlen; hdrextlen = sizeof(IPV6FragHdr); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } /* for the frag header, the length field is reserved */ if (*(pkt + 1) != 0) { ENGINE_SET_EVENT(p, IPV6_FH_NON_ZERO_RES_FIELD); /* non fatal, lets try to continue */ } if (IPV6_EXTHDR_ISSET_FH(p)) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_FH); nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } /* set the header flag first */ IPV6_EXTHDR_SET_FH(p); /* parse the header and setup the vars */ DecodeIPV6FragHeader(p, pkt, hdrextlen, plen, prev_hdrextlen); /* if FH has offset 0 and no more fragments are coming, we * parse this packet further right away, no defrag will be * needed. It is a useless FH then though, so we do set an * decoder event. */ if (p->ip6eh.fh_more_frags_set == 0 && p->ip6eh.fh_offset == 0) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_USELESS_FH); nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } /* the rest is parsed upon reassembly */ p->flags |= PKT_IS_FRAGMENT; SCReturn; } case IPPROTO_ESP: { IPV6_SET_L4PROTO(p,nh); hdrextlen = sizeof(IPV6EspHdr); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } if (eh) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_EH); SCReturn; } eh = 1; nh = IPPROTO_NONE; pkt += hdrextlen; plen -= hdrextlen; break; } case IPPROTO_AH: { IPV6_SET_L4PROTO(p,nh); /* we need the header as a minimum */ hdrextlen = sizeof(IPV6AuthHdr); /* the payload len field is the number of extra 4 byte fields, * IPV6AuthHdr already contains the first */ if (*(pkt+1) > 0) hdrextlen += ((*(pkt+1) - 1) * 4); SCLogDebug("hdrextlen %"PRIu8, hdrextlen); if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } IPV6AuthHdr *ahhdr = (IPV6AuthHdr *)pkt; if (ahhdr->ip6ah_reserved != 0x0000) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_AH_RES_NOT_NULL); } if (ah) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_AH); nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } ah = 1; nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; } case IPPROTO_IPIP: IPV6_SET_L4PROTO(p,nh); DecodeIPv4inIPv6(tv, dtv, p, pkt, plen, pq); SCReturn; /* none, last header */ case IPPROTO_NONE: IPV6_SET_L4PROTO(p,nh); SCReturn; case IPPROTO_ICMP: ENGINE_SET_EVENT(p,IPV6_WITH_ICMPV4); SCReturn; /* no parsing yet, just skip it */ case IPPROTO_MH: case IPPROTO_HIP: case IPPROTO_SHIM6: hdrextlen = 8 + (*(pkt+1) * 8); /* 8 bytes + length in 8 octet units */ if (hdrextlen > plen) { ENGINE_SET_EVENT(p, IPV6_TRUNC_EXTHDR); SCReturn; } nh = *pkt; pkt += hdrextlen; plen -= hdrextlen; break; default: ENGINE_SET_EVENT(p, IPV6_UNKNOWN_NEXT_HEADER); IPV6_SET_L4PROTO(p,nh); SCReturn; } } SCReturn; }