cef 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.1
1
+ 0.7.0
@@ -3,19 +3,18 @@ require 'rubygems'
3
3
  require 'cef'
4
4
  require 'getoptlong'
5
5
 
6
- sender=CEF::Sender.new
7
-
8
- e=CEF::Event.new
9
6
  @verbose=0
10
7
  @file=nil
8
+ cef_event=CEF::Event.new
11
9
  opts=GetoptLong.new(
12
- ["--verbose", GetoptLong::OPTIONAL_ARGUMENT],
13
- ["--help", GetoptLong::OPTIONAL_ARGUMENT],
14
- ["--schema", GetoptLong::OPTIONAL_ARGUMENT],
10
+ ["--verbose", GetoptLong::OPTIONAL_ARGUMENT],
11
+ ["--help", GetoptLong::OPTIONAL_ARGUMENT],
12
+ ["--schema", GetoptLong::OPTIONAL_ARGUMENT],
15
13
  ["--receiver", GetoptLong::OPTIONAL_ARGUMENT],
16
- ["--receiverPort", GetoptLong::OPTIONAL_ARGUMENT],
17
- ["--append-file", GetoptLong::OPTIONAL_ARGUMENT],
18
- *e.attrs.keys.collect {|o| ["--#{o}", GetoptLong::OPTIONAL_ARGUMENT]}
14
+ ["--receiverPort", GetoptLong::OPTIONAL_ARGUMENT],
15
+ ["--append-file", GetoptLong::OPTIONAL_ARGUMENT],
16
+ ["--tcp", GetoptLong::OPTIONAL_ARGUMENT],
17
+ *cef_event.attrs.keys.collect {|o| ["--#{o}", GetoptLong::OPTIONAL_ARGUMENT]}
19
18
  )
20
19
 
21
20
  def print_usage
@@ -27,6 +26,8 @@ Usage: cef_sender --sourceAddress="192.168.1.1" [--eventAttribute="something"]
27
26
  --schema will dump all of the callable event attribute names
28
27
  --receiver= syslog receiver hostname/ip
29
28
  --receiverPort= syslog port
29
+ --append-file= filename to append cef message to
30
+ --tcp will use TCP instead of the default (UDP) to send the message
30
31
 
31
32
  cef_sender will send CEF-formatted syslog messages to a receiver of your choice.
32
33
  only the cef fields defined in the cef reader flex connector are supported.
@@ -36,10 +37,11 @@ END_USAGE
36
37
 
37
38
  end
38
39
 
39
- def print_schema(e)
40
- e.attrs.keys.collect {|k| k.to_s}.sort.each {|a| puts a}
40
+ def print_schema(event)
41
+ event.attrs.keys.collect {|k| k.to_s}.sort.each {|a| puts a}
41
42
  end
42
43
 
44
+
43
45
  opts.each do |opt,arg|
44
46
  # TODO: set up cases for startTime, receiptTime, endTime to parse
45
47
  # text and convert to unix time * 1000
@@ -47,12 +49,12 @@ opts.each do |opt,arg|
47
49
  when "--verbose"
48
50
  @verbose+=1
49
51
  when "--schema"
50
- print_schema(e)
52
+ print_schema(cef_event)
51
53
  exit(0)
52
54
  when "--receiverPort"
53
- sender.receiverPort=arg
55
+ @receiver_port=arg
54
56
  when "--receiver"
55
- sender.receiver=arg
57
+ @receiver_host=arg
56
58
  when "--help"
57
59
  print_usage
58
60
  exit(0)
@@ -61,10 +63,16 @@ opts.each do |opt,arg|
61
63
  else
62
64
  fieldname = opt.gsub(/-/,'')
63
65
  value=arg
64
- e.send("#{fieldname}=",value)
66
+ cef_event.send("%s=" % fieldname, value)
65
67
  end
66
68
  end
67
- msg=sender.format_event(e)
69
+
70
+ cef_sender=CEF::UDPSender.new
71
+ cef_sender.receiver=@receiver_host
72
+ cef_sender.receiverPort=@receiver_port
73
+
74
+
75
+ msg=cef_event.format_cef
68
76
 
69
77
 
70
78
  if @verbose>0
@@ -73,5 +81,5 @@ end
73
81
  if !(@file.nil?) && File.exists?(@file)
74
82
  @file.write "%s\n" % msg.gsub(/^<\d+>/,'')
75
83
  else
76
- sender.emit(e)
84
+ cef_sender.emit(cef_event)
77
85
  end
@@ -0,0 +1,73 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{cef}
8
+ s.version = "0.7.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Ryan Breed"]
12
+ s.date = %q{2011-03-11}
13
+ s.default_executable = %q{cef_sender}
14
+ s.description = %q{ format/send CEF logs via API+syslog or client program }
15
+ s.email = %q{opensource@breed.org}
16
+ s.executables = ["cef_sender"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE.txt",
19
+ "README.rdoc"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".rspec",
24
+ "Gemfile",
25
+ "LICENSE.txt",
26
+ "README.rdoc",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "bin/cef_sender",
30
+ "cef.gemspec",
31
+ "lib/cef.rb",
32
+ "lib/cef/constants.rb",
33
+ "lib/cef/event.rb",
34
+ "lib/cef/file_logger.rb",
35
+ "lib/cef/sender.rb",
36
+ "spec/cef_spec.rb",
37
+ "spec/spec_helper.rb"
38
+ ]
39
+ s.homepage = %q{http://github.com/ryanbreed/cef}
40
+ s.licenses = ["MIT"]
41
+ s.require_paths = ["lib"]
42
+ s.rubygems_version = %q{1.5.2}
43
+ s.summary = %q{CEF Generation Library and Client}
44
+ s.test_files = [
45
+ "spec/cef_spec.rb",
46
+ "spec/spec_helper.rb"
47
+ ]
48
+
49
+ if s.respond_to? :specification_version then
50
+ s.specification_version = 3
51
+
52
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
53
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
54
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
55
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
56
+ s.add_development_dependency(%q<rcov>, [">= 0"])
57
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
58
+ else
59
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
60
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
61
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
62
+ s.add_dependency(%q<rcov>, [">= 0"])
63
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
64
+ end
65
+ else
66
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
67
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
68
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
69
+ s.add_dependency(%q<rcov>, [">= 0"])
70
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
71
+ end
72
+ end
73
+
data/lib/cef.rb CHANGED
@@ -1,274 +1,10 @@
1
1
  module CEF
2
2
  require 'socket'
3
3
  require 'parsedate'
4
- PREFIX_FORMAT="<%d>%s %s CEF:0|%s|%s"
5
- VERSION=File.read(File.join(File.expand_path(File.dirname(__FILE__)),'..','VERSION'))
6
-
7
-
8
- # CEF Dictionary
9
- # CEF Prefix attributes
10
- PREFIX_ATTRIBUTES = {
11
- :deviceVendor => "deviceVendor",
12
- :deviceVersion => "deviceVersion",
13
- :deviceProduct => "deviceProduct",
14
- :name => "name",
15
- :deviceSeverity => "deviceSeverity",
16
- :deviceEventClassId => "deviceEventClassId"
17
- }
18
-
19
- # these are the basic extension attributes. implementing others is as
20
- # simple as adding :symbolRepresentingMethodName => "cefkeyname", but
21
- # i am supremely lazy to type in the whole dictionary right now. perhaps
22
- # this should be a .yaml config file. Extension attributes are formatted
23
- # differently than core attributes.
24
- EXTENSION_ATTRIBUTES = {
25
- :applicationProtocol => "app",
26
- :baseEventCount => "cnt",
27
- :bytesIn => "in",
28
- :bytesOut => "out",
29
- :deviceAction => "act",
30
- :deviceHostNam => "dvc",
31
- :deviceNtDomain => "deviceNtDomain",
32
- :deviceDnsDomain => "deviceDnsDomain",
33
- :deviceTranslatedAddress => "deviceTranslatedAddress",
34
- :deviceMacAddress => "deviceMacAddress",
35
- :deviceCustomNumber1 => "cn1",
36
- :deviceCustomNumber2 => "cn2",
37
- :deviceCustomNumber3 => "cn3",
38
- :deviceCustomNumber1Label => "cn1Label",
39
- :deviceCustomNumber2Label => "cn2Label",
40
- :deviceCustomNumber3Label => "cn3Label",
41
- :deviceCustomString1 => "cs1",
42
- :deviceCustomString2 => "cs2",
43
- :deviceCustomString3 => "cs3",
44
- :deviceCustomString4 => "cs4",
45
- :deviceCustomString5 => "cs5",
46
- :deviceCustomString6 => "cs6",
47
- :deviceCustomString1Label => "cs1Label",
48
- :deviceCustomString2Label => "cs2Label",
49
- :deviceCustomString3Label => "cs3Label",
50
- :deviceCustomString4Label => "cs4Label",
51
- :deviceCustomString5Label => "cs5Label",
52
- :deviceCustomString6Label => "cs6Label",
53
- :deviceCustomDate1 => "deviceCustomDate1",
54
- :deviceCustomDate2 => "deviceCustomDate2",
55
- :deviceCustomDate1Label => "deviceCustomDate1Label",
56
- :deviceCustomDate2Label => "deviceCustomDate2Label",
57
- :deviceEventCategory => "cat",
58
- :destinationAddress => "dst",
59
- :destinationDnsDomain => "destinationDnsDomain",
60
- :destinationNtDomain => "dntdom",
61
- :destinationHostName => "dhost",
62
- :destinationMacAddress => "dmac",
63
- :destinationPort => "dpt",
64
- :destinationProcessName => "dproc",
65
- :destinationServiceName => "destinationServiceName",
66
- :destinationUserId => "duid",
67
- :destinationUserPrivileges => "dpriv",
68
- :destinationUserName => "duser",
69
- :destinationTranslatedAddress => "destinationTranslatedAddress",
70
- :destinationTranslatedPort => "destinationTranslatedPort",
71
- :deviceDirection => "deviceDirection",
72
- :deviceExternalId => "deviceExternalId",
73
- :deviceFacility => "deviceFacility",
74
- :deviceInboundInterface => "deviceInboundInterface",
75
- :deviceOutboundInterface => "deviceOutboundInterface",
76
- :deviceProcessName => "deviceProcessName",
77
- :externalId => "externalId",
78
- :fileHash => "fileHash",
79
- :fileId => "fileId",
80
- :fileName => "fname",
81
- :filePath => "filePath",
82
- :filePermission => "filePermission",
83
- :fsize => "fsize",
84
- :fileType => "fileType",
85
- :message => "msg",
86
- :oldfileHash => "oldfileHash",
87
- :oldfileId => "oldfileId",
88
- :oldFilename => "oldFilename",
89
- :oldfilePath => "oldfilePath",
90
- :oldfilePermission => "oldfilePermission",
91
- :oldfsize => "oldfsize",
92
- :oldfileType => "oldfileType",
93
- :requestURL => "request",
94
- :requestClientApplication => "requestClientApplication",
95
- :requestCookies => "requestCookies",
96
- :requestMethod => "requestMethod",
97
- :sourceAddress => "src",
98
- :sourceDnsDomain => "sourceDnsDomain",
99
- :sourceHostName => "shost",
100
- :sourceMacAddress => "smac",
101
- :sourceNtDomain => "sntdom",
102
- :sourcePort => "spt",
103
- :sourceServiceName => "sourceServiceName",
104
- :sourceTranslatedAddress => "sourceTranslatedAddress",
105
- :sourceTranslatedPort => "sourceTranslatedPort",
106
- :sourceUserPrivileges => "spriv",
107
- :sourceUserId => "suid",
108
- :sourceUserName => "suser",
109
- :transportProtocol => "proto"
110
- }
111
-
112
- # these are tracked separately so they can be normalized during formatting
113
- TIME_ATTRIBUTES={
114
- :fileCreateTime => "fileCreateTime",
115
- :fileModificationTime => "fileModificationTime",
116
- :oldfileCreateTime => "oldfileCreateTime",
117
- :oldfileModificationTime => "oldfileModificationTime",
118
- :receiptTime => "rt",
119
- :startTime => "start",
120
- :endTime => "end"
121
- }
122
-
123
- ATTRIBUTES=PREFIX_ATTRIBUTES.merge EXTENSION_ATTRIBUTES.merge TIME_ATTRIBUTES
124
-
125
- # this class will formats and sends the cef event objects. you can use senders to set
126
- # default values for any event attribute, and you can send cef event objects to multiple
127
- # senders if you wish.
128
- class Sender
129
- attr_accessor :receiver, :receiverPort, :eventDefaults
130
- attr_reader :sock
131
-
132
- # you can pass in a hash of options to be run to set parameters
133
- def initialize(*params)
134
- Hash[*params].each {|k,v| self.send("%s="%k,v) }
135
- @sock=nil
136
- end
137
-
138
- def socksetup
139
- @sock=UDPSocket.new
140
- receiver= self.receiver || "127.0.0.1"
141
- port= self.receiverPort || 514
142
- @sock.connect(receiver,port)
143
- end
144
-
145
- # formats a CEFEvent
146
- def format_event( event )
147
- #HELL yeah it's hard-coded. What are you going to do about it?
148
- #syslog_pri= Syslog::LOG_LOCAL0 | Syslog::LOG_NOTICE
149
- syslog_pri=131
150
-
151
- # process eventDefaults - we are expecting a hash here. These will
152
- # override any values in the events passed to us. i know. brutal.
153
- unless self.eventDefaults.nil?
154
- self.eventDefaults.each do |k,v|
155
- event.send("#{k}=",v)
156
- end
157
- end
158
-
159
- cef_message=PREFIX_FORMAT % [
160
- syslog_pri.to_s,
161
- Socket::gethostname,
162
- Time.new.strftime("%b %d %Y %H:%M:%S"),
163
- event.prefix,
164
- event.extension
165
- ]
166
- cef_message
167
- end
168
-
169
- #fire the message off
170
- def emit(event)
171
- self.socksetup if self.sock.nil?
172
- self.sock.send self.format_event(event), 0
173
- end
174
- end
175
-
176
- class Event
177
- #%#
178
- # set up accessors for all of the event attributes. ruby meta magic.
179
- ATTRIBUTES.each do |k,v|
180
- self.instance_eval do
181
- attr_accessor k
182
- end
183
- end
184
-
185
- def attrs
186
- ATTRIBUTES
187
- end
188
-
189
- # so we can CEFEvent.new(:foo=>"bar")
190
- def initialize( *params )
191
- Hash[*params].each { |k,v| self.send("%s="%k,v) }
192
- end
193
-
194
- # escape only pipes and backslashes in the prefix. you bet your sweet
195
- # ass there's a lot of backslashes in the substitution. you can thank
196
- # the three levels of lexical analysis/substitution in the ruby interpreter
197
- # for that.
198
- def prefix_escape(val)
199
- val.gsub(/(\||\\)/,'\\\\\&')
200
- end
201
-
202
- # only equals signs need to be escaped in the extension. i think.
203
- # TODO: something in the spec about \n and some others.
204
- def extension_escape(val)
205
- val.gsub(/=/,'\=')
206
- end
207
-
208
- # make a guess as to how the time was set. parse strings and convert
209
- # them to epoch milliseconds, or leave it alone if it looks like a number
210
- # bigger than epoch milliseconds when i wrote this.
211
- def time_convert(val)
212
- converted=nil
213
- #puts "converting time for #{val.class.to_s}/#{val}"
214
- case val.class.to_s
215
- when "String"
216
- begin
217
- converted=val.to_i
218
- rescue
219
- res=ParseDate.parsedate(val)
220
- converted=Time.local(*res).to_i * 1000
221
- end
222
- when "Integer","Bignum"
223
- if val < 1232589621000 #Wed Jan 21 20:00:21 -0600 2009
224
- converted=val * 1000
225
- else
226
- converted=val
227
- end
228
- end
229
- converted
230
- end
231
-
232
- # returns a pipe-delimeted list of prefix attributes
233
- def prefix
234
- vendor= self.deviceVendor || "Breed"
235
- product= self.deviceProduct || "CEF Sender"
236
- version= self.deviceVersion || CEF::VERSION
237
- declid= self.deviceEventClassId || "generic:0"
238
- name= self.name || "Generic Event"
239
- sev= self.deviceSeverity || "1"
240
- cef_prefix="%s|%s|%s|%s|%s|%s" % [
241
- prefix_escape(vendor),
242
- prefix_escape(product),
243
- prefix_escape(version),
244
- prefix_escape(declid),
245
- prefix_escape(name),
246
- prefix_escape(sev),
247
- ]
248
- end
249
-
250
- # returns a space-delimeted list of attribute=value pairs for all optionals
251
- def extension
252
- avpairs=[]
253
- EXTENSION_ATTRIBUTES.each do |attribute,shortname|
254
- unless self.send(attribute).nil?
255
- avpairs.push(
256
- "%s=%s" % [ shortname, extension_escape(self.send(attribute)) ]
257
- )
258
- end
259
- end
260
-
261
- # make sure time comes out as milliseconds since epoch
262
- TIME_ATTRIBUTES.each do |attribute,shortname|
263
- unless self.send(attribute).nil?
264
- avpairs.push(
265
- "%s=%s" % [ shortname, time_convert(self.send(attribute)) ]
266
- )
267
- end
268
- end
269
- avpairs.join(" ")
270
- end
271
- end
4
+ require 'cef/constants'
5
+ require 'cef/event'
6
+ require 'cef/sender'
7
+ require 'cef/file_logger'
272
8
  end
273
9
 
274
10
 
@@ -0,0 +1,122 @@
1
+ module CEF
2
+ PREFIX_FORMAT="<%d>%s %s CEF:0|%s|%s"
3
+ VERSION=File.read(File.join(File.expand_path(File.dirname(__FILE__)),'..','..','VERSION'))
4
+
5
+
6
+ # CEF Dictionary
7
+ # CEF Prefix attributes
8
+ PREFIX_ATTRIBUTES = {
9
+ :deviceVendor => "deviceVendor",
10
+ :deviceVersion => "deviceVersion",
11
+ :deviceProduct => "deviceProduct",
12
+ :name => "name",
13
+ :deviceSeverity => "deviceSeverity",
14
+ :deviceEventClassId => "deviceEventClassId"
15
+ }
16
+
17
+ # these are the basic extension attributes. implementing others is as
18
+ # simple as adding :symbolRepresentingMethodName => "cefkeyname", but
19
+ # i am supremely lazy to type in the whole dictionary right now. perhaps
20
+ # this should be a .yaml config file. Extension attributes are formatted
21
+ # differently than core attributes.
22
+ EXTENSION_ATTRIBUTES = {
23
+ :applicationProtocol => "app",
24
+ :baseEventCount => "cnt",
25
+ :bytesIn => "in",
26
+ :bytesOut => "out",
27
+ :deviceAction => "act",
28
+ :deviceHostNam => "dvc",
29
+ :deviceNtDomain => "deviceNtDomain",
30
+ :deviceDnsDomain => "deviceDnsDomain",
31
+ :deviceTranslatedAddress => "deviceTranslatedAddress",
32
+ :deviceMacAddress => "deviceMacAddress",
33
+ :deviceCustomNumber1 => "cn1",
34
+ :deviceCustomNumber2 => "cn2",
35
+ :deviceCustomNumber3 => "cn3",
36
+ :deviceCustomNumber1Label => "cn1Label",
37
+ :deviceCustomNumber2Label => "cn2Label",
38
+ :deviceCustomNumber3Label => "cn3Label",
39
+ :deviceCustomString1 => "cs1",
40
+ :deviceCustomString2 => "cs2",
41
+ :deviceCustomString3 => "cs3",
42
+ :deviceCustomString4 => "cs4",
43
+ :deviceCustomString5 => "cs5",
44
+ :deviceCustomString6 => "cs6",
45
+ :deviceCustomString1Label => "cs1Label",
46
+ :deviceCustomString2Label => "cs2Label",
47
+ :deviceCustomString3Label => "cs3Label",
48
+ :deviceCustomString4Label => "cs4Label",
49
+ :deviceCustomString5Label => "cs5Label",
50
+ :deviceCustomString6Label => "cs6Label",
51
+ :deviceCustomDate1 => "deviceCustomDate1",
52
+ :deviceCustomDate2 => "deviceCustomDate2",
53
+ :deviceCustomDate1Label => "deviceCustomDate1Label",
54
+ :deviceCustomDate2Label => "deviceCustomDate2Label",
55
+ :deviceEventCategory => "cat",
56
+ :destinationAddress => "dst",
57
+ :destinationDnsDomain => "destinationDnsDomain",
58
+ :destinationNtDomain => "dntdom",
59
+ :destinationHostName => "dhost",
60
+ :destinationMacAddress => "dmac",
61
+ :destinationPort => "dpt",
62
+ :destinationProcessName => "dproc",
63
+ :destinationServiceName => "destinationServiceName",
64
+ :destinationUserId => "duid",
65
+ :destinationUserPrivileges => "dpriv",
66
+ :destinationUserName => "duser",
67
+ :destinationTranslatedAddress => "destinationTranslatedAddress",
68
+ :destinationTranslatedPort => "destinationTranslatedPort",
69
+ :deviceDirection => "deviceDirection",
70
+ :deviceExternalId => "deviceExternalId",
71
+ :deviceFacility => "deviceFacility",
72
+ :deviceInboundInterface => "deviceInboundInterface",
73
+ :deviceOutboundInterface => "deviceOutboundInterface",
74
+ :deviceProcessName => "deviceProcessName",
75
+ :externalId => "externalId",
76
+ :fileHash => "fileHash",
77
+ :fileId => "fileId",
78
+ :fileName => "fname",
79
+ :filePath => "filePath",
80
+ :filePermission => "filePermission",
81
+ :fsize => "fsize",
82
+ :fileType => "fileType",
83
+ :message => "msg",
84
+ :oldfileHash => "oldfileHash",
85
+ :oldfileId => "oldfileId",
86
+ :oldFilename => "oldFilename",
87
+ :oldfilePath => "oldfilePath",
88
+ :oldfilePermission => "oldfilePermission",
89
+ :oldfsize => "oldfsize",
90
+ :oldfileType => "oldfileType",
91
+ :requestURL => "request",
92
+ :requestClientApplication => "requestClientApplication",
93
+ :requestCookies => "requestCookies",
94
+ :requestMethod => "requestMethod",
95
+ :sourceAddress => "src",
96
+ :sourceDnsDomain => "sourceDnsDomain",
97
+ :sourceHostName => "shost",
98
+ :sourceMacAddress => "smac",
99
+ :sourceNtDomain => "sntdom",
100
+ :sourcePort => "spt",
101
+ :sourceServiceName => "sourceServiceName",
102
+ :sourceTranslatedAddress => "sourceTranslatedAddress",
103
+ :sourceTranslatedPort => "sourceTranslatedPort",
104
+ :sourceUserPrivileges => "spriv",
105
+ :sourceUserId => "suid",
106
+ :sourceUserName => "suser",
107
+ :transportProtocol => "proto"
108
+ }
109
+
110
+ # these are tracked separately so they can be normalized during formatting
111
+ TIME_ATTRIBUTES={
112
+ :fileCreateTime => "fileCreateTime",
113
+ :fileModificationTime => "fileModificationTime",
114
+ :oldfileCreateTime => "oldfileCreateTime",
115
+ :oldfileModificationTime => "oldfileModificationTime",
116
+ :receiptTime => "rt",
117
+ :startTime => "start",
118
+ :endTime => "end"
119
+ }
120
+
121
+ ATTRIBUTES=PREFIX_ATTRIBUTES.merge EXTENSION_ATTRIBUTES.merge TIME_ATTRIBUTES
122
+ end
@@ -0,0 +1,116 @@
1
+ module CEF
2
+ class Event
3
+ attr_accessor :my_hostname, :syslog_pri
4
+ # set up accessors for all of the CEF event attributes. ruby meta magic.
5
+ CEF::ATTRIBUTES.each do |k,v|
6
+ self.instance_eval do
7
+ attr_accessor k
8
+ end
9
+ end
10
+
11
+ def attrs
12
+ CEF::ATTRIBUTES
13
+ end
14
+
15
+ # so we can CEF::Event.new(:foo=>"bar")
16
+ def initialize( *params )
17
+ Hash[*params].each { |k,v| self.send("%s="%k,v) }
18
+
19
+ @my_hostname ||= Socket::gethostname
20
+ # used to avoid requiring syslog.h on windoze
21
+ #syslog_pri= Syslog::LOG_LOCAL0 | Syslog::LOG_NOTICE
22
+ @syslog_pri ||= 131
23
+ end
24
+
25
+ # returns a cef formatted string
26
+ def format_cef
27
+ cef_message=CEF::PREFIX_FORMAT % [
28
+ syslog_pri.to_s,
29
+ my_hostname,
30
+ Time.new.strftime("%b %d %Y %H:%M:%S"),
31
+ format_prefix,
32
+ format_extension
33
+ ]
34
+ cef_message
35
+ end
36
+
37
+ private
38
+ # make a guess as to how the time was set. parse strings and convert
39
+ # them to epoch milliseconds, or leave it alone if it looks like a number
40
+ # bigger than epoch milliseconds when i wrote this.
41
+ def time_convert(val)
42
+ converted=nil
43
+ #puts "converting time for #{val.class.to_s}/#{val}"
44
+ case val.class.to_s
45
+ when "String"
46
+ begin
47
+ converted=val.to_i
48
+ rescue
49
+ res=ParseDate.parsedate(val)
50
+ converted=Time.local(*res).to_i * 1000
51
+ end
52
+ when "Integer","Bignum"
53
+ if val < 1232589621000 #Wed Jan 21 20:00:21 -0600 2009
54
+ converted=val * 1000
55
+ else
56
+ converted=val
57
+ end
58
+ end
59
+ converted
60
+ end
61
+
62
+ # escape only pipes and backslashes in the prefix. you bet your sweet
63
+ # ass there's a lot of backslashes in the substitution. you can thank
64
+ # the three levels of lexical analysis/substitution in the ruby interpreter
65
+ # for that.
66
+ def prefix_escape(val)
67
+ val.gsub(/(\||\\)/,'\\\\\&')
68
+ end
69
+
70
+ # only equals signs need to be escaped in the extension. i think.
71
+ # TODO: something in the spec about \n and some others.
72
+ def extension_escape(val)
73
+ val.gsub(/=/,'\=').gsub(/\n/,' ')
74
+ end
75
+
76
+ # returns a pipe-delimeted list of prefix attributes
77
+ def format_prefix
78
+ vendor= self.deviceVendor || "Breed"
79
+ product= self.deviceProduct || "CEF Sender"
80
+ version= self.deviceVersion || CEF::VERSION
81
+ declid= self.deviceEventClassId || "generic:0"
82
+ name= self.name || "Generic Event"
83
+ sev= self.deviceSeverity || "1"
84
+ cef_prefix="%s|%s|%s|%s|%s|%s" % [
85
+ prefix_escape(vendor),
86
+ prefix_escape(product),
87
+ prefix_escape(version),
88
+ prefix_escape(declid),
89
+ prefix_escape(name),
90
+ prefix_escape(sev),
91
+ ]
92
+ end
93
+
94
+ # returns a space-delimeted list of attribute=value pairs for all optionals
95
+ def format_extension
96
+ avpairs=[]
97
+ CEF::EXTENSION_ATTRIBUTES.each do |attribute,shortname|
98
+ unless self.send(attribute).nil?
99
+ avpairs.push(
100
+ "%s=%s" % [ shortname, extension_escape(self.send(attribute)) ]
101
+ )
102
+ end
103
+ end
104
+
105
+ # make sure time comes out as milliseconds since epoch
106
+ CEF::TIME_ATTRIBUTES.each do |attribute,shortname|
107
+ unless self.send(attribute).nil?
108
+ avpairs.push(
109
+ "%s=%s" % [ shortname, time_convert(self.send(attribute)) ]
110
+ )
111
+ end
112
+ end
113
+ avpairs.join(" ")
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,8 @@
1
+
2
+ module CEF
3
+ class FileLogger
4
+ def initialize(*args)
5
+ Hash[*args].each { |argname, argval| self.send(("%s="%argname), argval) }
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,38 @@
1
+ module CEF
2
+ require 'socket'
3
+
4
+ class Sender
5
+ attr_accessor :receiver, :receiverPort, :eventDefaults
6
+ attr_reader :sock
7
+ def initialize(*args)
8
+ Hash[*args].each { |argname, argval| self.send(("%s="%argname), argval) }
9
+ @sock=nil
10
+ end
11
+ end
12
+
13
+ #TODO: Implement relp/tcp senders
14
+
15
+ class UDPSender < Sender
16
+
17
+ #fire the message off
18
+ def emit(event)
19
+ self.socksetup if self.sock.nil?
20
+ # process eventDefaults - we are expecting a hash here. These will
21
+ # override any values in the events passed to us. i know. brutal.
22
+ unless self.eventDefaults.nil?
23
+ self.eventDefaults.each do |k,v|
24
+ event.send("%s=" % k,v)
25
+ end
26
+ end
27
+ self.sock.send event.format_cef, 0
28
+ end
29
+
30
+
31
+ def socksetup
32
+ @sock=UDPSocket.new
33
+ receiver= self.receiver || "127.0.0.1"
34
+ port= self.receiverPort || 514
35
+ @sock.connect(receiver,port)
36
+ end
37
+ end
38
+ end
@@ -5,8 +5,9 @@ describe "CEF Event Format" do
5
5
  prefix_vals=test_prefix_vals
6
6
  e=CEF::Event.new
7
7
  prefix_vals.each {|k,v| e.send("%s="%k,v) }
8
- s=CEF::Sender.new
9
8
  formatted=CEF::PREFIX_FORMAT % [ 131, *prefix_vals.values ]
10
- s.format_event(e)==formatted
9
+
10
+ e.format_cef==formatted
11
11
  end
12
+
12
13
  end
@@ -20,4 +20,8 @@ def test_prefix_vals
20
20
  :name => "test",
21
21
  :deviceSeverity => "1"
22
22
  }
23
+ end
24
+
25
+ def test_prefix_string
26
+ "CEF:0|breed|CEF Sender|0.1|0:debug|test|1|"
23
27
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cef
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
4
+ hash: 3
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 6
9
- - 1
10
- version: 0.6.1
8
+ - 7
9
+ - 0
10
+ version: 0.7.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ryan Breed
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-02-20 00:00:00 -06:00
18
+ date: 2011-03-11 00:00:00 -06:00
19
19
  default_executable: cef_sender
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -114,7 +114,12 @@ files:
114
114
  - Rakefile
115
115
  - VERSION
116
116
  - bin/cef_sender
117
+ - cef.gemspec
117
118
  - lib/cef.rb
119
+ - lib/cef/constants.rb
120
+ - lib/cef/event.rb
121
+ - lib/cef/file_logger.rb
122
+ - lib/cef/sender.rb
118
123
  - spec/cef_spec.rb
119
124
  - spec/spec_helper.rb
120
125
  has_rdoc: true