diff --git a/src/decode-ipv6.c b/src/decode-ipv6.c index c13b8806c9..9ca0630652 100644 --- a/src/decode-ipv6.c +++ b/src/decode-ipv6.c @@ -101,6 +101,49 @@ static int DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint return TM_ECODE_OK; } +#ifndef UNITTESTS // ugly, but we need this in defrag tests +static inline +#endif +void DecodeIPV6FragHeader(Packet *p, uint8_t *pkt, + uint16_t hdrextlen, uint16_t plen, + uint16_t ip6_exthdrs_cnt, IPV6GenOptHdr *ip6_exthdrs) +{ + 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 = ntohl(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 (ip6_exthdrs_cnt > 1) { + p->ip6eh.fh_prev_hdr_offset = frag_hdr_offset - ip6_exthdrs[ip6_exthdrs_cnt - 1].len; + } + + 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); +} + static void DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { @@ -429,46 +472,15 @@ DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt /* set the header flag first */ IPV6_EXTHDR_SET_FH(p); - 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 = ntohl(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 (ip6_exthdrs_cnt > 1) { - p->ip6eh.fh_prev_hdr_offset = frag_hdr_offset - ip6_exthdrs[ip6_exthdrs_cnt - 1].len; - } - - 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); + /* parse the header and setup the vars */ + DecodeIPV6FragHeader(p, pkt, hdrextlen, plen, + ip6_exthdrs_cnt, ip6_exthdrs); /* 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 (frag_morefrags == 0 && frag_offset == 0) { + if (p->ip6eh.fh_more_frags_set == 0 && p->ip6eh.fh_offset == 0) { ENGINE_SET_EVENT(p, IPV6_EXTHDR_USELESS_FH); nh = *pkt; diff --git a/src/defrag.c b/src/defrag.c index 488f9113ea..fd89a757f5 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -1071,6 +1071,10 @@ error: return NULL; } +void DecodeIPV6FragHeader(Packet *p, uint8_t *pkt, + uint16_t hdrextlen, uint16_t plen, + uint16_t ip6_exthdrs_cnt, IPV6GenOptHdr *ip6_exthdrs); + static Packet * IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content, int content_len) @@ -1111,6 +1115,8 @@ IPV6BuildTestPacket(uint32_t id, uint16_t off, int mf, const char content, fh->ip6fh_ident = htonl(id); fh->ip6fh_offlg = htons((off << 3) | mf); + DecodeIPV6FragHeader(p, (uint8_t *)fh, 8, 8 + content_len, 0, NULL); + pcontent = SCCalloc(1, content_len); if (unlikely(pcontent == NULL)) return NULL;