honeycomb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,72 @@
1
+ = honeycomb
2
+ Josh Grunzweig - jgrunzweig at trustwave dot com
3
+
4
+ == Introduction
5
+
6
+ Tool to manage and analyze data from the Dionaea Honeypot Project
7
+
8
+ The Dionaea Project is a great honeypot which originated from the Google Summer
9
+ of Code. The project aims at obtaining malware samples by emulating Microsoft
10
+ Windows services, however, has branched out since its create to emulate other
11
+ services as well, such as MySQL. This project was created out of the necessity
12
+ to monitor and manage multiple instances of the Dionaea on honeypots located
13
+ around the world.
14
+
15
+ You can view more information about the Dionaea at the following address:
16
+ http://dionaea.carnivore.it/
17
+
18
+
19
+ == Usage
20
+
21
+ # basic example... See how much disk space is located on all honeypots
22
+
23
+ require 'honeycomb'
24
+
25
+ all_pots = Honeycomb::Interact.new
26
+
27
+ all_pots.check_diskspace
28
+
29
+
30
+ # another example... See how many instances of a specific md5 there are
31
+
32
+ require 'honeycomb'
33
+
34
+ all_pots = Honeycomb::Interact.new
35
+
36
+ all_pots.all{Honeycomb::Download.all(:download_md5_hash => "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")}
37
+
38
+ == Versioning
39
+ The current version of honeycomb at the time of writing is 0.0.1. Code will be
40
+ buggy. Features may be lacking. However, in time I hope to make this a pretty
41
+ functional/useful tool.
42
+
43
+
44
+ == Requirements
45
+ There is, unfortunately, a number of gem pre-requisites. Apologies for this,
46
+ but it's the only way I could do it.
47
+
48
+ * bundler
49
+
50
+ After bundler is installed, do a "bundle install" to get everything installed.
51
+
52
+
53
+ == Copyright
54
+ honeycomb - Tool to manage and analyze data from the Dionaea Honeypot Project
55
+ Josh Grunzweig
56
+ Copyright (C) 2011 Trustwave Holdings
57
+
58
+ This program is free software: you can redistribute it and/or modify it
59
+ under the terms of the GNU General Public License as published by the
60
+ Free Software Foundation, either version 3 of the License, or (at your
61
+ option) any later version.
62
+
63
+ This program is distributed in the hope that it will be useful, but
64
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
65
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
66
+ for more details.
67
+
68
+ You should have received a copy of the GNU General Public License along
69
+ with this program. If not, see <http://www.gnu.org/licenses/>.
70
+
71
+ See LICENSE.txt
72
+
data/Rakefile ADDED
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ require 'rake'
6
+
7
+ begin
8
+ Bundler.setup(:default, :development)
9
+ rescue Bundler::BundlerError => e
10
+ $stderr.puts e.message
11
+ $stderr.puts "Run `bundle install` to install missing gems"
12
+ exit e.status_code
13
+ end
14
+
15
+ Dir["tasks/*.rake"].each { |taskfile| load taskfile }
16
+
17
+ require 'jeweler'
18
+ Jeweler::Tasks.new do |gem|
19
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
20
+ gem.name = "honeycomb"
21
+ gem.homepage = "http://github.com/spiderlabs/honeycomb"
22
+ gem.license = "GNU v3"
23
+ gem.summary = %Q{Tool to manage and analyze data from the Dionaea Honeypot Project}
24
+ gem.description = %Q{Tool to manage and analyze data from the Dionaea Honeypot Project}
25
+ gem.email = "jgrunzweig at trustwave dot com"
26
+ gem.authors = ["Josh Grunzweig"]
27
+ # dependencies defined in Gemfile
28
+ end
29
+ Jeweler::RubygemsDotOrgTasks.new
30
+
31
+ require 'rspec/core'
32
+ require 'rspec/core/rake_task'
33
+ RSpec::Core::RakeTask.new(:spec) do |spec|
34
+ spec.pattern = FileList['spec/**/*_spec.rb']
35
+ end
36
+
37
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
38
+ spec.pattern = 'spec/**/*_spec.rb'
39
+ spec.rcov = true
40
+ end
41
+
42
+ task :default => :spec
43
+
44
+ require 'rdoc/task'
45
+ Rake::RDocTask.new do |rdoc|
46
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
47
+
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "honeycomb #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
File without changes
File without changes
@@ -0,0 +1,11 @@
1
+ honey_config:
2
+ servers: ['honeypot1', 'honeypot2']
3
+ username: 'r00t'
4
+ key: 'path/to/key'
5
+ password: 'sekret'
6
+ path: 'path/to/dionaea'
7
+ # Uncomment to following to change default directory of
8
+ # honeycomb/data/binaries
9
+ # honeycomb/data/logsql
10
+ #download_binaries: 'where/to/store/binaries'
11
+ #download_databases: 'where/to/store/databases'
data/lib/honeycomb.rb ADDED
@@ -0,0 +1,24 @@
1
+ # honeycomb - Tool to manage and analyze data from the Dionaea Honeypot
2
+ # Project
3
+ # Josh Grunzweig
4
+ # Copyright (C) 2011 Trustwave Holdings
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify it
7
+ # under the terms of the GNU General Public License as published by the
8
+ # Free Software Foundation, either version 3 of the License, or (at your
9
+ # option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful, but
12
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
+ # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
+ # for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License along
17
+ # with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ require 'honeycomb/interact'
21
+ require 'honeycomb/environment'
22
+ require 'honeycomb/default_setup'
23
+ require 'honeycomb/model'
24
+
@@ -0,0 +1,25 @@
1
+ # honeycomb - Tool to manage and analyze data from the Dionaea Honeypot
2
+ # Project
3
+ # Josh Grunzweig
4
+ # Copyright (C) 2011 Trustwave Holdings
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify it
7
+ # under the terms of the GNU General Public License as published by the
8
+ # Free Software Foundation, either version 3 of the License, or (at your
9
+ # option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful, but
12
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
+ # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
+ # for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License along
17
+ # with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ require 'honeycomb'
21
+ require 'honeycomb/model'
22
+
23
+ Honeycomb::Env.read_config
24
+ Honeycomb::Model.setup!
25
+
@@ -0,0 +1,64 @@
1
+ # honeycomb - Tool to manage and analyze data from the Dionaea Honeypot
2
+ # Project
3
+ # Josh Grunzweig
4
+ # Copyright (C) 2011 Trustwave Holdings
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify it
7
+ # under the terms of the GNU General Public License as published by the
8
+ # Free Software Foundation, either version 3 of the License, or (at your
9
+ # option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful, but
12
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
+ # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
+ # for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License along
17
+ # with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ require 'pathname'
21
+ require 'yaml'
22
+
23
+ module Honeycomb
24
+
25
+ module Environment
26
+ CONFIG = {}
27
+ CFGFILE = Pathname.new(__FILE__).dirname.dirname.dirname.expand_path.join('etc').join('config.yml')
28
+
29
+ # TODO: Comment
30
+ def self.load_config(hash)
31
+ hash.each do |k,v|
32
+ if v.is_a?(String)
33
+ v = v.gsub(/\$([A-Z][A-Z0-9_]*)\$/) do |v|
34
+ var = $1
35
+ if const_defined?(var)
36
+ const_get(var).to_s
37
+ else
38
+ raise("Invalid variable referenced in configuration: #{v}")
39
+ end
40
+ end
41
+ end
42
+ CONFIG[k.to_s] = v
43
+ end
44
+ end
45
+
46
+ # TODO: Comment
47
+ def self.read_config(file=CFGFILE)
48
+ if h = YAML.load_file(file)
49
+ if h.is_a?(Hash)
50
+ load_config(h)
51
+ else
52
+ raise("invalid honeycomb config file format")
53
+ end
54
+ end
55
+ end
56
+
57
+ end
58
+
59
+ Env = Environment
60
+
61
+ end
62
+
63
+
64
+
@@ -0,0 +1,20 @@
1
+ # honeycomb - Tool to manage and analyze data from the Dionaea Honeypot
2
+ # Project
3
+ # Josh Grunzweig
4
+ # Copyright (C) 2011 Trustwave Holdings
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify it
7
+ # under the terms of the GNU General Public License as published by the
8
+ # Free Software Foundation, either version 3 of the License, or (at your
9
+ # option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful, but
12
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
+ # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
+ # for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License along
17
+ # with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ require 'honeycomb/interact/interact'
@@ -0,0 +1,392 @@
1
+ # honeycomb - Tool to manage and analyze data from the Dionaea Honeypot
2
+ # Project
3
+ # Josh Grunzweig
4
+ # Copyright (C) 2011 Trustwave Holdings
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify it
7
+ # under the terms of the GNU General Public License as published by the
8
+ # Free Software Foundation, either version 3 of the License, or (at your
9
+ # option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful, but
12
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
+ # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
+ # for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License along
17
+ # with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+
20
+ require 'net/ssh'
21
+ require 'net/scp'
22
+ require 'open3'
23
+
24
+ module Honeycomb
25
+
26
+ class Interact
27
+
28
+ attr_accessor :db_path, :bin_path, :base_path, :username, :servers, :key
29
+
30
+ # This initializes a Honeycomb::Interact object and sets all the necessary
31
+ # variables which are used by other methods of the object.
32
+ #
33
+ # Variables and their purpose:
34
+ # * db_path - Path where databases are stored/saved
35
+ # * bin_path - Path where binaries are stored/saved
36
+ # * username - Username to connect to remote honeypot servers
37
+ # * key - Path to private key which is used for connections to honeypot
38
+ # servers
39
+ # * servers - Array of servers to connect to
40
+ # * base_path - Base location where Dionaea is installed to (Default per
41
+ # installation instructions: /opt/dionaea)
42
+ def initialize(db_path = nil, bin_path = nil, username = nil, key = nil,
43
+ servers = nil, base_path = nil)
44
+ self.db_path = Honeycomb::Env::CONFIG[:download_databases] ||
45
+ self.db_path = Pathname.new(__FILE__).dirname.dirname.dirname.dirname.expand_path.join('data').join('logsql/').to_s ||
46
+ db_path
47
+ self.bin_path = Honeycomb::Env::CONFIG[:download_binaries] ||
48
+ self.bin_path = Pathname.new(__FILE__).dirname.dirname.dirname.dirname.expand_path.join('data').join('binaries/').to_s ||
49
+ bin_path
50
+ self.username = Honeycomb::Env::CONFIG["honey_config"]["username"] ||
51
+ username
52
+ self.key = Honeycomb::Env::CONFIG["honey_config"]["key"] || key
53
+ self.servers = Honeycomb::Env::CONFIG["honey_config"]["servers"] ||
54
+ servers
55
+ self.base_path = Honeycomb::Env::CONFIG["honey_config"]["path"] ||
56
+ base_path
57
+ end
58
+
59
+ # This method will attempt to download all binaries from all servers
60
+ # specified in Honeycomb::Interact.servers.
61
+ #
62
+ # It will attempt to store all binaries into the folder specified in
63
+ # Honeycomb::Interact.bin_path.
64
+ #
65
+ # Additionally, rsync is utilized to transfer these files. It was
66
+ # chosen to use rsync over scp in order to limit the amount of
67
+ # bandwidth used between the client and servers.
68
+ #
69
+ # Arguments:
70
+ # * server - Array of servers to query
71
+ def download_binaries(server = self.servers)
72
+ server.each do |server|
73
+ tries = 0
74
+ puts "Downloading binaries from #{server} ..."
75
+ begin
76
+ Open3::popen3("rsync -v --force --ignore-errors --times -r -u -e \"ssh -i #{self.key}\" #{self.username}@#{server}:#{self.base_path}/var/dionaea/binaries/ #{self.bin_path}") { |stdin, stdout, stderr|
77
+ puts stdout.read.strip
78
+ puts stderr.read.strip
79
+ }
80
+ rescue
81
+ tries += 1
82
+ retry if tries <= 3
83
+ puts "Unable to connect. Moving on ..."
84
+ next
85
+ end
86
+ end
87
+ end
88
+
89
+ # This method will attempt to download all databases from all servers
90
+ # specified in Honeycomb::Interact.servers.
91
+ #
92
+ # It will attempt to store all binaries into the folder specified in
93
+ # Honeycomb::Interact.db_path.
94
+ #
95
+ # Additionally, scp is utilized to transfer these files. During tests,
96
+ # it was discovered that rsync had less than ideal results when
97
+ # downloading these files. While the transfer would appear to occur
98
+ # without error, the databases were often found to be corrupt.
99
+ #
100
+ # Arguments:
101
+ # * server - Array of servers to query
102
+ def download_databases(server = self.servers)
103
+ server.each do |server|
104
+ tries = 0
105
+ begin
106
+ Net::SSH.start(server, self.username, :keys => self.key) do |session|
107
+ puts "Downloading database from #{server} ..."
108
+ session.scp.download!(base_path + "/var/dionaea/logsql.sqlite",
109
+ self.db_path + "#{server}.sqlite")
110
+ end
111
+ rescue Errno::ETIMEDOUT
112
+ tries += 1
113
+ retry if tries <= 3
114
+ puts "Unable to connect. Moving on ..."
115
+ next
116
+ rescue Exception => e
117
+ puts "Error encountered: #{e.message}"
118
+ next
119
+ end
120
+ end
121
+ end
122
+
123
+ # This method will execute a command via ssh on all servers specified in
124
+ # the Honeycomb::Interact.servers variable. This command calls the internal
125
+ # ssh_command method in order to properly function.
126
+ #
127
+ # Argument:
128
+ # * command - Command to execute
129
+ #
130
+ # Returns:
131
+ # * Nothing
132
+ #
133
+ # Multiple strings with the results are outputted to the screen.
134
+ def execute_command(command)
135
+ response = self.ssh_command(command)
136
+ response.each do |server_hash|
137
+ puts "Executing #{command} on #{server_hash[:server]}:"
138
+ puts "\t#{server_hash[:result].gsub!(/\n/,"\n\t")}"
139
+ end
140
+ end # end execute_command
141
+
142
+ # This method will query the diskspace on all remote servers by calling
143
+ # the internal ssh_command method. It executes the command 'df -h /' and
144
+ # parses the results. The response is then parsed to return the total
145
+ # percentage of diskspace being used currently on each host.
146
+ #
147
+ # Arguments:
148
+ # * None
149
+ #
150
+ # Returns:
151
+ # * [ {:server => "Server Hostname", :result =>
152
+ #
153
+ # Multiple strings with the results are outputted to the screen.
154
+ def check_diskspace
155
+ response = self.ssh_command("df -h /")
156
+ all_usage = []
157
+ response.each do |server_hash|
158
+ usage = server_hash[:result]
159
+ if usage =~ /^(\/\w+)+.+\S+\s+\S+\s+\S+\s+(([0-9]+)%)/m
160
+ all_usage << {:server => server_hash[:server], :result => $2}
161
+ end
162
+ end
163
+ all_usage
164
+ end # end check_diskspace
165
+
166
+ # Only leaving this in here because it does a decent job of showing some
167
+ # of the stuff you can do with these DataMapper database bindings.
168
+ #
169
+ # This method was mainly created to be utilized for another project. It
170
+ # takes the md5 as in argument and performs a series of queries against
171
+ # all of the database to retrieve a large amount of data about that
172
+ # provided binary (in md5 checksum)
173
+ #
174
+ # Multiple encounters can be returned. These encounters are uniqued based
175
+ # on the URL of the download. Additionally, if duplicates of a given url
176
+ # are discovered, the encounter with the earliest timestamp is added to
177
+ # the hash.
178
+ #
179
+ # Argument:
180
+ # * md5 - MD5 String of the binary to be examined.
181
+ #
182
+ # Returns:
183
+ # * Hash -
184
+ # {:md5 => <md5_provided>,
185
+ # :encounters = [{ :url => <url_discovered>,
186
+ # :original_filename => <md5_provided>,
187
+ # :remote_host => <ip_address>,
188
+ # :source_timestamp => <Time>,
189
+ # :source => "Honeypot - <ip_address>",
190
+ # :virustotal => {:url => <url>,
191
+ # :timestamp => <timestamp_of_vt_scan>,
192
+ # :results => {:scanner => <scanner>,
193
+ # :result => <result>}
194
+ # }
195
+ # }
196
+ def self.get_md5_info(md5)
197
+ all_encounters = []
198
+ all_instances = self.all{Honeycomb::Download.all(:download_md5_hash => md5)}
199
+ all_instances.each do |instance|
200
+ all_encounters << {:url => instance.download_url}
201
+ end
202
+ num = 0
203
+ all_encounters.uniq! {|e| e[:url] }
204
+ all_encounters.each do |url|
205
+ all_connections = self.all{Honeycomb::Download.all(:download_md5_hash => md5,
206
+ :download_url => url[:url]).connections}
207
+ connection = {}
208
+ all_connections.each do |conn|
209
+ if not connection[:source_timestamp].nil?
210
+ if Time.at(connection[:source_timestamp]) > Time.at(conn.connection_timestamp.to_i)
211
+ connection[:source_timestamp] = Time.at(conn.connection_timestamp.to_i)
212
+ connection[:remote_host] = conn.remote_host
213
+ connection[:source] = conn.local_host
214
+ end
215
+ else
216
+ connection[:source_timestamp] = Time.at(conn.connection_timestamp.to_i)
217
+ connection[:remote_host] = conn.remote_host
218
+ connection[:source] = conn.local_host
219
+ end
220
+ end
221
+ all_encounters[num][:original_filename] = md5
222
+ all_encounters[num][:remote_host] = connection[:remote_host]
223
+ all_encounters[num][:source_timestamp] = connection[:source_timestamp]
224
+ all_encounters[num][:source] = "Honeypot - #{connection[:source]}"
225
+ virustotal_links = self.all{Honeycomb::Virustotal.first(:virustotal_md5_hash => md5).virustotal_permalink}
226
+ virustotal_timestamp = self.all{Honeycomb::Virustotal.first(:virustotal_md5_hash => md5).virustotal_timestamp}
227
+ virustotal_results = {}
228
+ self.all{Honeycomb::Virustotal.first(:virustotal_md5_hash => md5).virustotalscans}.each do |vtscan|
229
+ virustotal_results[:scanner] = vtscan.virustotalscan_scanner
230
+ virustotal_results[:result] = vtscan.virustotalscan_result
231
+ end
232
+ all_encounters[num][:virustotal] = {:url => virustotal_links,
233
+ :timestamp => virustotal_timestamp, :results => virustotal_results} if virustotal_links
234
+ num += 1
235
+ end
236
+ return {:md5 => md5, :encounters => all_encounters}
237
+ end
238
+
239
+
240
+
241
+ # This method will call the get_md5_info method on all binaries located
242
+ # in the provided directory. This information is then outputted to screen
243
+ # (soon to be changed).
244
+ #
245
+ # Again, only leaving this in here because it does a decent job of showing
246
+ # the kind of information you can pull.
247
+ #
248
+ # Argument:
249
+ # * dif - Directory of binaries
250
+ #
251
+ # Retruns:
252
+ # * Nothing
253
+ #
254
+ # Multiple items are outputted to the screen.
255
+ def self.get_all_md5_info(dir = Pathname.new(__FILE__).dirname.dirname.dirname.dirname.expand_path.join('data').join('binaries/').to_s)
256
+ results = []
257
+ all_binaries = Dir.entries(dir)
258
+ all_binaries.each do |bin|
259
+ if bin =~ /\w{32}/
260
+ require 'pp'
261
+ pp self.get_md5_info(bin)
262
+ end
263
+ end
264
+ end
265
+
266
+ # Used for executing a query against all databases at once.
267
+ def all(&block)
268
+ all_values = []
269
+ ::DataMapper::Repository.adapters.each do |repo|
270
+ if repo[0] == :default
271
+ next
272
+ end
273
+ begin
274
+ response = DataMapper.repository(repo[0]) {yield}
275
+ if response.kind_of?(DataMapper::Collection)
276
+ response.each do |x|
277
+ all_values << x
278
+ end
279
+ else
280
+ all_values << response if response
281
+ end
282
+ rescue Exception => e
283
+ #puts e.message
284
+ end
285
+ end
286
+ all_values
287
+ end
288
+
289
+ # Used for executing a query against a single database.
290
+ def individual(repo, &block)
291
+ all_values = []
292
+ begin
293
+ response = DataMapper.repository(repo[0]) {yield}
294
+ if response.kind_of?(DataMapper::Collection)
295
+ response.each do |x|
296
+ all_values << x
297
+ end
298
+ else
299
+ all_values << response if response
300
+ end
301
+ rescue Exception => e
302
+ #puts e.message
303
+ end
304
+ all_values
305
+ end
306
+
307
+ # This method was created mainly for my own benefit, but I figured I'd
308
+ # leave it in here in case anyone else would like to use it. Was doing
309
+ # some statistics for a co-worker who was looking for information about
310
+ # the IP addresses which has connected to my honeypots.
311
+ #
312
+ # It's a little clunky right now, and I ended up just performing actual
313
+ # SQL queries due to memory issues (Some of my databases are over 10 gigs
314
+ # in size). It will write a list of IP addresses and the number of times
315
+ # encountered to the following log file:
316
+ #
317
+ # ip_reputation.txt
318
+ #
319
+ # The format of the data is:
320
+ #
321
+ # <ip_address>,<count>
322
+ #
323
+ # In order from most encountered to least encountered. I also ignore
324
+ # people that have connected to these honeypots less than 200 times.
325
+ #
326
+ def self.ip_reputation_rule
327
+ all_connections_hash = {}
328
+
329
+ ::DataMapper::Repository.adapters.each do |repo|
330
+ if repo[0] == :default
331
+ next
332
+ end
333
+ response = repo[1].select("SELECT COUNT(remote_host), remote_host FROM connections WHERE connection_type = \"accept\" GROUP BY remote_host ORDER BY COUNT(remote_host)")
334
+ response.each do |struct|
335
+ ip = struct.to_a[1]
336
+ count = struct.to_a[0]
337
+ if all_connections_hash[ip]
338
+ all_connections_hash[ip] = all_connections_hash[ip].to_i +
339
+ count.to_i
340
+ else
341
+ all_connections_hash[ip] = count.to_i
342
+ end
343
+ end
344
+ end
345
+ all_connections_hash = all_connections_hash.sort_by { |k,v| -1*v }
346
+ File.open("ip_reputation.txt", 'w') do |f|
347
+ all_connections_hash.each do |ip,count|
348
+ if count > 200
349
+ f.write("#{ip},#{count}\n")
350
+ end
351
+ end
352
+ end
353
+ end
354
+
355
+ # This method is used internally by the execute_command method.
356
+ # It will take a command as an argument and execute it on ever server
357
+ # that is stored in Honeycomb::Interact.servers. The results are
358
+ # stored in a hash which is returned in an Array.
359
+ #
360
+ # Argument:
361
+ # * command - Command to be executed
362
+ #
363
+ # Returns:
364
+ # * Array of hashes -
365
+ # [{:server => <server_name>, :result => <result_of_command>}]
366
+ def ssh_command(command)
367
+ results = []
368
+ self.servers.each do |server|
369
+ begin
370
+ Net::SSH.start(server, self.username, :keys => self.key) do |session|
371
+ session.exec command do |ch, stream, data|
372
+ if stream == :stderr
373
+ results << {:server => server, :result => "ERROR: #{data}"}
374
+ else
375
+ results << {:server => server, :result => data}
376
+ end
377
+ end
378
+ end
379
+ rescue
380
+ next
381
+ end
382
+ end
383
+ return results
384
+ end
385
+
386
+
387
+ end # end Interact
388
+
389
+ end # end Honeycomb
390
+
391
+
392
+