Skip to content

Instantly share code, notes, and snippets.

@sstelfox
Last active August 29, 2015 14:11
Show Gist options
  • Save sstelfox/0e9fc22b32af26e22fa1 to your computer and use it in GitHub Desktop.
Save sstelfox/0e9fc22b32af26e22fa1 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
require 'csv'
require 'liquid'
require 'ostruct'
module Engine
def self.compound(name = nil, &blk)
rule_list.push(CompoundRule.new(name, &blk))
end
def self.evaluate_obj(obj)
rule_list.each { |r| r.evaluate_obj(obj) }
end
def self.rule(name = nil, &blk)
rule_list.push(StandardRule.new(name = nil, &blk))
end
def self.rule_list
@rule_list ||= []
end
end
module ShortcutMatches
def offline
match { status == "offline" }
end
def online
match { status == "online" }
end
end
module RuleCommons
def alert(msg)
@alert_msg = msg
end
def print_alert(obj)
string_keyed_obj = Hash[obj.to_h.map { |k, v| [k.to_s, v] }]
puts Liquid::Template.parse(@alert_msg).render(string_keyed_obj)
end
end
class CompoundRule
include RuleCommons
def evaluate_obj(obj)
return false unless @enabled
if @matcher.call(@rules.map { |r| r.evaluate_obj(obj) })
print_alert(obj) if @alert_msg
end
end
def disable
@enabled = false
end
def initialize(name = nil, &blk)
@enabled = true
@name = name
@rules = []
instance_eval(&blk) if block_given?
end
def rule(&blk)
@rules.push(StandardRule.new(&blk))
end
def true_if(&blk)
@matcher = blk
end
end
class StandardRule
include ShortcutMatches
include RuleCommons
def disable
@enabled = false
end
def evaluate_obj(obj)
return false unless @enabled
@matches.each do |m|
# Break out of our rule checking as soon as one fails
return false unless (obj.instance_eval(&m) rescue false)
end
# All rules passed
print_alert(obj) if @alert_msg
true
end
def initialize(name = nil, &blk)
@enabled = true
@name = name
@matches = []
instance_eval(&blk) if block_given?
end
def match(&blk)
@matches.push(blk)
end
end
Engine.rule do
online
match { protocol == 'tcp' && port == '22' }
alert "Detected an SSH server on a network host (ID: {{ id }})"
end
Engine.evaluate_obj(OpenStruct.new(sensor: '1', protocol: 'tcp', port: '22', status: 'offline', id: '12'))
Engine.evaluate_obj(OpenStruct.new(sensor: '2', protocol: 'tcp', port: '22', status: 'online', id: '5'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment