/src/suricata7/src/decode-mpls.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2014-2021 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 | | |
29 | | #include "util-validate.h" |
30 | | #include "util-unittest.h" |
31 | | |
32 | 268k | #define MPLS_HEADER_LEN 4 |
33 | 27.6k | #define MPLS_PW_LEN 4 |
34 | 14.6k | #define MPLS_MAX_RESERVED_LABEL 15 |
35 | | |
36 | 16.7k | #define MPLS_LABEL_IPV4 0 |
37 | 16.1k | #define MPLS_LABEL_ROUTER_ALERT 1 |
38 | 15.5k | #define MPLS_LABEL_IPV6 2 |
39 | 15.0k | #define MPLS_LABEL_NULL 3 |
40 | | |
41 | 16.7k | #define MPLS_LABEL(shim) SCNtohl(shim) >> 12 |
42 | 88.1k | #define MPLS_BOTTOM(shim) ((SCNtohl(shim) >> 8) & 0x1) |
43 | | |
44 | | /* Inner protocol guessing values. */ |
45 | 6.87k | #define MPLS_PROTO_ETHERNET_PW 0 |
46 | 951 | #define MPLS_PROTO_IPV4 4 |
47 | 1.52k | #define MPLS_PROTO_IPV6 6 |
48 | | |
49 | | int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, |
50 | | const uint8_t *pkt, uint32_t len) |
51 | 21.3k | { |
52 | 21.3k | DEBUG_VALIDATE_BUG_ON(pkt == NULL); |
53 | | |
54 | 21.3k | uint32_t shim; |
55 | 21.3k | int label; |
56 | 21.3k | uint8_t event = 0; |
57 | | |
58 | 21.3k | StatsIncr(tv, dtv->counter_mpls); |
59 | | |
60 | 21.3k | if (!PacketIncreaseCheckLayers(p)) { |
61 | 186 | return TM_ECODE_FAILED; |
62 | 186 | } |
63 | 92.5k | do { |
64 | 92.5k | if (len < MPLS_HEADER_LEN) { |
65 | 4.40k | ENGINE_SET_INVALID_EVENT(p, MPLS_HEADER_TOO_SMALL); |
66 | 4.40k | return TM_ECODE_FAILED; |
67 | 4.40k | } |
68 | 88.1k | memcpy(&shim, pkt, sizeof(shim)); |
69 | 88.1k | pkt += MPLS_HEADER_LEN; |
70 | 88.1k | len -= MPLS_HEADER_LEN; |
71 | 88.1k | } while (MPLS_BOTTOM(shim) == 0); |
72 | | |
73 | 16.7k | label = MPLS_LABEL(shim); |
74 | 16.7k | if (label == MPLS_LABEL_IPV4) { |
75 | 556 | if (len > USHRT_MAX) { |
76 | 11 | return TM_ECODE_FAILED; |
77 | 11 | } |
78 | 545 | return DecodeIPV4(tv, dtv, p, pkt, (uint16_t)len); |
79 | 556 | } |
80 | 16.1k | else if (label == MPLS_LABEL_ROUTER_ALERT) { |
81 | | /* Not valid at the bottom of the stack. */ |
82 | 673 | event = MPLS_BAD_LABEL_ROUTER_ALERT; |
83 | 673 | } |
84 | 15.5k | else if (label == MPLS_LABEL_IPV6) { |
85 | 438 | if (len > USHRT_MAX) { |
86 | 18 | return TM_ECODE_FAILED; |
87 | 18 | } |
88 | 420 | return DecodeIPV6(tv, dtv, p, pkt, (uint16_t)len); |
89 | 438 | } |
90 | 15.0k | else if (label == MPLS_LABEL_NULL) { |
91 | | /* Shouldn't appear on the wire. */ |
92 | 455 | event = MPLS_BAD_LABEL_IMPLICIT_NULL; |
93 | 455 | } |
94 | 14.6k | else if (label < MPLS_MAX_RESERVED_LABEL) { |
95 | 683 | event = MPLS_BAD_LABEL_RESERVED; |
96 | 683 | } |
97 | | |
98 | 15.7k | if (event) { |
99 | 1.81k | goto end; |
100 | 1.81k | } |
101 | | |
102 | | // Make sure we still have enough data. While we only need 1 byte to test |
103 | | // for IPv4 and IPv4, we need for to check for ethernet. |
104 | 13.9k | if (len < MPLS_PW_LEN) { |
105 | 1.55k | ENGINE_SET_INVALID_EVENT(p, MPLS_PKT_TOO_SMALL); |
106 | 1.55k | return TM_ECODE_FAILED; |
107 | 1.55k | } |
108 | | |
109 | | /* Best guess at inner packet. */ |
110 | 12.3k | switch (pkt[0] >> 4) { |
111 | 951 | case MPLS_PROTO_IPV4: |
112 | 951 | if (len > USHRT_MAX) { |
113 | 12 | return TM_ECODE_FAILED; |
114 | 12 | } |
115 | 939 | DecodeIPV4(tv, dtv, p, pkt, (uint16_t)len); |
116 | 939 | break; |
117 | 1.52k | case MPLS_PROTO_IPV6: |
118 | 1.52k | if (len > USHRT_MAX) { |
119 | 9 | return TM_ECODE_FAILED; |
120 | 9 | } |
121 | 1.52k | DecodeIPV6(tv, dtv, p, pkt, (uint16_t)len); |
122 | 1.52k | break; |
123 | 6.87k | case MPLS_PROTO_ETHERNET_PW: |
124 | 6.87k | DecodeEthernet(tv, dtv, p, pkt + MPLS_PW_LEN, len - MPLS_PW_LEN); |
125 | 6.87k | break; |
126 | 3.04k | default: |
127 | 3.04k | ENGINE_SET_INVALID_EVENT(p, MPLS_UNKNOWN_PAYLOAD_TYPE); |
128 | 3.04k | return TM_ECODE_OK; |
129 | 12.3k | } |
130 | | |
131 | 11.1k | end: |
132 | 11.1k | if (event) { |
133 | 1.81k | ENGINE_SET_EVENT(p, event); |
134 | 1.81k | } |
135 | 11.1k | return TM_ECODE_OK; |
136 | 12.3k | } |
137 | | |
138 | | #ifdef UNITTESTS |
139 | | |
140 | | static int DecodeMPLSTestHeaderTooSmall(void) |
141 | | { |
142 | | /* A packet that is too small to have a complete MPLS header. */ |
143 | | uint8_t pkt[] = { |
144 | | 0x00, 0x00, 0x11 |
145 | | }; |
146 | | |
147 | | Packet *p = PacketGetFromAlloc(); |
148 | | FAIL_IF_NULL(p); |
149 | | ThreadVars tv; |
150 | | DecodeThreadVars dtv; |
151 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
152 | | memset(&tv, 0, sizeof(ThreadVars)); |
153 | | |
154 | | DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt)); |
155 | | FAIL_IF(!ENGINE_ISSET_EVENT(p, MPLS_HEADER_TOO_SMALL)); |
156 | | |
157 | | PacketFree(p); |
158 | | PASS; |
159 | | } |
160 | | |
161 | | static int DecodeMPLSTestPacketTooSmall(void) |
162 | | { |
163 | | ThreadVars tv; |
164 | | DecodeThreadVars dtv; |
165 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
166 | | memset(&tv, 0, sizeof(ThreadVars)); |
167 | | |
168 | | Packet *p = PacketGetFromAlloc(); |
169 | | FAIL_IF_NULL(p); |
170 | | uint8_t pkt0[] = { 0x00, 0x01, 0x51, 0xff }; |
171 | | DecodeMPLS(&tv, &dtv, p, pkt0, sizeof(pkt0)); |
172 | | FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, MPLS_PKT_TOO_SMALL)); |
173 | | PacketFree(p); |
174 | | |
175 | | p = PacketGetFromAlloc(); |
176 | | FAIL_IF_NULL(p); |
177 | | uint8_t pkt1[] = { 0x00, 0x01, 0x51, 0xff, 0x45 }; |
178 | | DecodeMPLS(&tv, &dtv, p, pkt1, sizeof(pkt1)); |
179 | | FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, MPLS_PKT_TOO_SMALL)); |
180 | | PacketFree(p); |
181 | | |
182 | | p = PacketGetFromAlloc(); |
183 | | FAIL_IF_NULL(p); |
184 | | uint8_t pkt2[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01 }; |
185 | | DecodeMPLS(&tv, &dtv, p, pkt2, sizeof(pkt2)); |
186 | | FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, MPLS_PKT_TOO_SMALL)); |
187 | | PacketFree(p); |
188 | | |
189 | | p = PacketGetFromAlloc(); |
190 | | FAIL_IF_NULL(p); |
191 | | uint8_t pkt3[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01, 0x02 }; |
192 | | DecodeMPLS(&tv, &dtv, p, pkt3, sizeof(pkt3)); |
193 | | FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, MPLS_PKT_TOO_SMALL)); |
194 | | PacketFree(p); |
195 | | |
196 | | // This should not create a too small event is it has one more byte |
197 | | // than required. |
198 | | p = PacketGetFromAlloc(); |
199 | | FAIL_IF_NULL(p); |
200 | | uint8_t pkt4[] = { 0x00, 0x01, 0x51, 0xff, 0x45, 0x01, 0x02, 0x03 }; |
201 | | DecodeMPLS(&tv, &dtv, p, pkt4, sizeof(pkt4)); |
202 | | FAIL_IF(ENGINE_ISSET_EVENT(p, MPLS_PKT_TOO_SMALL)); |
203 | | PacketFree(p); |
204 | | |
205 | | PASS; |
206 | | } |
207 | | |
208 | | static int DecodeMPLSTestBadLabelRouterAlert(void) |
209 | | { |
210 | | uint8_t pkt[] = { |
211 | | 0x00, 0x00, 0x11, 0xff, 0x45, 0x00, 0x00, 0x64, |
212 | | 0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a, |
213 | | 0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01, |
214 | | 0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b, |
215 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50, |
216 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
217 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
218 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
219 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
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 | | }; |
225 | | |
226 | | Packet *p = PacketGetFromAlloc(); |
227 | | FAIL_IF_NULL(p); |
228 | | ThreadVars tv; |
229 | | DecodeThreadVars dtv; |
230 | | |
231 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
232 | | memset(&tv, 0, sizeof(ThreadVars)); |
233 | | |
234 | | DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt)); |
235 | | FAIL_IF(!ENGINE_ISSET_EVENT(p, MPLS_BAD_LABEL_ROUTER_ALERT)); |
236 | | |
237 | | PacketFree(p); |
238 | | PASS; |
239 | | } |
240 | | |
241 | | static int DecodeMPLSTestBadLabelImplicitNull(void) |
242 | | { |
243 | | uint8_t pkt[] = { |
244 | | 0x00, 0x00, 0x31, 0xff, 0x45, 0x00, 0x00, 0x64, |
245 | | 0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a, |
246 | | 0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01, |
247 | | 0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b, |
248 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50, |
249 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
250 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
251 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
252 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
253 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
254 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
255 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
256 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd |
257 | | }; |
258 | | |
259 | | Packet *p = PacketGetFromAlloc(); |
260 | | FAIL_IF_NULL(p); |
261 | | ThreadVars tv; |
262 | | DecodeThreadVars dtv; |
263 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
264 | | memset(&tv, 0, sizeof(ThreadVars)); |
265 | | |
266 | | DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt)); |
267 | | FAIL_IF(!ENGINE_ISSET_EVENT(p, MPLS_BAD_LABEL_IMPLICIT_NULL)); |
268 | | |
269 | | PacketFree(p); |
270 | | PASS; |
271 | | } |
272 | | |
273 | | static int DecodeMPLSTestBadLabelReserved(void) |
274 | | { |
275 | | uint8_t pkt[] = { |
276 | | 0x00, 0x00, 0x51, 0xff, 0x45, 0x00, 0x00, 0x64, |
277 | | 0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a, |
278 | | 0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01, |
279 | | 0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b, |
280 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50, |
281 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
282 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
283 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
284 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
285 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
286 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
287 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
288 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd |
289 | | }; |
290 | | |
291 | | Packet *p = PacketGetFromAlloc(); |
292 | | FAIL_IF_NULL(p); |
293 | | ThreadVars tv; |
294 | | DecodeThreadVars dtv; |
295 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
296 | | memset(&tv, 0, sizeof(ThreadVars)); |
297 | | |
298 | | DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt)); |
299 | | FAIL_IF(!ENGINE_ISSET_EVENT(p, MPLS_BAD_LABEL_RESERVED)); |
300 | | |
301 | | PacketFree(p); |
302 | | PASS; |
303 | | } |
304 | | |
305 | | static int DecodeMPLSTestUnknownPayloadType(void) |
306 | | { |
307 | | /* Valid label: 21. |
308 | | * Unknown payload type: 1. |
309 | | */ |
310 | | uint8_t pkt[] = { |
311 | | 0x00, 0x01, 0x51, 0xff, 0x15, 0x00, 0x00, 0x64, |
312 | | 0x00, 0x0a, 0x00, 0x00, 0xff, 0x01, 0xa5, 0x6a, |
313 | | 0x0a, 0x01, 0x02, 0x01, 0x0a, 0x22, 0x00, 0x01, |
314 | | 0x08, 0x00, 0x3a, 0x77, 0x0a, 0x39, 0x06, 0x2b, |
315 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x50, |
316 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
317 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
318 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
319 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
320 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
321 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
322 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, |
323 | | 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd, 0xab, 0xcd |
324 | | }; |
325 | | |
326 | | Packet *p = PacketGetFromAlloc(); |
327 | | FAIL_IF_NULL(p); |
328 | | ThreadVars tv; |
329 | | DecodeThreadVars dtv; |
330 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
331 | | memset(&tv, 0, sizeof(ThreadVars)); |
332 | | |
333 | | DecodeMPLS(&tv, &dtv, p, pkt, sizeof(pkt)); |
334 | | FAIL_IF(!ENGINE_ISSET_EVENT(p, MPLS_UNKNOWN_PAYLOAD_TYPE)); |
335 | | |
336 | | PacketFree(p); |
337 | | PASS; |
338 | | } |
339 | | |
340 | | #endif /* UNITTESTS */ |
341 | | |
342 | | void DecodeMPLSRegisterTests(void) |
343 | 0 | { |
344 | | #ifdef UNITTESTS |
345 | | UtRegisterTest("DecodeMPLSTestHeaderTooSmall", |
346 | | DecodeMPLSTestHeaderTooSmall); |
347 | | UtRegisterTest("DecodeMPLSTestPacketTooSmall", |
348 | | DecodeMPLSTestPacketTooSmall); |
349 | | UtRegisterTest("DecodeMPLSTestBadLabelRouterAlert", |
350 | | DecodeMPLSTestBadLabelRouterAlert); |
351 | | UtRegisterTest("DecodeMPLSTestBadLabelImplicitNull", |
352 | | DecodeMPLSTestBadLabelImplicitNull); |
353 | | UtRegisterTest("DecodeMPLSTestBadLabelReserved", |
354 | | DecodeMPLSTestBadLabelReserved); |
355 | | UtRegisterTest("DecodeMPLSTestUnknownPayloadType", |
356 | | DecodeMPLSTestUnknownPayloadType); |
357 | | #endif /* UNITTESTS */ |
358 | 0 | } |