Branch data Line data Source code
1 : : // $Id: RuleMatcher.cc 6724 2009-06-07 09:23:03Z vern $
2 : :
3 : : #include "config.h"
4 : :
5 : : #include "Analyzer.h"
6 : : #include "RuleMatcher.h"
7 : : #include "DFA.h"
8 : : #include "NetVar.h"
9 : : #include "Scope.h"
10 : : #include "File.h"
11 : :
12 : : // FIXME: Things that are not fully implemented/working yet:
13 : : //
14 : : // - "ip-options" always evaluates to false
15 : : // - offsets for payload patterns are ignored
16 : : // (but simulated by snort2bro by leading dots)
17 : : // - if a rule contains "PayloadSize" and application
18 : : // specific patterns (like HTTP), but no "payload" patterns,
19 : : // it may fail to match. Work-around: Insert an always
20 : : // matching "payload" pattern (not done in snort2bro yet)
21 : : // - tcp-state always evaluates to true
22 : : // (implemented but deactivated for comparision to Snort)
23 : :
24 : : uint32 RuleHdrTest::idcounter = 0;
25 : :
26 : : RuleHdrTest::RuleHdrTest(Prot arg_prot, uint32 arg_offset, uint32 arg_size,
27 [ + + ][ # # ]: 198 : Comp arg_comp, maskedvalue_list* arg_vals)
[ # # ][ # # ]
[ # # ][ # # ]
28 : : {
29 : 22 : prot = arg_prot;
30 : 22 : offset = arg_offset;
31 : 22 : size = arg_size;
32 : 22 : comp = arg_comp;
33 : 22 : vals = arg_vals;
34 : 22 : sibling = 0;
35 : 22 : child = 0;
36 : 22 : pattern_rules = 0;
37 : 22 : pure_rules = 0;
38 : 22 : ruleset = new IntSet;
39 : 22 : id = ++idcounter;
40 : 22 : level = 0;
41 [ # # ][ # # ]: 22 : }
[ # # ][ # # ]
42 : :
43 : : Val* RuleMatcher::BuildRuleStateValue(const Rule* rule,
44 : 0 : const RuleEndpointState* state) const
45 : : {
46 : 0 : RecordVal* val = new RecordVal(signature_state);
47 : 0 : val->Assign(0, new StringVal(rule->ID()));
48 : 0 : val->Assign(1, state->GetAnalyzer()->BuildConnVal());
49 : 0 : val->Assign(2, new Val(state->is_orig, TYPE_BOOL));
50 : 0 : val->Assign(3, new Val(state->payload_size, TYPE_COUNT));
51 : 0 : return val;
52 : : }
53 : :
54 [ # # ][ # # ]: 0 : RuleHdrTest::RuleHdrTest(RuleHdrTest& h)
[ # # ][ # # ]
[ # # ][ # # ]
55 : : {
56 : 0 : prot = h.prot;
57 : 0 : offset = h.offset;
58 : 0 : size = h.size;
59 : 0 : comp = h.comp;
60 : :
61 : 0 : vals = new maskedvalue_list;
62 [ # # ][ # # ]: 0 : loop_over_list(*h.vals, i)
63 : 0 : vals->append(new MaskedValue(*(*h.vals)[i]));
64 : :
65 [ # # ][ # # ]: 0 : for ( int j = 0; j < Rule::TYPES; ++j )
66 : : {
67 [ # # ][ # # ]: 0 : loop_over_list(h.psets[j], k)
68 : : {
69 : 0 : PatternSet* orig_set = h.psets[j][k];
70 : 0 : PatternSet* copied_set = new PatternSet;
71 : 0 : copied_set->re = 0;
72 : 0 : copied_set->ids = orig_set->ids;
73 [ # # ][ # # ]: 0 : loop_over_list(orig_set->patterns, l)
74 : 0 : copied_set->patterns.append(copy_string(orig_set->patterns[l]));
75 : : }
76 : : }
77 : :
78 : 0 : sibling = 0;
79 : 0 : child = 0;
80 : 0 : pattern_rules = 0;
81 : 0 : pure_rules = 0;
82 : 0 : ruleset = new IntSet;
83 : 0 : id = ++idcounter;
84 : 0 : level = 0;
85 [ # # ][ # # ]: 0 : }
[ # # ][ # # ]
86 : :
87 : 0 : RuleHdrTest::~RuleHdrTest()
88 : : {
89 [ # # ][ # # ]: 0 : loop_over_list(*vals, i)
90 : 0 : delete (*vals)[i];
91 [ # # ][ # # ]: 0 : delete vals;
92 : :
93 [ # # ][ # # ]: 0 : for ( int i = 0; i < Rule::TYPES; ++i )
94 : : {
95 [ # # ][ # # ]: 0 : loop_over_list(psets[i], j)
96 [ # # ][ # # ]: 0 : delete psets[i][j]->re;
97 : : }
98 : :
99 [ # # ][ # # ]: 0 : delete ruleset;
100 [ # # ][ # # ]: 0 : }
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
101 : :
102 : 0 : bool RuleHdrTest::operator==(const RuleHdrTest& h)
103 : : {
104 [ # # ][ # # ]: 0 : if ( prot != h.prot || offset != h.offset || size != h.size ||
[ # # ][ # # ]
[ # # ][ # # ]
105 : : comp != h.comp || vals->length() != h.vals->length() )
106 : 0 : return false;
107 : :
108 [ # # ]: 0 : loop_over_list(*vals, i)
109 [ # # ][ # # ]: 0 : if ( (*vals)[i]->val != (*h.vals)[i]->val ||
[ # # ]
110 : : (*vals)[i]->mask != (*h.vals)[i]->mask )
111 : 0 : return false;
112 : :
113 : 0 : return true;
114 : : }
115 : :
116 : 0 : void RuleHdrTest::PrintDebug()
117 : : {
118 : : static const char* str_comp[] = { "<=", ">=", "<", ">", "==", "!=" };
119 : : static const char* str_prot[] = { "", "ip", "icmp", "tcp", "udp" };
120 : :
121 : : fprintf(stderr, " RuleHdrTest %s[%d:%d] %s",
122 : 0 : str_prot[prot], offset, size, str_comp[comp]);
123 : :
124 [ # # ]: 0 : loop_over_list(*vals, i)
125 : : fprintf(stderr, " 0x%08x/0x%08x",
126 : 0 : (*vals)[i]->val, (*vals)[i]->mask);
127 : :
128 : 0 : fprintf(stderr, "\n");
129 : 0 : }
130 : :
131 : : RuleEndpointState::RuleEndpointState(Analyzer* arg_analyzer, bool arg_is_orig,
132 : : RuleEndpointState* arg_opposite,
133 : 0 : ::PIA* arg_PIA)
134 : : {
135 : 0 : payload_size = -1;
136 : 0 : analyzer = arg_analyzer;
137 : 0 : is_orig = arg_is_orig;
138 : :
139 : 0 : opposite = arg_opposite;
140 [ # # # # ]: 0 : if ( opposite )
141 : 0 : opposite->opposite = this;
142 : :
143 : 0 : pia = arg_PIA;
144 : 0 : }
145 : :
146 : 0 : RuleEndpointState::~RuleEndpointState()
147 : : {
148 [ # # ][ # # ]: 0 : loop_over_list(matchers, i)
149 : : {
150 [ # # ][ # # ]: 0 : delete matchers[i]->state;
151 : 0 : delete matchers[i];
152 : : }
153 : :
154 [ # # ][ # # ]: 0 : loop_over_list(matched_text, j)
155 [ # # ][ # # ]: 0 : delete matched_text[j];
156 : 0 : }
157 : :
158 : 1 : RuleMatcher::RuleMatcher(int arg_RE_level)
159 : : {
160 : : root = new RuleHdrTest(RuleHdrTest::NOPROT, 0, 0, RuleHdrTest::EQ,
161 : 1 : new maskedvalue_list);
162 : 1 : RE_level = arg_RE_level;
163 : 1 : }
164 : :
165 : 0 : RuleMatcher::~RuleMatcher()
166 : : {
167 : : #ifdef MATCHER_PRINT_STATS
168 : : DumpStats(stderr);
169 : : #endif
170 : 0 : Delete(root);
171 : :
172 [ # # ][ # # ]: 0 : loop_over_list(rules, i)
173 [ # # ][ # # ]: 0 : delete rules[i];
174 : 0 : }
175 : :
176 : 0 : void RuleMatcher::Delete(RuleHdrTest* node)
177 : : {
178 : : RuleHdrTest* next;
179 [ # # ]: 0 : for ( RuleHdrTest* h = node->child; h; h = next )
180 : : {
181 : 0 : next = h->sibling;
182 : 0 : Delete(h);
183 : : }
184 : :
185 [ # # ]: 0 : delete node;
186 : 0 : }
187 : :
188 : 1 : bool RuleMatcher::ReadFiles(const name_list& files)
189 : : {
190 : : #ifdef USE_PERFTOOLS
191 : : HeapLeakChecker::Disabler disabler;
192 : : #endif
193 : :
194 : 1 : parse_error = false;
195 : :
196 [ + - ]: 2 : for ( int i = 0; i < files.length(); ++i )
197 : : {
198 : 2 : rules_in = search_for_file( files[i], "sig", 0);
199 [ + + ]: 2 : if ( ! rules_in )
200 : : {
201 : 1 : error("Can't open signature file", files[i]);
202 : 1 : return false;
203 : : }
204 : :
205 : 1 : rules_line_number = 0;
206 : 1 : current_rule_file = files[i];
207 : 1 : rules_parse();
208 : : }
209 : :
210 [ # # ]: 0 : if ( parse_error )
211 : 0 : return false;
212 : :
213 : 0 : BuildRulesTree();
214 : :
215 [ # # ][ # # ]: 0 : string_list exprs[Rule::TYPES];
[ # # ]
216 [ # # ][ # # ]: 0 : int_list ids[Rule::TYPES];
[ # # ]
217 : 0 : BuildRegEx(root, exprs, ids);
218 : :
219 [ # # ][ # # ]: 1 : return ! parse_error;
[ # # ][ # # ]
220 : : }
221 : :
222 : 21 : void RuleMatcher::AddRule(Rule* rule)
223 : : {
224 [ - + ]: 21 : if ( rules_by_id.Lookup(rule->ID()) )
225 : : {
226 : 0 : rules_error("rule defined twice");
227 : 0 : return;
228 : : }
229 : :
230 : 21 : rules.append(rule);
231 : 21 : rules_by_id.Insert(rule->ID(), rule);
232 : : }
233 : :
234 : 0 : void RuleMatcher::BuildRulesTree()
235 : : {
236 [ # # ]: 0 : loop_over_list(rules, r)
237 : : {
238 [ # # ]: 0 : if ( ! rules[r]->Active() )
239 : 0 : continue;
240 : :
241 : 0 : rules[r]->SortHdrTests();
242 : 0 : InsertRuleIntoTree(rules[r], 0, root, 0);
243 : : }
244 : 0 : }
245 : :
246 : : void RuleMatcher::InsertRuleIntoTree(Rule* r, int testnr,
247 : 0 : RuleHdrTest* dest, int level)
248 : : {
249 : : // Initiliaze the preconditions
250 [ # # ]: 0 : loop_over_list(r->preconds, i)
251 : : {
252 : 0 : Rule::Precond* pc = r->preconds[i];
253 : :
254 : 0 : Rule* pc_rule = rules_by_id.Lookup(pc->id);
255 [ # # ]: 0 : if ( ! pc_rule )
256 : : {
257 : 0 : rules_error(r, "unknown rule referenced");
258 : 0 : return;
259 : : }
260 : :
261 : 0 : pc->rule = pc_rule;
262 : 0 : pc_rule->dependents.append(r);
263 : : }
264 : :
265 : : // All tests in tree already?
266 [ # # ]: 0 : if ( testnr >= r->hdr_tests.length() )
267 : : { // then insert it into the right list of the test
268 [ # # ]: 0 : if ( r->patterns.length() )
269 : : {
270 : 0 : r->next = dest->pattern_rules;
271 : 0 : dest->pattern_rules = r;
272 : : }
273 : : else
274 : : {
275 : 0 : r->next = dest->pure_rules;
276 : 0 : dest->pure_rules = r;
277 : : }
278 : :
279 : 0 : dest->ruleset->Insert(r->Index());
280 : 0 : return;
281 : : }
282 : :
283 : : // Look for matching child.
284 [ # # ]: 0 : for ( RuleHdrTest* h = dest->child; h; h = h->sibling )
285 [ # # ]: 0 : if ( *h == *r->hdr_tests[testnr] )
286 : : {
287 : 0 : InsertRuleIntoTree(r, testnr + 1, h, level + 1);
288 : 0 : return;
289 : : }
290 : :
291 : : // Insert new child.
292 : 0 : RuleHdrTest* newtest = new RuleHdrTest(*r->hdr_tests[testnr]);
293 : 0 : newtest->sibling = dest->child;
294 : 0 : newtest->level = level + 1;
295 : 0 : dest->child = newtest;
296 : :
297 : 0 : InsertRuleIntoTree(r, testnr + 1, newtest, level + 1);
298 : : }
299 : :
300 : : void RuleMatcher::BuildRegEx(RuleHdrTest* hdr_test, string_list* exprs,
301 : 0 : int_list* ids)
302 : : {
303 : : // For each type, get all patterns on this node.
304 [ # # ]: 0 : for ( Rule* r = hdr_test->pattern_rules; r; r = r->next )
305 : : {
306 [ # # ]: 0 : loop_over_list(r->patterns, j)
307 : : {
308 : 0 : Rule::Pattern* p = r->patterns[j];
309 : 0 : exprs[p->type].append(p->pattern);
310 : 0 : ids[p->type].append(p->id);
311 : : }
312 : : }
313 : :
314 : : // If we're above the RE_level, these patterns will form the regexprs.
315 [ # # ]: 0 : if ( hdr_test->level < RE_level )
316 : : {
317 [ # # ]: 0 : for ( int i = 0; i < Rule::TYPES; ++i )
318 [ # # ]: 0 : if ( exprs[i].length() )
319 : 0 : BuildPatternSets(&hdr_test->psets[i], exprs[i], ids[i]);
320 : : }
321 : :
322 : : // Get the patterns on all of our children.
323 [ # # ][ # # ]: 0 : for ( RuleHdrTest* h = hdr_test->child; h; h = h->sibling )
[ # # ][ # # ]
[ # # ]
324 : : {
325 [ # # ][ # # ]: 0 : string_list child_exprs[Rule::TYPES];
[ # # ]
326 [ # # ][ # # ]: 0 : int_list child_ids[Rule::TYPES];
[ # # ]
327 : :
328 : 0 : BuildRegEx(h, child_exprs, child_ids);
329 : :
330 [ # # ]: 0 : for ( int i = 0; i < Rule::TYPES; ++i )
331 : : {
332 [ # # ]: 0 : loop_over_list(child_exprs[i], j)
333 : : {
334 : 0 : exprs[i].append(child_exprs[i][j]);
335 : 0 : ids[i].append(child_ids[i][j]);
336 : : }
337 : : }
338 : : }
339 : :
340 : : // If we're on the RE_level, all patterns gathered now
341 : : // form the regexprs.
342 [ # # ]: 0 : if ( hdr_test->level == RE_level )
343 : : {
344 [ # # ]: 0 : for ( int i = 0; i < Rule::TYPES; ++i )
345 [ # # ]: 0 : if ( exprs[i].length() )
346 : 0 : BuildPatternSets(&hdr_test->psets[i], exprs[i], ids[i]);
347 : : }
348 : :
349 : : // If we're below the RE_level, the regexprs remains empty.
350 : 0 : }
351 : :
352 : : void RuleMatcher::BuildPatternSets(RuleHdrTest::pattern_set_list* dst,
353 : 0 : const string_list& exprs, const int_list& ids)
354 : : {
355 [ # # ]: 0 : assert(exprs.length() == ids.length());
356 : :
357 : : // We build groups of at most sig_max_group_size regexps.
358 : :
359 : 0 : string_list group_exprs;
360 : 0 : int_list group_ids;
361 : :
362 [ # # ]: 0 : for ( int i = 0; i < exprs.length() + 1 /* sic! */; i++ )
363 : : {
364 [ # # ]: 0 : if ( i < exprs.length() )
365 : : {
366 : 0 : group_exprs.append(exprs[i]);
367 : 0 : group_ids.append(ids[i]);
368 : : }
369 : :
370 [ # # ][ # # ]: 0 : if ( group_exprs.length() > sig_max_group_size ||
[ # # ]
371 : : i == exprs.length() )
372 : : {
373 : : RuleHdrTest::PatternSet* set =
374 : 0 : new RuleHdrTest::PatternSet;
375 : 0 : set->re = new Specific_RE_Matcher(MATCH_EXACTLY, 1);
376 : 0 : set->re->CompileSet(group_exprs, group_ids);
377 : 0 : set->patterns = group_exprs;
378 : 0 : set->ids = group_ids;
379 : 0 : dst->append(set);
380 : :
381 : 0 : group_exprs.clear();
382 : 0 : group_ids.clear();
383 : : }
384 : 0 : }
385 : 0 : }
386 : :
387 : : // Get a 8/16/32-bit value from the given position in the packet header
388 : 0 : static inline uint32 getval(const u_char* data, int size)
389 : : {
390 [ # # # # ]: 0 : switch ( size ) {
391 : : case 1:
392 : 0 : return *(uint8*) data;
393 : :
394 : : case 2:
395 : 0 : return ntohs(*(uint16*) data);
396 : :
397 : : case 4:
398 : 0 : return ntohl(*(uint32*) data);
399 : :
400 : : default:
401 : 0 : internal_error("illegal HdrTest size");
402 : : }
403 : :
404 : : // Should not be reached.
405 : : return 0;
406 : : }
407 : :
408 : :
409 : : // A line which can be inserted into the macros below for debugging
410 : : // fprintf(stderr, "%.06f %08x & %08x %s %08x\n", network_time, v, (mvals)[i]->mask, #op, (mvals)[i]->val);
411 : :
412 : : // Evaluate a value list (matches if at least one value matches).
413 : : #define DO_MATCH_OR( mvals, v, op ) \
414 : : { \
415 : : loop_over_list((mvals), i) \
416 : : { \
417 : : if ( ((v) & (mvals)[i]->mask) op (mvals)[i]->val ) \
418 : : goto match; \
419 : : } \
420 : : goto no_match; \
421 : : }
422 : :
423 : : // Evaluate a value list (doesn't match if any value matches).
424 : : #define DO_MATCH_NOT_AND( mvals, v, op ) \
425 : : { \
426 : : loop_over_list((mvals), i) \
427 : : { \
428 : : if ( ((v) & (mvals)[i]->mask) op (mvals)[i]->val ) \
429 : : goto no_match; \
430 : : } \
431 : : goto match; \
432 : : }
433 : :
434 : : RuleEndpointState* RuleMatcher::InitEndpoint(Analyzer* analyzer,
435 : : const IP_Hdr* ip, int caplen,
436 : : RuleEndpointState* opposite,
437 : 0 : bool from_orig, PIA* pia)
438 : : {
439 : : RuleEndpointState* state =
440 : 0 : new RuleEndpointState(analyzer, from_orig, opposite, pia);
441 : :
442 [ # # ]: 0 : if ( rule_bench == 3 )
443 : 0 : return state;
444 : :
445 : 0 : rule_hdr_test_list tests;
446 : 0 : tests.append(root);
447 : :
448 [ # # ]: 0 : loop_over_list(tests, h)
449 : : {
450 : 0 : RuleHdrTest* hdr_test = tests[h];
451 : :
452 [ # # ][ # # ]: 0 : DBG_LOG(DBG_RULES, "HdrTest %d matches (%s%s)", hdr_test->id,
453 : : hdr_test->pattern_rules ? "+" : "-",
454 : : hdr_test->pure_rules ? "+" : "-");
455 : :
456 : : // Current HdrTest node matches the packet, so remember it
457 : : // if we have any rules on it.
458 [ # # # # ]: 0 : if ( hdr_test->pattern_rules || hdr_test->pure_rules )
459 : 0 : state->hdr_tests.append(hdr_test);
460 : :
461 : : // Evaluate all rules on this node which don't contain
462 : : // any patterns.
463 [ # # ]: 0 : for ( Rule* r = hdr_test->pure_rules; r; r = r->next )
464 [ # # ]: 0 : if ( EvalRuleConditions(r, state, 0, 0, 0) )
465 : 0 : ExecRuleActions(r, state, 0, 0, 0);
466 : :
467 : : // If we're on or above the RE_level, we may have some
468 : : // pattern matching to do.
469 [ # # ]: 0 : if ( hdr_test->level <= RE_level )
470 : : {
471 [ # # ]: 0 : for ( int i = 0; i < Rule::TYPES; ++i )
472 : : {
473 [ # # ]: 0 : loop_over_list(hdr_test->psets[i], j)
474 : : {
475 : : RuleHdrTest::PatternSet* set =
476 : 0 : hdr_test->psets[i][j];
477 : :
478 [ # # ]: 0 : assert(set->re);
479 : :
480 : : RuleEndpointState::Matcher* m =
481 : 0 : new RuleEndpointState::Matcher;
482 : 0 : m->state = new RE_Match_State(set->re);
483 : 0 : m->type = (Rule::PatternType) i;
484 : 0 : state->matchers.append(m);
485 : : }
486 : : }
487 : : }
488 : :
489 [ # # ]: 0 : if ( ip )
490 : : {
491 : : // Get start of transport layer.
492 : 0 : const u_char* transport = ip->Payload();
493 : :
494 : : // Descend the RuleHdrTest tree further.
495 [ # # ]: 0 : for ( RuleHdrTest* h = hdr_test->child; h;
496 : : h = h->sibling )
497 : : {
498 : : const u_char* data;
499 : :
500 : : // Evaluate the header test.
501 [ # # # ]: 0 : switch ( h->prot ) {
502 : : case RuleHdrTest::IP:
503 : 0 : data = (const u_char*) ip->IP4_Hdr();
504 : 0 : break;
505 : :
506 : : case RuleHdrTest::ICMP:
507 : : case RuleHdrTest::TCP:
508 : : case RuleHdrTest::UDP:
509 : 0 : data = transport;
510 : 0 : break;
511 : :
512 : : default:
513 : 0 : data = 0;
514 : 0 : internal_error("unknown protocol");
515 : : }
516 : :
517 : : // ### data can be nil here if it's an
518 : : // IPv6 packet and we're doing an IP test.
519 [ # # ]: 0 : if ( ! data )
520 : 0 : continue;
521 : :
522 : : // Sorry for the hidden gotos :-)
523 [ # # # # # : 0 : switch ( h->comp ) {
# # ]
524 : : case RuleHdrTest::EQ:
525 [ # # ][ # # ]: 0 : DO_MATCH_OR(*h->vals, getval(data + h->offset, h->size), ==);
526 : :
527 : : case RuleHdrTest::NE:
528 [ # # ][ # # ]: 0 : DO_MATCH_NOT_AND(*h->vals, getval(data + h->offset, h->size), ==);
529 : :
530 : : case RuleHdrTest::LT:
531 [ # # ][ # # ]: 0 : DO_MATCH_OR(*h->vals, getval(data + h->offset, h->size), <);
532 : :
533 : : case RuleHdrTest::GT:
534 [ # # ][ # # ]: 0 : DO_MATCH_OR(*h->vals, getval(data + h->offset, h->size), >);
535 : :
536 : : case RuleHdrTest::LE:
537 [ # # ][ # # ]: 0 : DO_MATCH_OR(*h->vals, getval(data + h->offset, h->size), <=);
538 : :
539 : : case RuleHdrTest::GE:
540 [ # # ][ # # ]: 0 : DO_MATCH_OR(*h->vals, getval(data + h->offset, h->size), >=);
541 : :
542 : : default:
543 : 0 : internal_error("unknown comparision type");
544 : : }
545 : :
546 : 0 : no_match:
547 : 0 : continue;
548 : :
549 : 0 : match:
550 : 0 : tests.append(h);
551 : : }
552 : : }
553 : : }
554 : : // Save some memory.
555 : 0 : state->hdr_tests.resize(0);
556 : 0 : state->matchers.resize(0);
557 : :
558 : : // Send BOL to payload matchers.
559 : 0 : Match(state, Rule::PAYLOAD, (const u_char *) "", 0, true, false, false);
560 : :
561 : 0 : return state;
562 : : }
563 : :
564 : : void RuleMatcher::Match(RuleEndpointState* state, Rule::PatternType type,
565 : : const u_char* data, int data_len,
566 : 0 : bool bol, bool eol, bool clear)
567 : : {
568 [ # # ]: 0 : if ( ! state )
569 : : {
570 : 0 : warn("RuleEndpointState not initialized yet.");
571 : 0 : return;
572 : : }
573 : :
574 : : // FIXME: There is probably some room for performance improvements
575 : : // in this method. For example, it *may* help to use an IntSet
576 : : // for 'accepted' (that depends on the average number of matching
577 : : // patterns).
578 : :
579 [ # # ]: 0 : if ( rule_bench >= 2 )
580 : 0 : return;
581 : :
582 : 0 : bool newmatch = false;
583 : :
584 : : #ifdef DEBUG
585 [ # # ]: 0 : if ( debug_logger.IsEnabled(DBG_RULES) )
586 : : {
587 : : const char* s =
588 : 0 : fmt_bytes((const char *) data, min(40, data_len));
589 : :
590 [ # # ]: 0 : DBG_LOG(DBG_RULES, "Matching %s rules [%d,%d] on |%s%s|",
591 : : Rule::TypeToString(type), bol, eol, s,
592 : : data_len > 40 ? "..." : "");
593 : : }
594 : : #endif
595 : :
596 : : // Remember size of first non-null data.
597 [ # # ]: 0 : if ( type == Rule::PAYLOAD )
598 : : {
599 : 0 : bol = state->payload_size < 0;
600 : :
601 [ # # ][ # # ]: 0 : if ( state->payload_size <= 0 && data_len )
602 : 0 : state->payload_size = data_len;
603 : :
604 [ # # ]: 0 : else if ( state->payload_size < 0 )
605 : 0 : state->payload_size = 0;
606 : : }
607 : :
608 : : // Feed data into all relevant matchers.
609 [ # # ]: 0 : loop_over_list(state->matchers, x)
610 : : {
611 : 0 : RuleEndpointState::Matcher* m = state->matchers[x];
612 [ # # # # ]: 0 : if ( m->type == type &&
[ # # ]
613 : : m->state->Match((const u_char*) data, data_len,
614 : : bol, eol, clear) )
615 : 0 : newmatch = true;
616 : : }
617 : :
618 : : // If no new match found, we're already done.
619 [ # # ]: 0 : if ( ! newmatch )
620 : 0 : return;
621 : :
622 : 0 : DBG_LOG(DBG_RULES, "New pattern match found");
623 : :
624 : : // Build a joined AcceptingSet.
625 : 0 : AcceptingSet accepted;
626 : 0 : int_list matchpos;
627 : :
628 [ # # ]: 0 : loop_over_list(state->matchers, y)
629 : : {
630 : 0 : RuleEndpointState::Matcher* m = state->matchers[y];
631 : 0 : const AcceptingSet* ac = m->state->Accepted();
632 : :
633 [ # # ]: 0 : loop_over_list(*ac, k)
634 : : {
635 [ # # ]: 0 : if ( ! accepted.is_member((*ac)[k]) )
636 : : {
637 : 0 : accepted.append((*ac)[k]);
638 : 0 : matchpos.append((*m->state->MatchPositions())[k]);
639 : : }
640 : : }
641 : : }
642 : :
643 : : // Determine the rules for which all patterns have matched.
644 : : // This code should be fast enough as long as there are only very few
645 : : // matched patterns per connection (which is a plausible assumption).
646 : :
647 : 0 : rule_list matched;
648 : :
649 [ # # ]: 0 : loop_over_list(accepted, i)
650 : : {
651 : 0 : Rule* r = Rule::rule_table[accepted[i] - 1];
652 : :
653 : 0 : DBG_LOG(DBG_RULES, "Checking rule: %s", r->id);
654 : :
655 : : // Check whether all patterns of the rule have matched.
656 [ # # ]: 0 : loop_over_list(r->patterns, j)
657 : : {
658 [ # # ]: 0 : if ( ! accepted.is_member(r->patterns[j]->id) )
659 : 0 : goto next_pattern;
660 : :
661 : : // See if depth is satisfied.
662 [ # # ]: 0 : if ( (unsigned int) matchpos[i] >
663 : : r->patterns[j]->offset + r->patterns[j]->depth )
664 : 0 : goto next_pattern;
665 : :
666 : 0 : DBG_LOG(DBG_RULES, "All patterns of rule satisfied");
667 : :
668 : : // FIXME: How to check for offset ??? ###
669 : : }
670 : :
671 : : // If not already in the list of matching rules, add it.
672 [ # # ]: 0 : if ( ! matched.is_member(r) )
673 : 0 : matched.append(r);
674 : :
675 : 0 : next_pattern:
676 : : continue;
677 : : }
678 : :
679 : : // Check which of the matching rules really belong to any of our nodes.
680 : :
681 [ # # ]: 0 : loop_over_list(matched, j)
682 : : {
683 : 0 : Rule* r = matched[j];
684 : :
685 : 0 : DBG_LOG(DBG_RULES, "Accepted rule: %s", r->id);
686 : :
687 [ # # ]: 0 : loop_over_list(state->hdr_tests, k)
688 : : {
689 : 0 : RuleHdrTest* h = state->hdr_tests[k];
690 : :
691 : 0 : DBG_LOG(DBG_RULES, "Checking for accepted rule on HdrTest %d", h->id);
692 : :
693 : : // Skip if rule does not belong to this node.
694 [ # # ]: 0 : if ( ! h->ruleset->Contains(r->Index()) )
695 : 0 : continue;
696 : :
697 : 0 : DBG_LOG(DBG_RULES, "On current node");
698 : :
699 : : // Skip if rule already fired for this connection.
700 [ # # ]: 0 : if ( state->matched_rules.is_member(r->Index()) )
701 : 0 : continue;
702 : :
703 : : // Remember that all patterns have matched.
704 [ # # ]: 0 : if ( ! state->matched_by_patterns.is_member(r) )
705 : : {
706 : 0 : state->matched_by_patterns.append(r);
707 : 0 : BroString* s = new BroString(data, data_len, 0);
708 : 0 : state->matched_text.append(s);
709 : : }
710 : :
711 : 0 : DBG_LOG(DBG_RULES, "And has not already fired");
712 : : // Eval additional conditions.
713 [ # # ]: 0 : if ( ! EvalRuleConditions(r, state, data, data_len, 0) )
714 : 0 : continue;
715 : :
716 : : // Found a match.
717 : 0 : ExecRuleActions(r, state, data, data_len, 0);
718 : : }
719 : 0 : }
720 : : }
721 : :
722 : 0 : void RuleMatcher::FinishEndpoint(RuleEndpointState* state)
723 : : {
724 [ # # ]: 0 : if ( rule_bench == 3 )
725 : 0 : return;
726 : :
727 : : // Send EOL to payload matchers.
728 : 0 : Match(state, Rule::PAYLOAD, (const u_char *) "", 0, false, true, false);
729 : :
730 : : // Some of the pure rules may match at the end of the connection,
731 : : // although they have not matched at the beginning. So, we have
732 : : // to test the candidates here.
733 : :
734 : 0 : ExecPureRules(state, 1);
735 : :
736 [ # # ]: 0 : loop_over_list(state->matched_by_patterns, i)
737 : : ExecRulePurely(state->matched_by_patterns[i],
738 : 0 : state->matched_text[i], state, 1);
739 : : }
740 : :
741 : 0 : void RuleMatcher::ExecPureRules(RuleEndpointState* state, bool eos)
742 : : {
743 [ # # ]: 0 : loop_over_list(state->hdr_tests, i)
744 : : {
745 : 0 : RuleHdrTest* hdr_test = state->hdr_tests[i];
746 [ # # ]: 0 : for ( Rule* r = hdr_test->pure_rules; r; r = r->next )
747 : 0 : ExecRulePurely(r, 0, state, eos);
748 : : }
749 : 0 : }
750 : :
751 : : bool RuleMatcher::ExecRulePurely(Rule* r, BroString* s,
752 : 0 : RuleEndpointState* state, bool eos)
753 : : {
754 [ # # ]: 0 : if ( state->matched_rules.is_member(r->Index()) )
755 : 0 : return false;
756 : :
757 : 0 : DBG_LOG(DBG_RULES, "Checking rule %s purely", r->ID());
758 : :
759 [ # # ]: 0 : if ( EvalRuleConditions(r, state, 0, 0, eos) )
760 : : {
761 : 0 : DBG_LOG(DBG_RULES, "MATCH!");
762 : :
763 [ # # ]: 0 : if ( s )
764 : 0 : ExecRuleActions(r, state, s->Bytes(), s->Len(), eos);
765 : : else
766 : 0 : ExecRuleActions(r, state, 0, 0, eos);
767 : :
768 : 0 : return true;
769 : : }
770 : :
771 : 0 : return false;
772 : : }
773 : :
774 : : bool RuleMatcher::EvalRuleConditions(Rule* r, RuleEndpointState* state,
775 : 0 : const u_char* data, int len, bool eos)
776 : : {
777 : 0 : DBG_LOG(DBG_RULES, "Evaluating conditions for rule %s", r->ID());
778 : :
779 : : // Check for other rules which have to match first.
780 [ # # ]: 0 : loop_over_list(r->preconds, i)
781 : : {
782 : 0 : Rule::Precond* pc = r->preconds[i];
783 : :
784 : 0 : RuleEndpointState* pc_state = state;
785 : :
786 [ # # ]: 0 : if ( pc->opposite_dir )
787 : : {
788 [ # # ]: 0 : if ( ! state->opposite )
789 : : // No rule matching for other direction yet.
790 : 0 : return false;
791 : :
792 : 0 : pc_state = state->opposite;
793 : : }
794 : :
795 [ # # ]: 0 : if ( ! pc->negate )
796 : : {
797 [ # # ]: 0 : if ( ! pc_state->matched_rules.is_member(pc->rule->Index()) )
798 : : // Precond rule has not matched yet.
799 : 0 : return false;
800 : : }
801 : : else
802 : : {
803 : : // Only at eos can we decide about negated conditions.
804 [ # # ]: 0 : if ( ! eos )
805 : 0 : return false;
806 : :
807 [ # # ]: 0 : if ( pc_state->matched_rules.is_member(pc->rule->Index()) )
808 : 0 : return false;
809 : : }
810 : : }
811 : :
812 [ # # ]: 0 : loop_over_list(r->conditions, l)
813 [ # # ]: 0 : if ( ! r->conditions[l]->DoMatch(r, state, data, len) )
814 : 0 : return false;
815 : :
816 : 0 : DBG_LOG(DBG_RULES, "Conditions met: MATCH! %s", r->ID());
817 : 0 : return true;
818 : : }
819 : :
820 : : void RuleMatcher::ExecRuleActions(Rule* r, RuleEndpointState* state,
821 : 0 : const u_char* data, int len, bool eos)
822 : : {
823 [ # # ][ # # ]: 0 : if ( state->opposite &&
[ # # ]
824 : : state->opposite->matched_rules.is_member(r->Index()) )
825 : : // We have already executed the actions.
826 : 0 : return;
827 : :
828 : 0 : state->matched_rules.append(r->Index());
829 : :
830 [ # # ]: 0 : loop_over_list(r->actions, i)
831 : 0 : r->actions[i]->DoAction(r, state, data, len);
832 : :
833 : : // This rule may trigger some other rules; check them.
834 [ # # ]: 0 : loop_over_list(r->dependents, j)
835 : : {
836 : 0 : Rule* dep = (r->dependents)[j];
837 : 0 : ExecRule(dep, state, eos);
838 [ # # ]: 0 : if ( state->opposite )
839 : 0 : ExecRule(dep, state->opposite, eos);
840 : : }
841 : : }
842 : :
843 : 0 : void RuleMatcher::ExecRule(Rule* rule, RuleEndpointState* state, bool eos)
844 : : {
845 : : // Nothing to do if it has already matched.
846 [ # # ]: 0 : if ( state->matched_rules.is_member(rule->Index()) )
847 : 0 : return;
848 : :
849 [ # # ]: 0 : loop_over_list(state->hdr_tests, i)
850 : : {
851 : 0 : RuleHdrTest* h = state->hdr_tests[i];
852 : :
853 : : // Is it on this HdrTest at all?
854 [ # # ]: 0 : if ( ! h->ruleset->Contains(rule->Index()) )
855 : 0 : continue;
856 : :
857 : : // Is it a pure rule?
858 [ # # ]: 0 : for ( Rule* r = h->pure_rules; r; r = r->next )
859 [ # # ]: 0 : if ( r == rule )
860 : : { // found, so let's evaluate it
861 : 0 : ExecRulePurely(rule, 0, state, eos);
862 : 0 : return;
863 : : }
864 : :
865 : : // It must be a non-pure rule. It can only match right now if
866 : : // all its patterns are satisfied already.
867 : 0 : int pos = state->matched_by_patterns.member_pos(rule);
868 [ # # ]: 0 : if ( pos >= 0 )
869 : : { // they are, so let's evaluate it
870 : 0 : ExecRulePurely(rule, state->matched_text[pos], state, eos);
871 : 0 : return;
872 : : }
873 : : }
874 : : }
875 : :
876 : 0 : void RuleMatcher::ClearEndpointState(RuleEndpointState* state)
877 : : {
878 [ # # ]: 0 : if ( rule_bench == 3 )
879 : 0 : return;
880 : :
881 : 0 : ExecPureRules(state, 1);
882 : 0 : state->payload_size = -1;
883 : 0 : state->matched_by_patterns.clear();
884 [ # # ]: 0 : loop_over_list(state->matched_text, i)
885 [ # # ]: 0 : delete state->matched_text[i];
886 : 0 : state->matched_text.clear();
887 : :
888 [ # # ]: 0 : loop_over_list(state->matchers, j)
889 : 0 : state->matchers[j]->state->Clear();
890 : : }
891 : :
892 : 0 : void RuleMatcher::PrintDebug()
893 : : {
894 [ # # ]: 0 : loop_over_list(rules, i)
895 : 0 : rules[i]->PrintDebug();
896 : :
897 : 0 : fprintf(stderr, "\n---------------\n");
898 : :
899 : 0 : PrintTreeDebug(root);
900 : 0 : }
901 : :
902 : 0 : static inline void indent(int level)
903 : : {
904 [ # # ]: 0 : for ( int i = level * 2; i; --i )
905 : 0 : fputc(' ', stderr);
906 : 0 : }
907 : :
908 : 0 : void RuleMatcher::PrintTreeDebug(RuleHdrTest* node)
909 : : {
910 [ # # ]: 0 : for ( int i = 0; i < Rule::TYPES; ++i )
911 : : {
912 : 0 : indent(node->level);
913 [ # # ]: 0 : loop_over_list(node->psets[i], j)
914 : : {
915 : 0 : RuleHdrTest::PatternSet* set = node->psets[i][j];
916 : :
917 : : fprintf(stderr,
918 : : "[%d patterns in %s group %d from %d rules]\n",
919 : : set->patterns.length(),
920 : : Rule::TypeToString((Rule::PatternType) i), j,
921 : 0 : set->ids.length());
922 : : }
923 : : }
924 : :
925 [ # # ]: 0 : for ( Rule* r = node->pattern_rules; r; r = r->next )
926 : : {
927 : 0 : indent(node->level);
928 : : fprintf(stderr, "Pattern rule %s (%d/%d)\n", r->id, r->idx,
929 : 0 : node->ruleset->Contains(r->Index()));
930 : : }
931 : :
932 [ # # ]: 0 : for ( Rule* r = node->pure_rules; r; r = r->next )
933 : : {
934 : 0 : indent(node->level);
935 : : fprintf(stderr, "Pure rule %s (%d/%d)\n", r->id, r->idx,
936 : 0 : node->ruleset->Contains(r->Index()));
937 : : }
938 : :
939 [ # # ]: 0 : for ( RuleHdrTest* h = node->child; h; h = h->sibling )
940 : : {
941 : 0 : indent(node->level);
942 : 0 : fprintf(stderr, "Test %4d\n", h->id);
943 : 0 : PrintTreeDebug(h);
944 : : }
945 : 0 : }
946 : :
947 : 0 : void RuleMatcher::GetStats(Stats* stats, RuleHdrTest* hdr_test)
948 : : {
949 [ # # ]: 0 : if ( ! hdr_test )
950 : : {
951 : 0 : stats->matchers = 0;
952 : 0 : stats->dfa_states = 0;
953 : 0 : stats->computed = 0;
954 : 0 : stats->mem = 0;
955 : 0 : stats->hits = 0;
956 : 0 : stats->misses = 0;
957 : 0 : stats->avg_nfa_states = 0;
958 : 0 : hdr_test = root;
959 : : }
960 : :
961 : : DFA_State_Cache::Stats cstats;
962 : :
963 [ # # ]: 0 : for ( int i = 0; i < Rule::TYPES; ++i )
964 : : {
965 [ # # ]: 0 : loop_over_list(hdr_test->psets[i], j)
966 : : {
967 : 0 : RuleHdrTest::PatternSet* set = hdr_test->psets[i][j];
968 [ # # ]: 0 : assert(set->re);
969 : :
970 : 0 : ++stats->matchers;
971 : 0 : set->re->DFA()->Cache()->GetStats(&cstats);
972 : :
973 : 0 : stats->dfa_states += cstats.dfa_states;
974 : 0 : stats->computed += cstats.computed;
975 : 0 : stats->mem += cstats.mem;
976 : 0 : stats->hits += cstats.hits;
977 : 0 : stats->misses += cstats.misses;
978 : 0 : stats->avg_nfa_states += cstats.nfa_states;
979 : : }
980 : : }
981 : :
982 [ # # ]: 0 : if ( stats->dfa_states )
983 : 0 : stats->avg_nfa_states /= stats->dfa_states;
984 : : else
985 : 0 : stats->avg_nfa_states = 0;
986 : :
987 [ # # ]: 0 : for ( RuleHdrTest* h = hdr_test->child; h; h = h->sibling )
988 : 0 : GetStats(stats, h);
989 : 0 : }
990 : :
991 : 0 : void RuleMatcher::DumpStats(BroFile* f)
992 : : {
993 : : Stats stats;
994 : 0 : GetStats(&stats);
995 : :
996 : : f->Write(fmt("%.6f computed dfa states = %d; classes = ??; "
997 : : "computed trans. = %d; matchers = %d; mem = %d\n",
998 : : network_time, stats.dfa_states, stats.computed,
999 : 0 : stats.matchers, stats.mem));
1000 : : f->Write(fmt("%.6f DFA cache hits = %d; misses = %d\n", network_time,
1001 : 0 : stats.hits, stats.misses));
1002 : :
1003 : 0 : DumpStateStats(f, root);
1004 : 0 : }
1005 : :
1006 : 0 : void RuleMatcher::DumpStateStats(BroFile* f, RuleHdrTest* hdr_test)
1007 : : {
1008 [ # # ]: 0 : if ( ! hdr_test )
1009 : 0 : return;
1010 : :
1011 [ # # ]: 0 : for ( int i = 0; i < Rule::TYPES; i++ )
1012 : : {
1013 [ # # ]: 0 : loop_over_list(hdr_test->psets[i], j)
1014 : : {
1015 : 0 : RuleHdrTest::PatternSet* set = hdr_test->psets[i][j];
1016 [ # # ]: 0 : assert(set->re);
1017 : :
1018 : : f->Write(fmt("%.6f %d DFA states in %s group %d from sigs ", network_time,
1019 : : set->re->DFA()->NumStates(),
1020 : 0 : Rule::TypeToString((Rule::PatternType)i), j));
1021 : :
1022 [ # # ]: 0 : loop_over_list(set->ids, k)
1023 : : {
1024 : 0 : Rule* r = Rule::rule_table[set->ids[k] - 1];
1025 : 0 : f->Write(fmt("%s ", r->ID()));
1026 : : }
1027 : :
1028 : 0 : f->Write("\n");
1029 : : }
1030 : : }
1031 : :
1032 [ # # ]: 0 : for ( RuleHdrTest* h = hdr_test->child; h; h = h->sibling )
1033 : 0 : DumpStateStats(f, h);
1034 : : }
1035 : :
1036 : 0 : static Val* get_bro_val(const char* label)
1037 : : {
1038 : 0 : ID* id = lookup_ID(label, GLOBAL_MODULE_NAME, false);
1039 [ # # ]: 0 : if ( ! id )
1040 : : {
1041 : 0 : rules_error("unknown script-level identifier", label);
1042 : 0 : return 0;
1043 : : }
1044 : :
1045 : 0 : return id->ID_Val();
1046 : : }
1047 : :
1048 : :
1049 : : // Converts an atomic Val and appends it to the list
1050 : 0 : static bool val_to_maskedval(Val* v, maskedvalue_list* append_to)
1051 : : {
1052 : 0 : MaskedValue* mval = new MaskedValue;
1053 : :
1054 [ # # # # ]: 0 : switch ( v->Type()->Tag() ) {
1055 : : case TYPE_PORT:
1056 : 0 : mval->val = v->AsPortVal()->Port();
1057 : 0 : mval->mask = 0xffffffff;
1058 : 0 : break;
1059 : :
1060 : : case TYPE_BOOL:
1061 : : case TYPE_COUNT:
1062 : : case TYPE_ENUM:
1063 : : case TYPE_INT:
1064 : 0 : mval->val = v->CoerceToUnsigned();
1065 : 0 : mval->mask = 0xffffffff;
1066 : 0 : break;
1067 : :
1068 : : case TYPE_SUBNET:
1069 : : #ifdef BROv6
1070 : : {
1071 : : uint32* n = v->AsSubNet()->net;
1072 : : uint32* m = v->AsSubNetVal()->Mask();
1073 : : bool is_v4_mask = m[0] == 0xffffffff &&
1074 : : m[1] == m[0] && m[2] == m[0];
1075 : :
1076 : : if ( is_v4_addr(n) && is_v4_mask )
1077 : : {
1078 : : mval->val = ntohl(to_v4_addr(n));
1079 : : mval->mask = m[3];
1080 : : }
1081 : :
1082 : : else
1083 : : {
1084 : : rules_error("IPv6 subnets not supported");
1085 : : mval->val = 0;
1086 : : mval->mask = 0;
1087 : : }
1088 : : }
1089 : : #else
1090 : 0 : mval->val = ntohl(v->AsSubNet()->net);
1091 : 0 : mval->mask = v->AsSubNetVal()->Mask();
1092 : : #endif
1093 : 0 : break;
1094 : :
1095 : : default:
1096 : 0 : rules_error("Wrong type of identifier");
1097 : 0 : return false;
1098 : : }
1099 : :
1100 : 0 : append_to->append(mval);
1101 : :
1102 : 0 : return true;
1103 : : }
1104 : :
1105 : 0 : void id_to_maskedvallist(const char* id, maskedvalue_list* append_to)
1106 : : {
1107 : 0 : Val* v = get_bro_val(id);
1108 [ # # ]: 0 : if ( ! v )
1109 : 0 : return;
1110 : :
1111 [ # # ]: 0 : if ( v->Type()->Tag() == TYPE_TABLE )
1112 : : {
1113 : 0 : val_list* vals = v->AsTableVal()->ConvertToPureList()->Vals();
1114 [ # # ]: 0 : loop_over_list(*vals, i )
1115 [ # # ]: 0 : if ( ! val_to_maskedval((*vals)[i], append_to) )
1116 : 0 : return;
1117 : : }
1118 : :
1119 : : else
1120 : 0 : val_to_maskedval(v, append_to);
1121 : : }
1122 : :
1123 : 0 : char* id_to_str(const char* id)
1124 : : {
1125 : : const BroString* src;
1126 : : char* dst;
1127 : :
1128 : 0 : Val* v = get_bro_val(id);
1129 [ # # ]: 0 : if ( ! v )
1130 : 0 : goto error;
1131 : :
1132 [ # # ]: 0 : if ( v->Type()->Tag() != TYPE_STRING )
1133 : : {
1134 : 0 : rules_error("Identifier must refer to string");
1135 : 0 : goto error;
1136 : : }
1137 : :
1138 : 0 : src = v->AsString();
1139 : 0 : dst = new char[src->Len()+1];
1140 : 0 : memcpy(dst, src->Bytes(), src->Len());
1141 : 0 : *(dst+src->Len()) = '\0';
1142 : 0 : return dst;
1143 : :
1144 : 0 : error:
1145 : 0 : char* dummy = copy_string("<error>");
1146 : 0 : return dummy;
1147 : : }
1148 : :
1149 : 0 : uint32 id_to_uint(const char* id)
1150 : : {
1151 : 0 : Val* v = get_bro_val(id);
1152 [ # # ]: 0 : if ( ! v )
1153 : 0 : return 0;
1154 : :
1155 : 0 : TypeTag t = v->Type()->Tag();
1156 : :
1157 [ # # # # ]: 0 : if ( t == TYPE_BOOL || t == TYPE_COUNT || t == TYPE_ENUM ||
[ # # ][ # # ]
[ # # ]
1158 : : t == TYPE_INT || t == TYPE_PORT )
1159 : 0 : return v->CoerceToUnsigned();
1160 : :
1161 : 0 : rules_error("Identifier must refer to integer");
1162 : 0 : return 0;
1163 : : }
1164 : :
1165 : : void RuleMatcherState::InitEndpointMatcher(Analyzer* analyzer, const IP_Hdr* ip,
1166 : 26764 : int caplen, bool from_orig, PIA* pia)
1167 : : {
1168 [ + - ]: 26764 : if ( ! rule_matcher )
1169 : 26764 : return;
1170 : :
1171 [ # # ]: 0 : if ( from_orig )
1172 : : {
1173 [ # # ]: 0 : if ( orig_match_state )
1174 : : {
1175 : 0 : rule_matcher->FinishEndpoint(orig_match_state);
1176 [ # # ]: 0 : delete orig_match_state;
1177 : : }
1178 : :
1179 : : orig_match_state =
1180 : : rule_matcher->InitEndpoint(analyzer, ip, caplen,
1181 : 0 : resp_match_state, from_orig, pia);
1182 : : }
1183 : :
1184 : : else
1185 : : {
1186 [ # # ]: 0 : if ( resp_match_state )
1187 : : {
1188 : 0 : rule_matcher->FinishEndpoint( resp_match_state );
1189 [ # # ]: 0 : delete resp_match_state;
1190 : : }
1191 : :
1192 : : resp_match_state =
1193 : : rule_matcher->InitEndpoint(analyzer, ip, caplen,
1194 : 26764 : orig_match_state, from_orig, pia);
1195 : : }
1196 : : }
1197 : :
1198 : 1627 : void RuleMatcherState::FinishEndpointMatcher()
1199 : : {
1200 [ + - ]: 1627 : if ( ! rule_matcher )
1201 : 1627 : return;
1202 : :
1203 [ # # ]: 0 : if ( orig_match_state )
1204 : 0 : rule_matcher->FinishEndpoint(orig_match_state);
1205 : :
1206 [ # # ]: 0 : if ( resp_match_state )
1207 : 0 : rule_matcher->FinishEndpoint(resp_match_state);
1208 : :
1209 [ # # ]: 0 : delete orig_match_state;
1210 [ # # ]: 0 : delete resp_match_state;
1211 : :
1212 : 1627 : orig_match_state = resp_match_state = 0;
1213 : : }
1214 : :
1215 : : void RuleMatcherState::Match(Rule::PatternType type, const u_char* data,
1216 : : int data_len, bool from_orig,
1217 : 26764 : bool bol, bool eol, bool clear)
1218 : : {
1219 [ + - ]: 26764 : if ( ! rule_matcher )
1220 : 26764 : return;
1221 : :
1222 : : rule_matcher->Match(from_orig ? orig_match_state : resp_match_state,
1223 [ # # ]: 26764 : type, data, data_len, bol, eol, clear);
1224 : : }
1225 : :
1226 : 0 : void RuleMatcherState::ClearMatchState(bool orig)
1227 : : {
1228 [ # # ]: 0 : if ( ! rule_matcher )
1229 : 0 : return;
1230 : :
1231 [ # # ]: 0 : if ( orig_match_state )
1232 : 0 : rule_matcher->ClearEndpointState(orig_match_state);
1233 [ # # ]: 0 : if ( resp_match_state )
1234 : 0 : rule_matcher->ClearEndpointState(resp_match_state);
1235 [ + - ][ + - ]: 6 : }
|