Class: REC::Rule

Inherits:
Object show all
Defined in:
lib/rec/rule.rb

Overview

A Rule specifies which log entries to match, what to remember, and what to do about them.

Constant Summary collapse

@@rules =
[]
@@index =

hash index of rules to allow lookup of messages etc.

{}
@@checked =
{}
@@matched =
{}
@@created =
{}
@@reacted =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rid, params = {}, &action) ⇒ Rule

Creates a new rule. rid must be unique. action may be supplied as a block argument: :lifespan => 479 }) { |state| state.alert_first_only() } or as a Proc.new value to the :action key: :lifespan => 479, :action => Proc.new { |state| state.alert_first_only() } }) In most cases, an action is required when a state reacts with an event, but only in certain cases do we need an :onexpiry block. That is why the action may be supplied as a block if desired.



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/rec/rule.rb', line 94

def initialize(rid, params={}, &action)
	@rid = rid
	@pattern = params[:pattern] || raise("No pattern specified for rule #{@ruleId}")
	@message = params[:message] || ""	# no message means no state created - ie. ignore event
	@lifespan = params[:lifespan] || 0
	@allstates = params[:allstates] || []
	@anystates = params[:anystates] || []
	@notstates = params[:notstates] || []
	@details = params[:details] || []
	@params = params
	@params[:action] = action unless action.nil?	# store the action into the params
	@params[:alert] = @params[:message] unless @params.has_key?(:alert)	# default alert if absent
	@matches = nil
	Rule << self
end

Instance Attribute Details

#alertObject (readonly)

the template for an alert message to be generated should it be necessary



61
62
63
# File 'lib/rec/rule.rb', line 61

def alert
  @alert
end

#lifespanObject (readonly)

the time in seconds for a created state to persist



59
60
61
# File 'lib/rec/rule.rb', line 59

def lifespan
  @lifespan
end

#messageObject (readonly)

the template for the title of any state created. :message => “sudo activity for user %userid$s”, will create states with titles like “sudo activity for user richard”



57
58
59
# File 'lib/rec/rule.rb', line 57

def message
  @message
end

#paramsObject (readonly)

hash of the rules parameters, passed in when creating the rule



63
64
65
# File 'lib/rec/rule.rb', line 63

def params
  @params
end

#patternObject (readonly)

the regexp pattern to match an original log entry against :pattern => /^sw+sFirewall:sSkype is listening from 0.0.0.0:(d+)/, :details => [”port“], Note that regexp captures must correspond to customer field names in details



53
54
55
# File 'lib/rec/rule.rb', line 53

def pattern
  @pattern
end

#ridObject (readonly)

the unique ID of the rule



48
49
50
# File 'lib/rec/rule.rb', line 48

def rid
  @rid
end

Class Method Details

.<<(rule) ⇒ Object

Adds a rule to the ruleset



22
23
24
25
26
27
28
29
# File 'lib/rec/rule.rb', line 22

def self.<<(rule)
	@@rules << rule
	@@index[rule.rid] = rule
	@@checked[rule.rid] = 0
	@@matched[rule.rid] = 0
	@@created[rule.rid] = 0
	@@reacted[rule.rid] = 0
end

.[](rid) ⇒ Object

Get a rule belonging to the key of rid



32
33
34
# File 'lib/rec/rule.rb', line 32

def self.[](rid)
	@@index[rid]
end

.each(&block) ⇒ Object

Convenience method to iterate through the ruleset



17
18
19
# File 'lib/rec/rule.rb', line 17

def self.each(&block)
	@@rules.each(&block)
end

.statsObject

Returns some summary statistics in a 5-element array, the first four elements a hash keyed on rule ID, the fifth is an array of rules:

  1. number of times each rule was checked

  2. number of times each rule was matched

  3. number of states created by each rule

  4. number of times #react was called on each rule

  5. list of rules, evaluated in sequence for each event



43
44
45
# File 'lib/rec/rule.rb', line 43

def self.stats()
	[@@checked, @@matched, @@created, @@reacted, @@rules]
end

Instance Method Details

#actionObject

block to be executed when #react is called. For example: Rule.new(10035, { :pattern => /^sw+sFirewall:sSkype is listening from 0.0.0.0:(d+)/, :details => [”port“], :message => ”Skype conversation started on port %port$d“, :alert => ”Skype running on port %port$d“, :lifespan => 479 }) { |state| state.alert_first_only() }



74
75
76
# File 'lib/rec/rule.rb', line 74

def action()
	@params[:action]
end

#check(logMessage) ⇒ Object

Checks the original logMessage against the rule, looking for a match. Returns a boolean (true if entry matched the pattern), and a string



112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/rec/rule.rb', line 112

def check(logMessage)
	@@checked[@rid] += 1
	return [false, nil] unless matchData = @pattern.match(logMessage)
	@matches = Hash[@details.zip(matchData.to_a()[1..-1])]	# map matched values to detail keys
	# if any notstates are specified, make sure none are present
	@notstates.each { |str| return([true, nil]) if State[str.sprinth(@matches)]	}
	# if any allstates are specified, they all need to be present
	@allstates.each { |str| return([true, nil]) unless State[str.sprinth(@matches)]	}
	# if anystates are specified, we must find one that matches
	return([true, nil]) unless @anystates.empty? or @anystates.detect {|str| State[str.sprinth(@matches)] }
	title = @message.sprinth(@matches)
	@@matched[@rid] += 1
	return([true, title])
end

#continueObject

Returns the continue parameter. If false, stop processing rules for this event.



143
144
145
# File 'lib/rec/rule.rb', line 143

def continue()
	@params[:continue]
end

#create_state(title) ⇒ Object

Creates a state with the given title at the specified time



128
129
130
131
132
# File 'lib/rec/rule.rb', line 128

def create_state(title)
	@@created[@rid] += 1
	$stderr.puts("+ Creating new state  #{title}") if $debug
	State.new(title, @lifespan, @params)
end

#react(state, logLine) ⇒ Object

Executes any action specified by the rule



135
136
137
138
139
140
# File 'lib/rec/rule.rb', line 135

def react(state, logLine)
	@@reacted[@rid] += 1
	state.update(@rid, @matches, logLine)
	$stderr.puts("~ Rule #{@rid}, state = #{state.inspect()}") if $debug
	action().call(state) if action()
end