/src/suricata/src/decode-icmpv4.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2020 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 Victor Julien <victor@inliniac.net> |
29 | | * |
30 | | * Decode ICMPv4 |
31 | | */ |
32 | | |
33 | | #include "suricata-common.h" |
34 | | |
35 | | #include "decode.h" |
36 | | #include "decode-events.h" |
37 | | #include "decode-ipv4.h" |
38 | | #include "decode-icmpv4.h" |
39 | | |
40 | | #include "flow.h" |
41 | | |
42 | | #include "util-unittest.h" |
43 | | #include "util-unittest-helper.h" |
44 | | #include "util-debug.h" |
45 | | #include "util-print.h" |
46 | | #include "util-validate.h" |
47 | | |
48 | | /** |
49 | | * Note, this is the IP header, plus a bit of the original packet, not the whole thing! |
50 | | */ |
51 | | static int DecodePartialIPV4(Packet* p, uint8_t* partial_packet, uint16_t len) |
52 | 6.51k | { |
53 | | /** Check the sizes, the header must fit at least */ |
54 | 6.51k | if (len < IPV4_HEADER_LEN) { |
55 | 770 | SCLogDebug("DecodePartialIPV4: ICMPV4_IPV4_TRUNC_PKT"); |
56 | 770 | ENGINE_SET_INVALID_EVENT(p, ICMPV4_IPV4_TRUNC_PKT); |
57 | 770 | return -1; |
58 | 770 | } |
59 | | |
60 | 5.74k | IPV4Hdr *icmp4_ip4h = (IPV4Hdr*)partial_packet; |
61 | | |
62 | | /** Check the embedded version */ |
63 | 5.74k | if (IPV4_GET_RAW_VER(icmp4_ip4h) != 4) { |
64 | | /** Check the embedded version */ |
65 | 850 | SCLogDebug("DecodePartialIPV4: ICMPv4 contains Unknown IPV4 version " |
66 | 850 | "ICMPV4_IPV4_UNKNOWN_VER"); |
67 | 850 | ENGINE_SET_INVALID_EVENT(p, ICMPV4_IPV4_UNKNOWN_VER); |
68 | 850 | return -1; |
69 | 850 | } |
70 | | |
71 | | /** We need to fill icmpv4vars */ |
72 | 4.89k | const uint8_t *icmpv4_ptr = (const uint8_t *)p->l4.hdrs.icmpv4h; |
73 | 4.89k | DEBUG_VALIDATE_BUG_ON((ptrdiff_t)(partial_packet - icmpv4_ptr) > (ptrdiff_t)UINT16_MAX); |
74 | 4.89k | p->l4.vars.icmpv4.emb_ip4h_offset = (uint16_t)(partial_packet - icmpv4_ptr); |
75 | | |
76 | 4.89k | switch (IPV4_GET_RAW_IPPROTO(icmp4_ip4h)) { |
77 | 1.75k | case IPPROTO_TCP: |
78 | 1.75k | if (len >= IPV4_HEADER_LEN + TCP_HEADER_LEN ) { |
79 | 1.49k | TCPHdr *emb_tcph = (TCPHdr *)(partial_packet + IPV4_HEADER_LEN); |
80 | 1.49k | p->l4.vars.icmpv4.emb_sport = SCNtohs(emb_tcph->th_sport); |
81 | 1.49k | p->l4.vars.icmpv4.emb_dport = SCNtohs(emb_tcph->th_dport); |
82 | 1.49k | p->l4.vars.icmpv4.emb_ports_set = true; |
83 | 1.49k | p->l4.vars.icmpv4.emb_ip4_proto = IPPROTO_TCP; |
84 | | |
85 | 1.49k | SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->TCP header sport: " |
86 | 1.49k | "%" PRIu16 " dport %" PRIu16 "", |
87 | 1.49k | p->l4.vars.icmpv4.emb_sport, p->l4.vars.icmpv4.emb_dport); |
88 | 1.49k | } else if (len >= IPV4_HEADER_LEN + 4) { |
89 | | /* only access th_sport and th_dport */ |
90 | 62 | TCPHdr *emb_tcph = (TCPHdr *)(partial_packet + IPV4_HEADER_LEN); |
91 | 62 | p->l4.vars.icmpv4.emb_sport = SCNtohs(emb_tcph->th_sport); |
92 | 62 | p->l4.vars.icmpv4.emb_dport = SCNtohs(emb_tcph->th_dport); |
93 | 62 | p->l4.vars.icmpv4.emb_ports_set = true; |
94 | 62 | p->l4.vars.icmpv4.emb_ip4_proto = IPPROTO_TCP; |
95 | 62 | SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->TCP partial header sport: " |
96 | 62 | "%" PRIu16 " dport %" PRIu16 "", |
97 | 62 | p->l4.vars.icmpv4.emb_sport, p->l4.vars.icmpv4.emb_dport); |
98 | 196 | } else { |
99 | 196 | SCLogDebug("DecodePartialIPV4: Warning, ICMPV4->IPV4->TCP " |
100 | 196 | "header Didn't fit in the packet!"); |
101 | 196 | p->l4.vars.icmpv4.emb_sport = 0; |
102 | 196 | p->l4.vars.icmpv4.emb_dport = 0; |
103 | 196 | } |
104 | | |
105 | 1.75k | break; |
106 | 1.14k | case IPPROTO_UDP: |
107 | 1.14k | if (len >= IPV4_HEADER_LEN + UDP_HEADER_LEN ) { |
108 | 907 | UDPHdr *emb_udph = (UDPHdr *)(partial_packet + IPV4_HEADER_LEN); |
109 | 907 | p->l4.vars.icmpv4.emb_sport = SCNtohs(emb_udph->uh_sport); |
110 | 907 | p->l4.vars.icmpv4.emb_dport = SCNtohs(emb_udph->uh_dport); |
111 | 907 | p->l4.vars.icmpv4.emb_ports_set = true; |
112 | 907 | p->l4.vars.icmpv4.emb_ip4_proto = IPPROTO_UDP; |
113 | | |
114 | 907 | SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->UDP header sport: " |
115 | 907 | "%" PRIu16 " dport %" PRIu16 "", |
116 | 907 | p->l4.vars.icmpv4.emb_sport, p->l4.vars.icmpv4.emb_dport); |
117 | 907 | } else { |
118 | 234 | SCLogDebug("DecodePartialIPV4: Warning, ICMPV4->IPV4->UDP " |
119 | 234 | "header Didn't fit in the packet!"); |
120 | 234 | p->l4.vars.icmpv4.emb_sport = 0; |
121 | 234 | p->l4.vars.icmpv4.emb_dport = 0; |
122 | 234 | } |
123 | | |
124 | 1.14k | break; |
125 | 576 | case IPPROTO_ICMP: |
126 | 576 | if (len >= IPV4_HEADER_LEN + ICMPV4_HEADER_LEN) { |
127 | 104 | p->l4.vars.icmpv4.emb_sport = 0; |
128 | 104 | p->l4.vars.icmpv4.emb_dport = 0; |
129 | 104 | p->l4.vars.icmpv4.emb_ip4_proto = IPPROTO_ICMP; |
130 | | |
131 | 104 | SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->ICMP header"); |
132 | 104 | } |
133 | | |
134 | 576 | break; |
135 | 4.89k | } |
136 | | |
137 | 4.89k | return 0; |
138 | 4.89k | } |
139 | | |
140 | | /** DecodeICMPV4 |
141 | | * \brief Main ICMPv4 decoding function |
142 | | */ |
143 | | int DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len) |
144 | 108k | { |
145 | 108k | StatsCounterIncr(&tv->stats, dtv->counter_icmpv4); |
146 | | |
147 | 108k | if (len < ICMPV4_HEADER_LEN) { |
148 | 3.60k | ENGINE_SET_INVALID_EVENT(p, ICMPV4_PKT_TOO_SMALL); |
149 | 3.60k | return TM_ECODE_FAILED; |
150 | 3.60k | } |
151 | | |
152 | 104k | ICMPV4Hdr *icmpv4h = PacketSetICMPv4(p, pkt); |
153 | | |
154 | 104k | SCLogDebug("ICMPV4 TYPE %" PRIu32 " CODE %" PRIu32 "", icmpv4h->type, icmpv4h->code); |
155 | | |
156 | 104k | p->proto = IPPROTO_ICMP; |
157 | 104k | const uint8_t type = p->icmp_s.type = icmpv4h->type; |
158 | 104k | const uint8_t code = p->icmp_s.code = icmpv4h->code; |
159 | | |
160 | 104k | int ctype = ICMPv4GetCounterpart(type); |
161 | 104k | if (ctype != -1) { |
162 | 64.4k | p->icmp_d.type = (uint8_t)ctype; |
163 | 64.4k | } |
164 | | |
165 | 104k | ICMPV4ExtHdr *icmp4eh = (ICMPV4ExtHdr *)icmpv4h; |
166 | 104k | p->l4.vars.icmpv4.hlen = ICMPV4_HEADER_LEN; |
167 | | |
168 | 104k | switch (type) { |
169 | 19.5k | case ICMP_ECHOREPLY: |
170 | 19.5k | p->l4.vars.icmpv4.id = icmp4eh->id; |
171 | 19.5k | p->l4.vars.icmpv4.seq = icmp4eh->seq; |
172 | 19.5k | if (code != 0) { |
173 | 5.12k | ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); |
174 | 5.12k | } |
175 | 19.5k | break; |
176 | | |
177 | 10.0k | case ICMP_DEST_UNREACH: |
178 | 10.0k | if (code > NR_ICMP_UNREACH) { |
179 | 1.05k | ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); |
180 | 8.97k | } else { |
181 | | /* parse IP header plus 64 bytes */ |
182 | 8.97k | if (len > ICMPV4_HEADER_PKT_OFFSET) { |
183 | 7.42k | if (unlikely(len > ICMPV4_HEADER_PKT_OFFSET + USHRT_MAX)) { |
184 | 0 | return TM_ECODE_FAILED; |
185 | 0 | } |
186 | 7.42k | (void)DecodePartialIPV4(p, (uint8_t *)(pkt + ICMPV4_HEADER_PKT_OFFSET), |
187 | 7.42k | (uint16_t)(len - ICMPV4_HEADER_PKT_OFFSET)); |
188 | 7.42k | } |
189 | 8.97k | } |
190 | 10.0k | break; |
191 | | |
192 | 10.0k | case ICMP_SOURCE_QUENCH: |
193 | 4.28k | if (code != 0) { |
194 | 758 | ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); |
195 | 3.52k | } else { |
196 | | // parse IP header plus 64 bytes |
197 | 3.52k | if (len >= ICMPV4_HEADER_PKT_OFFSET) { |
198 | 3.52k | if (unlikely(len > ICMPV4_HEADER_PKT_OFFSET + USHRT_MAX)) { |
199 | 0 | return TM_ECODE_FAILED; |
200 | 0 | } |
201 | 3.52k | DecodePartialIPV4(p, (uint8_t *)(pkt + ICMPV4_HEADER_PKT_OFFSET), |
202 | 3.52k | (uint16_t)(len - ICMPV4_HEADER_PKT_OFFSET)); |
203 | 3.52k | } |
204 | 3.52k | } |
205 | 4.28k | break; |
206 | | |
207 | 4.28k | case ICMP_REDIRECT: |
208 | 2.42k | if (code > ICMP_REDIR_HOSTTOS) { |
209 | 840 | ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); |
210 | 1.58k | } else { |
211 | | // parse IP header plus 64 bytes |
212 | 1.58k | if (len > ICMPV4_HEADER_PKT_OFFSET) { |
213 | 1.05k | if (unlikely(len > ICMPV4_HEADER_PKT_OFFSET + USHRT_MAX)) { |
214 | 0 | return TM_ECODE_FAILED; |
215 | 0 | } |
216 | 1.05k | DecodePartialIPV4(p, (uint8_t *)(pkt + ICMPV4_HEADER_PKT_OFFSET), |
217 | 1.05k | (uint16_t)(len - ICMPV4_HEADER_PKT_OFFSET)); |
218 | 1.05k | } |
219 | 1.58k | } |
220 | 2.42k | break; |
221 | | |
222 | 20.7k | case ICMP_ECHO: |
223 | 20.7k | p->l4.vars.icmpv4.id = icmp4eh->id; |
224 | 20.7k | p->l4.vars.icmpv4.seq = icmp4eh->seq; |
225 | 20.7k | if (code != 0) { |
226 | 5.60k | ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); |
227 | 5.60k | } |
228 | 20.7k | break; |
229 | | |
230 | 3.00k | case ICMP_TIME_EXCEEDED: |
231 | 3.00k | if (code > ICMP_EXC_FRAGTIME) { |
232 | 1.92k | ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); |
233 | 1.92k | } else { |
234 | | // parse IP header plus 64 bytes |
235 | 1.07k | if (len > ICMPV4_HEADER_PKT_OFFSET) { |
236 | 891 | if (unlikely(len > ICMPV4_HEADER_PKT_OFFSET + USHRT_MAX)) { |
237 | 0 | return TM_ECODE_FAILED; |
238 | 0 | } |
239 | 891 | DecodePartialIPV4(p, (uint8_t *)(pkt + ICMPV4_HEADER_PKT_OFFSET), |
240 | 891 | (uint16_t)(len - ICMPV4_HEADER_PKT_OFFSET)); |
241 | 891 | } |
242 | 1.07k | } |
243 | 3.00k | break; |
244 | | |
245 | 3.00k | case ICMP_PARAMETERPROB: |
246 | 2.93k | if (code != 0) { |
247 | 2.14k | ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); |
248 | 2.14k | } else { |
249 | | // parse IP header plus 64 bytes |
250 | 791 | if (len > ICMPV4_HEADER_PKT_OFFSET) { |
251 | 443 | if (unlikely(len > ICMPV4_HEADER_PKT_OFFSET + USHRT_MAX)) { |
252 | 0 | return TM_ECODE_FAILED; |
253 | 0 | } |
254 | 443 | DecodePartialIPV4(p, (uint8_t *)(pkt + ICMPV4_HEADER_PKT_OFFSET), |
255 | 443 | (uint16_t)(len - ICMPV4_HEADER_PKT_OFFSET)); |
256 | 443 | } |
257 | 791 | } |
258 | 2.93k | break; |
259 | | |
260 | 2.93k | case ICMP_TIMESTAMP: |
261 | 2.82k | p->l4.vars.icmpv4.id = icmp4eh->id; |
262 | 2.82k | p->l4.vars.icmpv4.seq = icmp4eh->seq; |
263 | 2.82k | if (code != 0) { |
264 | 1.76k | ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); |
265 | 1.76k | } |
266 | | |
267 | 2.82k | if (len < (sizeof(ICMPV4Timestamp) + ICMPV4_HEADER_LEN)) { |
268 | 1.02k | ENGINE_SET_EVENT(p, ICMPV4_IPV4_TRUNC_PKT); |
269 | 1.79k | } else { |
270 | 1.79k | p->l4.vars.icmpv4.hlen += sizeof(ICMPV4Timestamp); |
271 | 1.79k | } |
272 | 2.82k | break; |
273 | | |
274 | 2.54k | case ICMP_TIMESTAMPREPLY: |
275 | 2.54k | p->l4.vars.icmpv4.id = icmp4eh->id; |
276 | 2.54k | p->l4.vars.icmpv4.seq = icmp4eh->seq; |
277 | 2.54k | if (code != 0) { |
278 | 1.16k | ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); |
279 | 1.16k | } |
280 | | |
281 | 2.54k | if (len < (sizeof(ICMPV4Timestamp) + ICMPV4_HEADER_LEN)) { |
282 | 2.12k | ENGINE_SET_EVENT(p, ICMPV4_IPV4_TRUNC_PKT); |
283 | 2.12k | } else { |
284 | 421 | p->l4.vars.icmpv4.hlen += sizeof(ICMPV4Timestamp); |
285 | 421 | } |
286 | 2.54k | break; |
287 | | |
288 | 1.75k | case ICMP_INFO_REQUEST: |
289 | 1.75k | p->l4.vars.icmpv4.id = icmp4eh->id; |
290 | 1.75k | p->l4.vars.icmpv4.seq = icmp4eh->seq; |
291 | 1.75k | if (code != 0) { |
292 | 874 | ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); |
293 | 874 | } |
294 | 1.75k | break; |
295 | | |
296 | 3.23k | case ICMP_INFO_REPLY: |
297 | 3.23k | p->l4.vars.icmpv4.id = icmp4eh->id; |
298 | 3.23k | p->l4.vars.icmpv4.seq = icmp4eh->seq; |
299 | 3.23k | if (code != 0) { |
300 | 1.61k | ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); |
301 | 1.61k | } |
302 | 3.23k | break; |
303 | | |
304 | 4.35k | case ICMP_ROUTERADVERT: { |
305 | | /* pkt points to beginning of icmp message */ |
306 | 4.35k | ICMPV4RtrAdvert *icmpv4_router_advert = (ICMPV4RtrAdvert *)(pkt + sizeof(ICMPV4Hdr)); |
307 | 4.35k | uint32_t advert_len = icmpv4_router_advert->naddr * |
308 | 4.35k | (icmpv4_router_advert->addr_sz * sizeof(uint32_t)); |
309 | 4.35k | if (len < (advert_len + ICMPV4_HEADER_LEN)) { |
310 | 3.17k | ENGINE_SET_EVENT(p, ICMPV4_IPV4_TRUNC_PKT); |
311 | 3.17k | } else { |
312 | 1.18k | p->l4.vars.icmpv4.hlen += advert_len; |
313 | 1.18k | } |
314 | 4.35k | } break; |
315 | | |
316 | 2.83k | case ICMP_ADDRESS: |
317 | 2.83k | p->l4.vars.icmpv4.id = icmp4eh->id; |
318 | 2.83k | p->l4.vars.icmpv4.seq = icmp4eh->seq; |
319 | 2.83k | if (code != 0) { |
320 | 1.54k | ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); |
321 | 1.54k | } |
322 | 2.83k | break; |
323 | | |
324 | 4.05k | case ICMP_ADDRESSREPLY: |
325 | 4.05k | p->l4.vars.icmpv4.id = icmp4eh->id; |
326 | 4.05k | p->l4.vars.icmpv4.seq = icmp4eh->seq; |
327 | 4.05k | if (code != 0) { |
328 | 3.21k | ENGINE_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); |
329 | 3.21k | } |
330 | 4.05k | break; |
331 | | |
332 | 20.1k | default: |
333 | 20.1k | ENGINE_SET_EVENT(p, ICMPV4_UNKNOWN_TYPE); |
334 | 104k | } |
335 | | |
336 | 104k | p->payload = (uint8_t *)pkt + p->l4.vars.icmpv4.hlen; |
337 | 104k | DEBUG_VALIDATE_BUG_ON(len - p->l4.vars.icmpv4.hlen > UINT16_MAX); |
338 | 104k | p->payload_len = (uint16_t)(len - p->l4.vars.icmpv4.hlen); |
339 | | |
340 | 104k | FlowSetupPacket(p); |
341 | 104k | return TM_ECODE_OK; |
342 | 104k | } |
343 | | |
344 | | /** \retval type counterpart type or -1 */ |
345 | | int ICMPv4GetCounterpart(uint8_t type) |
346 | 111k | { |
347 | 111k | #define CASE_CODE(t,r) case (t): return r; case (r): return t; |
348 | 111k | switch (type) { |
349 | 22.0k | CASE_CODE(ICMP_ECHO, ICMP_ECHOREPLY); |
350 | 2.95k | CASE_CODE(ICMP_TIMESTAMP, ICMP_TIMESTAMPREPLY); |
351 | 1.90k | CASE_CODE(ICMP_INFO_REQUEST, ICMP_INFO_REPLY); |
352 | 2.70k | CASE_CODE(ICMP_ROUTERSOLICIT, ICMP_ROUTERADVERT); |
353 | 2.98k | CASE_CODE(ICMP_ADDRESS, ICMP_ADDRESSREPLY); |
354 | 43.2k | default: |
355 | 43.2k | return -1; |
356 | 111k | } |
357 | 111k | #undef CASE_CODE |
358 | 111k | } |
359 | | |
360 | | #ifdef UNITTESTS |
361 | | |
362 | | /** DecodeICMPV4test01 |
363 | | * \brief |
364 | | * \retval 1 Expected test value |
365 | | */ |
366 | | static int DecodeICMPV4test01(void) |
367 | | { |
368 | | uint8_t raw_icmpv4[] = { |
369 | | 0x08, 0x00, 0x78, 0x47, 0xfc, 0x55, 0x00, 0x04, |
370 | | 0x52, 0xab, 0x86, 0x4a, 0x84, 0x50, 0x0e, 0x00, |
371 | | 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, |
372 | | 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, |
373 | | 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, |
374 | | 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, |
375 | | 0xab }; |
376 | | Packet *p = PacketGetFromAlloc(); |
377 | | FAIL_IF_NULL(p); |
378 | | ThreadVars tv; |
379 | | DecodeThreadVars dtv; |
380 | | IPV4Hdr ip4h; |
381 | | |
382 | | memset(&ip4h, 0, sizeof(IPV4Hdr)); |
383 | | memset(&tv, 0, sizeof(ThreadVars)); |
384 | | memset(&ip4h, 0, sizeof(IPV4Hdr)); |
385 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
386 | | |
387 | | FlowInitConfig(FLOW_QUIET); |
388 | | |
389 | | p->src.family = AF_INET; |
390 | | p->dst.family = AF_INET; |
391 | | p->src.addr_data32[0] = UTHSetIPv4Address("4.3.2.1"); |
392 | | p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); |
393 | | |
394 | | ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; |
395 | | ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; |
396 | | UTHSetIPV4Hdr(p, &ip4h); |
397 | | |
398 | | DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4)); |
399 | | FAIL_IF_NOT(PacketIsICMPv4(p)); |
400 | | |
401 | | const ICMPV4Hdr *icmpv4h = PacketGetICMPv4(p); |
402 | | FAIL_IF_NULL(icmpv4h); |
403 | | |
404 | | FAIL_IF_NOT(icmpv4h->type == 8); |
405 | | FAIL_IF_NOT(icmpv4h->code == 0); |
406 | | |
407 | | FlowShutdown(); |
408 | | PacketFree(p); |
409 | | PASS; |
410 | | } |
411 | | |
412 | | /** DecodeICMPV4test02 |
413 | | * \brief |
414 | | * \retval 1 Expected test value |
415 | | */ |
416 | | static int DecodeICMPV4test02(void) |
417 | | { |
418 | | uint8_t raw_icmpv4[] = { |
419 | | 0x00, 0x00, 0x57, 0x64, 0xfb, 0x55, 0x00, 0x03, |
420 | | 0x43, 0xab, 0x86, 0x4a, 0xf6, 0x49, 0x02, 0x00, |
421 | | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
422 | | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
423 | | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, |
424 | | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, |
425 | | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f }; |
426 | | Packet *p = PacketGetFromAlloc(); |
427 | | FAIL_IF_NULL(p); |
428 | | ThreadVars tv; |
429 | | DecodeThreadVars dtv; |
430 | | IPV4Hdr ip4h; |
431 | | |
432 | | memset(&ip4h, 0, sizeof(IPV4Hdr)); |
433 | | memset(&tv, 0, sizeof(ThreadVars)); |
434 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
435 | | |
436 | | FlowInitConfig(FLOW_QUIET); |
437 | | |
438 | | p->src.family = AF_INET; |
439 | | p->dst.family = AF_INET; |
440 | | p->src.addr_data32[0] = UTHSetIPv4Address("4.3.2.1"); |
441 | | p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); |
442 | | |
443 | | ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; |
444 | | ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; |
445 | | UTHSetIPV4Hdr(p, &ip4h); |
446 | | |
447 | | DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4)); |
448 | | FAIL_IF_NOT(PacketIsICMPv4(p)); |
449 | | |
450 | | const ICMPV4Hdr *icmpv4h = PacketGetICMPv4(p); |
451 | | FAIL_IF_NULL(icmpv4h); |
452 | | |
453 | | FAIL_IF_NOT(icmpv4h->type == 0); |
454 | | FAIL_IF_NOT(icmpv4h->code == 0); |
455 | | |
456 | | FlowShutdown(); |
457 | | PacketFree(p); |
458 | | PASS; |
459 | | } |
460 | | |
461 | | /** DecodeICMPV4test03 |
462 | | * \brief TTL exceeded |
463 | | * \retval Expected test value: 1 |
464 | | */ |
465 | | static int DecodeICMPV4test03(void) |
466 | | { |
467 | | uint8_t raw_icmpv4[] = { |
468 | | 0x0b, 0x00, 0x6a, 0x3d, 0x00, 0x00, 0x00, 0x00, |
469 | | 0x45, 0x00, 0x00, 0x3c, 0x64, 0x15, 0x00, 0x00, |
470 | | 0x01, 0x11, 0xde, 0xfd, 0xc0, 0xa8, 0x01, 0x0d, |
471 | | 0xd1, 0x55, 0xe3, 0x93, 0x8b, 0x12, 0x82, 0xaa, |
472 | | 0x00, 0x28, 0x7c, 0xdd }; |
473 | | Packet *p = PacketGetFromAlloc(); |
474 | | FAIL_IF_NULL(p); |
475 | | ThreadVars tv; |
476 | | DecodeThreadVars dtv; |
477 | | IPV4Hdr ip4h; |
478 | | |
479 | | memset(&ip4h, 0, sizeof(IPV4Hdr)); |
480 | | memset(&tv, 0, sizeof(ThreadVars)); |
481 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
482 | | |
483 | | FlowInitConfig(FLOW_QUIET); |
484 | | |
485 | | p->src.family = AF_INET; |
486 | | p->dst.family = AF_INET; |
487 | | p->src.addr_data32[0] = UTHSetIPv4Address("4.3.2.1"); |
488 | | p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); |
489 | | |
490 | | ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; |
491 | | ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; |
492 | | UTHSetIPV4Hdr(p, &ip4h); |
493 | | |
494 | | DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4)); |
495 | | FAIL_IF_NOT(PacketIsICMPv4(p)); |
496 | | |
497 | | const ICMPV4Hdr *icmpv4h = PacketGetICMPv4(p); |
498 | | FAIL_IF_NULL(icmpv4h); |
499 | | |
500 | | /* check it's type 11 code 0 */ |
501 | | FAIL_IF_NOT(icmpv4h->type == 11); |
502 | | FAIL_IF_NOT(icmpv4h->code == 0); |
503 | | |
504 | | /* check it's source port 35602 to port 33450 */ |
505 | | FAIL_IF(p->l4.vars.icmpv4.emb_sport != 35602); |
506 | | FAIL_IF(p->l4.vars.icmpv4.emb_dport != 33450); |
507 | | |
508 | | /* check the src,dst IPs contained inside */ |
509 | | uint32_t src_ip = IPV4_GET_RAW_IPSRC_U32(PacketGetICMPv4EmbIPv4(p)); |
510 | | uint32_t dst_ip = IPV4_GET_RAW_IPDST_U32(PacketGetICMPv4EmbIPv4(p)); |
511 | | char s[16], d[16]; |
512 | | PrintInet(AF_INET, &src_ip, s, sizeof(s)); |
513 | | PrintInet(AF_INET, &dst_ip, d, sizeof(d)); |
514 | | |
515 | | /* ICMPv4 embedding IPV4 192.168.1.13->209.85.227.147 pass */ |
516 | | FAIL_IF_NOT(strcmp(s, "192.168.1.13") == 0); |
517 | | FAIL_IF_NOT(strcmp(d, "209.85.227.147") == 0); |
518 | | |
519 | | FlowShutdown(); |
520 | | PacketFree(p); |
521 | | PASS; |
522 | | } |
523 | | |
524 | | /** DecodeICMPV4test04 |
525 | | * \brief dest. unreachable, administratively prohibited |
526 | | * \retval 1 Expected test value |
527 | | */ |
528 | | static int DecodeICMPV4test04(void) |
529 | | { |
530 | | uint8_t raw_icmpv4[] = { |
531 | | 0x03, 0x0a, 0x36, 0xc3, 0x00, 0x00, 0x00, 0x00, |
532 | | 0x45, 0x00, 0x00, 0x3c, 0x62, 0xee, 0x40, 0x00, |
533 | | 0x33, 0x06, 0xb4, 0x8f, 0xc0, 0xa8, 0x01, 0x0d, |
534 | | 0x58, 0x60, 0x16, 0x29, 0xb1, 0x0a, 0x00, 0x32, |
535 | | 0x3e, 0x36, 0x38, 0x7c, 0x00, 0x00, 0x00, 0x00, |
536 | | 0xa0, 0x02, 0x16, 0xd0, 0x72, 0x04, 0x00, 0x00, |
537 | | 0x02, 0x04, 0x05, 0x8a, 0x04, 0x02, 0x08, 0x0a }; |
538 | | Packet *p = PacketGetFromAlloc(); |
539 | | if (unlikely(p == NULL)) |
540 | | return 0; |
541 | | ThreadVars tv; |
542 | | DecodeThreadVars dtv; |
543 | | int ret = 0; |
544 | | IPV4Hdr ip4h; |
545 | | |
546 | | memset(&ip4h, 0, sizeof(IPV4Hdr)); |
547 | | memset(&tv, 0, sizeof(ThreadVars)); |
548 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
549 | | |
550 | | FlowInitConfig(FLOW_QUIET); |
551 | | |
552 | | p->src.family = AF_INET; |
553 | | p->dst.family = AF_INET; |
554 | | p->src.addr_data32[0] = UTHSetIPv4Address("4.3.2.1"); |
555 | | p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); |
556 | | |
557 | | ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; |
558 | | ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; |
559 | | UTHSetIPV4Hdr(p, &ip4h); |
560 | | |
561 | | DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4)); |
562 | | FAIL_IF_NOT(PacketIsICMPv4(p)); |
563 | | |
564 | | const ICMPV4Hdr *icmpv4h = PacketGetICMPv4(p); |
565 | | FAIL_IF_NULL(icmpv4h); |
566 | | |
567 | | /* check the type,code pair is correct - type 3, code 10 */ |
568 | | FAIL_IF_NOT(icmpv4h->type == 3); |
569 | | FAIL_IF_NOT(icmpv4h->code == 10); |
570 | | |
571 | | /* check it's src port 45322 to dst port 50 */ |
572 | | if (p->l4.vars.icmpv4.emb_sport != 45322 || p->l4.vars.icmpv4.emb_dport != 50) { |
573 | | goto end; |
574 | | } |
575 | | |
576 | | // check the src,dst IPs contained inside |
577 | | uint32_t src_ip = IPV4_GET_RAW_IPSRC_U32(PacketGetICMPv4EmbIPv4(p)); |
578 | | uint32_t dst_ip = IPV4_GET_RAW_IPDST_U32(PacketGetICMPv4EmbIPv4(p)); |
579 | | char s[16], d[16]; |
580 | | PrintInet(AF_INET, &src_ip, s, sizeof(s)); |
581 | | PrintInet(AF_INET, &dst_ip, d, sizeof(d)); |
582 | | |
583 | | // ICMPv4 embedding IPV4 192.168.1.13->88.96.22.41 |
584 | | if (strcmp(s, "192.168.1.13") == 0 && strcmp(d, "88.96.22.41") == 0) { |
585 | | ret = 1; |
586 | | } |
587 | | |
588 | | end: |
589 | | FlowShutdown(); |
590 | | PacketFree(p); |
591 | | return ret; |
592 | | } |
593 | | |
594 | | /** DecodeICMPV4test05 |
595 | | * \brief dest. unreachable, administratively prohibited |
596 | | * \retval 1 Expected test value |
597 | | */ |
598 | | static int DecodeICMPV4test05(void) |
599 | | { |
600 | | uint8_t raw_icmpv4[] = { |
601 | | 0x0b, 0x00, 0x5c, 0x46, 0x00, 0x00, 0x00, 0x00, 0x45, |
602 | | 0x00, 0x00, 0x30, 0x02, 0x17, 0x40, 0x00, 0x01, 0x06, |
603 | | 0xd6, 0xbd, 0xc0, 0xa8, 0x02, 0x05, 0x3d, 0x23, 0xa1, |
604 | | 0x23, 0x04, 0x18, 0x00, 0x50, 0xd2, 0x08, 0xc2, 0x48, |
605 | | }; |
606 | | Packet *p = PacketGetFromAlloc(); |
607 | | if (unlikely(p == NULL)) |
608 | | return 0; |
609 | | ThreadVars tv; |
610 | | DecodeThreadVars dtv; |
611 | | int ret = 0; |
612 | | IPV4Hdr ip4h; |
613 | | |
614 | | memset(&ip4h, 0, sizeof(IPV4Hdr)); |
615 | | memset(&tv, 0, sizeof(ThreadVars)); |
616 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
617 | | |
618 | | FlowInitConfig(FLOW_QUIET); |
619 | | |
620 | | p->src.family = AF_INET; |
621 | | p->dst.family = AF_INET; |
622 | | p->src.addr_data32[0] = UTHSetIPv4Address("4.3.2.1"); |
623 | | p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); |
624 | | |
625 | | ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; |
626 | | ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; |
627 | | UTHSetIPV4Hdr(p, &ip4h); |
628 | | |
629 | | DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4)); |
630 | | FAIL_IF_NOT(PacketIsICMPv4(p)); |
631 | | |
632 | | const ICMPV4Hdr *icmpv4h = PacketGetICMPv4(p); |
633 | | FAIL_IF_NULL(icmpv4h); |
634 | | |
635 | | /* check the type,code pair is correct - type 11, code 0 */ |
636 | | FAIL_IF_NOT(icmpv4h->type == 11); |
637 | | FAIL_IF_NOT(icmpv4h->code == 0); |
638 | | |
639 | | /* check it's src port 1048 to dst port 80 */ |
640 | | if (p->l4.vars.icmpv4.emb_sport != 1048 || p->l4.vars.icmpv4.emb_dport != 80) { |
641 | | goto end; |
642 | | } |
643 | | |
644 | | // check the src,dst IPs contained inside |
645 | | uint32_t src_ip = IPV4_GET_RAW_IPSRC_U32(PacketGetICMPv4EmbIPv4(p)); |
646 | | uint32_t dst_ip = IPV4_GET_RAW_IPDST_U32(PacketGetICMPv4EmbIPv4(p)); |
647 | | char s[16], d[16]; |
648 | | PrintInet(AF_INET, &src_ip, s, sizeof(s)); |
649 | | PrintInet(AF_INET, &dst_ip, d, sizeof(d)); |
650 | | |
651 | | // ICMPv4 embedding IPV4 192.168.2.5->61.35.161.35 |
652 | | if (strcmp(s, "192.168.2.5") == 0 && strcmp(d, "61.35.161.35") == 0) { |
653 | | ret = 1; |
654 | | } |
655 | | |
656 | | end: |
657 | | FlowShutdown(); |
658 | | PacketFree(p); |
659 | | return ret; |
660 | | } |
661 | | |
662 | | static int ICMPV4CalculateValidChecksumtest05(void) |
663 | | { |
664 | | uint16_t csum = 0; |
665 | | |
666 | | uint8_t raw_icmpv4[] = { |
667 | | 0x08, 0x00, 0xab, 0x9b, 0x7f, 0x2b, 0x05, 0x2c, |
668 | | 0x3f, 0x72, 0x93, 0x4a, 0x00, 0x4d, 0x0a, 0x00, |
669 | | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
670 | | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
671 | | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, |
672 | | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, |
673 | | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, |
674 | | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}; |
675 | | |
676 | | csum = *( ((uint16_t *)raw_icmpv4) + 1); |
677 | | return (csum == ICMPV4CalculateChecksum((uint16_t *)raw_icmpv4, sizeof(raw_icmpv4))); |
678 | | } |
679 | | |
680 | | static int ICMPV4CalculateInvalidChecksumtest06(void) |
681 | | { |
682 | | uint16_t csum = 0; |
683 | | |
684 | | uint8_t raw_icmpv4[] = { |
685 | | 0x08, 0x00, 0xab, 0x9b, 0x7f, 0x2b, 0x05, 0x2c, |
686 | | 0x3f, 0x72, 0x93, 0x4a, 0x00, 0x4d, 0x0a, 0x00, |
687 | | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
688 | | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
689 | | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, |
690 | | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, |
691 | | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, |
692 | | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38}; |
693 | | |
694 | | csum = *( ((uint16_t *)raw_icmpv4) + 1); |
695 | | return (csum != ICMPV4CalculateChecksum((uint16_t *)raw_icmpv4, sizeof(raw_icmpv4))); |
696 | | } |
697 | | |
698 | | static int ICMPV4InvalidType07(void) |
699 | | { |
700 | | |
701 | | uint8_t raw_icmpv4[] = { |
702 | | 0xff, 0x00, 0xab, 0x9b, 0x7f, 0x2b, 0x05, 0x2c, |
703 | | 0x3f, 0x72, 0x93, 0x4a, 0x00, 0x4d, 0x0a, 0x00, |
704 | | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
705 | | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
706 | | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, |
707 | | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, |
708 | | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, |
709 | | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38}; |
710 | | |
711 | | Packet *p = PacketGetFromAlloc(); |
712 | | if (unlikely(p == NULL)) |
713 | | return 0; |
714 | | ThreadVars tv; |
715 | | DecodeThreadVars dtv; |
716 | | int ret = 0; |
717 | | IPV4Hdr ip4h; |
718 | | |
719 | | memset(&ip4h, 0, sizeof(IPV4Hdr)); |
720 | | memset(&tv, 0, sizeof(ThreadVars)); |
721 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
722 | | |
723 | | FlowInitConfig(FLOW_QUIET); |
724 | | |
725 | | p->src.family = AF_INET; |
726 | | p->dst.family = AF_INET; |
727 | | p->src.addr_data32[0] = UTHSetIPv4Address("4.3.2.1"); |
728 | | p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); |
729 | | |
730 | | ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; |
731 | | ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; |
732 | | UTHSetIPV4Hdr(p, &ip4h); |
733 | | |
734 | | DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4)); |
735 | | |
736 | | if(ENGINE_ISSET_EVENT(p,ICMPV4_UNKNOWN_TYPE)) { |
737 | | ret = 1; |
738 | | } |
739 | | |
740 | | FlowShutdown(); |
741 | | PacketFree(p); |
742 | | return ret; |
743 | | } |
744 | | |
745 | | /** DecodeICMPV4test08 |
746 | | * \brief |
747 | | * \retval 1 Expected test value - what we really want is not to segfault |
748 | | */ |
749 | | static int DecodeICMPV4test08(void) |
750 | | { |
751 | | uint8_t raw_icmpv4[] = { |
752 | | 0x08, 0x00, 0x78, 0x47, 0xfc, 0x55, 0x00, 0x00 |
753 | | }; |
754 | | Packet *p = PacketGetFromAlloc(); |
755 | | FAIL_IF_NULL(p); |
756 | | ThreadVars tv; |
757 | | DecodeThreadVars dtv; |
758 | | IPV4Hdr ip4h; |
759 | | |
760 | | memset(&ip4h, 0, sizeof(IPV4Hdr)); |
761 | | memset(&tv, 0, sizeof(ThreadVars)); |
762 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
763 | | |
764 | | FlowInitConfig(FLOW_QUIET); |
765 | | |
766 | | p->src.family = AF_INET; |
767 | | p->dst.family = AF_INET; |
768 | | p->src.addr_data32[0] = UTHSetIPv4Address("4.3.2.1"); |
769 | | p->dst.addr_data32[0] = UTHSetIPv4Address("1.2.3.4"); |
770 | | |
771 | | ip4h.s_ip_src.s_addr = p->src.addr_data32[0]; |
772 | | ip4h.s_ip_dst.s_addr = p->dst.addr_data32[0]; |
773 | | UTHSetIPV4Hdr(p, &ip4h); |
774 | | |
775 | | DecodeICMPV4(&tv, &dtv, p, raw_icmpv4, sizeof(raw_icmpv4)); |
776 | | FAIL_IF_NOT(PacketIsICMPv4(p)); |
777 | | |
778 | | const ICMPV4Hdr *icmpv4h = PacketGetICMPv4(p); |
779 | | FAIL_IF_NULL(icmpv4h); |
780 | | |
781 | | FAIL_IF_NOT(icmpv4h->type == 8); |
782 | | FAIL_IF_NOT(icmpv4h->code == 0); |
783 | | |
784 | | FlowShutdown(); |
785 | | PacketFree(p); |
786 | | PASS; |
787 | | } |
788 | | #endif /* UNITTESTS */ |
789 | | |
790 | | /** |
791 | | * \brief Registers ICMPV4 unit test |
792 | | */ |
793 | | void DecodeICMPV4RegisterTests(void) |
794 | 0 | { |
795 | | #ifdef UNITTESTS |
796 | | UtRegisterTest("DecodeICMPV4test01", DecodeICMPV4test01); |
797 | | UtRegisterTest("DecodeICMPV4test02", DecodeICMPV4test02); |
798 | | UtRegisterTest("DecodeICMPV4test03", DecodeICMPV4test03); |
799 | | UtRegisterTest("DecodeICMPV4test04", DecodeICMPV4test04); |
800 | | UtRegisterTest("DecodeICMPV4test05", DecodeICMPV4test05); |
801 | | UtRegisterTest("ICMPV4CalculateValidChecksumtest05", |
802 | | ICMPV4CalculateValidChecksumtest05); |
803 | | UtRegisterTest("ICMPV4CalculateInvalidChecksumtest06", |
804 | | ICMPV4CalculateInvalidChecksumtest06); |
805 | | UtRegisterTest("DecodeICMPV4InvalidType", ICMPV4InvalidType07); |
806 | | UtRegisterTest("DecodeICMPV4test08", DecodeICMPV4test08); |
807 | | #endif /* UNITTESTS */ |
808 | 0 | } |
809 | | /** |
810 | | * @} |
811 | | */ |