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 #include "util-unittest.h"
31 
32 #define MPLS_HEADER_LEN 4
33 #define MPLS_PW_LEN 4
34 #define MPLS_MAX_RESERVED_LABEL 15
35 
36 #define MPLS_LABEL_IPV4 0
37 #define MPLS_LABEL_ROUTER_ALERT 1
38 #define MPLS_LABEL_IPV6 2
39 #define MPLS_LABEL_NULL 3
40 
41 #define MPLS_LABEL(shim) SCNtohl(shim) >> 12
42 #define MPLS_BOTTOM(shim) ((SCNtohl(shim) >> 8) & 0x1)
43 
44 /* Inner protocol guessing values. */
45 #define MPLS_PROTO_ETHERNET_PW 0
46 #define MPLS_PROTO_IPV4 4
47 #define MPLS_PROTO_IPV6 6
48 
50  const uint8_t *pkt, uint32_t len)
51 {
52  DEBUG_VALIDATE_BUG_ON(pkt == NULL);
53 
54  uint32_t shim;
55  int label;
56  uint8_t event = 0;
57 
59 
60  if (!PacketIncreaseCheckLayers(p)) {
61  return TM_ECODE_FAILED;
62  }
63  do {
64  if (len < MPLS_HEADER_LEN) {
66  return TM_ECODE_FAILED;
67  }
68  memcpy(&shim, pkt, sizeof(shim));
69  pkt += MPLS_HEADER_LEN;
71  } while (MPLS_BOTTOM(shim) == 0);
72 
73  label = MPLS_LABEL(shim);
74  if (label == MPLS_LABEL_IPV4) {
75  if (len > USHRT_MAX) {
76  return TM_ECODE_FAILED;
77  }
78  return DecodeIPV4(tv, dtv, p, pkt, (uint16_t)len);
79  }
80  else if (label == MPLS_LABEL_ROUTER_ALERT) {
81  /* Not valid at the bottom of the stack. */
83  }
84  else if (label == MPLS_LABEL_IPV6) {
85  if (len > USHRT_MAX) {
86  return TM_ECODE_FAILED;
87  }
88  return DecodeIPV6(tv, dtv, p, pkt, (uint16_t)len);
89  }
90  else if (label == MPLS_LABEL_NULL) {
91  /* Shouldn't appear on the wire. */
93  }
94  else if (label < MPLS_MAX_RESERVED_LABEL) {
96  }
97 
98  if (event) {
99  goto end;
100  }
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  if (len < MPLS_PW_LEN) {
106  return TM_ECODE_FAILED;
107  }
108 
109  /* Best guess at inner packet. */
110  switch (pkt[0] >> 4) {
111  case MPLS_PROTO_IPV4:
112  if (len > USHRT_MAX) {
113  return TM_ECODE_FAILED;
114  }
115  DecodeIPV4(tv, dtv, p, pkt, (uint16_t)len);
116  break;
117  case MPLS_PROTO_IPV6:
118  if (len > USHRT_MAX) {
119  return TM_ECODE_FAILED;
120  }
121  DecodeIPV6(tv, dtv, p, pkt, (uint16_t)len);
122  break;
125  break;
126  default:
128  return TM_ECODE_OK;
129  }
130 
131 end:
132  if (event) {
133  ENGINE_SET_EVENT(p, event);
134  }
135  return TM_ECODE_OK;
136 }
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;
151  memset(&dtv, 0, sizeof(DecodeThreadVars));
152  memset(&tv, 0, sizeof(ThreadVars));
153 
154  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
156 
157  PacketFree(p);
158  PASS;
159 }
160 
161 static int DecodeMPLSTestPacketTooSmall(void)
162 {
163  ThreadVars tv;
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));
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));
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));
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));
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));
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;
230 
231  memset(&dtv, 0, sizeof(DecodeThreadVars));
232  memset(&tv, 0, sizeof(ThreadVars));
233 
234  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
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;
263  memset(&dtv, 0, sizeof(DecodeThreadVars));
264  memset(&tv, 0, sizeof(ThreadVars));
265 
266  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
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;
295  memset(&dtv, 0, sizeof(DecodeThreadVars));
296  memset(&tv, 0, sizeof(ThreadVars));
297 
298  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
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;
330  memset(&dtv, 0, sizeof(DecodeThreadVars));
331  memset(&tv, 0, sizeof(ThreadVars));
332 
333  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
335 
336  PacketFree(p);
337  PASS;
338 }
339 
340 #endif /* UNITTESTS */
341 
343 {
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 }
ENGINE_SET_EVENT
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:904
MPLS_BAD_LABEL_RESERVED
@ MPLS_BAD_LABEL_RESERVED
Definition: decode-events.h:192
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
StatsIncr
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:167
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
ENGINE_ISSET_EVENT
#define ENGINE_ISSET_EVENT(p, e)
Definition: decode.h:919
MPLS_PROTO_IPV6
#define MPLS_PROTO_IPV6
Definition: decode-mpls.c:47
MPLS_MAX_RESERVED_LABEL
#define MPLS_MAX_RESERVED_LABEL
Definition: decode-mpls.c:34
MPLS_BOTTOM
#define MPLS_BOTTOM(shim)
Definition: decode-mpls.c:42
MPLS_HEADER_LEN
#define MPLS_HEADER_LEN
Definition: decode-mpls.c:32
MPLS_HEADER_TOO_SMALL
@ MPLS_HEADER_TOO_SMALL
Definition: decode-events.h:188
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:85
MPLS_BAD_LABEL_IMPLICIT_NULL
@ MPLS_BAD_LABEL_IMPLICIT_NULL
Definition: decode-events.h:191
util-unittest.h
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:84
MPLS_LABEL_NULL
#define MPLS_LABEL_NULL
Definition: decode-mpls.c:39
DecodeMPLSRegisterTests
void DecodeMPLSRegisterTests(void)
Definition: decode-mpls.c:342
decode.h
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
MPLS_PROTO_ETHERNET_PW
#define MPLS_PROTO_ETHERNET_PW
Definition: decode-mpls.c:45
PacketFree
void PacketFree(Packet *p)
Return a malloced packet.
Definition: decode.c:190
DecodeMPLS
int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-mpls.c:49
MPLS_LABEL
#define MPLS_LABEL(shim)
Definition: decode-mpls.c:41
Packet_
Definition: decode.h:437
DecodeIPV6
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
Definition: decode-ipv6.c:564
MPLS_PROTO_IPV4
#define MPLS_PROTO_IPV4
Definition: decode-mpls.c:46
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:33
MPLS_LABEL_ROUTER_ALERT
#define MPLS_LABEL_ROUTER_ALERT
Definition: decode-mpls.c:37
MPLS_UNKNOWN_PAYLOAD_TYPE
@ MPLS_UNKNOWN_PAYLOAD_TYPE
Definition: decode-events.h:193
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
suricata-common.h
MPLS_BAD_LABEL_ROUTER_ALERT
@ MPLS_BAD_LABEL_ROUTER_ALERT
Definition: decode-events.h:190
MPLS_LABEL_IPV4
#define MPLS_LABEL_IPV4
Definition: decode-mpls.c:36
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
util-validate.h
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:229
MPLS_LABEL_IPV6
#define MPLS_LABEL_IPV6
Definition: decode-mpls.c:38
DecodeThreadVars_::counter_mpls
uint16_t counter_mpls
Definition: decode.h:729
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:685
ENGINE_SET_INVALID_EVENT
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition: decode.h:912
MPLS_PKT_TOO_SMALL
@ MPLS_PKT_TOO_SMALL
Definition: decode-events.h:189
DecodeIPV4
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
Definition: decode-ipv4.c:520
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:103
DecodeEthernet
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ethernet.c:42
MPLS_PW_LEN
#define MPLS_PW_LEN
Definition: decode-mpls.c:33