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, PacketQueue *pq)
49 {
50  uint32_t shim;
51  int label;
52  int event = 0;
53 
54  StatsIncr(tv, dtv->counter_mpls);
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;
63  len -= 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, pq);
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, pq);
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, pq);
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, pq);
115  break;
117  DecodeEthernet(tv, dtv, p, pkt + MPLS_PW_LEN, len - MPLS_PW_LEN,
118  pq);
119  break;
120  default:
122  return TM_ECODE_OK;
123  }
124 
125 end:
126  if (event) {
127  ENGINE_SET_EVENT(p, event);
128  }
129  return TM_ECODE_OK;
130 }
131 
132 #ifdef UNITTESTS
133 
134 static int DecodeMPLSTestHeaderTooSmall(void)
135 {
136  int ret = 1;
137 
138  /* A packet that is too small to have a complete MPLS header. */
139  uint8_t pkt[] = {
140  0x00, 0x00, 0x11
141  };
142 
144  if (unlikely(p == NULL)) {
145  return 0;
146  }
147  ThreadVars tv;
148  DecodeThreadVars dtv;
149 
150  memset(&dtv, 0, sizeof(DecodeThreadVars));
151  memset(&tv, 0, sizeof(ThreadVars));
152  memset(p, 0, SIZE_OF_PACKET);
153 
154  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt), NULL);
155 
157  ret = 0;
158  }
159 
160  SCFree(p);
161  return ret;
162 }
163 
164 static int DecodeMPLSTestPacketTooSmall(void)
165 {
166  ThreadVars tv;
167  DecodeThreadVars dtv;
168 
169  memset(&dtv, 0, sizeof(DecodeThreadVars));
170  memset(&tv, 0, sizeof(ThreadVars));
171 
172  Packet *p0 = SCCalloc(1, SIZE_OF_PACKET);
173  memset(p0, 0, SIZE_OF_PACKET);
174  uint8_t pkt0[] = { 0x00, 0x01, 0x51, 0xff };
175  DecodeMPLS(&tv, &dtv, p0, pkt0, sizeof(pkt0), NULL);
177  SCFree(p0);
178 
179  Packet *p1 = SCCalloc(1, SIZE_OF_PACKET);
180  FAIL_IF_NULL(p1);
181  uint8_t pkt1[] = { 0x00, 0x01, 0x51, 0xff, 0x45 };
182  DecodeMPLS(&tv, &dtv, p1, pkt1, sizeof(pkt1), NULL);
184  SCFree(p1);
185 
186  Packet *p2 = SCCalloc(1, SIZE_OF_PACKET);
187  FAIL_IF_NULL(p2);
188  uint8_t pkt2[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01 };
189  DecodeMPLS(&tv, &dtv, p2, pkt2, sizeof(pkt2), NULL);
191  SCFree(p2);
192 
193  Packet *p3 = SCCalloc(1, SIZE_OF_PACKET);
194  FAIL_IF_NULL(p3);
195  uint8_t pkt3[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01, 0x02 };
196  DecodeMPLS(&tv, &dtv, p3, pkt3, sizeof(pkt3), NULL);
198  SCFree(p3);
199 
200  // This should not create a too small event is it has one more byte
201  // than required.
202  Packet *p4 = SCCalloc(1, SIZE_OF_PACKET);
203  FAIL_IF_NULL(p4);
204  uint8_t pkt4[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01, 0x02, 0x03 };
205  DecodeMPLS(&tv, &dtv, p4, pkt4, sizeof(pkt4), NULL);
207  SCFree(p4);
208 
209  PASS;
210 }
211 
212 static int DecodeMPLSTestBadLabelRouterAlert(void)
213 {
214  int ret = 1;
215  uint8_t pkt[] = {
216  0x00, 0x00, 0x11, 0xff, 0x45, 0x00, 0x00, 0x64,
217  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
218  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
219  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
220  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
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  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
229  };
230 
232  if (unlikely(p == NULL)) {
233  return 0;
234  }
235  ThreadVars tv;
236  DecodeThreadVars dtv;
237 
238  memset(&dtv, 0, sizeof(DecodeThreadVars));
239  memset(&tv, 0, sizeof(ThreadVars));
240  memset(p, 0, SIZE_OF_PACKET);
241 
242  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt), NULL);
243 
245  ret = 0;
246  }
247 
248  SCFree(p);
249  return ret;
250 }
251 
252 static int DecodeMPLSTestBadLabelImplicitNull(void)
253 {
254  int ret = 1;
255  uint8_t pkt[] = {
256  0x00, 0x00, 0x31, 0xff, 0x45, 0x00, 0x00, 0x64,
257  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
258  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
259  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
260  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
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  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
269  };
270 
272  if (unlikely(p == NULL)) {
273  return 0;
274  }
275  ThreadVars tv;
276  DecodeThreadVars dtv;
277 
278  memset(&dtv, 0, sizeof(DecodeThreadVars));
279  memset(&tv, 0, sizeof(ThreadVars));
280  memset(p, 0, SIZE_OF_PACKET);
281 
282  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt), NULL);
283 
285  ret = 0;
286  }
287 
288  SCFree(p);
289  return ret;
290 }
291 
292 static int DecodeMPLSTestBadLabelReserved(void)
293 {
294  int ret = 1;
295  uint8_t pkt[] = {
296  0x00, 0x00, 0x51, 0xff, 0x45, 0x00, 0x00, 0x64,
297  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
298  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
299  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
300  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
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  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
309  };
310 
312  if (unlikely(p == NULL)) {
313  return 0;
314  }
315  ThreadVars tv;
316  DecodeThreadVars dtv;
317 
318  memset(&dtv, 0, sizeof(DecodeThreadVars));
319  memset(&tv, 0, sizeof(ThreadVars));
320  memset(p, 0, SIZE_OF_PACKET);
321 
322  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt), NULL);
323 
325  ret = 0;
326  }
327 
328  SCFree(p);
329  return ret;
330 }
331 
332 static int DecodeMPLSTestUnknownPayloadType(void)
333 {
334  int ret = 1;
335 
336  /* Valid label: 21.
337  * Unknown payload type: 1.
338  */
339  uint8_t pkt[] = {
340  0x00, 0x01, 0x51, 0xff, 0x15, 0x00, 0x00, 0x64,
341  0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a,
342  0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01,
343  0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b,
344  0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50,
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  0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd
353  };
354 
356  if (unlikely(p == NULL)) {
357  return 0;
358  }
359  ThreadVars tv;
360  DecodeThreadVars dtv;
361 
362  memset(&dtv, 0, sizeof(DecodeThreadVars));
363  memset(&tv, 0, sizeof(ThreadVars));
364  memset(p, 0, SIZE_OF_PACKET);
365 
366  DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt), NULL);
367 
369  ret = 0;
370  }
371 
372  SCFree(p);
373  return ret;
374 }
375 
376 #endif /* UNITTESTS */
377 
379 {
380 #ifdef UNITTESTS
381  UtRegisterTest("DecodeMPLSTestHeaderTooSmall",
382  DecodeMPLSTestHeaderTooSmall);
383  UtRegisterTest("DecodeMPLSTestPacketTooSmall",
384  DecodeMPLSTestPacketTooSmall);
385  UtRegisterTest("DecodeMPLSTestBadLabelRouterAlert",
386  DecodeMPLSTestBadLabelRouterAlert);
387  UtRegisterTest("DecodeMPLSTestBadLabelImplicitNull",
388  DecodeMPLSTestBadLabelImplicitNull);
389  UtRegisterTest("DecodeMPLSTestBadLabelReserved",
390  DecodeMPLSTestBadLabelReserved);
391  UtRegisterTest("DecodeMPLSTestUnknownPayloadType",
392  DecodeMPLSTestUnknownPayloadType);
393 #endif /* UNITTESTS */
394 }
#define ENGINE_SET_EVENT(p, e)
Definition: decode.h:993
#define ENGINE_ISSET_EVENT(p, e)
Definition: decode.h:1008
#define MPLS_LABEL(shim)
Definition: decode-mpls.c:39
#define MPLS_HEADER_LEN
Definition: decode-mpls.c:30
#define PASS
Pass the test.
#define unlikely(expr)
Definition: util-optimize.h:35
#define MPLS_PROTO_IPV6
Definition: decode-mpls.c:45
#define FAIL_IF(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:71
#define MPLS_MAX_RESERVED_LABEL
Definition: decode-mpls.c:32
#define MPLS_LABEL_ROUTER_ALERT
Definition: decode-mpls.c:35
#define MPLS_LABEL_IPV6
Definition: decode-mpls.c:36
#define SIZE_OF_PACKET
Definition: decode.h:619
#define SCCalloc(nm, a)
Definition: util-mem.h:253
#define MPLS_LABEL_NULL
Definition: decode-mpls.c:37
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
void DecodeMPLSRegisterTests(void)
Definition: decode-mpls.c:378
Structure to hold thread specific data for all decode modules.
Definition: decode.h:633
uint16_t counter_mpls
Definition: decode.h:666
#define MPLS_PROTO_IPV4
Definition: decode-mpls.c:44
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:168
#define MPLS_PW_LEN
Definition: decode-mpls.c:31
#define SCMalloc(a)
Definition: util-mem.h:222
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len, PacketQueue *pq)
Definition: decode-ipv6.c:585
#define SCFree(a)
Definition: util-mem.h:322
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len, PacketQueue *pq)
Definition: decode-ipv4.c:532
int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len, PacketQueue *pq)
Definition: decode-mpls.c:47
#define MPLS_BOTTOM(shim)
Definition: decode-mpls.c:40
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len, PacketQueue *pq)
uint8_t len
Per thread variable structure.
Definition: threadvars.h:57
#define MPLS_PROTO_ETHERNET_PW
Definition: decode-mpls.c:43
#define MPLS_LABEL_IPV4
Definition: decode-mpls.c:34
#define FAIL_IF_NOT(expr)
Fail a test if expression to true.
Definition: util-unittest.h:82
#define ENGINE_SET_INVALID_EVENT(p, e)
Definition: decode.h:1001