Coverage Report

Created: 2026-08-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/decode-vlan.c
Line
Count
Source
1
/* Copyright (C) 2007-2022 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 Breno Silva <breno.silva@gmail.com>
29
 *
30
 * Decode 802.1q
31
 */
32
33
#include "suricata-common.h"
34
#include "decode.h"
35
#include "decode-vlan.h"
36
#include "decode-events.h"
37
38
#include "util-validate.h"
39
#include "util-unittest.h"
40
#include "util-debug.h"
41
42
/**
43
 * \internal
44
 * \brief this function is used to decode IEEE802.1q packets
45
 *
46
 * \param tv pointer to the thread vars
47
 * \param dtv pointer code thread vars
48
 * \param p pointer to the packet struct
49
 * \param pkt pointer to the raw packet
50
 * \param len packet len
51
 * \param pq pointer to the packet queue
52
 *
53
 */
54
int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
55
        const uint8_t *pkt, uint32_t len)
56
435k
{
57
435k
    DEBUG_VALIDATE_BUG_ON(pkt == NULL);
58
59
435k
    uint16_t proto;
60
61
435k
    if (p->vlan_idx == 0)
62
425k
        StatsIncr(tv, dtv->counter_vlan);
63
9.96k
    else if (p->vlan_idx == 1)
64
8.27k
        StatsIncr(tv, dtv->counter_vlan_qinq);
65
1.69k
    else if (p->vlan_idx == 2)
66
1.69k
        StatsIncr(tv, dtv->counter_vlan_qinqinq);
67
68
435k
    if(len < VLAN_HEADER_LEN)    {
69
862
        ENGINE_SET_INVALID_EVENT(p, VLAN_HEADER_TOO_SMALL);
70
862
        return TM_ECODE_FAILED;
71
862
    }
72
434k
    if (!PacketIncreaseCheckLayers(p)) {
73
82
        return TM_ECODE_FAILED;
74
82
    }
75
434k
    if (p->vlan_idx > VLAN_MAX_LAYER_IDX) {
76
0
        ENGINE_SET_EVENT(p,VLAN_HEADER_TOO_MANY_LAYERS);
77
0
        return TM_ECODE_FAILED;
78
0
    }
79
80
434k
    VLANHdr *vlan_hdr = (VLANHdr *)pkt;
81
82
434k
    proto = GET_VLAN_PROTO(vlan_hdr);
83
84
434k
    SCLogDebug("p %p pkt %p VLAN protocol %04x VLAN PRI %d VLAN CFI %d VLAN ID %d Len: %" PRIu32 "",
85
434k
            p, pkt, proto, GET_VLAN_PRIORITY(vlan_hdr), GET_VLAN_CFI(vlan_hdr),
86
434k
            GET_VLAN_ID(vlan_hdr), len);
87
88
434k
    p->vlan_id[p->vlan_idx++] = (uint16_t)GET_VLAN_ID(vlan_hdr);
89
90
434k
    if (DecodeNetworkLayer(tv, dtv, proto, p,
91
434k
                pkt + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN) == false) {
92
10.1k
        ENGINE_SET_INVALID_EVENT(p, VLAN_UNKNOWN_TYPE);
93
10.1k
        return TM_ECODE_FAILED;
94
10.1k
    }
95
423k
    return TM_ECODE_OK;
96
434k
}
97
98
typedef struct IEEE8021ahHdr_ {
99
    uint32_t flags;
100
    uint8_t c_destination[6];
101
    uint8_t c_source[6];
102
    uint16_t type;              /**< next protocol */
103
}  __attribute__((__packed__)) IEEE8021ahHdr;
104
105
12.1k
#define IEEE8021AH_HEADER_LEN sizeof(IEEE8021ahHdr)
106
107
int DecodeIEEE8021ah(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
108
        const uint8_t *pkt, uint32_t len)
109
4.82k
{
110
4.82k
    DEBUG_VALIDATE_BUG_ON(pkt == NULL);
111
112
4.82k
    StatsIncr(tv, dtv->counter_ieee8021ah);
113
114
4.82k
    if (len < IEEE8021AH_HEADER_LEN) {
115
1.16k
        ENGINE_SET_INVALID_EVENT(p, IEEE8021AH_HEADER_TOO_SMALL);
116
1.16k
        return TM_ECODE_FAILED;
117
1.16k
    }
118
119
3.65k
    IEEE8021ahHdr *hdr = (IEEE8021ahHdr *)pkt;
120
3.65k
    const uint16_t next_proto = SCNtohs(hdr->type);
121
122
3.65k
    DecodeNetworkLayer(tv, dtv, next_proto, p,
123
3.65k
            pkt + IEEE8021AH_HEADER_LEN, len - IEEE8021AH_HEADER_LEN);
124
125
3.65k
    return TM_ECODE_OK;
126
4.82k
}
127
128
#ifdef UNITTESTS
129
#include "util-unittest-helper.h"
130
#include "packet.h"
131
132
/** \todo Must GRE+VLAN and Multi-Vlan packets to
133
 * create more tests
134
 */
135
136
/**
137
 * \test DecodeVLANTest01 test if vlan header is too small.
138
 *
139
 *  \retval 1 on success
140
 *  \retval 0 on failure
141
 */
142
static int DecodeVLANtest01 (void)
143
{
144
    uint8_t raw_vlan[] = { 0x00, 0x20, 0x08 };
145
    Packet *p = PacketGetFromAlloc();
146
    if (unlikely(p == NULL))
147
        return 0;
148
    ThreadVars tv;
149
    DecodeThreadVars dtv;
150
151
    memset(&tv, 0, sizeof(ThreadVars));
152
    memset(&dtv, 0, sizeof(DecodeThreadVars));
153
154
    DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan));
155
156
    if(ENGINE_ISSET_EVENT(p,VLAN_HEADER_TOO_SMALL))  {
157
        SCFree(p);
158
        return 1;
159
    }
160
161
    SCFree(p);
162
    return 0;
163
}
164
165
/**
166
 * \test DecodeVLANTest02 test if vlan header has unknown type.
167
 *
168
 *  \retval 1 on success
169
 *  \retval 0 on failure
170
 */
171
static int DecodeVLANtest02 (void)
172
{
173
    uint8_t raw_vlan[] = {
174
        0x00, 0x20, 0x01, 0x00, 0x45, 0x00, 0x00, 0x34,
175
        0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9,
176
        0x83, 0x97, 0x20, 0x81, 0x83, 0x97, 0x20, 0x15,
177
        0x04, 0x8a, 0x17, 0x70, 0x4e, 0x14, 0xdf, 0x55,
178
        0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50,
179
        0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a,
180
        0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3};
181
    Packet *p = PacketGetFromAlloc();
182
    if (unlikely(p == NULL))
183
        return 0;
184
    ThreadVars tv;
185
    DecodeThreadVars dtv;
186
187
    memset(&tv, 0, sizeof(ThreadVars));
188
    memset(&dtv, 0, sizeof(DecodeThreadVars));
189
190
    DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan));
191
192
193
    if(ENGINE_ISSET_EVENT(p,VLAN_UNKNOWN_TYPE))  {
194
        SCFree(p);
195
        return 1;
196
    }
197
198
    SCFree(p);
199
    return 0;
200
}
201
202
/**
203
 * \test DecodeVLANTest02 test a good vlan header.
204
 *
205
 *  \retval 1 on success
206
 *  \retval 0 on failure
207
 */
208
static int DecodeVLANtest03 (void)
209
{
210
    uint8_t raw_vlan[] = {
211
        0x00, 0x20, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34,
212
        0x3b, 0x36, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xc9,
213
        0x83, 0x97, 0x20, 0x81, 0x83, 0x97, 0x20, 0x15,
214
        0x04, 0x8a, 0x17, 0x70, 0x4e, 0x14, 0xdf, 0x55,
215
        0x4d, 0x3d, 0x5a, 0x61, 0x80, 0x10, 0x6b, 0x50,
216
        0x3c, 0x4c, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a,
217
        0x00, 0x04, 0xf0, 0xc8, 0x01, 0x99, 0xa3, 0xf3};
218
    Packet *p = PacketGetFromAlloc();
219
    if (unlikely(p == NULL))
220
        return 0;
221
    ThreadVars tv;
222
    DecodeThreadVars dtv;
223
224
    memset(&tv, 0, sizeof(ThreadVars));
225
    memset(&dtv, 0, sizeof(DecodeThreadVars));
226
227
    FlowInitConfig(FLOW_QUIET);
228
229
    DecodeVLAN(&tv, &dtv, p, raw_vlan, sizeof(raw_vlan));
230
231
232
    if(p->vlan_id[0] == 0) {
233
        goto error;
234
    }
235
236
    if(ENGINE_ISSET_EVENT(p,VLAN_HEADER_TOO_SMALL))  {
237
        goto error;
238
    }
239
240
    if(ENGINE_ISSET_EVENT(p,VLAN_UNKNOWN_TYPE))  {
241
        goto error;
242
    }
243
244
    PacketRecycle(p);
245
    FlowShutdown();
246
    SCFree(p);
247
    return 1;
248
249
error:
250
    PacketRecycle(p);
251
    FlowShutdown();
252
    SCFree(p);
253
    return 0;
254
}
255
#endif /* UNITTESTS */
256
257
void DecodeVLANRegisterTests(void)
258
0
{
259
#ifdef UNITTESTS
260
    UtRegisterTest("DecodeVLANtest01", DecodeVLANtest01);
261
    UtRegisterTest("DecodeVLANtest02", DecodeVLANtest02);
262
    UtRegisterTest("DecodeVLANtest03", DecodeVLANtest03);
263
#endif /* UNITTESTS */
264
0
}
265
266
/**
267
 * @}
268
 */