suricata
decode-mpls.c
Go to the documentation of this file.
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 
31 #define MPLS_HEADER_LEN 4
32 #define MPLS_PW_LEN 4
33 #define MPLS_MAX_RESERVED_LABEL 15
34 
35 #define MPLS_LABEL_IPV4 0
36 #define MPLS_LABEL_ROUTER_ALERT 1
37 #define MPLS_LABEL_IPV6 2
38 #define MPLS_LABEL_NULL 3
39 
40 #define MPLS_LABEL(shim) SCNtohl(shim) >> 12
41 #define MPLS_BOTTOM(shim) ((SCNtohl(shim) >> 8) & 0x1)
42 
43 /* Inner protocol guessing values. */
44 #define MPLS_PROTO_ETHERNET_PW 0
45 #define MPLS_PROTO_IPV4 4
46 #define MPLS_PROTO_IPV6 6
47 
49  const uint8_t *pkt, uint32_t len)
50 {
51  DEBUG_VALIDATE_BUG_ON(pkt == NULL);
52 
53  uint32_t shim;
54  int label;
55  uint8_t event = 0;
56 
58 
59  if (!PacketIncreaseCheckLayers(p)) {
60  return TM_ECODE_FAILED;
61  }
62  do {
63  if (len < MPLS_HEADER_LEN) {
65  return TM_ECODE_FAILED;
66  }
67  memcpy(&shim, pkt, sizeof(shim));
68  pkt += MPLS_HEADER_LEN;
70  } while (MPLS_BOTTOM(shim) == 0);
71 
72  label = MPLS_LABEL(shim);
73  if (label == MPLS_LABEL_IPV4) {
74  if (len > USHRT_MAX) {
75  return TM_ECODE_FAILED;
76  }
77  return DecodeIPV4(tv, dtv, p, pkt, (uint16_t)len);
78  }
79  else if (label == MPLS_LABEL_ROUTER_ALERT) {
80  /* Not valid at the bottom of the stack. */
82  }
83  else if (label == MPLS_LABEL_IPV6) {
84  return DecodeIPV6(tv, dtv, p, pkt, len);
85  }
86  else if (label == MPLS_LABEL_NULL) {
87  /* Shouldn't appear on the wire. */
89  }
90  else if (label < MPLS_MAX_RESERVED_LABEL) {
92  }
93 
94  if (event) {
95  goto end;
96  }
97 
98  // Make sure we still have enough data. While we only need 1 byte to test
99  // for IPv4 and IPv4, we need for to check for ethernet.
100  if (len < MPLS_PW_LEN) {
102  return TM_ECODE_FAILED;
103  }
104 
105  /* Best guess at inner packet. */
106  switch (pkt[0] >> 4) {
107  case MPLS_PROTO_IPV4:
108  if (len > USHRT_MAX) {
109  return TM_ECODE_FAILED;
110  }
111  DecodeIPV4(tv, dtv, p, pkt, (uint16_t)len);
112  break;
113  case MPLS_PROTO_IPV6:
114  DecodeIPV6(tv, dtv, p, pkt, len);
115  break;
118  break;
119  default:
121  return TM_ECODE_OK;
122  }
123 
124 end:
125  if (event) {
126  ENGINE_SET_EVENT(p, event);
127  }
128  return TM_ECODE_OK;
129 }
130 
131 #ifdef UNITTESTS
132 
133 static int DecodeMPLSTestHeaderTooSmall(void)
134 {
135  /* A packet that is too small to have a complete MPLS header. */
136  uint8_t pkt[] = {
137  0x00, 0x00, 0x11
138  };
139 
141  FAIL_IF_NULL(p);
142  ThreadVars tv;
144  memset(&dtv, 0, sizeof(DecodeThreadVars));
145  memset(&tv, 0, sizeof(ThreadVars));
146 
147  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
149 
150  PacketFree(p);
151  PASS;
152 }
153 
154 static int DecodeMPLSTestPacketTooSmall(void)
155 {
156  ThreadVars tv;
158  memset(&dtv, 0, sizeof(DecodeThreadVars));
159  memset(&tv, 0, sizeof(ThreadVars));
160 
162  FAIL_IF_NULL(p);
163  uint8_t pkt0[] = { 0x00, 0x01, 0x51, 0xff };
164  DecodeMPLS(&tv, &dtv, p, pkt0, sizeof(pkt0));
166  PacketFree(p);
167 
168  p = PacketGetFromAlloc();
169  FAIL_IF_NULL(p);
170  uint8_t pkt1[] = { 0x00, 0x01, 0x51, 0xff, 0x45 };
171  DecodeMPLS(&tv, &dtv, p, pkt1, sizeof(pkt1));
173  PacketFree(p);
174 
175  p = PacketGetFromAlloc();
176  FAIL_IF_NULL(p);
177  uint8_t pkt2[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01 };
178  DecodeMPLS(&tv, &dtv, p, pkt2, sizeof(pkt2));
180  PacketFree(p);
181 
182  p = PacketGetFromAlloc();
183  FAIL_IF_NULL(p);
184  uint8_t pkt3[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01, 0x02 };
185  DecodeMPLS(&tv, &dtv, p, pkt3, sizeof(pkt3));
187  PacketFree(p);
188 
189  // This should not create a too small event is it has one more byte
190  // than required.
191  p = PacketGetFromAlloc();
192  FAIL_IF_NULL(p);
193  uint8_t pkt4[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01, 0x02, 0x03 };
194  DecodeMPLS(&tv, &dtv, p, pkt4, sizeof(pkt4));
196  PacketFree(p);
197 
198  PASS;
199 }
200 
201 static int DecodeMPLSTestBadLabelRouterAlert(void)
202 {
203  uint8_t pkt[] = {
204  0x00, 0x00, 0x11, 0xff, 0x45, 0x00, 0x00, 0x64,
205  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
206  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
207  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
208  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
209  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
210  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
211  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
212  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
213  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
214  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
215  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
216  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
217  };
218 
220  FAIL_IF_NULL(p);
221  ThreadVars tv;
223 
224  memset(&dtv, 0, sizeof(DecodeThreadVars));
225  memset(&tv, 0, sizeof(ThreadVars));
226 
227  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
229 
230  PacketFree(p);
231  PASS;
232 }
233 
234 static int DecodeMPLSTestBadLabelImplicitNull(void)
235 {
236  uint8_t pkt[] = {
237  0x00, 0x00, 0x31, 0xff, 0x45, 0x00, 0x00, 0x64,
238  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
239  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
240  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
241  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
242  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
243  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
244  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
245  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
246  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
247  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
248  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
249  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
250  };
251 
253  FAIL_IF_NULL(p);
254  ThreadVars tv;
256  memset(&dtv, 0, sizeof(DecodeThreadVars));
257  memset(&tv, 0, sizeof(ThreadVars));
258 
259  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
261 
262  PacketFree(p);
263  PASS;
264 }
265 
266 static int DecodeMPLSTestBadLabelReserved(void)
267 {
268  uint8_t pkt[] = {
269  0x00, 0x00, 0x51, 0xff, 0x45, 0x00, 0x00, 0x64,
270  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
271  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
272  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
273  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
274  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
275  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
276  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
277  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
278  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
279  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
280  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
281  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
282  };
283 
285  FAIL_IF_NULL(p);
286  ThreadVars tv;
288  memset(&dtv, 0, sizeof(DecodeThreadVars));
289  memset(&tv, 0, sizeof(ThreadVars));
290 
291  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
293 
294  PacketFree(p);
295  PASS;
296 }
297 
298 static int DecodeMPLSTestUnknownPayloadType(void)
299 {
300  /* Valid label: 21.
301  * Unknown payload type: 1.
302  */
303  uint8_t pkt[] = {
304  0x00, 0x01, 0x51, 0xff, 0x15, 0x00, 0x00, 0x64,
305  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
306  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
307  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
308  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
309  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
310  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
311  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
312  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
313  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
314  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
315  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
316  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
317  };
318 
320  FAIL_IF_NULL(p);
321  ThreadVars tv;
323  memset(&dtv, 0, sizeof(DecodeThreadVars));
324  memset(&tv, 0, sizeof(ThreadVars));
325 
326  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
328 
329  PacketFree(p);
330  PASS;
331 }
332 
333 #endif /* UNITTESTS */
334 
336 {
337 #ifdef UNITTESTS
338  UtRegisterTest("DecodeMPLSTestHeaderTooSmall",
339  DecodeMPLSTestHeaderTooSmall);
340  UtRegisterTest("DecodeMPLSTestPacketTooSmall",
341  DecodeMPLSTestPacketTooSmall);
342  UtRegisterTest("DecodeMPLSTestBadLabelRouterAlert",
343  DecodeMPLSTestBadLabelRouterAlert);
344  UtRegisterTest("DecodeMPLSTestBadLabelImplicitNull",
345  DecodeMPLSTestBadLabelImplicitNull);
346  UtRegisterTest("DecodeMPLSTestBadLabelReserved",
347  DecodeMPLSTestBadLabelReserved);
348  UtRegisterTest("DecodeMPLSTestUnknownPayloadType",
349  DecodeMPLSTestUnknownPayloadType);
350 #endif /* UNITTESTS */
351 }
ENGINE_SET_EVENT
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:1231
len
uint8_t len
Definition: app-layer-dnp3.h:2
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:101
ENGINE_ISSET_EVENT
#define ENGINE_ISSET_EVENT(p, e)
Definition: decode.h:1244
MPLS_PROTO_IPV6
#define MPLS_PROTO_IPV6
Definition: decode-mpls.c:46
MPLS_MAX_RESERVED_LABEL
#define MPLS_MAX_RESERVED_LABEL
Definition: decode-mpls.c:33
MPLS_BOTTOM
#define MPLS_BOTTOM(shim)
Definition: decode-mpls.c:41
MPLS_HEADER_LEN
#define MPLS_HEADER_LEN
Definition: decode-mpls.c:31
p
Packet * p
Definition: fuzz_dataset.c:30
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:82
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:81
MPLS_LABEL_NULL
#define MPLS_LABEL_NULL
Definition: decode-mpls.c:38
DecodeMPLSRegisterTests
void DecodeMPLSRegisterTests(void)
Definition: decode-mpls.c:335
decode.h
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
MPLS_UNKNOWN_PAYLOAD_TYPE
@ MPLS_UNKNOWN_PAYLOAD_TYPE
Definition: decode-events.h:212
MPLS_BAD_LABEL_ROUTER_ALERT
@ MPLS_BAD_LABEL_ROUTER_ALERT
Definition: decode-events.h:209
MPLS_PKT_TOO_SMALL
@ MPLS_PKT_TOO_SMALL
Definition: decode-events.h:208
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
MPLS_PROTO_ETHERNET_PW
#define MPLS_PROTO_ETHERNET_PW
Definition: decode-mpls.c:44
StatsCounterIncr
void StatsCounterIncr(StatsThreadContext *stats, StatsCounterId id)
Increments the local counter.
Definition: counters.c:163
PacketFree
void PacketFree(Packet *p)
Return a malloced packet.
Definition: decode.c:221
DecodeMPLS
int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-mpls.c:48
MPLS_BAD_LABEL_IMPLICIT_NULL
@ MPLS_BAD_LABEL_IMPLICIT_NULL
Definition: decode-events.h:210
MPLS_LABEL
#define MPLS_LABEL(shim)
Definition: decode-mpls.c:40
Packet_
Definition: decode.h:516
MPLS_PROTO_IPV4
#define MPLS_PROTO_IPV4
Definition: decode-mpls.c:45
DecodeIPV6
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ipv6.c:551
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:35
MPLS_LABEL_ROUTER_ALERT
#define MPLS_LABEL_ROUTER_ALERT
Definition: decode-mpls.c:36
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
suricata-common.h
MPLS_LABEL_IPV4
#define MPLS_LABEL_IPV4
Definition: decode-mpls.c:35
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:34
util-validate.h
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:260
MPLS_LABEL_IPV6
#define MPLS_LABEL_IPV6
Definition: decode-mpls.c:37
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:995
DecodeThreadVars_::counter_mpls
StatsCounterId counter_mpls
Definition: decode.h:1048
ENGINE_SET_INVALID_EVENT
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition: decode.h:1239
MPLS_HEADER_TOO_SMALL
@ MPLS_HEADER_TOO_SMALL
Definition: decode-events.h:207
DecodeIPV4
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
Definition: decode-ipv4.c:515
ThreadVars_::stats
StatsThreadContext stats
Definition: threadvars.h:120
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:109
DecodeEthernet
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ethernet.c:41
MPLS_BAD_LABEL_RESERVED
@ MPLS_BAD_LABEL_RESERVED
Definition: decode-events.h:211
MPLS_PW_LEN
#define MPLS_PW_LEN
Definition: decode-mpls.c:32