#!/usr/bin/ruby class Unified attr_accessor :version attr_accessor :type, :version, :endian attr_accessor :fh FIELDS = { 1 => { 'log' => { 'type' => 'packet', 'pack' => 'N14', 'size' => 14 * 4, 'header_size' => 20, 'fields' => [ 'gid', 'sid', 'rev', 'classtype', 'priority', 'event_id', 'reference', 'tv_sec', 'tv_usec', 'flags', 'pkt_sec', 'pkt_usec', 'caplen', 'pktlen', 'pkt' ] }, 'alert' => { 'type' => 'event', 'size' => (4 * 13) + (2 * 2) + (4 * 2), 'pack' => 'N13n2N2', 'header_size' => 12, 'fields' => [ 'gid', 'sid', 'rev', 'classtype', 'priority', 'event_id', 'reference', 'tv_sec', 'tv_usec', 'tv_sec2', 'tv_usec2', 'source_ip', 'destination_ip', 'source_port', 'destination_port', 'protocol', 'flags' ] } }, 2 => { 1 => { 'type' => 'event', 'pack' => 'N11n2C', 'size' => (11 * 4) + (2 * 2) + 1, 'fields' => ['sensor_id', 'event_id', 'tv_sec', 'tv_usec', 'sig', 'gen', 'rev', 'classtype', 'priority', 'source_ip', 'destination_ip', 'source_port', 'destination_port', 'protocol' ] }, 2 => { 'type' => 'packet', 'pack' => 'N7', 'size' => (14 * 4), 'fields' => ['sensor_id', 'event_id', 'event_sec', 'tv_sec', 'tv_usec', 'link', 'caplen', 'pkt' ] }, 7 => { 'type' => 'event', 'pack' => 'N11n2C2', 'size' => (11 * 4) + (2 * 2) + 2, 'fields' => ['sensor_id', 'event_id', 'tv_sec', 'tv_usec', 'sig', 'gen', 'rev', 'classtype', 'priority', 'source_ip', 'destination_ip', 'source_port', 'destination_port', 'protocol', 'impact' ] }, } } def initialize(file) self.fh = File.open("#{file}", 'r') magic = self.fh.read(4) case magic when "\x80\x10\xad\xde" self.type = 'log' self.endian = 'little' self.version = 1 when "\x37\x41\xad\xde" self.type = 'alert' self.endian = 'little' self.version = 1 when "\xde\xad\x41\x37" self.type = 'alert' self.endian = 'big' self.version = 1 else self.type = 'combined' self.version = 2 self.endian = 'big' end if self.version == 1 self.header() else self.fh.seek(0) end end def fixpack(pack) if self.endian == 'little' pack.gsub!('N','V') pack.gsub!('n','v') end return pack end def header() size = FIELDS[self.version][self.type]['header_size'] self.fh.read(size) end def record() record = {} if self.version == 1 record['type'] = FIELDS[self.version][self.type]['type'] data = self.fh.read(FIELDS[self.version][self.type]['size']) if data.nil? || data.size != FIELDS[self.version][self.type]['size'] return nil end tmp = data.unpack(self.fixpack(FIELDS[self.version][self.type]['pack'])) FIELDS[self.version][self.type]['fields'].each_with_index { |field, index| record[field] = tmp[index] } if record['caplen'] record['pkt'] = self.fh.read(record['caplen']) end return record elsif self.version == 2 data = self.fh.read(8) if data.nil? || data.size != 8 return nil end type, len = data.unpack('NN') data = self.fh.read(len) if data.nil? || data.size != len return nil end if FIELDS[self.version][type].nil? record["type"] = type record["raw"] = data return record end record["type"] = FIELDS[self.version][type]['type'] tmp = data.unpack(self.fixpack(FIELDS[self.version][type]['pack'])) FIELDS[self.version][type]['fields'].each_with_index { |field, index| record[field] = tmp[index] } if record['caplen'] record['pkt'] = data[FIELDS[self.version][type]['size']..-1] end return record end end end #ARGV.each { |file| # unified = Unified.new(file) # print "FILE:#{file} VERSION:#{unified.version} TYPE:#{unified.type} ENDIAN:#{unified.endian}\n"; # while (record = unified.record()) # p record # end #}