#-- # Copyright (C) 2016 Wolfgang Hotwagner # # This file is part of the suricata gem # # This mindwave gem is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This gem is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this gem; if not, write to the # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301 USA #++ module Suricata require 'suricata/logfile' require 'suricata/fast' require 'optparse' # This class offers all functionalities for a suricata-nagios-plugin class Nagios # @!attribute fast # this attribute stores the Suricata::Logfile-object # @!attribute found_str # this attribute stores the string found by search() in the Logfile-object # @!attribute search_str # the search-pattern is stored in this attribute attr_reader :fast, :found_str, :search_str # @!attribute whitelist # this whitelist can be used to exclude results from the search # @!attribute alertfile # this alertfile(fast.log) is used for the search # @!attribute return_found # this value is returned from search() on succes. (Default: 2) # @!attribute return_notfound # this value is returned from search() on failure (Default: 0) # @!attribute ack # it is possible to acknowlege alerts, so that they will be # excluded from the next search. Use this member to set the acknowlege-file. # Default ack-file is: /tmp/surack.lst attr_accessor :whitelist, :alertfile, :return_found, :return_notfound, :ack # constructor # @param [String] alertfile path to the suricata-log-file(default: /var/log/suricata/fast.log) # @param [String] whitelist path to the whitelist(default: nil) def initialize(alertfile="/var/log/suricata/fast.log",whitelist=nil) @whitelist = whitelist @alertfile = alertfile @return_found = 2 @return_notfound = 0 @ack = "/tmp/surack.lst" end # this method initializes the Suricata::Logfile(@fast) and opens # the @alertfile # @see alertfile def init_log @fast = Suricata::Logfile.new(@alertfile) end # this is the check_suricata-application. this function exits with 3 # on error # @param [Array] args typically ARGV # @return [Integer] @return_found if searchstring was found # @return [Integer] @return_notfound if searchstring was not found # @see return_found # @see return_notfound def runApp(args) help = nil interactive = false OptionParser.new do |opt| opt.banner = "Usage: #{$PROGRAM_NAME} [ -a alertfile ] [ -w whitelistfile ] -e searchstring" opt.on('-h', '--help', 'This help screen') do $stderr.puts opt exit 3 end opt.on('-a','--alertfile ALERTFILE','alertfile(default: /var/log/suricata/fast.log)') { |o| @alertfile = o } opt.on('-w','--whitelist WHITELISTFILE','whitelistfile') { |o| @whitelist = o } opt.on('-e','--search STRING','searchstring') { |o| @search_str = o } opt.on('-i','--interactive','interactive acknowleges') { |o| interactive = o } opt.on('-k','--ackfile ACKFILE','ackfile(default: /tmp/surack.lst)') { |o| @ack = o } help = opt.help end.parse!(args) if @search_str.nil? $stderr.puts help exit 3 end if interactive acknowlege(@search_str) exit 3 end ret = search(@search_str) if ret > 0 puts "FOUND" else puts "OK" end exit ret end # this method performs a search(str). It will ask interactively for ever # hit if it should be acknowleged. In case of "yes", the routine will # add a shortform of the entry to the acknowlege-file # @param [String] str string to search # @see ack def acknowlege(str) if @fast.nil? init_log end list = File.open(@ack,'a') @fast.readline_parse do |fast_entry| if fast_entry.description =~ /#{str}/ if not search_list("#{fast_entry.timestamp} #{fast_entry.id} #{fast_entry.conn}",@ack) printf("Acknowlege the following entry:\n") printf("#{fast_entry}\n") printf("Acknowlege(y|n): ") answer = STDIN.gets if answer == "y\n" list.write("#{fast_entry.timestamp} #{fast_entry.id} #{fast_entry.conn}\n") end end end end list.close end # this function performs a search for a string(str) # in the alert-file. If a whitelistfile is given, # or a acknowlege-file, it will search those files # too and eventually exclude the hit from the result. # @param [String] str search-query # @return [Integer] @return_found on success # @return [Integer] @return_notfound on failure # @see return_found # @see return_notfound # @see ack # @see whitelist def search(str) @search_str = str @found_str = nil if @fast.nil? init_log end wl_found = false ack_found = false @fast.readline_parse do |fast_entry| if fast_entry.description =~ /#{@search_str}/ if not @whitelist.nil? wl_found = search_list(fast_entry.description,@whitelist) end if not @ack.nil? and File.file?(@ack) ack_found = search_list("#{fast_entry.timestamp} #{fast_entry.id} #{fast_entry.conn}",@ack) end if wl_found == false and ack_found == false @found_str = fast_entry.description return @return_found end end end @fast.close return @return_notfound end private # this function performs a search for a line in a file # @param [String] str search-query # @param [String] listfile file to search # @return [Boolean] true if it succeded # @return [Boolean] false if it did not succed def search_list(str,listfile) list = File.open(listfile,'r') begin while entry = list.readline entry = entry.chomp if str =~ /#{entry}/ list.close return true end end rescue EOFError end list.close return false end end end