1 /* $Id$ */
2 /*
3 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
4 ** Copyright (C) 2007-2013 Sourcefire, Inc.
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License Version 2 as
8 ** published by the Free Software Foundation. You may not use, modify or
9 ** distribute this program under any other version of the GNU General
10 ** Public License.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 **
21 **/
22
23 /**
24 ** @file detection_options.c
25 **
26 ** @author Steven Sturges
27 **
28 ** @brief Support functions for rule option tree
29 **
30 ** This implements tree processing for rule options, evaluating common
31 ** detection options only once per pattern match.
32 **
33 */
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #include "sfutil/sfxhash.h"
40 #include "sfutil/sfhashfcn.h"
41 #include "detection_options.h"
42 #include "detection_util.h"
43 #include "rules.h"
44 #include "treenodes.h"
45 #include "util.h"
46 #include "fpcreate.h"
47 #include "parser.h"
48
49 #include "sp_asn1.h"
50 #include "sp_byte_check.h"
51 #include "sp_byte_jump.h"
52 #include "sp_byte_extract.h"
53 #include "sp_byte_math.h"
54 #include "sp_clientserver.h"
55 #include "sp_cvs.h"
56 #include "sp_dsize_check.h"
57 #include "sp_flowbits.h"
58 #include "sp_ftpbounce.h"
59 #include "sp_icmp_code_check.h"
60 #include "sp_icmp_id_check.h"
61 #include "sp_icmp_seq_check.h"
62 #include "sp_icmp_type_check.h"
63 #include "sp_ip_fragbits.h"
64 #include "sp_ip_id_check.h"
65 #include "sp_ipoption_check.h"
66 #include "sp_ip_proto.h"
67 #include "sp_ip_same_check.h"
68 #include "sp_ip_tos_check.h"
69 #include "sp_file_data.h"
70 #include "sp_base64_decode.h"
71 #include "sp_isdataat.h"
72 #include "sp_pattern_match.h"
73 #include "sp_pcre.h"
74 #ifdef ENABLE_REACT
75 #include "sp_react.h"
76 #endif
77 #include "sp_replace.h"
78 #ifdef ENABLE_RESPOND
79 #include "sp_respond.h"
80 #endif
81 #include "sp_rpc_check.h"
82 #include "sp_session.h"
83 #include "sp_tcp_ack_check.h"
84 #include "sp_tcp_flag_check.h"
85 #include "sp_tcp_seq_check.h"
86 #include "sp_tcp_win_check.h"
87 #include "sp_ttl_check.h"
88 #include "sp_urilen_check.h"
89 #include "sp_hdr_opt_wrap.h"
90 # include "sp_file_type.h"
91
92 #include "sp_preprocopt.h"
93 #include "sp_dynamic.h"
94
95 #include "fpdetect.h"
96 #include "ppm.h"
97 #include "profiler.h"
98 #include "sfPolicy.h"
99 #include "detection_filter.h"
100 #include "encode.h"
101 #if defined(FEAT_OPEN_APPID)
102 #include "stream_common.h"
103 #include "sp_appid.h"
104 #endif /* defined(FEAT_OPEN_APPID) */
105
106 typedef struct _detection_option_key
107 {
108 option_type_t option_type;
109 void *option_data;
110 } detection_option_key_t;
111
112 #define HASH_RULE_OPTIONS 16384
113 #define HASH_RULE_TREE 8192
114
detection_option_hash_func(SFHASHFCN * p,unsigned char * k,int n)115 uint32_t detection_option_hash_func(SFHASHFCN *p, unsigned char *k, int n)
116 {
117 uint32_t hash = 0;
118 detection_option_key_t *key = (detection_option_key_t*)k;
119
120 switch (key->option_type)
121 {
122 /* Call hash function specific to the key type */
123 case RULE_OPTION_TYPE_ASN1:
124 hash = Asn1Hash(key->option_data);
125 break;
126 case RULE_OPTION_TYPE_BYTE_TEST:
127 hash = ByteTestHash(key->option_data);
128 break;
129 case RULE_OPTION_TYPE_BYTE_JUMP:
130 hash = ByteJumpHash(key->option_data);
131 break;
132 case RULE_OPTION_TYPE_BYTE_EXTRACT:
133 hash = ByteExtractHash(key->option_data);
134 break;
135 case RULE_OPTION_TYPE_BYTE_MATH:
136 hash = ByteMathHash(key->option_data);
137 break;
138 case RULE_OPTION_TYPE_FLOW:
139 hash = FlowHash(key->option_data);
140 break;
141 case RULE_OPTION_TYPE_CVS:
142 hash = CvsHash(key->option_data);
143 break;
144 case RULE_OPTION_TYPE_DSIZE:
145 hash = DSizeCheckHash(key->option_data);
146 break;
147 case RULE_OPTION_TYPE_FLOWBIT:
148 hash = FlowBitsHash(key->option_data);
149 break;
150 case RULE_OPTION_TYPE_FTPBOUNCE:
151 break;
152 case RULE_OPTION_TYPE_FILE_DATA:
153 hash = FileDataHash(key->option_data);
154 break;
155 case RULE_OPTION_TYPE_BASE64_DECODE:
156 hash = Base64DecodeHash(key->option_data);
157 break;
158 case RULE_OPTION_TYPE_BASE64_DATA:
159 break;
160 case RULE_OPTION_TYPE_PKT_DATA:
161 break;
162 case RULE_OPTION_TYPE_ICMP_CODE:
163 hash = IcmpCodeCheckHash(key->option_data);
164 break;
165 case RULE_OPTION_TYPE_ICMP_ID:
166 hash = IcmpIdCheckHash(key->option_data);
167 break;
168 case RULE_OPTION_TYPE_ICMP_SEQ:
169 hash = IcmpSeqCheckHash(key->option_data);
170 break;
171 case RULE_OPTION_TYPE_ICMP_TYPE:
172 hash = IcmpTypeCheckHash(key->option_data);
173 break;
174 case RULE_OPTION_TYPE_IP_FRAGBITS:
175 hash = IpFragBitsCheckHash(key->option_data);
176 break;
177 case RULE_OPTION_TYPE_IP_FRAG_OFFSET:
178 hash = IpFragOffsetCheckHash(key->option_data);
179 break;
180 case RULE_OPTION_TYPE_IP_ID:
181 hash = IpIdCheckHash(key->option_data);
182 break;
183 case RULE_OPTION_TYPE_IP_OPTION:
184 hash = IpOptionCheckHash(key->option_data);
185 break;
186 case RULE_OPTION_TYPE_IP_PROTO:
187 hash = IpProtoCheckHash(key->option_data);
188 break;
189 case RULE_OPTION_TYPE_IP_SAME:
190 hash = IpSameCheckHash(key->option_data);
191 break;
192 case RULE_OPTION_TYPE_IP_TOS:
193 hash = IpTosCheckHash(key->option_data);
194 break;
195 case RULE_OPTION_TYPE_IS_DATA_AT:
196 hash = IsDataAtHash(key->option_data);
197 break;
198 case RULE_OPTION_TYPE_CONTENT:
199 case RULE_OPTION_TYPE_CONTENT_URI:
200 hash = PatternMatchHash(key->option_data);
201 break;
202 case RULE_OPTION_TYPE_PCRE:
203 hash = PcreHash(key->option_data);
204 break;
205 #ifdef ENABLE_REACT
206 case RULE_OPTION_TYPE_REACT:
207 hash = ReactHash(key->option_data);
208 break;
209 #endif
210 #ifdef ENABLE_RESPOND
211 case RULE_OPTION_TYPE_RESPOND:
212 hash = RespondHash(key->option_data);
213 break;
214 #endif
215 case RULE_OPTION_TYPE_RPC_CHECK:
216 hash = RpcCheckHash(key->option_data);
217 break;
218 case RULE_OPTION_TYPE_SESSION:
219 hash = SessionHash(key->option_data);
220 break;
221 case RULE_OPTION_TYPE_TCP_ACK:
222 hash = TcpAckCheckHash(key->option_data);
223 break;
224 case RULE_OPTION_TYPE_TCP_FLAG:
225 hash = TcpFlagCheckHash(key->option_data);
226 break;
227 case RULE_OPTION_TYPE_TCP_SEQ:
228 hash = TcpSeqCheckHash(key->option_data);
229 break;
230 case RULE_OPTION_TYPE_TCP_WIN:
231 hash = TcpWinCheckHash(key->option_data);
232 break;
233 case RULE_OPTION_TYPE_TTL:
234 hash = TtlCheckHash(key->option_data);
235 break;
236 case RULE_OPTION_TYPE_URILEN:
237 hash = UriLenCheckHash(key->option_data);
238 break;
239 case RULE_OPTION_TYPE_HDR_OPT_CHECK:
240 hash = HdrOptCheckHash(key->option_data);
241 break;
242 case RULE_OPTION_TYPE_FILE_TYPE:
243 hash = FileTypeHash(key->option_data);
244 break;
245 case RULE_OPTION_TYPE_PREPROCESSOR:
246 hash = PreprocessorRuleOptionHash(key->option_data);
247 break;
248 case RULE_OPTION_TYPE_DYNAMIC:
249 hash = DynamicRuleHash(key->option_data);
250 break;
251 case RULE_OPTION_TYPE_LEAF_NODE:
252 hash = 0;
253 break;
254 #if defined(FEAT_OPEN_APPID)
255 case RULE_OPTION_TYPE_APPID:
256 hash = optionAppIdHash(key->option_data);
257 break;
258 #endif /* defined(FEAT_OPEN_APPID) */
259 }
260
261 return hash;
262 }
263
detection_option_key_compare_func(const void * k1,const void * k2,size_t n)264 int detection_option_key_compare_func(const void *k1, const void *k2, size_t n)
265 {
266 int ret = DETECTION_OPTION_NOT_EQUAL;
267 const detection_option_key_t *key1 = (detection_option_key_t*)k1;
268 const detection_option_key_t *key2 = (detection_option_key_t*)k2;
269
270 #ifdef KEEP_THEM_ALLOCATED
271 return DETECTION_OPTION_NOT_EQUAL;
272 #endif
273
274 if (!key1 || !key2)
275 return DETECTION_OPTION_NOT_EQUAL;
276
277 if (key1->option_type != key2->option_type)
278 return DETECTION_OPTION_NOT_EQUAL;
279
280 switch (key1->option_type)
281 {
282 /* Call compare function specific to the key type */
283 case RULE_OPTION_TYPE_LEAF_NODE:
284 /* Leaf node always not equal. */
285 break;
286 case RULE_OPTION_TYPE_ASN1:
287 ret = Asn1Compare(key1->option_data, key2->option_data);
288 break;
289 case RULE_OPTION_TYPE_BYTE_TEST:
290 ret = ByteTestCompare(key1->option_data, key2->option_data);
291 break;
292 case RULE_OPTION_TYPE_BYTE_JUMP:
293 ret = ByteJumpCompare(key1->option_data, key2->option_data);
294 break;
295 case RULE_OPTION_TYPE_BYTE_EXTRACT:
296 ret = ByteExtractCompare(key1->option_data, key2->option_data);
297 break;
298 case RULE_OPTION_TYPE_BYTE_MATH:
299 ret = ByteMathCompare(key1->option_data, key2->option_data);
300 break;
301 case RULE_OPTION_TYPE_FLOW:
302 ret = FlowCompare(key1->option_data, key2->option_data);
303 break;
304 case RULE_OPTION_TYPE_CVS:
305 ret = CvsCompare(key1->option_data, key2->option_data);
306 break;
307 case RULE_OPTION_TYPE_DSIZE:
308 ret = DSizeCheckCompare(key1->option_data, key2->option_data);
309 break;
310 case RULE_OPTION_TYPE_FLOWBIT:
311 ret = FlowBitsCompare(key1->option_data, key2->option_data);
312 break;
313 case RULE_OPTION_TYPE_FTPBOUNCE:
314 break;
315 case RULE_OPTION_TYPE_FILE_DATA:
316 ret = FileDataCompare(key1->option_data, key2->option_data);
317 break;
318 case RULE_OPTION_TYPE_BASE64_DECODE:
319 ret = Base64DecodeCompare(key1->option_data, key2->option_data);
320 break;
321 case RULE_OPTION_TYPE_BASE64_DATA:
322 break;
323 case RULE_OPTION_TYPE_PKT_DATA:
324 break;
325 case RULE_OPTION_TYPE_ICMP_CODE:
326 ret = IcmpCodeCheckCompare(key1->option_data, key2->option_data);
327 break;
328 case RULE_OPTION_TYPE_ICMP_ID:
329 ret = IcmpIdCheckCompare(key1->option_data, key2->option_data);
330 break;
331 case RULE_OPTION_TYPE_ICMP_SEQ:
332 ret = IcmpSeqCheckCompare(key1->option_data, key2->option_data);
333 break;
334 case RULE_OPTION_TYPE_ICMP_TYPE:
335 ret = IcmpTypeCheckCompare(key1->option_data, key2->option_data);
336 break;
337 case RULE_OPTION_TYPE_IP_FRAGBITS:
338 ret = IpFragBitsCheckCompare(key1->option_data, key2->option_data);
339 break;
340 case RULE_OPTION_TYPE_IP_FRAG_OFFSET:
341 ret = IpFragOffsetCheckCompare(key1->option_data, key2->option_data);
342 break;
343 case RULE_OPTION_TYPE_IP_ID:
344 ret = IpIdCheckCompare(key1->option_data, key2->option_data);
345 break;
346 case RULE_OPTION_TYPE_IP_OPTION:
347 ret = IpOptionCheckCompare(key1->option_data, key2->option_data);
348 break;
349 case RULE_OPTION_TYPE_IP_PROTO:
350 ret = IpProtoCheckCompare(key1->option_data, key2->option_data);
351 break;
352 case RULE_OPTION_TYPE_IP_SAME:
353 ret = IpSameCheckCompare(key1->option_data, key2->option_data);
354 break;
355 case RULE_OPTION_TYPE_IP_TOS:
356 ret = IpTosCheckCompare(key1->option_data, key2->option_data);
357 break;
358 case RULE_OPTION_TYPE_IS_DATA_AT:
359 ret = IsDataAtCompare(key1->option_data, key2->option_data);
360 break;
361 case RULE_OPTION_TYPE_CONTENT:
362 case RULE_OPTION_TYPE_CONTENT_URI:
363 ret = PatternMatchCompare(key1->option_data, key2->option_data);
364 break;
365 case RULE_OPTION_TYPE_PCRE:
366 ret = PcreCompare(key1->option_data, key2->option_data);
367 break;
368 #ifdef ENABLE_REACT
369 case RULE_OPTION_TYPE_REACT:
370 ret = ReactCompare(key1->option_data, key2->option_data);
371 break;
372 #endif
373 #ifdef ENABLE_RESPOND
374 case RULE_OPTION_TYPE_RESPOND:
375 ret = RespondCompare(key1->option_data, key2->option_data);
376 break;
377 #endif
378 case RULE_OPTION_TYPE_RPC_CHECK:
379 ret = RpcCheckCompare(key1->option_data, key2->option_data);
380 break;
381 case RULE_OPTION_TYPE_SESSION:
382 ret = SessionCompare(key1->option_data, key2->option_data);
383 break;
384 case RULE_OPTION_TYPE_TCP_ACK:
385 ret = TcpAckCheckCompare(key1->option_data, key2->option_data);
386 break;
387 case RULE_OPTION_TYPE_TCP_FLAG:
388 ret = TcpFlagCheckCompare(key1->option_data, key2->option_data);
389 break;
390 case RULE_OPTION_TYPE_TCP_SEQ:
391 ret = TcpSeqCheckCompare(key1->option_data, key2->option_data);
392 break;
393 case RULE_OPTION_TYPE_TCP_WIN:
394 ret = TcpWinCheckCompare(key1->option_data, key2->option_data);
395 break;
396 case RULE_OPTION_TYPE_TTL:
397 ret = TtlCheckCompare(key1->option_data, key2->option_data);
398 break;
399 case RULE_OPTION_TYPE_URILEN:
400 ret = UriLenCheckCompare(key1->option_data, key2->option_data);
401 break;
402 case RULE_OPTION_TYPE_HDR_OPT_CHECK:
403 ret = HdrOptCheckCompare(key1->option_data, key2->option_data);
404 break;
405 case RULE_OPTION_TYPE_FILE_TYPE:
406 ret = FileTypeCompare(key1->option_data, key2->option_data);
407 break;
408 case RULE_OPTION_TYPE_PREPROCESSOR:
409 ret = PreprocessorRuleOptionCompare(key1->option_data, key2->option_data);
410 break;
411 case RULE_OPTION_TYPE_DYNAMIC:
412 ret = DynamicRuleCompare(key1->option_data, key2->option_data);
413 break;
414 #if defined(FEAT_OPEN_APPID)
415 case RULE_OPTION_TYPE_APPID:
416 ret = optionAppIdCompare(key1->option_data, key2->option_data);
417 break;
418 #endif /* defined(FEAT_OPEN_APPID) */
419 }
420
421 return ret;
422 }
423
detection_hash_free_func(void * option_key,void * data)424 int detection_hash_free_func(void *option_key, void *data)
425 {
426 detection_option_key_t *key = (detection_option_key_t*)option_key;
427
428 switch (key->option_type)
429 {
430 /* Call free function specific to the key type */
431 case RULE_OPTION_TYPE_ASN1:
432 free(key->option_data);
433 break;
434 case RULE_OPTION_TYPE_BYTE_TEST:
435 free(key->option_data);
436 break;
437 case RULE_OPTION_TYPE_BYTE_JUMP:
438 free(key->option_data);
439 break;
440 case RULE_OPTION_TYPE_BYTE_EXTRACT:
441 ByteExtractFree(key->option_data);
442 break;
443 case RULE_OPTION_TYPE_BYTE_MATH:
444 ByteMathFree(key->option_data);
445 break;
446 case RULE_OPTION_TYPE_FLOW:
447 free(key->option_data);
448 break;
449 case RULE_OPTION_TYPE_CVS:
450 free(key->option_data);
451 break;
452 case RULE_OPTION_TYPE_DSIZE:
453 free(key->option_data);
454 break;
455 case RULE_OPTION_TYPE_FLOWBIT:
456 FlowBitsFree(key->option_data);
457 break;
458 case RULE_OPTION_TYPE_FTPBOUNCE:
459 /* Data is NULL, nothing to free */
460 break;
461 case RULE_OPTION_TYPE_FILE_DATA:
462 free(key->option_data);
463 break;
464 case RULE_OPTION_TYPE_BASE64_DECODE:
465 free(key->option_data);
466 break;
467 case RULE_OPTION_TYPE_BASE64_DATA:
468 break;
469 case RULE_OPTION_TYPE_PKT_DATA:
470 break;
471 case RULE_OPTION_TYPE_ICMP_CODE:
472 free(key->option_data);
473 break;
474 case RULE_OPTION_TYPE_ICMP_ID:
475 free(key->option_data);
476 break;
477 case RULE_OPTION_TYPE_ICMP_SEQ:
478 free(key->option_data);
479 break;
480 case RULE_OPTION_TYPE_ICMP_TYPE:
481 free(key->option_data);
482 break;
483 case RULE_OPTION_TYPE_IP_FRAGBITS:
484 free(key->option_data);
485 break;
486 case RULE_OPTION_TYPE_IP_FRAG_OFFSET:
487 free(key->option_data);
488 break;
489 case RULE_OPTION_TYPE_IP_ID:
490 free(key->option_data);
491 break;
492 case RULE_OPTION_TYPE_IP_OPTION:
493 free(key->option_data);
494 break;
495 case RULE_OPTION_TYPE_IP_PROTO:
496 free(key->option_data);
497 break;
498 case RULE_OPTION_TYPE_IP_SAME:
499 /* Data is NULL, nothing to free */
500 break;
501 case RULE_OPTION_TYPE_IP_TOS:
502 free(key->option_data);
503 break;
504 case RULE_OPTION_TYPE_IS_DATA_AT:
505 free(key->option_data);
506 break;
507 case RULE_OPTION_TYPE_CONTENT:
508 case RULE_OPTION_TYPE_CONTENT_URI:
509 PatternMatchFree(key->option_data);
510 break;
511 case RULE_OPTION_TYPE_PCRE:
512 PcreFree(key->option_data);
513 break;
514 #ifdef ENABLE_REACT
515 case RULE_OPTION_TYPE_REACT:
516 ReactFree(key->option_data);
517 break;
518 #endif
519 #ifdef ENABLE_RESPOND
520 case RULE_OPTION_TYPE_RESPOND:
521 free(key->option_data);
522 break;
523 #endif
524 case RULE_OPTION_TYPE_RPC_CHECK:
525 free(key->option_data);
526 break;
527 case RULE_OPTION_TYPE_SESSION:
528 free(key->option_data);
529 break;
530 case RULE_OPTION_TYPE_TCP_ACK:
531 free(key->option_data);
532 break;
533 case RULE_OPTION_TYPE_TCP_FLAG:
534 free(key->option_data);
535 break;
536 case RULE_OPTION_TYPE_TCP_SEQ:
537 free(key->option_data);
538 break;
539 case RULE_OPTION_TYPE_TCP_WIN:
540 free(key->option_data);
541 break;
542 case RULE_OPTION_TYPE_TTL:
543 free(key->option_data);
544 break;
545 case RULE_OPTION_TYPE_URILEN:
546 free(key->option_data);
547 break;
548 case RULE_OPTION_TYPE_HDR_OPT_CHECK:
549 break;
550 case RULE_OPTION_TYPE_FILE_TYPE:
551 FileTypeFree(key->option_data);
552 break;
553 case RULE_OPTION_TYPE_PREPROCESSOR:
554 PreprocessorRuleOptionsFreeFunc(key->option_data);
555 break;
556 case RULE_OPTION_TYPE_DYNAMIC:
557 fpDynamicDataFree(key->option_data);
558 break;
559 case RULE_OPTION_TYPE_LEAF_NODE:
560 break;
561 #if defined(FEAT_OPEN_APPID)
562 case RULE_OPTION_TYPE_APPID:
563 optionAppIdFree(key->option_data);
564 break;
565 #endif /* defined(FEAT_OPEN_APPID) */
566 }
567 return 0;
568 }
569
DetectionHashTableNew(void)570 SFXHASH * DetectionHashTableNew(void)
571 {
572 SFXHASH *doht = sfxhash_new(HASH_RULE_OPTIONS,
573 sizeof(detection_option_key_t),
574 0, /* Data size == 0, just store the ptr */
575 0, /* Memcap */
576 0, /* Auto node recovery */
577 NULL, /* Auto free function */
578 detection_hash_free_func, /* User free function */
579 1); /* Recycle nodes */
580
581
582 if (doht == NULL)
583 FatalError("Failed to create rule detection option hash table");
584
585 sfxhash_set_keyops(doht, detection_option_hash_func,
586 detection_option_key_compare_func);
587
588 return doht;
589 }
590
DetectionHashTableFree(SFXHASH * doht)591 void DetectionHashTableFree(SFXHASH *doht)
592 {
593 if (doht != NULL)
594 sfxhash_delete(doht);
595 }
596
add_detection_option(struct _SnortConfig * sc,option_type_t type,void * option_data,void ** existing_data)597 int add_detection_option(struct _SnortConfig *sc, option_type_t type, void *option_data, void **existing_data)
598 {
599 detection_option_key_t key;
600
601 if (sc == NULL)
602 {
603 FatalError("%s(%d) Snort config is NULL.\n",
604 __FILE__, __LINE__);
605 }
606
607 if (sc->detection_option_hash_table == NULL)
608 sc->detection_option_hash_table = DetectionHashTableNew();
609
610 if (!option_data)
611 {
612 /* No option data, no conflict to resolve. */
613 return DETECTION_OPTION_EQUAL;
614 }
615
616 key.option_type = type;
617 key.option_data = option_data;
618
619 *existing_data = sfxhash_find(sc->detection_option_hash_table, &key);
620 if (*existing_data)
621 {
622 return DETECTION_OPTION_EQUAL;
623 }
624
625 sfxhash_add(sc->detection_option_hash_table, &key, option_data);
626 return DETECTION_OPTION_NOT_EQUAL;
627 }
628
detection_option_tree_hash(detection_option_tree_node_t * node)629 uint32_t detection_option_tree_hash(detection_option_tree_node_t *node)
630 {
631 uint32_t a,b,c;
632 int i;
633
634 if (!node)
635 return 0;
636
637 a = b = c = 0;
638
639 for (i=0;i<node->num_children;i++)
640 {
641 #if (defined(__ia64) || defined(__amd64) || defined(_LP64))
642 {
643 /* Cleanup warning because of cast from 64bit ptr to 32bit int
644 * warning on 64bit OSs */
645 uint64_t ptr; /* Addresses are 64bits */
646 ptr = (uint64_t)node->children[i]->option_data;
647 a += (ptr >> 32);
648 b += (ptr & 0xFFFFFFFF);
649 }
650 #else
651 a += (uint32_t)node->children[i]->option_data;
652 b += 0;
653 #endif
654 c += detection_option_tree_hash(node->children[i]);
655 mix(a,b,c);
656 a += node->children[i]->num_children;
657 mix(a,b,c);
658 #if 0
659 a += (uint32_t)node->children[i]->option_data;
660 /* Recurse & hash up this guy's children */
661 b += detection_option_tree_hash(node->children[i]);
662 c += node->children[i]->num_children;
663 mix(a,b,c);
664 #endif
665 }
666
667 final(a,b,c);
668
669 return c;
670 }
671
detection_option_tree_hash_func(SFHASHFCN * p,unsigned char * k,int n)672 uint32_t detection_option_tree_hash_func(SFHASHFCN *p, unsigned char *k, int n)
673 {
674 detection_option_key_t *key = (detection_option_key_t *)k;
675 detection_option_tree_node_t *node;
676
677 if (!key || !key->option_data)
678 return 0;
679
680 node = (detection_option_tree_node_t*)key->option_data;
681
682 return detection_option_tree_hash(node);
683 }
684
detection_option_tree_compare(detection_option_tree_node_t * r,detection_option_tree_node_t * l)685 int detection_option_tree_compare(detection_option_tree_node_t *r, detection_option_tree_node_t *l)
686 {
687 int ret = DETECTION_OPTION_NOT_EQUAL;
688 int i;
689
690 if ((r == NULL) && (l == NULL))
691 return DETECTION_OPTION_EQUAL;
692
693 if ((!r && l) || (r && !l))
694 return DETECTION_OPTION_NOT_EQUAL;
695
696 if (r->option_data != l->option_data)
697 return DETECTION_OPTION_NOT_EQUAL;
698
699 if (r->num_children != l->num_children)
700 return DETECTION_OPTION_NOT_EQUAL;
701
702 for (i=0;i<r->num_children;i++)
703 {
704 /* Recurse & check the children for equality */
705 ret = detection_option_tree_compare(r->children[i], l->children[i]);
706 if (ret != DETECTION_OPTION_EQUAL)
707 return ret;
708 }
709
710 return DETECTION_OPTION_EQUAL;
711 }
712
detection_option_tree_compare_func(const void * k1,const void * k2,size_t n)713 int detection_option_tree_compare_func(const void *k1, const void *k2, size_t n)
714 {
715 detection_option_key_t *key_r = (detection_option_key_t *)k1;
716 detection_option_key_t *key_l = (detection_option_key_t *)k2;
717 detection_option_tree_node_t *r;
718 detection_option_tree_node_t *l;
719
720 if (!key_r || !key_l)
721 return DETECTION_OPTION_NOT_EQUAL;
722
723 r = (detection_option_tree_node_t *)key_r->option_data;
724 l = (detection_option_tree_node_t *)key_l->option_data;
725
726 return detection_option_tree_compare(r, l);
727 }
728
detection_option_tree_free_func(void * option_key,void * data)729 int detection_option_tree_free_func(void *option_key, void *data)
730 {
731 detection_option_tree_node_t *node = (detection_option_tree_node_t *)data;
732 /* In fpcreate.c */
733 free_detection_option_tree(node);
734 return 0;
735 }
736
DetectionTreeHashTableFree(SFXHASH * dtht)737 void DetectionTreeHashTableFree(SFXHASH *dtht)
738 {
739 if (dtht != NULL)
740 sfxhash_delete(dtht);
741 }
742
DetectionTreeHashTableNew(void)743 SFXHASH * DetectionTreeHashTableNew(void)
744 {
745 SFXHASH *dtht = sfxhash_new(HASH_RULE_TREE,
746 sizeof(detection_option_key_t),
747 0, /* Data size == 0, just store the ptr */
748 0, /* Memcap */
749 0, /* Auto node recovery */
750 NULL, /* Auto free function */
751 detection_option_tree_free_func, /* User free function */
752 1); /* Recycle nodes */
753
754
755 if (dtht == NULL)
756 FatalError("Failed to create rule detection option hash table");
757
758 sfxhash_set_keyops(dtht, detection_option_tree_hash_func,
759 detection_option_tree_compare_func);
760
761 return dtht;
762 }
763
764 char *option_type_str[] =
765 {
766 "RULE_OPTION_TYPE_LEAF_NODE",
767 "RULE_OPTION_TYPE_ASN1",
768 "RULE_OPTION_TYPE_BYTE_TEST",
769 "RULE_OPTION_TYPE_BYTE_JUMP",
770 "RULE_OPTION_TYPE_BYTE_EXTRACT",
771 "RULE_OPTION_TYPE_FLOW",
772 "RULE_OPTION_TYPE_CVS",
773 "RULE_OPTION_TYPE_DSIZE",
774 "RULE_OPTION_TYPE_FLOWBIT",
775 "RULE_OPTION_TYPE_FTPBOUNCE",
776 "RULE_OPTION_TYPE_ICMP_CODE",
777 "RULE_OPTION_TYPE_ICMP_ID",
778 "RULE_OPTION_TYPE_ICMP_SEQ",
779 "RULE_OPTION_TYPE_ICMP_TYPE",
780 "RULE_OPTION_TYPE_IP_FRAGBITS",
781 "RULE_OPTION_TYPE_IP_FRAG_OFFSET",
782 "RULE_OPTION_TYPE_IP_ID",
783 "RULE_OPTION_TYPE_IP_OPTION",
784 "RULE_OPTION_TYPE_IP_PROTO",
785 "RULE_OPTION_TYPE_IP_SAME",
786 "RULE_OPTION_TYPE_IP_TOS",
787 "RULE_OPTION_TYPE_IS_DATA_AT",
788 "RULE_OPTION_TYPE_FILE_DATA",
789 "RULE_OPTION_TYPE_FILE_TYPE",
790 "RULE_OPTION_TYPE_BASE64_DECODE",
791 "RULE_OPTION_TYPE_BASE64_DATA",
792 "RULE_OPTION_TYPE_PKT_DATA",
793 "RULE_OPTION_TYPE_CONTENT",
794 "RULE_OPTION_TYPE_CONTENT_URI",
795 "RULE_OPTION_TYPE_PCRE",
796 #ifdef ENABLE_REACT
797 "RULE_OPTION_TYPE_REACT",
798 #endif
799 #ifdef ENABLE_RESPOND
800 "RULE_OPTION_TYPE_RESPOND",
801 #endif
802 "RULE_OPTION_TYPE_RPC_CHECK",
803 "RULE_OPTION_TYPE_SESSION",
804 "RULE_OPTION_TYPE_TCP_ACK",
805 "RULE_OPTION_TYPE_TCP_FLAG",
806 "RULE_OPTION_TYPE_TCP_SEQ",
807 "RULE_OPTION_TYPE_TCP_WIN",
808 "RULE_OPTION_TYPE_TTL",
809 "RULE_OPTION_TYPE_URILEN",
810 "RULE_OPTION_TYPE_HDR_OPT_CHECK",
811 "RULE_OPTION_TYPE_PREPROCESSOR",
812 "RULE_OPTION_TYPE_DYNAMIC"
813 #if defined(FEAT_OPEN_APPID)
814 ,"RULE_OPTION_TYPE_APPID"
815 #endif /* defined(FEAT_OPEN_APPID) */
816 ,"RULE_OPTION_TYPE_BYTE_MATH"
817 };
818
819 #ifdef DEBUG_OPTION_TREE
print_option_tree(detection_option_tree_node_t * node,int level)820 void print_option_tree(detection_option_tree_node_t *node, int level)
821 {
822 int i;
823 unsigned int indent = 12 - (11 - level) + strlen(option_type_str[node->option_type]);
824 unsigned int offset = 0;
825 if (level >= 10)
826 offset++;
827
828 DEBUG_WRAP(
829 DebugMessage(DEBUG_DETECT, "%d%*s%*d 0x%x\n",
830 level, indent - offset, option_type_str[node->option_type],
831 54 - indent, node->num_children,
832 node->option_data);
833 for (i=0;i<node->num_children;i++)
834 print_option_tree(node->children[i], level+1);
835 );
836 }
837 #endif
838
add_detection_option_tree(SnortConfig * sc,detection_option_tree_node_t * option_tree,void ** existing_data)839 int add_detection_option_tree(SnortConfig *sc, detection_option_tree_node_t *option_tree, void **existing_data)
840 {
841 detection_option_key_t key;
842
843 if (sc == NULL)
844 {
845 FatalError("%s(%d) Snort config for parsing is NULL.\n",
846 __FILE__, __LINE__);
847 }
848
849 if (sc->detection_option_tree_hash_table == NULL)
850 sc->detection_option_tree_hash_table = DetectionTreeHashTableNew();
851
852 if (!option_tree)
853 {
854 /* No option data, no conflict to resolve. */
855 return DETECTION_OPTION_EQUAL;
856 }
857
858 key.option_data = (void *)option_tree;
859 key.option_type = RULE_OPTION_TYPE_LEAF_NODE;
860
861 *existing_data = sfxhash_find(sc->detection_option_tree_hash_table, &key);
862 if (*existing_data)
863 {
864 return DETECTION_OPTION_EQUAL;
865 }
866
867 sfxhash_add(sc->detection_option_tree_hash_table, &key, option_tree);
868 return DETECTION_OPTION_NOT_EQUAL;
869 }
870
871
872 uint64_t rule_eval_pkt_count = 0;
873
874 /* Include "detection_leaf_node.c"
875 *
876 * Service matches, toggles 'check_ports' and then evaluation
877 * of the leaf nodes (ie. the rule header stuffs).
878 *
879 * This defines the routine "detection_leaf_node_eval($,$)" which
880 * is called from the switch case RULE_OPTION_TYPE_LEAF_NODE below.
881 */
882 #include "detection_leaf_node.c"
883
detection_option_node_evaluate(detection_option_tree_node_t * node,detection_option_eval_data_t * eval_data)884 int detection_option_node_evaluate(detection_option_tree_node_t *node, detection_option_eval_data_t *eval_data)
885 {
886 int i, result = 0, prior_result = 0;
887 int rval = DETECTION_OPTION_NO_MATCH;
888 const uint8_t *orig_doe_ptr;
889 char tmp_noalert_flag = 0;
890 PatternMatchData dup_content_option_data;
891 PcreData dup_pcre_option_data;
892 const uint8_t *dp = NULL;
893 char continue_loop = 1;
894 char flowbits_setoperation = 0;
895 int loop_count = 0;
896 uint32_t tmp_byte_extract_vars[NUM_BYTE_EXTRACT_VARS];
897 uint16_t save_dflags = 0;
898 uint64_t cur_eval_pkt_count = (rule_eval_pkt_count + (GetRebuiltPktCount()));
899 NODE_PROFILE_VARS;
900
901 if (!node || !eval_data || !eval_data->p || !eval_data->pomd)
902 return 0;
903
904 save_dflags = Get_DetectFlags();
905
906 /* see if evaluated it before ... */
907 if (node->last_check.is_relative == 0)
908 {
909 /* Only matters if not relative... */
910 if ((node->last_check.ts.tv_usec == eval_data->p->pkth->ts.tv_usec) &&
911 (node->last_check.ts.tv_sec == eval_data->p->pkth->ts.tv_sec) &&
912 (node->last_check.packet_number == cur_eval_pkt_count) &&
913 (node->last_check.rebuild_flag == (eval_data->p->packet_flags & PKT_REBUILT_STREAM)) &&
914 (!(eval_data->p->packet_flags & PKT_ALLOW_MULTIPLE_DETECT)))
915 {
916 /* eval'd this rule option before on this packet,
917 * use the cached result. */
918 if ((node->last_check.flowbit_failed == 0) &&
919 !(eval_data->p->packet_flags & PKT_IP_RULE_2ND) &&
920 !(eval_data->p->proto_bits & (PROTO_BIT__TEREDO | PROTO_BIT__GTP )))
921 {
922 return node->last_check.result;
923 }
924 }
925 }
926
927 NODE_PROFILE_START(node);
928
929 node->last_check.ts.tv_sec = eval_data->p->pkth->ts.tv_sec;
930 node->last_check.ts.tv_usec = eval_data->p->pkth->ts.tv_usec;
931 node->last_check.packet_number = cur_eval_pkt_count;
932 node->last_check.rebuild_flag = (eval_data->p->packet_flags & PKT_REBUILT_STREAM);
933 node->last_check.flowbit_failed = 0;
934
935 /* Save some stuff off for repeated pattern tests */
936 orig_doe_ptr = doe_ptr;
937
938 if ((node->option_type == RULE_OPTION_TYPE_CONTENT) ||
939 (node->option_type == RULE_OPTION_TYPE_CONTENT_URI))
940 {
941 PatternMatchDuplicatePmd(node->option_data, &dup_content_option_data);
942
943 if (dup_content_option_data.buffer_func == CHECK_URI_PATTERN_MATCH)
944 {
945 const HttpBuffer* hb = GetHttpBuffer(dup_content_option_data.http_buffer);
946 dp = hb ? hb->buf : NULL; // FIXTHIS set length too
947 }
948 else if (dup_content_option_data.rawbytes == 0)
949 {
950 /* If AltDetect is set by calling the rule options which set it,
951 * we should use the Alt Detect before checking for any other buffers.
952 * Alt Detect will take precedence over the Alt Decode and/or packet data.
953 */
954 if(Is_DetectFlag(FLAG_ALT_DETECT))
955 dp = DetectBuffer.data;
956 else if(Is_DetectFlag(FLAG_ALT_DECODE))
957 dp = (uint8_t *)DecodeBuffer.data;
958 else
959 dp = eval_data->p->data;
960 }
961 else
962 {
963 dp = eval_data->p->data;
964 }
965 }
966 else if (node->option_type == RULE_OPTION_TYPE_PCRE)
967 {
968 unsigned hb_type;
969 PcreDuplicatePcreData(node->option_data, &dup_pcre_option_data);
970 hb_type = dup_pcre_option_data.options & SNORT_PCRE_HTTP_BUFS;
971
972 if ( hb_type )
973 {
974 const HttpBuffer* hb = GetHttpBuffer(hb_type);
975 dp = hb ? hb->buf : NULL; // FIXTHIS set length too
976 }
977 else if (!(dup_pcre_option_data.options & SNORT_PCRE_RAWBYTES))
978 {
979 /* If AltDetect is set by calling the rule options which set it,
980 * we should use the Alt Detect before checking for any other buffers.
981 * Alt Detect will take precedence over the Alt Decode and/or packet data.
982 */
983 if(Is_DetectFlag(FLAG_ALT_DETECT))
984 dp = DetectBuffer.data;
985 else if(Is_DetectFlag(FLAG_ALT_DECODE))
986 dp = (uint8_t *)DecodeBuffer.data;
987 else
988 dp = eval_data->p->data;
989 }
990 else
991 {
992 dp = eval_data->p->data;
993 }
994 }
995
996 /* No, haven't evaluated this one before... Check it. */
997 do
998 {
999 switch (node->option_type)
1000 {
1001 case RULE_OPTION_TYPE_LEAF_NODE:
1002 /* Add the match for this otn to the queue. */
1003 {
1004 int pattern_size = 0;
1005 int eval_rtn_result = 1;
1006 int check_ports = 1;
1007 OptTreeNode *otn = (OptTreeNode*) node->option_data;
1008 PatternMatchData *pmd = (PatternMatchData*) eval_data->pmd;
1009
1010 if (pmd)
1011 pattern_size = pmd->pattern_size;
1012
1013 // See "detection_leaf_node.c" (detection_leaf_node_eval).
1014 #ifdef TARGET_BASED
1015 switch (detection_leaf_node_eval (node, eval_data))
1016 {
1017 case Leaf_Abort:
1018 eval_rtn_result = 0;
1019 break;
1020
1021 case Leaf_SkipPorts:
1022 check_ports = 0;
1023 // fall through
1024
1025 case Leaf_CheckPorts:
1026 NODE_PROFILE_TMPEND(node);
1027 eval_rtn_result = fpEvalRTN (getRuntimeRtnFromOtn (otn), eval_data->p, check_ports);
1028 NODE_PROFILE_TMPSTART(node);
1029 break;
1030 }
1031 #endif
1032
1033 if (eval_rtn_result)
1034 {
1035 if ((!otn->detection_filter) ||
1036 !detection_filter_test(
1037 otn->detection_filter,
1038 GET_SRC_IP(eval_data->p), GET_DST_IP(eval_data->p),
1039 eval_data->p->pkth->ts.tv_sec, eval_data))
1040 {
1041 #ifdef PERF_PROFILING
1042 if (PROFILING_RULES)
1043 otn->matches++;
1044 #endif
1045 if (!eval_data->flowbit_noalert)
1046 {
1047 fpAddMatch(eval_data->pomd, pattern_size, otn);
1048 }
1049 result = rval = DETECTION_OPTION_MATCH;
1050 }
1051 }
1052 }
1053 break;
1054
1055 case RULE_OPTION_TYPE_CONTENT:
1056 if (node->evaluate)
1057 {
1058 /* This will be set in the fast pattern matcher if we found
1059 * a content and the rule option specifies not that
1060 * content. Essentially we've already evaluated this rule
1061 * option via the content option processing since only not
1062 * contents that are not relative in any way will have this
1063 * flag set */
1064 if (dup_content_option_data.exception_flag)
1065 {
1066 if ((dup_content_option_data.last_check.ts.tv_sec == eval_data->p->pkth->ts.tv_sec) &&
1067 (dup_content_option_data.last_check.ts.tv_usec == eval_data->p->pkth->ts.tv_usec) &&
1068 (dup_content_option_data.last_check.packet_number == cur_eval_pkt_count) &&
1069 (dup_content_option_data.last_check.rebuild_flag == (eval_data->p->packet_flags & PKT_REBUILT_STREAM)))
1070 {
1071 rval = DETECTION_OPTION_NO_MATCH;
1072 break;
1073 }
1074 }
1075
1076 rval = node->evaluate(&dup_content_option_data, eval_data->p);
1077 }
1078 break;
1079 case RULE_OPTION_TYPE_CONTENT_URI:
1080 if (node->evaluate)
1081 {
1082 rval = node->evaluate(&dup_content_option_data, eval_data->p);
1083 }
1084 break;
1085 case RULE_OPTION_TYPE_PCRE:
1086 if (node->evaluate)
1087 {
1088 rval = node->evaluate(&dup_pcre_option_data, eval_data->p);
1089 }
1090 break;
1091 case RULE_OPTION_TYPE_PKT_DATA:
1092 case RULE_OPTION_TYPE_FILE_DATA:
1093 case RULE_OPTION_TYPE_BASE64_DATA:
1094 if (node->evaluate)
1095 {
1096 save_dflags = Get_DetectFlags();
1097 rval = node->evaluate(node->option_data, eval_data->p);
1098 }
1099 break;
1100 case RULE_OPTION_TYPE_FLOWBIT:
1101 if (node->evaluate)
1102 {
1103 flowbits_setoperation = FlowBits_SetOperation(node->option_data);
1104 if (!flowbits_setoperation)
1105 {
1106 rval = node->evaluate(node->option_data, eval_data->p);
1107 }
1108 else
1109 {
1110 /* set to match so we don't bail early. */
1111 rval = DETECTION_OPTION_MATCH;
1112 }
1113 }
1114 break;
1115 case RULE_OPTION_TYPE_ASN1:
1116 case RULE_OPTION_TYPE_BYTE_TEST:
1117 case RULE_OPTION_TYPE_BYTE_JUMP:
1118 case RULE_OPTION_TYPE_BYTE_EXTRACT:
1119 case RULE_OPTION_TYPE_BYTE_MATH:
1120 case RULE_OPTION_TYPE_FLOW:
1121 case RULE_OPTION_TYPE_CVS:
1122 case RULE_OPTION_TYPE_DSIZE:
1123 case RULE_OPTION_TYPE_FTPBOUNCE:
1124 case RULE_OPTION_TYPE_BASE64_DECODE:
1125 case RULE_OPTION_TYPE_ICMP_CODE:
1126 case RULE_OPTION_TYPE_ICMP_ID:
1127 case RULE_OPTION_TYPE_ICMP_SEQ:
1128 case RULE_OPTION_TYPE_ICMP_TYPE:
1129 case RULE_OPTION_TYPE_IP_FRAGBITS:
1130 case RULE_OPTION_TYPE_IP_FRAG_OFFSET:
1131 case RULE_OPTION_TYPE_IP_ID:
1132 case RULE_OPTION_TYPE_IP_OPTION:
1133 case RULE_OPTION_TYPE_IP_PROTO:
1134 case RULE_OPTION_TYPE_IP_SAME:
1135 case RULE_OPTION_TYPE_IP_TOS:
1136 case RULE_OPTION_TYPE_IS_DATA_AT:
1137 #ifdef ENABLE_REACT
1138 case RULE_OPTION_TYPE_REACT:
1139 #endif
1140 #ifdef ENABLE_RESPOND
1141 case RULE_OPTION_TYPE_RESPOND:
1142 #endif
1143 case RULE_OPTION_TYPE_RPC_CHECK:
1144 case RULE_OPTION_TYPE_SESSION:
1145 case RULE_OPTION_TYPE_TCP_ACK:
1146 case RULE_OPTION_TYPE_TCP_FLAG:
1147 case RULE_OPTION_TYPE_TCP_SEQ:
1148 case RULE_OPTION_TYPE_TCP_WIN:
1149 case RULE_OPTION_TYPE_TTL:
1150 case RULE_OPTION_TYPE_URILEN:
1151 case RULE_OPTION_TYPE_HDR_OPT_CHECK:
1152 case RULE_OPTION_TYPE_FILE_TYPE:
1153 case RULE_OPTION_TYPE_PREPROCESSOR:
1154 if (node->evaluate)
1155 rval = node->evaluate(node->option_data, eval_data->p);
1156 break;
1157 case RULE_OPTION_TYPE_DYNAMIC:
1158 if (node->evaluate)
1159 rval = node->evaluate(node->option_data, eval_data->p);
1160 break;
1161 #if defined(FEAT_OPEN_APPID)
1162 case RULE_OPTION_TYPE_APPID:
1163 if (node->evaluate)
1164 rval = node->evaluate(node->option_data, eval_data->p);
1165 break;
1166 #endif /* defined(FEAT_OPEN_APPID) */
1167 }
1168
1169 if (rval == DETECTION_OPTION_NO_MATCH)
1170 {
1171 node->last_check.result = result;
1172 NODE_PROFILE_END_NOMATCH(node);
1173 return result;
1174 }
1175 else if (rval == DETECTION_OPTION_FAILED_BIT)
1176 {
1177 eval_data->flowbit_failed = 1;
1178 /* clear the timestamp so failed flowbit gets eval'd again */
1179 node->last_check.flowbit_failed = 1;
1180 node->last_check.result = result;
1181 NODE_PROFILE_END_NOMATCH(node);
1182 return 0;
1183 }
1184 else if (rval == DETECTION_OPTION_NO_ALERT)
1185 {
1186 /* Cache the current flowbit_noalert flag, and set it
1187 * so nodes below this don't alert. */
1188 tmp_noalert_flag = eval_data->flowbit_noalert;
1189 eval_data->flowbit_noalert = 1;
1190 }
1191
1192 /* Back up byte_extract vars so they don't get overwritten between rules */
1193 for (i = 0; i < NUM_BYTE_EXTRACT_VARS; i++)
1194 {
1195 GetByteExtractValue(&(tmp_byte_extract_vars[i]), (int8_t)i);
1196 }
1197
1198 #ifdef PPM_MGR
1199 if( PPM_PKTS_ENABLED() )
1200 {
1201 PPM_GET_TIME();
1202 PPM_PACKET_TEST();
1203 if( PPM_PACKET_ABORT_FLAG() )
1204 {
1205 /* bail if we exceeded time */
1206 if (result == DETECTION_OPTION_NO_MATCH)
1207 {
1208 NODE_PROFILE_END_NOMATCH(node);
1209 }
1210 else
1211 {
1212 NODE_PROFILE_END_MATCH(node);
1213 }
1214 node->last_check.result = result;
1215 Reset_DetectFlags(save_dflags);
1216 return result;
1217 }
1218 }
1219 #endif
1220 /* Don't include children's time in this node */
1221 NODE_PROFILE_TMPEND(node);
1222
1223 /* Passed, check the children. */
1224 if (node->num_children)
1225 {
1226 const uint8_t *tmp_doe_ptr = doe_ptr;
1227 const uint8_t tmp_doe_flags = doe_buf_flags;
1228
1229 for (i=0;i<node->num_children; i++)
1230 {
1231 int j = 0;
1232 detection_option_tree_node_t *child_node = node->children[i];
1233
1234 /* reset the DOE ptr for each child from here */
1235 SetDoePtr(tmp_doe_ptr, tmp_doe_flags);
1236
1237 for (j = 0; j < NUM_BYTE_EXTRACT_VARS; j++)
1238 {
1239 SetByteExtractValue(tmp_byte_extract_vars[j], (int8_t)j);
1240 }
1241
1242 if (loop_count > 0)
1243 {
1244 if (child_node->result == DETECTION_OPTION_NO_MATCH)
1245 {
1246 if (((child_node->option_type == RULE_OPTION_TYPE_CONTENT)
1247 || (child_node->option_type == RULE_OPTION_TYPE_PCRE))
1248 && !child_node->last_check.is_relative)
1249 {
1250 /* If it's a non-relative content or pcre, no reason
1251 * to check again. Only increment result once.
1252 * Should hit this condition on first loop iteration. */
1253 if (loop_count == 1)
1254 result++;
1255 continue;
1256 }
1257 else if ((child_node->option_type == RULE_OPTION_TYPE_CONTENT)
1258 && child_node->last_check.is_relative)
1259 {
1260 PatternMatchData *pmd = (PatternMatchData *)child_node->option_data;
1261
1262 /* Check for an unbounded relative search. If this
1263 * failed before, it's going to fail again so don't
1264 * go down this path again
1265 * Check for protected pattern because in this case
1266 * we had checked for 'n'bytes only where 'n' is the
1267 * length of protected pattern.
1268 * */
1269 if (pmd->within == PMD_WITHIN_UNDEFINED && !pmd->protected_pattern)
1270 {
1271 /* Only increment result once. Should hit this
1272 * condition on first loop iteration. */
1273 if (loop_count == 1)
1274 result++;
1275 continue;
1276 }
1277 }
1278 }
1279 else if (child_node->option_type == RULE_OPTION_TYPE_LEAF_NODE)
1280 {
1281 /* Leaf node matched, don't eval again */
1282 continue;
1283 }
1284 else if (child_node->result == child_node->num_children)
1285 {
1286 /* This branch of the tree matched or has options that
1287 * don't need to be evaluated again, so don't need to
1288 * evaluate this option again */
1289 continue;
1290 }
1291 }
1292
1293 child_node->result = detection_option_node_evaluate(node->children[i], eval_data);
1294 if (child_node->option_type == RULE_OPTION_TYPE_LEAF_NODE)
1295 {
1296 /* Leaf node won't have any children but will return success
1297 * or failure; regardless we must count them here */
1298 result += 1;
1299 }
1300 else if (child_node->result == child_node->num_children)
1301 {
1302 /* Indicate that the child's tree branches are done */
1303 result++;
1304 }
1305 #ifdef PPM_MGR
1306 if( PPM_PKTS_ENABLED() )
1307 {
1308 PPM_GET_TIME();
1309 PPM_PACKET_TEST();
1310 if( PPM_PACKET_ABORT_FLAG() )
1311 {
1312 /* bail if we exceeded time */
1313 node->last_check.result = result;
1314 Reset_DetectFlags(save_dflags);
1315 return result;
1316 }
1317 }
1318 #endif
1319 }
1320
1321 /* If all children branches matched, we don't need to reeval any of
1322 * the children so don't need to reeval this content/pcre rule
1323 * option at a new offset.
1324 * Else, reset the DOE ptr to last eval for offset/depth,
1325 * distance/within adjustments for this same content/pcre
1326 * rule option */
1327 if (result == node->num_children)
1328 continue_loop = 0;
1329 else
1330 SetDoePtr(tmp_doe_ptr, tmp_doe_flags);
1331
1332 /* Don't need to reset since it's only checked after we've gone
1333 * through the loop at least once and the result will have
1334 * been set again already */
1335 //for (i = 0; i < node->num_children; i++)
1336 // node->children[i]->result;
1337 }
1338
1339 if (result - prior_result > 0
1340 && node->option_type == RULE_OPTION_TYPE_CONTENT
1341 && Replace_OffsetStored(&dup_content_option_data) && ScIpsInlineMode())
1342 {
1343 if(!ScDisableReplaceOpt())
1344 {
1345 Replace_QueueChange(&dup_content_option_data);
1346 prior_result = result;
1347 }
1348 }
1349
1350 NODE_PROFILE_TMPSTART(node);
1351
1352 if (rval == DETECTION_OPTION_NO_ALERT)
1353 {
1354 /* Reset the flowbit_noalert flag in eval data */
1355 eval_data->flowbit_noalert = tmp_noalert_flag;
1356 }
1357
1358 if (continue_loop && (rval == DETECTION_OPTION_MATCH) && (node->relative_children))
1359 {
1360 if ((node->option_type == RULE_OPTION_TYPE_CONTENT) ||
1361 (node->option_type == RULE_OPTION_TYPE_CONTENT_URI))
1362 {
1363 if (dup_content_option_data.exception_flag)
1364 {
1365 continue_loop = 0;
1366 }
1367 else
1368 {
1369 const uint8_t *orig_ptr;
1370
1371 if (dup_content_option_data.use_doe)
1372 orig_ptr = (orig_doe_ptr == NULL) ? dp : orig_doe_ptr;
1373 else
1374 orig_ptr = dp;
1375
1376 continue_loop = PatternMatchAdjustRelativeOffsets((PatternMatchData *)node->option_data,
1377 &dup_content_option_data, doe_ptr, orig_ptr);
1378 }
1379 }
1380 else if (node->option_type == RULE_OPTION_TYPE_PCRE)
1381 {
1382 if (dup_pcre_option_data.options & SNORT_PCRE_INVERT)
1383 {
1384 continue_loop = 0;
1385 }
1386 else
1387 {
1388 const uint8_t *orig_ptr;
1389
1390 if (dup_pcre_option_data.options & SNORT_PCRE_RELATIVE)
1391 orig_ptr = (orig_doe_ptr == NULL) ? dp : orig_doe_ptr;
1392 else
1393 orig_ptr = dp;
1394
1395 continue_loop = PcreAdjustRelativeOffsets(&dup_pcre_option_data, doe_ptr - orig_ptr);
1396 }
1397 }
1398 else
1399 {
1400 continue_loop = 0;
1401 }
1402 }
1403 else
1404 {
1405 continue_loop = 0;
1406 }
1407
1408 #ifdef PERF_PROFILING
1409 /* We're essentially checking this node again and it potentially
1410 * might match again */
1411 if (continue_loop && PROFILING_RULES)
1412 node->checks++;
1413 #endif
1414
1415 loop_count++;
1416
1417 if (continue_loop)
1418 UpdateDoePtr(orig_doe_ptr, 0);
1419
1420 } while (continue_loop);
1421
1422 if (flowbits_setoperation && (result == DETECTION_OPTION_MATCH))
1423 {
1424 /* Do any setting/clearing/resetting/toggling of flowbits here
1425 * given that other rule options matched. */
1426 rval = node->evaluate(node->option_data, eval_data->p);
1427 if (rval != DETECTION_OPTION_MATCH)
1428 {
1429 result = rval;
1430 }
1431 }
1432
1433 if (eval_data->flowbit_failed)
1434 {
1435 /* something deeper in the tree failed a flowbit test, we may need to
1436 * reeval this node. */
1437 node->last_check.flowbit_failed = 1;
1438 }
1439 node->last_check.result = result;
1440
1441 if (result == DETECTION_OPTION_NO_MATCH)
1442 {
1443 NODE_PROFILE_END_NOMATCH(node);
1444 }
1445 else
1446 {
1447 NODE_PROFILE_END_MATCH(node);
1448 }
1449
1450 Reset_DetectFlags(save_dflags);
1451 return result;
1452 }
1453
1454 #ifdef PERF_PROFILING
1455 typedef struct node_profile_stats
1456 {
1457 uint64_t ticks;
1458 uint64_t ticks_match;
1459 uint64_t ticks_no_match;
1460 uint64_t checks;
1461 uint64_t disables;
1462 } node_profile_stats_t;
1463
detection_option_node_update_otn_stats(detection_option_tree_node_t * node,node_profile_stats_t * stats,uint64_t checks,uint64_t disables)1464 static void detection_option_node_update_otn_stats(detection_option_tree_node_t *node,
1465 node_profile_stats_t *stats, uint64_t checks
1466 #ifdef PPM_MGR
1467 , uint64_t disables
1468 #endif
1469 )
1470 {
1471 int i;
1472 node_profile_stats_t local_stats; /* cumulative stats for this node */
1473
1474 if (stats)
1475 {
1476 local_stats.ticks = stats->ticks + node->ticks;
1477 local_stats.ticks_match = stats->ticks_match + node->ticks_match;
1478 local_stats.ticks_no_match = stats->ticks_no_match + node->ticks_no_match;
1479 if (node->checks > stats->checks)
1480 local_stats.checks = node->checks;
1481 else
1482 local_stats.checks = stats->checks;
1483 #ifdef PPM_MGR
1484 local_stats.disables = disables;
1485 #endif
1486 }
1487 else
1488 {
1489 local_stats.ticks = node->ticks;
1490 local_stats.ticks_match = node->ticks_match;
1491 local_stats.ticks_no_match = node->ticks_no_match;
1492 local_stats.checks = node->checks;
1493 #ifdef PPM_MGR
1494 local_stats.disables = disables;
1495 #endif
1496 }
1497
1498 if (node->option_type == RULE_OPTION_TYPE_LEAF_NODE)
1499 {
1500 OptTreeNode *otn = (OptTreeNode *)node->option_data;
1501 /* Update stats for this otn */
1502 otn->ticks += local_stats.ticks;
1503 otn->ticks_match += local_stats.ticks_match;
1504 otn->ticks_no_match += local_stats.ticks_no_match;
1505 if (local_stats.checks > otn->checks)
1506 otn->checks = local_stats.checks;
1507 #ifdef PPM_MGR
1508 otn->ppm_disable_cnt += local_stats.disables;
1509 #endif
1510 }
1511
1512 if (node->num_children)
1513 {
1514 for (i=0;i<node->num_children; i++)
1515 {
1516 detection_option_node_update_otn_stats(node->children[i], &local_stats, checks
1517 #ifdef PPM_MGR
1518 , disables
1519 #endif
1520 );
1521 }
1522 }
1523 }
1524
detection_option_tree_update_otn_stats(SFXHASH * doth)1525 void detection_option_tree_update_otn_stats(SFXHASH *doth)
1526 {
1527 SFXHASH_NODE *hashnode;
1528
1529 if (doth == NULL)
1530 return;
1531
1532 /* Find the first tree root in the table */
1533 hashnode = sfxhash_findfirst(doth);
1534 while (hashnode)
1535 {
1536 detection_option_tree_node_t *node = hashnode->data;
1537 if (node->checks)
1538 {
1539 detection_option_node_update_otn_stats(node, NULL, node->checks
1540 #ifdef PPM_MGR
1541 , node->ppm_disable_cnt
1542 #endif
1543 );
1544 }
1545 hashnode = sfxhash_findnext(doth);
1546 }
1547 }
1548 #endif
1549