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

OISF / suricata / 22618661228

02 Mar 2026 09:33PM UTC coverage: 42.258% (-34.4%) from 76.611%
22618661228

push

github

victorjulien
github-actions: bump actions/download-artifact from 7.0.0 to 8.0.0

Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 7.0.0 to 8.0.0.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/37930b1c2...70fc10c6e)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 8.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

91511 of 216553 relevant lines covered (42.26%)

3416852.41 hits per line

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

70.4
/src/decode-vxlan.c
1
/* Copyright (C) 2019-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 Henrik Kramshoej <hlk@kramse.org>
22
 *
23
 * VXLAN tunneling scheme decoder.
24
 *
25
 * This implementation is based on the following specification doc:
26
 * https://tools.ietf.org/html/rfc7348
27
 */
28

29
#include "suricata-common.h"
30
#include "decode.h"
31
#include "decode-vxlan.h"
32
#include "decode-events.h"
33

34
#include "detect.h"
35
#include "detect-engine-port.h"
36

37
#include "flow.h"
38

39
#include "util-validate.h"
40
#include "util-unittest.h"
41
#include "util-debug.h"
42

43
#define VXLAN_HEADER_LEN sizeof(VXLANHeader)
454✔
44

45
#define VXLAN_MAX_PORTS         4
7✔
46
#define VXLAN_UNSET_PORT        -1
16,746✔
47
#define VXLAN_DEFAULT_PORT      4789
48
#define VXLAN_DEFAULT_PORT_S    "4789"
6✔
49

50
typedef enum {
51
    VXLAN_RES_CHECK_STRICT = 0,
52
    VXLAN_RES_CHECK_PERMISSIVE,
53
} VXLANReservedCheckMode;
54

55
static bool g_vxlan_enabled = true;
56
static int g_vxlan_ports_idx = 0;
57
static int g_vxlan_ports[VXLAN_MAX_PORTS] = { VXLAN_DEFAULT_PORT, VXLAN_UNSET_PORT,
58
    VXLAN_UNSET_PORT, VXLAN_UNSET_PORT };
59
static VXLANReservedCheckMode g_vxlan_reserved_check_mode = VXLAN_RES_CHECK_STRICT;
60

61
typedef struct VXLANHeader_ {
62
    uint8_t flags[2];
63
    uint16_t gdp;
64
    uint8_t vni[3];
65
    uint8_t res;
66
} VXLANHeader;
67

68
bool DecodeVXLANEnabledForPort(const uint16_t dp)
69
{
16,746✔
70
    SCLogDebug("checking dest port %u against ports %d %d %d %d", dp, g_vxlan_ports[0],
16,746✔
71
            g_vxlan_ports[1], g_vxlan_ports[2], g_vxlan_ports[3]);
16,746✔
72

73
    if (g_vxlan_enabled) {
16,746✔
74
        for (int i = 0; i < g_vxlan_ports_idx; i++) {
33,371✔
75
            if (g_vxlan_ports[i] == VXLAN_UNSET_PORT)
16,746✔
76
                return false;
×
77
            /* RFC 7348: VXLAN identification is based on destination port only */
78
            if (g_vxlan_ports[i] == (const int)dp)
16,746✔
79
                return true;
121✔
80
        }
16,746✔
81
    }
16,746✔
82
    return false;
16,625✔
83
}
16,746✔
84

85
static void DecodeVXLANConfigPorts(const char *pstr)
86
{
7✔
87
    SCLogDebug("parsing \'%s\'", pstr);
7✔
88

89
    DetectPort *head = NULL;
7✔
90
    DetectPortParse(NULL, &head, pstr);
7✔
91

92
    g_vxlan_ports_idx = 0;
7✔
93
    for (DetectPort *p = head; p != NULL; p = p->next) {
14✔
94
        if (g_vxlan_ports_idx >= VXLAN_MAX_PORTS) {
7✔
95
            SCLogWarning("more than %d VXLAN ports defined", VXLAN_MAX_PORTS);
×
96
            break;
×
97
        }
×
98
        g_vxlan_ports[g_vxlan_ports_idx++] = (int)p->port;
7✔
99
    }
7✔
100

101
    DetectPortCleanupList(NULL, head);
7✔
102
}
7✔
103

104
void DecodeVXLANConfig(void)
105
{
7✔
106
    int enabled = 0;
7✔
107
    if (SCConfGetBool("decoder.vxlan.enabled", &enabled) == 1) {
7✔
108
        if (enabled) {
1✔
109
            g_vxlan_enabled = true;
1✔
110
        } else {
1✔
111
            g_vxlan_enabled = false;
×
112
        }
×
113
    }
1✔
114

115
    if (g_vxlan_enabled) {
7✔
116
        SCConfNode *node = SCConfGetNode("decoder.vxlan.ports");
7✔
117
        if (node && node->val) {
7✔
118
            DecodeVXLANConfigPorts(node->val);
1✔
119
        } else {
7✔
120
            DecodeVXLANConfigPorts(VXLAN_DEFAULT_PORT_S);
6✔
121
        }
6✔
122

123
        node = SCConfGetNode("decoder.vxlan.reserved-bits-check");
7✔
124
        if (node && node->val) {
7✔
125
            if (strcasecmp(node->val, "strict") == 0) {
×
126
                g_vxlan_reserved_check_mode = VXLAN_RES_CHECK_STRICT;
×
127
            } else if (strcasecmp(node->val, "permissive") == 0) {
×
128
                g_vxlan_reserved_check_mode = VXLAN_RES_CHECK_PERMISSIVE;
×
129
            } else {
×
130
                SCLogWarning(
×
131
                        "Invalid VXLAN reserved-bits-check mode '%s', using 'strict'", node->val);
×
132
                g_vxlan_reserved_check_mode = VXLAN_RES_CHECK_STRICT;
×
133
            }
×
134
        }
×
135
    }
7✔
136
}
7✔
137

138
/** \param pkt payload data directly above UDP header
139
 *  \param len length in bytes of pkt
140
 *
141
 *  \note p->flow is not set yet at this point, so we cannot easily
142
 *  check if the flow is unidirectional here.
143
 */
144
int DecodeVXLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
145
        const uint8_t *pkt, uint32_t len)
146
{
121✔
147
    DEBUG_VALIDATE_BUG_ON(pkt == NULL);
121✔
148

149
    /* Initial packet validation */
150
    if (unlikely(!g_vxlan_enabled))
121✔
151
        return TM_ECODE_FAILED;
×
152

153
    if (len < (VXLAN_HEADER_LEN + sizeof(EthernetHdr)))
121✔
154
        return TM_ECODE_FAILED;
×
155
    if (!PacketIncreaseCheckLayers(p)) {
121✔
156
        return TM_ECODE_FAILED;
×
157
    }
×
158

159
    const VXLANHeader *vxlanh = (const VXLANHeader *)pkt;
121✔
160
    if ((vxlanh->flags[0] & 0x08) == 0)
121✔
161
        return TM_ECODE_FAILED;
×
162

163
    switch (g_vxlan_reserved_check_mode) {
121✔
164
        case VXLAN_RES_CHECK_STRICT:
121✔
165
            if ((vxlanh->flags[0] & 0xF7) != 0 || /* All reserved bits are zero except I bit */
121✔
166
                    vxlanh->flags[1] != 0 ||      /* Second byte should be all zeros */
121✔
167
                    vxlanh->gdp != 0 ||           /* GDP field is reserved in standard VXLAN */
121✔
168
                    vxlanh->res != 0) {           /* Last reserved byte should be zero */
121✔
169
                return TM_ECODE_FAILED;
10✔
170
            }
10✔
171
            break;
111✔
172
        case VXLAN_RES_CHECK_PERMISSIVE:
111✔
173
            break;
×
174
    }
121✔
175

176
#if DEBUG
177
    uint32_t vni = (vxlanh->vni[0] << 16) + (vxlanh->vni[1] << 8) + (vxlanh->vni[2]);
178
    SCLogDebug("VXLAN vni %u", vni);
179
#endif
180

181
    /* Increment stats counter for VXLAN packets */
182
    StatsCounterIncr(&tv->stats, dtv->counter_vxlan);
111✔
183

184
    EthernetHdr *ethh = (EthernetHdr *)(pkt + VXLAN_HEADER_LEN);
111✔
185
    bool eth_ok = false;
111✔
186

187
    /* Look at encapsulated Ethernet frame to get next protocol  */
188
    uint16_t eth_type = SCNtohs(ethh->eth_type);
111✔
189
    SCLogDebug("VXLAN ethertype 0x%04x", eth_type);
111✔
190

191
    switch (eth_type) {
111✔
192
        case ETHERNET_TYPE_ARP:
2✔
193
            SCLogDebug("VXLAN found ARP");
2✔
194
            eth_ok = true;
2✔
195
            break;
2✔
196
        case ETHERNET_TYPE_IP:
109✔
197
            SCLogDebug("VXLAN found IPv4");
109✔
198
            eth_ok = true;
109✔
199
            break;
109✔
200
        case ETHERNET_TYPE_IPV6:
×
201
            SCLogDebug("VXLAN found IPv6");
×
202
            eth_ok = true;
×
203
            break;
×
204
        case ETHERNET_TYPE_VLAN:
×
205
        case ETHERNET_TYPE_8021AD:
×
206
        case ETHERNET_TYPE_8021QINQ:
×
207
            SCLogDebug("VXLAN found VLAN");
×
208
            eth_ok = true;
×
209
            break;
×
210
        default:
×
211
            SCLogDebug("VXLAN found unsupported Ethertype - expected IPv4, IPv6, VLAN, or ARP");
×
212
            ENGINE_SET_INVALID_EVENT(p, VXLAN_UNKNOWN_PAYLOAD_TYPE);
×
213
    }
111✔
214

215
    /* Set-up and process inner packet if it is a supported ethertype */
216
    if (eth_ok) {
111✔
217
        Packet *tp = PacketTunnelPktSetup(
111✔
218
                tv, dtv, p, pkt + VXLAN_HEADER_LEN, len - VXLAN_HEADER_LEN, DECODE_TUNNEL_VXLAN);
111✔
219
        if (tp != NULL) {
111✔
220
            PKT_SET_SRC(tp, PKT_SRC_DECODER_VXLAN);
111✔
221
            PacketEnqueueNoLock(&tv->decode_pq, tp);
111✔
222
        }
111✔
223
    }
111✔
224

225
    return TM_ECODE_OK;
111✔
226
}
111✔
227

228
#ifdef UNITTESTS
229
#include "conf-yaml-loader.h"
230

231
/**
232
 * \test DecodeVXLANTest01 test a good vxlan header.
233
 * Contains a DNS request packet.
234
 */
235
static int DecodeVXLANtest01 (void)
236
{
237
    uint8_t raw_vxlan[] = {
238
        0x12, 0xb5, 0x12, 0xb5, 0x00, 0x3a, 0x87, 0x51, /* UDP header */
239
        0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, /* VXLAN header */
240
        0x10, 0x00, 0x00, 0x0c, 0x01, 0x00, /* inner destination MAC */
241
        0x00, 0x51, 0x52, 0xb3, 0x54, 0xe5, /* inner source MAC */
242
        0x08, 0x00, /* another IPv4 0x0800 */
243
        0x45, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
244
        0x44, 0x45, 0x0a, 0x60, 0x00, 0x0a, 0xb9, 0x1b, 0x73, 0x06,  /* IPv4 hdr */
245
        0x00, 0x35, 0x30, 0x39, 0x00, 0x08, 0x98, 0xe4 /* UDP probe src port 53 */
246
    };
247
    Packet *p = PacketGetFromAlloc();
248
    FAIL_IF_NULL(p);
249
    ThreadVars tv;
250
    DecodeThreadVars dtv;
251
    memset(&tv, 0, sizeof(ThreadVars));
252
    memset(&dtv, 0, sizeof(DecodeThreadVars));
253

254
    DecodeVXLANConfigPorts(VXLAN_DEFAULT_PORT_S);
255
    FlowInitConfig(FLOW_QUIET);
256

257
    DecodeUDP(&tv, &dtv, p, raw_vxlan, sizeof(raw_vxlan));
258
    FAIL_IF_NOT(PacketIsUDP(p));
259
    FAIL_IF(tv.decode_pq.top == NULL);
260

261
    Packet *tp = PacketDequeueNoLock(&tv.decode_pq);
262
    FAIL_IF_NOT(PacketIsUDP(tp));
263
    FAIL_IF_NOT(tp->sp == 53);
264

265
    FlowShutdown();
266
    PacketFree(p);
267
    PacketFreeOrRelease(tp);
268
    PASS;
269
}
270

271
/**
272
 * \test DecodeVXLANtest02 tests default port disabled by the config.
273
 */
274
static int DecodeVXLANtest02 (void)
275
{
276
    uint8_t raw_vxlan[] = {
277
        0x12, 0xb5, 0x12, 0xb5, 0x00, 0x3a, 0x87, 0x51, /* UDP header */
278
        0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, /* VXLAN header */
279
        0x10, 0x00, 0x00, 0x0c, 0x01, 0x00, /* inner destination MAC */
280
        0x00, 0x51, 0x52, 0xb3, 0x54, 0xe5, /* inner source MAC */
281
        0x08, 0x00, /* another IPv4 0x0800 */
282
        0x45, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
283
        0x44, 0x45, 0x0a, 0x60, 0x00, 0x0a, 0xb9, 0x1b, 0x73, 0x06,  /* IPv4 hdr */
284
        0x00, 0x35, 0x30, 0x39, 0x00, 0x08, 0x98, 0xe4 /* UDP probe src port 53 */
285
    };
286
    Packet *p = PacketGetFromAlloc();
287
    FAIL_IF_NULL(p);
288
    ThreadVars tv;
289
    DecodeThreadVars dtv;
290
    memset(&tv, 0, sizeof(ThreadVars));
291
    memset(&dtv, 0, sizeof(DecodeThreadVars));
292

293
    DecodeVXLANConfigPorts("1");
294
    FlowInitConfig(FLOW_QUIET);
295

296
    DecodeUDP(&tv, &dtv, p, raw_vxlan, sizeof(raw_vxlan));
297
    FAIL_IF_NOT(PacketIsUDP(p));
298
    FAIL_IF(tv.decode_pq.top != NULL);
299

300
    DecodeVXLANConfigPorts(VXLAN_DEFAULT_PORT_S); /* reset */
301
    FlowShutdown();
302
    PacketFree(p);
303
    PASS;
304
}
305

306
/**
307
 * \test DecodeVXLANtest03 tests the non-zero res field on receiver side.
308
 * Contains a HTTP response packet.
309
 */
310
static int DecodeVXLANtest03(void)
311
{
312
    uint8_t raw_vxlan[] = {
313
        0xc0, 0x00, 0x12, 0xb5, 0x00, 0x57, 0x00, 0x00, /* UDP header */
314
        0xff, 0x01, 0xd2, 0x0a, 0x00, 0x00, 0x0b, 0x01, /* VXLAN header (res = 0x01) */
315
        0xfa, 0x16, 0x3e, 0xfe, 0x55, 0x1c,             /* inner destination MAC */
316
        0xfa, 0x16, 0x3e, 0xfe, 0x57, 0xdc,             /* inner source MAC */
317
        0x08, 0x00,                                     /* another IPv4 0x0800 */
318
        0x45, 0x00, 0x00, 0x39, 0xc2, 0xae, 0x40, 0x00, 0x40, 0x06, 0x7e, 0x61, 0xc0, 0xa8, 0x01,
319
        0x86, 0xda, 0x5e, 0x5d, 0x22, /* IPv4 hdr */
320
        0x00, 0x50, 0xc8, 0x34, 0xaf, 0xbd, 0x02, 0x16, 0x56, 0xea, 0x3b, 0x41, 0x50, 0x18, 0x00,
321
        0xee, 0xf9, 0xda, 0x00, 0x00, /* TCP probe src port 80 */
322
        0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b,
323
        0xd, 0xa /* HTTP response (HTTP/1.0 200 OK\r\n) */
324
    };
325
    char config[] = "\
326
%YAML 1.1\n\
327
---\n\
328
decoder:\n\
329
\n\
330
  vxlan:\n\
331
    enabled: true\n\
332
    ports: \"4789\"\n\
333
    reserved-bits-check: permissive\n\
334
";
335

336
    SCConfCreateContextBackup();
337
    SCConfInit();
338
    SCConfYamlLoadString(config, strlen(config));
339

340
    Packet *p = PacketGetFromAlloc();
341
    FAIL_IF_NULL(p);
342
    ThreadVars tv;
343
    DecodeThreadVars dtv;
344
    memset(&tv, 0, sizeof(ThreadVars));
345
    memset(&dtv, 0, sizeof(DecodeThreadVars));
346

347
    DecodeVXLANConfig();
348
    DecodeVXLANConfigPorts(VXLAN_DEFAULT_PORT_S);
349
    FlowInitConfig(FLOW_QUIET);
350

351
    DecodeUDP(&tv, &dtv, p, raw_vxlan, sizeof(raw_vxlan));
352
    FAIL_IF_NOT(PacketIsUDP(p));
353
    FAIL_IF(tv.decode_pq.top == NULL);
354

355
    Packet *tp = PacketDequeueNoLock(&tv.decode_pq);
356
    FAIL_IF_NOT(PacketIsTCP(tp));
357
    FAIL_IF_NOT(tp->sp == 80);
358

359
    FlowShutdown();
360
    PacketFree(p);
361
    PacketFreeOrRelease(tp);
362
    SCConfDeInit();
363
    SCConfRestoreContextBackup();
364
    PASS;
365
}
366

367
/**
368
 * \test DecodeVXLANtest04 tests strict mode with standard VXLAN header.
369
 */
370
static int DecodeVXLANtest04(void)
371
{
372
    uint8_t raw_vxlan[] = {
373
        0x12, 0xb5, 0x12, 0xb5, 0x00, 0x3a, 0x87, 0x51, /* UDP header */
374
        0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, /* VXLAN header (strict compliant) */
375
        0x10, 0x00, 0x00, 0x0c, 0x01, 0x00,             /* inner destination MAC */
376
        0x00, 0x51, 0x52, 0xb3, 0x54, 0xe5,             /* inner source MAC */
377
        0x08, 0x00,                                     /* another IPv4 0x0800 */
378
        0x45, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11, 0x44, 0x45, 0x0a, 0x60, 0x00,
379
        0x0a, 0xb9, 0x1b, 0x73, 0x06,                  /* IPv4 hdr */
380
        0x00, 0x35, 0x30, 0x39, 0x00, 0x08, 0x98, 0xe4 /* UDP probe src port 53 */
381
    };
382
    char config[] = "\
383
%YAML 1.1\n\
384
---\n\
385
decoder:\n\
386
\n\
387
  vxlan:\n\
388
    enabled: true\n\
389
    ports: \"4789\"\n\
390
    reserved-bits-check: strict\n\
391
";
392

393
    SCConfCreateContextBackup();
394
    SCConfInit();
395
    SCConfYamlLoadString(config, strlen(config));
396

397
    Packet *p = PacketGetFromAlloc();
398
    FAIL_IF_NULL(p);
399
    ThreadVars tv;
400
    DecodeThreadVars dtv;
401
    memset(&tv, 0, sizeof(ThreadVars));
402
    memset(&dtv, 0, sizeof(DecodeThreadVars));
403

404
    DecodeVXLANConfig();
405
    DecodeVXLANConfigPorts(VXLAN_DEFAULT_PORT_S);
406
    FlowInitConfig(FLOW_QUIET);
407

408
    DecodeUDP(&tv, &dtv, p, raw_vxlan, sizeof(raw_vxlan));
409
    FAIL_IF_NOT(PacketIsUDP(p));
410
    FAIL_IF(tv.decode_pq.top == NULL);
411

412
    Packet *tp = PacketDequeueNoLock(&tv.decode_pq);
413
    FAIL_IF_NOT(PacketIsUDP(tp));
414
    FAIL_IF_NOT(tp->sp == 53);
415

416
    FlowShutdown();
417
    PacketFree(p);
418
    PacketFreeOrRelease(tp);
419
    SCConfDeInit();
420
    SCConfRestoreContextBackup();
421
    PASS;
422
}
423

424
/**
425
 * \test DecodeVXLANtest05 tests strict mode with GBP header (should fail).
426
 */
427
static int DecodeVXLANtest05(void)
428
{
429
    uint8_t raw_vxlan[] = {
430
        0x12, 0xb5, 0x12, 0xb5, 0x00, 0x3a, 0x87, 0x51, /* UDP header */
431
        0x88, 0x00, 0x12, 0x34, 0x00, 0x00, 0x25,
432
        0x00,                               /* VXLAN-GBP header (G bit set, Group Policy ID) */
433
        0x10, 0x00, 0x00, 0x0c, 0x01, 0x00, /* inner destination MAC */
434
        0x00, 0x51, 0x52, 0xb3, 0x54, 0xe5, /* inner source MAC */
435
        0x08, 0x00,                         /* another IPv4 0x0800 */
436
        0x45, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11, 0x44, 0x45, 0x0a, 0x60, 0x00,
437
        0x0a, 0xb9, 0x1b, 0x73, 0x06,                  /* IPv4 hdr */
438
        0x00, 0x35, 0x30, 0x39, 0x00, 0x08, 0x98, 0xe4 /* UDP probe src port 53 */
439
    };
440
    char config[] = "\
441
%YAML 1.1\n\
442
---\n\
443
decoder:\n\
444
\n\
445
  vxlan:\n\
446
    enabled: true\n\
447
    ports: \"4789\"\n\
448
    reserved-bits-check: strict\n\
449
";
450

451
    SCConfCreateContextBackup();
452
    SCConfInit();
453
    SCConfYamlLoadString(config, strlen(config));
454

455
    Packet *p = PacketGetFromAlloc();
456
    FAIL_IF_NULL(p);
457
    ThreadVars tv;
458
    DecodeThreadVars dtv;
459
    memset(&tv, 0, sizeof(ThreadVars));
460
    memset(&dtv, 0, sizeof(DecodeThreadVars));
461

462
    DecodeVXLANConfig();
463
    DecodeVXLANConfigPorts(VXLAN_DEFAULT_PORT_S);
464
    FlowInitConfig(FLOW_QUIET);
465

466
    DecodeUDP(&tv, &dtv, p, raw_vxlan, sizeof(raw_vxlan));
467
    FAIL_IF_NOT(PacketIsUDP(p));
468
    /* Should fail to decode VXLAN in strict mode */
469
    FAIL_IF(tv.decode_pq.top != NULL);
470

471
    FlowShutdown();
472
    PacketFree(p);
473
    SCConfDeInit();
474
    SCConfRestoreContextBackup();
475
    PASS;
476
}
477

478
/**
479
 * \test DecodeVXLANtest06 tests permissive mode with GBP header (should pass).
480
 */
481
static int DecodeVXLANtest06(void)
482
{
483
    uint8_t raw_vxlan[] = {
484
        0x12, 0xb5, 0x12, 0xb5, 0x00, 0x3a, 0x87, 0x51, /* UDP header */
485
        0x88, 0x00, 0x12, 0x34, 0x00, 0x00, 0x25,
486
        0x00,                               /* VXLAN-GBP header (G bit set, Group Policy ID) */
487
        0x10, 0x00, 0x00, 0x0c, 0x01, 0x00, /* inner destination MAC */
488
        0x00, 0x51, 0x52, 0xb3, 0x54, 0xe5, /* inner source MAC */
489
        0x08, 0x00,                         /* another IPv4 0x0800 */
490
        0x45, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11, 0x44, 0x45, 0x0a, 0x60, 0x00,
491
        0x0a, 0xb9, 0x1b, 0x73, 0x06,                  /* IPv4 hdr */
492
        0x00, 0x35, 0x30, 0x39, 0x00, 0x08, 0x98, 0xe4 /* UDP probe src port 53 */
493
    };
494
    char config[] = "\
495
%YAML 1.1\n\
496
---\n\
497
decoder:\n\
498
\n\
499
  vxlan:\n\
500
    enabled: true\n\
501
    ports: \"4789\"\n\
502
    reserved-bits-check: permissive\n\
503
";
504

505
    SCConfCreateContextBackup();
506
    SCConfInit();
507
    SCConfYamlLoadString(config, strlen(config));
508

509
    Packet *p = PacketGetFromAlloc();
510
    FAIL_IF_NULL(p);
511
    ThreadVars tv;
512
    DecodeThreadVars dtv;
513
    memset(&tv, 0, sizeof(ThreadVars));
514
    memset(&dtv, 0, sizeof(DecodeThreadVars));
515

516
    DecodeVXLANConfig();
517
    DecodeVXLANConfigPorts(VXLAN_DEFAULT_PORT_S);
518
    FlowInitConfig(FLOW_QUIET);
519

520
    DecodeUDP(&tv, &dtv, p, raw_vxlan, sizeof(raw_vxlan));
521
    FAIL_IF_NOT(PacketIsUDP(p));
522
    FAIL_IF(tv.decode_pq.top == NULL);
523

524
    Packet *tp = PacketDequeueNoLock(&tv.decode_pq);
525
    FAIL_IF_NOT(PacketIsUDP(tp));
526
    FAIL_IF_NOT(tp->sp == 53);
527

528
    FlowShutdown();
529
    PacketFree(p);
530
    PacketFreeOrRelease(tp);
531
    SCConfDeInit();
532
    SCConfRestoreContextBackup();
533
    PASS;
534
}
535

536
/**
537
 * \test DecodeVXLANtest07 tests that only destination port is checked for VXLAN identification.
538
 * Source port 4789, destination port 53 DNS query should NOT be VXLAN.
539
 */
540
static int DecodeVXLANtest07(void)
541
{
542
    uint8_t raw_dns[] = {
543
        0x12, 0xb5, 0x00, 0x35, 0x00, 0x24, 0xb9, 0xd7, /* UDP header (sp=4789, dp=53) */
544
        0x49, 0xa1, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x67, 0x6f,
545
        0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x1d, 0x00,
546
        0x01 /* DNS query (google.com) */
547
    };
548

549
    Packet *p = PacketGetFromAlloc();
550
    FAIL_IF_NULL(p);
551
    ThreadVars tv;
552
    DecodeThreadVars dtv;
553
    memset(&tv, 0, sizeof(ThreadVars));
554
    memset(&dtv, 0, sizeof(DecodeThreadVars));
555

556
    DecodeVXLANConfigPorts(VXLAN_DEFAULT_PORT_S);
557
    FlowInitConfig(FLOW_QUIET);
558

559
    DecodeUDP(&tv, &dtv, p, raw_dns, sizeof(raw_dns));
560
    FAIL_IF_NOT(PacketIsUDP(p));
561

562
    /* Should not be VXLAN packet, and not invalid packet */
563
    FAIL_IF(DecodeVXLANEnabledForPort(p->dp));
564
    FAIL_IF(tv.decode_pq.top != NULL);
565
    FAIL_IF(p->flags & PKT_IS_INVALID);
566

567
    FlowShutdown();
568
    PacketFree(p);
569
    PASS;
570
}
571
#endif /* UNITTESTS */
572

573
void DecodeVXLANRegisterTests(void)
574
{
×
575
#ifdef UNITTESTS
576
    UtRegisterTest("DecodeVXLANtest01",
577
                   DecodeVXLANtest01);
578
    UtRegisterTest("DecodeVXLANtest02",
579
                   DecodeVXLANtest02);
580
    UtRegisterTest("DecodeVXLANtest03", DecodeVXLANtest03);
581
    UtRegisterTest("DecodeVXLANtest04", DecodeVXLANtest04);
582
    UtRegisterTest("DecodeVXLANtest05", DecodeVXLANtest05);
583
    UtRegisterTest("DecodeVXLANtest06", DecodeVXLANtest06);
584
    UtRegisterTest("DecodeVXLANtest07", DecodeVXLANtest07);
585
#endif /* UNITTESTS */
586
}
×
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