• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.55
/src/decode-ipv6.c
1
/* Copyright (C) 2007-2025 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17

18
/**
19
 * \ingroup decode
20
 *
21
 * @{
22
 */
23

24

25
/**
26
 * \file
27
 *
28
 * \author Victor Julien <victor@inliniac.net>
29
 *
30
 * Decode IPv6
31
 */
32

33
#include "suricata-common.h"
34
#include "decode-ipv6.h"
35
#include "decode.h"
36
#include "defrag.h"
37
#include "flow-hash.h"
38
#include "util-print.h"
39
#include "util-validate.h"
40

41
/**
42
 * \brief Function to decode IPv4 in IPv6 packets
43
 *
44
 */
45
static void DecodeIPv4inIPv6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t plen)
46
{
3,504✔
47

48
    if (unlikely(plen < IPV4_HEADER_LEN)) {
3,504✔
49
        ENGINE_SET_INVALID_EVENT(p, IPV4_IN_IPV6_PKT_TOO_SMALL);
1,095✔
50
        return;
1,095✔
51
    }
1,095✔
52
    if (IP_GET_RAW_VER(pkt) == 4) {
2,409✔
53
        Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt, plen, DECODE_TUNNEL_IPV4);
293✔
54
        if (tp != NULL) {
293✔
55
            PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6);
77✔
56
            PacketEnqueueNoLock(&tv->decode_pq,tp);
77✔
57
            StatsCounterIncr(&tv->stats, dtv->counter_ipv4inipv6);
77✔
58
        }
77✔
59
        FlowSetupPacket(p);
293✔
60
    } else {
2,116✔
61
        ENGINE_SET_INVALID_EVENT(p, IPV4_IN_IPV6_WRONG_IP_VER);
2,116✔
62
    }
2,116✔
63
}
2,409✔
64

65
/**
66
 * \brief Function to decode IPv6 in IPv6 packets
67
 *
68
 */
69
static int DecodeIP6inIP6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
70
        const uint8_t *pkt, uint16_t plen)
71
{
728✔
72

73
    if (unlikely(plen < IPV6_HEADER_LEN)) {
728✔
74
        ENGINE_SET_INVALID_EVENT(p, IPV6_IN_IPV6_PKT_TOO_SMALL);
204✔
75
        return TM_ECODE_FAILED;
204✔
76
    }
204✔
77
    if (IP_GET_RAW_VER(pkt) == 6) {
524✔
78
        Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt, plen, DECODE_TUNNEL_IPV6);
327✔
79
        if (tp != NULL) {
327✔
80
            PKT_SET_SRC(tp, PKT_SRC_DECODER_IPV6);
260✔
81
            PacketEnqueueNoLock(&tv->decode_pq,tp);
260✔
82
            StatsCounterIncr(&tv->stats, dtv->counter_ipv6inipv6);
260✔
83
        }
260✔
84
        FlowSetupPacket(p);
327✔
85
    } else {
327✔
86
        ENGINE_SET_INVALID_EVENT(p, IPV6_IN_IPV6_WRONG_IP_VER);
197✔
87
    }
197✔
88
    return TM_ECODE_OK;
524✔
89
}
728✔
90

91
#ifndef UNITTESTS // ugly, but we need this in defrag tests
92
static inline
93
#endif
94
void DecodeIPV6FragHeader(Packet *p, const uint8_t *pkt,
95
                          uint16_t hdrextlen, uint16_t plen,
96
                          uint16_t prev_hdrextlen)
97
{
229,770✔
98
    uint16_t frag_offset = (*(pkt + 2) << 8 | *(pkt + 3)) & 0xFFF8;
229,770✔
99
    int frag_morefrags   = (*(pkt + 2) << 8 | *(pkt + 3)) & 0x0001;
229,770✔
100

101
    p->l3.vars.ip6.eh.fh_offset = frag_offset;
229,770✔
102
    p->l3.vars.ip6.eh.fh_more_frags_set = frag_morefrags ? true : false;
229,770✔
103
    p->l3.vars.ip6.eh.fh_nh = *pkt;
229,770✔
104

105
    uint32_t fh_id;
229,770✔
106
    memcpy(&fh_id, pkt+4, 4);
229,770✔
107
    p->l3.vars.ip6.eh.fh_id = SCNtohl(fh_id);
229,770✔
108

109
    SCLogDebug("IPV6 FH: offset %u, mf %s, nh %u, id %u/%x", p->l3.vars.ip6.eh.fh_offset,
229,770✔
110
            p->l3.vars.ip6.eh.fh_more_frags_set ? "true" : "false", p->l3.vars.ip6.eh.fh_nh,
229,770✔
111
            p->l3.vars.ip6.eh.fh_id, p->l3.vars.ip6.eh.fh_id);
229,770✔
112

113
    // store header offset, data offset
114
    uint16_t frag_hdr_offset = (uint16_t)(pkt - GET_PKT_DATA(p));
229,770✔
115
    uint16_t data_offset = (uint16_t)(frag_hdr_offset + hdrextlen);
229,770✔
116
    uint16_t data_len = plen - hdrextlen;
229,770✔
117

118
    p->l3.vars.ip6.eh.fh_header_offset = frag_hdr_offset;
229,770✔
119
    p->l3.vars.ip6.eh.fh_data_offset = data_offset;
229,770✔
120
    p->l3.vars.ip6.eh.fh_data_len = data_len;
229,770✔
121

122
    /* if we have a prev hdr, store the type and offset of it */
123
    if (prev_hdrextlen) {
229,770✔
124
        p->l3.vars.ip6.eh.fh_prev_hdr_offset = frag_hdr_offset - prev_hdrextlen;
207,665✔
125
    }
207,665✔
126

127
    SCLogDebug("IPV6 FH: frag_hdr_offset %u, data_offset %u, data_len %u",
229,770✔
128
            p->l3.vars.ip6.eh.fh_header_offset, p->l3.vars.ip6.eh.fh_data_offset,
229,770✔
129
            p->l3.vars.ip6.eh.fh_data_len);
229,770✔
130
}
229,770✔
131

132
static void DecodeIPV6ExtHdrs(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const IPV6Hdr *ip6h,
133
        const uint8_t *pkt, uint16_t len)
134
{
305,155✔
135
    SCEnter();
305,155✔
136

137
    const uint8_t *orig_pkt = pkt;
305,155✔
138
    uint8_t nh = IPV6_GET_RAW_NH(ip6h); /* careful, 0 is actually a real type */
305,155✔
139
    uint16_t hdrextlen = 0;
305,155✔
140
    uint16_t plen = len;
305,155✔
141
    char dstopts = 0;
305,155✔
142
    char exthdr_fh_done = 0;
305,155✔
143
    int hh = 0;
305,155✔
144
    int rh = 0;
305,155✔
145
    int ah = 0;
305,155✔
146

147
    while(1)
1,905,269✔
148
    {
1,905,269✔
149
        IPV6_SET_EXTHDRS_LEN(p, (len - plen));
1,905,269✔
150

151
        if (nh == IPPROTO_NONE) {
1,905,269✔
152
            if (plen > 0) {
4,297✔
153
                /* No upper layer, but we do have data. Suspicious. */
154
                ENGINE_SET_EVENT(p, IPV6_DATA_AFTER_NONE_HEADER);
334✔
155
            }
334✔
156
            SCReturn;
4,297✔
157
        }
4,297✔
158

159
        if (plen < 2) { /* minimal needed in a hdr */
1,900,972✔
160
            ENGINE_SET_INVALID_EVENT(p, IPV6_TRUNC_EXTHDR);
4,817✔
161
            SCReturn;
4,817✔
162
        }
4,817✔
163

164
        switch(nh)
1,896,155✔
165
        {
1,896,155✔
166
            case IPPROTO_TCP:
1,914✔
167
                IPV6_SET_L4PROTO(p,nh);
1,914✔
168
                DecodeTCP(tv, dtv, p, pkt, plen);
1,914✔
169
                SCReturn;
1,914✔
170

171
            case IPPROTO_UDP:
452✔
172
                IPV6_SET_L4PROTO(p,nh);
452✔
173
                DecodeUDP(tv, dtv, p, pkt, plen);
452✔
174
                SCReturn;
452✔
175

176
            case IPPROTO_ICMPV6:
53,691✔
177
                IPV6_SET_L4PROTO(p,nh);
53,691✔
178
                DecodeICMPV6(tv, dtv, p, pkt, plen);
53,691✔
179
                SCReturn;
53,691✔
180

181
            case IPPROTO_SCTP:
77✔
182
                IPV6_SET_L4PROTO(p,nh);
77✔
183
                DecodeSCTP(tv, dtv, p, pkt, plen);
77✔
184
                SCReturn;
77✔
185

186
            case IPPROTO_ROUTING:
7,354✔
187
                IPV6_SET_L4PROTO(p,nh);
7,354✔
188
                hdrextlen = 8 + (*(pkt+1) * 8);  /* 8 bytes + length in 8 octet units */
7,354✔
189

190
                SCLogDebug("hdrextlen %"PRIu16, hdrextlen);
7,354✔
191

192
                if (hdrextlen > plen) {
7,354✔
193
                    ENGINE_SET_INVALID_EVENT(p, IPV6_TRUNC_EXTHDR);
587✔
194
                    SCReturn;
587✔
195
                }
587✔
196

197
                if (rh) {
6,767✔
198
                    ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_RH);
2,036✔
199
                    /* skip past this extension so we can continue parsing the rest
200
                     * of the packet */
201
                    nh = *pkt;
2,036✔
202
                    pkt += hdrextlen;
2,036✔
203
                    plen -= hdrextlen;
2,036✔
204
                    break;
2,036✔
205
                }
2,036✔
206

207
                rh = 1;
4,731✔
208
                IPV6_EXTHDR_SET_RH(p);
4,731✔
209

210
                uint8_t ip6rh_type = *(pkt + 2);
4,731✔
211
                if (ip6rh_type == 0) {
4,731✔
212
                    ENGINE_SET_EVENT(p, IPV6_EXTHDR_RH_TYPE_0);
4,148✔
213
                }
4,148✔
214
                p->l3.vars.ip6.eh.rh_type = ip6rh_type;
4,731✔
215

216
                nh = *pkt;
4,731✔
217
                pkt += hdrextlen;
4,731✔
218
                plen -= hdrextlen;
4,731✔
219
                break;
4,731✔
220

221
            case IPPROTO_HOPOPTS:
271,154✔
222
            case IPPROTO_DSTOPTS:
1,550,950✔
223
            {
1,550,950✔
224
                IPV6OptHAO hao_s, *hao = &hao_s;
1,550,950✔
225
                IPV6OptRA ra_s, *ra = &ra_s;
1,550,950✔
226
                IPV6OptJumbo jumbo_s, *jumbo = &jumbo_s;
1,550,950✔
227
                uint16_t optslen = 0;
1,550,950✔
228

229
                IPV6_SET_L4PROTO(p,nh);
1,550,950✔
230
                hdrextlen = (uint16_t)((*(pkt + 1) + 1) << 3);
1,550,950✔
231
                if (hdrextlen > plen) {
1,550,950✔
232
                    ENGINE_SET_INVALID_EVENT(p, IPV6_TRUNC_EXTHDR);
3,705✔
233
                    SCReturn;
3,705✔
234
                }
3,705✔
235

236
                const uint8_t *ptr = pkt + 2; /* +2 to go past nxthdr and len */
1,547,245✔
237

238
                /* point the pointers to right structures
239
                 * in Packet. */
240
                if (nh == IPPROTO_HOPOPTS) {
1,547,245✔
241
                    if (hh) {
268,233✔
242
                        ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_HH);
36,846✔
243
                        /* skip past this extension so we can continue parsing the rest
244
                         * of the packet */
245
                        nh = *pkt;
36,846✔
246
                        pkt += hdrextlen;
36,846✔
247
                        plen -= hdrextlen;
36,846✔
248
                        break;
36,846✔
249
                    }
36,846✔
250

251
                    hh = 1;
231,387✔
252

253
                    optslen = (uint16_t)((*(pkt + 1) + 1) << 3) - 2;
231,387✔
254
                }
231,387✔
255
                else if (nh == IPPROTO_DSTOPTS)
1,279,012✔
256
                {
1,279,012✔
257
                    if (dstopts == 0) {
1,279,012✔
258
                        optslen = (uint16_t)((*(pkt + 1) + 1) << 3) - 2;
27,169✔
259
                        dstopts = 1;
27,169✔
260
                    } else if (dstopts == 1) {
1,251,843✔
261
                        optslen = (uint16_t)((*(pkt + 1) + 1) << 3) - 2;
10,658✔
262
                        dstopts = 2;
10,658✔
263
                    } else {
1,241,185✔
264
                        ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_DH);
1,241,185✔
265
                        /* skip past this extension so we can continue parsing the rest
266
                         * of the packet */
267
                        nh = *pkt;
1,241,185✔
268
                        pkt += hdrextlen;
1,241,185✔
269
                        plen -= hdrextlen;
1,241,185✔
270
                        break;
1,241,185✔
271
                    }
1,241,185✔
272
                }
1,279,012✔
273

274
                if (optslen > plen) {
269,214✔
275
                    /* since the packet is long enough (we checked
276
                     * plen against hdrlen, the optlen must be malformed. */
277
                    ENGINE_SET_INVALID_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN);
×
278
                    /* skip past this extension so we can continue parsing the rest
279
                     * of the packet */
280
                    nh = *pkt;
×
281
                    pkt += hdrextlen;
×
282
                    plen -= hdrextlen;
×
283
                    break;
×
284
                }
×
285
/** \todo move into own function to loaded on demand */
286
                uint16_t padn_cnt = 0;
269,214✔
287
                uint16_t other_cnt = 0;
269,214✔
288
                uint16_t offset = 0;
269,214✔
289
                while(offset < optslen)
1,884,994✔
290
                {
1,651,612✔
291
                    if (*ptr == IPV6OPT_PAD1)
1,651,612✔
292
                    {
1,027,117✔
293
                        padn_cnt++;
1,027,117✔
294
                        offset++;
1,027,117✔
295
                        ptr++;
1,027,117✔
296
                        continue;
1,027,117✔
297
                    }
1,027,117✔
298

299
                    if (offset + 1 >= optslen) {
624,495✔
300
                        ENGINE_SET_INVALID_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN);
9,149✔
301
                        break;
9,149✔
302
                    }
9,149✔
303

304
                    /* length field for each opt */
305
                    uint8_t ip6_optlen = *(ptr + 1);
615,346✔
306

307
                    /* see if the optlen from the packet fits the total optslen */
308
                    if ((offset + 1 + ip6_optlen) > optslen) {
615,346✔
309
                        ENGINE_SET_INVALID_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN);
24,264✔
310
                        break;
24,264✔
311
                    }
24,264✔
312

313
                    if (*ptr == IPV6OPT_PADN) /* PadN */
591,082✔
314
                    {
49,513✔
315
                        padn_cnt++;
49,513✔
316

317
                        /* a zero padN len would be weird */
318
                        if (ip6_optlen == 0)
49,513✔
319
                            ENGINE_SET_EVENT(p, IPV6_EXTHDR_ZERO_LEN_PADN);
47,603✔
320
                    } else if (*ptr == IPV6OPT_RA) /* RA */
541,569✔
321
                    {
206,145✔
322
                        ra->ip6ra_type = *(ptr);
206,145✔
323
                        ra->ip6ra_len  = ip6_optlen;
206,145✔
324

325
                        if (ip6_optlen < sizeof(ra->ip6ra_value)) {
206,145✔
326
                            ENGINE_SET_INVALID_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN);
808✔
327
                            break;
808✔
328
                        }
808✔
329

330
                        memcpy(&ra->ip6ra_value, (ptr + 2), sizeof(ra->ip6ra_value));
205,337✔
331
                        ra->ip6ra_value = SCNtohs(ra->ip6ra_value);
205,337✔
332
                        other_cnt++;
205,337✔
333
                    } else if (*ptr == IPV6OPT_JUMBO) /* Jumbo */
335,424✔
334
                    {
1,086✔
335
                        jumbo->ip6j_type = *(ptr);
1,086✔
336
                        jumbo->ip6j_len  = ip6_optlen;
1,086✔
337

338
                        if (ip6_optlen < sizeof(jumbo->ip6j_payload_len)) {
1,086✔
339
                            ENGINE_SET_INVALID_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN);
857✔
340
                            break;
857✔
341
                        }
857✔
342

343
                        memcpy(&jumbo->ip6j_payload_len, (ptr+2), sizeof(jumbo->ip6j_payload_len));
229✔
344
                        jumbo->ip6j_payload_len = SCNtohl(jumbo->ip6j_payload_len);
229✔
345
                    } else if (*ptr == IPV6OPT_HAO) /* HAO */
334,338✔
346
                    {
832✔
347
                        hao->ip6hao_type = *(ptr);
832✔
348
                        hao->ip6hao_len  = ip6_optlen;
832✔
349

350
                        if (ip6_optlen < sizeof(hao->ip6hao_hoa)) {
832✔
351
                            ENGINE_SET_INVALID_EVENT(p, IPV6_EXTHDR_INVALID_OPTLEN);
754✔
352
                            break;
754✔
353
                        }
754✔
354

355
                        memcpy(&hao->ip6hao_hoa, (ptr + 2), sizeof(hao->ip6hao_hoa));
78✔
356
                        other_cnt++;
78✔
357
                    } else {
333,506✔
358
                        if (nh == IPPROTO_HOPOPTS)
333,506✔
359
                            ENGINE_SET_EVENT(p, IPV6_HOPOPTS_UNKNOWN_OPT);
53,534✔
360
                        else
279,972✔
361
                            ENGINE_SET_EVENT(p, IPV6_DSTOPTS_UNKNOWN_OPT);
279,972✔
362

363
                        other_cnt++;
333,506✔
364
                    }
333,506✔
365
                    uint16_t optlen = (*(ptr + 1) + 2);
588,663✔
366
                    ptr += optlen; /* +2 for opt type and opt len fields */
588,663✔
367
                    offset += optlen;
588,663✔
368
                }
588,663✔
369
                /* flag packets that have only padding */
370
                if (padn_cnt > 0 && other_cnt == 0) {
269,214✔
371
                    if (nh == IPPROTO_HOPOPTS)
25,240✔
372
                        ENGINE_SET_EVENT(p, IPV6_HOPOPTS_ONLY_PADDING);
5,712✔
373
                    else
19,528✔
374
                        ENGINE_SET_EVENT(p, IPV6_DSTOPTS_ONLY_PADDING);
19,528✔
375
                }
25,240✔
376

377
                nh = *pkt;
269,214✔
378
                pkt += hdrextlen;
269,214✔
379
                plen -= hdrextlen;
269,214✔
380
                break;
269,214✔
381
            }
269,214✔
382

383
            case IPPROTO_FRAGMENT:
232,207✔
384
            {
232,207✔
385
                IPV6_SET_L4PROTO(p,nh);
232,207✔
386
                /* store the offset of this extension into the packet
387
                 * past the ipv6 header. We use it in defrag for creating
388
                 * a defragmented packet without the frag header */
389
                if (exthdr_fh_done == 0) {
232,207✔
390
                    DEBUG_VALIDATE_BUG_ON(pkt - orig_pkt > UINT16_MAX);
229,993✔
391
                    p->l3.vars.ip6.eh.fh_offset = (uint16_t)(pkt - orig_pkt);
229,993✔
392
                    exthdr_fh_done = 1;
229,993✔
393
                }
229,993✔
394

395
                uint16_t prev_hdrextlen = hdrextlen;
232,207✔
396
                hdrextlen = sizeof(IPV6FragHdr);
232,207✔
397
                if (hdrextlen > plen) {
232,207✔
398
                    ENGINE_SET_INVALID_EVENT(p, IPV6_TRUNC_EXTHDR);
337✔
399
                    SCReturn;
337✔
400
                }
337✔
401

402
                /* for the frag header, the length field is reserved */
403
                if (*(pkt + 1) != 0) {
231,870✔
404
                    ENGINE_SET_EVENT(p, IPV6_FH_NON_ZERO_RES_FIELD);
27,895✔
405
                    /* non fatal, lets try to continue */
406
                }
27,895✔
407

408
                if (IPV6_EXTHDR_ISSET_FH(p)) {
231,870✔
409
                    ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_FH);
2,100✔
410
                    nh = *pkt;
2,100✔
411
                    pkt += hdrextlen;
2,100✔
412
                    plen -= hdrextlen;
2,100✔
413
                    break;
2,100✔
414
                }
2,100✔
415

416
                /* set the header flag first */
417
                IPV6_EXTHDR_SET_FH(p);
229,770✔
418

419
                /* parse the header and setup the vars */
420
                DecodeIPV6FragHeader(p, pkt, hdrextlen, plen, prev_hdrextlen);
229,770✔
421

422
                /* if FH has offset 0 and no more fragments are coming, we
423
                 * parse this packet further right away, no defrag will be
424
                 * needed. It is a useless FH then though, so we do set an
425
                 * decoder event. */
426
                if (p->l3.vars.ip6.eh.fh_more_frags_set == 0 && p->l3.vars.ip6.eh.fh_offset == 0) {
229,770✔
427
                    ENGINE_SET_EVENT(p, IPV6_EXTHDR_USELESS_FH);
2,821✔
428

429
                    nh = *pkt;
2,821✔
430
                    pkt += hdrextlen;
2,821✔
431
                    plen -= hdrextlen;
2,821✔
432
                    break;
2,821✔
433
                }
2,821✔
434
                if (p->l3.vars.ip6.eh.fh_more_frags_set != 0 && plen % 8 != 0) {
226,949✔
435
                    // cf https://datatracker.ietf.org/doc/html/rfc2460#section-4.5
436
                    // each, except possibly the last ("rightmost") one,
437
                    // being an integer multiple of 8 octets long.
438
                    ENGINE_SET_EVENT(p, IPV6_FRAG_INVALID_LENGTH);
207,665✔
439
                }
207,665✔
440

441
                /* the rest is parsed upon reassembly */
442
                p->flags |= PKT_IS_FRAGMENT;
226,949✔
443
                SCReturn;
226,949✔
444
            }
229,770✔
445
            case IPPROTO_ESP:
584✔
446
            {
584✔
447
                IPV6_SET_L4PROTO(p,nh);
584✔
448
                DecodeESP(tv, dtv, p, pkt, plen);
584✔
449
                SCReturn;
584✔
450
            }
229,770✔
451
            case IPPROTO_AH:
40,247✔
452
            {
40,247✔
453
                IPV6_SET_L4PROTO(p,nh);
40,247✔
454
                /* we need the header as a minimum */
455
                hdrextlen = sizeof(IPV6AuthHdr);
40,247✔
456
                /* the payload len field is the number of extra 4 byte fields,
457
                 * IPV6AuthHdr already contains the first */
458
                if (*(pkt+1) > 0)
40,247✔
459
                    hdrextlen += ((*(pkt+1) - 1) * 4);
36,605✔
460

461
                SCLogDebug("hdrextlen %"PRIu16, hdrextlen);
40,247✔
462

463
                if (hdrextlen > plen) {
40,247✔
464
                    ENGINE_SET_INVALID_EVENT(p, IPV6_TRUNC_EXTHDR);
330✔
465
                    SCReturn;
330✔
466
                }
330✔
467

468
                IPV6AuthHdr *ahhdr = (IPV6AuthHdr *)pkt;
39,917✔
469
                if (ahhdr->ip6ah_reserved != 0x0000) {
39,917✔
470
                    ENGINE_SET_EVENT(p, IPV6_EXTHDR_AH_RES_NOT_NULL);
3,914✔
471
                }
3,914✔
472

473
                if (ah) {
39,917✔
474
                    ENGINE_SET_EVENT(p, IPV6_EXTHDR_DUPL_AH);
3,632✔
475
                    nh = *pkt;
3,632✔
476
                    pkt += hdrextlen;
3,632✔
477
                    plen -= hdrextlen;
3,632✔
478
                    break;
3,632✔
479
                }
3,632✔
480

481
                ah = 1;
36,285✔
482

483
                nh = *pkt;
36,285✔
484
                pkt += hdrextlen;
36,285✔
485
                plen -= hdrextlen;
36,285✔
486
                break;
36,285✔
487
            }
39,917✔
488
            case IPPROTO_IPIP:
2,835✔
489
                IPV6_SET_L4PROTO(p,nh);
2,835✔
490
                DecodeIPv4inIPv6(tv, dtv, p, pkt, plen);
2,835✔
491
                SCReturn;
2,835✔
492
            /* none, last header */
493
            case IPPROTO_NONE:
×
494
                IPV6_SET_L4PROTO(p,nh);
×
495
                SCReturn;
×
496
            case IPPROTO_ICMP:
604✔
497
                ENGINE_SET_EVENT(p,IPV6_WITH_ICMPV4);
604✔
498
                SCReturn;
604✔
499
            /* no parsing yet, just skip it */
500
            case IPPROTO_MH:
1,008✔
501
            case IPPROTO_HIP:
1,578✔
502
            case IPPROTO_SHIM6:
2,015✔
503
                hdrextlen = 8 + (*(pkt+1) * 8);  /* 8 bytes + length in 8 octet units */
2,015✔
504
                if (hdrextlen > plen) {
2,015✔
505
                    ENGINE_SET_INVALID_EVENT(p, IPV6_TRUNC_EXTHDR);
751✔
506
                    SCReturn;
751✔
507
                }
751✔
508
                nh = *pkt;
1,264✔
509
                pkt += hdrextlen;
1,264✔
510
                plen -= hdrextlen;
1,264✔
511
                break;
1,264✔
512
            default:
3,225✔
513
                ENGINE_SET_EVENT(p, IPV6_UNKNOWN_NEXT_HEADER);
3,225✔
514
                IPV6_SET_L4PROTO(p,nh);
3,225✔
515
                SCReturn;
3,225✔
516
        }
1,896,155✔
517
    }
1,896,155✔
518

519
    SCReturn;
305,155✔
520
}
305,155✔
521

522
static const IPV6Hdr *DecodeIPV6Packet(
523
        ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
524
{
374,468✔
525
    if (unlikely(len < IPV6_HEADER_LEN)) {
374,468✔
526
        ENGINE_SET_INVALID_EVENT(p, IPV6_PKT_TOO_SMALL);
10,696✔
527
        return NULL;
10,696✔
528
    }
10,696✔
529

530
    if (unlikely(IP_GET_RAW_VER(pkt) != 6)) {
363,772✔
531
        SCLogDebug("wrong ip version %d",IP_GET_RAW_VER(pkt));
2,020✔
532
        ENGINE_SET_INVALID_EVENT(p, IPV6_WRONG_IP_VER);
2,020✔
533
        return NULL;
2,020✔
534
    }
2,020✔
535

536
    const IPV6Hdr *ip6h = PacketSetIPV6(p, pkt);
361,752✔
537

538
    if (unlikely(len < (IPV6_HEADER_LEN + IPV6_GET_RAW_PLEN(ip6h)))) {
361,752✔
539
        ENGINE_SET_INVALID_EVENT(p, IPV6_TRUNC_PKT);
4,951✔
540
        return NULL;
4,951✔
541
    }
4,951✔
542

543
    SET_IPV6_SRC_ADDR(ip6h, &p->src);
356,801✔
544
    SET_IPV6_DST_ADDR(ip6h, &p->dst);
356,801✔
545

546
    return ip6h;
356,801✔
547
}
361,752✔
548

549
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
550
{
374,487✔
551
    StatsCounterIncr(&tv->stats, dtv->counter_ipv6);
374,487✔
552

553
    if (!PacketIncreaseCheckLayers(p)) {
374,487✔
554
        return TM_ECODE_FAILED;
19✔
555
    }
19✔
556
    /* do the actual decoding */
557
    const IPV6Hdr *ip6h = DecodeIPV6Packet(tv, dtv, p, pkt, len);
374,468✔
558
    if (unlikely(ip6h == NULL)) {
374,468✔
559
        PacketClearL3(p);
17,667✔
560
        return TM_ECODE_FAILED;
17,667✔
561
    }
17,667✔
562
    p->proto = IPV6_GET_RAW_NH(ip6h);
356,801✔
563

564
#ifdef DEBUG
565
    if (SCLogDebugEnabled()) { /* only convert the addresses if debug is really enabled */
566
        /* debug print */
567
        char s[46], d[46];
568
        PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), s, sizeof(s));
569
        PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), d, sizeof(d));
570
        SCLogDebug("IPV6 %s->%s - CLASS: %" PRIu32 " FLOW: %" PRIu32 " NH: %" PRIu32
571
                   " PLEN: %" PRIu32 " HLIM: %" PRIu32 "",
572
                s, d, IPV6_GET_RAW_CLASS(ip6h), IPV6_GET_RAW_FLOW(ip6h), IPV6_GET_RAW_NH(ip6h),
573
                IPV6_GET_RAW_PLEN(ip6h), IPV6_GET_RAW_HLIM(ip6h));
574
    }
575
#endif /* DEBUG */
576
    const uint8_t *data = pkt + IPV6_HEADER_LEN;
356,801✔
577
    const uint16_t data_len = IPV6_GET_RAW_PLEN(ip6h);
356,801✔
578

579
    /* now process the Ext headers and/or the L4 Layer */
580
    switch (IPV6_GET_RAW_NH(ip6h)) {
356,801✔
581
        case IPPROTO_TCP:
9,336✔
582
            IPV6_SET_L4PROTO (p, IPPROTO_TCP);
9,336✔
583
            DecodeTCP(tv, dtv, p, data, data_len);
9,336✔
584
            return TM_ECODE_OK;
9,336✔
585
        case IPPROTO_UDP:
5,720✔
586
            IPV6_SET_L4PROTO (p, IPPROTO_UDP);
5,720✔
587
            DecodeUDP(tv, dtv, p, data, data_len);
5,720✔
588
            return TM_ECODE_OK;
5,720✔
589
        case IPPROTO_ICMPV6:
30,640✔
590
            IPV6_SET_L4PROTO (p, IPPROTO_ICMPV6);
30,640✔
591
            DecodeICMPV6(tv, dtv, p, data, data_len);
30,640✔
592
            return TM_ECODE_OK;
30,640✔
593
        case IPPROTO_SCTP:
195✔
594
            IPV6_SET_L4PROTO (p, IPPROTO_SCTP);
195✔
595
            DecodeSCTP(tv, dtv, p, data, data_len);
195✔
596
            return TM_ECODE_OK;
195✔
597
        case IPPROTO_IPIP:
669✔
598
            IPV6_SET_L4PROTO(p, IPPROTO_IPIP);
669✔
599
            DecodeIPv4inIPv6(tv, dtv, p, data, data_len);
669✔
600
            return TM_ECODE_OK;
669✔
601
        case IPPROTO_IPV6:
728✔
602
            DecodeIP6inIP6(tv, dtv, p, data, data_len);
728✔
603
            return TM_ECODE_OK;
728✔
604
        case IPPROTO_GRE:
1,412✔
605
            IPV6_SET_L4PROTO(p, IPPROTO_GRE);
1,412✔
606
            DecodeGRE(tv, dtv, p, data, data_len);
1,412✔
607
            break;
1,412✔
608
        case IPPROTO_FRAGMENT:
22,364✔
609
        case IPPROTO_HOPOPTS:
248,490✔
610
        case IPPROTO_ROUTING:
249,433✔
611
        case IPPROTO_NONE:
250,015✔
612
        case IPPROTO_DSTOPTS:
267,596✔
613
        case IPPROTO_AH:
303,961✔
614
        case IPPROTO_ESP:
304,208✔
615
        case IPPROTO_MH:
304,528✔
616
        case IPPROTO_HIP:
304,876✔
617
        case IPPROTO_SHIM6:
305,155✔
618
            DecodeIPV6ExtHdrs(tv, dtv, p, ip6h, data, data_len);
305,155✔
619
            break;
305,155✔
620
        case IPPROTO_ICMP:
273✔
621
            ENGINE_SET_EVENT(p,IPV6_WITH_ICMPV4);
273✔
622
            break;
273✔
623
        default:
2,673✔
624
            ENGINE_SET_EVENT(p, IPV6_UNKNOWN_NEXT_HEADER);
2,673✔
625
            IPV6_SET_L4PROTO(p, IPV6_GET_RAW_NH(ip6h));
2,673✔
626
            break;
2,673✔
627
    }
356,801✔
628
    p->proto = IPV6_GET_L4PROTO (p);
309,513✔
629

630
    /* Pass to defragger if a fragment. */
631
    if (IPV6_EXTHDR_ISSET_FH(p)) {
309,513✔
632
        Packet *rp = Defrag(tv, dtv, p);
229,770✔
633
        if (rp != NULL) {
229,770✔
634
            PacketEnqueueNoLock(&tv->decode_pq,rp);
2,905✔
635
        }
2,905✔
636
    }
229,770✔
637

638
    return TM_ECODE_OK;
309,513✔
639
}
356,801✔
640

641
#ifdef UNITTESTS
642
#include "util-unittest-helper.h"
643
#include "packet.h"
644

645
/**
646
 * \test fragment decoding
647
 */
648
static int DecodeIPV6FragTest01 (void)
649
{
650

651
    uint8_t raw_frag1[] = {
652
        0x60, 0x0f, 0x1a, 0xcf, 0x05, 0xa8, 0x2c, 0x36, 0x20, 0x01, 0x04, 0x70, 0x00, 0x01, 0x00, 0x18,
653
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x09, 0x80, 0x32, 0xb2, 0x00, 0x01,
654
        0x2e, 0x41, 0x38, 0xff, 0xfe, 0xa7, 0xea, 0xeb, 0x06, 0x00, 0x00, 0x01, 0xdf, 0xf8, 0x11, 0xd7,
655
        0x00, 0x50, 0xa6, 0x5c, 0xcc, 0xd7, 0x28, 0x9f, 0xc3, 0x34, 0xc6, 0x58, 0x80, 0x10, 0x20, 0x13,
656
        0x18, 0x1f, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0xcd, 0xf9, 0x3a, 0x41, 0x00, 0x1a, 0x91, 0x8a,
657
        0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0x0d,
658
        0x0a, 0x44, 0x61, 0x74, 0x65, 0x3a, 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x30, 0x32, 0x20, 0x44,
659
        0x65, 0x63, 0x20, 0x32, 0x30, 0x31, 0x31, 0x20, 0x30, 0x38, 0x3a, 0x33, 0x32, 0x3a, 0x35, 0x37,
660
        0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x41, 0x70,
661
        0x61, 0x63, 0x68, 0x65, 0x0d, 0x0a, 0x43, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x43, 0x6f, 0x6e, 0x74,
662
        0x72, 0x6f, 0x6c, 0x3a, 0x20, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x0d, 0x0a, 0x50,
663
        0x72, 0x61, 0x67, 0x6d, 0x61, 0x3a, 0x20, 0x6e, 0x6f, 0x2d, 0x63, 0x61, 0x63, 0x68, 0x65, 0x0d,
664
        0x0a, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x3a, 0x20, 0x54, 0x68, 0x75, 0x2c, 0x20, 0x30,
665
        0x31, 0x20, 0x4a, 0x61, 0x6e, 0x20, 0x31, 0x39, 0x37, 0x31, 0x20, 0x30, 0x30, 0x3a, 0x30, 0x30,
666
        0x3a, 0x30, 0x30, 0x20, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
667
        0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, 0x31, 0x35, 0x39, 0x39, 0x0d, 0x0a, 0x4b,
668
        0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x3a, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x6f,
669
        0x75, 0x74, 0x3d, 0x35, 0x2c, 0x20, 0x6d, 0x61, 0x78, 0x3d, 0x39, 0x39, 0x0d, 0x0a, 0x43, 0x6f,
670
        0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b, 0x65, 0x65, 0x70, 0x2d, 0x41,
671
        0x6c, 0x69, 0x76, 0x65, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79,
672
        0x70, 0x65, 0x3a, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f,
673
        0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3b, 0x63, 0x68, 0x61, 0x72, 0x73,
674
        0x65, 0x74, 0x3d, 0x61, 0x73, 0x63, 0x69, 0x69, 0x0d, 0x0a, 0x0d, 0x0a, 0x5f, 0x6a, 0x71, 0x6a,
675
        0x73, 0x70, 0x28, 0x7b, 0x22, 0x69, 0x70, 0x22, 0x3a, 0x22, 0x32, 0x30, 0x30, 0x31, 0x3a, 0x39,
676
        0x38, 0x30, 0x3a, 0x33, 0x32, 0x62, 0x32, 0x3a, 0x31, 0x3a, 0x32, 0x65, 0x34, 0x31, 0x3a, 0x33,
677
        0x38, 0x66, 0x66, 0x3a, 0x66, 0x65, 0x61, 0x37, 0x3a, 0x65, 0x61, 0x65, 0x62, 0x22, 0x2c, 0x22,
678
        0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x69, 0x70, 0x76, 0x36, 0x22, 0x2c, 0x22, 0x73, 0x75,
679
        0x62, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x76, 0x69, 0x61, 0x22, 0x3a,
680
        0x22, 0x22, 0x2c, 0x22, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x3a, 0x22, 0x20, 0x20,
681
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
682
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
683
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
684
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
685
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
686
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
687
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
688
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
689
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
690
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
691
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
692
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
693
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
694
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
695
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
696
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
697
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
698
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
699
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
700
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
701
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
702
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
703
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
704
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
705
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
706
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
707
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
708
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
709
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
710
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
711
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
712
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
713
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
714
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
715
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
716
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
717
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
718
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
719
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
720
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
721
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
722
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
723
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
724
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
725
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
726
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
727
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
728
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
729
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
730
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
731
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
732
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
733
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
734
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
735
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
736
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
737
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
738
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
739
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
740
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
741
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
742
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
743
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
744
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
745
    };
746
    uint8_t raw_frag2[] = {
747
        0x60, 0x0f, 0x1a, 0xcf, 0x00, 0x1c, 0x2c, 0x36, 0x20, 0x01, 0x04, 0x70, 0x00, 0x01, 0x00, 0x18,
748
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x09, 0x80, 0x32, 0xb2, 0x00, 0x01,
749
        0x2e, 0x41, 0x38, 0xff, 0xfe, 0xa7, 0xea, 0xeb, 0x06, 0x00, 0x05, 0xa0, 0xdf, 0xf8, 0x11, 0xd7,
750
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
751
        0x20, 0x20, 0x20, 0x20,
752
    };
753
    Packet *pkt;
754
    Packet *p1 = PacketGetFromAlloc();
755
    if (unlikely(p1 == NULL))
756
        return 0;
757
    Packet *p2 = PacketGetFromAlloc();
758
    if (unlikely(p2 == NULL)) {
759
        PacketFree(p1);
760
        return 0;
761
    }
762
    ThreadVars tv;
763
    DecodeThreadVars dtv;
764
    int result = 0;
765

766
    FlowInitConfig(FLOW_QUIET);
767
    DefragInit();
768

769
    memset(&tv, 0, sizeof(ThreadVars));
770
    memset(&dtv, 0, sizeof(DecodeThreadVars));
771

772
    PacketCopyData(p1, raw_frag1, sizeof(raw_frag1));
773
    PacketCopyData(p2, raw_frag2, sizeof(raw_frag2));
774

775
    DecodeIPV6(&tv, &dtv, p1, GET_PKT_DATA(p1), GET_PKT_LEN(p1));
776

777
    if (!(IPV6_EXTHDR_ISSET_FH(p1))) {
778
        printf("ipv6 frag header not detected: ");
779
        goto end;
780
    }
781

782
    DecodeIPV6(&tv, &dtv, p2, GET_PKT_DATA(p2), GET_PKT_LEN(p2));
783

784
    if (!(IPV6_EXTHDR_ISSET_FH(p2))) {
785
        printf("ipv6 frag header not detected: ");
786
        goto end;
787
    }
788

789
    if (tv.decode_pq.len != 1) {
790
        printf("no reassembled packet: ");
791
        goto end;
792
    }
793

794
    result = 1;
795
end:
796
    PacketRecycle(p1);
797
    PacketRecycle(p2);
798
    PacketFree(p1);
799
    PacketFree(p2);
800
    pkt = PacketDequeueNoLock(&tv.decode_pq);
801
    while (pkt != NULL) {
802
        PacketRecycle(pkt);
803
        PacketFree(pkt);
804
        pkt = PacketDequeueNoLock(&tv.decode_pq);
805
    }
806
    DefragDestroy();
807
    FlowShutdown();
808
    return result;
809
}
810

811
/**
812
 * \test routing header decode
813
 */
814
static int DecodeIPV6RouteTest01 (void)
815
{
816
    uint8_t raw_pkt1[] = {
817
        0x60, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x2b, 0x40,
818
        0x20, 0x01, 0xaa, 0xaa, 0x00, 0x01, 0x00, 0x00,
819
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
820
        0x20, 0x01, 0xaa, 0xaa, 0x00, 0x01, 0x00, 0x00,
821
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
822
        0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
823

824
        0xb2, 0xed, 0x00, 0x50, 0x1b, 0xc7, 0x6a, 0xdf,
825
        0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0x20, 0x00,
826
        0xfa, 0x87, 0x00, 0x00,
827
    };
828
    Packet *p1 = PacketGetFromAlloc();
829
    FAIL_IF(unlikely(p1 == NULL));
830
    ThreadVars tv;
831
    DecodeThreadVars dtv;
832

833
    FlowInitConfig(FLOW_QUIET);
834

835
    memset(&tv, 0, sizeof(ThreadVars));
836
    memset(&dtv, 0, sizeof(DecodeThreadVars));
837

838
    PacketCopyData(p1, raw_pkt1, sizeof(raw_pkt1));
839

840
    DecodeIPV6(&tv, &dtv, p1, GET_PKT_DATA(p1), GET_PKT_LEN(p1));
841

842
    FAIL_IF (!(IPV6_EXTHDR_ISSET_RH(p1)));
843
    FAIL_IF(p1->l3.vars.ip6.eh.rh_type != 0);
844
    PacketRecycle(p1);
845
    PacketFree(p1);
846
    FlowShutdown();
847
    PASS;
848
}
849

850
/**
851
 * \test HOP header decode
852
 */
853
static int DecodeIPV6HopTest01 (void)
854
{
855
    uint8_t raw_pkt1[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00,
856
        0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0xfe, 0xff, 0xfe, 0x98, 0x3d, 0x01, 0xff, 0x02, 0x00,
857
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3a, 0x00,
858
        0xff, /* 0xff is a nonsense opt */
859
        0x02, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x1c, 0x6f, 0x27, 0x10, 0x00, 0x00, 0x00, 0x00,
860
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
861
    Packet *p1 = PacketGetFromAlloc();
862
    FAIL_IF(unlikely(p1 == NULL));
863
    ThreadVars tv;
864
    DecodeThreadVars dtv;
865

866
    FlowInitConfig(FLOW_QUIET);
867

868
    memset(&tv, 0, sizeof(ThreadVars));
869
    memset(&dtv, 0, sizeof(DecodeThreadVars));
870

871
    PacketCopyData(p1, raw_pkt1, sizeof(raw_pkt1));
872

873
    DecodeIPV6(&tv, &dtv, p1, GET_PKT_DATA(p1), GET_PKT_LEN(p1));
874

875
    FAIL_IF (!(ENGINE_ISSET_EVENT(p1, IPV6_HOPOPTS_UNKNOWN_OPT)));
876

877
    PacketRecycle(p1);
878
    PacketFree(p1);
879
    FlowShutdown();
880
    PASS;
881
}
882

883
/**
884
 * \test pkt too small event setting
885
 */
886
static int DecodeIPV6PktTooSmallTest01(void)
887
{
888
    uint8_t raw_pkt1[] = { 0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00,
889
        0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0xfe, 0xff, 0xfe, 0x98, 0x3d, 0x01, 0xff, 0x02, 0x00,
890
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3a, 0x00,
891
        0xff, /* 0xff is a nonsense opt */
892
        0x02, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x1c, 0x6f, 0x27, 0x10, 0x00, 0x00, 0x00, 0x00,
893
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
894
    Packet *p1 = PacketGetFromAlloc();
895
    FAIL_IF(unlikely(p1 == NULL));
896
    ThreadVars tv;
897
    DecodeThreadVars dtv;
898

899
    FlowInitConfig(FLOW_QUIET);
900

901
    memset(&tv, 0, sizeof(ThreadVars));
902
    memset(&dtv, 0, sizeof(DecodeThreadVars));
903

904
    PacketCopyData(p1, raw_pkt1, sizeof(raw_pkt1));
905

906
    /* force pkt length to be shorter than headers length */
907
    DecodeIPV6(&tv, &dtv, p1, GET_PKT_DATA(p1), GET_PKT_LEN(p1) - 33);
908

909
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(p1, IPV6_PKT_TOO_SMALL));
910
    PacketRecycle(p1);
911
    PacketFree(p1);
912
    FlowShutdown();
913
    PASS;
914
}
915

916
#endif /* UNITTESTS */
917

918
/**
919
 * \brief this function registers unit tests for IPV6 decoder
920
 */
921

922
void DecodeIPV6RegisterTests(void)
UNCOV
923
{
×
924
#ifdef UNITTESTS
925
    UtRegisterTest("DecodeIPV6FragTest01", DecodeIPV6FragTest01);
926
    UtRegisterTest("DecodeIPV6RouteTest01", DecodeIPV6RouteTest01);
927
    UtRegisterTest("DecodeIPV6HopTest01", DecodeIPV6HopTest01);
928
    UtRegisterTest("DecodeIPV6PktTooSmallTest01", DecodeIPV6PktTooSmallTest01);
929
#endif /* UNITTESTS */
UNCOV
930
}
×
931

932
/**
933
 * @}
934
 */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc