Changeset 260


Ignore:
Timestamp:
Dec 7, 2009, 10:00:29 PM (15 years ago)
Author:
katerina
Message:

Support event correlation (ticket #178).

Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/sh_cat.h

    r192 r260  
    167167 MSG_LOGMON_REP,
    168168 MSG_LOGMON_SUM,
     169 MSG_LOGMON_COR,
    169170#endif
    170171
  • trunk/include/sh_log_evalrule.h

    r183 r260  
    3535int sh_eval_gend (const char * str);
    3636
     37/* Process a single log record
     38 */
    3739int sh_eval_process_msg(struct sh_logrecord * record);
     40
     41/* Match correlated rules
     42 */
     43void sh_keep_match();
     44
    3845#endif
  • trunk/include/sh_string.h

    r215 r260  
    8484char ** split_array_list(char *line, unsigned int * nfields, size_t * lengths);
    8585
     86/* Return a split_array_list() of a list contained in 'PREFIX\s*( list ).*'
     87 */
     88char ** split_array_braced (char *line, const char * prefix,
     89                            unsigned int * nfields, size_t * lengths);
     90
    8691/* Replaces fields in s with 'replacement'. Fields are given
    8792 * in the ordered array ovector, comprising ovecnum pairs
  • trunk/src/sh_cat.c

    r257 r260  
    159159  { MSG_LOGMON_REP,  SH_ERR_SEVERE,  EVENT, N_("msg=\"POLICY [Logfile] %s\" time=\"%s\" host=\"%s\" path=\"%s\"") },
    160160  { MSG_LOGMON_SUM,  SH_ERR_SEVERE,  EVENT, N_("msg=\"POLICY [Logfile] %s\" host=\"%s\" path=\"%s\"") },
     161  { MSG_LOGMON_COR,  SH_ERR_SEVERE,  EVENT, N_("msg=\"POLICY [Logfile] Correlated events %s\"") },
    161162#endif
    162163
     
    488489  { MSG_LOGMON_REP,  SH_ERR_SEVERE,  EVENT, N_("msg=<POLICY [Logfile] %s> time=<%s> host=<%s> path=<%s>") },
    489490  { MSG_LOGMON_SUM,  SH_ERR_SEVERE,  EVENT, N_("msg=<POLICY [Logfile] %s> host=<%s> path=<%s>") },
     491  { MSG_LOGMON_COR,  SH_ERR_SEVERE,  EVENT, N_("msg=<POLICY [Logfile] Correlated events %s>") },
    490492#endif
    491493
  • trunk/src/sh_log_check.c

    r257 r260  
    2828
    2929/* List of supported logfile types, format is
    30  * { "TYPE_CODE", Reader_Callback_Function, Parser_Callback_function }
     30 * {
     31 *   "TYPE_CODE",
     32 *   Reader_Callback_Function,
     33 *   Parser_Callback_function,
     34 *   Evaluate_Callback_Function
     35 * }
    3136 * If Reader_Callback_Function is NULL, the default (line-oriented
    3237 * text file) reader is used.
     
    7883  plen = strlen(save_dir);
    7984
    80   if (SL_TRUE == sl_ok_adds(plen, 129))
    81     {
    82       plen += 129; /* 64 + 64 + 1 */
     85  if (SL_TRUE == sl_ok_adds(plen, 130))
     86    {
     87      plen += 130; /* 64 + 64 + 2 */
    8388      path = SH_ALLOC(plen);
    8489      (void) sl_snprintf(path, plen, "%s/%lu_%lu", save_dir,
     
    860865    {
    861866      sh_check_watches();
     867      sh_keep_match();
    862868    }
    863869  SH_MUTEX_UNLOCK(mutex_logmon_check);
     
    10361042
    10371043/* Define a check rule.
    1038  * Format: Queue_Label : Regex
    1039  * TYPE must be 'report' or 'sum'
     1044 * Format: [KEEP(seconds,label):]Queue_Label : Regex
     1045 * KEEP indicates that we keep the label, to perform
     1046 *      correlation matching
    10401047 */
    10411048static int sh_logmon_add_rule (const char * str)
  • trunk/src/sh_log_evalrule.c

    r203 r260  
    8989};
    9090
     91enum {
     92  RFL_ISRULE  = 1 << 0,
     93  RFL_ISGROUP = 1 << 1,
     94  RFL_KEEP    = 1 << 2
     95};
     96
     97/*--------------------------------------------------------------*/
     98
     99struct sh_keep
     100{
     101  sh_string       * label;           /* label of keep rule   */
     102  unsigned long     delay;           /* valid delay             */
     103  time_t            last;            /* seen at                 */
     104  struct sh_keep *  next;
     105};
     106
     107static struct sh_keep * keeplist  = NULL;
     108static struct sh_keep * keeplast  = NULL;
     109static unsigned long    keepcount = 0;
     110
     111static void sh_keep_free(void * item)
     112{
     113  struct sh_keep * keep = (struct sh_keep *) item;
     114  if (!keep)
     115    return;
     116  sh_string_destroy(&(keep->label));
     117  SH_FREE(keep);
     118}
     119
     120static void sh_keep_destroy()
     121{
     122  struct sh_keep * keep;
     123
     124  while (keeplist)
     125    {
     126      keep = keeplist;
     127      keeplist = keep->next;
     128      sh_keep_free(keep);
     129      --keepcount;
     130    }
     131  keeplist  = NULL;
     132  keeplast  = NULL;
     133  keepcount = 0;
     134}
     135
     136static int sh_keep_add(sh_string * label, unsigned long delay, time_t last)
     137{
     138  struct sh_keep * keep = SH_ALLOC(sizeof(struct sh_keep));
     139
     140  keep->label = sh_string_copy(label);
     141  keep->delay = delay;
     142  keep->last  = last;
     143  keep->next  = NULL;
     144
     145  if (keeplast && keeplist)
     146    {
     147      keeplast->next = keep;
     148      keeplast       = keep;
     149    }
     150  else
     151    {
     152      keeplist = keep;
     153      keeplast = keeplist;
     154    }
     155  ++keepcount;
     156  return 0;
     157}
     158
     159int sh_keep_comp(const void * a, const void * b)
     160{
     161  return ( (int)(((struct sh_keep *)a)->last) -
     162           (int)(((struct sh_keep *)b)->last) );
     163}
     164
     165static sh_string * sh_keep_eval()
     166{
     167  unsigned long count   = 0;
     168  sh_string * res       = NULL;
     169  time_t now            = time(NULL);
     170  struct sh_keep * keep = keeplist;
     171  struct sh_keep * prev = keeplist;
     172  struct sh_keep * arr;
     173
     174  if (keepcount > 0)
     175    {
     176      arr = SH_ALLOC (keepcount * sizeof(struct sh_keep));
     177
     178      while (count < keepcount && keep)
     179        {
     180          if ((now > keep->last) && ((unsigned long)(now - keep->last) <= keep->delay))
     181            {
     182              memcpy(&(arr[count]), keep, sizeof(struct sh_keep));
     183              ++count;
     184              prev = keep;
     185              keep = keep->next;
     186            }
     187          else /* Too old or in future, delete it */
     188            {
     189              if (keep != keeplist)
     190                {
     191                  prev->next = keep->next;
     192                  sh_keep_free(keep);
     193                  keep = prev->next;
     194                  --keepcount;
     195                }
     196              else /* list head */
     197                {
     198                  keeplist = keep->next;
     199                  prev     = keeplist;
     200                  sh_keep_free(keep);
     201                  keep     = keeplist;
     202                  --keepcount;
     203                }
     204            }
     205        }
     206
     207      if (count > 0)
     208        {
     209          unsigned long i;
     210          qsort(arr, count, sizeof(struct sh_keep), sh_keep_comp);
     211          res = sh_string_copy(arr[0].label);
     212          for (i = 1; i < count; ++i)
     213            res = sh_string_add(res, arr[i].label);
     214        }
     215      SH_FREE(arr);
     216    }
     217  return res;
     218}
     219
     220struct sh_mkeep
     221{
     222  sh_string       * label;           /* label of match rule     */
     223  pcre            * rule;            /* compiled regex for rule */
     224  struct sh_qeval * queue;           /* assigned queue          */
     225  struct sh_mkeep * next;
     226};
     227
     228struct sh_mkeep * mkeep_list = NULL;
     229
     230static struct sh_qeval * find_queue(const char * str);
     231
     232static int sh_keep_match_add(const char * str, const char * queue, const char * pattern)
     233{
     234  unsigned int nfields = 1; /* seconds:label */
     235  size_t       lengths[1];
     236  char *       new    = sh_util_strdup(str);
     237  char **      splits = split_array_braced(new, _("CORRELATE"), &nfields, lengths);
     238
     239  if (nfields == 1 && lengths[0] > 0)
     240    {
     241      struct sh_mkeep * mkeep = SH_ALLOC(sizeof(struct sh_mkeep));
     242      const char * error;
     243      int          erroffset;
     244      struct sh_qeval * rqueue = NULL;
     245
     246      mkeep->rule = pcre_compile(pattern, PCRE_NO_AUTO_CAPTURE,
     247                             &error, &erroffset, NULL);
     248      if (!(mkeep->rule))
     249        {
     250          sh_string * msg =  sh_string_new(0);
     251          sh_string_add_from_char(msg, _("Bad regex: "));
     252          sh_string_add_from_char(msg, pattern);
     253         
     254          SH_MUTEX_LOCK(mutex_thread_nolog);
     255          sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
     256                          sh_string_str(msg),
     257                          _("sh_keep_match_add"));
     258          SH_MUTEX_UNLOCK(mutex_thread_nolog);
     259          sh_string_destroy(&msg);
     260         
     261          SH_FREE(splits);
     262          SH_FREE(mkeep);
     263          SH_FREE(new);
     264          return -1;
     265        }
     266
     267      if (0 != strcmp(queue, _("trash")))
     268        {
     269
     270          rqueue = find_queue(queue);
     271          if (!rqueue)
     272            {
     273              pcre_free(mkeep->rule);
     274              SH_FREE(splits);
     275              SH_FREE(mkeep);
     276              SH_FREE(new);
     277              return -1;
     278            }
     279        }
     280
     281      mkeep->queue = rqueue;
     282      mkeep->label = sh_string_new_from_lchar(splits[0], strlen(splits[0]));
     283      mkeep->next  = mkeep_list;
     284      mkeep_list   = mkeep;
     285    }
     286  SH_FREE(new);
     287  return 0;
     288}
     289
     290static void sh_keep_match_del()
     291{
     292  struct sh_mkeep * mkeep = mkeep_list;
     293  while (mkeep)
     294    {
     295      mkeep_list = mkeep->next;
     296      sh_string_destroy(&(mkeep->label));
     297      pcre_free(mkeep->rule);
     298      mkeep = mkeep_list;
     299    }
     300  mkeep_list = NULL;
     301}
     302
     303static struct sh_mkeep ** dummy_mkeep;
     304
     305void sh_keep_match()
     306{
     307  if (mkeep_list)
     308    {
     309      sh_string       * res = sh_keep_eval();
     310
     311      if (res)
     312        {
     313          struct sh_mkeep * mkeep = mkeep_list;
     314
     315          dummy_mkeep = &mkeep;
     316
     317          while (mkeep)
     318            {
     319              int val = pcre_exec(mkeep->rule, NULL,
     320                                  sh_string_str(res), (int)sh_string_len(res),
     321                                  0, 0, NULL, 0);
     322              if (val >= 0)
     323                {
     324                  char * tmp;
     325                  SH_MUTEX_LOCK(mutex_thread_nolog);
     326                  tmp = sh_util_safe_name (sh_string_str(mkeep->label));
     327                  sh_error_handle (mkeep->queue->severity, FIL__, __LINE__, 0,
     328                                   MSG_LOGMON_COR, tmp);
     329                  SH_FREE(tmp);
     330                  SH_MUTEX_UNLOCK(mutex_thread_nolog);
     331                }
     332              mkeep = mkeep->next;
     333            }
     334          sh_string_destroy(&res);
     335        }
     336    }
     337  return;
     338}
     339
     340/*--------------------------------------------------------------*/
     341
    91342struct sh_geval  /* Group of rules (may be a single rule) */
    92343{
     
    97348  int               ovecnum;         /* how many captured       */
    98349  int               captures;        /* (captures+1)*3 required */
     350  int               flags;           /* bit flags               */
     351  unsigned long     delay;           /* delay for keep rules    */
    99352  zAVLTree        * counterlist;     /* counters if EVAL_SUM    */
    100353  struct sh_qeval * queue;           /* queue for this rule     */
     
    178431  ng = SH_ALLOC(sizeof(struct sh_geval));
    179432  ng->label       = sh_string_new_from_lchar(splits[0], lengths[0]);
     433  ng->flags       = RFL_ISGROUP;
     434
    180435  ng->rule        = group;
    181436  ng->rule_extra  = group_extra;
     
    384639}
    385640
     641char * get_keep(char * str, unsigned long * seconds)
     642{
     643  char       * res    = NULL;
     644  char       * endptr = NULL;
     645
     646  unsigned int nfields = 2; /* seconds:label */
     647  size_t       lengths[2];
     648  char *       new    = sh_util_strdup(str);
     649  char **      splits = split_array_braced(new, _("KEEP"), &nfields, lengths);
     650
     651  if (nfields == 2 && lengths[0] > 0 && lengths[1] > 0)
     652    {
     653      *seconds = strtoul(splits[0], &endptr, 10);
     654      if ((endptr == '\0' || endptr != splits[0]) && (*seconds != ULONG_MAX))
     655        {
     656          res = sh_util_strdup(splits[1]);
     657        }
     658    }
     659  if (splits)
     660    SH_FREE(splits);
     661  SH_FREE(new);
     662  return res;
     663}
     664
    386665static struct sh_qeval ** dummy_queue;
     666static char            ** dummy_dstr;
    387667
    388668int sh_eval_radd (const char * str)
     
    398678  unsigned int nfields = 2; /* queue:regex */
    399679  size_t       lengths[2];
    400   char *       new = sh_util_strdup(str);
     680  char *       new    = sh_util_strdup(str);
    401681  char **      splits = split_array(new, &nfields, ':', lengths);
    402682
     683  int           qpos = 0;
     684  int           rpos = 1;
     685  unsigned long dsec = 0;
     686  char *        dstr = NULL;
     687
    403688  dummy_queue = &queue;
    404 
    405   if (nfields != 2)
     689  dummy_dstr  = &dstr;
     690
     691  if (nfields < 2 || nfields > 3)
    406692    {
    407693      SH_FREE(splits);
     
    410696    }
    411697
    412   if (0 != strcmp(splits[0], _("trash")))
    413       {
    414         queue = find_queue(splits[0]);
    415         if (!queue)
    416           {
    417             SH_FREE(splits);
    418             SH_FREE(new);
    419             return -1;
    420           }
    421       }
    422 
    423   rule = pcre_compile(splits[1], 0,
     698  if (nfields == 3)
     699    {
     700      /* KEEP(nsec):queue:regex
     701       */
     702      dstr = get_keep(splits[0], &dsec);
     703      if (!dstr)
     704        {
     705          /* CORRELATE:queue:regex
     706           */
     707          int retval = sh_keep_match_add(splits[0], splits[1], splits[2]);
     708          SH_FREE(splits);
     709          SH_FREE(new);
     710          return retval;
     711        }
     712      ++qpos; ++rpos;
     713    }
     714
     715  if (0 != strcmp(splits[qpos], _("trash")))
     716    {
     717      queue = find_queue(splits[qpos]);
     718      if (!queue)
     719        {
     720          SH_FREE(splits);
     721          SH_FREE(new);
     722          return -1;
     723        }
     724    }
     725
     726  rule = pcre_compile(splits[rpos], 0,
    424727                      &error, &erroffset, NULL);
    425728  if (!rule)
     
    427730      sh_string * msg =  sh_string_new(0);
    428731      sh_string_add_from_char(msg, _("Bad regex: "));
    429       sh_string_add_from_char(msg, splits[1]);
     732      sh_string_add_from_char(msg, splits[rpos]);
    430733     
    431734      SH_MUTEX_LOCK(mutex_thread_nolog);
     
    446749    {
    447750      char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
    448       sl_snprintf(emsg,  SH_ERRBUF_SIZE, _("Adding rule: |%s| with %d captures"),
    449                   splits[1], captures);
     751      if (dstr)
     752        sl_snprintf(emsg,  SH_ERRBUF_SIZE, _("Adding rule: |%s| with %d captures, keep(%lu,%s)"),
     753                    splits[rpos], captures, dsec, dstr);
     754      else
     755        sl_snprintf(emsg,  SH_ERRBUF_SIZE, _("Adding rule: |%s| with %d captures"),
     756                    splits[rpos], captures);
    450757      SH_MUTEX_LOCK(mutex_thread_nolog);
    451758      sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
     
    455762    }
    456763
    457   DEBUG("adding rule: |%s| with %d captures\n", splits[1], captures);
     764  DEBUG("adding rule: |%s| with %d captures\n", splits[rpos], captures);
    458765
    459766  SH_FREE(splits);
     
    462769  nr = SH_ALLOC(sizeof(struct sh_geval));
    463770  nr->label       = NULL;
     771  nr->flags       = RFL_ISRULE;
     772  nr->delay       = 0;
     773
    464774  nr->rule        = rule;
    465775  nr->rule_extra  = rule_extra;
     
    473783  nr->gnext       = NULL;
    474784
     785
     786  if (dstr)
     787    {
     788      nr->label   = sh_string_new_from_lchar(dstr, strlen(dstr));
     789      nr->flags  |= RFL_KEEP;
     790      nr->delay   = dsec;
     791      SH_FREE(dstr);
     792    }
     793
    475794  /*
    476795   * If there is an open group, add it to its
     
    513832          if (0 != sh_eval_hadd("^.*"))
    514833            {
     834              if (nr->label)
     835                sh_string_destroy(&(nr->label));
    515836              SH_FREE(nr->ovector);
    516837              SH_FREE(nr);
     
    559880      else
    560881        {
     882          if (nr->label)
     883            sh_string_destroy(&(nr->label));
    561884          SH_FREE(nr->ovector);
    562885          SH_FREE(nr);
     
    623946    }
    624947
     948  sh_keep_destroy();
     949  sh_keep_match_del();
     950
     951  return;
    625952}
    626953
     
    636963static struct sh_geval ** dummy1;
    637964
    638 static struct sh_geval * test_rule (struct sh_geval * rule, sh_string *msg)
     965static struct sh_geval * test_rule (struct sh_geval * rule, sh_string *msg, time_t tstamp)
    639966{
    640967  int res;
    641   volatile int count;
     968  volatile int    count;
     969  volatile time_t timestamp = tstamp;
    642970
    643971  dummy1 = &rule;
     
    6741002              {
    6751003                char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
    676                 sl_snprintf(emsg,  SH_ERRBUF_SIZE, _("Rule %d matches, result = %d"),
    677                             count, res);
     1004                if ( rule->flags & RFL_KEEP )
     1005                  sl_snprintf(emsg,  SH_ERRBUF_SIZE, _("Rule %d matches, result = %d (keep)"),
     1006                              count, res);
     1007                else
     1008                  sl_snprintf(emsg,  SH_ERRBUF_SIZE, _("Rule %d matches, result = %d"),
     1009                              count, res);
    6781010                SH_MUTEX_LOCK(mutex_thread_nolog);
    6791011                sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
     
    6821014                SH_FREE(emsg);
    6831015              }
    684             DEBUG("debug: rule %d matches, result = %d\n", count, res);
     1016
     1017            if ( rule->flags & RFL_KEEP )
     1018              {
     1019                DEBUG("debug: rule %d matches (keep)\n", count);
     1020                sh_keep_add(rule->label, rule->delay,
     1021                            timestamp == 0 ? time(NULL) : timestamp);
     1022              }
     1023
    6851024            break; /* return the matching rule; ovector is filled in */
    6861025          }
     
    6981037          }
    6991038        DEBUG("debug: rule %d did not match\n", count);
     1039
    7001040        rule = rule->nextrule; ++count;
    7011041      } while (rule);
     
    7141054
    7151055static struct sh_geval * test_grules (struct sh_heval * host,
    716                                       sh_string *msg)
     1056                                      sh_string       * msg,
     1057                                      time_t            timestamp)
    7171058{
    7181059  struct sh_geval * result = NULL;
     
    7261067      DEBUG("debug: if group\n");
    7271068      do {
    728         if(group->label != NULL)
     1069        if( (group->label != NULL) && (0 != (group->flags & RFL_ISGROUP)))
    7291070          {
    730             /* this is a rule group; only groups have labels */
     1071            /* this is a rule group */
    7311072
    7321073            if (flag_err_debug == SL_TRUE)
     
    7471088                          0, 0, NULL, 0) >= 0)
    7481089              {
    749                 result = test_rule(group->nextrule, msg);
     1090                result = test_rule(group->nextrule, msg, timestamp);
    7501091                if (result)
    7511092                  break;
     
    7701111
    7711112            DEBUG("debug: else (single rule)\n");
    772             result = test_rule(group, msg);
     1113            result = test_rule(group, msg, timestamp);
    7731114            if (result)
    7741115              break;
     
    7831124 */
    7841125static struct sh_geval * find_rule (sh_string *host,
    785                                     sh_string *msg)
     1126                                    sh_string *msg,
     1127                                    time_t     timestamp)
    7861128{
    7871129  struct sh_geval * result = NULL;
     
    7961138          {
    7971139            /* matching host, check rules/groups of rules */
    798             result = test_grules(hlist, msg);
     1140            result = test_grules(hlist, msg, timestamp);
    7991141            if (result)
    8001142              break;
     
    9941336    {
    9951337      struct sh_geval * rule = find_rule (record->host,
    996                                           record->message);
     1338                                          record->message,
     1339                                          record->timestamp);
    9971340
    9981341      if (rule)
  • trunk/src/sh_string.c

    r237 r260  
    238238{
    239239  return split_array_ws_int (line, nfields, lengths, SH_SPLIT_LIST);
     240}
     241
     242/* return a split() of a list contained in 'PREFIX\s*( list ).*'
     243 */
     244char ** split_array_braced (char *line, const char * prefix,
     245                            unsigned int * nfields, size_t * lengths)
     246{
     247  char * s = line;
     248  char * p;
     249
     250  while ( *s && isspace((int)*s) ) ++s;
     251  if (prefix && 0 != strncmp(s, prefix, strlen(prefix)))
     252    return NULL;
     253  s = &s[strlen(prefix)];
     254  while ( *s && isspace((int)*s) ) ++s;
     255  if (!s || (*s != '('))
     256    return NULL;
     257  ++s;
     258  p = strchr(s, ')');
     259  if (!p || (*p == *s))
     260    return NULL;
     261  *p = '\0';
     262  return split_array_list (s, nfields, lengths);
    240263}
    241264
Note: See TracChangeset for help on using the changeset viewer.