dorothy2 1.2.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|