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