dorothy2 1.2.0 → 2.0.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.
- checksums.yaml +8 -8
- data/CHANGELOG +39 -14
- data/README.md +80 -62
- data/UPDATE +6 -14
- data/bin/dorothy2 +472 -0
- data/dorothy2.gemspec +22 -16
- data/etc/ddl/dorothive.ddl +619 -373
- data/etc/sources.yml.example +27 -2
- data/lib/doroGUI.rb +232 -0
- data/lib/doroParser.rb +34 -78
- data/lib/dorothy2.rb +288 -248
- data/lib/dorothy2/BFM.rb +114 -61
- data/lib/dorothy2/DEM.rb +3 -1
- data/lib/dorothy2/NAM.rb +2 -2
- data/lib/dorothy2/Settings.rb +2 -1
- data/lib/dorothy2/VSM.rb +2 -1
- data/lib/dorothy2/deep_symbolize.rb +2 -7
- data/lib/dorothy2/do-init.rb +286 -19
- data/lib/dorothy2/do-logger.rb +1 -1
- data/lib/dorothy2/do-utils.rb +382 -33
- data/lib/dorothy2/version.rb +1 -1
- data/lib/dorothy2/vtotal.rb +30 -20
- data/lib/mu/xtractr.rb +11 -11
- data/lib/mu/xtractr/stream.rb +1 -1
- data/lib/www/public/reset.css +153 -0
- data/lib/www/public/style.css +65 -0
- data/lib/www/views/analyses.erb +28 -0
- data/lib/www/views/email.erb +63 -0
- data/lib/www/views/flows.erb +30 -0
- data/lib/www/views/layout.erb +27 -0
- data/lib/www/views/profile.erb +49 -0
- data/lib/www/views/queue.erb +28 -0
- data/lib/www/views/resume.erb +135 -0
- data/lib/www/views/resume.erb~ +88 -0
- data/lib/www/views/samples.erb +20 -0
- data/lib/www/views/upload.erb +154 -0
- data/share/img/The_big_picture.pdf +0 -0
- data/test/tc_dorothy_full.rb +3 -0
- metadata +169 -70
- data/TODO +0 -27
- data/bin/dorothy_start +0 -225
- data/bin/dorothy_stop +0 -28
- data/bin/dparser_start +0 -94
- data/bin/dparser_stop +0 -31
- data/etc/dorothy copy.yml.example +0 -39
- data/etc/extensions.yml +0 -41
- data/share/update-dorothive.sql +0 -19
data/etc/sources.yml.example
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
###
|
5
5
|
### type means the communication channel used
|
6
6
|
### to download the binaries, possible values
|
7
|
-
### are: system | ssh
|
7
|
+
### are: system | ssh | mail
|
8
8
|
###
|
9
9
|
### typeid defines the type of the source, it
|
10
10
|
### depends on a userdefined-type in
|
@@ -17,10 +17,20 @@
|
|
17
17
|
### 2 - unknown
|
18
18
|
#############################################
|
19
19
|
---
|
20
|
+
#dont change the name of the webgui source, or if wont work. Change only the local path, the priority and the profile
|
21
|
+
webgui:
|
22
|
+
type: web
|
23
|
+
localdir: /opt/dorothy2/opt/bins/web
|
24
|
+
typeid: 1
|
25
|
+
|
26
|
+
#Examples below
|
20
27
|
malwarefolder:
|
21
28
|
type: system
|
22
|
-
localdir: /
|
29
|
+
localdir: /opt/dorothy2/opt/bins/manual
|
23
30
|
typeid: 2
|
31
|
+
priority: 1
|
32
|
+
profile: test
|
33
|
+
|
24
34
|
honeypot1:
|
25
35
|
type: ssh
|
26
36
|
ip: 1.2.3.4
|
@@ -30,3 +40,18 @@ honeypot1:
|
|
30
40
|
remotedir: /asda/bins
|
31
41
|
localdir: /opt/bins/honeypot
|
32
42
|
typeid: 0
|
43
|
+
priority: 1
|
44
|
+
profile: test
|
45
|
+
|
46
|
+
mailpot@example.com:
|
47
|
+
type: mail
|
48
|
+
localdir: /opt/dorothy2/opt/bins/mailpot@example.com
|
49
|
+
typeid: 1
|
50
|
+
address: pop-mail.outlook.com
|
51
|
+
username: mailpot@example.com
|
52
|
+
password: myPASS
|
53
|
+
port: 995
|
54
|
+
enable_ssl: true
|
55
|
+
metodo_analisi: 1
|
56
|
+
priority: 2
|
57
|
+
profile: test
|
data/lib/doroGUI.rb
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'sinatra/activerecord'
|
3
|
+
require 'sinatra/namespace'
|
4
|
+
|
5
|
+
|
6
|
+
module Dorothy
|
7
|
+
class DoroGUI < Sinatra::Base
|
8
|
+
register Sinatra::Namespace
|
9
|
+
|
10
|
+
enable :logging, :dump_errors
|
11
|
+
file = File.new(DoroSettings.wgui[:logfile], 'a+')
|
12
|
+
file.sync = true
|
13
|
+
use Rack::CommonLogger, file
|
14
|
+
before { env['rack.errors'] = file }
|
15
|
+
|
16
|
+
set :app_file, __FILE__
|
17
|
+
root = File.expand_path(File.dirname(__FILE__))
|
18
|
+
set :public_folder, File.join(root, 'www/public')
|
19
|
+
set :views, Proc.new { File.join(root, 'www/views') }
|
20
|
+
|
21
|
+
|
22
|
+
ActiveRecord::Base.establish_connection(
|
23
|
+
adapter: 'postgresql',
|
24
|
+
host: DoroSettings.dorothive[:dbhost],
|
25
|
+
database: DoroSettings.dorothive[:dbname],
|
26
|
+
username: DoroSettings.dorothive[:dbuser],
|
27
|
+
password: DoroSettings.dorothive[:dbpass],
|
28
|
+
port: 5432,
|
29
|
+
schema_search_path: 'dorothy' )
|
30
|
+
|
31
|
+
sources = YAML.load_file(DoroSettings.env[:home] + '/etc/sources.yml')
|
32
|
+
|
33
|
+
|
34
|
+
class Analyses < ActiveRecord::Base
|
35
|
+
self.table_name = "analyses"
|
36
|
+
end
|
37
|
+
|
38
|
+
class Samples < ActiveRecord::Base
|
39
|
+
self.table_name = "samples"
|
40
|
+
end
|
41
|
+
|
42
|
+
class Flows < ActiveRecord::Base
|
43
|
+
self.table_name = "flows"
|
44
|
+
end
|
45
|
+
|
46
|
+
class Sandboxes < ActiveRecord::Base
|
47
|
+
self.table_name = "sandboxes"
|
48
|
+
end
|
49
|
+
|
50
|
+
class AnalysisQueue < ActiveRecord::Base
|
51
|
+
self.table_name = "analysis_queue"
|
52
|
+
end
|
53
|
+
|
54
|
+
class TrafficDumps < ActiveRecord::Base
|
55
|
+
self.table_name = "traffic_dumps"
|
56
|
+
end
|
57
|
+
|
58
|
+
class Sources < ActiveRecord::Base
|
59
|
+
self.table_name = "sources"
|
60
|
+
end
|
61
|
+
|
62
|
+
class Emails < ActiveRecord::Base
|
63
|
+
self.table_name = "emails"
|
64
|
+
end
|
65
|
+
|
66
|
+
class Receivers < ActiveRecord::Base
|
67
|
+
self.table_name = "email_receivers"
|
68
|
+
end
|
69
|
+
|
70
|
+
class Sightings < ActiveRecord::Base
|
71
|
+
self.table_name = "sightings"
|
72
|
+
end
|
73
|
+
|
74
|
+
class SystemProcs < ActiveRecord::Base
|
75
|
+
self.table_name = "sys_procs"
|
76
|
+
end
|
77
|
+
|
78
|
+
class Malwares < ActiveRecord::Base
|
79
|
+
self.table_name = "malwares"
|
80
|
+
end
|
81
|
+
|
82
|
+
class AvSigns < ActiveRecord::Base
|
83
|
+
self.table_name = "av_signs"
|
84
|
+
end
|
85
|
+
|
86
|
+
get '/' do
|
87
|
+
@title = "Analyses"
|
88
|
+
@analyses = Analyses.all
|
89
|
+
@samples = Samples.all
|
90
|
+
@queue = AnalysisQueue.all
|
91
|
+
@sightings = Sightings.all
|
92
|
+
@emails = Emails.all
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
erb :analyses
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
get '/queue' do
|
102
|
+
@title = "Queue Status"
|
103
|
+
@queue = AnalysisQueue.all.order(id: :asc, priority: :desc)
|
104
|
+
@sources = Sources.all
|
105
|
+
@analyses = Analyses.all
|
106
|
+
@emails = Emails.all
|
107
|
+
erb :queue
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
get '/resume/:analid' do
|
112
|
+
@title = "Sample Analysis Resume"
|
113
|
+
@analysis_dir = DoroSettings.env[:analysis_dir]
|
114
|
+
@analid = params[:analid]
|
115
|
+
@sample = Samples.where(:sha256 => Analyses.where(:id => @analid).first.sample).first
|
116
|
+
@sys_procs = SystemProcs.where(:analysis_id => params[:analid])
|
117
|
+
@malware = Malwares.where(:bin => Analyses.where(:id => @analid).first.sample).first
|
118
|
+
@sophos = @malware.nil? ? nil : AvSigns.where(:id => @malware.id).where(:av_name => 'Sophos').first
|
119
|
+
|
120
|
+
@mailid = Sightings.where(:id => AnalysisQueue.where( :id => Analyses.where(:id => @analid).first.queue_id).first.sighting).first.src_email
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
@net_dumps = TrafficDumps.where(:sha256 => Analyses.where(:id => @analid).first.traffic_dump)
|
125
|
+
@flows= Flows.where(:traffic_dump => Analyses.where(:id => @analid).first.traffic_dump)
|
126
|
+
|
127
|
+
@imgs = []
|
128
|
+
Dir[DoroSettings.env[:analysis_dir] + "/#{@analid}/screens/*.png"].each {|file| @imgs.push(File.basename(file)) }
|
129
|
+
|
130
|
+
erb :resume
|
131
|
+
end
|
132
|
+
|
133
|
+
get '/screens/:analid/:name' do
|
134
|
+
full_path = DoroSettings.env[:analysis_dir] + "/" + params[:analid] + "/screens/" + params[:name]
|
135
|
+
send_file full_path.strip, :filename => params[:name].strip, :disposition => 'inline'
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
get '/profile/:profile' do
|
140
|
+
@profile = Util.load_profile(params[:profile])
|
141
|
+
|
142
|
+
erb :profile
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
get '/upload' do
|
147
|
+
@sandboxes = Sandboxes.all
|
148
|
+
@profiles = YAML.load_file(DoroSettings.env[:home] + '/etc/profiles.yml')
|
149
|
+
|
150
|
+
erb :upload
|
151
|
+
end
|
152
|
+
|
153
|
+
post '/upload' do
|
154
|
+
localpath = sources["webgui"]["localdir"] + "/#{params[:uploaded_data][:filename]}"
|
155
|
+
FileUtils.mv(params[:uploaded_data][:tempfile].path, localpath) unless params[:uploaded_data].nil?
|
156
|
+
id = QueueManager.add(localpath, 'webgui', params[:profile], params[:priority])
|
157
|
+
|
158
|
+
#entry = AnalysisQueue.create(date: get_time, binary: localpath, filename: filename, source: "webgui", priority: params[:priority], profile: params[:OS], user: "webuser")
|
159
|
+
#entry.save
|
160
|
+
erb "Upload Complete. Prio #{params[:priority]} - OS #{params[:OS]} - Scheduled with Queue ID #{id}"
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
|
165
|
+
namespace '/email' do
|
166
|
+
get '/view/:mail_id' do
|
167
|
+
@email = Emails.where(:id => params[:mail_id]).first
|
168
|
+
@receivers = Receivers.where(:email_id => params[:mail_id])
|
169
|
+
erb :email
|
170
|
+
end
|
171
|
+
|
172
|
+
get '/download/:mail_id' do
|
173
|
+
email = Emails.where(:id => params[:mail_id]).first
|
174
|
+
|
175
|
+
content_type 'Application/octet-stream'
|
176
|
+
attachment( "Message_#{email.id}" + '.eml')
|
177
|
+
PG::Connection.unescape_bytea(email.data)
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
|
184
|
+
namespace '/samples/' do
|
185
|
+
|
186
|
+
get '/' do
|
187
|
+
@title = "Sample Information"
|
188
|
+
@samples = Samples.all
|
189
|
+
erb :samples
|
190
|
+
end
|
191
|
+
|
192
|
+
get ':sha256' do |sha256|
|
193
|
+
@samples = Samples.where(:sha256 => params[:sha256])
|
194
|
+
|
195
|
+
#list all the analysis that have been done on this file , including timestamp, OS, etc
|
196
|
+
erb :samples
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
get 'download/:sha256' do |sha256|
|
201
|
+
first_id = Analyses.where(:sample => params[:sha256]).first.id
|
202
|
+
filename = Samples.where(:sha256 => params[:sha256]).first.filename
|
203
|
+
full_path = DoroSettings.env[:analysis_dir] + "/#{first_id}/bin/" + filename
|
204
|
+
send_file full_path.strip, :filename => filename, :type => 'Application/octet-stream'
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
namespace '/net' do
|
211
|
+
|
212
|
+
namespace '/:dump_sha1' do
|
213
|
+
|
214
|
+
get '/' do
|
215
|
+
@title = "Network Flows"
|
216
|
+
@net_dumps = TrafficDumps.where(:sha256 => params[:dump_sha1])
|
217
|
+
@flows= Flows.where(:traffic_dump => params[:dump_sha1])
|
218
|
+
|
219
|
+
erb :flows
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
after do
|
227
|
+
ActiveRecord::Base.connection.close
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
data/lib/doroParser.rb
CHANGED
@@ -13,26 +13,18 @@
|
|
13
13
|
## Data Definition Module ##
|
14
14
|
############################
|
15
15
|
|
16
|
-
|
17
|
-
require 'rbvmomi'
|
18
|
-
require 'rest_client'
|
16
|
+
|
19
17
|
require 'net/dns'
|
20
18
|
require 'net/dns/packet'
|
21
19
|
require 'ipaddr'
|
22
|
-
require 'colored'
|
23
|
-
require 'filemagic'
|
24
20
|
require 'geoip'
|
25
|
-
require 'pg'
|
26
|
-
require 'tmail'
|
27
21
|
require 'ipaddr'
|
28
22
|
require 'net/http'
|
29
23
|
require 'json'
|
30
24
|
|
31
25
|
require File.dirname(__FILE__) + '/mu/xtractr'
|
32
26
|
require File.dirname(__FILE__) + '/dorothy2/DEM'
|
33
|
-
|
34
|
-
require File.dirname(__FILE__) + '/dorothy2/do-logger'
|
35
|
-
require File.dirname(__FILE__) + '/dorothy2/deep_symbolize'
|
27
|
+
|
36
28
|
|
37
29
|
|
38
30
|
module DoroParser
|
@@ -41,6 +33,7 @@ module DoroParser
|
|
41
33
|
CCIRC = 1
|
42
34
|
CCDROP = 3
|
43
35
|
CCSUPPORT = 5
|
36
|
+
NONETBIOS = true
|
44
37
|
|
45
38
|
def search_irc(streamdata)
|
46
39
|
|
@@ -53,14 +46,13 @@ module DoroParser
|
|
53
46
|
|
54
47
|
ircvalues.push "default, currval('dorothy.connections_id_seq'), E'#{Insertdb.escape_bytea(m[0])}', #{direction_bool}"
|
55
48
|
end
|
56
|
-
|
49
|
+
ircvalues
|
57
50
|
end
|
58
51
|
|
59
52
|
def analyze_bintraffic(pcaps)
|
60
53
|
|
61
54
|
dns_list = Hash.new
|
62
55
|
hosts = []
|
63
|
-
@insertdb.begin_t
|
64
56
|
|
65
57
|
pcaps.each do |dump|
|
66
58
|
#RETRIVE MALWARE FILE INFO
|
@@ -92,12 +84,12 @@ module DoroParser
|
|
92
84
|
#The following section is to avoid a crash while quering such (still-empty instance)
|
93
85
|
#In addition, an added check is inserted, to see if the pcapr instance really match the pcap filename
|
94
86
|
begin
|
95
|
-
|
96
|
-
|
97
|
-
|
87
|
+
pcapr_query = URI.parse "http://#{DoroSettings.pcapr[:host]}:#{DoroSettings.pcapr[:port]}/pcaps/1/about/#{dump['pcapr_id'].rstrip}"
|
88
|
+
pcapr_response = Net::HTTP.get_response(pcapr_query)
|
89
|
+
pcapname = File.basename(JSON.parse(pcapr_response.body)["filename"], ".pcap")
|
98
90
|
|
99
|
-
|
100
|
-
|
91
|
+
t ||= $1 if pcapname =~ /[0-9]*\-(.*)$/
|
92
|
+
raise NameError.new if t != dump['sample'].rstrip
|
101
93
|
|
102
94
|
rescue NameError
|
103
95
|
LOGGER_PARSER.error "PARSER", "The pcapr filename mismatchs the one present in Dorothive!. Skipping."
|
@@ -111,6 +103,9 @@ module DoroParser
|
|
111
103
|
|
112
104
|
LOGGER_PARSER.info "PARSER", "Scanning network flows and searching for unknown host IPs".yellow
|
113
105
|
|
106
|
+
@insertdb.begin_t
|
107
|
+
|
108
|
+
|
114
109
|
xtractr.flows.each { |flow|
|
115
110
|
|
116
111
|
begin
|
@@ -139,7 +134,7 @@ module DoroParser
|
|
139
134
|
|
140
135
|
|
141
136
|
#insert Geoinfo
|
142
|
-
unless
|
137
|
+
unless localnet.include?(flow.dst.address) || multicast.include?(flow.dst.address)
|
143
138
|
|
144
139
|
geo = Geoinfo.new(flow.dst.address.to_s)
|
145
140
|
geoval = ["default", geo.coord, geo.country, geo.city, geo.updated, geo.asn]
|
@@ -163,9 +158,9 @@ module DoroParser
|
|
163
158
|
#Insert host info
|
164
159
|
#ip - geoinfo - sbl - uptime - is_online - whois - zone - last-update - id - dns_name
|
165
160
|
hostname = (dns_list[dest].nil? ? "null" : dns_list[dest])
|
166
|
-
hostval = [dest, geoval, "null", "null", true, "null", "null", get_time, "default", hostname]
|
161
|
+
hostval = [dest, geoval, "null", "null", true, "null", "null", Util.get_time, "default", hostname]
|
167
162
|
|
168
|
-
|
163
|
+
unless @insertdb.insert("host_ips",hostval)
|
169
164
|
LOGGER_PARSER.debug "DB", " Skipping flow #{flow.id}: #{flow.src.address} > #{flow.dst.address}" if VERBOSE
|
170
165
|
next
|
171
166
|
end
|
@@ -179,7 +174,7 @@ module DoroParser
|
|
179
174
|
|
180
175
|
flowvals = [flow.src.address, flow.dst.address, flow.sport, flow.dport, flow.bytes, dump['sha256'], flow.packets, "default", flow.proto, flow.service.name, title, "null", flow.duration, flow.time, flow.id ]
|
181
176
|
|
182
|
-
|
177
|
+
unless @insertdb.insert("flows",flowvals)
|
183
178
|
LOGGER_PARSER.info "PARSER", "Skipping flow #{flow.id}: #{flow.src.address} > #{flow.dst.address}"
|
184
179
|
next
|
185
180
|
end
|
@@ -424,72 +419,33 @@ module DoroParser
|
|
424
419
|
|
425
420
|
LOGGER_PARSER.info "PARSER", "Started, looking for network dumps into Dorothive.."
|
426
421
|
|
427
|
-
if daemon
|
428
|
-
check_pid_file DoroSettings.env[:pidfile_parser]
|
429
|
-
puts "[PARSER]".yellow + " Going in backround with pid #{Process.pid}"
|
430
|
-
puts "[PARSER]".yellow + " Logging on #{DoroSettings.env[:logfile_parser]}"
|
431
|
-
Process.daemon
|
432
|
-
create_pid_file DoroSettings.env[:pidfile_parser]
|
433
|
-
puts "[PARSER]".yellow + " Going in backround with pid #{Process.pid}"
|
434
|
-
end
|
435
422
|
|
436
|
-
@insertdb = Insertdb.new
|
437
423
|
infinite = true
|
438
424
|
|
439
|
-
|
440
|
-
pcaps = @insertdb.find_pcap
|
441
|
-
analyze_bintraffic(pcaps)
|
442
|
-
infinite = daemon
|
443
|
-
LOGGER.info "PARSER", "SLEEPING" if daemon
|
444
|
-
sleep DoroSettings.env[:dtimeout].to_i if daemon # Sleeping a while if -d wasn't set, then quit.
|
445
|
-
end
|
446
|
-
LOGGER_PARSER.info "PARSER" , "There are no more pcaps to analyze.".yellow
|
447
|
-
@insertdb.close
|
448
|
-
exit(0)
|
449
|
-
end
|
425
|
+
@insertdb = Insertdb.new
|
450
426
|
|
451
|
-
def check_pid_file file
|
452
|
-
if File.exist? file
|
453
|
-
# If we get Errno::ESRCH then process does not exist and
|
454
|
-
# we can safely cleanup the pid file.
|
455
|
-
pid = File.read(file).to_i
|
456
|
-
begin
|
457
|
-
Process.kill(0, pid)
|
458
|
-
rescue Errno::ESRCH
|
459
|
-
stale_pid = true
|
460
|
-
end
|
461
427
|
|
462
|
-
|
463
|
-
|
464
|
-
|
428
|
+
begin
|
429
|
+
while infinite
|
430
|
+
begin
|
431
|
+
pcaps = @insertdb.find_pcap
|
432
|
+
analyze_bintraffic(pcaps)
|
433
|
+
rescue SignalException #, RuntimeError
|
434
|
+
LOGGER.warn "PARSER", "SIGINT".red + " Catched [1], exiting gracefully."
|
435
|
+
end
|
436
|
+
infinite = daemon
|
437
|
+
LOGGER.debug "PARSER", "SLEEPING" if daemon && DEBUG
|
438
|
+
sleep DoroSettings.env[:sleeptime].to_i if daemon # Sleeping a while if -d wasn't set, then quit.
|
465
439
|
end
|
466
|
-
|
467
|
-
|
440
|
+
LOGGER_PARSER.info "PARSER" , "There are no more pcaps to analyze.".yellow if DEBUG
|
441
|
+
@insertdb.close
|
442
|
+
exit(0)
|
468
443
|
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
# Remove pid file during shutdown
|
473
|
-
at_exit do
|
474
|
-
LOGGER_PARSER.info "PARSER", "Shutting down." rescue nil
|
475
|
-
if File.exist? file
|
476
|
-
File.unlink file
|
477
|
-
end
|
444
|
+
rescue SignalException #, RuntimeError
|
445
|
+
LOGGER.warn "PARSER", "SIGINT".red + " Catched [2], exiting gracefully."
|
478
446
|
end
|
479
|
-
end
|
480
447
|
|
481
|
-
# Sends SIGTERM to process in pidfile. Server should trap this
|
482
|
-
# and shutdown cleanly.
|
483
|
-
def self.stop
|
484
|
-
LOGGER_PARSER.info "PARSER", "Shutting down.."
|
485
|
-
pid_file = DoroSettings.env[:pidfile_parser]
|
486
|
-
if pid_file and File.exist? pid_file
|
487
|
-
pid = Integer(File.read(pid_file))
|
488
|
-
Process.kill -15, -pid
|
489
|
-
LOGGER_PARSER.info "PARSER", "Process #{DoroSettings.env[:pidfile_parser]} terminated"
|
490
|
-
else
|
491
|
-
LOGGER_PARSER.info "PARSER", "Can't find PID file, is DoroParser really running?"
|
492
|
-
end
|
493
448
|
end
|
494
449
|
|
450
|
+
|
495
451
|
end
|