suricata
detect-csum.c
Go to the documentation of this file.
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 * \file
20 *
21 * \author Anoop Saldanha <anoopsaldanha@gmail.com>
22 *
23 * Implements checksum keyword.
24 */
25
26#include "suricata-common.h"
27#include "decode.h"
28
29#include "detect.h"
30#include "detect-parse.h"
31
32#include "detect-csum.h"
33
34#include "util-unittest.h"
35#include "util-debug.h"
36
37#include "pkt-var.h"
38#include "host.h"
39#include "util-profiling.h"
40#include "detect-engine-build.h"
41
42#define DETECT_CSUM_VALID "valid"
43#define DETECT_CSUM_INVALID "invalid"
44
45typedef struct DetectCsumData_ {
46 /* Indicates if the csum-<protocol> keyword in a rule holds the
47 keyvalue "valid" or "invalid" */
48 int16_t valid;
50
51/* prototypes for the "ipv4-csum" rule keyword */
52static int DetectIPV4CsumMatch(DetectEngineThreadCtx *,
53 Packet *, const Signature *, const SigMatchCtx *);
54static int DetectIPV4CsumSetup(DetectEngineCtx *, Signature *, const char *);
55static void DetectIPV4CsumFree(DetectEngineCtx *, void *);
56
57/* prototypes for the "tcpv4-csum" rule keyword */
58static int DetectTCPV4CsumMatch(DetectEngineThreadCtx *,
59 Packet *, const Signature *, const SigMatchCtx *);
60static int DetectTCPV4CsumSetup(DetectEngineCtx *, Signature *, const char *);
61static void DetectTCPV4CsumFree(DetectEngineCtx *, void *);
62
63/* prototypes for the "tcpv6-csum" rule keyword */
64static int DetectTCPV6CsumMatch(DetectEngineThreadCtx *,
65 Packet *, const Signature *, const SigMatchCtx *);
66static int DetectTCPV6CsumSetup(DetectEngineCtx *, Signature *, const char *);
67static void DetectTCPV6CsumFree(DetectEngineCtx *, void *);
68
69/* prototypes for the "udpv4-csum" rule keyword */
70static int DetectUDPV4CsumMatch(DetectEngineThreadCtx *,
71 Packet *, const Signature *, const SigMatchCtx *);
72static int DetectUDPV4CsumSetup(DetectEngineCtx *, Signature *, const char *);
73static void DetectUDPV4CsumFree(DetectEngineCtx *, void *);
74
75/* prototypes for the "udpv6-csum" rule keyword */
76static int DetectUDPV6CsumMatch(DetectEngineThreadCtx *,
77 Packet *, const Signature *, const SigMatchCtx *);
78static int DetectUDPV6CsumSetup(DetectEngineCtx *, Signature *, const char *);
79static void DetectUDPV6CsumFree(DetectEngineCtx *de_ctx, void *);
80
81/* prototypes for the "icmpv4-csum" rule keyword */
82static int DetectICMPV4CsumMatch(DetectEngineThreadCtx *,
83 Packet *, const Signature *, const SigMatchCtx *);
84static int DetectICMPV4CsumSetup(DetectEngineCtx *, Signature *, const char *);
85static void DetectICMPV4CsumFree(DetectEngineCtx *, void *);
86
87/* prototypes for the "icmpv6-csum" rule keyword */
88static int DetectICMPV6CsumMatch(DetectEngineThreadCtx *,
89 Packet *, const Signature *, const SigMatchCtx *);
90static int DetectICMPV6CsumSetup(DetectEngineCtx *, Signature *, const char *);
91static void DetectICMPV6CsumFree(DetectEngineCtx *, void *);
92
93#ifdef UNITTESTS
94static void DetectCsumRegisterTests(void);
95#endif
96
97/**
98 * \brief Registers handlers for all the checksum keywords. The checksum
99 * keywords that are registered are ipv4-sum, tcpv4-csum, tcpv6-csum,
100 * udpv4-csum, udpv6-csum, icmpv4-csum and icmpv6-csum.
101 *
102 * Each of the checksum keywords implemented here takes 2 arguments -
103 * "valid" or "invalid". If the rule keyword in the signature is
104 * specified as "valid", the Match function would return TRUE if the
105 * checksum for that particular packet and protocol is valid. Similarly
106 * for "invalid".
107 *
108 * The Setup functions takes 4 arguments -
109 *
110 * DetectEngineCtx * (de_ctx) - A pointer to the detection engine context
111 * Signature *(s) - Pointer to signature for the current Signature being
112 * parsed from the rules
113 * SigMatchCtx * (m) - Pointer to the head of the SigMatchs added to the
114 * current Signature being parsed
115 * char * (csum_str) - Pointer to a string holding the keyword value
116 *
117 * The Setup function returns 0 if it successfully parses the keyword
118 * value, and -1 otherwise.
119 *
120 * The Match function takes 5 arguments -
121 *
122 * ThreadVars * (t) - Pointer to the tv for the detection module instance
123 * DetectEngineThreadCtx * (det_ctx) - Pointer to the detection engine
124 * thread context
125 * Packet * (p) - Pointer to the Packet currently being handled
126 * Signature * (s) - Pointer to the Signature, the packet is being
127 * currently matched with
128 * SigMatchCtx * (m) - Pointer to the keyword structure from the above
129 * Signature, the Packet is being currently matched
130 * with
131 *
132 * The Match function returns 1 if the Packet contents match the keyword,
133 * and 0 otherwise
134 *
135 * The Free function takes a single argument -
136 *
137 * void * (ptr) - Pointer to the DetectCsumData for a keyword
138 */
140{
141 sigmatch_table[DETECT_IPV4_CSUM].name = "ipv4-csum";
142 sigmatch_table[DETECT_IPV4_CSUM].Match = DetectIPV4CsumMatch;
143 sigmatch_table[DETECT_IPV4_CSUM].Setup = DetectIPV4CsumSetup;
144 sigmatch_table[DETECT_IPV4_CSUM].Free = DetectIPV4CsumFree;
145#ifdef UNITTESTS
146 sigmatch_table[DETECT_IPV4_CSUM].RegisterTests = DetectCsumRegisterTests;
147#endif
148
149 sigmatch_table[DETECT_TCPV4_CSUM].name = "tcpv4-csum";
150 sigmatch_table[DETECT_TCPV4_CSUM].Match = DetectTCPV4CsumMatch;
151 sigmatch_table[DETECT_TCPV4_CSUM].Setup = DetectTCPV4CsumSetup;
152 sigmatch_table[DETECT_TCPV4_CSUM].Free = DetectTCPV4CsumFree;
153
154 sigmatch_table[DETECT_TCPV6_CSUM].name = "tcpv6-csum";
155 sigmatch_table[DETECT_TCPV6_CSUM].Match = DetectTCPV6CsumMatch;
156 sigmatch_table[DETECT_TCPV6_CSUM].Setup = DetectTCPV6CsumSetup;
157 sigmatch_table[DETECT_TCPV6_CSUM].Free = DetectTCPV6CsumFree;
158
159 sigmatch_table[DETECT_UDPV4_CSUM].name = "udpv4-csum";
160 sigmatch_table[DETECT_UDPV4_CSUM].Match = DetectUDPV4CsumMatch;
161 sigmatch_table[DETECT_UDPV4_CSUM].Setup = DetectUDPV4CsumSetup;
162 sigmatch_table[DETECT_UDPV4_CSUM].Free = DetectUDPV4CsumFree;
163
164 sigmatch_table[DETECT_UDPV6_CSUM].name = "udpv6-csum";
165 sigmatch_table[DETECT_UDPV6_CSUM].Match = DetectUDPV6CsumMatch;
166 sigmatch_table[DETECT_UDPV6_CSUM].Setup = DetectUDPV6CsumSetup;
167 sigmatch_table[DETECT_UDPV6_CSUM].Free = DetectUDPV6CsumFree;
168
169 sigmatch_table[DETECT_ICMPV4_CSUM].name = "icmpv4-csum";
170 sigmatch_table[DETECT_ICMPV4_CSUM].Match = DetectICMPV4CsumMatch;
171 sigmatch_table[DETECT_ICMPV4_CSUM].Setup = DetectICMPV4CsumSetup;
172 sigmatch_table[DETECT_ICMPV4_CSUM].Free = DetectICMPV4CsumFree;
173
174 sigmatch_table[DETECT_ICMPV6_CSUM].name = "icmpv6-csum";
175 sigmatch_table[DETECT_ICMPV6_CSUM].Match = DetectICMPV6CsumMatch;
176 sigmatch_table[DETECT_ICMPV6_CSUM].Setup = DetectICMPV6CsumSetup;
177 sigmatch_table[DETECT_ICMPV6_CSUM].Free = DetectICMPV6CsumFree;
178}
179
180/**
181 * \brief Validates and parses the argument supplied with the checksum keyword.
182 * Accepts strings both with and without quotes, i.e. valid, \"valid\",
183 * invalid and \"invalid\"
184 *
185 * \param key Pointer to a const character string holding the csum keyword value
186 * \param cd Pointer to the DetectCsumData structure that holds the keyword
187 * value sent as argument
188 *
189 * \retval 1 the keyvalue has been parsed successfully
190 * \retval 0 error
191 */
192static int DetectCsumParseArg(const char *key, DetectCsumData *cd)
193{
194 char *str;
195
196 if (key[0] == '\"' && key[strlen(key) - 1] == '\"') {
197 str = SCStrdup(key + 1);
198 if (unlikely(str == NULL)) {
199 return 0;
200 }
201 str[strlen(key) - 2] = '\0';
202 } else {
203 str = SCStrdup(key);
204 if (unlikely(str == NULL)) {
205 return 0;
206 }
207 }
208
209 if (strcasecmp(str, DETECT_CSUM_VALID) == 0 ||
210 strcasecmp(str, DETECT_CSUM_INVALID) == 0) {
211 cd->valid = (strcasecmp(key, DETECT_CSUM_VALID) == 0);
212 SCFree(str);
213 return 1;
214 }
215
216 SCFree(str);
217 return 0;
218}
219
220/**
221 * \brief Checks if the packet sent as the argument, has a valid or invalid
222 * ipv4 checksum, based on whether ipv4-csum option for this rule
223 * has been supplied with "valid" or "invalid" argument
224 *
225 * \param t Pointer to the tv for this detection module instance
226 * \param det_ctx Pointer to the detection engine thread context
227 * \param p Pointer to the Packet currently being matched
228 * \param s Pointer to the Signature, the packet is being currently
229 * matched with
230 * \param m Pointer to the keyword_structure(SigMatch) from the above
231 * Signature, the Packet is being currently matched with
232 *
233 * \retval 1 if the Packet contents match the keyword option; 0 otherwise
234 */
235static int DetectIPV4CsumMatch(DetectEngineThreadCtx *det_ctx,
236 Packet *p, const Signature *s, const SigMatchCtx *ctx)
237{
238 const DetectCsumData *cd = (const DetectCsumData *)ctx;
239
240 if (!PacketIsIPv4(p))
241 return 0;
242
243 if (p->flags & PKT_IGNORE_CHECKSUM) {
244 return cd->valid;
245 }
246
247 if (!p->l3.csum_set) {
248 const IPV4Hdr *ip4h = PacketGetIPv4(p);
249 p->l3.csum = IPV4Checksum((uint16_t *)ip4h, IPV4_GET_RAW_HLEN(ip4h), ip4h->ip_csum);
250 p->l3.csum_set = true;
251 }
252
253 if (p->l3.csum == 0 && cd->valid == 1)
254 return 1;
255 else if (p->l3.csum != 0 && cd->valid == 0)
256 return 1;
257 else
258 return 0;
259}
260
261/**
262 * \brief Creates a SigMatch for the ipv4-csum keyword being sent as argument,
263 * and appends it to the Signature(s). Accepts 2 values for the
264 * keyword - "valid" and "invalid", both with and without quotes
265 *
266 * \param de_ctx Pointer to the detection engine context
267 * \param s Pointer to signature for the current Signature being parsed
268 * from the rules
269 * \param csum_str Pointer to the string holding the keyword value
270 *
271 * \retval 0 on success, -1 on failure
272 */
273static int DetectIPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, const char *csum_str)
274{
275 DetectCsumData *cd = SCCalloc(1, sizeof(DetectCsumData));
276 if (cd == NULL)
277 return -1;
278
279 if (DetectCsumParseArg(csum_str, cd) == 0)
280 goto error;
281
284 goto error;
285 }
286
287 return 0;
288
289error:
290 DetectIPV4CsumFree(de_ctx, cd);
291 return -1;
292}
293
294static void DetectIPV4CsumFree(DetectEngineCtx *de_ctx, void *ptr)
295{
296 SCFree(ptr);
297}
298
299/**
300 * \brief Checks if the packet sent as the argument, has a valid or invalid
301 * tcpv4 checksum, based on whether tcpv4-csum option for this rule
302 * has been supplied with "valid" or "invalid" argument
303 *
304 * \param t Pointer to the tv for this detection module instance
305 * \param det_ctx Pointer to the detection engine thread context
306 * \param p Pointer to the Packet currently being matched
307 * \param s Pointer to the Signature, the packet is being currently
308 * matched with
309 * \param m Pointer to the keyword_structure(SigMatch) from the above
310 * Signature, the Packet is being currently matched with
311 *
312 * \retval 1 if the Packet contents match the keyword option; 0 otherwise
313 */
314static int DetectTCPV4CsumMatch(DetectEngineThreadCtx *det_ctx,
315 Packet *p, const Signature *s, const SigMatchCtx *ctx)
316{
317 const DetectCsumData *cd = (const DetectCsumData *)ctx;
318
319 if (!PacketIsIPv4(p) || !PacketIsTCP(p) || p->proto != IPPROTO_TCP)
320 return 0;
321
322 if (p->flags & PKT_IGNORE_CHECKSUM) {
323 return cd->valid;
324 }
325
326 if (!p->l4.csum_set) {
327 const IPV4Hdr *ip4h = PacketGetIPv4(p);
328 const TCPHdr *tcph = PacketGetTCP(p);
329 p->l4.csum = TCPChecksum(ip4h->s_ip_addrs, (uint16_t *)tcph,
330 (p->payload_len + TCP_GET_RAW_HLEN(tcph)), tcph->th_sum);
331 p->l4.csum_set = true;
332 }
333 if (p->l4.csum == 0 && cd->valid == 1)
334 return 1;
335 else if (p->l4.csum != 0 && cd->valid == 0)
336 return 1;
337 else
338 return 0;
339}
340
341/**
342 * \brief Creates a SigMatch for the tcpv4-csum keyword being sent as argument,
343 * and appends it to the Signature(s). Accepts 2 values for the
344 * keyword - "valid" and "invalid", both with and without quotes
345 *
346 * \param de_ctx Pointer to the detection engine context
347 * \param s Pointer to signature for the current Signature being parsed
348 * from the rules
349 * \param csum_str Pointer to the string holding the keyword value
350 *
351 * \retval 0 on success, -1 on failure
352 */
353static int DetectTCPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, const char *csum_str)
354{
355 DetectCsumData *cd = SCCalloc(1, sizeof(DetectCsumData));
356 if (cd == NULL)
357 return -1;
358
359 if (DetectCsumParseArg(csum_str, cd) == 0)
360 goto error;
361
364 goto error;
365 }
366
367 return 0;
368
369error:
370 DetectTCPV4CsumFree(de_ctx, cd);
371 return -1;
372}
373
374static void DetectTCPV4CsumFree(DetectEngineCtx *de_ctx, void *ptr)
375{
376 SCFree(ptr);
377}
378
379/**
380 * \brief Checks if the packet sent as the argument, has a valid or invalid
381 * tcpv6 checksum, based on whether tcpv6-csum option for this rule
382 * has been supplied with "valid" or "invalid" argument
383 *
384 * \param t Pointer to the tv for this detection module instance
385 * \param det_ctx Pointer to the detection engine thread context
386 * \param p Pointer to the Packet currently being matched
387 * \param s Pointer to the Signature, the packet is being currently
388 * matched with
389 * \param m Pointer to the keyword_structure(SigMatch) from the above
390 * Signature, the Packet is being currently matched with
391 *
392 * \retval 1 if the Packet contents match the keyword option; 0 otherwise
393 */
394static int DetectTCPV6CsumMatch(DetectEngineThreadCtx *det_ctx,
395 Packet *p, const Signature *s, const SigMatchCtx *ctx)
396{
397 const DetectCsumData *cd = (const DetectCsumData *)ctx;
398
399 if (!PacketIsIPv6(p) || !PacketIsTCP(p) || p->proto != IPPROTO_TCP)
400 return 0;
401
402 if (p->flags & PKT_IGNORE_CHECKSUM) {
403 return cd->valid;
404 }
405
406 if (!p->l4.csum_set) {
407 const IPV6Hdr *ip6h = PacketGetIPv6(p);
408 const TCPHdr *tcph = PacketGetTCP(p);
409 p->l4.csum = TCPV6Checksum(ip6h->s_ip6_addrs, (uint16_t *)tcph,
410 (p->payload_len + TCP_GET_RAW_HLEN(tcph)), tcph->th_sum);
411 p->l4.csum_set = true;
412 }
413
414 if (p->l4.csum == 0 && cd->valid == 1)
415 return 1;
416 else if (p->l4.csum != 0 && cd->valid == 0)
417 return 1;
418 else
419 return 0;
420}
421
422/**
423 * \brief Creates a SigMatch for the tcpv6-csum keyword being sent as argument,
424 * and appends it to the Signature(s). Accepts 2 values for the
425 * keyword - "valid" and "invalid", both with and without quotes
426 *
427 * \param de_ctx Pointer to the detection engine context
428 * \param s Pointer to signature for the current Signature being parsed
429 * from the rules
430 * \param csum_str Pointer to the string holding the keyword value
431 *
432 * \retval 0 on success, -1 on failure
433 */
434static int DetectTCPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, const char *csum_str)
435{
436 DetectCsumData *cd = SCCalloc(1, sizeof(DetectCsumData));
437 if (cd == NULL)
438 return -1;
439
440 if (DetectCsumParseArg(csum_str, cd) == 0)
441 goto error;
442
445 goto error;
446 }
447
448 return 0;
449
450error:
451 DetectTCPV6CsumFree(de_ctx, cd);
452 return -1;
453}
454
455static void DetectTCPV6CsumFree(DetectEngineCtx *de_ctx, void *ptr)
456{
457 SCFree(ptr);
458}
459
460/**
461 * \brief Checks if the packet sent as the argument, has a valid or invalid
462 * udpv4 checksum, based on whether udpv4-csum option for this rule
463 * has been supplied with "valid" or "invalid" argument
464 *
465 * \param t Pointer to the tv for this detection module instance
466 * \param det_ctx Pointer to the detection engine thread context
467 * \param p Pointer to the Packet currently being matched
468 * \param s Pointer to the Signature, the packet is being currently
469 * matched with
470 * \param m Pointer to the keyword_structure(SigMatch) from the above
471 * Signature, the Packet is being currently matched with
472 *
473 * \retval 1 if the Packet contents match the keyword option; 0 otherwise
474 */
475static int DetectUDPV4CsumMatch(DetectEngineThreadCtx *det_ctx,
476 Packet *p, const Signature *s, const SigMatchCtx *ctx)
477{
478 const DetectCsumData *cd = (const DetectCsumData *)ctx;
479
480 if (!PacketIsIPv4(p) || !PacketIsUDP(p) || p->proto != IPPROTO_UDP)
481 return 0;
482
483 const UDPHdr *udph = PacketGetUDP(p);
484 if (udph->uh_sum == 0)
485 return 0;
486
487 if (p->flags & PKT_IGNORE_CHECKSUM) {
488 return cd->valid;
489 }
490
491 if (!p->l4.csum_set) {
492 const IPV4Hdr *ip4h = PacketGetIPv4(p);
493 p->l4.csum = UDPV4Checksum(ip4h->s_ip_addrs, (uint16_t *)udph,
494 (p->payload_len + UDP_HEADER_LEN), udph->uh_sum);
495 p->l4.csum_set = true;
496 }
497 if (p->l4.csum == 0 && cd->valid == 1)
498 return 1;
499 else if (p->l4.csum != 0 && cd->valid == 0)
500 return 1;
501 else
502 return 0;
503}
504
505/**
506 * \brief Creates a SigMatch for the udpv4-csum keyword being sent as argument,
507 * and appends it to the Signature(s). Accepts 2 values for the
508 * keyword - "valid" and "invalid", both with and without quotes
509 *
510 * \param de_ctx Pointer to the detection engine context
511 * \param s Pointer to signature for the current Signature being parsed
512 * from the rules
513 * \param csum_str Pointer to the string holding the keyword value
514 *
515 * \retval 0 on success, -1 on failure
516 */
517static int DetectUDPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, const char *csum_str)
518{
519 DetectCsumData *cd = SCCalloc(1, sizeof(DetectCsumData));
520 if (cd == NULL)
521 return -1;
522
523 if (DetectCsumParseArg(csum_str, cd) == 0)
524 goto error;
525
528 goto error;
529 }
530
531 return 0;
532
533error:
534 DetectUDPV4CsumFree(de_ctx, cd);
535 return -1;
536}
537
538static void DetectUDPV4CsumFree(DetectEngineCtx *de_ctx, void *ptr)
539{
540 SCFree(ptr);
541}
542
543/**
544 * \brief Checks if the packet sent as the argument, has a valid or invalid
545 * udpv6 checksum, based on whether udpv6-csum option for this rule
546 * has been supplied with "valid" or "invalid" argument
547 *
548 * \param t Pointer to the tv for this detection module instance
549 * \param det_ctx Pointer to the detection engine thread context
550 * \param p Pointer to the Packet currently being matched
551 * \param s Pointer to the Signature, the packet is being currently
552 * matched with
553 * \param m Pointer to the keyword_structure(SigMatch) from the above
554 * Signature, the Packet is being currently matched with
555 *
556 * \retval 1 if the Packet contents match the keyword option; 0 otherwise
557 */
558static int DetectUDPV6CsumMatch(DetectEngineThreadCtx *det_ctx,
559 Packet *p, const Signature *s, const SigMatchCtx *ctx)
560{
561 const DetectCsumData *cd = (const DetectCsumData *)ctx;
562
563 if (!PacketIsIPv6(p) || !PacketIsUDP(p) || p->proto != IPPROTO_UDP)
564 return 0;
565
566 if (p->flags & PKT_IGNORE_CHECKSUM) {
567 return cd->valid;
568 }
569
570 if (!p->l4.csum_set) {
571 const IPV6Hdr *ip6h = PacketGetIPv6(p);
572 const UDPHdr *udph = PacketGetUDP(p);
573 p->l4.csum = UDPV6Checksum(ip6h->s_ip6_addrs, (uint16_t *)udph,
574 (p->payload_len + UDP_HEADER_LEN), udph->uh_sum);
575 p->l4.csum_set = true;
576 }
577 if (p->l4.csum == 0 && cd->valid == 1)
578 return 1;
579 else if (p->l4.csum != 0 && cd->valid == 0)
580 return 1;
581 else
582 return 0;
583}
584
585/**
586 * \brief Creates a SigMatch for the udpv6-csum keyword being sent as argument,
587 * and appends it to the Signature(s). Accepts 2 values for the
588 * keyword - "valid" and "invalid", both with and without quotes
589 *
590 * \param de_ctx Pointer to the detection engine context
591 * \param s Pointer to signature for the current Signature being parsed
592 * from the rules
593 * \param csum_str Pointer to the string holding the keyword value
594 *
595 * \retval 0 on success, -1 on failure
596 */
597static int DetectUDPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, const char *csum_str)
598{
599 DetectCsumData *cd = SCCalloc(1, sizeof(DetectCsumData));
600 if (cd == NULL)
601 return -1;
602
603 if (DetectCsumParseArg(csum_str, cd) == 0)
604 goto error;
605
608 goto error;
609 }
610
611 return 0;
612
613error:
614 DetectUDPV6CsumFree(de_ctx, cd);
615 return -1;
616}
617
618static void DetectUDPV6CsumFree(DetectEngineCtx *de_ctx, void *ptr)
619{
620 DetectCsumData *cd = (DetectCsumData *)ptr;
621
622 if (cd != NULL)
623 SCFree(cd);
624}
625
626/**
627 * \brief Checks if the packet sent as the argument, has a valid or invalid
628 * icmpv4 checksum, based on whether icmpv4-csum option for this rule
629 * has been supplied with "valid" or "invalid" argument
630 *
631 * \param t Pointer to the tv for this detection module instance
632 * \param det_ctx Pointer to the detection engine thread context
633 * \param p Pointer to the Packet currently being matched
634 * \param s Pointer to the Signature, the packet is being currently
635 * matched with
636 * \param m Pointer to the keyword_structure(SigMatch) from the above
637 * Signature, the Packet is being currently matched with
638 *
639 * \retval 1 if the Packet contents match the keyword option; 0 otherwise
640 */
641static int DetectICMPV4CsumMatch(DetectEngineThreadCtx *det_ctx,
642 Packet *p, const Signature *s, const SigMatchCtx *ctx)
643{
644 const DetectCsumData *cd = (const DetectCsumData *)ctx;
645
646 if (!PacketIsIPv4(p) || !PacketIsICMPv4(p) || p->proto != IPPROTO_ICMP)
647 return 0;
648
649 if (p->flags & PKT_IGNORE_CHECKSUM) {
650 return cd->valid;
651 }
652
653 const ICMPV4Hdr *icmpv4h = PacketGetICMPv4(p);
654 if (!p->l4.csum_set) {
655 const IPV4Hdr *ip4h = PacketGetIPv4(p);
656 p->l4.csum = ICMPV4CalculateChecksum(
657 (uint16_t *)icmpv4h, IPV4_GET_RAW_IPLEN(ip4h) - IPV4_GET_RAW_HLEN(ip4h));
658 p->l4.csum_set = true;
659 }
660 if (p->l4.csum == icmpv4h->checksum && cd->valid == 1)
661 return 1;
662 else if (p->l4.csum != icmpv4h->checksum && cd->valid == 0)
663 return 1;
664 else
665 return 0;
666}
667
668/**
669 * \brief Creates a SigMatch for the icmpv4-csum keyword being sent as argument,
670 * and appends it to the Signature(s). Accepts 2 values for the
671 * keyword - "valid" and "invalid", both with and without quotes
672 *
673 * \param de_ctx Pointer to the detection engine context
674 * \param s Pointer to signature for the current Signature being parsed
675 * from the rules
676 * \param csum_str Pointer to the string holding the keyword value
677 *
678 * \retval 0 on success, -1 on failure
679 */
680static int DetectICMPV4CsumSetup(DetectEngineCtx *de_ctx, Signature *s, const char *csum_str)
681{
682 DetectCsumData *cd = SCCalloc(1, sizeof(DetectCsumData));
683 if (cd == NULL)
684 return -1;
685
686 if (DetectCsumParseArg(csum_str, cd) == 0)
687 goto error;
688
691 goto error;
692 }
693
694 return 0;
695
696error:
697 DetectICMPV4CsumFree(de_ctx, cd);
698 return -1;
699}
700
701static void DetectICMPV4CsumFree(DetectEngineCtx *de_ctx, void *ptr)
702{
703 SCFree(ptr);
704}
705
706/**
707 * \brief Checks if the packet sent as the argument, has a valid or invalid
708 * icmpv6 checksum, based on whether icmpv6-csum option for this rule
709 * has been supplied with "valid" or "invalid" argument
710 *
711 * \param t Pointer to the tv for this detection module instance
712 * \param det_ctx Pointer to the detection engine thread context
713 * \param p Pointer to the Packet currently being matched
714 * \param s Pointer to the Signature, the packet is being currently
715 * matched with
716 * \param m Pointer to the keyword_structure(SigMatch) from the above
717 * Signature, the Packet is being currently matched with
718 *
719 * \retval 1 if the Packet contents match the keyword option; 0 otherwise
720 */
721static int DetectICMPV6CsumMatch(DetectEngineThreadCtx *det_ctx,
722 Packet *p, const Signature *s, const SigMatchCtx *ctx)
723{
724 const DetectCsumData *cd = (const DetectCsumData *)ctx;
725
726 if (!PacketIsIPv6(p) || !PacketIsICMPv6(p) || p->proto != IPPROTO_ICMPV6) {
727 return 0;
728 }
729 const ICMPV6Hdr *icmpv6h = PacketGetICMPv6(p);
730 if ((GET_PKT_LEN(p) - ((uint8_t *)icmpv6h - GET_PKT_DATA(p))) <= 0) {
731 return 0;
732 }
733
734 if (p->flags & PKT_IGNORE_CHECKSUM) {
735 return cd->valid;
736 }
737
738 if (!p->l4.csum_set) {
739 const IPV6Hdr *ip6h = PacketGetIPv6(p);
740 uint16_t len = IPV6_GET_RAW_PLEN(ip6h) -
741 (uint16_t)((uint8_t *)icmpv6h - (uint8_t *)ip6h - IPV6_HEADER_LEN);
742 p->l4.csum = ICMPV6CalculateChecksum(ip6h->s_ip6_addrs, (uint16_t *)icmpv6h, len);
743 p->l4.csum_set = true;
744 }
745
746 if (p->l4.csum == icmpv6h->csum && cd->valid == 1)
747 return 1;
748 else if (p->l4.csum != icmpv6h->csum && cd->valid == 0)
749 return 1;
750 else
751 return 0;
752}
753
754/**
755 * \brief Creates a SigMatch for the icmpv6-csum keyword being sent as argument,
756 * and appends it to the Signature(s). Accepts 2 values for the
757 * keyword - "valid" and "invalid", both with and without quotes
758 *
759 * \param de_ctx Pointer to the detection engine context
760 * \param s Pointer to signature for the current Signature being parsed
761 * from the rules
762 * \param csum_str Pointer to the string holding the keyword value
763 *
764 * \retval 0 on success, -1 on failure
765 */
766static int DetectICMPV6CsumSetup(DetectEngineCtx *de_ctx, Signature *s, const char *csum_str)
767{
768 DetectCsumData *cd = SCCalloc(1, sizeof(DetectCsumData));
769 if (cd == NULL)
770 return -1;
771
772 if (DetectCsumParseArg(csum_str, cd) == 0)
773 goto error;
774
777 goto error;
778 }
779
780 return 0;
781
782error:
783 DetectICMPV6CsumFree(de_ctx, cd);
784 return -1;
785}
786
787static void DetectICMPV6CsumFree(DetectEngineCtx *de_ctx, void *ptr)
788{
789 SCFree(ptr);
790}
791
792/* ---------------------------------- Unit Tests --------------------------- */
793
794#ifdef UNITTESTS
795#include "util-unittest-helper.h"
796#include "detect-engine.h"
797#include "detect-engine-alert.h"
798#include "packet.h"
799
800#define mystr(s) #s
801#define TEST1(kwstr) {\
802 DetectEngineCtx *de_ctx = DetectEngineCtxInit();\
803 FAIL_IF_NULL(de_ctx);\
804 de_ctx->flags = DE_QUIET;\
805 \
806 Signature *s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:valid; sid:1;)");\
807 FAIL_IF_NULL(s);\
808 s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:invalid; sid:2;)");\
809 FAIL_IF_NULL(s);\
810 s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:vaLid; sid:3;)");\
811 FAIL_IF_NULL(s);\
812 s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:VALID; sid:4;)");\
813 FAIL_IF_NULL(s);\
814 s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:iNvaLid; sid:5;)");\
815 FAIL_IF_NULL(s);\
816 DetectEngineCtxFree(de_ctx);\
817}
818
819
820static int DetectCsumValidArgsTestParse01(void)
821{
822 TEST1(ipv4);
823 TEST1(tcpv4);
824 TEST1(tcpv6);
825 TEST1(udpv4);
826 TEST1(udpv6);
827 TEST1(icmpv4);
828 TEST1(icmpv6);
829 PASS;
830}
831#undef TEST1
832
833#define TEST2(kwstr) \
834 { \
835 DetectEngineCtx *de_ctx = DetectEngineCtxInit(); \
836 FAIL_IF_NULL(de_ctx); \
837 Signature *s = DetectEngineAppendSig( \
838 de_ctx, "alert ip any any -> any any (" mystr(kwstr) "-csum:xxxx; sid:1;)"); \
839 FAIL_IF(s); \
840 s = DetectEngineAppendSig( \
841 de_ctx, "alert ip any any -> any any (" mystr(kwstr) "-csum:xxxxxxxx; sid:2;)"); \
842 FAIL_IF(s); \
843 s = DetectEngineAppendSig( \
844 de_ctx, "alert ip any any -> any any (" mystr(kwstr) "-csum:xxxxxx; sid:3;)"); \
845 FAIL_IF(s); \
846 s = DetectEngineAppendSig( \
847 de_ctx, "alert ip any any -> any any (" mystr(kwstr) "-csum:XXXXXX; sid:4;)"); \
848 FAIL_IF(s); \
849 s = DetectEngineAppendSig( \
850 de_ctx, "alert ip any any -> any any (" mystr(kwstr) "-csum:XxXxXxX; sid:5;)"); \
851 FAIL_IF(s); \
852 DetectEngineCtxFree(de_ctx); \
853 }
854
855static int DetectCsumInvalidArgsTestParse02(void)
856{
857 TEST2(ipv4);
858 TEST2(tcpv4);
859 TEST2(tcpv6);
860 TEST2(udpv4);
861 TEST2(udpv6);
862 TEST2(icmpv4);
863 TEST2(icmpv6);
864 PASS;
865}
866#undef TEST2
867
868#define TEST3(kwstr, kwtype) { \
869 DetectEngineCtx *de_ctx = DetectEngineCtxInit();\
870 FAIL_IF_NULL(de_ctx);\
871 Signature *s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:valid; sid:1;)");\
872 FAIL_IF_NULL(s);\
873 SigMatch *sm = DetectGetLastSMFromLists(s, (kwtype), -1);\
874 FAIL_IF_NULL(sm);\
875 FAIL_IF_NULL(sm->ctx);\
876 FAIL_IF_NOT(((DetectCsumData *)sm->ctx)->valid == 1);\
877 s = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any ("mystr(kwstr)"-csum:INVALID; sid:2;)");\
878 FAIL_IF_NULL(s);\
879 sm = DetectGetLastSMFromLists(s, (kwtype), -1);\
880 FAIL_IF_NULL(sm);\
881 FAIL_IF_NULL(sm->ctx);\
882 FAIL_IF_NOT(((DetectCsumData *)sm->ctx)->valid == 0);\
883 DetectEngineCtxFree(de_ctx);\
884}
885
886static int DetectCsumValidArgsTestParse03(void)
887{
888 TEST3(ipv4, DETECT_IPV4_CSUM);
889 TEST3(tcpv4, DETECT_TCPV4_CSUM);
890 TEST3(tcpv6, DETECT_TCPV6_CSUM);
891 TEST3(udpv4, DETECT_UDPV4_CSUM);
892 TEST3(udpv6, DETECT_UDPV6_CSUM);
893 TEST3(icmpv4, DETECT_ICMPV4_CSUM);
894 TEST3(icmpv6, DETECT_ICMPV6_CSUM);
895 PASS;
896}
897#undef TEST3
898#undef mystr
899
900#include "stream-tcp.h"
901
902static int DetectCsumICMPV6Test01(void)
903{
904 DetectEngineCtx *de_ctx = NULL;
905 Signature *s = NULL;
907 DetectEngineThreadCtx *det_ctx = NULL;
909
911 FAIL_IF_NULL(p);
912
913 uint8_t pkt[] = {
914 0x00, 0x30, 0x18, 0xa8, 0x7c, 0x23, 0x2c, 0x41,
915 0x38, 0xa7, 0xea, 0xeb, 0x86, 0xdd, 0x60, 0x00,
916 0x00, 0x00, 0x00, 0x40, 0x3c, 0x40, 0xad, 0xa1,
917 0x09, 0x80, 0x00, 0x01, 0xd6, 0xf3, 0x20, 0x01,
918 0xf4, 0xbe, 0xea, 0x3c, 0x00, 0x01, 0x00, 0x00,
919 0x00, 0x00, 0x32, 0xb2, 0x00, 0x01, 0x32, 0xb2,
920 0x09, 0x80, 0x20, 0x01, 0x00, 0x00, 0x3c, 0x00,
921 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00,
922 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00,
923 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00,
924 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00,
925 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00,
926 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00,
927 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
928 0x63, 0xc2, 0x00, 0x00, 0x00, 0x00 };
929
930 PacketCopyData(p, pkt, sizeof(pkt));
931
932 memset(&tv, 0, sizeof(tv));
933 memset(&dtv, 0, sizeof(dtv));
934
937
942
943 s = de_ctx->sig_list = SigInit(de_ctx, "alert ip any any -> any any "
944 "(icmpv6-csum:valid; sid:1;)");
945 FAIL_IF_NULL(s);
947
949
950 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
951
952 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
953
955
958
960 PacketRecycle(p);
961 FlowShutdown();
962 SCFree(p);
963 PASS;
964}
965
966static void DetectCsumRegisterTests(void)
967{
968 UtRegisterTest("DetectCsumValidArgsTestParse01",
969 DetectCsumValidArgsTestParse01);
970 UtRegisterTest("DetectCsumInvalidArgsTestParse02",
971 DetectCsumInvalidArgsTestParse02);
972 UtRegisterTest("DetectCsumValidArgsTestParse03",
973 DetectCsumValidArgsTestParse03);
974
975 UtRegisterTest("DetectCsumICMPV6Test01",
976 DetectCsumICMPV6Test01);
977}
978#endif /* UNITTESTS */
uint8_t len
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
#define IPV4_GET_RAW_IPLEN(ip4h)
Definition decode-ipv4.h:98
#define IPV4_GET_RAW_HLEN(ip4h)
Definition decode-ipv4.h:96
#define IPV6_GET_RAW_PLEN(ip6h)
Definition decode-ipv6.h:66
#define IPV6_HEADER_LEN
Definition decode-ipv6.h:27
#define TCP_GET_RAW_HLEN(tcph)
Definition decode-tcp.h:72
#define UDP_HEADER_LEN
Definition decode-udp.h:27
#define GET_PKT_DATA(p)
Definition decode.h:209
#define GET_PKT_LEN(p)
Definition decode.h:208
#define PKT_IGNORE_CHECKSUM
Definition decode.h:1282
#define TEST1(kwstr)
#define TEST2(kwstr)
void DetectCsumRegister(void)
Registers handlers for all the checksum keywords. The checksum keywords that are registered are ipv4-...
#define DETECT_CSUM_VALID
Definition detect-csum.c:42
struct DetectCsumData_ DetectCsumData
#define TEST3(kwstr, kwtype)
#define DETECT_CSUM_INVALID
Definition detect-csum.c:43
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
@ DETECT_TCPV4_CSUM
@ DETECT_UDPV4_CSUM
@ DETECT_TCPV6_CSUM
@ DETECT_ICMPV4_CSUM
@ DETECT_UDPV6_CSUM
@ DETECT_ICMPV6_CSUM
DetectEngineCtx * DetectEngineCtxInit(void)
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
SigTableElmt * sigmatch_table
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition detect.c:2420
#define DE_QUIET
Definition detect.h:330
@ DETECT_SM_LIST_MATCH
Definition detect.h:117
void FlowInitConfig(bool quiet)
initialize the configuration
Definition flow.c:547
void FlowShutdown(void)
shutdown the flow engine
Definition flow.c:691
#define FLOW_QUIET
Definition flow.h:43
DecodeThreadVars * dtv
ThreadVars * tv
DetectEngineCtx * de_ctx
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define PASS
Pass the test.
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition decode.c:258
int PacketCopyData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Copy data to Packet payload and set packet length.
Definition decode.c:377
struct Thresholds ctx
void PacketRecycle(Packet *p)
Definition packet.c:150
void StreamTcpFreeConfig(bool quiet)
Definition stream-tcp.c:859
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition stream-tcp.c:488
Structure to hold thread specific data for all decode modules.
Definition decode.h:963
main detection engine ctx
Definition detect.h:932
uint8_t mpm_matcher
Definition detect.h:935
uint8_t flags
Definition detect.h:934
Signature * sig_list
Definition detect.h:941
uint16_t csum
bool csum_set
Definition decode.h:436
uint16_t csum
Definition decode.h:437
bool csum_set
Definition decode.h:466
uint16_t csum
Definition decode.h:467
struct PacketL4 l4
Definition decode.h:601
struct PacketL3 l3
Definition decode.h:600
uint16_t payload_len
Definition decode.h:606
uint32_t flags
Definition decode.h:544
uint8_t proto
Definition decode.h:523
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition detect.h:351
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
void(* Free)(DetectEngineCtx *, void *)
Definition detect.h:1446
void(* RegisterTests)(void)
Definition detect.h:1448
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition detect.h:1421
const char * name
Definition detect.h:1459
Signature container.
Definition detect.h:668
Per thread variable structure.
Definition threadvars.h:58
uint16_t uh_sum
Definition decode-udp.h:46
#define str(s)
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define SCStrdup(s)
Definition util-mem.h:56
uint8_t mpm_default_matcher
Definition util-mpm.c:48
#define unlikely(expr)