Coverage Report

Created: 2025-07-23 07:29

/src/suricata7/src/decode-mpls.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2014-2021 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
 * \file
20
 *
21
 * \author Jason Ish <jason.ish@emulex.com>
22
 *
23
 * MPLS decoder.
24
 */
25
26
#include "suricata-common.h"
27
#include "decode.h"
28
29
#include "util-validate.h"
30
#include "util-unittest.h"
31
32
268k
#define MPLS_HEADER_LEN         4
33
27.6k
#define MPLS_PW_LEN             4
34
14.6k
#define MPLS_MAX_RESERVED_LABEL 15
35
36
16.7k
#define MPLS_LABEL_IPV4         0
37
16.1k
#define MPLS_LABEL_ROUTER_ALERT 1
38
15.5k
#define MPLS_LABEL_IPV6         2
39
15.0k
#define MPLS_LABEL_NULL         3
40
41
16.7k
#define MPLS_LABEL(shim)        SCNtohl(shim) >> 12
42
88.1k
#define MPLS_BOTTOM(shim)       ((SCNtohl(shim) >> 8) & 0x1)
43
44
/* Inner protocol guessing values. */
45
6.87k
#define MPLS_PROTO_ETHERNET_PW  0
46
951
#define MPLS_PROTO_IPV4         4
47
1.52k
#define MPLS_PROTO_IPV6         6
48
49
int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
50
        const uint8_t *pkt, uint32_t len)
51
21.3k
{
52
21.3k
    DEBUG_VALIDATE_BUG_ON(pkt == NULL);
53
54
21.3k
    uint32_t shim;
55
21.3k
    int label;
56
21.3k
    uint8_t event = 0;
57
58
21.3k
    StatsIncr(tv, dtv->counter_mpls);
59
60
21.3k
    if (!PacketIncreaseCheckLayers(p)) {
61
186
        return TM_ECODE_FAILED;
62
186
    }
63
92.5k
    do {
64
92.5k
        if (len < MPLS_HEADER_LEN) {
65
4.40k
            ENGINE_SET_INVALID_EVENT(p, MPLS_HEADER_TOO_SMALL);
66
4.40k
            return TM_ECODE_FAILED;
67
4.40k
        }
68
88.1k
        memcpy(&shim, pkt, sizeof(shim));
69
88.1k
        pkt += MPLS_HEADER_LEN;
70
88.1k
        len -= MPLS_HEADER_LEN;
71
88.1k
    } while (MPLS_BOTTOM(shim) == 0);
72
73
16.7k
    label = MPLS_LABEL(shim);
74
16.7k
    if (label == MPLS_LABEL_IPV4) {
75
556
        if (len > USHRT_MAX) {
76
11
            return TM_ECODE_FAILED;
77
11
        }
78
545
        return DecodeIPV4(tv, dtv, p, pkt, (uint16_t)len);
79
556
    }
80
16.1k
    else if (label == MPLS_LABEL_ROUTER_ALERT) {
81
        /* Not valid at the bottom of the stack. */
82
673
        event = MPLS_BAD_LABEL_ROUTER_ALERT;
83
673
    }
84
15.5k
    else if (label == MPLS_LABEL_IPV6) {
85
438
        if (len > USHRT_MAX) {
86
18
            return TM_ECODE_FAILED;
87
18
        }
88
420
        return DecodeIPV6(tv, dtv, p, pkt, (uint16_t)len);
89
438
    }
90
15.0k
    else if (label == MPLS_LABEL_NULL) {
91
        /* Shouldn't appear on the wire. */
92
455
        event = MPLS_BAD_LABEL_IMPLICIT_NULL;
93
455
    }
94
14.6k
    else if (label < MPLS_MAX_RESERVED_LABEL) {
95
683
        event = MPLS_BAD_LABEL_RESERVED;
96
683
    }
97
98
15.7k
    if (event) {
99
1.81k
        goto end;
100
1.81k
    }
101
102
    // Make sure we still have enough data. While we only need 1 byte to test
103
    // for IPv4 and IPv4, we need for to check for ethernet.
104
13.9k
    if (len < MPLS_PW_LEN) {
105
1.55k
        ENGINE_SET_INVALID_EVENT(p, MPLS_PKT_TOO_SMALL);
106
1.55k
        return TM_ECODE_FAILED;
107
1.55k
    }
108
109
    /* Best guess at inner packet. */
110
12.3k
    switch (pkt[0] >> 4) {
111
951
    case MPLS_PROTO_IPV4:
112
951
        if (len > USHRT_MAX) {
113
12
            return TM_ECODE_FAILED;
114
12
        }
115
939
        DecodeIPV4(tv, dtv, p, pkt, (uint16_t)len);
116
939
        break;
117
1.52k
    case MPLS_PROTO_IPV6:
118
1.52k
        if (len > USHRT_MAX) {
119
9
            return TM_ECODE_FAILED;
120
9
        }
121
1.52k
        DecodeIPV6(tv, dtv, p, pkt, (uint16_t)len);
122
1.52k
        break;
123
6.87k
    case MPLS_PROTO_ETHERNET_PW:
124
6.87k
        DecodeEthernet(tv, dtv, p, pkt + MPLS_PW_LEN, len - MPLS_PW_LEN);
125
6.87k
        break;
126
3.04k
    default:
127
3.04k
        ENGINE_SET_INVALID_EVENT(p, MPLS_UNKNOWN_PAYLOAD_TYPE);
128
3.04k
        return TM_ECODE_OK;
129
12.3k
    }
130
131
11.1k
end:
132
11.1k
    if (event) {
133
1.81k
        ENGINE_SET_EVENT(p, event);
134
1.81k
    }
135
11.1k
    return TM_ECODE_OK;
136
12.3k
}
137
138
#ifdef UNITTESTS
139
140
static int DecodeMPLSTestHeaderTooSmall(void)
141
{
142
    /* A packet that is too small to have a complete MPLS header. */
143
    uint8_t pkt[] = {
144
        0x00, 0x00, 0x11
145
    };
146
147
    Packet *p = PacketGetFromAlloc();
148
    FAIL_IF_NULL(p);
149
    ThreadVars tv;
150
    DecodeThreadVars dtv;
151
    memset(&dtv, 0, sizeof(DecodeThreadVars));
152
    memset(&tv,  0, sizeof(ThreadVars));
153
154
    DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
155
    FAIL_IF(!ENGINE_ISSET_EVENT(p, MPLS_HEADER_TOO_SMALL));
156
157
    PacketFree(p);
158
    PASS;
159
}
160
161
static int DecodeMPLSTestPacketTooSmall(void)
162
{
163
    ThreadVars tv;
164
    DecodeThreadVars dtv;
165
    memset(&dtv, 0, sizeof(DecodeThreadVars));
166
    memset(&tv,  0, sizeof(ThreadVars));
167
168
    Packet *p = PacketGetFromAlloc();
169
    FAIL_IF_NULL(p);
170
    uint8_t pkt0[] = { 0x00, 0x01, 0x51, 0xff };
171
    DecodeMPLS(&tv, &dtv, p, pkt0, sizeof(pkt0));
172
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, MPLS_PKT_TOO_SMALL));
173
    PacketFree(p);
174
175
    p = PacketGetFromAlloc();
176
    FAIL_IF_NULL(p);
177
    uint8_t pkt1[] = { 0x00, 0x01, 0x51, 0xff, 0x45 };
178
    DecodeMPLS(&tv, &dtv, p, pkt1, sizeof(pkt1));
179
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, MPLS_PKT_TOO_SMALL));
180
    PacketFree(p);
181
182
    p = PacketGetFromAlloc();
183
    FAIL_IF_NULL(p);
184
    uint8_t pkt2[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01 };
185
    DecodeMPLS(&tv, &dtv, p, pkt2, sizeof(pkt2));
186
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, MPLS_PKT_TOO_SMALL));
187
    PacketFree(p);
188
189
    p = PacketGetFromAlloc();
190
    FAIL_IF_NULL(p);
191
    uint8_t pkt3[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01, 0x02 };
192
    DecodeMPLS(&tv, &dtv, p, pkt3, sizeof(pkt3));
193
    FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, MPLS_PKT_TOO_SMALL));
194
    PacketFree(p);
195
196
    // This should not create a too small event is it has one more byte
197
    // than required.
198
    p = PacketGetFromAlloc();
199
    FAIL_IF_NULL(p);
200
    uint8_t pkt4[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01, 0x02, 0x03 };
201
    DecodeMPLS(&tv, &dtv, p, pkt4, sizeof(pkt4));
202
    FAIL_IF(ENGINE_ISSET_EVENT(p, MPLS_PKT_TOO_SMALL));
203
    PacketFree(p);
204
205
    PASS;
206
}
207
208
static int DecodeMPLSTestBadLabelRouterAlert(void)
209
{
210
    uint8_t pkt[] = {
211
        0x00, 0x00, 0x11, 0xff, 0x45, 0x00, 0x00, 0x64,
212
        0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
213
        0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
214
        0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
215
        0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
216
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
217
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
218
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
219
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
220
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
221
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
222
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
223
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
224
    };
225
226
    Packet *p = PacketGetFromAlloc();
227
    FAIL_IF_NULL(p);
228
    ThreadVars tv;
229
    DecodeThreadVars dtv;
230
231
    memset(&dtv, 0, sizeof(DecodeThreadVars));
232
    memset(&tv,  0, sizeof(ThreadVars));
233
234
    DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
235
    FAIL_IF(!ENGINE_ISSET_EVENT(p, MPLS_BAD_LABEL_ROUTER_ALERT));
236
237
    PacketFree(p);
238
    PASS;
239
}
240
241
static int DecodeMPLSTestBadLabelImplicitNull(void)
242
{
243
    uint8_t pkt[] = {
244
        0x00, 0x00, 0x31, 0xff, 0x45, 0x00, 0x00, 0x64,
245
        0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
246
        0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
247
        0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
248
        0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
249
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
250
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
251
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
252
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
253
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
254
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
255
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
256
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
257
    };
258
259
    Packet *p = PacketGetFromAlloc();
260
    FAIL_IF_NULL(p);
261
    ThreadVars tv;
262
    DecodeThreadVars dtv;
263
    memset(&dtv, 0, sizeof(DecodeThreadVars));
264
    memset(&tv,  0, sizeof(ThreadVars));
265
266
    DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
267
    FAIL_IF(!ENGINE_ISSET_EVENT(p, MPLS_BAD_LABEL_IMPLICIT_NULL));
268
269
    PacketFree(p);
270
    PASS;
271
}
272
273
static int DecodeMPLSTestBadLabelReserved(void)
274
{
275
    uint8_t pkt[] = {
276
        0x00, 0x00, 0x51, 0xff, 0x45, 0x00, 0x00, 0x64,
277
        0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
278
        0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
279
        0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
280
        0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
281
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
282
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
283
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
284
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
285
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
286
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
287
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
288
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
289
    };
290
291
    Packet *p = PacketGetFromAlloc();
292
    FAIL_IF_NULL(p);
293
    ThreadVars tv;
294
    DecodeThreadVars dtv;
295
    memset(&dtv, 0, sizeof(DecodeThreadVars));
296
    memset(&tv,  0, sizeof(ThreadVars));
297
298
    DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
299
    FAIL_IF(!ENGINE_ISSET_EVENT(p, MPLS_BAD_LABEL_RESERVED));
300
301
    PacketFree(p);
302
    PASS;
303
}
304
305
static int DecodeMPLSTestUnknownPayloadType(void)
306
{
307
    /* Valid label: 21.
308
     * Unknown payload type: 1.
309
     */
310
    uint8_t pkt[] = {
311
        0x00, 0x01, 0x51, 0xff, 0x15, 0x00, 0x00, 0x64,
312
        0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
313
        0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
314
        0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
315
        0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
316
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
317
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
318
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
319
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
320
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
321
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
322
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
323
        0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
324
    };
325
326
    Packet *p = PacketGetFromAlloc();
327
    FAIL_IF_NULL(p);
328
    ThreadVars tv;
329
    DecodeThreadVars dtv;
330
    memset(&dtv, 0, sizeof(DecodeThreadVars));
331
    memset(&tv,  0, sizeof(ThreadVars));
332
333
    DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
334
    FAIL_IF(!ENGINE_ISSET_EVENT(p, MPLS_UNKNOWN_PAYLOAD_TYPE));
335
336
    PacketFree(p);
337
    PASS;
338
}
339
340
#endif /* UNITTESTS */
341
342
void DecodeMPLSRegisterTests(void)
343
0
{
344
#ifdef UNITTESTS
345
    UtRegisterTest("DecodeMPLSTestHeaderTooSmall",
346
                   DecodeMPLSTestHeaderTooSmall);
347
    UtRegisterTest("DecodeMPLSTestPacketTooSmall",
348
                   DecodeMPLSTestPacketTooSmall);
349
    UtRegisterTest("DecodeMPLSTestBadLabelRouterAlert",
350
                   DecodeMPLSTestBadLabelRouterAlert);
351
    UtRegisterTest("DecodeMPLSTestBadLabelImplicitNull",
352
                   DecodeMPLSTestBadLabelImplicitNull);
353
    UtRegisterTest("DecodeMPLSTestBadLabelReserved",
354
                   DecodeMPLSTestBadLabelReserved);
355
    UtRegisterTest("DecodeMPLSTestUnknownPayloadType",
356
                   DecodeMPLSTestUnknownPayloadType);
357
#endif /* UNITTESTS */
358
0
}