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
DecodeMPLS(ThreadVars * tv,DecodeThreadVars * dtv,Packet * p,const uint8_t * pkt,uint32_t len)47 int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
48 const uint8_t *pkt, uint32_t len)
49 {
50 uint32_t shim;
51 int label;
52 int event = 0;
53
54 StatsIncr(tv, dtv->counter_mpls);
55
56 if (!PacketIncreaseCheckLayers(p)) {
57 return TM_ECODE_FAILED;
58 }
59 do {
60 if (len < MPLS_HEADER_LEN) {
61 ENGINE_SET_INVALID_EVENT(p, MPLS_HEADER_TOO_SMALL);
62 return TM_ECODE_FAILED;
63 }
64 memcpy(&shim, pkt, sizeof(shim));
65 pkt += MPLS_HEADER_LEN;
66 len -= 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. */
78 event = MPLS_BAD_LABEL_ROUTER_ALERT;
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. */
88 event = MPLS_BAD_LABEL_IMPLICIT_NULL;
89 }
90 else if (label < MPLS_MAX_RESERVED_LABEL) {
91 event = MPLS_BAD_LABEL_RESERVED;
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) {
101 ENGINE_SET_INVALID_EVENT(p, MPLS_PKT_TOO_SMALL);
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;
119 case MPLS_PROTO_ETHERNET_PW:
120 DecodeEthernet(tv, dtv, p, pkt + MPLS_PW_LEN, len - MPLS_PW_LEN);
121 break;
122 default:
123 ENGINE_SET_INVALID_EVENT(p, MPLS_UNKNOWN_PAYLOAD_TYPE);
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
DecodeMPLSTestHeaderTooSmall(void)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
145 Packet *p = SCMalloc(SIZE_OF_PACKET);
146 if (unlikely(p == NULL)) {
147 return 0;
148 }
149 ThreadVars tv;
150 DecodeThreadVars dtv;
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
158 if (!ENGINE_ISSET_EVENT(p, MPLS_HEADER_TOO_SMALL)) {
159 ret = 0;
160 }
161
162 SCFree(p);
163 return ret;
164 }
165
DecodeMPLSTestPacketTooSmall(void)166 static int DecodeMPLSTestPacketTooSmall(void)
167 {
168 ThreadVars tv;
169 DecodeThreadVars dtv;
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));
178 FAIL_IF_NOT(ENGINE_ISSET_EVENT(p0, MPLS_PKT_TOO_SMALL));
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));
185 FAIL_IF_NOT(ENGINE_ISSET_EVENT(p1, MPLS_PKT_TOO_SMALL));
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));
192 FAIL_IF_NOT(ENGINE_ISSET_EVENT(p2, MPLS_PKT_TOO_SMALL));
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));
199 FAIL_IF_NOT(ENGINE_ISSET_EVENT(p3, MPLS_PKT_TOO_SMALL));
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));
208 FAIL_IF(ENGINE_ISSET_EVENT(p4, MPLS_PKT_TOO_SMALL));
209 SCFree(p4);
210
211 PASS;
212 }
213
DecodeMPLSTestBadLabelRouterAlert(void)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
233 Packet *p = SCMalloc(SIZE_OF_PACKET);
234 if (unlikely(p == NULL)) {
235 return 0;
236 }
237 ThreadVars tv;
238 DecodeThreadVars dtv;
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
246 if (!ENGINE_ISSET_EVENT(p, MPLS_BAD_LABEL_ROUTER_ALERT)) {
247 ret = 0;
248 }
249
250 SCFree(p);
251 return ret;
252 }
253
DecodeMPLSTestBadLabelImplicitNull(void)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
273 Packet *p = SCMalloc(SIZE_OF_PACKET);
274 if (unlikely(p == NULL)) {
275 return 0;
276 }
277 ThreadVars tv;
278 DecodeThreadVars dtv;
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
286 if (!ENGINE_ISSET_EVENT(p, MPLS_BAD_LABEL_IMPLICIT_NULL)) {
287 ret = 0;
288 }
289
290 SCFree(p);
291 return ret;
292 }
293
DecodeMPLSTestBadLabelReserved(void)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
313 Packet *p = SCMalloc(SIZE_OF_PACKET);
314 if (unlikely(p == NULL)) {
315 return 0;
316 }
317 ThreadVars tv;
318 DecodeThreadVars dtv;
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
326 if (!ENGINE_ISSET_EVENT(p, MPLS_BAD_LABEL_RESERVED)) {
327 ret = 0;
328 }
329
330 SCFree(p);
331 return ret;
332 }
333
DecodeMPLSTestUnknownPayloadType(void)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
357 Packet *p = SCMalloc(SIZE_OF_PACKET);
358 if (unlikely(p == NULL)) {
359 return 0;
360 }
361 ThreadVars tv;
362 DecodeThreadVars dtv;
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
370 if (!ENGINE_ISSET_EVENT(p, MPLS_UNKNOWN_PAYLOAD_TYPE)) {
371 ret = 0;
372 }
373
374 SCFree(p);
375 return ret;
376 }
377
378 #endif /* UNITTESTS */
379
DecodeMPLSRegisterTests(void)380 void DecodeMPLSRegisterTests(void)
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 }
397