/src/suricata8/src/decode-gre.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-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 | | * \ingroup decode |
20 | | * |
21 | | * @{ |
22 | | */ |
23 | | |
24 | | |
25 | | /** |
26 | | * \file |
27 | | * |
28 | | * \author Breno Silva <breno.silva@gmail.com> |
29 | | * |
30 | | * Decodes GRE |
31 | | */ |
32 | | |
33 | | #include "suricata-common.h" |
34 | | #include "suricata.h" |
35 | | #include "decode.h" |
36 | | #include "decode-events.h" |
37 | | #include "decode-gre.h" |
38 | | |
39 | | #include "util-validate.h" |
40 | | #include "util-unittest.h" |
41 | | #include "util-debug.h" |
42 | | |
43 | | /** |
44 | | * \brief Function to decode GRE packets |
45 | | */ |
46 | | |
47 | | int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) |
48 | 201k | { |
49 | 201k | DEBUG_VALIDATE_BUG_ON(pkt == NULL); |
50 | | |
51 | 201k | uint32_t header_len = GRE_HDR_LEN; |
52 | 201k | GRESreHdr *gsre = NULL; |
53 | 201k | GREPPtPHd *gre_pptp_h = NULL; |
54 | | |
55 | 201k | StatsIncr(tv, dtv->counter_gre); |
56 | | |
57 | 201k | if(len < GRE_HDR_LEN) { |
58 | 834 | ENGINE_SET_INVALID_EVENT(p, GRE_PKT_TOO_SMALL); |
59 | 834 | return TM_ECODE_FAILED; |
60 | 834 | } |
61 | 200k | if (!PacketIncreaseCheckLayers(p)) { |
62 | 65 | return TM_ECODE_FAILED; |
63 | 65 | } |
64 | | |
65 | 200k | GREHdr *greh = PacketSetGRE(p, pkt); |
66 | | |
67 | 200k | SCLogDebug("p %p pkt %p GRE protocol %04x Len: %d GRE version %x", p, pkt, GRE_GET_PROTO(greh), |
68 | 200k | len, GRE_GET_VERSION(greh)); |
69 | | |
70 | 200k | switch (GRE_GET_VERSION(greh)) { |
71 | 152k | case GRE_VERSION_0: |
72 | | |
73 | | /* GRE version 0 doesn't support the fields below RFC 1701 */ |
74 | | |
75 | | /** |
76 | | * \todo We need to make sure this does not allow bypassing |
77 | | * inspection. A server may just ignore these and |
78 | | * continue processing the packet, but we will not look |
79 | | * further into it. |
80 | | */ |
81 | | |
82 | 152k | if (GRE_FLAG_ISSET_RECUR(greh)) { |
83 | 1.69k | ENGINE_SET_INVALID_EVENT(p, GRE_VERSION0_RECUR); |
84 | 1.69k | return TM_ECODE_OK; |
85 | 1.69k | } |
86 | | |
87 | 150k | if (GREV1_FLAG_ISSET_FLAGS(greh)) { |
88 | 2.24k | ENGINE_SET_INVALID_EVENT(p, GRE_VERSION0_FLAGS); |
89 | 2.24k | return TM_ECODE_OK; |
90 | 2.24k | } |
91 | | |
92 | | /* Adjust header length based on content */ |
93 | | |
94 | 148k | if (GRE_FLAG_ISSET_KY(greh)) |
95 | 7.25k | header_len += GRE_KEY_LEN; |
96 | | |
97 | 148k | if (GRE_FLAG_ISSET_SQ(greh)) |
98 | 5.92k | header_len += GRE_SEQ_LEN; |
99 | | |
100 | 148k | if (GRE_FLAG_ISSET_CHKSUM(greh) || GRE_FLAG_ISSET_ROUTE(greh)) |
101 | 8.01k | header_len += GRE_CHKSUM_LEN + GRE_OFFSET_LEN; |
102 | | |
103 | 148k | if (header_len > len) { |
104 | 1.76k | ENGINE_SET_INVALID_EVENT(p, GRE_VERSION0_HDR_TOO_BIG); |
105 | 1.76k | return TM_ECODE_OK; |
106 | 1.76k | } |
107 | | |
108 | 146k | if (GRE_FLAG_ISSET_ROUTE(greh)) { |
109 | 10.7k | while (1) |
110 | 10.7k | { |
111 | 10.7k | if ((header_len + GRE_SRE_HDR_LEN) > len) { |
112 | 1.42k | ENGINE_SET_INVALID_EVENT(p, |
113 | 1.42k | GRE_VERSION0_MALFORMED_SRE_HDR); |
114 | 1.42k | return TM_ECODE_OK; |
115 | 1.42k | } |
116 | | |
117 | 9.29k | gsre = (GRESreHdr *)(pkt + header_len); |
118 | | |
119 | 9.29k | header_len += GRE_SRE_HDR_LEN; |
120 | | |
121 | 9.29k | if ((SCNtohs(gsre->af) == 0) && (gsre->sre_length == 0)) |
122 | 2.82k | break; |
123 | | |
124 | 6.47k | header_len += gsre->sre_length; |
125 | 6.47k | if (header_len > len) { |
126 | 1.75k | ENGINE_SET_INVALID_EVENT(p, |
127 | 1.75k | GRE_VERSION0_MALFORMED_SRE_HDR); |
128 | 1.75k | return TM_ECODE_OK; |
129 | 1.75k | } |
130 | 6.47k | } |
131 | 6.00k | } |
132 | 143k | break; |
133 | | |
134 | 143k | case GRE_VERSION_1: |
135 | | |
136 | | /* GRE version 1 doesn't support the fields below RFC 1701 */ |
137 | | |
138 | | /** |
139 | | * \todo We need to make sure this does not allow bypassing |
140 | | * inspection. A server may just ignore these and |
141 | | * continue processing the packet, but we will not look |
142 | | * further into it. |
143 | | */ |
144 | | |
145 | 9.28k | if (GRE_FLAG_ISSET_CHKSUM(greh)) { |
146 | 602 | ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_CHKSUM); |
147 | 602 | return TM_ECODE_OK; |
148 | 602 | } |
149 | | |
150 | 8.68k | if (GRE_FLAG_ISSET_ROUTE(greh)) { |
151 | 964 | ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_ROUTE); |
152 | 964 | return TM_ECODE_OK; |
153 | 964 | } |
154 | | |
155 | 7.72k | if (GRE_FLAG_ISSET_SSR(greh)) { |
156 | 1.60k | ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_SSR); |
157 | 1.60k | return TM_ECODE_OK; |
158 | 1.60k | } |
159 | | |
160 | 6.12k | if (GRE_FLAG_ISSET_RECUR(greh)) { |
161 | 637 | ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_RECUR); |
162 | 637 | return TM_ECODE_OK; |
163 | 637 | } |
164 | | |
165 | 5.48k | if (GREV1_FLAG_ISSET_FLAGS(greh)) { |
166 | 1.19k | ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_FLAGS); |
167 | 1.19k | return TM_ECODE_OK; |
168 | 1.19k | } |
169 | | |
170 | 4.28k | if (GRE_GET_PROTO(greh) != GRE_PROTO_PPP) { |
171 | 672 | ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_WRONG_PROTOCOL); |
172 | 672 | return TM_ECODE_OK; |
173 | 672 | } |
174 | | |
175 | 3.61k | if (!(GRE_FLAG_ISSET_KY(greh))) { |
176 | 868 | ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_NO_KEY); |
177 | 868 | return TM_ECODE_OK; |
178 | 868 | } |
179 | | |
180 | 2.74k | header_len += GRE_KEY_LEN; |
181 | | /* key is set and proto == PPP */ |
182 | 2.74k | gre_pptp_h = (GREPPtPHd *)pkt; |
183 | | |
184 | | /* Adjust header length based on content */ |
185 | | |
186 | 2.74k | if (GRE_FLAG_ISSET_SQ(greh)) |
187 | 218 | header_len += GRE_SEQ_LEN; |
188 | | |
189 | 2.74k | if (GREV1_FLAG_ISSET_ACK(greh)) |
190 | 202 | header_len += GREV1_ACK_LEN; |
191 | | |
192 | 2.74k | if (header_len > len) { |
193 | 451 | ENGINE_SET_INVALID_EVENT(p, GRE_VERSION1_HDR_TOO_BIG); |
194 | 451 | return TM_ECODE_OK; |
195 | 451 | } |
196 | | |
197 | 2.29k | break; |
198 | 38.9k | default: |
199 | 38.9k | ENGINE_SET_INVALID_EVENT(p, GRE_WRONG_VERSION); |
200 | 38.9k | return TM_ECODE_OK; |
201 | 200k | } |
202 | | |
203 | 145k | switch (GRE_GET_PROTO(greh)) { |
204 | 3.40k | case ETHERNET_TYPE_IP: |
205 | 3.40k | { |
206 | 3.40k | Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, |
207 | 3.40k | len - header_len, DECODE_TUNNEL_IPV4); |
208 | 3.40k | if (tp != NULL) { |
209 | 3.06k | PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); |
210 | 3.06k | PacketEnqueueNoLock(&tv->decode_pq,tp); |
211 | 3.06k | } |
212 | 3.40k | break; |
213 | 0 | } |
214 | | |
215 | 127k | case GRE_PROTO_PPP: |
216 | 127k | { |
217 | 127k | if (gre_pptp_h && !gre_pptp_h->payload_length) |
218 | 795 | return TM_ECODE_OK; |
219 | | |
220 | 127k | Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, |
221 | 127k | len - header_len, DECODE_TUNNEL_PPP); |
222 | 127k | if (tp != NULL) { |
223 | 123k | PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); |
224 | 123k | PacketEnqueueNoLock(&tv->decode_pq,tp); |
225 | 123k | } |
226 | 127k | break; |
227 | 127k | } |
228 | | |
229 | 392 | case ETHERNET_TYPE_IPV6: |
230 | 392 | { |
231 | 392 | Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, |
232 | 392 | len - header_len, DECODE_TUNNEL_IPV6); |
233 | 392 | if (tp != NULL) { |
234 | 84 | PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); |
235 | 84 | PacketEnqueueNoLock(&tv->decode_pq,tp); |
236 | 84 | } |
237 | 392 | break; |
238 | 127k | } |
239 | | |
240 | 998 | case ETHERNET_TYPE_VLAN: |
241 | 998 | { |
242 | 998 | Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, |
243 | 998 | len - header_len, DECODE_TUNNEL_VLAN); |
244 | 998 | if (tp != NULL) { |
245 | 559 | PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); |
246 | 559 | PacketEnqueueNoLock(&tv->decode_pq,tp); |
247 | 559 | } |
248 | 998 | break; |
249 | 127k | } |
250 | | |
251 | 3.76k | case ETHERNET_TYPE_ERSPAN: |
252 | 3.76k | { |
253 | | // Determine if it's Type I or Type II based on the flags in the GRE header. |
254 | | // Type I: 0|0|0|0|0|00000|000000000|00000 |
255 | | // Type II: 0|0|0|1|0|00000|000000000|00000 |
256 | | // Seq |
257 | 3.76k | Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, |
258 | 3.76k | GRE_FLAG_ISSET_SQ(greh) == 0 ? DECODE_TUNNEL_ERSPANI : DECODE_TUNNEL_ERSPANII); |
259 | 3.76k | if (tp != NULL) { |
260 | 1.33k | PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); |
261 | 1.33k | PacketEnqueueNoLock(&tv->decode_pq,tp); |
262 | 1.33k | } |
263 | 3.76k | break; |
264 | 127k | } |
265 | | |
266 | 803 | case ETHERNET_TYPE_BRIDGE: |
267 | 803 | { |
268 | 803 | Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, |
269 | 803 | len - header_len, DECODE_TUNNEL_ETHERNET); |
270 | 803 | if (tp != NULL) { |
271 | 575 | PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); |
272 | 575 | PacketEnqueueNoLock(&tv->decode_pq,tp); |
273 | 575 | } |
274 | 803 | break; |
275 | 127k | } |
276 | | |
277 | 1.13k | case ETHERNET_TYPE_ARP: { |
278 | 1.13k | Packet *tp = PacketTunnelPktSetup( |
279 | 1.13k | tv, dtv, p, pkt + header_len, len - header_len, DECODE_TUNNEL_ARP); |
280 | 1.13k | if (tp != NULL) { |
281 | 428 | PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); |
282 | 428 | PacketEnqueueNoLock(&tv->decode_pq, tp); |
283 | 428 | } |
284 | 1.13k | break; |
285 | 127k | } |
286 | | |
287 | 7.27k | default: |
288 | 7.27k | return TM_ECODE_OK; |
289 | 145k | } |
290 | 137k | return TM_ECODE_OK; |
291 | 145k | } |
292 | | |
293 | | |
294 | | #ifdef UNITTESTS |
295 | | /** |
296 | | * \test DecodeGRETest01 is a test for small gre packet |
297 | | */ |
298 | | |
299 | | static int DecodeGREtest01 (void) |
300 | | { |
301 | | uint8_t raw_gre[] = { 0x00 ,0x6e ,0x62 }; |
302 | | Packet *p = PacketGetFromAlloc(); |
303 | | FAIL_IF_NULL(p); |
304 | | ThreadVars tv; |
305 | | DecodeThreadVars dtv; |
306 | | |
307 | | memset(&tv, 0, sizeof(ThreadVars)); |
308 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
309 | | |
310 | | DecodeGRE(&tv, &dtv, p, raw_gre, sizeof(raw_gre)); |
311 | | FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, GRE_PKT_TOO_SMALL)); |
312 | | |
313 | | SCFree(p); |
314 | | PASS; |
315 | | } |
316 | | |
317 | | /** |
318 | | * \test DecodeGRETest02 is a test for wrong gre version |
319 | | */ |
320 | | |
321 | | static int DecodeGREtest02 (void) |
322 | | { |
323 | | uint8_t raw_gre[] = { |
324 | | 0x00, 0x6e, 0x62, 0xac, 0x40, 0x00, 0x40, 0x2f, |
325 | | 0xc2, 0xc7, 0x0a, 0x00, 0x00, 0x64, 0x0a, 0x00, |
326 | | 0x00, 0x8a, 0x30, 0x01, 0x0b, 0x00, 0x4e, 0x00, |
327 | | 0x00, 0x00, 0x18, 0x4a, 0x50, 0xff, 0x03, 0x00, |
328 | | 0x21, 0x45, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x40, |
329 | | 0x00, 0x40, 0x11, 0x94, 0x22, 0x50, 0x7e, 0x2b, |
330 | | 0x2d, 0xc2, 0x6d, 0x68, 0x68, 0x80, 0x0e, 0x00, |
331 | | 0x35, 0x00, 0x36, 0x9f, 0x18, 0xdb, 0xc4, 0x01, |
332 | | 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, |
333 | | 0x01, 0x03, 0x73, 0x31, 0x36, 0x09, 0x73, 0x69, |
334 | | 0x74, 0x65, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x03, |
335 | | 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, |
336 | | 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x00, |
337 | | 0x00, 0x00, 0x00 }; |
338 | | Packet *p = PacketGetFromAlloc(); |
339 | | FAIL_IF_NULL(p); |
340 | | ThreadVars tv; |
341 | | DecodeThreadVars dtv; |
342 | | |
343 | | memset(&tv, 0, sizeof(ThreadVars)); |
344 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
345 | | |
346 | | DecodeGRE(&tv, &dtv, p, raw_gre, sizeof(raw_gre)); |
347 | | FAIL_IF_NOT(ENGINE_ISSET_EVENT(p, GRE_WRONG_VERSION)); |
348 | | |
349 | | SCFree(p); |
350 | | PASS; |
351 | | } |
352 | | |
353 | | |
354 | | /** |
355 | | * \test DecodeGRETest03 is a test for valid gre packet |
356 | | */ |
357 | | |
358 | | static int DecodeGREtest03 (void) |
359 | | { |
360 | | uint8_t raw_gre[] = { |
361 | | 0x00, 0x6e, 0x62, 0xac, 0x40, 0x00, 0x40, 0x2f, |
362 | | 0xc2, 0xc7, 0x0a, 0x00, 0x00, 0x64, 0x0a, 0x00, |
363 | | 0x00, 0x8a, 0x30, 0x01, 0x88, 0x0b, 0x00, 0x4e, |
364 | | 0x00, 0x00, 0x00, 0x18, 0x4a, 0x50, 0xff, 0x03, |
365 | | 0x00, 0x21, 0x45, 0x00, 0x00, 0x4a, 0x00, 0x00, |
366 | | 0x40, 0x00, 0x40, 0x11, 0x94, 0x22, 0x50, 0x7e, |
367 | | 0x2b, 0x2d, 0xc2, 0x6d, 0x68, 0x68, 0x80, 0x0e, |
368 | | 0x00, 0x35, 0x00, 0x36, 0x9f, 0x18, 0xdb, 0xc4, |
369 | | 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, |
370 | | 0x00, 0x01, 0x03, 0x73, 0x31, 0x36, 0x09, 0x73, |
371 | | 0x69, 0x74, 0x65, 0x6d, 0x65, 0x74, 0x65, 0x72, |
372 | | 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, |
373 | | 0x01, 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, |
374 | | 0x00, 0x00, 0x00, 0x00 }; |
375 | | Packet *p = PacketGetFromAlloc(); |
376 | | FAIL_IF_NULL(p); |
377 | | ThreadVars tv; |
378 | | DecodeThreadVars dtv; |
379 | | |
380 | | memset(&tv, 0, sizeof(ThreadVars)); |
381 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
382 | | |
383 | | DecodeGRE(&tv, &dtv, p, raw_gre, sizeof(raw_gre)); |
384 | | FAIL_IF_NOT(PacketIsGRE(p)); |
385 | | |
386 | | SCFree(p); |
387 | | PASS; |
388 | | } |
389 | | #endif /* UNITTESTS */ |
390 | | |
391 | | /** |
392 | | * \brief this function registers unit tests for GRE decoder |
393 | | */ |
394 | | |
395 | | void DecodeGRERegisterTests(void) |
396 | 0 | { |
397 | | #ifdef UNITTESTS |
398 | | UtRegisterTest("DecodeGREtest01", DecodeGREtest01); |
399 | | UtRegisterTest("DecodeGREtest02", DecodeGREtest02); |
400 | | UtRegisterTest("DecodeGREtest03", DecodeGREtest03); |
401 | | #endif /* UNITTESTS */ |
402 | 0 | } |
403 | | /** |
404 | | * @} |
405 | | */ |