/src/suricata7/src/decode.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2024 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 | | * \defgroup decode Packet decoding |
20 | | * |
21 | | * \brief Code in charge of protocol decoding |
22 | | * |
23 | | * The task of decoding packets is made in different files and |
24 | | * as Suricata is supporting encapsulation there is a potential |
25 | | * recursivity in the call. |
26 | | * |
27 | | * For each protocol a DecodePROTO function is provided. For |
28 | | * example we have DecodeIPV4() for IPv4 and DecodePPP() for |
29 | | * PPP. |
30 | | * |
31 | | * These functions have all a pkt and a len argument which |
32 | | * are respectively a pointer to the protocol data and the length |
33 | | * of this protocol data. |
34 | | * |
35 | | * \attention The pkt parameter must point to the effective data because |
36 | | * it will be used later to set per protocol pointer like Packet::tcph |
37 | | * |
38 | | * @{ |
39 | | */ |
40 | | |
41 | | |
42 | | /** |
43 | | * \file |
44 | | * |
45 | | * \author Victor Julien <victor@inliniac.net> |
46 | | * |
47 | | * Decode the raw packet |
48 | | */ |
49 | | |
50 | | #include "suricata-common.h" |
51 | | #include "decode.h" |
52 | | |
53 | | #include "packet.h" |
54 | | #include "flow.h" |
55 | | #include "flow-storage.h" |
56 | | #include "tmqh-packetpool.h" |
57 | | #include "app-layer.h" |
58 | | #include "output.h" |
59 | | |
60 | | #include "decode-vxlan.h" |
61 | | #include "decode-geneve.h" |
62 | | #include "decode-erspan.h" |
63 | | #include "decode-teredo.h" |
64 | | |
65 | | #include "defrag-hash.h" |
66 | | |
67 | | #include "util-hash.h" |
68 | | #include "util-hash-string.h" |
69 | | #include "util-print.h" |
70 | | #include "util-profiling.h" |
71 | | #include "util-validate.h" |
72 | | #include "util-debug.h" |
73 | | #include "util-exception-policy.h" |
74 | | #include "action-globals.h" |
75 | | |
76 | | uint32_t default_packet_size = 0; |
77 | | extern bool stats_decoder_events; |
78 | | extern const char *stats_decoder_events_prefix; |
79 | | extern bool stats_stream_events; |
80 | | uint8_t decoder_max_layers = PKT_DEFAULT_MAX_DECODED_LAYERS; |
81 | | uint16_t packet_alert_max = PACKET_ALERT_MAX; |
82 | | |
83 | | /* Settings order as in the enum */ |
84 | | // clang-format off |
85 | | ExceptionPolicyStatsSetts defrag_memcap_eps_stats = { |
86 | | .valid_settings_ids = { |
87 | | /* EXCEPTION_POLICY_NOT_SET */ false, |
88 | | /* EXCEPTION_POLICY_AUTO */ false, |
89 | | /* EXCEPTION_POLICY_PASS_PACKET */ true, |
90 | | /* EXCEPTION_POLICY_PASS_FLOW */ false, |
91 | | /* EXCEPTION_POLICY_BYPASS_FLOW */ true, |
92 | | /* EXCEPTION_POLICY_DROP_PACKET */ false, |
93 | | /* EXCEPTION_POLICY_DROP_FLOW */ false, |
94 | | /* EXCEPTION_POLICY_REJECT */ true, |
95 | | /* EXCEPTION_POLICY_REJECT_BOTH */ true, |
96 | | }, |
97 | | .valid_settings_ips = { |
98 | | /* EXCEPTION_POLICY_NOT_SET */ false, |
99 | | /* EXCEPTION_POLICY_AUTO */ false, |
100 | | /* EXCEPTION_POLICY_PASS_PACKET */ true, |
101 | | /* EXCEPTION_POLICY_PASS_FLOW */ false, |
102 | | /* EXCEPTION_POLICY_BYPASS_FLOW */ true, |
103 | | /* EXCEPTION_POLICY_DROP_PACKET */ true, |
104 | | /* EXCEPTION_POLICY_DROP_FLOW */ false, |
105 | | /* EXCEPTION_POLICY_REJECT */ true, |
106 | | /* EXCEPTION_POLICY_REJECT_BOTH */ true, |
107 | | }, |
108 | | }; |
109 | | // clang-format on |
110 | | |
111 | | /* Settings order as in the enum */ |
112 | | // clang-format off |
113 | | ExceptionPolicyStatsSetts flow_memcap_eps_stats = { |
114 | | .valid_settings_ids = { |
115 | | /* EXCEPTION_POLICY_NOT_SET */ false, |
116 | | /* EXCEPTION_POLICY_AUTO */ false, |
117 | | /* EXCEPTION_POLICY_PASS_PACKET */ true, |
118 | | /* EXCEPTION_POLICY_PASS_FLOW */ false, |
119 | | /* EXCEPTION_POLICY_BYPASS_FLOW */ true, |
120 | | /* EXCEPTION_POLICY_DROP_PACKET */ false, |
121 | | /* EXCEPTION_POLICY_DROP_FLOW */ false, |
122 | | /* EXCEPTION_POLICY_REJECT */ true, |
123 | | /* EXCEPTION_POLICY_REJECT_BOTH */ true, |
124 | | }, |
125 | | .valid_settings_ips = { |
126 | | /* EXCEPTION_POLICY_NOT_SET */ false, |
127 | | /* EXCEPTION_POLICY_AUTO */ false, |
128 | | /* EXCEPTION_POLICY_PASS_PACKET */ true, |
129 | | /* EXCEPTION_POLICY_PASS_FLOW */ false, |
130 | | /* EXCEPTION_POLICY_BYPASS_FLOW */ true, |
131 | | /* EXCEPTION_POLICY_DROP_PACKET */ true, |
132 | | /* EXCEPTION_POLICY_DROP_FLOW */ false, |
133 | | /* EXCEPTION_POLICY_REJECT */ true, |
134 | | /* EXCEPTION_POLICY_REJECT_BOTH */ true, |
135 | | }, |
136 | | }; |
137 | | // clang-format on |
138 | | |
139 | | /** |
140 | | * \brief Initialize PacketAlerts with dynamic alerts array size |
141 | | * |
142 | | */ |
143 | | PacketAlert *PacketAlertCreate(void) |
144 | 105k | { |
145 | 105k | PacketAlert *pa_array = SCCalloc(packet_alert_max, sizeof(PacketAlert)); |
146 | 105k | BUG_ON(pa_array == NULL); |
147 | | |
148 | 105k | return pa_array; |
149 | 105k | } |
150 | | |
151 | | void PacketAlertFree(PacketAlert *pa) |
152 | 49.0k | { |
153 | 49.0k | if (pa != NULL) { |
154 | 49.0k | SCFree(pa); |
155 | 49.0k | } |
156 | 49.0k | } |
157 | | |
158 | | static int DecodeTunnel(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t, |
159 | | enum DecodeTunnelProto) WARN_UNUSED; |
160 | | |
161 | | static int DecodeTunnel(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, |
162 | | uint32_t len, enum DecodeTunnelProto proto) |
163 | 22.1k | { |
164 | 22.1k | switch (proto) { |
165 | 5.72k | case DECODE_TUNNEL_PPP: |
166 | 5.72k | return DecodePPP(tv, dtv, p, pkt, len); |
167 | 7.39k | case DECODE_TUNNEL_IPV4: |
168 | 7.39k | DEBUG_VALIDATE_BUG_ON(len > UINT16_MAX); |
169 | 7.39k | return DecodeIPV4(tv, dtv, p, pkt, (uint16_t)len); |
170 | 2.70k | case DECODE_TUNNEL_IPV6: |
171 | 4.22k | case DECODE_TUNNEL_IPV6_TEREDO: |
172 | 4.22k | DEBUG_VALIDATE_BUG_ON(len > UINT16_MAX); |
173 | 4.22k | return DecodeIPV6(tv, dtv, p, pkt, (uint16_t)len); |
174 | 1.65k | case DECODE_TUNNEL_VLAN: |
175 | 1.65k | return DecodeVLAN(tv, dtv, p, pkt, len); |
176 | 865 | case DECODE_TUNNEL_ETHERNET: |
177 | 865 | return DecodeEthernet(tv, dtv, p, pkt, len); |
178 | 2.04k | case DECODE_TUNNEL_ERSPANII: |
179 | 2.04k | return DecodeERSPAN(tv, dtv, p, pkt, len); |
180 | 210 | case DECODE_TUNNEL_ERSPANI: |
181 | 210 | return DecodeERSPANTypeI(tv, dtv, p, pkt, len); |
182 | 0 | case DECODE_TUNNEL_NSH: |
183 | 0 | return DecodeNSH(tv, dtv, p, pkt, len); |
184 | 0 | default: |
185 | 0 | SCLogDebug("FIXME: DecodeTunnel: protocol %" PRIu32 " not supported.", proto); |
186 | 0 | break; |
187 | 22.1k | } |
188 | 0 | return TM_ECODE_OK; |
189 | 22.1k | } |
190 | | |
191 | | /** |
192 | | * \brief Return a malloced packet. |
193 | | */ |
194 | | void PacketFree(Packet *p) |
195 | 104k | { |
196 | 104k | PacketDestructor(p); |
197 | 104k | SCFree(p); |
198 | 104k | } |
199 | | |
200 | | /** |
201 | | * \brief Finalize decoding of a packet |
202 | | * |
203 | | * This function needs to be call at the end of decode |
204 | | * functions when decoding has been successful. |
205 | | * |
206 | | */ |
207 | | void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) |
208 | 21.2M | { |
209 | 21.2M | if (p->flags & PKT_IS_INVALID) { |
210 | 3.48M | StatsIncr(tv, dtv->counter_invalid); |
211 | 3.48M | } |
212 | 21.2M | } |
213 | | |
214 | | void PacketUpdateEngineEventCounters(ThreadVars *tv, |
215 | | DecodeThreadVars *dtv, Packet *p) |
216 | 20.2M | { |
217 | 29.9M | for (uint8_t i = 0; i < p->events.cnt; i++) { |
218 | 9.75M | const uint8_t e = p->events.events[i]; |
219 | | |
220 | 9.75M | if (e <= DECODE_EVENT_PACKET_MAX && !stats_decoder_events) |
221 | 0 | continue; |
222 | 9.75M | else if (e > DECODE_EVENT_PACKET_MAX && !stats_stream_events) |
223 | 4.02M | continue; |
224 | 5.73M | StatsIncr(tv, dtv->counter_engine_events[e]); |
225 | 5.73M | } |
226 | 20.2M | } |
227 | | |
228 | | /** |
229 | | * \brief Get a malloced packet. |
230 | | * |
231 | | * \retval p packet, NULL on error |
232 | | */ |
233 | | Packet *PacketGetFromAlloc(void) |
234 | 105k | { |
235 | 105k | Packet *p = SCCalloc(1, SIZE_OF_PACKET); |
236 | 105k | if (unlikely(p == NULL)) { |
237 | 0 | return NULL; |
238 | 0 | } |
239 | 105k | PacketInit(p); |
240 | 105k | p->ReleasePacket = PacketFree; |
241 | | |
242 | 105k | SCLogDebug("allocated a new packet only using alloc..."); |
243 | | |
244 | 105k | PACKET_PROFILING_START(p); |
245 | 105k | return p; |
246 | 105k | } |
247 | | |
248 | | /** |
249 | | * \brief Return a packet to where it was allocated. |
250 | | */ |
251 | | void PacketFreeOrRelease(Packet *p) |
252 | 26.2k | { |
253 | 26.2k | if (likely(p->pool != NULL)) { |
254 | 26.2k | p->ReleasePacket = PacketPoolReturnPacket; |
255 | 26.2k | PacketPoolReturnPacket(p); |
256 | 26.2k | } else { |
257 | 0 | PacketFree(p); |
258 | 0 | } |
259 | 26.2k | } |
260 | | |
261 | | /** |
262 | | * \brief Get a packet. We try to get a packet from the packetpool first, but |
263 | | * if that is empty we alloc a packet that is free'd again after |
264 | | * processing. |
265 | | * |
266 | | * \retval p packet, NULL on error |
267 | | */ |
268 | | Packet *PacketGetFromQueueOrAlloc(void) |
269 | 1.35M | { |
270 | | /* try the pool first */ |
271 | 1.35M | Packet *p = PacketPoolGetPacket(); |
272 | | |
273 | 1.35M | if (p == NULL) { |
274 | | /* non fatal, we're just not processing a packet then */ |
275 | 0 | p = PacketGetFromAlloc(); |
276 | 1.35M | } else { |
277 | 1.35M | DEBUG_VALIDATE_BUG_ON(p->ReleasePacket != PacketPoolReturnPacket); |
278 | 1.35M | PACKET_PROFILING_START(p); |
279 | 1.35M | } |
280 | | |
281 | 1.35M | return p; |
282 | 1.35M | } |
283 | | |
284 | | inline int PacketCallocExtPkt(Packet *p, int datalen) |
285 | 0 | { |
286 | 0 | if (! p->ext_pkt) { |
287 | 0 | p->ext_pkt = SCCalloc(1, datalen); |
288 | 0 | if (unlikely(p->ext_pkt == NULL)) { |
289 | 0 | SET_PKT_LEN(p, 0); |
290 | 0 | return -1; |
291 | 0 | } |
292 | 0 | } |
293 | 0 | return 0; |
294 | 0 | } |
295 | | |
296 | | /** |
297 | | * \brief Copy data to Packet payload at given offset |
298 | | * |
299 | | * This function copies data/payload to a Packet. It uses the |
300 | | * space allocated at Packet creation (pointed by Packet::pkt) |
301 | | * or allocate some memory (pointed by Packet::ext_pkt) if the |
302 | | * data size is to big to fit in initial space (of size |
303 | | * default_packet_size). |
304 | | * |
305 | | * \param Pointer to the Packet to modify |
306 | | * \param Offset of the copy relatively to payload of Packet |
307 | | * \param Pointer to the data to copy |
308 | | * \param Length of the data to copy |
309 | | */ |
310 | | inline int PacketCopyDataOffset(Packet *p, uint32_t offset, const uint8_t *data, uint32_t datalen) |
311 | 21.3M | { |
312 | 21.3M | if (unlikely(offset + datalen > MAX_PAYLOAD_SIZE)) { |
313 | | /* too big */ |
314 | 388 | SET_PKT_LEN(p, 0); |
315 | 388 | return -1; |
316 | 388 | } |
317 | | |
318 | | /* Do we have already an packet with allocated data */ |
319 | 21.3M | if (! p->ext_pkt) { |
320 | 21.3M | uint32_t newsize = offset + datalen; |
321 | | // check overflow |
322 | 21.3M | if (newsize < offset) |
323 | 0 | return -1; |
324 | 21.3M | if (newsize <= default_packet_size) { |
325 | | /* data will fit in memory allocated with packet */ |
326 | 21.1M | memcpy(GET_PKT_DIRECT_DATA(p) + offset, data, datalen); |
327 | 21.1M | } else { |
328 | | /* here we need a dynamic allocation */ |
329 | 130k | p->ext_pkt = SCMalloc(MAX_PAYLOAD_SIZE); |
330 | 130k | if (unlikely(p->ext_pkt == NULL)) { |
331 | 0 | SET_PKT_LEN(p, 0); |
332 | 0 | return -1; |
333 | 0 | } |
334 | | /* copy initial data */ |
335 | 130k | memcpy(p->ext_pkt, GET_PKT_DIRECT_DATA(p), GET_PKT_DIRECT_MAX_SIZE(p)); |
336 | | /* copy data as asked */ |
337 | 130k | memcpy(p->ext_pkt + offset, data, datalen); |
338 | 130k | } |
339 | 21.3M | } else { |
340 | 5.89k | memcpy(p->ext_pkt + offset, data, datalen); |
341 | 5.89k | } |
342 | 21.3M | return 0; |
343 | 21.3M | } |
344 | | |
345 | | /** |
346 | | * \brief Copy data to Packet payload and set packet length |
347 | | * |
348 | | * \param Pointer to the Packet to modify |
349 | | * \param Pointer to the data to copy |
350 | | * \param Length of the data to copy |
351 | | */ |
352 | | inline int PacketCopyData(Packet *p, const uint8_t *pktdata, uint32_t pktlen) |
353 | 21.2M | { |
354 | 21.2M | SET_PKT_LEN(p, (size_t)pktlen); |
355 | 21.2M | return PacketCopyDataOffset(p, 0, pktdata, pktlen); |
356 | 21.2M | } |
357 | | |
358 | | /** |
359 | | * \brief Setup a pseudo packet (tunnel) |
360 | | * |
361 | | * \param parent parent packet for this pseudo pkt |
362 | | * \param pkt raw packet data |
363 | | * \param len packet data length |
364 | | * \param proto protocol of the tunneled packet |
365 | | * |
366 | | * \retval p the pseudo packet or NULL if out of memory |
367 | | */ |
368 | | Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *parent, |
369 | | const uint8_t *pkt, uint32_t len, enum DecodeTunnelProto proto) |
370 | 22.1k | { |
371 | 22.1k | int ret; |
372 | | |
373 | 22.1k | SCEnter(); |
374 | | |
375 | 22.1k | if (parent->nb_decoded_layers + 1 >= decoder_max_layers) { |
376 | 28 | ENGINE_SET_INVALID_EVENT(parent, GENERIC_TOO_MANY_LAYERS); |
377 | 28 | SCReturnPtr(NULL, "Packet"); |
378 | 28 | } |
379 | | |
380 | | /* get us a packet */ |
381 | 22.1k | Packet *p = PacketGetFromQueueOrAlloc(); |
382 | 22.1k | if (unlikely(p == NULL)) { |
383 | 0 | SCReturnPtr(NULL, "Packet"); |
384 | 0 | } |
385 | | |
386 | | /* copy packet and set length, proto */ |
387 | 22.1k | PacketCopyData(p, pkt, len); |
388 | 22.1k | DEBUG_VALIDATE_BUG_ON(parent->recursion_level == 255); |
389 | 22.1k | p->recursion_level = parent->recursion_level + 1; |
390 | 22.1k | DEBUG_VALIDATE_BUG_ON(parent->nb_decoded_layers >= decoder_max_layers); |
391 | 22.1k | p->nb_decoded_layers = parent->nb_decoded_layers + 1; |
392 | 22.1k | p->ts = parent->ts; |
393 | 22.1k | p->datalink = DLT_RAW; |
394 | 22.1k | p->tenant_id = parent->tenant_id; |
395 | 22.1k | p->livedev = parent->livedev; |
396 | | |
397 | | /* set the root ptr to the lowest layer */ |
398 | 22.1k | if (parent->root != NULL) |
399 | 2.42k | p->root = parent->root; |
400 | 19.6k | else |
401 | 19.6k | p->root = parent; |
402 | | |
403 | | /* tell new packet it's part of a tunnel */ |
404 | 22.1k | SET_TUNNEL_PKT(p); |
405 | | |
406 | 22.1k | ret = DecodeTunnel(tv, dtv, p, GET_PKT_DATA(p), |
407 | 22.1k | GET_PKT_LEN(p), proto); |
408 | | |
409 | 22.1k | if (unlikely(ret != TM_ECODE_OK) || |
410 | 14.4k | (proto == DECODE_TUNNEL_IPV6_TEREDO && (p->flags & PKT_IS_INVALID))) |
411 | 7.99k | { |
412 | | /* Not a (valid) tunnel packet */ |
413 | 7.99k | SCLogDebug("tunnel packet is invalid"); |
414 | | |
415 | 7.99k | p->root = NULL; |
416 | 7.99k | UNSET_TUNNEL_PKT(p); |
417 | 7.99k | TmqhOutputPacketpool(tv, p); |
418 | 7.99k | SCReturnPtr(NULL, "Packet"); |
419 | 7.99k | } |
420 | | |
421 | | |
422 | | /* tell parent packet it's part of a tunnel */ |
423 | 14.1k | SET_TUNNEL_PKT(parent); |
424 | | |
425 | | /* increment tunnel packet refcnt in the root packet */ |
426 | 14.1k | TUNNEL_INCR_PKT_TPR(p); |
427 | | |
428 | | /* disable payload (not packet) inspection on the parent, as the payload |
429 | | * is the packet we will now run through the system separately. We do |
430 | | * check it against the ip/port/other header checks though */ |
431 | 14.1k | DecodeSetNoPayloadInspectionFlag(parent); |
432 | 14.1k | SCReturnPtr(p, "Packet"); |
433 | 22.1k | } |
434 | | |
435 | | /** |
436 | | * \brief Setup a pseudo packet (reassembled frags) |
437 | | * |
438 | | * Difference with PacketPseudoPktSetup is that this func doesn't increment |
439 | | * the recursion level. It needs to be on the same level as the frags because |
440 | | * we run the flow engine against this and we need to get the same flow. |
441 | | * |
442 | | * \param parent parent packet for this pseudo pkt |
443 | | * \param pkt raw packet data |
444 | | * \param len packet data length |
445 | | * \param proto protocol of the tunneled packet |
446 | | * |
447 | | * \retval p the pseudo packet or NULL if out of memory |
448 | | */ |
449 | | Packet *PacketDefragPktSetup(Packet *parent, const uint8_t *pkt, uint32_t len, uint8_t proto) |
450 | 2.21k | { |
451 | 2.21k | SCEnter(); |
452 | | |
453 | | /* get us a packet */ |
454 | 2.21k | Packet *p = PacketGetFromQueueOrAlloc(); |
455 | 2.21k | if (unlikely(p == NULL)) { |
456 | 0 | SCReturnPtr(NULL, "Packet"); |
457 | 0 | } |
458 | | |
459 | | /* set the root ptr to the lowest layer */ |
460 | 2.21k | if (parent->root != NULL) |
461 | 8 | p->root = parent->root; |
462 | 2.20k | else |
463 | 2.20k | p->root = parent; |
464 | | |
465 | | /* copy packet and set length, proto */ |
466 | 2.21k | if (pkt && len) { |
467 | 1.47k | PacketCopyData(p, pkt, len); |
468 | 1.47k | } |
469 | 2.21k | p->recursion_level = parent->recursion_level; /* NOT incremented */ |
470 | 2.21k | p->ts = parent->ts; |
471 | 2.21k | p->tenant_id = parent->tenant_id; |
472 | | /* tell new packet it's part of a tunnel */ |
473 | 2.21k | SET_TUNNEL_PKT(p); |
474 | 2.21k | memcpy(&p->vlan_id[0], &parent->vlan_id[0], sizeof(p->vlan_id)); |
475 | 2.21k | p->vlan_idx = parent->vlan_idx; |
476 | 2.21k | p->livedev = parent->livedev; |
477 | | |
478 | 2.21k | SCReturnPtr(p, "Packet"); |
479 | 2.21k | } |
480 | | |
481 | | /** |
482 | | * \brief inform defrag "parent" that a pseudo packet is |
483 | | * now associated to it. |
484 | | */ |
485 | | void PacketDefragPktSetupParent(Packet *parent) |
486 | 2.21k | { |
487 | | /* tell parent packet it's part of a tunnel */ |
488 | 2.21k | SET_TUNNEL_PKT(parent); |
489 | | |
490 | | /* increment tunnel packet refcnt in the root packet */ |
491 | 2.21k | TUNNEL_INCR_PKT_TPR(parent); |
492 | | |
493 | | /* disable payload (not packet) inspection on the parent, as the payload |
494 | | * is the packet we will now run through the system separately. We do |
495 | | * check it against the ip/port/other header checks though */ |
496 | 2.21k | DecodeSetNoPayloadInspectionFlag(parent); |
497 | 2.21k | } |
498 | | |
499 | | /** |
500 | | * \note if p->flow is set, the flow is locked |
501 | | */ |
502 | | void PacketBypassCallback(Packet *p) |
503 | 18 | { |
504 | 18 | if (PKT_IS_PSEUDOPKT(p)) |
505 | 0 | return; |
506 | | |
507 | | #ifdef CAPTURE_OFFLOAD |
508 | | /* Don't try to bypass if flow is already out or |
509 | | * if we have failed to do it once */ |
510 | | if (p->flow) { |
511 | | int state = p->flow->flow_state; |
512 | | if ((state == FLOW_STATE_LOCAL_BYPASSED) || |
513 | | (state == FLOW_STATE_CAPTURE_BYPASSED)) { |
514 | | return; |
515 | | } |
516 | | |
517 | | FlowBypassInfo *fc; |
518 | | |
519 | | fc = FlowGetStorageById(p->flow, GetFlowBypassInfoID()); |
520 | | if (fc == NULL) { |
521 | | fc = SCCalloc(sizeof(FlowBypassInfo), 1); |
522 | | if (fc) { |
523 | | FlowSetStorageById(p->flow, GetFlowBypassInfoID(), fc); |
524 | | } else { |
525 | | return; |
526 | | } |
527 | | } |
528 | | } |
529 | | if (p->BypassPacketsFlow && p->BypassPacketsFlow(p)) { |
530 | | if (p->flow) { |
531 | | FlowUpdateState(p->flow, FLOW_STATE_CAPTURE_BYPASSED); |
532 | | } |
533 | | } else { |
534 | | if (p->flow) { |
535 | | FlowUpdateState(p->flow, FLOW_STATE_LOCAL_BYPASSED); |
536 | | } |
537 | | } |
538 | | #else /* CAPTURE_OFFLOAD */ |
539 | 18 | if (p->flow) { |
540 | 18 | int state = p->flow->flow_state; |
541 | 18 | if (state == FLOW_STATE_LOCAL_BYPASSED) |
542 | 0 | return; |
543 | 18 | FlowUpdateState(p->flow, FLOW_STATE_LOCAL_BYPASSED); |
544 | 18 | } |
545 | 18 | #endif |
546 | 18 | } |
547 | | |
548 | | /** \brief switch direction of a packet */ |
549 | | void PacketSwap(Packet *p) |
550 | 130k | { |
551 | 130k | if (PKT_IS_TOSERVER(p)) { |
552 | 107k | p->flowflags &= ~FLOW_PKT_TOSERVER; |
553 | 107k | p->flowflags |= FLOW_PKT_TOCLIENT; |
554 | | |
555 | 107k | if (p->flowflags & FLOW_PKT_TOSERVER_FIRST) { |
556 | 95.3k | p->flowflags &= ~FLOW_PKT_TOSERVER_FIRST; |
557 | 95.3k | p->flowflags |= FLOW_PKT_TOCLIENT_FIRST; |
558 | 95.3k | } |
559 | 107k | } else { |
560 | 22.6k | p->flowflags &= ~FLOW_PKT_TOCLIENT; |
561 | 22.6k | p->flowflags |= FLOW_PKT_TOSERVER; |
562 | | |
563 | 22.6k | if (p->flowflags & FLOW_PKT_TOCLIENT_FIRST) { |
564 | 18.0k | p->flowflags &= ~FLOW_PKT_TOCLIENT_FIRST; |
565 | 18.0k | p->flowflags |= FLOW_PKT_TOSERVER_FIRST; |
566 | 18.0k | } |
567 | 22.6k | } |
568 | 130k | } |
569 | | |
570 | | /* counter name store */ |
571 | | static HashTable *g_counter_table = NULL; |
572 | | static SCMutex g_counter_table_mutex = SCMUTEX_INITIALIZER; |
573 | | |
574 | | void DecodeUnregisterCounters(void) |
575 | 0 | { |
576 | 0 | SCMutexLock(&g_counter_table_mutex); |
577 | 0 | if (g_counter_table) { |
578 | 0 | HashTableFree(g_counter_table); |
579 | 0 | g_counter_table = NULL; |
580 | 0 | } |
581 | 0 | SCMutexUnlock(&g_counter_table_mutex); |
582 | 0 | } |
583 | | |
584 | | static bool IsDefragMemcapExceptionPolicyStatsValid(enum ExceptionPolicy policy) |
585 | 0 | { |
586 | 0 | if (EngineModeIsIPS()) { |
587 | 0 | return defrag_memcap_eps_stats.valid_settings_ips[policy]; |
588 | 0 | } |
589 | 0 | return defrag_memcap_eps_stats.valid_settings_ids[policy]; |
590 | 0 | } |
591 | | |
592 | | static bool IsFlowMemcapExceptionPolicyStatsValid(enum ExceptionPolicy policy) |
593 | 0 | { |
594 | 0 | if (EngineModeIsIPS()) { |
595 | 0 | return flow_memcap_eps_stats.valid_settings_ips[policy]; |
596 | 0 | } |
597 | 0 | return flow_memcap_eps_stats.valid_settings_ids[policy]; |
598 | 0 | } |
599 | | |
600 | | void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) |
601 | 5 | { |
602 | | /* register counters */ |
603 | 5 | dtv->counter_pkts = StatsRegisterCounter("decoder.pkts", tv); |
604 | 5 | dtv->counter_bytes = StatsRegisterCounter("decoder.bytes", tv); |
605 | 5 | dtv->counter_invalid = StatsRegisterCounter("decoder.invalid", tv); |
606 | 5 | dtv->counter_ipv4 = StatsRegisterCounter("decoder.ipv4", tv); |
607 | 5 | dtv->counter_ipv6 = StatsRegisterCounter("decoder.ipv6", tv); |
608 | 5 | dtv->counter_eth = StatsRegisterCounter("decoder.ethernet", tv); |
609 | 5 | dtv->counter_arp = StatsRegisterCounter("decoder.arp", tv); |
610 | 5 | dtv->counter_ethertype_unknown = StatsRegisterCounter("decoder.unknown_ethertype", tv); |
611 | 5 | dtv->counter_chdlc = StatsRegisterCounter("decoder.chdlc", tv); |
612 | 5 | dtv->counter_raw = StatsRegisterCounter("decoder.raw", tv); |
613 | 5 | dtv->counter_null = StatsRegisterCounter("decoder.null", tv); |
614 | 5 | dtv->counter_sll = StatsRegisterCounter("decoder.sll", tv); |
615 | 5 | dtv->counter_tcp = StatsRegisterCounter("decoder.tcp", tv); |
616 | | |
617 | 5 | dtv->counter_tcp_syn = StatsRegisterCounter("tcp.syn", tv); |
618 | 5 | dtv->counter_tcp_synack = StatsRegisterCounter("tcp.synack", tv); |
619 | 5 | dtv->counter_tcp_rst = StatsRegisterCounter("tcp.rst", tv); |
620 | 5 | dtv->counter_tcp_urg = StatsRegisterCounter("tcp.urg", tv); |
621 | | |
622 | 5 | dtv->counter_udp = StatsRegisterCounter("decoder.udp", tv); |
623 | 5 | dtv->counter_sctp = StatsRegisterCounter("decoder.sctp", tv); |
624 | 5 | dtv->counter_esp = StatsRegisterCounter("decoder.esp", tv); |
625 | 5 | dtv->counter_icmpv4 = StatsRegisterCounter("decoder.icmpv4", tv); |
626 | 5 | dtv->counter_icmpv6 = StatsRegisterCounter("decoder.icmpv6", tv); |
627 | 5 | dtv->counter_ppp = StatsRegisterCounter("decoder.ppp", tv); |
628 | 5 | dtv->counter_pppoe = StatsRegisterCounter("decoder.pppoe", tv); |
629 | 5 | dtv->counter_geneve = StatsRegisterCounter("decoder.geneve", tv); |
630 | 5 | dtv->counter_gre = StatsRegisterCounter("decoder.gre", tv); |
631 | 5 | dtv->counter_vlan = StatsRegisterCounter("decoder.vlan", tv); |
632 | 5 | dtv->counter_vlan_qinq = StatsRegisterCounter("decoder.vlan_qinq", tv); |
633 | 5 | dtv->counter_vlan_qinqinq = StatsRegisterCounter("decoder.vlan_qinqinq", tv); |
634 | 5 | dtv->counter_vxlan = StatsRegisterCounter("decoder.vxlan", tv); |
635 | 5 | dtv->counter_vntag = StatsRegisterCounter("decoder.vntag", tv); |
636 | 5 | dtv->counter_ieee8021ah = StatsRegisterCounter("decoder.ieee8021ah", tv); |
637 | 5 | dtv->counter_teredo = StatsRegisterCounter("decoder.teredo", tv); |
638 | 5 | dtv->counter_ipv4inipv4 = StatsRegisterCounter("decoder.ipv4_in_ipv4", tv); |
639 | 5 | dtv->counter_ipv6inipv4 = StatsRegisterCounter("decoder.ipv6_in_ipv4", tv); |
640 | 5 | dtv->counter_ipv4inipv6 = StatsRegisterCounter("decoder.ipv4_in_ipv6", tv); |
641 | 5 | dtv->counter_ipv6inipv6 = StatsRegisterCounter("decoder.ipv6_in_ipv6", tv); |
642 | 5 | dtv->counter_mpls = StatsRegisterCounter("decoder.mpls", tv); |
643 | 5 | dtv->counter_avg_pkt_size = StatsRegisterAvgCounter("decoder.avg_pkt_size", tv); |
644 | 5 | dtv->counter_max_pkt_size = StatsRegisterMaxCounter("decoder.max_pkt_size", tv); |
645 | 5 | dtv->counter_max_mac_addrs_src = StatsRegisterMaxCounter("decoder.max_mac_addrs_src", tv); |
646 | 5 | dtv->counter_max_mac_addrs_dst = StatsRegisterMaxCounter("decoder.max_mac_addrs_dst", tv); |
647 | 5 | dtv->counter_erspan = StatsRegisterMaxCounter("decoder.erspan", tv); |
648 | 5 | dtv->counter_nsh = StatsRegisterMaxCounter("decoder.nsh", tv); |
649 | 5 | dtv->counter_flow_memcap = StatsRegisterCounter("flow.memcap", tv); |
650 | 5 | ExceptionPolicySetStatsCounters(tv, &dtv->counter_flow_memcap_eps, &flow_memcap_eps_stats, |
651 | 5 | FlowGetMemcapExceptionPolicy(), "exception_policy.flow.memcap.", |
652 | 5 | IsFlowMemcapExceptionPolicyStatsValid); |
653 | | |
654 | 5 | dtv->counter_tcp_active_sessions = StatsRegisterCounter("tcp.active_sessions", tv); |
655 | 5 | dtv->counter_flow_total = StatsRegisterCounter("flow.total", tv); |
656 | 5 | dtv->counter_flow_active = StatsRegisterCounter("flow.active", tv); |
657 | 5 | dtv->counter_flow_tcp = StatsRegisterCounter("flow.tcp", tv); |
658 | 5 | dtv->counter_flow_udp = StatsRegisterCounter("flow.udp", tv); |
659 | 5 | dtv->counter_flow_icmp4 = StatsRegisterCounter("flow.icmpv4", tv); |
660 | 5 | dtv->counter_flow_icmp6 = StatsRegisterCounter("flow.icmpv6", tv); |
661 | 5 | dtv->counter_flow_tcp_reuse = StatsRegisterCounter("flow.tcp_reuse", tv); |
662 | 5 | dtv->counter_flow_get_used = StatsRegisterCounter("flow.get_used", tv); |
663 | 5 | dtv->counter_flow_get_used_eval = StatsRegisterCounter("flow.get_used_eval", tv); |
664 | 5 | dtv->counter_flow_get_used_eval_reject = StatsRegisterCounter("flow.get_used_eval_reject", tv); |
665 | 5 | dtv->counter_flow_get_used_eval_busy = StatsRegisterCounter("flow.get_used_eval_busy", tv); |
666 | 5 | dtv->counter_flow_get_used_failed = StatsRegisterCounter("flow.get_used_failed", tv); |
667 | | |
668 | 5 | dtv->counter_flow_spare_sync_avg = StatsRegisterAvgCounter("flow.wrk.spare_sync_avg", tv); |
669 | 5 | dtv->counter_flow_spare_sync = StatsRegisterCounter("flow.wrk.spare_sync", tv); |
670 | 5 | dtv->counter_flow_spare_sync_incomplete = StatsRegisterCounter("flow.wrk.spare_sync_incomplete", tv); |
671 | 5 | dtv->counter_flow_spare_sync_empty = StatsRegisterCounter("flow.wrk.spare_sync_empty", tv); |
672 | | |
673 | 5 | dtv->counter_defrag_ipv4_fragments = |
674 | 5 | StatsRegisterCounter("defrag.ipv4.fragments", tv); |
675 | 5 | dtv->counter_defrag_ipv4_reassembled = StatsRegisterCounter("defrag.ipv4.reassembled", tv); |
676 | 5 | dtv->counter_defrag_ipv6_fragments = |
677 | 5 | StatsRegisterCounter("defrag.ipv6.fragments", tv); |
678 | 5 | dtv->counter_defrag_ipv6_reassembled = StatsRegisterCounter("defrag.ipv6.reassembled", tv); |
679 | 5 | dtv->counter_defrag_max_hit = |
680 | 5 | StatsRegisterCounter("defrag.max_frag_hits", tv); |
681 | | |
682 | 5 | ExceptionPolicySetStatsCounters(tv, &dtv->counter_defrag_memcap_eps, &defrag_memcap_eps_stats, |
683 | 5 | DefragGetMemcapExceptionPolicy(), "exception_policy.defrag.memcap.", |
684 | 5 | IsDefragMemcapExceptionPolicyStatsValid); |
685 | | |
686 | 995 | for (int i = 0; i < DECODE_EVENT_MAX; i++) { |
687 | 990 | BUG_ON(i != (int)DEvents[i].code); |
688 | | |
689 | 990 | if (i <= DECODE_EVENT_PACKET_MAX && !stats_decoder_events) |
690 | 0 | continue; |
691 | 990 | else if (i > DECODE_EVENT_PACKET_MAX && !stats_stream_events) |
692 | 355 | continue; |
693 | | |
694 | 635 | if (i < DECODE_EVENT_PACKET_MAX && |
695 | 630 | strncmp(DEvents[i].event_name, "decoder.", 8) == 0) |
696 | 630 | { |
697 | 630 | SCMutexLock(&g_counter_table_mutex); |
698 | 630 | if (g_counter_table == NULL) { |
699 | 3 | g_counter_table = HashTableInit(256, StringHashFunc, |
700 | 3 | StringHashCompareFunc, |
701 | 3 | StringHashFreeFunc); |
702 | 3 | if (g_counter_table == NULL) { |
703 | 0 | FatalError("decoder counter hash " |
704 | 0 | "table init failed"); |
705 | 0 | } |
706 | 3 | } |
707 | | |
708 | 630 | char name[256]; |
709 | 630 | char *dot = strchr(DEvents[i].event_name, '.'); |
710 | 630 | BUG_ON(!dot); |
711 | 630 | snprintf(name, sizeof(name), "%s.%s", |
712 | 630 | stats_decoder_events_prefix, dot+1); |
713 | | |
714 | 630 | const char *found = HashTableLookup(g_counter_table, name, 0); |
715 | 630 | if (!found) { |
716 | 378 | char *add = SCStrdup(name); |
717 | 378 | if (add == NULL) |
718 | 0 | FatalError("decoder counter hash " |
719 | 378 | "table name init failed"); |
720 | 378 | int r = HashTableAdd(g_counter_table, add, 0); |
721 | 378 | if (r != 0) |
722 | 0 | FatalError("decoder counter hash " |
723 | 378 | "table name add failed"); |
724 | 378 | found = add; |
725 | 378 | } |
726 | 630 | dtv->counter_engine_events[i] = StatsRegisterCounter( |
727 | 630 | found, tv); |
728 | | |
729 | 630 | SCMutexUnlock(&g_counter_table_mutex); |
730 | 630 | } else { |
731 | 5 | dtv->counter_engine_events[i] = StatsRegisterCounter( |
732 | 5 | DEvents[i].event_name, tv); |
733 | 5 | } |
734 | 635 | } |
735 | | |
736 | 5 | return; |
737 | 5 | } |
738 | | |
739 | | void DecodeUpdatePacketCounters(ThreadVars *tv, |
740 | | const DecodeThreadVars *dtv, const Packet *p) |
741 | 21.2M | { |
742 | 21.2M | StatsIncr(tv, dtv->counter_pkts); |
743 | | //StatsIncr(tv, dtv->counter_pkts_per_sec); |
744 | 21.2M | StatsAddUI64(tv, dtv->counter_bytes, GET_PKT_LEN(p)); |
745 | 21.2M | StatsAddUI64(tv, dtv->counter_avg_pkt_size, GET_PKT_LEN(p)); |
746 | 21.2M | StatsSetUI64(tv, dtv->counter_max_pkt_size, GET_PKT_LEN(p)); |
747 | 21.2M | } |
748 | | |
749 | | /** |
750 | | * \brief Debug print function for printing addresses |
751 | | * |
752 | | * \param Address object |
753 | | * |
754 | | * \todo IPv6 |
755 | | */ |
756 | | void AddressDebugPrint(Address *a) |
757 | 0 | { |
758 | 0 | if (a == NULL) |
759 | 0 | return; |
760 | | |
761 | 0 | switch (a->family) { |
762 | 0 | case AF_INET: |
763 | 0 | { |
764 | 0 | char s[16]; |
765 | 0 | PrintInet(AF_INET, (const void *)&a->addr_data32[0], s, sizeof(s)); |
766 | 0 | SCLogDebug("%s", s); |
767 | 0 | break; |
768 | 0 | } |
769 | 0 | } |
770 | 0 | } |
771 | | |
772 | | /** \brief Alloc and setup DecodeThreadVars */ |
773 | | DecodeThreadVars *DecodeThreadVarsAlloc(ThreadVars *tv) |
774 | 10 | { |
775 | 10 | DecodeThreadVars *dtv = NULL; |
776 | | |
777 | 10 | if ( (dtv = SCMalloc(sizeof(DecodeThreadVars))) == NULL) |
778 | 0 | return NULL; |
779 | 10 | memset(dtv, 0, sizeof(DecodeThreadVars)); |
780 | | |
781 | 10 | dtv->app_tctx = AppLayerGetCtxThread(tv); |
782 | | |
783 | 10 | if (OutputFlowLogThreadInit(tv, NULL, &dtv->output_flow_thread_data) != TM_ECODE_OK) { |
784 | 0 | SCLogError("initializing flow log API for thread failed"); |
785 | 0 | DecodeThreadVarsFree(tv, dtv); |
786 | 0 | return NULL; |
787 | 0 | } |
788 | | |
789 | 10 | return dtv; |
790 | 10 | } |
791 | | |
792 | | void DecodeThreadVarsFree(ThreadVars *tv, DecodeThreadVars *dtv) |
793 | 0 | { |
794 | 0 | if (dtv != NULL) { |
795 | 0 | if (dtv->app_tctx != NULL) |
796 | 0 | AppLayerDestroyCtxThread(dtv->app_tctx); |
797 | |
|
798 | 0 | if (dtv->output_flow_thread_data != NULL) |
799 | 0 | OutputFlowLogThreadDeinit(tv, dtv->output_flow_thread_data); |
800 | |
|
801 | 0 | SCFree(dtv); |
802 | 0 | } |
803 | 0 | } |
804 | | |
805 | | /** |
806 | | * \brief Set data for Packet and set length when zero copy is used |
807 | | * |
808 | | * \param Pointer to the Packet to modify |
809 | | * \param Pointer to the data |
810 | | * \param Length of the data |
811 | | */ |
812 | | inline int PacketSetData(Packet *p, const uint8_t *pktdata, uint32_t pktlen) |
813 | 0 | { |
814 | 0 | SET_PKT_LEN(p, (size_t)pktlen); |
815 | 0 | if (unlikely(!pktdata)) { |
816 | 0 | return -1; |
817 | 0 | } |
818 | | // ext_pkt cannot be const (because we sometimes copy) |
819 | 0 | p->ext_pkt = (uint8_t *) pktdata; |
820 | 0 | p->flags |= PKT_ZERO_COPY; |
821 | |
|
822 | 0 | return 0; |
823 | 0 | } |
824 | | |
825 | | const char *PktSrcToString(enum PktSrcEnum pkt_src) |
826 | 13.5M | { |
827 | 13.5M | const char *pkt_src_str = NULL; |
828 | 13.5M | switch (pkt_src) { |
829 | 13.3M | case PKT_SRC_WIRE: |
830 | 13.3M | pkt_src_str = "wire/pcap"; |
831 | 13.3M | break; |
832 | 0 | case PKT_SRC_DECODER_GRE: |
833 | 0 | pkt_src_str = "gre tunnel"; |
834 | 0 | break; |
835 | 0 | case PKT_SRC_DECODER_IPV4: |
836 | 0 | pkt_src_str = "ipv4 tunnel"; |
837 | 0 | break; |
838 | 0 | case PKT_SRC_DECODER_IPV6: |
839 | 0 | pkt_src_str = "ipv6 tunnel"; |
840 | 0 | break; |
841 | 0 | case PKT_SRC_DECODER_TEREDO: |
842 | 0 | pkt_src_str = "teredo tunnel"; |
843 | 0 | break; |
844 | 0 | case PKT_SRC_DEFRAG: |
845 | 0 | pkt_src_str = "defrag"; |
846 | 0 | break; |
847 | 23.2k | case PKT_SRC_STREAM_TCP_DETECTLOG_FLUSH: |
848 | 23.2k | pkt_src_str = "stream (detect/log)"; |
849 | 23.2k | break; |
850 | 121k | case PKT_SRC_FFR: |
851 | 121k | pkt_src_str = "stream (flow timeout)"; |
852 | 121k | break; |
853 | 0 | case PKT_SRC_DECODER_GENEVE: |
854 | 0 | pkt_src_str = "geneve encapsulation"; |
855 | 0 | break; |
856 | 0 | case PKT_SRC_DECODER_VXLAN: |
857 | 0 | pkt_src_str = "vxlan encapsulation"; |
858 | 0 | break; |
859 | 0 | case PKT_SRC_DETECT_RELOAD_FLUSH: |
860 | 0 | pkt_src_str = "detect reload flush"; |
861 | 0 | break; |
862 | 0 | case PKT_SRC_CAPTURE_TIMEOUT: |
863 | 0 | pkt_src_str = "capture timeout flush"; |
864 | 0 | break; |
865 | 0 | case PKT_SRC_SHUTDOWN_FLUSH: |
866 | 0 | pkt_src_str = "shutdown flush"; |
867 | 0 | break; |
868 | 13.5M | } |
869 | 13.5M | DEBUG_VALIDATE_BUG_ON(pkt_src_str == NULL); |
870 | 13.5M | return pkt_src_str; |
871 | 13.5M | } |
872 | | |
873 | | const char *PacketDropReasonToString(enum PacketDropReason r) |
874 | 0 | { |
875 | 0 | switch (r) { |
876 | 0 | case PKT_DROP_REASON_DECODE_ERROR: |
877 | 0 | return "decode error"; |
878 | 0 | case PKT_DROP_REASON_DEFRAG_ERROR: |
879 | 0 | return "defrag error"; |
880 | 0 | case PKT_DROP_REASON_DEFRAG_MEMCAP: |
881 | 0 | return "defrag memcap"; |
882 | 0 | case PKT_DROP_REASON_FLOW_MEMCAP: |
883 | 0 | return "flow memcap"; |
884 | 0 | case PKT_DROP_REASON_FLOW_DROP: |
885 | 0 | return "flow drop"; |
886 | 0 | case PKT_DROP_REASON_STREAM_ERROR: |
887 | 0 | return "stream error"; |
888 | 0 | case PKT_DROP_REASON_STREAM_MEMCAP: |
889 | 0 | return "stream memcap"; |
890 | 0 | case PKT_DROP_REASON_STREAM_MIDSTREAM: |
891 | 0 | return "stream midstream"; |
892 | 0 | case PKT_DROP_REASON_STREAM_URG: |
893 | 0 | return "stream urgent"; |
894 | 0 | case PKT_DROP_REASON_STREAM_REASSEMBLY: |
895 | 0 | return "stream reassembly"; |
896 | 0 | case PKT_DROP_REASON_APPLAYER_ERROR: |
897 | 0 | return "applayer error"; |
898 | 0 | case PKT_DROP_REASON_APPLAYER_MEMCAP: |
899 | 0 | return "applayer memcap"; |
900 | 0 | case PKT_DROP_REASON_RULES: |
901 | 0 | return "rules"; |
902 | 0 | case PKT_DROP_REASON_RULES_THRESHOLD: |
903 | 0 | return "threshold detection_filter"; |
904 | 0 | case PKT_DROP_REASON_NFQ_ERROR: |
905 | 0 | return "nfq error"; |
906 | 0 | case PKT_DROP_REASON_INNER_PACKET: |
907 | 0 | return "tunnel packet drop"; |
908 | 0 | case PKT_DROP_REASON_NOT_SET: |
909 | 0 | case PKT_DROP_REASON_MAX: |
910 | 0 | return NULL; |
911 | 0 | } |
912 | 0 | return NULL; |
913 | 0 | } |
914 | | |
915 | | static const char *PacketDropReasonToJsonString(enum PacketDropReason r) |
916 | 0 | { |
917 | 0 | switch (r) { |
918 | 0 | case PKT_DROP_REASON_DECODE_ERROR: |
919 | 0 | return "ips.drop_reason.decode_error"; |
920 | 0 | case PKT_DROP_REASON_DEFRAG_ERROR: |
921 | 0 | return "ips.drop_reason.defrag_error"; |
922 | 0 | case PKT_DROP_REASON_DEFRAG_MEMCAP: |
923 | 0 | return "ips.drop_reason.defrag_memcap"; |
924 | 0 | case PKT_DROP_REASON_FLOW_MEMCAP: |
925 | 0 | return "ips.drop_reason.flow_memcap"; |
926 | 0 | case PKT_DROP_REASON_FLOW_DROP: |
927 | 0 | return "ips.drop_reason.flow_drop"; |
928 | 0 | case PKT_DROP_REASON_STREAM_ERROR: |
929 | 0 | return "ips.drop_reason.stream_error"; |
930 | 0 | case PKT_DROP_REASON_STREAM_MEMCAP: |
931 | 0 | return "ips.drop_reason.stream_memcap"; |
932 | 0 | case PKT_DROP_REASON_STREAM_MIDSTREAM: |
933 | 0 | return "ips.drop_reason.stream_midstream"; |
934 | 0 | case PKT_DROP_REASON_STREAM_URG: |
935 | 0 | return "ips.drop_reason.stream_urgent"; |
936 | 0 | case PKT_DROP_REASON_STREAM_REASSEMBLY: |
937 | 0 | return "ips.drop_reason.stream_reassembly"; |
938 | 0 | case PKT_DROP_REASON_APPLAYER_ERROR: |
939 | 0 | return "ips.drop_reason.applayer_error"; |
940 | 0 | case PKT_DROP_REASON_APPLAYER_MEMCAP: |
941 | 0 | return "ips.drop_reason.applayer_memcap"; |
942 | 0 | case PKT_DROP_REASON_RULES: |
943 | 0 | return "ips.drop_reason.rules"; |
944 | 0 | case PKT_DROP_REASON_RULES_THRESHOLD: |
945 | 0 | return "ips.drop_reason.threshold_detection_filter"; |
946 | 0 | case PKT_DROP_REASON_NFQ_ERROR: |
947 | 0 | return "ips.drop_reason.nfq_error"; |
948 | 0 | case PKT_DROP_REASON_INNER_PACKET: |
949 | 0 | return "ips.drop_reason.tunnel_packet_drop"; |
950 | 0 | case PKT_DROP_REASON_NOT_SET: |
951 | 0 | case PKT_DROP_REASON_MAX: |
952 | 0 | return NULL; |
953 | 0 | } |
954 | 0 | return NULL; |
955 | 0 | } |
956 | | |
957 | | typedef struct CaptureStats_ { |
958 | | uint16_t counter_ips_accepted; |
959 | | uint16_t counter_ips_blocked; |
960 | | uint16_t counter_ips_rejected; |
961 | | uint16_t counter_ips_replaced; |
962 | | |
963 | | uint16_t counter_drop_reason[PKT_DROP_REASON_MAX]; |
964 | | } CaptureStats; |
965 | | |
966 | | thread_local CaptureStats t_capture_stats; |
967 | | |
968 | | void CaptureStatsUpdate(ThreadVars *tv, const Packet *p) |
969 | 1.37M | { |
970 | 1.37M | if (!EngineModeIsIPS() || PKT_IS_PSEUDOPKT(p)) |
971 | 1.37M | return; |
972 | | |
973 | 0 | CaptureStats *s = &t_capture_stats; |
974 | 0 | if (unlikely(PacketCheckAction(p, ACTION_REJECT_ANY))) { |
975 | 0 | StatsIncr(tv, s->counter_ips_rejected); |
976 | 0 | } else if (unlikely(PacketCheckAction(p, ACTION_DROP))) { |
977 | 0 | StatsIncr(tv, s->counter_ips_blocked); |
978 | 0 | } else if (unlikely(p->flags & PKT_STREAM_MODIFIED)) { |
979 | 0 | StatsIncr(tv, s->counter_ips_replaced); |
980 | 0 | } else { |
981 | 0 | StatsIncr(tv, s->counter_ips_accepted); |
982 | 0 | } |
983 | 0 | if (p->drop_reason != PKT_DROP_REASON_NOT_SET) { |
984 | 0 | StatsIncr(tv, s->counter_drop_reason[p->drop_reason]); |
985 | 0 | } |
986 | 0 | } |
987 | | |
988 | | void CaptureStatsSetup(ThreadVars *tv) |
989 | 0 | { |
990 | 0 | if (EngineModeIsIPS()) { |
991 | 0 | CaptureStats *s = &t_capture_stats; |
992 | 0 | s->counter_ips_accepted = StatsRegisterCounter("ips.accepted", tv); |
993 | 0 | s->counter_ips_blocked = StatsRegisterCounter("ips.blocked", tv); |
994 | 0 | s->counter_ips_rejected = StatsRegisterCounter("ips.rejected", tv); |
995 | 0 | s->counter_ips_replaced = StatsRegisterCounter("ips.replaced", tv); |
996 | 0 | for (int i = PKT_DROP_REASON_NOT_SET; i < PKT_DROP_REASON_MAX; i++) { |
997 | 0 | const char *name = PacketDropReasonToJsonString(i); |
998 | 0 | if (name != NULL) |
999 | 0 | s->counter_drop_reason[i] = StatsRegisterCounter(name, tv); |
1000 | 0 | } |
1001 | 0 | } |
1002 | 0 | } |
1003 | | |
1004 | | void DecodeGlobalConfig(void) |
1005 | 71 | { |
1006 | 71 | DecodeIPV4IpInIpConfig(); |
1007 | 71 | DecodeIPV4InIPV6Config(); |
1008 | 71 | DecodeIPV6InIPV6Config(); |
1009 | 71 | DecodeTeredoConfig(); |
1010 | 71 | DecodeGeneveConfig(); |
1011 | 71 | DecodeVXLANConfig(); |
1012 | 71 | DecodeERSPANConfig(); |
1013 | 71 | intmax_t value = 0; |
1014 | 71 | if (ConfGetInt("decoder.max-layers", &value) == 1) { |
1015 | 0 | if (value < 0 || value > UINT8_MAX) { |
1016 | 0 | SCLogWarning("Invalid value for decoder.max-layers"); |
1017 | 0 | } else { |
1018 | 0 | decoder_max_layers = (uint8_t)value; |
1019 | 0 | } |
1020 | 0 | } |
1021 | 71 | PacketAlertGetMaxConfig(); |
1022 | 71 | } |
1023 | | |
1024 | | void PacketAlertGetMaxConfig(void) |
1025 | 71 | { |
1026 | 71 | intmax_t max = 0; |
1027 | 71 | if (ConfGetInt("packet-alert-max", &max) == 1) { |
1028 | 0 | if (max <= 0 || max > UINT8_MAX) { |
1029 | 0 | SCLogWarning("Invalid value for packet-alert-max, default value set instead"); |
1030 | 0 | } else { |
1031 | 0 | packet_alert_max = (uint16_t)max; |
1032 | 0 | } |
1033 | 0 | } |
1034 | 71 | SCLogDebug("detect->packet_alert_max set to %d", packet_alert_max); |
1035 | 71 | } |
1036 | | |
1037 | | /** |
1038 | | * @} |
1039 | | */ |