dap 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/.rspec +2 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +55 -0
- data/LICENSE +20 -0
- data/README.md +15 -0
- data/bin/dap +137 -0
- data/dap.gemspec +42 -0
- data/data/.gitkeep +0 -0
- data/lib/dap.rb +101 -0
- data/lib/dap/filter.rb +8 -0
- data/lib/dap/filter/base.rb +37 -0
- data/lib/dap/filter/geoip.rb +72 -0
- data/lib/dap/filter/http.rb +173 -0
- data/lib/dap/filter/names.rb +151 -0
- data/lib/dap/filter/openssl.rb +53 -0
- data/lib/dap/filter/recog.rb +23 -0
- data/lib/dap/filter/simple.rb +340 -0
- data/lib/dap/filter/udp.rb +401 -0
- data/lib/dap/input.rb +74 -0
- data/lib/dap/input/csv.rb +60 -0
- data/lib/dap/input/warc.rb +81 -0
- data/lib/dap/output.rb +117 -0
- data/lib/dap/proto/addp.rb +0 -0
- data/lib/dap/proto/dtls.rb +21 -0
- data/lib/dap/proto/ipmi.rb +94 -0
- data/lib/dap/proto/natpmp.rb +19 -0
- data/lib/dap/proto/wdbrpc.rb +58 -0
- data/lib/dap/utils/oui.rb +16586 -0
- data/lib/dap/version.rb +3 -0
- data/samples/http_get_reply.ic12.bz2 +0 -0
- data/samples/http_get_reply.ic12.sh +1 -0
- data/samples/http_get_reply_iframes.json.bz2 +0 -0
- data/samples/http_get_reply_iframes.json.sh +1 -0
- data/samples/http_get_reply_links.json.sh +1 -0
- data/samples/iawide.warc.bz2 +0 -0
- data/samples/iawide_warc.sh +1 -0
- data/samples/ipmi_chan_auth_replies.crd.bz2 +0 -0
- data/samples/ipmi_chan_auth_replies.sh +1 -0
- data/samples/ssl_certs.bz2 +0 -0
- data/samples/ssl_certs_geo.sh +1 -0
- data/samples/ssl_certs_names.sh +1 -0
- data/samples/ssl_certs_names_expanded.sh +1 -0
- data/samples/ssl_certs_org.sh +1 -0
- data/samples/udp-netbios.csv.bz2 +0 -0
- data/samples/udp-netbios.sh +1 -0
- data/spec/dap/proto/ipmi_spec.rb +19 -0
- data/tools/geo-ip-summary.rb +149 -0
- data/tools/ipmi-vulns.rb +27 -0
- data/tools/json-summarize.rb +81 -0
- data/tools/netbios-counts.rb +271 -0
- data/tools/upnp-vulns.rb +35 -0
- data/tools/value-counts-to-md-table.rb +23 -0
- metadata +264 -0
data/lib/dap/version.rb
ADDED
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
bzcat http_get_reply.ic12.bz2 | ../bin/dap lines + field_split_tab line + rename line.f1=ip line.f4=data + select ip data + transform data=qprintdecode + decode_http_reply data + select ip data.http_code data.http_server + json
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
bzcat http_get_reply_iframes.json.bz2 | ../bin/dap json + transform data=base64decode + include data='<iframe' + html_iframes data + select ip iframe + json
|
@@ -0,0 +1 @@
|
|
1
|
+
bzcat http_get_reply_iframes.json.bz2 | ../bin/dap json + transform data=base64decode + html_links data + select ip link element + decode_uri link + json
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
bzcat iawide.warc.bz2 | ../bin/dap warc + html_links content + select ip link element + decode_uri link + json
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
bzcat ipmi_chan_auth_replies.crd.bz2 | ../bin/dap lines + field_split_tab line + rename line.f2=ip line.f6=data + select ip data + transform data=hexdecode + decode_ipmi_chan_auth_reply data + remove data + json
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
bzcat ssl_certs.bz2 | ../bin/dap json + select host_ip ssl_version port cipher + geo_ip host_ip + json
|
@@ -0,0 +1 @@
|
|
1
|
+
bzcat ssl_certs.bz2 | ../bin/dap json + field_split_array certs + transform certs.f1=base64decode + remove certs + decode_x509 certs.f1 + select certs.f1.names + exists certs.f1.names + split_array certs.f1.names + select certs.f1.names.item + exists certs.f1.names.item + lines
|
@@ -0,0 +1 @@
|
|
1
|
+
bzcat ssl_certs.bz2 | ../bin/dap json + field_split_array certs + transform certs.f1=base64decode + remove certs + decode_x509 certs.f1 + select certs.f1.names + exists certs.f1.names + split_array certs.f1.names + select certs.f1.names.item + exists certs.f1.names.item + rename certs.f1.names.item=hostname + extract_hostname hostname + select hostname.hostname + split_domains hostname.hostname + select hostname.hostname.domain + rename hostname.hostname.domain=name + prepend_subdomains name=www,dns,mail,vpn,secure,ssl + json
|
@@ -0,0 +1 @@
|
|
1
|
+
bzcat ssl_certs.bz2 | ../bin/dap json + select host_ip ssl_version port cipher + geo_ip_org host_ip + json
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
bzcat udp-netbios.csv.bz2 | ../bin/dap csv - header=y + select saddr data + rename saddr=ip + transform data=hexdecode + decode_netbios_status_reply data + remove data + geo_ip ip + json
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'bit-struct'
|
2
|
+
require_relative '../../../lib/dap/proto/ipmi'
|
3
|
+
|
4
|
+
module Dap
|
5
|
+
module Proto
|
6
|
+
module IPMI
|
7
|
+
|
8
|
+
describe Channel_Auth_Reply do
|
9
|
+
it "valid with the proper rmcp version and message length" do
|
10
|
+
expect(subject.valid?).to be_false
|
11
|
+
expect(Channel_Auth_Reply.new(rmcp_version: 6).valid?).to be_false
|
12
|
+
expect(Channel_Auth_Reply.new(message_length: 16).valid?).to be_false
|
13
|
+
expect(Channel_Auth_Reply.new(rmcp_version: 6, message_length: 16).valid?).to be_true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'oj'
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
class GeoIPSummary
|
6
|
+
attr_accessor :country_name, :region_name, :city_name, :tree
|
7
|
+
#
|
8
|
+
# Pass the hash keys for the country name, region name and
|
9
|
+
# city name that we'll encounter during the process_hash function.
|
10
|
+
#
|
11
|
+
def initialize(country_name, region_name, city_name)
|
12
|
+
@country_name = country_name
|
13
|
+
@region_name = region_name
|
14
|
+
@city_name = city_name
|
15
|
+
@tree = {}
|
16
|
+
@tree['count'] = 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def process_hash( json_hash )
|
20
|
+
country = json_hash[@country_name]
|
21
|
+
region = json_hash[@region_name] || 'Undefined Region'
|
22
|
+
city = json_hash[@city_name] || 'Undefined City'
|
23
|
+
|
24
|
+
# Create subhashes and values as needed on down the tree
|
25
|
+
@tree[country] ||= {}
|
26
|
+
@tree[country]['count'] ||=0
|
27
|
+
@tree[country][region] ||= {}
|
28
|
+
@tree[country][region]['count'] ||= 0
|
29
|
+
@tree[country][region][city] ||= 0
|
30
|
+
|
31
|
+
# Now increment counters
|
32
|
+
@tree['count'] += 1
|
33
|
+
@tree[country]['count'] += 1
|
34
|
+
@tree[country][region]['count'] +=1
|
35
|
+
@tree[country][region][city] += 1
|
36
|
+
end
|
37
|
+
|
38
|
+
# Performs the final sorting of the hash, with descending order of counts
|
39
|
+
#
|
40
|
+
def order_tree
|
41
|
+
@tree.each do | country, country_hash|
|
42
|
+
if country != 'count'
|
43
|
+
country_hash.each do | region, region_hash |
|
44
|
+
@tree[country][region] = order_hash(@tree[country][region]) if region != 'count'
|
45
|
+
end
|
46
|
+
@tree[country] = order_hash(@tree[country])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
@tree = order_hash(@tree)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
# Sorts the hash, and returns a copy of the hash in sorted order by their counts, or if
|
55
|
+
# counts are equal then by their names.
|
56
|
+
def order_hash(h)
|
57
|
+
keys = h.keys.sort { | k1,k2 |
|
58
|
+
if k1 == 'count'
|
59
|
+
ret = -1
|
60
|
+
elsif k2 == 'count'
|
61
|
+
ret = 1
|
62
|
+
else
|
63
|
+
# Cities level is slightly different form, if hash at this level then compare
|
64
|
+
# count value within hash, otherwise just compare values. mult by -1 to reverse
|
65
|
+
# ordering
|
66
|
+
if h[k1].class == Hash
|
67
|
+
ret = ( h[k1]['count'] <=> h[k2]['count'] ) * -1
|
68
|
+
ret = k1 <=> k2 if ret == 0 && k1!=nil && k2!=nil
|
69
|
+
else
|
70
|
+
ret = ( h[k1] <=> h[k2] ) * -1
|
71
|
+
ret = k1 <=> k2 if ret == 0 && k1!=nil && k2!=nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
ret
|
75
|
+
}
|
76
|
+
|
77
|
+
# build up return hash
|
78
|
+
ret_hash = {}
|
79
|
+
keys.each do | key |
|
80
|
+
ret_hash[key] = h[key]
|
81
|
+
end
|
82
|
+
|
83
|
+
ret_hash
|
84
|
+
end
|
85
|
+
end
|
86
|
+
HELP=<<EOF
|
87
|
+
This script is used to summarize geoip data from data in a json file. The name of the json element for
|
88
|
+
the country, region, and city must be provided. The output is a hash with the country/region/city data and
|
89
|
+
the count of occurrences from the input file; this output hash is sorted in count descending order so that
|
90
|
+
the most common country, region within a country, and city within a region is returned first.
|
91
|
+
|
92
|
+
Example with dap:
|
93
|
+
bzcat ../samples/ssl_certs.bz2 | ../bin/dap json + select host_ip + geo_ip host_ip + json | ./geo-ip-summary.rb --var host_ip > /tmp/ssl_geo.json
|
94
|
+
EOF
|
95
|
+
|
96
|
+
def parse_command_line(args)
|
97
|
+
|
98
|
+
options={
|
99
|
+
:country => nil,
|
100
|
+
:region => nil,
|
101
|
+
:city => nil,
|
102
|
+
:var => nil
|
103
|
+
}
|
104
|
+
|
105
|
+
OptionParser.new do | opts |
|
106
|
+
opts.banner = HELP
|
107
|
+
opts.separator ''
|
108
|
+
|
109
|
+
opts.separator 'GeoIP name options:'
|
110
|
+
|
111
|
+
opts.on( '--country country_key', 'The name of json key for the country.') do | val |
|
112
|
+
options[:country] = val
|
113
|
+
end
|
114
|
+
|
115
|
+
opts.on( '--region region_key', 'The name of the json key for the region.') do | val |
|
116
|
+
options[:region] = val
|
117
|
+
end
|
118
|
+
|
119
|
+
opts.on( '--city city_key', 'The name of the json key for the city.' ) do | val |
|
120
|
+
options[:city] = val
|
121
|
+
end
|
122
|
+
|
123
|
+
opts.on('--var top-level-var', 'Sets the top level json name, for defining all of country/region/city') do | val |
|
124
|
+
options[:var] = val
|
125
|
+
options[:country] = "#{val}.country_name"
|
126
|
+
options[:region] = "#{val}.region"
|
127
|
+
options[:city] = "#{val}.city"
|
128
|
+
end
|
129
|
+
|
130
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
131
|
+
puts opts
|
132
|
+
exit(0)
|
133
|
+
end
|
134
|
+
opts.parse!(args)
|
135
|
+
options
|
136
|
+
end
|
137
|
+
options
|
138
|
+
end
|
139
|
+
opts = parse_command_line(ARGV)
|
140
|
+
raise 'Need json key names for country,region and city.' if opts[:country].nil? || opts[:region].nil? || opts[:city].nil?
|
141
|
+
|
142
|
+
summarizer = GeoIPSummary.new(opts[:country], opts[:region], opts[:city])
|
143
|
+
while line=gets
|
144
|
+
summarizer.process_hash(Oj.load(line.strip))
|
145
|
+
end
|
146
|
+
|
147
|
+
Oj.default_options={:indent=>2}
|
148
|
+
|
149
|
+
puts Oj.dump(summarizer.order_tree)
|
data/tools/ipmi-vulns.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'oj'
|
4
|
+
|
5
|
+
SEARCHES = {
|
6
|
+
"data.ipmi_compat_password" => { value: "1", name: "straight-pass" },
|
7
|
+
"data.ipmi_compat_md2" => { value: "1", name: "md2" },
|
8
|
+
"data.ipmi_compat_none" => { value: "1", name: "noauth" },
|
9
|
+
"data.ipmi_user_disable_message_auth" => { value: "1", name: "permsg" },
|
10
|
+
"data.ipmi_user_disable_user_auth" => { value: "1", name: "usrlvl" }
|
11
|
+
}
|
12
|
+
|
13
|
+
def search(hash)
|
14
|
+
SEARCHES.each do | key, vuln |
|
15
|
+
if hash[key] == vuln[:value]
|
16
|
+
hash["VULN-IPMI-#{vuln[:name].upcase}"] = "true"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
if (hash['data.ipmi_user_non_null'] == "0") && (hash['data.ipmi_user_null'] == "0")
|
20
|
+
hash["VULN-IPMI-ANON"] = "true"
|
21
|
+
end
|
22
|
+
hash
|
23
|
+
end
|
24
|
+
|
25
|
+
while line=gets
|
26
|
+
puts Oj.dump(search(Oj.load(line.strip)))
|
27
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'oj'
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
HELP=<<EOF
|
6
|
+
This script is used to locate the frequency of a given key in a json document. It will
|
7
|
+
inspect and increment the frequency count for each instance of the key found in the json
|
8
|
+
document, then order them in descending order and output a json document with the top n
|
9
|
+
occurrences of the key value.
|
10
|
+
|
11
|
+
Note that if passed a key that has unique values, this script can consume a lot of memory.
|
12
|
+
|
13
|
+
Sample:
|
14
|
+
unpigz -c /tmp/2014-05-05-mssql-udp-decoded.json.gz | ruby ~/src/dap/tools/json-summarize.rb --top 20 --key data.mssql.Version
|
15
|
+
EOF
|
16
|
+
|
17
|
+
def parse_command_line(args)
|
18
|
+
|
19
|
+
options={
|
20
|
+
:key => nil,
|
21
|
+
:number => nil
|
22
|
+
}
|
23
|
+
|
24
|
+
OptionParser.new do | opts |
|
25
|
+
opts.banner = HELP
|
26
|
+
opts.separator ''
|
27
|
+
|
28
|
+
opts.separator 'GeoIP name options:'
|
29
|
+
|
30
|
+
opts.on( '--key keyname', 'The name of json key to be summarized.') do | val |
|
31
|
+
options[:key] = val
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on( '--top num_items', 'Return top n occurrences.') do | val |
|
35
|
+
options[:number] = val.to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
39
|
+
puts opts
|
40
|
+
exit(0)
|
41
|
+
end
|
42
|
+
opts.parse!(args)
|
43
|
+
options
|
44
|
+
end
|
45
|
+
options
|
46
|
+
end
|
47
|
+
|
48
|
+
# Sorts the hash in descending numerical value for the values
|
49
|
+
# part of the hash, returning the sorted hash.
|
50
|
+
#
|
51
|
+
def order_hash(h)
|
52
|
+
keys = h.keys.sort { | k1,k2 |
|
53
|
+
ret = ( h[k1] <=> h[k2] ) * -1
|
54
|
+
ret = k1 <=> k2 if ret == 0 && k1!=nil && k2!=nil
|
55
|
+
ret
|
56
|
+
}
|
57
|
+
# build up return hash
|
58
|
+
ret_hash = {}
|
59
|
+
keys.each do | key |
|
60
|
+
ret_hash[key] = h[key]
|
61
|
+
end
|
62
|
+
|
63
|
+
ret_hash
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
summary={}
|
70
|
+
opts = parse_command_line(ARGV)
|
71
|
+
key = opts[:key]
|
72
|
+
|
73
|
+
while line = gets
|
74
|
+
val = Oj.load(line.chomp.strip)[key]
|
75
|
+
summary[val] ||= 0
|
76
|
+
summary[val] += 1
|
77
|
+
end
|
78
|
+
|
79
|
+
summary = Hash[ *order_hash(summary).flatten.slice(0,2*opts[:number]) ]
|
80
|
+
puts Oj.dump(summary)
|
81
|
+
|
@@ -0,0 +1,271 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'oj'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
options = OpenStruct.new
|
9
|
+
options.top_count = 5
|
10
|
+
options.exclude_default_counts = false
|
11
|
+
|
12
|
+
OptionParser.new do |opts|
|
13
|
+
opts.banner = "Usage: netbios-counts.rb [options]"
|
14
|
+
|
15
|
+
opts.on("-c", "--count [NUM]", OptionParser::DecimalInteger,
|
16
|
+
"Specify the number of top count results") do |count|
|
17
|
+
options.top_count = count if count > 1
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on("--count-hostnames-containing [TEXT]", "Count hostnames that include the speified text") do |text|
|
21
|
+
options.hostname_containing = text
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on("--exclude-default-counts", "Exclude the provided top counts") do
|
25
|
+
options.exclude_default_counts = true
|
26
|
+
end
|
27
|
+
end.parse!
|
28
|
+
|
29
|
+
NUM_TOP_RECORDS = options.top_count
|
30
|
+
|
31
|
+
module Counter
|
32
|
+
def count(hash)
|
33
|
+
value = countable_value(hash)
|
34
|
+
@counts[value] += 1 unless (value.empty? || value == 'UNKNOWN')
|
35
|
+
end
|
36
|
+
|
37
|
+
def top_counts
|
38
|
+
[].tap do |counts|
|
39
|
+
ordered_by_count.to_a.take(NUM_TOP_RECORDS).each do |values|
|
40
|
+
counts << count_hash(values)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def ordered_by_count
|
46
|
+
Hash[@counts.sort_by{|k, v| v}.reverse]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class CompanyNameCounter
|
51
|
+
include Counter
|
52
|
+
|
53
|
+
def initialize
|
54
|
+
@counts = Hash.new(0)
|
55
|
+
end
|
56
|
+
|
57
|
+
def countable_value(hash)
|
58
|
+
hash['data.netbios_mac_company'].to_s
|
59
|
+
end
|
60
|
+
|
61
|
+
def count_hash(values)
|
62
|
+
{ 'name' => values[0], 'count' => values[1] }
|
63
|
+
end
|
64
|
+
|
65
|
+
def apply_to(hash)
|
66
|
+
hash['top_companies'] = top_counts
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class NetbiosNameCounter
|
71
|
+
include Counter
|
72
|
+
|
73
|
+
def initialize
|
74
|
+
@counts = Hash.new(0)
|
75
|
+
end
|
76
|
+
|
77
|
+
def countable_value(hash)
|
78
|
+
hash['data.netbios_hname'].to_s
|
79
|
+
end
|
80
|
+
|
81
|
+
def count_hash(values)
|
82
|
+
{ 'hostname' => values[0], 'count' => values[1] }
|
83
|
+
end
|
84
|
+
|
85
|
+
def apply_to(hash)
|
86
|
+
hash['top_netbios_hostnames'] = top_counts
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class MacAddressCounter
|
91
|
+
include Counter
|
92
|
+
|
93
|
+
def initialize
|
94
|
+
@counts = Hash.new(0)
|
95
|
+
end
|
96
|
+
|
97
|
+
def countable_value(hash)
|
98
|
+
address = hash['data.netbios_mac'].to_s
|
99
|
+
[].tap do |data|
|
100
|
+
unless (address.empty? || address == '00:00:00:00:00:00')
|
101
|
+
data << address
|
102
|
+
data << hash['data.netbios_hname']
|
103
|
+
data << hash['data.netbios_mac_company']
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def count_hash(values)
|
109
|
+
{
|
110
|
+
'mac_address' => values[0][0],
|
111
|
+
'hostname' => values[0][1],
|
112
|
+
'company' => values[0][2],
|
113
|
+
'count' => values[1]
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
def apply_to(hash)
|
118
|
+
hash['top_mac_addresses'] = top_counts
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
class GeoCounter
|
123
|
+
def initialize
|
124
|
+
@cities = Hash.new(0)
|
125
|
+
@countries = Hash.new(0)
|
126
|
+
@regions = Hash.new(0)
|
127
|
+
end
|
128
|
+
|
129
|
+
def count(hash)
|
130
|
+
city = hash['ip.city'].to_s
|
131
|
+
country_code = hash['ip.country_code'].to_s
|
132
|
+
region = hash['ip.region'].to_s
|
133
|
+
region_name = hash['ip.region_name'].to_s
|
134
|
+
|
135
|
+
@cities[[city, country_code]] += 1 unless city.empty?
|
136
|
+
@countries[country_code] += 1 unless country_code.empty?
|
137
|
+
@regions[[region, region_name]] += 1 unless region.empty?
|
138
|
+
end
|
139
|
+
|
140
|
+
def top_cities
|
141
|
+
[].tap do |counts|
|
142
|
+
ordered_cities.to_a.take(NUM_TOP_RECORDS).each do |values|
|
143
|
+
counts << {
|
144
|
+
'city' => values[0][0],
|
145
|
+
'country_code' => values[0][1],
|
146
|
+
'count' => values[1]
|
147
|
+
}
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def top_countries
|
153
|
+
[].tap do |counts|
|
154
|
+
ordered_countries.to_a.take(NUM_TOP_RECORDS).each do |values|
|
155
|
+
counts << { 'country_code' => values[0], 'count' => values[1] }
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def top_regions
|
161
|
+
[].tap do |counts|
|
162
|
+
ordered_regions.to_a.take(NUM_TOP_RECORDS).each do |values|
|
163
|
+
counts << {
|
164
|
+
'region' => values[0][0],
|
165
|
+
'region_name' => values[0][1],
|
166
|
+
'count' => values[1]
|
167
|
+
}
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def ordered_cities
|
173
|
+
Hash[@cities.sort_by{|k, v| v}.reverse]
|
174
|
+
end
|
175
|
+
|
176
|
+
def ordered_countries
|
177
|
+
Hash[@countries.sort_by{|k, v| v}.reverse]
|
178
|
+
end
|
179
|
+
|
180
|
+
def ordered_regions
|
181
|
+
Hash[@regions.sort_by{|k, v| v}.reverse]
|
182
|
+
end
|
183
|
+
|
184
|
+
def apply_to(hash)
|
185
|
+
hash['top_cities'] = top_cities unless top_cities.empty?
|
186
|
+
hash['top_countries'] = top_countries unless top_countries.empty?
|
187
|
+
hash['top_regions'] = top_regions unless top_regions.empty?
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
class SambaCounter
|
192
|
+
include Counter
|
193
|
+
|
194
|
+
def initialize
|
195
|
+
@counts = Hash.new(0)
|
196
|
+
end
|
197
|
+
|
198
|
+
def countable_value(hash)
|
199
|
+
address = hash['data.netbios_mac'].to_s
|
200
|
+
if (address == '00:00:00:00:00:00')
|
201
|
+
hash['data.netbios_hname']
|
202
|
+
else
|
203
|
+
''
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def count_hash(values)
|
208
|
+
{ 'name' => values[0], 'count' => values[1] }
|
209
|
+
end
|
210
|
+
|
211
|
+
def apply_to(hash)
|
212
|
+
hash['top_samba_names'] = top_counts
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
class HostnameContainingCounter
|
217
|
+
include Counter
|
218
|
+
|
219
|
+
def initialize(text)
|
220
|
+
@text = text
|
221
|
+
@counts = Hash.new(0)
|
222
|
+
end
|
223
|
+
|
224
|
+
def countable_value(hash)
|
225
|
+
hostname = hash['data.netbios_hname'].to_s
|
226
|
+
[].tap do |data|
|
227
|
+
if hostname.include?(@text)
|
228
|
+
data << hostname
|
229
|
+
data << hash['data.netbios_mac_company']
|
230
|
+
data << hash['ip.city'].to_s
|
231
|
+
data << hash['ip.country_code'].to_s
|
232
|
+
data << hash['ip.country_name'].to_s
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def count_hash(values)
|
238
|
+
{
|
239
|
+
'hostname' => values[0][0],
|
240
|
+
'company' => values[0][1],
|
241
|
+
'city' => values[0][2],
|
242
|
+
'country_code' => values[0][3],
|
243
|
+
'country_name' => values[0][4],
|
244
|
+
'count' => values[1]
|
245
|
+
}
|
246
|
+
end
|
247
|
+
|
248
|
+
def apply_to(hash)
|
249
|
+
hash["hostnames with '#{@text}'"] = top_counts
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
counters = []
|
254
|
+
unless options.exclude_default_counts
|
255
|
+
counters << CompanyNameCounter.new
|
256
|
+
counters << NetbiosNameCounter.new
|
257
|
+
counters << MacAddressCounter.new
|
258
|
+
counters << GeoCounter.new
|
259
|
+
counters << SambaCounter.new
|
260
|
+
end
|
261
|
+
counters << HostnameContainingCounter.new(options.hostname_containing) unless options.hostname_containing.nil?
|
262
|
+
|
263
|
+
while line=gets
|
264
|
+
hash = Oj.load(line.strip)
|
265
|
+
counters.each { |counter| counter.count(hash) }
|
266
|
+
end
|
267
|
+
|
268
|
+
summary = {}
|
269
|
+
counters.each { |counter| counter.apply_to(summary) }
|
270
|
+
|
271
|
+
puts JSON.pretty_generate(summary)
|