dap 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.
- 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)
|