cef 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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