LCOV - code coverage report
Current view: top level - src - RuleMatcher.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 47 566 8.3 %
Date: 2010-12-13 Functions: 9 51 17.6 %
Branches: 11 538 2.0 %

           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 :         }

Generated by: LCOV version 1.8