/src/suricata/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 | 38.5k | { |
49 | 38.5k | DEBUG_VALIDATE_BUG_ON(pkt == NULL); |
50 | | |
51 | 38.5k | uint32_t header_len = GRE_HDR_LEN; |
52 | 38.5k | GRESreHdr *gsre = NULL; |
53 | 38.5k | GREPPtPHd *gre_pptp_h = NULL; |
54 | | |
55 | 38.5k | StatsCounterIncr(&tv->stats, dtv->counter_gre); |
56 | | |
57 | 38.5k | if(len < GRE_HDR_LEN) { |
58 | 576 | ENGINE_SET_INVALID_EVENT(p, GRE_PKT_TOO_SMALL); |
59 | 576 | return TM_ECODE_FAILED; |
60 | 576 | } |
61 | 37.9k | if (!PacketIncreaseCheckLayers(p)) { |
62 | 34 | return TM_ECODE_FAILED; |
63 | 34 | } |
64 | | |
65 | 37.9k | GREHdr *greh = PacketSetGRE(p, pkt); |
66 | | |
67 | 37.9k | SCLogDebug("p %p pkt %p GRE protocol %04x Len: %d GRE version %x", p, pkt, GRE_GET_PROTO(greh), |
68 | 37.9k | len, GRE_GET_VERSION(greh)); |
69 | | |
70 | 37.9k | switch (GRE_GET_VERSION(greh)) { |
71 | 30.9k | 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 | 30.9k | if (GRE_FLAG_ISSET_RECUR(greh)) { |
83 | 1.02k | ENGINE_SET_INVALID_EVENT(p, GRE_VERSION0_RECUR); |
84 | 1.02k | return TM_ECODE_OK; |
85 | 1.02k | } |
86 | | |
87 | 29.9k | if (GREV1_FLAG_ISSET_FLAGS(greh)) { |
88 | 876 | ENGINE_SET_INVALID_EVENT(p, GRE_VERSION0_FLAGS); |
89 | 876 | return TM_ECODE_OK; |
90 | 876 | } |
91 | | |
92 | | /* Adjust header length based on content */ |
93 | | |
94 | 29.0k | if (GRE_FLAG_ISSET_KY(greh)) |
95 | 5.48k | header_len += GRE_KEY_LEN; |
96 | | |
97 | 29.0k | if (GRE_FLAG_ISSET_SQ(greh)) |
98 | 5.17k | header_len += GRE_SEQ_LEN; |
99 | | |
100 | 29.0k | if (GRE_FLAG_ISSET_CHKSUM(greh) || GRE_FLAG_ISSET_ROUTE(greh)) |
101 | 5.86k | header_len += GRE_CHKSUM_LEN + GRE_OFFSET_LEN; |
102 | | |
103 | 29.0k | if (header_len > len) { |
104 | 1.35k | ENGINE_SET_INVALID_EVENT(p, GRE_VERSION0_HDR_TOO_BIG); |
105 | 1.35k | return TM_ECODE_OK; |
106 | 1.35k | } |
107 | | |
108 | 27.7k | if (GRE_FLAG_ISSET_ROUTE(greh)) { |
109 | 7.65k | while (1) |
110 | 7.65k | { |
111 | 7.65k | if ((header_len + GRE_SRE_HDR_LEN) > len) { |
112 | 1.02k | ENGINE_SET_INVALID_EVENT(p, |
113 | 1.02k | GRE_VERSION0_MALFORMED_SRE_HDR); |
114 | 1.02k | return TM_ECODE_OK; |
115 | 1.02k | } |
116 | | |
117 | 6.63k | gsre = (GRESreHdr *)(pkt + header_len); |
118 | | |
119 | 6.63k | header_len += GRE_SRE_HDR_LEN; |
120 | | |
121 | 6.63k | if ((SCNtohs(gsre->af) == 0) && (gsre->sre_length == 0)) |
122 | 1.76k | break; |
123 | | |
124 | 4.87k | header_len += gsre->sre_length; |
125 | 4.87k | if (header_len > len) { |
126 | 1.59k | ENGINE_SET_INVALID_EVENT(p, |
127 | 1.59k | GRE_VERSION0_MALFORMED_SRE_HDR); |
128 | 1.59k | return TM_ECODE_OK; |
129 | 1.59k | } |
130 | 4.87k | } |
131 | 4.38k | } |
132 | 25.0k | break; |
133 | | |
134 | 25.0k | 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 | 5.25k | if (GRE_FLAG_ISSET_CHKSUM(greh)) { |
146 | 365 | ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_CHKSUM); |
147 | 365 | return TM_ECODE_OK; |
148 | 365 | } |
149 | | |
150 | 4.88k | if (GRE_FLAG_ISSET_ROUTE(greh)) { |
151 | 159 | ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_ROUTE); |
152 | 159 | return TM_ECODE_OK; |
153 | 159 | } |
154 | | |
155 | 4.72k | if (GRE_FLAG_ISSET_SSR(greh)) { |
156 | 280 | ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_SSR); |
157 | 280 | return TM_ECODE_OK; |
158 | 280 | } |
159 | | |
160 | 4.44k | if (GRE_FLAG_ISSET_RECUR(greh)) { |
161 | 341 | ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_RECUR); |
162 | 341 | return TM_ECODE_OK; |
163 | 341 | } |
164 | | |
165 | 4.10k | if (GREV1_FLAG_ISSET_FLAGS(greh)) { |
166 | 636 | ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_FLAGS); |
167 | 636 | return TM_ECODE_OK; |
168 | 636 | } |
169 | | |
170 | 3.47k | if (GRE_GET_PROTO(greh) != GRE_PROTO_PPP) { |
171 | 402 | ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_WRONG_PROTOCOL); |
172 | 402 | return TM_ECODE_OK; |
173 | 402 | } |
174 | | |
175 | 3.06k | if (!(GRE_FLAG_ISSET_KY(greh))) { |
176 | 220 | ENGINE_SET_INVALID_EVENT(p,GRE_VERSION1_NO_KEY); |
177 | 220 | return TM_ECODE_OK; |
178 | 220 | } |
179 | | |
180 | 2.84k | header_len += GRE_KEY_LEN; |
181 | | /* key is set and proto == PPP */ |
182 | 2.84k | gre_pptp_h = (GREPPtPHd *)pkt; |
183 | | |
184 | | /* Adjust header length based on content */ |
185 | | |
186 | 2.84k | if (GRE_FLAG_ISSET_SQ(greh)) |
187 | 180 | header_len += GRE_SEQ_LEN; |
188 | | |
189 | 2.84k | if (GREV1_FLAG_ISSET_ACK(greh)) |
190 | 187 | header_len += GREV1_ACK_LEN; |
191 | | |
192 | 2.84k | if (header_len > len) { |
193 | 397 | ENGINE_SET_INVALID_EVENT(p, GRE_VERSION1_HDR_TOO_BIG); |
194 | 397 | return TM_ECODE_OK; |
195 | 397 | } |
196 | | |
197 | 2.45k | break; |
198 | 2.45k | default: |
199 | 1.71k | ENGINE_SET_INVALID_EVENT(p, GRE_WRONG_VERSION); |
200 | 1.71k | return TM_ECODE_OK; |
201 | 37.9k | } |
202 | | |
203 | 27.5k | switch (GRE_GET_PROTO(greh)) { |
204 | 3.61k | case ETHERNET_TYPE_IP: |
205 | 3.61k | { |
206 | 3.61k | Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, |
207 | 3.61k | len - header_len, DECODE_TUNNEL_IPV4); |
208 | 3.61k | if (tp != NULL) { |
209 | 3.33k | PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); |
210 | 3.33k | PacketEnqueueNoLock(&tv->decode_pq,tp); |
211 | 3.33k | } |
212 | 3.61k | break; |
213 | 0 | } |
214 | | |
215 | 12.6k | case GRE_PROTO_PPP: |
216 | 12.6k | { |
217 | 12.6k | if (gre_pptp_h && !gre_pptp_h->payload_length) |
218 | 891 | return TM_ECODE_OK; |
219 | | |
220 | 11.7k | Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, |
221 | 11.7k | len - header_len, DECODE_TUNNEL_PPP); |
222 | 11.7k | if (tp != NULL) { |
223 | 11.1k | PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); |
224 | 11.1k | PacketEnqueueNoLock(&tv->decode_pq,tp); |
225 | 11.1k | } |
226 | 11.7k | break; |
227 | 12.6k | } |
228 | | |
229 | 393 | case ETHERNET_TYPE_IPV6: |
230 | 393 | { |
231 | 393 | Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, |
232 | 393 | len - header_len, DECODE_TUNNEL_IPV6); |
233 | 393 | if (tp != NULL) { |
234 | 66 | PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); |
235 | 66 | PacketEnqueueNoLock(&tv->decode_pq,tp); |
236 | 66 | } |
237 | 393 | break; |
238 | 12.6k | } |
239 | | |
240 | 1.55k | case ETHERNET_TYPE_VLAN: |
241 | 1.55k | { |
242 | 1.55k | Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, |
243 | 1.55k | len - header_len, DECODE_TUNNEL_VLAN); |
244 | 1.55k | if (tp != NULL) { |
245 | 668 | PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); |
246 | 668 | PacketEnqueueNoLock(&tv->decode_pq,tp); |
247 | 668 | } |
248 | 1.55k | break; |
249 | 12.6k | } |
250 | | |
251 | 3.93k | case ETHERNET_TYPE_ERSPAN: |
252 | 3.93k | { |
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.93k | Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, len - header_len, |
258 | 3.93k | GRE_FLAG_ISSET_SQ(greh) == 0 ? DECODE_TUNNEL_ERSPANI : DECODE_TUNNEL_ERSPANII); |
259 | 3.93k | if (tp != NULL) { |
260 | 1.06k | PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); |
261 | 1.06k | PacketEnqueueNoLock(&tv->decode_pq,tp); |
262 | 1.06k | } |
263 | 3.93k | break; |
264 | 12.6k | } |
265 | | |
266 | 639 | case ETHERNET_TYPE_BRIDGE: |
267 | 639 | { |
268 | 639 | Packet *tp = PacketTunnelPktSetup(tv, dtv, p, pkt + header_len, |
269 | 639 | len - header_len, DECODE_TUNNEL_ETHERNET); |
270 | 639 | if (tp != NULL) { |
271 | 573 | PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); |
272 | 573 | PacketEnqueueNoLock(&tv->decode_pq,tp); |
273 | 573 | } |
274 | 639 | break; |
275 | 12.6k | } |
276 | | |
277 | 93 | case ETHERNET_TYPE_ARP: { |
278 | 93 | Packet *tp = PacketTunnelPktSetup( |
279 | 93 | tv, dtv, p, pkt + header_len, len - header_len, DECODE_TUNNEL_ARP); |
280 | 93 | if (tp != NULL) { |
281 | 23 | PKT_SET_SRC(tp, PKT_SRC_DECODER_GRE); |
282 | 23 | PacketEnqueueNoLock(&tv->decode_pq, tp); |
283 | 23 | } |
284 | 93 | break; |
285 | 12.6k | } |
286 | | |
287 | 4.68k | default: |
288 | 4.68k | return TM_ECODE_OK; |
289 | 27.5k | } |
290 | 21.9k | return TM_ECODE_OK; |
291 | 27.5k | } |
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 | | PacketFree(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 | | PacketFree(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 | | PacketFree(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 | | */ |