Пример #1
0
void
test_rule_action_message_tag(const gchar *pattern, gint timeout, gint ndx, const gchar *tag, gboolean set)
{
  LogMessage *msg = log_msg_new_empty();
  gboolean found, result;
  PDBInput input;

  log_msg_set_value(msg, LM_V_MESSAGE, pattern, strlen(pattern));
  log_msg_set_value(msg, LM_V_PROGRAM, "prog2", 5);
  log_msg_set_value(msg, LM_V_HOST, MYHOST, strlen(MYHOST));
  log_msg_set_value(msg, LM_V_PID, MYPID, strlen(MYPID));
  msg->timestamps[LM_TS_STAMP].tv_sec = msg->timestamps[LM_TS_RECVD].tv_sec;

  result = pattern_db_process(patterndb, PDB_INPUT_WRAP_MESSAGE(&input, msg));
  if (timeout)
    timer_wheel_set_time(patterndb->timer_wheel, timer_wheel_get_time(patterndb->timer_wheel) + timeout + 5);
  if (ndx >= messages->len)
    {
      test_fail("Expected the %d. message, but no such message was returned by patterndb\n", ndx);
      goto exit;
    }
  found = log_msg_is_tag_by_name((LogMessage *) g_ptr_array_index(messages, ndx), tag);

  if (set ^ found)
    test_fail("Tag '%s' is %sset for pattern '%s' (%d), index %d\n", tag, found ? "" : "not ", pattern, !!result, ndx);
exit:
  log_msg_unref(msg);
  test_clean_state();
}
Пример #2
0
static void
_advance_time(gint timeout)
{
  if (timeout)
    timer_wheel_set_time(pattern_db_get_timer_wheel(patterndb),
                         timer_wheel_get_time(pattern_db_get_timer_wheel(patterndb)) + timeout + 1);
}
Пример #3
0
/* NOTE: lock should be acquired for writing before calling this function. */
static void
_advance_time_based_on_message(PatternDB *self, PDBProcessParams *process_params, const LogStamp *ls)
{
  GTimeVal now;

  /* clamp the current time between the timestamp of the current message
   * (low limit) and the current system time (high limit).  This ensures
   * that incorrect clocks do not skew the current time know by the
   * correllation engine too much. */

  cached_g_current_time(&now);
  self->last_tick = now;

  if (ls->tv_sec < now.tv_sec)
    now.tv_sec = ls->tv_sec;

  /* the expire callback uses this pointer to find the process_params it
   * needs to emit messages.  ProcessParams itself is a per-thread value,
   * however the timer callback is executing with the writer lock held.
   * There's no other mechanism to pass this pointer to the timer callback,
   * so we add it to PatternDB, but make sure it is properly protected by
   * locks.
   * */
  self->timer_process_params = process_params;
  timer_wheel_set_time(self->timer_wheel, now.tv_sec);
  self->timer_process_params = NULL;

  msg_debug("Advancing patterndb current time because of an incoming message",
            evt_tag_long("utc", timer_wheel_get_time(self->timer_wheel)));
}
Пример #4
0
static gboolean
_is_action_within_rate_limit(PatternDB *db, PDBProcessParams *process_params)
{
  PDBRule *rule = process_params->rule;
  PDBAction *action = process_params->action;
  LogMessage *msg = process_params->msg;
  GString *buffer = process_params->buffer;

  CorrellationKey key;
  PDBRateLimit *rl;
  guint64 now;

  if (action->rate == 0)
    return TRUE;

  g_string_printf(buffer, "%s:%d", rule->rule_id, action->id);
  correllation_key_setup(&key, rule->context.scope, msg, buffer->str);

  rl = g_hash_table_lookup(db->rate_limits, &key);
  if (!rl)
    {
      rl = pdb_rate_limit_new(&key);
      g_hash_table_insert(db->rate_limits, &rl->key, rl);
      g_string_steal(buffer);
    }
  now = timer_wheel_get_time(db->timer_wheel);
  if (rl->last_check == 0)
    {
      rl->last_check = now;
      rl->buckets = action->rate;
    }
  else
    {
      /* quick and dirty fixed point arithmetic, 8 bit fraction part */
      gint new_credits = (((glong) (now - rl->last_check)) << 8) / ((((glong) action->rate_quantum) << 8) / action->rate);

      if (new_credits)
        {
          /* ok, enough time has passed to increase the current credit.
           * Deposit the new credits in bucket but make sure we don't permit
           * more than the maximum rate. */

          rl->buckets = MIN(rl->buckets + new_credits, action->rate);
          rl->last_check = now;
        }
    }
  if (rl->buckets)
    {
      rl->buckets--;
      return TRUE;
    }
  return FALSE;
}
Пример #5
0
/*
 * This function can be called any time when pattern-db is not processing
 * messages, but we expect the correllation timer to move forward.  It
 * doesn't need to be called absolutely regularly as it'll use the current
 * system time to determine how much time has passed since the last
 * invocation.  See the timing comment at pattern_db_process() for more
 * information.
 */
void
pattern_db_timer_tick(PatternDB *self)
{
  GTimeVal now;
  glong diff;
  PDBProcessParams process_params_p = {0};
  PDBProcessParams *process_params = &process_params_p;

  g_static_rw_lock_writer_lock(&self->lock);
  self->timer_process_params = process_params;
  cached_g_current_time(&now);
  diff = g_time_val_diff(&now, &self->last_tick);

  if (diff > 1e6)
    {
      glong diff_sec = (glong) (diff / 1e6);

      timer_wheel_set_time(self->timer_wheel, timer_wheel_get_time(self->timer_wheel) + diff_sec);
      msg_debug("Advancing patterndb current time because of timer tick",
                evt_tag_long("utc", timer_wheel_get_time(self->timer_wheel)));
      /* update last_tick, take the fraction of the seconds not calculated into this update into account */

      self->last_tick = now;
      g_time_val_add(&self->last_tick, - (glong)(diff - diff_sec * 1e6));
    }
  else if (diff < 0)
    {
      /* time moving backwards, this can only happen if the computer's time
       * is changed.  We don't update patterndb's idea of the time now, wait
       * another tick instead to update that instead.
       */
      self->last_tick = now;
    }
  self->timer_process_params = NULL;
  g_static_rw_lock_writer_unlock(&self->lock);
  _flush_emitted_messages(self, process_params);
}
Пример #6
0
static void
_execute_action_create_context(PatternDB *db, PDBProcessParams *process_params)
{
  CorrellationKey key;
  PDBAction *action = process_params->action;
  PDBRule *rule = process_params->rule;
  PDBContext *triggering_context = process_params->context;
  LogMessage *triggering_msg = process_params->msg;
  GString *buffer = process_params->buffer;
  PDBContext *new_context;
  LogMessage *context_msg;
  SyntheticContext *syn_context;
  SyntheticMessage *syn_message;

  syn_context = &action->content.create_context.context;
  syn_message = &action->content.create_context.message;
  if (triggering_context)
    {
      context_msg = synthetic_message_generate_with_context(syn_message, &triggering_context->super, buffer);
      log_template_format_with_context(syn_context->id_template,
                                       (LogMessage **) triggering_context->super.messages->pdata, triggering_context->super.messages->len,
                                       NULL, LTZ_LOCAL, 0, NULL, buffer);
    }
  else
    {
      context_msg = synthetic_message_generate_without_context(syn_message, triggering_msg, buffer);
      log_template_format(syn_context->id_template,
                          triggering_msg,
                          NULL, LTZ_LOCAL, 0, NULL, buffer);
    }

  msg_debug("Explicit create-context action, starting a new context",
            evt_tag_str("rule", rule->rule_id),
            evt_tag_str("context", buffer->str),
            evt_tag_int("context_timeout", syn_context->timeout),
            evt_tag_int("context_expiration", timer_wheel_get_time(db->timer_wheel) + syn_context->timeout));

  correllation_key_setup(&key, syn_context->scope, context_msg, buffer->str);
  new_context = pdb_context_new(&key);
  g_hash_table_insert(db->correllation.state, &new_context->super.key, new_context);
  g_string_steal(buffer);

  g_ptr_array_add(new_context->super.messages, context_msg);

  new_context->super.timer = timer_wheel_add_timer(db->timer_wheel, rule->context.timeout, pattern_db_expire_entry,
                                                   correllation_context_ref(&new_context->super),
                                                   (GDestroyNotify) correllation_context_unref);
  new_context->rule = pdb_rule_ref(rule);
}
Пример #7
0
void
pattern_db_advance_time(PatternDB *self, gint timeout)
{
  PDBProcessParams process_params_p = {0};
  PDBProcessParams *process_params = &process_params_p;
  time_t new_time;

  g_static_rw_lock_writer_lock(&self->lock);
  new_time = timer_wheel_get_time(self->timer_wheel) + timeout;
  self->timer_process_params = process_params;
  timer_wheel_set_time(self->timer_wheel, new_time);
  self->timer_process_params = NULL;
  g_static_rw_lock_writer_unlock(&self->lock);
  _flush_emitted_messages(self, process_params);
}
Пример #8
0
void
test_rule_action_message_value(const gchar *pattern, gint timeout, gint ndx, const gchar *name, const gchar *value)
{
  LogMessage *msg = log_msg_new_empty();
  gboolean found = FALSE, result;
  const gchar *val;
  gssize len;
  PDBInput input;

  log_msg_set_value(msg, LM_V_MESSAGE, pattern, strlen(pattern));
  log_msg_set_value(msg, LM_V_PROGRAM, "prog2", 5);
  log_msg_set_value(msg, LM_V_HOST, MYHOST, strlen(MYHOST));
  log_msg_set_value(msg, LM_V_PID, MYPID, strlen(MYPID));
  msg->timestamps[LM_TS_STAMP].tv_sec = msg->timestamps[LM_TS_RECVD].tv_sec;

  result = pattern_db_process(patterndb, PDB_INPUT_WRAP_MESSAGE(&input, msg));
  if (timeout)
    timer_wheel_set_time(patterndb->timer_wheel, timer_wheel_get_time(patterndb->timer_wheel) + timeout + 1);

  if (ndx >= messages->len)
    {
      test_fail("Expected the %d. message, but no such message was returned by patterndb\n", ndx);
      goto exit;
    }

  val = log_msg_get_value((LogMessage *) g_ptr_array_index(messages, ndx), log_msg_get_value_handle(name), &len);
  if (value)
    found = strcmp(val, value) == 0;

  if (!!value ^ (len > 0))
    test_fail("Value '%s' is %smatching for pattern '%s' (%d) index %d\n", name, found ? "" : "not ", pattern, !!result, ndx);

exit:
  log_msg_unref(msg);
  test_clean_state();
}
Пример #9
0
static void
pattern_db_expire_entry(TimerWheel *wheel, guint64 now, gpointer user_data)
{
  PDBContext *context = user_data;
  PatternDB *pdb = (PatternDB *) timer_wheel_get_associated_data(wheel);
  GString *buffer = g_string_sized_new(256);
  LogMessage *msg = correllation_context_get_last_message(&context->super);
  PDBProcessParams *process_params = pdb->timer_process_params;

  msg_debug("Expiring patterndb correllation context",
            evt_tag_str("last_rule", context->rule->rule_id),
            evt_tag_long("utc", timer_wheel_get_time(pdb->timer_wheel)));
  process_params->context = context;
  process_params->rule = context->rule;
  process_params->msg = msg;
  process_params->buffer = buffer;
  _execute_rule_actions(pdb, process_params, RAT_TIMEOUT);
  g_hash_table_remove(pdb->correllation.state, &context->super.key);
  g_string_free(buffer, TRUE);

  /* pdb_context_free is automatically called when returning from
     this function by the timerwheel code as a destroy notify
     callback. */
}
Пример #10
0
static void
_advance_time(gint timeout)
{
  if (timeout)
    timer_wheel_set_time(patterndb->timer_wheel, timer_wheel_get_time(patterndb->timer_wheel) + timeout + 1);
}
Пример #11
0
static void
_pattern_db_process_matching_rule(PatternDB *self, PDBProcessParams *process_params)
{
  PDBContext *context = NULL;
  PDBRule *rule = process_params->rule;
  LogMessage *msg = process_params->msg;
  GString *buffer = g_string_sized_new(32);

  g_static_rw_lock_writer_lock(&self->lock);
  _advance_time_based_on_message(self, process_params, &msg->timestamps[LM_TS_STAMP]);
  if (rule->context.id_template)
    {
      CorrellationKey key;

      log_template_format(rule->context.id_template, msg, NULL, LTZ_LOCAL, 0, NULL, buffer);
      log_msg_set_value(msg, context_id_handle, buffer->str, -1);

      correllation_key_setup(&key, rule->context.scope, msg, buffer->str);
      context = g_hash_table_lookup(self->correllation.state, &key);
      if (!context)
        {
          msg_debug("Correllation context lookup failure, starting a new context",
                    evt_tag_str("rule", rule->rule_id),
                    evt_tag_str("context", buffer->str),
                    evt_tag_int("context_timeout", rule->context.timeout),
                    evt_tag_int("context_expiration", timer_wheel_get_time(self->timer_wheel) + rule->context.timeout));
          context = pdb_context_new(&key);
          g_hash_table_insert(self->correllation.state, &context->super.key, context);
          g_string_steal(buffer);
        }
      else
        {
          msg_debug("Correllation context lookup successful",
                    evt_tag_str("rule", rule->rule_id),
                    evt_tag_str("context", buffer->str),
                    evt_tag_int("context_timeout", rule->context.timeout),
                    evt_tag_int("context_expiration", timer_wheel_get_time(self->timer_wheel) + rule->context.timeout),
                    evt_tag_int("num_messages", context->super.messages->len));
        }

      g_ptr_array_add(context->super.messages, log_msg_ref(msg));

      if (context->super.timer)
        {
          timer_wheel_mod_timer(self->timer_wheel, context->super.timer, rule->context.timeout);
        }
      else
        {
          context->super.timer = timer_wheel_add_timer(self->timer_wheel, rule->context.timeout, pattern_db_expire_entry,
                                                       correllation_context_ref(&context->super),
                                                       (GDestroyNotify) correllation_context_unref);
        }
      if (context->rule != rule)
        {
          if (context->rule)
            pdb_rule_unref(context->rule);
          context->rule = pdb_rule_ref(rule);
        }
    }
  else
    {
      context = NULL;
    }

  process_params->context = context;
  process_params->buffer = buffer;
  synthetic_message_apply(&rule->msg, &context->super, msg, buffer);

  _emit_message(self, process_params, FALSE, msg);
  _execute_rule_actions(self, process_params, RAT_MATCH);

  pdb_rule_unref(rule);
  g_static_rw_lock_writer_unlock(&self->lock);

  if (context)
    log_msg_write_protect(msg);

  g_string_free(buffer, TRUE);
}