grok 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.rdoc CHANGED
@@ -3,7 +3,7 @@
3
3
  Grok aims to be a replacement for the now antiquated SEC (Simple Event
4
4
  Correlator).
5
5
 
6
- == Usage
6
+ == Getting started
7
7
  A simple Grok watcher needs very little in the way of configuration
8
8
  require 'grok'
9
9
 
@@ -37,8 +37,26 @@ RegExp functionality in the event handlers
37
37
  puts "SSH authentication failure for #{username} from #{ip}"
38
38
  end
39
39
 
40
- This is a bit better. You could go further to have it automatically block the
41
- IP with iptables if you wanted (see examples/ssh_sentry.rb).
40
+ This is a bit better. It seems a bit unfair to block someone for a single typo
41
+ though, so why don't we give them three tries before blocking them?
42
+
43
+ on /sshd\[\d+\]: Failed password for ([\d\w]+) from ([\d\.]+)/, :times => 3 do |username, ip|
44
+ puts "SSH authentication failure for #{username} from #{ip}"
45
+ end
46
+
47
+ Getting there. What if our user failed a couple of times over the past month?
48
+ We don't really want to him out for that, so we'll put a time limit on the rule
49
+ so only 3 incorrect login attempts within the past 2 minutes will trigger it.
50
+
51
+ on /sshd\[\d+\]: Failed password for ([\d\w]+) from ([\d\.]+)/, :times => 3, :withn => '2m' do |username, ip|
52
+ puts "SSH authentication failure for #{username} from #{ip}"
53
+ end
54
+
55
+ Your time string can be made of any combination of years (y), months (M),
56
+ weeks (w), days (d), hours (h), minutes (m) and seconds (s). For example
57
+
58
+ '1d2h3s' => 1 day, 2 hours and 3 seconds
59
+ '2y3m' => 2 years and 3 minutes
42
60
 
43
61
  == Note on Patches/Pull Requests
44
62
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
@@ -6,6 +6,6 @@ configure do |c|
6
6
  c.replay = 0
7
7
  end
8
8
 
9
- on /Failed password for root from ([\d\.]+)/ do |ip|
9
+ on /Failed password for root from ([\d\.]+)/, :times => 3, :within => '2m' do |ip|
10
10
  ret = `/sbin/iptables -I INPUT --source #{ip} -j REJECT`
11
11
  end
data/lib/grok.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'grok/watcher'
2
+ require 'grok/time'
2
3
 
3
4
  $watcher = Grok::Watcher.new
4
5
 
data/lib/grok/time.rb ADDED
@@ -0,0 +1,57 @@
1
+ # This bit of code has been shamelessly stolen from rufus-scheduler because
2
+ # it's awesome.
3
+
4
+ module Grok
5
+ def Grok.parse_time_string(string)
6
+ string = string.strip
7
+ index = -1
8
+ result = 0.0
9
+
10
+ number = ''
11
+ loop do
12
+ index = index+1
13
+
14
+ if index >= string.length
15
+ result += (Float(number) / 1000.0) if number.length > 0
16
+ break
17
+ end
18
+
19
+ c = string[index, 1]
20
+
21
+ if (c >= '0' and c <= '9')
22
+ number += c
23
+ next
24
+ end
25
+
26
+ value = Integer(number)
27
+ number = ''
28
+ multiplier = DURATIONS[c]
29
+
30
+ raise "unknown time char '#{c}'" unless multiplier
31
+
32
+ result += (value * multiplier)
33
+ end
34
+
35
+ result
36
+ end
37
+
38
+ protected
39
+
40
+ DURATIONS2M = [
41
+ [ 'y', 365 * 24 * 3600 ],
42
+ [ 'M', 30 * 24 * 3600 ],
43
+ [ 'w', 7 * 24 * 3600 ],
44
+ [ 'd', 24 * 3600 ],
45
+ [ 'h', 3600 ],
46
+ [ 'm', 60 ],
47
+ [ 's', 1 ]
48
+ ]
49
+
50
+ DURATIONS2 = DURATIONS2M.dup
51
+ DURATIONS2.delete_at(1)
52
+
53
+ DURATIONS = DURATIONS2M.inject({}) do |r, (k, v)|
54
+ r[k] = v
55
+ r
56
+ end
57
+ end
data/lib/grok/watcher.rb CHANGED
@@ -9,6 +9,7 @@ module Grok
9
9
 
10
10
  def initialize(&b)
11
11
  @events = {}
12
+ @event_log = {}
12
13
  @config = Config.new("/var/log/messages", 10)
13
14
 
14
15
  #instance_eval(&b) if block_given?
@@ -21,7 +22,8 @@ module Grok
21
22
  def on(match, opts={}, &block)
22
23
  event = :log
23
24
  match = match.to_s if match.is_a? Integer
24
- (@events[event] ||= []) << [Regexp.new(match), block]
25
+ within = opts[:within] ? Grok.parse_time_string(opts[:within]) : nil
26
+ (@events[event] ||= []) << [Regexp.new(match), block, opts[:times], within]
25
27
  end
26
28
 
27
29
  def start
@@ -61,9 +63,23 @@ module Grok
61
63
 
62
64
  def dispatch(event, log)
63
65
  if handler = find(event, log)
64
- regexp, block = *handler
66
+ regexp, block, times, within = *handler
65
67
  self.match = log.match(regexp).captures
66
- invoke block
68
+ (@event_log[match] ||= []) << Time.now.to_i
69
+ if @event_log[match].length >= times.to_i
70
+ if within:
71
+ times_within_range = @event_log[match].reject { |event_time|
72
+ event_time < (Time.now.to_i - within)
73
+ }
74
+ if times_within_range.length >= times.to_i
75
+ invoke block
76
+ @event_log[match].clear
77
+ end
78
+ else
79
+ invoke block
80
+ @event_log[match].clear
81
+ end
82
+ end
67
83
  end
68
84
  end
69
85
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grok
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Sharpe
@@ -50,6 +50,7 @@ files:
50
50
  - VERSION
51
51
  - examples/ssh_sentry.rb
52
52
  - lib/grok.rb
53
+ - lib/grok/time.rb
53
54
  - lib/grok/watcher.rb
54
55
  - test/helper.rb
55
56
  - test/test_grok.rb