suricata
decode-mpls.c
Go to the documentation of this file.
1 /* Copyright (C) 2014 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 #include "util-unittest.h"
29 
30 #define MPLS_HEADER_LEN 4
31 #define MPLS_PW_LEN 4
32 #define MPLS_MAX_RESERVED_LABEL 15
33 
34 #define MPLS_LABEL_IPV4 0
35 #define MPLS_LABEL_ROUTER_ALERT 1
36 #define MPLS_LABEL_IPV6 2
37 #define MPLS_LABEL_NULL 3
38 
39 #define MPLS_LABEL(shim) SCNtohl(shim) >> 12
40 #define MPLS_BOTTOM(shim) ((SCNtohl(shim) >> 8) & 0x1)
41 
42 /* Inner protocol guessing values. */
43 #define MPLS_PROTO_ETHERNET_PW 0
44 #define MPLS_PROTO_IPV4 4
45 #define MPLS_PROTO_IPV6 6
46 
48  const uint8_t *pkt, uint32_t len)
49 {
50  uint32_t shim;
51  int label;
52  int event = 0;
53 
55 
56  if (!PacketIncreaseCheckLayers(p)) {
57  return TM_ECODE_FAILED;
58  }
59  do {
60  if (len < MPLS_HEADER_LEN) {
62  return TM_ECODE_FAILED;
63  }
64  memcpy(&shim, pkt, sizeof(shim));
65  pkt += MPLS_HEADER_LEN;
67  } while (MPLS_BOTTOM(shim) == 0);
68 
69  label = MPLS_LABEL(shim);
70  if (label == MPLS_LABEL_IPV4) {
71  if (len > USHRT_MAX) {
72  return TM_ECODE_FAILED;
73  }
74  return DecodeIPV4(tv, dtv, p, pkt, len);
75  }
76  else if (label == MPLS_LABEL_ROUTER_ALERT) {
77  /* Not valid at the bottom of the stack. */
79  }
80  else if (label == MPLS_LABEL_IPV6) {
81  if (len > USHRT_MAX) {
82  return TM_ECODE_FAILED;
83  }
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, len);
112  break;
113  case MPLS_PROTO_IPV6:
114  if (len > USHRT_MAX) {
115  return TM_ECODE_FAILED;
116  }
117  DecodeIPV6(tv, dtv, p, pkt, len);
118  break;
121  break;
122  default:
124  return TM_ECODE_OK;
125  }
126 
127 end:
128  if (event) {
129  ENGINE_SET_EVENT(p, event);
130  }
131  return TM_ECODE_OK;
132 }
133 
134 #ifdef UNITTESTS
135 
136 static int DecodeMPLSTestHeaderTooSmall(void)
137 {
138  int ret = 1;
139 
140  /* A packet that is too small to have a complete MPLS header. */
141  uint8_t pkt[] = {
142  0x00, 0x00, 0x11
143  };
144 
146  if (unlikely(p == NULL)) {
147  return 0;
148  }
149  ThreadVars tv;
151 
152  memset(&dtv, 0, sizeof(DecodeThreadVars));
153  memset(&tv, 0, sizeof(ThreadVars));
154  memset(p, 0, SIZE_OF_PACKET);
155 
156  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
157 
159  ret = 0;
160  }
161 
162  SCFree(p);
163  return ret;
164 }
165 
166 static int DecodeMPLSTestPacketTooSmall(void)
167 {
168  ThreadVars tv;
170 
171  memset(&dtv, 0, sizeof(DecodeThreadVars));
172  memset(&tv, 0, sizeof(ThreadVars));
173 
174  Packet *p0 = SCCalloc(1, SIZE_OF_PACKET);
175  memset(p0, 0, SIZE_OF_PACKET);
176  uint8_t pkt0[] = { 0x00, 0x01, 0x51, 0xff };
177  DecodeMPLS(&tv, &dtv, p0, pkt0, sizeof(pkt0));
179  SCFree(p0);
180 
181  Packet *p1 = SCCalloc(1, SIZE_OF_PACKET);
182  FAIL_IF_NULL(p1);
183  uint8_t pkt1[] = { 0x00, 0x01, 0x51, 0xff, 0x45 };
184  DecodeMPLS(&tv, &dtv, p1, pkt1, sizeof(pkt1));
186  SCFree(p1);
187 
188  Packet *p2 = SCCalloc(1, SIZE_OF_PACKET);
189  FAIL_IF_NULL(p2);
190  uint8_t pkt2[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01 };
191  DecodeMPLS(&tv, &dtv, p2, pkt2, sizeof(pkt2));
193  SCFree(p2);
194 
195  Packet *p3 = SCCalloc(1, SIZE_OF_PACKET);
196  FAIL_IF_NULL(p3);
197  uint8_t pkt3[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01, 0x02 };
198  DecodeMPLS(&tv, &dtv, p3, pkt3, sizeof(pkt3));
200  SCFree(p3);
201 
202  // This should not create a too small event is it has one more byte
203  // than required.
204  Packet *p4 = SCCalloc(1, SIZE_OF_PACKET);
205  FAIL_IF_NULL(p4);
206  uint8_t pkt4[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01, 0x02, 0x03 };
207  DecodeMPLS(&tv, &dtv, p4, pkt4, sizeof(pkt4));
209  SCFree(p4);
210 
211  PASS;
212 }
213 
214 static int DecodeMPLSTestBadLabelRouterAlert(void)
215 {
216  int ret = 1;
217  uint8_t pkt[] = {
218  0x00, 0x00, 0x11, 0xff, 0x45, 0x00, 0x00, 0x64,
219  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
220  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
221  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
222  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
223  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
224  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
225  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
226  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
227  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
228  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
229  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
230  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
231  };
232 
234  if (unlikely(p == NULL)) {
235  return 0;
236  }
237  ThreadVars tv;
239 
240  memset(&dtv, 0, sizeof(DecodeThreadVars));
241  memset(&tv, 0, sizeof(ThreadVars));
242  memset(p, 0, SIZE_OF_PACKET);
243 
244  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
245 
247  ret = 0;
248  }
249 
250  SCFree(p);
251  return ret;
252 }
253 
254 static int DecodeMPLSTestBadLabelImplicitNull(void)
255 {
256  int ret = 1;
257  uint8_t pkt[] = {
258  0x00, 0x00, 0x31, 0xff, 0x45, 0x00, 0x00, 0x64,
259  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
260  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
261  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
262  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
263  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
264  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
265  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
266  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
267  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
268  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
269  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
270  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
271  };
272 
274  if (unlikely(p == NULL)) {
275  return 0;
276  }
277  ThreadVars tv;
279 
280  memset(&dtv, 0, sizeof(DecodeThreadVars));
281  memset(&tv, 0, sizeof(ThreadVars));
282  memset(p, 0, SIZE_OF_PACKET);
283 
284  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
285 
287  ret = 0;
288  }
289 
290  SCFree(p);
291  return ret;
292 }
293 
294 static int DecodeMPLSTestBadLabelReserved(void)
295 {
296  int ret = 1;
297  uint8_t pkt[] = {
298  0x00, 0x00, 0x51, 0xff, 0x45, 0x00, 0x00, 0x64,
299  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
300  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
301  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
302  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
303  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
304  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
305  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
306  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
307  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
308  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
309  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
310  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
311  };
312 
314  if (unlikely(p == NULL)) {
315  return 0;
316  }
317  ThreadVars tv;
319 
320  memset(&dtv, 0, sizeof(DecodeThreadVars));
321  memset(&tv, 0, sizeof(ThreadVars));
322  memset(p, 0, SIZE_OF_PACKET);
323 
324  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
325 
327  ret = 0;
328  }
329 
330  SCFree(p);
331  return ret;
332 }
333 
334 static int DecodeMPLSTestUnknownPayloadType(void)
335 {
336  int ret = 1;
337 
338  /* Valid label: 21.
339  * Unknown payload type: 1.
340  */
341  uint8_t pkt[] = {
342  0x00, 0x01, 0x51, 0xff, 0x15, 0x00, 0x00, 0x64,
343  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
344  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
345  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
346  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
347  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
348  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
349  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
350  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
351  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
352  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
353  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
354  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
355  };
356 
358  if (unlikely(p == NULL)) {
359  return 0;
360  }
361  ThreadVars tv;
363 
364  memset(&dtv, 0, sizeof(DecodeThreadVars));
365  memset(&tv, 0, sizeof(ThreadVars));
366  memset(p, 0, SIZE_OF_PACKET);
367 
368  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
369 
371  ret = 0;
372  }
373 
374  SCFree(p);
375  return ret;
376 }
377 
378 #endif /* UNITTESTS */
379 
381 {
382 #ifdef UNITTESTS
383  UtRegisterTest("DecodeMPLSTestHeaderTooSmall",
384  DecodeMPLSTestHeaderTooSmall);
385  UtRegisterTest("DecodeMPLSTestPacketTooSmall",
386  DecodeMPLSTestPacketTooSmall);
387  UtRegisterTest("DecodeMPLSTestBadLabelRouterAlert",
388  DecodeMPLSTestBadLabelRouterAlert);
389  UtRegisterTest("DecodeMPLSTestBadLabelImplicitNull",
390  DecodeMPLSTestBadLabelImplicitNull);
391  UtRegisterTest("DecodeMPLSTestBadLabelReserved",
392  DecodeMPLSTestBadLabelReserved);
393  UtRegisterTest("DecodeMPLSTestUnknownPayloadType",
394  DecodeMPLSTestUnknownPayloadType);
395 #endif /* UNITTESTS */
396 }
ENGINE_SET_EVENT
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:1020
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:169
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
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:1035
MPLS_PROTO_IPV6
#define MPLS_PROTO_IPV6
Definition: decode-mpls.c:45
MPLS_MAX_RESERVED_LABEL
#define MPLS_MAX_RESERVED_LABEL
Definition: decode-mpls.c:32
MPLS_BOTTOM
#define MPLS_BOTTOM(shim)
Definition: decode-mpls.c:40
MPLS_BAD_LABEL_IMPLICIT_NULL
@ MPLS_BAD_LABEL_IMPLICIT_NULL
Definition: decode-events.h:185
MPLS_PKT_TOO_SMALL
@ MPLS_PKT_TOO_SMALL
Definition: decode-events.h:183
MPLS_HEADER_LEN
#define MPLS_HEADER_LEN
Definition: decode-mpls.c:30
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:81
util-unittest.h
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression to true.
Definition: util-unittest.h:82
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:80
MPLS_LABEL_NULL
#define MPLS_LABEL_NULL
Definition: decode-mpls.c:37
DecodeMPLSRegisterTests
void DecodeMPLSRegisterTests(void)
Definition: decode-mpls.c:380
MPLS_BAD_LABEL_RESERVED
@ MPLS_BAD_LABEL_RESERVED
Definition: decode-events.h:186
MPLS_BAD_LABEL_ROUTER_ALERT
@ MPLS_BAD_LABEL_ROUTER_ALERT
Definition: decode-events.h:184
decode.h
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
MPLS_PROTO_ETHERNET_PW
#define MPLS_PROTO_ETHERNET_PW
Definition: decode-mpls.c:43
DecodeMPLS
int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-mpls.c:47
SIZE_OF_PACKET
#define SIZE_OF_PACKET
Definition: decode.h:635
MPLS_LABEL
#define MPLS_LABEL(shim)
Definition: decode-mpls.c:39
Packet_
Definition: decode.h:415
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:44
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:30
MPLS_LABEL_ROUTER_ALERT
#define MPLS_LABEL_ROUTER_ALERT
Definition: decode-mpls.c:35
MPLS_HEADER_TOO_SMALL
@ MPLS_HEADER_TOO_SMALL
Definition: decode-events.h:182
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:71
suricata-common.h
MPLS_LABEL_IPV4
#define MPLS_LABEL_IPV4
Definition: decode-mpls.c:34
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:29
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
MPLS_LABEL_IPV6
#define MPLS_LABEL_IPV6
Definition: decode-mpls.c:36
DecodeThreadVars_::counter_mpls
uint16_t counter_mpls
Definition: decode.h:676
SCFree
#define SCFree(p)
Definition: util-mem.h:61
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:639
ENGINE_SET_INVALID_EVENT
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition: decode.h:1028
DecodeIPV4
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
Definition: decode-ipv4.c:517
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
DecodeEthernet
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ethernet.c:41
MPLS_UNKNOWN_PAYLOAD_TYPE
@ MPLS_UNKNOWN_PAYLOAD_TYPE
Definition: decode-events.h:187
MPLS_PW_LEN
#define MPLS_PW_LEN
Definition: decode-mpls.c:31