Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- require 'socket'
- require 'time'
- require 'og'
- class Logger
- def self.method_missing(sym, *args)
- $stderr.puts "#{sym.to_s.upcase} #{args.join(', ')}"
- end
- end
- class ClamScanner
- class ScannerException < RuntimeError
- def initialize(message)
- Logger.error(message)
- end
- end
- attr_accessor :socket, :result
- def initialize
- @socket = '/var/run/clamav/clamd.sock'
- end
- def check
- res = talk("PING")
- if(res !~ /PONG$/)
- Logger.error("check failed: erroneous clam answer: #{res}")
- return false
- end
- return true
- end
- def scan(path)
- if(@result)
- Logger.info("reusing previous scan result: <#{@result}> of:
- <#{path}>")
- else
- begin
- res = talk("SCAN #{path}")
- rescue ScannerException
- Logger.error("unable to scan message: #{path}")
- return nil
- end
- if res =~ /: (.*) FOUND$/
- Logger.info("virus: #{$1} in: #{path}")
- @result = $1;
- elsif res =~ /: (Zip module failure) ERROR$/
- Logger.info("broken zip in #{path}")
- @result = 'Broken.ZIP.Archive'
- elsif res =~ /OK$/
- Logger.info("no virus detected in: #{path}")
- @result = 'clean'
- else
- Logger.error("unknown clam resource problem: #{$1}: when
- scanning: #{path}")
- return nil
- end
- end
- return @result
- end # end scan
- def talk(msg)
- data = nil
- session = nil
- if msg.nil?
- raise ScannerException.new("method called with empty args")
- end
- begin
- session = UNIXSocket.new(@socket)
- session.send(msg,0)
- data = session.recvfrom(512)[0] # [0] ensures we only get clam's respons
- session.close()
- rescue
- raise ScannerException.new("unable to use socket: #{@socket}")
- end
- return data
- end # end talk
- end
- class ClamavScanResult
- is Timestamped
- property :path, String
- property :result, String
- end
- class UploadedFile
- attr_reader :date, :transfertime, :remotecomputer, :filesize, :filename, :transfertype, :actionflag, :direction, :accessmode, :username, :servicename, :authentication, :id, :complete
- def initialize(options)
- options.each do |key, value|
- instance_variable_set("@#{key}", value)
- end
- end
- # In der angegeben Datei (hier eben: /var/log/proftpd.xferlog) werden
- # folgende Werte geloggt:
- #
- # * aktuelle Zeit
- # * Uebertragungszeit in Sekunden
- # * Name des Remote Computers
- # * Dateigroesse
- # * Dateiname
- # * Transfertyp ("a": Ascii; "b": Binary)
- # * Aktion Flag ("C": Datei war komprimiert; "U": Datei war unkomprimiert;
- # "T": Tarball)
- # * Richtung ("o": Outgoing; "i": incoming, "d": Delete)
- # * Zugriffsmode ("a": Anonym; "r": richtiger User)
- # * Username (Achtung bei Anonym das uebergebene Passwort)
- # * Service Name (normalerweise "FTP")
- # * Authentifizierungsmethode ("0": keine; "1": RFC931 Authentication)
- # * Rueckmelde ID ("*": wenn keine Rueckmelde ID kam)
- # * Komplett ("c": komplett; "i": nicht komlett). Achtung: uploads sind
- # immer "c", da ProFTPD nicht erkennen kann, wann das Ende kommt
- #
- # Example:
- #
- # Tue Dec 12 16:40:20 2006 0 port-212-202-55-195.dynamic.qsc.de 245
- # /home/BGB1-Jemenit/build/.autotest b _ i r BGB1-Jemenit ftp 1 * c
- def self.parse(line)
- line.strip!
- date, transfertime, remotecomputer, filesize, filename, transfertype, actionflag, direction, accessmode, username, servicename, authentication, id, complete =
- line.scan(/
- (\w+\s+\w+\s+\d+\s+\d+:\d+:\d+\s\d+)\s+ # date
- (\d+)\s+ # transfertime
- ([^\s]*)\s+ # remotecomputer
- (\d+)\s+ # filesize
- (.*?)\s+ # filename
- ([ab])\s+ # transfertype
- ([CUT_])\s+ # actionflag
- ([oid])\s+ # direction
- ([ar])\s+ # accessmode
- ([^\s]+)\s+ # username
- (\w+)\s+ # servicename
- ([01])\s+ # authentication
- ([^\s])\s+ # id
- ([ci]) # complete
- /mix).first
- date = Time.parse(date)
- transfertime = transfertime.to_i
- filesize = filesize.to_i
- complete = (complete == 'c' ? true : false)
- options = {
- :date => date,
- :transfertime => transfertime,
- :remotecomputer => remotecomputer,
- :filesize => filesize,
- :filename => filename,
- :transfertype => transfertype,
- :actionflag => actionflag,
- :direction => direction,
- :accessmode => accessmode,
- :username => username,
- :servicename => servicename,
- :authentication => authentication,
- :id => id,
- :complete => complete
- }
- UploadedFile.new(options)
- end
- end
- Og.start(:store => :mysql, :name => 'clamavdb', :user => 'testuser',
- :password => 'private', :classes => [ClamavScanResult])
- if $0 == __FILE__
- if DEBUG
- # test scanner
- clamav = ClamScanner.new
- if !clamav.check
- Logger.error("Clamav probably not running")
- exit(1)
- end
- end
- while io = select([$stdin])
- next unless io[0][0].kind_of?(IO) rescue nil
- line = io[0][0].readline.chomp
- file = UploadedFile.parse(line)
- res = clamav.scan(file.filename)
- ClamavScanResult.create_with(:path => file.filename, :result => res)
- end
- end
Add Comment
Please, Sign In to add comment