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  do {
57  if (len < MPLS_HEADER_LEN) {
59  return TM_ECODE_FAILED;
60  }
61  memcpy(&shim, pkt, sizeof(shim));
62  pkt += MPLS_HEADER_LEN;
64  } while (MPLS_BOTTOM(shim) == 0);
65 
66  label = MPLS_LABEL(shim);
67  if (label == MPLS_LABEL_IPV4) {
68  if (len > USHRT_MAX) {
69  return TM_ECODE_FAILED;
70  }
71  return DecodeIPV4(tv, dtv, p, pkt, len);
72  }
73  else if (label == MPLS_LABEL_ROUTER_ALERT) {
74  /* Not valid at the bottom of the stack. */
76  }
77  else if (label == MPLS_LABEL_IPV6) {
78  if (len > USHRT_MAX) {
79  return TM_ECODE_FAILED;
80  }
81  return DecodeIPV6(tv, dtv, p, pkt, len);
82  }
83  else if (label == MPLS_LABEL_NULL) {
84  /* Shouldn't appear on the wire. */
86  }
87  else if (label < MPLS_MAX_RESERVED_LABEL) {
89  }
90 
91  if (event) {
92  goto end;
93  }
94 
95  // Make sure we still have enough data. While we only need 1 byte to test
96  // for IPv4 and IPv4, we need for to check for ethernet.
97  if (len < MPLS_PW_LEN) {
99  return TM_ECODE_FAILED;
100  }
101 
102  /* Best guess at inner packet. */
103  switch (pkt[0] >> 4) {
104  case MPLS_PROTO_IPV4:
105  if (len > USHRT_MAX) {
106  return TM_ECODE_FAILED;
107  }
108  DecodeIPV4(tv, dtv, p, pkt, len);
109  break;
110  case MPLS_PROTO_IPV6:
111  if (len > USHRT_MAX) {
112  return TM_ECODE_FAILED;
113  }
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  int ret = 1;
136 
137  /* A packet that is too small to have a complete MPLS header. */
138  uint8_t pkt[] = {
139  0x00, 0x00, 0x11
140  };
141 
143  if (unlikely(p == NULL)) {
144  return 0;
145  }
146  ThreadVars tv;
148 
149  memset(&dtv, 0, sizeof(DecodeThreadVars));
150  memset(&tv, 0, sizeof(ThreadVars));
151  memset(p, 0, SIZE_OF_PACKET);
152 
153  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
154 
156  ret = 0;
157  }
158 
159  SCFree(p);
160  return ret;
161 }
162 
163 static int DecodeMPLSTestPacketTooSmall(void)
164 {
165  ThreadVars tv;
167 
168  memset(&dtv, 0, sizeof(DecodeThreadVars));
169  memset(&tv, 0, sizeof(ThreadVars));
170 
171  Packet *p0 = SCCalloc(1, SIZE_OF_PACKET);
172  memset(p0, 0, SIZE_OF_PACKET);
173  uint8_t pkt0[] = { 0x00, 0x01, 0x51, 0xff };
174  DecodeMPLS(&tv, &dtv, p0, pkt0, sizeof(pkt0));
176  SCFree(p0);
177 
178  Packet *p1 = SCCalloc(1, SIZE_OF_PACKET);
179  FAIL_IF_NULL(p1);
180  uint8_t pkt1[] = { 0x00, 0x01, 0x51, 0xff, 0x45 };
181  DecodeMPLS(&tv, &dtv, p1, pkt1, sizeof(pkt1));
183  SCFree(p1);
184 
185  Packet *p2 = SCCalloc(1, SIZE_OF_PACKET);
186  FAIL_IF_NULL(p2);
187  uint8_t pkt2[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01 };
188  DecodeMPLS(&tv, &dtv, p2, pkt2, sizeof(pkt2));
190  SCFree(p2);
191 
192  Packet *p3 = SCCalloc(1, SIZE_OF_PACKET);
193  FAIL_IF_NULL(p3);
194  uint8_t pkt3[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01, 0x02 };
195  DecodeMPLS(&tv, &dtv, p3, pkt3, sizeof(pkt3));
197  SCFree(p3);
198 
199  // This should not create a too small event is it has one more byte
200  // than required.
201  Packet *p4 = SCCalloc(1, SIZE_OF_PACKET);
202  FAIL_IF_NULL(p4);
203  uint8_t pkt4[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01, 0x02, 0x03 };
204  DecodeMPLS(&tv, &dtv, p4, pkt4, sizeof(pkt4));
206  SCFree(p4);
207 
208  PASS;
209 }
210 
211 static int DecodeMPLSTestBadLabelRouterAlert(void)
212 {
213  int ret = 1;
214  uint8_t pkt[] = {
215  0x00, 0x00, 0x11, 0xff, 0x45, 0x00, 0x00, 0x64,
216  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
217  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
218  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
219  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
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  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  };
229 
231  if (unlikely(p == NULL)) {
232  return 0;
233  }
234  ThreadVars tv;
236 
237  memset(&dtv, 0, sizeof(DecodeThreadVars));
238  memset(&tv, 0, sizeof(ThreadVars));
239  memset(p, 0, SIZE_OF_PACKET);
240 
241  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
242 
244  ret = 0;
245  }
246 
247  SCFree(p);
248  return ret;
249 }
250 
251 static int DecodeMPLSTestBadLabelImplicitNull(void)
252 {
253  int ret = 1;
254  uint8_t pkt[] = {
255  0x00, 0x00, 0x31, 0xff, 0x45, 0x00, 0x00, 0x64,
256  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
257  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
258  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
259  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
260  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
261  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
262  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
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  };
269 
271  if (unlikely(p == NULL)) {
272  return 0;
273  }
274  ThreadVars tv;
276 
277  memset(&dtv, 0, sizeof(DecodeThreadVars));
278  memset(&tv, 0, sizeof(ThreadVars));
279  memset(p, 0, SIZE_OF_PACKET);
280 
281  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
282 
284  ret = 0;
285  }
286 
287  SCFree(p);
288  return ret;
289 }
290 
291 static int DecodeMPLSTestBadLabelReserved(void)
292 {
293  int ret = 1;
294  uint8_t pkt[] = {
295  0x00, 0x00, 0x51, 0xff, 0x45, 0x00, 0x00, 0x64,
296  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
297  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
298  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
299  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
300  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
301  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
302  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
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  };
309 
311  if (unlikely(p == NULL)) {
312  return 0;
313  }
314  ThreadVars tv;
316 
317  memset(&dtv, 0, sizeof(DecodeThreadVars));
318  memset(&tv, 0, sizeof(ThreadVars));
319  memset(p, 0, SIZE_OF_PACKET);
320 
321  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
322 
324  ret = 0;
325  }
326 
327  SCFree(p);
328  return ret;
329 }
330 
331 static int DecodeMPLSTestUnknownPayloadType(void)
332 {
333  int ret = 1;
334 
335  /* Valid label: 21.
336  * Unknown payload type: 1.
337  */
338  uint8_t pkt[] = {
339  0x00, 0x01, 0x51, 0xff, 0x15, 0x00, 0x00, 0x64,
340  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
341  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
342  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
343  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
344  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
345  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
346  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd,
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  };
353 
355  if (unlikely(p == NULL)) {
356  return 0;
357  }
358  ThreadVars tv;
360 
361  memset(&dtv, 0, sizeof(DecodeThreadVars));
362  memset(&tv, 0, sizeof(ThreadVars));
363  memset(p, 0, SIZE_OF_PACKET);
364 
365  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt));
366 
368  ret = 0;
369  }
370 
371  SCFree(p);
372  return ret;
373 }
374 
375 #endif /* UNITTESTS */
376 
378 {
379 #ifdef UNITTESTS
380  UtRegisterTest("DecodeMPLSTestHeaderTooSmall",
381  DecodeMPLSTestHeaderTooSmall);
382  UtRegisterTest("DecodeMPLSTestPacketTooSmall",
383  DecodeMPLSTestPacketTooSmall);
384  UtRegisterTest("DecodeMPLSTestBadLabelRouterAlert",
385  DecodeMPLSTestBadLabelRouterAlert);
386  UtRegisterTest("DecodeMPLSTestBadLabelImplicitNull",
387  DecodeMPLSTestBadLabelImplicitNull);
388  UtRegisterTest("DecodeMPLSTestBadLabelReserved",
389  DecodeMPLSTestBadLabelReserved);
390  UtRegisterTest("DecodeMPLSTestUnknownPayloadType",
391  DecodeMPLSTestUnknownPayloadType);
392 #endif /* UNITTESTS */
393 }
ENGINE_SET_EVENT
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:976
len
uint8_t len
Definition: app-layer-dnp3.h:4
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:168
SCFree
#define SCFree(a)
Definition: util-mem.h:322
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:991
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_HEADER_LEN
#define MPLS_HEADER_LEN
Definition: decode-mpls.c:30
MPLS_UNKNOWN_PAYLOAD_TYPE
@ MPLS_UNKNOWN_PAYLOAD_TYPE
Definition: decode-events.h:184
MPLS_BAD_LABEL_ROUTER_ALERT
@ MPLS_BAD_LABEL_ROUTER_ALERT
Definition: decode-events.h:181
MPLS_BAD_LABEL_IMPLICIT_NULL
@ MPLS_BAD_LABEL_IMPLICIT_NULL
Definition: decode-events.h:182
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:79
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:78
MPLS_LABEL_NULL
#define MPLS_LABEL_NULL
Definition: decode-mpls.c:37
DecodeMPLSRegisterTests
void DecodeMPLSRegisterTests(void)
Definition: decode-mpls.c:377
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: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:619
SCMalloc
#define SCMalloc(a)
Definition: util-mem.h:222
MPLS_LABEL
#define MPLS_LABEL(shim)
Definition: decode-mpls.c:39
Packet_
Definition: decode.h:408
SCCalloc
#define SCCalloc(nm, a)
Definition: util-mem.h:253
DecodeIPV6
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
Definition: decode-ipv6.c:580
MPLS_PROTO_IPV4
#define MPLS_PROTO_IPV4
Definition: decode-mpls.c:44
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:33
MPLS_LABEL_ROUTER_ALERT
#define MPLS_LABEL_ROUTER_ALERT
Definition: decode-mpls.c:35
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:71
suricata-common.h
MPLS_BAD_LABEL_RESERVED
@ MPLS_BAD_LABEL_RESERVED
Definition: decode-events.h:183
MPLS_LABEL_IPV4
#define MPLS_LABEL_IPV4
Definition: decode-mpls.c:34
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
MPLS_LABEL_IPV6
#define MPLS_LABEL_IPV6
Definition: decode-mpls.c:36
DecodeThreadVars_::counter_mpls
uint16_t counter_mpls
Definition: decode.h:655
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:622
MPLS_PKT_TOO_SMALL
@ MPLS_PKT_TOO_SMALL
Definition: decode-events.h:180
MPLS_HEADER_TOO_SMALL
@ MPLS_HEADER_TOO_SMALL
Definition: decode-events.h:179
ENGINE_SET_INVALID_EVENT
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition: decode.h:984
DecodeIPV4
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
Definition: decode-ipv4.c:517
DecodeEthernet
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ethernet.c:41
MPLS_PW_LEN
#define MPLS_PW_LEN
Definition: decode-mpls.c:31