dorothy2 0.0.1

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.
@@ -0,0 +1,39 @@
1
+ ---
2
+ dorothive:
3
+ dbuser: postgres
4
+ dbpass: password
5
+ dbhost: localhost
6
+ dbname: dorothive
7
+ ddl: /Users/akira/Codes/dorothy-gem-try/dorothy2/etc/ddl/dorothive.ddl
8
+ env:
9
+ geoip: /Users/akira/Codes/dorothy-gem-try/dorothy2/etc/geo/GeoLiteCity.dat
10
+ geoasn: /Users/akira/Codes/dorothy-gem-try/dorothy2/etc/geo/GeoIPASNum.dat
11
+ loglevel: 0
12
+ testmode: true
13
+ dtimeout: 3600
14
+ logfile_parser: /Users/akira/Codes/dorothy-gem-try/dorothy2/var/log/parser.log
15
+ analysis_dir: /Users/akira/Codes/dorothy-gem-try/dorothy2/opt/analyzed
16
+ pidfile_parser: /Users/akira/Codes/dorothy-gem-try/dorothy2/var/doroParser.pid
17
+ pidfile: /Users/akira/Codes/dorothy-gem-try/dorothy2/var/dorothy.pid
18
+ logage: weekly
19
+ logfile: /Users/akira/Codes/dorothy-gem-try/dorothy2/var/log/dorothy.log
20
+ home: /Users/akira/Codes/dorothy-gem-try/dorothy2
21
+ esx:
22
+ user: "root"
23
+ pass: "Dorothy!?!"
24
+ host: "192.168.187.128"
25
+ sandbox:
26
+ screen1time: 1
27
+ sleeptime: 60
28
+ screen2time: 15
29
+ nam:
30
+ namuser: dorothy
31
+ pcaphome: ~/pcaps
32
+ nampass: ""
33
+ interface: eth0
34
+ namserver: ""
35
+ virustotal:
36
+ vtapikey: "c37baad50a42d7df3f91e957255a2c6a9deabe339c2ff44d4a637fff912def48"
37
+
38
+
39
+
@@ -0,0 +1,20 @@
1
+ #############################################
2
+ ### DOROTHY SANDBOX LIST #
3
+ #############################################
4
+ ###
5
+ ###
6
+ ### List of the available virtual machines
7
+ ### (loaded into ESX)
8
+ ### WARNING - after editing this file, run
9
+ ### $dorothy_start -sandbox reload
10
+ #############################################
11
+ ---
12
+ WinXP1:
13
+ password: password
14
+ ipaddress: 192.168.187.130
15
+ username: billy
16
+ os_lang: eng
17
+ os: Windows
18
+ version: XP SP2
19
+ type: virtual
20
+
@@ -0,0 +1,32 @@
1
+ #############################################
2
+ ### DOROTHY SOURCE LIST #
3
+ #############################################
4
+ ###
5
+ ### type means the communication channel used
6
+ ### to download the binaries, possible values
7
+ ### are: system | ssh
8
+ ###
9
+ ### typeid defines the type of the source, it
10
+ ### depends on a userdefined-type in
11
+ ### dorothive(DB) (table Sensors) please use
12
+ ### ONLY the following ones (or add new ones
13
+ ### in the DB accordingly)
14
+ ###
15
+ ### 0 - lowinteraction
16
+ ### 1 - external source
17
+ ### 2 - unknown
18
+ #############################################
19
+ ---
20
+ malwarefolder:
21
+ type: system
22
+ localdir: /Users/m4rco/dorothy2/opt/bins/manual
23
+ typeid: 2
24
+ honeypot1:
25
+ type: ssh
26
+ ip: 1.2.3.4
27
+ port: 22
28
+ user: asd
29
+ pass: asdasdasd
30
+ remotedir: /asda/bins
31
+ localdir: /opt/bins/honeypot
32
+ typeid: 0
data/lib/doroParser.rb ADDED
@@ -0,0 +1,518 @@
1
+ # Copyright (C) 2010-2013 marco riccardi.
2
+ # This file is part of Dorothy - http://www.honeynet.it/dorothy
3
+ # See the file 'LICENSE' for copying permission.
4
+
5
+ #!/usr/local/bin/ruby
6
+ $LOAD_PATH.unshift '/opt/local/lib/ruby/gems/1.8/gems/ruby-filemagic-0.4.2/lib' #for MACOSX
7
+ #$LOAD_PATH.unshift '/usr/lib/ruby/gems/1.8/gems/ruby-filemagic-0.4.2/lib' #for linux Debian
8
+ require 'rubygems'
9
+ require 'mu/xtractr'
10
+ require 'md5'
11
+ require 'rbvmomi'
12
+ require 'rest_client'
13
+ require 'net/dns/packet'
14
+ require 'ipaddr'
15
+ require 'colored'
16
+ require 'trollop'
17
+ require 'ftools'
18
+ require 'filemagic' #require 'pcaplet'
19
+ require 'geoip' #1)gem install geoip
20
+ require 'pg'
21
+ require 'iconv'
22
+ require 'tmail'
23
+ require 'ipaddr'
24
+
25
+ require File.dirname(__FILE__) + '/dorothy/environment'
26
+ require File.dirname(__FILE__) + '/dorothy/do-parsers'
27
+ require File.dirname(__FILE__) + '/dorothy/do-utils'
28
+ require File.dirname(__FILE__) + '/dorothy/do-logger'
29
+
30
+
31
+ module DoroParser
32
+ #Host roles
33
+
34
+ CCIRC = 1
35
+ CCDROP = 3
36
+ CCSUPPORT = 5
37
+
38
+ def search_irc(streamdata)
39
+
40
+ util = Util.new
41
+
42
+
43
+ ircvalues = []
44
+ streamdata.each do |m|
45
+ # if m[1] == 0 #we fetch only outgoing traffic
46
+ direction_bool = (m[1] == 0 ? false : true)
47
+ LOGGER_PARSER.info "PARSER", "FOUND IRC DATA".white
48
+ LOGGER_PARSER.info "IRC", "#{m[0]}".yellow
49
+ #puts "..::: #{parsed.command}".white + " #{parsed.content}".yellow
50
+
51
+ ircvalues.push "default, currval('dorothy.connections_id_seq'), E'#{Insertdb.escape_bytea(m[0])}', #{direction_bool}"
52
+ # end
53
+ end
54
+ return ircvalues
55
+ end
56
+
57
+ def analyze_bintraffic(pcaps)
58
+
59
+ dns_list = Hash.new
60
+ hosts = []
61
+ @insertdb.begin_t
62
+
63
+ pcaps.each do |dump|
64
+ #RETRIVE MALWARE FILE INFO
65
+
66
+ !dump['sample'].nil? && !dump['hash'].nil? && !dump['pcapr_id'].nil? or next
67
+
68
+ LOGGER_PARSER.info "PARSER", "Analyzing file: ".yellow + dump['sample']
69
+ LOGGER_PARSER.info "PARSER", "Analyzing pcaprid: ".yellow + dump['pcapr_id'].gsub(/\s+/, "")
70
+
71
+
72
+ LOGGER_PARSER.debug "PARSER", "Analyzing dump: ".yellow + dump['hash'].gsub(/\s+/, "") if VERBOSE
73
+
74
+
75
+ #gets
76
+
77
+ downloadir = "#{ANALYSIS_DIR}/#{dump['sample'].gsub(/\s+/, "")}/downloads"
78
+
79
+ #puts "Sighting of #{malw.sha} imported"
80
+
81
+ ##NETWORK DUMP PARSING#
82
+ #######################
83
+ #LOAD XTRACTR INSTANCE#
84
+
85
+ # begin
86
+ # t = RestClient.get "http://172.20.250.13:8080/pcaps/1/about/#{dump['pcapr_id'].gsub(/\s+/, "")"
87
+ # jt = JSON.parse(t)
88
+ # rescue RestClient::InternalServerError
89
+ # puts ".:: File not found: http://172.20.250.13:8080/pcaps/1/about/#{dump['pcapr_id'].gsub(/\s+/, "")".red
90
+ # puts ".:: #{$!}".red
91
+ ## puts ".:: Skipping malware #{dump['hash']} and doing DB ROLLBACK".red
92
+ # next
93
+ # end
94
+
95
+ # puts ".:: File PCAP found on PCAPR DB - #{jt['filename']} - ID #{dump['pcapr_id'].gsub(/\s+/, "")"
96
+ #xtractr = Mu::Xtractr.create "http://172.20.250.13:8080/home/index.html#/browse/pcap/dd737a00ff0495083cf6edd772fe2a18"
97
+ # 843272e9a0b6a5f4aa5985d151cb6721
98
+
99
+ begin
100
+ #TEST!
101
+ xtractr = Doroxtractr.create "http://172.20.250.13:8080/pcaps/1/pcap/#{dump['pcapr_id'].gsub(/\s+/, "")}"
102
+ #xtractr = Doroxtractr.create "http://172.20.250.13:8080/pcaps/1/pcap/071dc8540a88d72c15d8542f6c7610f8"
103
+ #puts "TEST MODE ON!"
104
+ #gets
105
+
106
+ rescue
107
+ LOGGER_PARSER.fatal "PARSER", "Can't create a XTRACTR instance, try with nextone".red
108
+ # LOGGER_PARSER.debug "PARSER", "#{$!}"
109
+ next
110
+ end
111
+
112
+
113
+ LOGGER_PARSER.info "PARSER", "Scanning network flows and searching for unknown host IPs".yellow
114
+
115
+ #xtractr.flows('flow.service:HTTP').each { |flow|
116
+
117
+ xtractr.flows.each { |flow|
118
+ #TODO: begin , make exception hangling for every flow
119
+
120
+ #DEBUG
121
+ #puts flow.id
122
+
123
+ flowdeep = xtractr.flows("flow.id:#{flow.id}")
124
+
125
+
126
+
127
+ #Skipping if NETBIOS spreading activity:
128
+ if flow.dport == 135 or flow.dport == 445
129
+ LOGGER_PARSER.info "PARSER", "Netbios connections, skipping flow" unless NONETBIOS
130
+ next
131
+ end
132
+
133
+
134
+ title = flow.title[0..200].gsub(/'/,"") #xtool bug ->')
135
+
136
+
137
+ #insert hosts (geo) info into db
138
+ #check if is a localaddress
139
+ localip = "10.0.0.0"
140
+ localnet = IPAddr.new("#{localip}/24")
141
+ multicast = IPAddr.new("224.0.0.0/4")
142
+
143
+ #check if already present in DB
144
+ unless(@insertdb.select("host_ips", "ip", flow.dst.address).one? || hosts.include?(flow.dst.address))
145
+ LOGGER_PARSER.info "PARSER", "Analyzing #{flow.dst.address}".yellow
146
+ hosts << flow.dst.address
147
+ dest = flow.dst.address
148
+
149
+
150
+ #insert Geoinfo
151
+ unless(localnet.include?(flow.dst.address) || multicast.include?(flow.dst.address))
152
+
153
+ geo = Geoinfo.new(flow.dst.address.to_s)
154
+ geoval = ["default", geo.coord, geo.country, geo.city, geo.updated, geo.asn]
155
+ LOGGER_PARSER.debug "GEO", "Geo-values for #{flow.dst.address.to_s}: " + geo.country + " " + geo.city + " " + geo.coord if VERBOSE
156
+
157
+ if geo.coord != "null"
158
+ LOGGER_PARSER.debug "DB", " Inserting geo values for #{flow.dst.address.to_s} : #{geo.country}".blue if VERBOSE
159
+ @insertdb.insert("geoinfo",geoval)
160
+ geoval = "currval('dorothy.geoinfo_id_seq')"
161
+ else
162
+ LOGGER_PARSER.warn "DB", " No Geovalues found for #{flow.dst.address.to_s}".red if VERBOSE
163
+ geoval = "null"
164
+ end
165
+
166
+ else
167
+ LOGGER_PARSER.warn "PARSER", "#{flow.dst.address} skipped while searching for GeoInfo (it's a local network))".yellow
168
+ geoval = 'null'
169
+ dest = localip
170
+ end
171
+
172
+ #Insert host info
173
+ #ip - geoinfo - sbl - uptime - is_online - whois - zone - last-update - id - dns_name
174
+ hostname = (dns_list[dest].nil? ? "null" : dns_list[dest])
175
+ hostval = [dest, geoval, "null", "null", true, "null", "null", get_time, "default", hostname]
176
+
177
+ if !@insertdb.insert("host_ips",hostval)
178
+ LOGGER_PARSER.debug "DB", " Skipping flow #{flow.id}: #{flow.src.address} > #{flow.dst.address}" if VERBOSE
179
+ next
180
+ end
181
+
182
+ else
183
+ LOGGER_PARSER.debug "PARSER", "Host already #{flow.dst.address} known, skipping..." if VERBOSE
184
+ #puts ".:: Geo info host #{flow.dst.address} already present in geodatabase, skipping.." if @insertdb.select("host_ips", "ip", flow.dst.address)
185
+ end
186
+
187
+ #case TCP xtractr.flows('flow.service:SMTP').first.proto = 6
188
+
189
+ flowvals = [flow.src.address, flow.dst.address, flow.sport, flow.dport, flow.bytes, dump['hash'], flow.packets, "default", flow.proto, flow.service.name, title, "null", flow.duration, flow.time, flow.id ]
190
+
191
+ if !@insertdb.insert("flows",flowvals)
192
+ LOGGER_PARSER.info "PARSER", "Skipping flow #{flow.id}: #{flow.src.address} > #{flow.dst.address}"
193
+ next
194
+ end
195
+
196
+ LOGGER_PARSER.debug("DB", "Inserting flow #{flow.id} - #{flow.title}".blue) if VERBOSE
197
+
198
+ flowid = "currval('dorothy.connections_id_seq')"
199
+
200
+ #Layer 3 analysis
201
+ service = flow.service.name
202
+
203
+ #DEBUG
204
+ #puts "PROTO = " + flow.proto.to_s
205
+
206
+ case flow.proto
207
+ when 6 then
208
+ #check if HTTP,IRC, MAIL
209
+ #xtractr.flows('flow.service:SMTP').first.service.name == "TCP" when unknow
210
+
211
+ #Layer 4 analysis
212
+ streamdata = xtractr.streamdata(flow.id)
213
+
214
+ #DEBUG
215
+ #puts "SERVICE = " + service.to_s
216
+
217
+ case service #TODO: don't trust service field: it's based on default-port definition, do a packet inspection instead.
218
+
219
+ #case HTTP
220
+ when "HTTP" then
221
+ http = DoroHttp.new(flowdeep)
222
+
223
+ if http.method =~ /GET|POST/
224
+ LOGGER_PARSER.info "HTTP", "FOUND an HTTP request".white
225
+ LOGGER_PARSER.info "HTTP", "HTTP #{http.method}".white + " #{http.uri}".yellow
226
+
227
+ t = http.uri.split('/')
228
+ filename = (t[t.length - 1].nil? ? "noname-#{flow.id}" : t[t.length - 1])
229
+
230
+ if http.method =~ /POST/
231
+ role_values = [CCDROP, flow.dst.address]
232
+ @insertdb.insert("host_roles", role_values ) unless @insertdb.select("host_roles", "role", role_values[0], "host_ip", role_values[1]).one?
233
+ http.data = xtractr.flowcontent(flow.id)
234
+ LOGGER_PARSER.debug "DB", "POST DATA SAVED IN THE DB"
235
+ end
236
+
237
+ if http.contype =~ /application/ # STORING ONLY application* type GET DATA (avoid html pages, etc)
238
+ LOGGER_PARSER.info "HTTP", "FOUND an Application Type".white
239
+ LOGGER_PARSER.debug "DB", " Inserting #{filename} downloaded file info" if VERBOSE
240
+
241
+ #download
242
+ flowdeep.each do |flow|
243
+ flow.contents.each do |c|
244
+
245
+ LOGGER_PARSER.debug("DB", "Inserting downloaded http file info from #{flow.dst.address.to_s}".blue) if VERBOSE
246
+
247
+ downvalues = [ DoroFile.sha2(c.body), flowid, downloadir, filename ]
248
+ @insertdb.insert("downloads", downvalues )
249
+
250
+ role_values = [CCSUPPORT, flow.dst.address]
251
+ @insertdb.insert("host_roles", role_values ) unless @insertdb.select("host_roles", "role", role_values[0], "host_ip", role_values[1]).one?
252
+
253
+ LOGGER_PARSER.debug "HTTP", "Saving downloaded file into #{downloadir}".white if VERBOSE
254
+ c.save("#{downloadir}/#{filename}")
255
+ end
256
+
257
+ end
258
+
259
+
260
+ end
261
+
262
+ httpvalues = "default, '#{http.method.downcase}', '#{http.uri}', #{http.size}, #{http.ssl}, #{flowid}, E'#{Insertdb.escape_bytea(http.data)}' "
263
+
264
+ LOGGER_PARSER.debug "DB", " Inserting http data info from #{flow.dst.address.to_s}".blue if VERBOSE
265
+ @insertdb.raw_insert("http_data", httpvalues)
266
+
267
+ else
268
+ LOGGER_PARSER.warn "HTTP", "Not a regular HTTP traffic on flow #{flow.id}".yellow
269
+ LOGGER_PARSER.info "PARSER", "Trying to guess if it is IRC".white
270
+
271
+ if Parser.guess(streamdata.inspect).class.inspect =~ /IRC/
272
+ ircvalues = search_irc(streamdata)
273
+ ircvalues.each do |ircvalue|
274
+ LOGGER_PARSER.debug "DB", " Inserting IRC DATA info from #{flow.dst.address.to_s}".blue if VERBOSE
275
+ @insertdb.raw_insert("irc_data", ircvalue )
276
+ role_values = [CCIRC, flow.dst.address]
277
+ @insertdb.insert("host_roles", role_values ) unless @insertdb.select("host_roles", "role", role_values[0], "host_ip", role_values[1]).one?
278
+ end
279
+
280
+ else
281
+ LOGGER_PARSER.info "PARSER", "NO-IRC".red
282
+ #TODO, store UNKNOWN communication data
283
+
284
+ end
285
+
286
+
287
+
288
+
289
+
290
+ end
291
+
292
+ #case MAIL
293
+ when "SMTP" then
294
+ LOGGER_PARSER.info "SMTP", "FOUND an SMTP request..".white
295
+ #insert mail
296
+ #by from to subject data id time connection
297
+
298
+
299
+ streamdata.each do |m|
300
+ mailfrom = 'null'
301
+ mailto = 'null'
302
+ mailcontent = 'null'
303
+ mailsubject = 'null'
304
+ mailhcmd = 'null'
305
+ mailhcont = 'null'
306
+ rdata = ['null', 'null']
307
+
308
+ case m[1]
309
+ when 0
310
+ if Parser::SMTP.header?(m[0])
311
+ @email = Parser::SMTP.new(m[0])
312
+ LOGGER_PARSER.info "SMTP", "[A]".white + @email.hcmd + " " + @email.hcont
313
+ if Parser::SMTP.hasbody?(m[0])
314
+ @email.body = Parser::SMTP.body(m[0])
315
+ mailto = @email.body.to
316
+ mailfrom = @email.body.from
317
+ mailsubject = @email.body.subject.gsub(/'/,"") #xtool bug ->')
318
+ end
319
+ end
320
+ when 1
321
+ rdata = Parser::SMTP.response(m[0]) if Parser::SMTP.response(m[0])
322
+ LOGGER_PARSER.info "SMTP", "[R]".white + rdata[0] + " " + rdata[1]
323
+ rdata[0] = 'null' if rdata[0].empty?
324
+ rdata[1] = 'null' if rdata[1].empty?
325
+
326
+ end
327
+ mailvalues = [mailfrom, mailto, mailsubject, mailcontent, "default", flowid, mailhcmd, mailhcont, rdata[0], rdata[1].gsub(/'/,"")] #xtool bug ->')
328
+ @insertdb.insert("emails", mailvalues )
329
+ end
330
+
331
+
332
+
333
+ #case FTP
334
+ when "FTP" then
335
+ LOGGER_PARSER.info "FTP", "FOUND an FTP request".white
336
+ #TODO
337
+ when "TCP" then
338
+
339
+ LOGGER_PARSER.info "TCP", "FOUND GENERIC TCP TRAFFIC - may be a netbios scan".white
340
+ LOGGER_PARSER.info "PARSER", "Trying see if it is IRC traffic".white
341
+
342
+ if Parser.guess(streamdata.inspect).class.inspect =~ /IRC/
343
+ ircvalues = search_irc(streamdata)
344
+ ircvalues.each do |ircvalue|
345
+ LOGGER_PARSER.debug "DB", " Inserting IRC DATA info from #{flow.dst.address.to_s}".blue if VERBOSE
346
+ @insertdb.raw_insert("irc_data", ircvalue )
347
+ role_values = [CCIRC, flow.dst.address]
348
+ @insertdb.insert("host_roles", role_values ) unless @insertdb.select("host_roles", "role", CCIRC, "host_ip", flow.dst.address).one?
349
+ end
350
+ end
351
+
352
+
353
+ else
354
+
355
+ LOGGER_PARSER.info "PARSER", "Unknown traffic, try see if it is IRC traffic"
356
+
357
+ if Parser.guess(streamdata.inspect).class.inspect =~ /IRC/
358
+ ircvalues = search_irc(streamdata)
359
+ ircvalues.each do |ircvalue|
360
+ LOGGER_PARSER.debug "DB", " Inserting IRC DATA info from #{flow.dst.address.to_s}".blue if VERBOSE
361
+ @insertdb.raw_insert("irc_data", ircvalue )
362
+ role_values = [CCIRC, flow.dst.address]
363
+ @insertdb.insert("host_roles", role_values ) unless @insertdb.select("host_roles", "role", CCIRC, "host_ip", flow.dst.address).one?
364
+ end
365
+ end
366
+
367
+ end
368
+
369
+ when 17 then
370
+ #check if DNS
371
+
372
+ #Layer 4 analysis
373
+ case service
374
+ when "DNS" then
375
+ #DEBUG
376
+ #puts "DNS"
377
+
378
+ @i = 0
379
+ @p = []
380
+
381
+ flowdeep.each do |flow|
382
+ flow.each do |pkt|
383
+ @p[@i] = pkt.payload
384
+ @i = @i + 1
385
+ end
386
+ end
387
+
388
+
389
+ @p.each do |d|
390
+
391
+ begin
392
+
393
+ dns = DoroDNS.new(d)
394
+
395
+
396
+ dnsvalues = ["default", dns.name, dns.cls_i.inspect, dns.qry?, dns.ttl, flowid, dns.address.to_s, dns.data, dns.type_i.inspect]
397
+
398
+ LOGGER_PARSER.debug "DB", " Inserting DNS data from #{flow.dst.address.to_s}".blue if VERBOSE
399
+ unless @insertdb.insert("dns_data", dnsvalues )
400
+ LOGGER_PARSER.error "DB", " Error while Inserting DNS data".blue
401
+ nex
402
+ end
403
+ dnsid = @insertdb.find_seq("dns_id_seq").first['currval']
404
+
405
+ if dns.qry?
406
+ LOGGER_PARSER.info "DNS", "DNS Query:".white + " #{dns.name}".yellow + " class #{dns.cls_i} type #{dns.type_i}"
407
+ else
408
+ dns_list.merge!( dns.address.to_s => dnsid)
409
+ LOGGER_PARSER.info "DNS", "DNS Answer:".white + " #{dns.name}".yellow + " class #{dns.cls} type #{dns.type} ttl #{dns.ttl} " + "#{dns.address}".yellow
410
+ end
411
+
412
+ rescue
413
+
414
+ LOGGER_PARSER.error "DB", "Something went wrong while adding a DNS entry into the DB (packet malformed?) - The packet will be skipped ::."
415
+ LOGGER_PARSER.debug "DB", "#{$!}"
416
+ end
417
+
418
+
419
+ end
420
+ end
421
+
422
+ when 1 then
423
+ #TODO: ICMP data
424
+ #case ICMP xtractr.flows('flow.service:SMTP').first.proto = 1
425
+ else
426
+
427
+ LOGGER_PARSER.warn "PARSER", "Unknown protocol: #{flow.id} -- Proto #{flow.proto}".yellow
428
+
429
+ end
430
+
431
+
432
+ }
433
+
434
+ #DEBUG
435
+ #puts "save?"
436
+ #gets
437
+ @insertdb.set_analyzed(dump['hash'])
438
+ @insertdb.commit
439
+ @insertdb.close
440
+ end
441
+ end
442
+
443
+
444
+ def self.start(daemon)
445
+ daemon ||= false
446
+
447
+ puts "[DoroParser]".yellow + " Started, tail log file to see some stuff.."
448
+ LOGGER_PARSER.info "Dorothy", "Started".yellow
449
+
450
+ if daemon
451
+ check_pid_file DoroSettings.env[:pidfile]
452
+ puts "[DoroParser]".yellow + " Going in backround with pid #{Process.pid}"
453
+ Process.daemon
454
+ create_pid_file DoroSettings.env[:pidfile]
455
+ LOGGER_PARSER.info "DoroParser", "Going in backround with pid #{Process.pid}"
456
+ end
457
+
458
+
459
+ @insertdb = Insertdb.new
460
+ infinite = true
461
+
462
+ while infinite
463
+ pcaps = @insertdb.find_pcap
464
+ analyze_bintraffic pcaps
465
+ infinite = daemon
466
+ sleep DTIMEOUT if daemon # Sleeping a while if -d wasn't set, then quit.
467
+ end
468
+ LOGGER_PARSER.info "DoroParser" , "There are no more files to analyze.".yellow
469
+ exit(0)
470
+ end
471
+
472
+ def check_pid_file file
473
+ if File.exist? file
474
+ # If we get Errno::ESRCH then process does not exist and
475
+ # we can safely cleanup the pid file.
476
+ pid = File.read(file).to_i
477
+ begin
478
+ Process.kill(0, pid)
479
+ rescue Errno::ESRCH
480
+ stale_pid = true
481
+ rescue
482
+ end
483
+
484
+ unless stale_pid
485
+ puts "[DoroParser]".yellow + " Dorothy is already running (pid=#{pid})"
486
+ exit
487
+ end
488
+ end
489
+ end
490
+
491
+ def create_pid_file file
492
+ File.open(file, "w") { |f| f.puts Process.pid }
493
+
494
+ # Remove pid file during shutdown
495
+ at_exit do
496
+ LOGGER_PARSER.info "DoroParser", "Shutting down." rescue nil
497
+ if File.exist? file
498
+ File.unlink file
499
+ end
500
+ end
501
+ end
502
+
503
+ # Sends SIGTERM to process in pidfile. Server should trap this
504
+ # and shutdown cleanly.
505
+ def self.stop
506
+ LOGGER_PARSER.info "DoroParser", "Shutting down.."
507
+ pid_file = DoroSettings.env[:pidfile]
508
+ if pid_file and File.exist? pid_file
509
+ pid = Integer(File.read(pid_file))
510
+ Process.kill -15, -pid
511
+ puts "[DoroParser]".yellow + " Process #{pid} terminated"
512
+ LOGGER_PARSER.info "DoroParser", "Process #{pid} terminated"
513
+ else
514
+ puts "[DoroParser]".yellow + "Can't find PID file, is Dorothy really running?"
515
+ end
516
+ end
517
+
518
+ end