wmap 2.4.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +141 -0
- data/LICENSE.txt +15 -0
- data/README.rdoc +98 -0
- data/TODO +13 -0
- data/bin/deprime +21 -0
- data/bin/distrust +38 -0
- data/bin/googleBot +23 -0
- data/bin/prime +21 -0
- data/bin/refresh +26 -0
- data/bin/run_tests +16 -0
- data/bin/spiderBot +26 -0
- data/bin/trust +38 -0
- data/bin/updateAll +57 -0
- data/bin/wadd +25 -0
- data/bin/wadds +26 -0
- data/bin/wcheck +28 -0
- data/bin/wdel +25 -0
- data/bin/wdump +21 -0
- data/bin/wmap +151 -0
- data/bin/wscan +32 -0
- data/data/cidrs +2 -0
- data/data/deactivated_sites +1 -0
- data/data/domains +2 -0
- data/data/hosts +1 -0
- data/data/prime_hosts +1 -0
- data/data/sites +2 -0
- data/data/sub_domains +2 -0
- data/demos/bruter.rb +27 -0
- data/demos/dns_brutes.rb +28 -0
- data/demos/filter_cidr.rb +18 -0
- data/demos/filter_crawls.rb +5 -0
- data/demos/filter_domain.rb +25 -0
- data/demos/filter_geoip.rb +26 -0
- data/demos/filter_known_services.rb +59 -0
- data/demos/filter_netinfo.rb +23 -0
- data/demos/filter_prime.rb +25 -0
- data/demos/filter_profiler.rb +3 -0
- data/demos/filter_redirection.rb +19 -0
- data/demos/filter_site.rb +40 -0
- data/demos/filter_siteip.rb +31 -0
- data/demos/filter_status.rb +17 -0
- data/demos/filter_timestamp.rb +23 -0
- data/demos/filter_url.rb +19 -0
- data/demos/new_fnd.rb +66 -0
- data/demos/nmap_parser.pl +138 -0
- data/demos/site_format.rb +18 -0
- data/demos/whois_domain.rb +78 -0
- data/dicts/GeoIP.dat +0 -0
- data/dicts/GeoIPASNum.dat +0 -0
- data/dicts/GeoLiteCity.dat +0 -0
- data/dicts/ccsld.txt +2646 -0
- data/dicts/cctld.txt +243 -0
- data/dicts/gtld.txt +25 -0
- data/dicts/hostnames-dict.big +1402 -0
- data/dicts/hostnames-dict.txt +101 -0
- data/lib/wmap/cidr_tracker.rb +327 -0
- data/lib/wmap/dns_bruter.rb +308 -0
- data/lib/wmap/domain_tracker/sub_domain.rb +142 -0
- data/lib/wmap/domain_tracker.rb +342 -0
- data/lib/wmap/geoip_tracker.rb +72 -0
- data/lib/wmap/google_search_scraper.rb +177 -0
- data/lib/wmap/host_tracker/primary_host.rb +130 -0
- data/lib/wmap/host_tracker.rb +550 -0
- data/lib/wmap/network_profiler.rb +144 -0
- data/lib/wmap/port_scanner.rb +208 -0
- data/lib/wmap/site_tracker/deactivated_site.rb +85 -0
- data/lib/wmap/site_tracker.rb +937 -0
- data/lib/wmap/url_checker.rb +314 -0
- data/lib/wmap/url_crawler.rb +381 -0
- data/lib/wmap/utils/domain_root.rb +184 -0
- data/lib/wmap/utils/logger.rb +53 -0
- data/lib/wmap/utils/url_magic.rb +343 -0
- data/lib/wmap/utils/utils.rb +333 -0
- data/lib/wmap/whois.rb +76 -0
- data/lib/wmap.rb +227 -0
- data/logs/wmap.log +17 -0
- data/ruby_whois_patches/base_cocca2.rb +149 -0
- data/ruby_whois_patches/kero.yachay.pe.rb +120 -0
- data/ruby_whois_patches/whois.PublicDomainRegistry.com.rb +124 -0
- data/ruby_whois_patches/whois.above.com.rb +61 -0
- data/ruby_whois_patches/whois.adamsnames.tc.rb +107 -0
- data/ruby_whois_patches/whois.aeda.net.ae.rb +105 -0
- data/ruby_whois_patches/whois.ai.rb +112 -0
- data/ruby_whois_patches/whois.arnes.si.rb +121 -0
- data/ruby_whois_patches/whois.ascio.com.rb +91 -0
- data/ruby_whois_patches/whois.cnnic.cn.rb +123 -0
- data/ruby_whois_patches/whois.corporatedomains.com.rb +67 -0
- data/ruby_whois_patches/whois.crsnic.net.rb +108 -0
- data/ruby_whois_patches/whois.denic.de.rb +174 -0
- data/ruby_whois_patches/whois.dk-hostmaster.dk.rb +120 -0
- data/ruby_whois_patches/whois.dns.be.rb +134 -0
- data/ruby_whois_patches/whois.dns.lu.rb +129 -0
- data/ruby_whois_patches/whois.dns.pl.rb +150 -0
- data/ruby_whois_patches/whois.dns.pt.rb +119 -0
- data/ruby_whois_patches/whois.domain.kg.rb +126 -0
- data/ruby_whois_patches/whois.domainregistry.my.rb +123 -0
- data/ruby_whois_patches/whois.domreg.lt.rb +110 -0
- data/ruby_whois_patches/whois.dot.tk.rb +140 -0
- data/ruby_whois_patches/whois.hkirc.hk.rb +121 -0
- data/ruby_whois_patches/whois.isnic.is.rb +130 -0
- data/ruby_whois_patches/whois.je.rb +119 -0
- data/ruby_whois_patches/whois.jprs.jp.rb +137 -0
- data/ruby_whois_patches/whois.kenic.or.ke.rb +140 -0
- data/ruby_whois_patches/whois.markmonitor.com.rb +118 -0
- data/ruby_whois_patches/whois.melbourneit.com.rb +58 -0
- data/ruby_whois_patches/whois.nic.as.rb +96 -0
- data/ruby_whois_patches/whois.nic.at.rb +109 -0
- data/ruby_whois_patches/whois.nic.ch.rb +141 -0
- data/ruby_whois_patches/whois.nic.cl.rb +117 -0
- data/ruby_whois_patches/whois.nic.ec.rb +157 -0
- data/ruby_whois_patches/whois.nic.im.rb +120 -0
- data/ruby_whois_patches/whois.nic.it.rb +170 -0
- data/ruby_whois_patches/whois.nic.lv.rb +116 -0
- data/ruby_whois_patches/whois.nic.ly.rb +127 -0
- data/ruby_whois_patches/whois.nic.mu.rb +27 -0
- data/ruby_whois_patches/whois.nic.mx.rb +123 -0
- data/ruby_whois_patches/whois.nic.net.sa.rb +111 -0
- data/ruby_whois_patches/whois.nic.or.kr.rb +101 -0
- data/ruby_whois_patches/whois.nic.tel.rb +129 -0
- data/ruby_whois_patches/whois.nic.tr.rb +133 -0
- data/ruby_whois_patches/whois.nic.us.rb +129 -0
- data/ruby_whois_patches/whois.nic.ve.rb +135 -0
- data/ruby_whois_patches/whois.norid.no.rb +127 -0
- data/ruby_whois_patches/whois.pandi.or.id.rb +118 -0
- data/ruby_whois_patches/whois.psi-usa.info.rb +63 -0
- data/ruby_whois_patches/whois.registro.br.rb +109 -0
- data/ruby_whois_patches/whois.registrygate.com.rb +55 -0
- data/ruby_whois_patches/whois.rrpproxy.net.rb +61 -0
- data/ruby_whois_patches/whois.sgnic.sg.rb +130 -0
- data/ruby_whois_patches/whois.srs.net.nz.rb +166 -0
- data/ruby_whois_patches/whois.tucows.com.rb +70 -0
- data/ruby_whois_patches/whois.twnic.net.tw.rb +133 -0
- data/settings/discovery_ports +24 -0
- data/settings/google_keywords.txt +9 -0
- data/settings/google_locator.txt +23 -0
- data/test/domain_tracker_test.rb +31 -0
- data/test/utils_test.rb +168 -0
- data/version.txt +13 -0
- data/wmap.gemspec +49 -0
- metadata +202 -0
@@ -0,0 +1,130 @@
|
|
1
|
+
#--
|
2
|
+
# Wmap
|
3
|
+
#
|
4
|
+
# A pure Ruby library for Internet web application discovery and tracking.
|
5
|
+
#
|
6
|
+
# Copyright (c) 2012-2015 Yang Li <yang.li@owasp.org>
|
7
|
+
#++
|
8
|
+
#require "singleton" # Implement singleton pattern to avoid race condition under parallel engine
|
9
|
+
|
10
|
+
|
11
|
+
module Wmap
|
12
|
+
class HostTracker
|
13
|
+
|
14
|
+
# Class to differentiate the primary host-name from the potential aliases. This is needed in order to minimize the confusion on our final site inventory list, as it contains a large number of duplicates (aliases). More specifically, a filter could be built by using this class to track the primary url of a website.
|
15
|
+
class PrimaryHost < Wmap::HostTracker
|
16
|
+
include Wmap::Utils
|
17
|
+
include Singleton
|
18
|
+
|
19
|
+
attr_accessor :hosts_file, :verbose, :data_dir
|
20
|
+
attr_reader :known_hosts, :known_ips
|
21
|
+
|
22
|
+
# Initialize the instance variables
|
23
|
+
def initialize (params = {})
|
24
|
+
@verbose=params.fetch(:verbose, false)
|
25
|
+
@data_dir=params.fetch(:data_dir, File.dirname(__FILE__)+'/../../../data/')
|
26
|
+
# Set default instance variables
|
27
|
+
@file_hosts=@data_dir + 'prime_hosts'
|
28
|
+
file=params.fetch(:hosts_file, @file_hosts)
|
29
|
+
# Initialize the instance variables
|
30
|
+
File.write(@file_hosts, "") unless File.exist?(@file_hosts)
|
31
|
+
@known_hosts=load_known_hosts_from_file(file)
|
32
|
+
@known_ips=Hash.new
|
33
|
+
de_duplicate
|
34
|
+
end
|
35
|
+
|
36
|
+
# Procedures to identify primary host-name from the site store SSL certificates. The assumption is that the CN used in the cert application must be primary hostname and used by the users.
|
37
|
+
def update_from_site_store!
|
38
|
+
puts "Invoke internal procedures to update the primary host-name table from the site store."
|
39
|
+
begin
|
40
|
+
# Step 1 - update the prime host table based on the SSL cert CN fields
|
41
|
+
cns=Hash.new
|
42
|
+
checker=Wmap::UrlChecker.new(:data_dir=>@data_dir)
|
43
|
+
my_tracker = Wmap::SiteTracker.new(:data_dir=>@data_dir)
|
44
|
+
my_tracker.get_ssl_sites.map do |site|
|
45
|
+
puts "Exam SSL enabled site entry #{site} ..."
|
46
|
+
my_host=url_2_host(site)
|
47
|
+
next if @known_hosts.key?(my_host) # add the logic to optimize the process
|
48
|
+
puts "Pull SSL cert details on site: #{site}"
|
49
|
+
cn=checker.get_cert_cn(site)
|
50
|
+
unless cn.nil? or cns.key?(cn)
|
51
|
+
cns[cn]=true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
cns.keys.map do |cn|
|
55
|
+
if is_fqdn?(cn)
|
56
|
+
next if @known_hosts.key?(cn)
|
57
|
+
self.add(cn)
|
58
|
+
puts "New entry added: #{cn}\t#{@known_hosts[cn]}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
# Step 2 - Save the cache into the file
|
62
|
+
self.save!
|
63
|
+
checker=nil
|
64
|
+
my_tracker=nil
|
65
|
+
rescue Exception => ee
|
66
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
67
|
+
checker=nil
|
68
|
+
my_tracker=nil
|
69
|
+
return nil
|
70
|
+
end
|
71
|
+
end
|
72
|
+
alias_method :update!, :update_from_site_store!
|
73
|
+
|
74
|
+
# Procedures to identify primary host-name from the site store redirection URLs. The assumption is that on site redirection, it must be directed to the well known primary site.
|
75
|
+
def update_from_site_redirections!
|
76
|
+
puts "Invoke internal procedures to update the primary host-name table from the site store."
|
77
|
+
begin
|
78
|
+
urls=Wmap::SiteTracker.new(:data_dir=>@data_dir).get_redirection_urls
|
79
|
+
urls.map do |url|
|
80
|
+
if is_url?(url)
|
81
|
+
host=url_2_host(url)
|
82
|
+
if is_fqdn?(host)
|
83
|
+
ip=host_2_ip(host)
|
84
|
+
# Add duplication check
|
85
|
+
unless @known_hosts.key?(ip)
|
86
|
+
self.add(host)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
self.save!
|
92
|
+
rescue Exception => ee
|
93
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
94
|
+
return nil
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Procedures to remove the redundant entries in the primary hosts data repository
|
99
|
+
def de_duplicate
|
100
|
+
@known_hosts.keys.map do |key|
|
101
|
+
ip=@known_hosts[key]
|
102
|
+
if @known_ips.key?(ip)
|
103
|
+
@known_hosts.delete(key)
|
104
|
+
else
|
105
|
+
@known_ips[ip]=true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
alias_method :deduplicate, :de_duplicate
|
110
|
+
|
111
|
+
# Method to replace hostname with known primary hostname
|
112
|
+
def prime (host)
|
113
|
+
begin
|
114
|
+
raise "Unknown hostname format: #{host}" unless is_fqdn?(host)
|
115
|
+
ip=local_host_2_ip(host)
|
116
|
+
ip=host_2_ip(host) if ip.nil?
|
117
|
+
if @known_ips.key?(ip)
|
118
|
+
return @known_hosts[ip]
|
119
|
+
end
|
120
|
+
return host
|
121
|
+
rescue Exception => ee
|
122
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
123
|
+
return host
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,550 @@
|
|
1
|
+
#--
|
2
|
+
# Wmap
|
3
|
+
#
|
4
|
+
# A pure Ruby library for Internet web application discovery and tracking.
|
5
|
+
#
|
6
|
+
# Copyright (c) 2012-2015 Yang Li <yang.li@owasp.org>
|
7
|
+
#++
|
8
|
+
require "parallel"
|
9
|
+
require "singleton" # Implement singleton pattern to avoid race condition under parallel engine
|
10
|
+
|
11
|
+
|
12
|
+
# Class to handle the local host data repository file where lists of known hosts from discovery and past assessment efforts are stored
|
13
|
+
class Wmap::HostTracker
|
14
|
+
#include Singleton
|
15
|
+
include Wmap::Utils
|
16
|
+
|
17
|
+
attr_accessor :hosts_file, :max_parallel, :verbose, :data_dir
|
18
|
+
attr_reader :known_hosts, :alias
|
19
|
+
|
20
|
+
# Instance default variables
|
21
|
+
def initialize (params = {})
|
22
|
+
@verbose=params.fetch(:verbose, false)
|
23
|
+
@data_dir=params.fetch(:data_dir, File.dirname(__FILE__)+'/../../data/')
|
24
|
+
# Set default instance variables
|
25
|
+
@file_hosts=@data_dir + 'hosts'
|
26
|
+
file=params.fetch(:hosts_file, @file_hosts)
|
27
|
+
@max_parallel=params.fetch(:max_parallel, 40)
|
28
|
+
# Initialize the instance variables
|
29
|
+
File.write(@file_hosts, "") unless File.exist?(@file_hosts)
|
30
|
+
@known_hosts=load_known_hosts_from_file(file)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Setter to load the known hosts from the local hosts file into a class instance
|
34
|
+
def load_known_hosts_from_file (f_hosts=@file_hosts)
|
35
|
+
puts "Loading local hosts from file: #{f_hosts} ..." if @verbose
|
36
|
+
begin
|
37
|
+
known_hosts=Hash.new
|
38
|
+
@alias = Hash.new
|
39
|
+
f=File.open(f_hosts, 'r')
|
40
|
+
f.each do |line|
|
41
|
+
next unless line =~ /\d+\.\d+\.\d+\.\d+/
|
42
|
+
entry=line.chomp.split(%r{\t+|\s+|\,})
|
43
|
+
key=entry[0].downcase
|
44
|
+
value=entry[1]
|
45
|
+
puts "Loading value pair: #{key} - #{value}" if @verbose
|
46
|
+
known_hosts[key] = Hash.new unless known_hosts.key?(key)
|
47
|
+
known_hosts[key]= value
|
48
|
+
# For reverse host lookup
|
49
|
+
known_hosts[value] = Hash.new unless known_hosts.key?(value)
|
50
|
+
known_hosts[value] = key
|
51
|
+
# Count the number of alias for the recorded IP
|
52
|
+
if @alias.key?(value)
|
53
|
+
@alias[value]+=1
|
54
|
+
else
|
55
|
+
@alias[value]=1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
f.close
|
59
|
+
return known_hosts
|
60
|
+
rescue => ee
|
61
|
+
puts "Exception on method #{__method__}: #{ee}"
|
62
|
+
return known_hosts
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Save the current local hosts hash table into a (random) data repository file
|
67
|
+
def save_known_hosts_to_file!(f_hosts=@file_hosts)
|
68
|
+
puts "Saving the local host repository from memory to file: #{f_hosts} ..."
|
69
|
+
begin
|
70
|
+
timestamp=Time.now
|
71
|
+
f=File.open(f_hosts, 'w')
|
72
|
+
f.write "# local hosts file created by the #{self.class} class #{__method__} method at: #{timestamp}"
|
73
|
+
@known_hosts.keys.sort.map do |key|
|
74
|
+
unless key =~ /\d+\.\d+\.\d+\.\d+/
|
75
|
+
f.write "\n#{key}\t#{@known_hosts[key]}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
f.close
|
79
|
+
puts "local host repository is successfully saved to: #{f_hosts}"
|
80
|
+
rescue => ee
|
81
|
+
puts "Exception on method #{__method__}: #{ee}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
alias_method :save!, :save_known_hosts_to_file!
|
85
|
+
|
86
|
+
# Count numbers of entries in the local host repository
|
87
|
+
def count
|
88
|
+
puts "Counting number of entries in the local host repository ..."
|
89
|
+
begin
|
90
|
+
cnt=0
|
91
|
+
@known_hosts.keys.map do |key|
|
92
|
+
unless is_ip?(key)
|
93
|
+
cnt=cnt+1
|
94
|
+
end
|
95
|
+
end
|
96
|
+
puts "Current number of entries: #{cnt}"
|
97
|
+
return cnt
|
98
|
+
rescue => ee
|
99
|
+
puts "Exception on method #{__method__}: #{ee}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Setter to add host entry to the cache once at a time
|
104
|
+
def add(host)
|
105
|
+
puts "Add entry to the local host repository: #{host}"
|
106
|
+
begin
|
107
|
+
host=host.strip.downcase unless host.nil?
|
108
|
+
unless @known_hosts.key?(host)
|
109
|
+
ip=host_2_ip(host)
|
110
|
+
record=Hash.new
|
111
|
+
if is_ip?(ip)
|
112
|
+
# filter host to known domains only
|
113
|
+
root=get_domain_root(host)
|
114
|
+
if Wmap::DomainTracker.new(:data_dir=>@data_dir).domain_known?(root)
|
115
|
+
record[host]=ip
|
116
|
+
record[ip]=host
|
117
|
+
puts "Host data repository entry loaded: #{host} <=> #{ip}"
|
118
|
+
# Replace instance with the class variable to avoid potential race condition under parallel engine
|
119
|
+
# add additional logic to update the sub-domain table as well, 02/10/2014
|
120
|
+
sub=get_sub_domain(host)
|
121
|
+
if sub!=root
|
122
|
+
tracker=Wmap::DomainTracker::SubDomain.new(:data_dir=>@data_dir)
|
123
|
+
unless tracker.domain_known?(sub)
|
124
|
+
tracker.add(sub)
|
125
|
+
tracker.save!
|
126
|
+
end
|
127
|
+
tracker=nil
|
128
|
+
end
|
129
|
+
@known_hosts.merge!(record)
|
130
|
+
return record
|
131
|
+
else
|
132
|
+
puts "Error - host #{host} has an untrusted internet root domain: #{root}\nPlease update the trusted domain seeds file first if necessary."
|
133
|
+
end
|
134
|
+
else
|
135
|
+
puts "Problem resolve host #{host} - unknown IP: #{ip}"
|
136
|
+
end
|
137
|
+
else
|
138
|
+
puts "Host is already exist. Skip: #{host}"
|
139
|
+
end
|
140
|
+
rescue => ee
|
141
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Setter to add host entry to the local hosts in batch (from an array)
|
146
|
+
def bulk_add(list, num=@max_parallel)
|
147
|
+
puts "Add entries to the local host repository: #{list}"
|
148
|
+
begin
|
149
|
+
results=Hash.new
|
150
|
+
if list.size > 0
|
151
|
+
puts "Start parallel host update processing on:\n #{list}" if @verbose
|
152
|
+
Parallel.map(list, :in_processes => num) { |target|
|
153
|
+
add(target)
|
154
|
+
}.each do |process|
|
155
|
+
if process.nil?
|
156
|
+
next
|
157
|
+
elsif process.empty?
|
158
|
+
#do nothing
|
159
|
+
else
|
160
|
+
results.merge!(process)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
@known_hosts.merge!(results)
|
164
|
+
puts "Done loading entries."
|
165
|
+
return results
|
166
|
+
else
|
167
|
+
puts "Error: empty list - no entry is loaded. Please check your input list and try again."
|
168
|
+
end
|
169
|
+
return results
|
170
|
+
rescue => ee
|
171
|
+
puts "Exception on method #{__method__}: #{ee}"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
alias_method :adds, :bulk_add
|
175
|
+
|
176
|
+
# 'setter' to add host entry to the local hosts in batch (from a file)
|
177
|
+
def file_add(file)
|
178
|
+
begin
|
179
|
+
puts "Add entries to the local host repository from file: #{file}"
|
180
|
+
raise "File non-exist. Please check your file path and name again: #{file}" unless File.exist?(file)
|
181
|
+
hosts=file_2_list(file)
|
182
|
+
changes=bulk_add(hosts)
|
183
|
+
return changes
|
184
|
+
rescue => ee
|
185
|
+
puts "Exception on method #{__method__}: #{ee}"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# 'setter' to remove entry from the local hosts one at a time
|
190
|
+
def delete(host)
|
191
|
+
puts "Remove entry from the local host repository: #{host} "
|
192
|
+
begin
|
193
|
+
host=host.strip.downcase
|
194
|
+
if @known_hosts.key?(host)
|
195
|
+
@known_hosts.delete(host)
|
196
|
+
puts "Entry cleared."
|
197
|
+
return host
|
198
|
+
else
|
199
|
+
puts "Entry not fund. Skip: #{host}"
|
200
|
+
end
|
201
|
+
rescue => ee
|
202
|
+
puts "Exception on method #{__method__}: #{ee}"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# 'setter' to delete host entry to the cache in batch (from an array)
|
207
|
+
def bulk_delete(list)
|
208
|
+
puts "Delete entries to the local host repository from:\n #{list}"
|
209
|
+
begin
|
210
|
+
hosts=list
|
211
|
+
changes=Array.new
|
212
|
+
if hosts.size > 0
|
213
|
+
hosts.map do |x|
|
214
|
+
host=delete(x)
|
215
|
+
changes.push(host) unless host.nil?
|
216
|
+
end
|
217
|
+
puts "Done deleting hosts."
|
218
|
+
return changes
|
219
|
+
else
|
220
|
+
puts "Error: empty list - no entry is loaded. Please check your list and try again."
|
221
|
+
end
|
222
|
+
rescue => ee
|
223
|
+
puts "Exception on method #{__method__}: #{ee}"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
alias_method :dels, :bulk_delete
|
227
|
+
|
228
|
+
# Setter to delete host entries in the local hosts in batch (from a file)
|
229
|
+
def file_delete(file)
|
230
|
+
begin
|
231
|
+
puts "Delete the local host repository entries from file: #{file}"
|
232
|
+
raise "File non-exist. Please check your file path and name again: #{file}" unless File.exist?(file)
|
233
|
+
hosts=file_2_list(file)
|
234
|
+
changes=bulk_delete(hosts)
|
235
|
+
puts "Delete done."
|
236
|
+
return changes
|
237
|
+
rescue => ee
|
238
|
+
puts "Exception on method #{__method__}: #{ee}"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# Setter to refresh the entry from the cache one at a time
|
243
|
+
def refresh(host)
|
244
|
+
puts "Refresh the local host repository for host: #{host} "
|
245
|
+
begin
|
246
|
+
host=host.strip.downcase
|
247
|
+
if @known_hosts.key?(host)
|
248
|
+
old_ip=@known_hosts[host]
|
249
|
+
new_ip=host_2_ip(host)
|
250
|
+
if is_ip?(new_ip)
|
251
|
+
if old_ip==new_ip
|
252
|
+
puts "No change for the host entry: #{host}\t#{old_ip}"
|
253
|
+
return nil
|
254
|
+
else
|
255
|
+
@known_hosts[host]=new_ip
|
256
|
+
@known_hosts[new_ip]=host
|
257
|
+
puts "Entry refreshed: #{host}\t#{@known_hosts[host]}"
|
258
|
+
return host
|
259
|
+
end
|
260
|
+
else
|
261
|
+
puts "Host can no longer be resolved in the Internet. Entry removed: #{host}\t#{@known_hosts[host]}"
|
262
|
+
@known_hosts.delete(host)
|
263
|
+
return host
|
264
|
+
end
|
265
|
+
else
|
266
|
+
puts "Error entry non exist: #{host}"
|
267
|
+
end
|
268
|
+
rescue => ee
|
269
|
+
puts "Exception on method #{__method__}: #{ee}"
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
# Refresh all the entries in the local hosts by querying the Internet
|
274
|
+
def refresh_all
|
275
|
+
puts "Refresh all the entries in the local host repository in one shot."
|
276
|
+
begin
|
277
|
+
changes=Hash.new
|
278
|
+
hosts=@known_hosts.keys
|
279
|
+
@known_hosts=Hash.new
|
280
|
+
changes=bulk_add(hosts)
|
281
|
+
@known_hosts.merge!(changes)
|
282
|
+
#@known_hosts.keys.map do |key|
|
283
|
+
# unless is_ip?(key)
|
284
|
+
# host=refresh(key)
|
285
|
+
# changes.push(host) unless host.nil?
|
286
|
+
# end
|
287
|
+
#end
|
288
|
+
puts "\n#{changes.size} Entries Refreshed:" if changes.size>0
|
289
|
+
#changes.map { |x| puts x }
|
290
|
+
puts "Done refreshing the local hosts."
|
291
|
+
return changes
|
292
|
+
rescue => ee
|
293
|
+
puts "Exception on method #{__method__}: #{ee}"
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
# Extract known root domains from the local host repository @known_hosts
|
298
|
+
def get_root_domains
|
299
|
+
puts "Dump out all active root domains from the cache."
|
300
|
+
begin
|
301
|
+
zones=Array.new
|
302
|
+
(@known_hosts.keys-["",nil]).map do |hostname|
|
303
|
+
next if is_ip?(hostname)
|
304
|
+
hostname = hostname.strip
|
305
|
+
zone = get_domain_root(hostname)
|
306
|
+
zones.push(zone) unless zone.nil?
|
307
|
+
end
|
308
|
+
zones.uniq!.sort!
|
309
|
+
return zones
|
310
|
+
rescue => ee
|
311
|
+
puts "Exception on method #{__method__}: #{ee}"
|
312
|
+
end
|
313
|
+
end
|
314
|
+
alias_method :dump_root_domains, :get_root_domains
|
315
|
+
|
316
|
+
# Extract hostname without the root domain part from the @known_hosts. Data can be used for statistics study.
|
317
|
+
def get_a_records
|
318
|
+
puts "Dump out all known A records from the local hosts."
|
319
|
+
begin
|
320
|
+
records=Array.new
|
321
|
+
(@known_hosts.keys-["",nil]).map do |hostname|
|
322
|
+
next if is_ip?(hostname)
|
323
|
+
hostname = hostname.strip
|
324
|
+
root = get_domain_root(hostname)
|
325
|
+
record = hostname.sub('.'+root,'')
|
326
|
+
records.push(record) unless record.nil?
|
327
|
+
end
|
328
|
+
records.sort!
|
329
|
+
return records
|
330
|
+
rescue => ee
|
331
|
+
puts "Exception on method #{__method__}: #{ee}"
|
332
|
+
end
|
333
|
+
end
|
334
|
+
alias_method :dump_a_records, :get_a_records
|
335
|
+
|
336
|
+
# Print summary report on the cache
|
337
|
+
def print_known_hosts
|
338
|
+
puts "\nSummary of local hosts Table:"
|
339
|
+
puts "Total entries: #{@known_hosts.size}"
|
340
|
+
(@known_hosts.keys.sort-["",nil]).each do |key|
|
341
|
+
value=@known_hosts[key]
|
342
|
+
puts "#{key}\t#{value}" if is_fqdn?(key)
|
343
|
+
end
|
344
|
+
puts "End of the summary"
|
345
|
+
end
|
346
|
+
alias_method :print_all, :print_known_hosts
|
347
|
+
|
348
|
+
# Print summary report on the cache
|
349
|
+
def print_host(host)
|
350
|
+
puts "Local host store entry for #{host}"
|
351
|
+
begin
|
352
|
+
host.strip!
|
353
|
+
raise "Invalid input: #{host}" unless is_fqdn?(host)
|
354
|
+
if @known_hosts.key?(host)
|
355
|
+
value=@known_hosts[host]
|
356
|
+
puts "#{host}\t#{value}"
|
357
|
+
else
|
358
|
+
puts "Unknown host in the local store: #{host}"
|
359
|
+
end
|
360
|
+
rescue => ee
|
361
|
+
puts "Exception on method #{__method__}: #{ee}"
|
362
|
+
end
|
363
|
+
end
|
364
|
+
alias_method :print, :print_host
|
365
|
+
|
366
|
+
# Check if the specific IP within @known_hosts table
|
367
|
+
def ip_known? (ip)
|
368
|
+
known = false
|
369
|
+
begin
|
370
|
+
ip=ip.strip unless ip.nil?
|
371
|
+
return false if @known_hosts==nil
|
372
|
+
return @known_hosts.key?(ip.strip)
|
373
|
+
rescue => ee
|
374
|
+
if @verbose
|
375
|
+
puts "IP Lookup Error: #{ee}"
|
376
|
+
end
|
377
|
+
return false
|
378
|
+
end
|
379
|
+
return known
|
380
|
+
end
|
381
|
+
alias_method :has_a_record?, :ip_known?
|
382
|
+
|
383
|
+
# Check if the specific host within @known_hosts table
|
384
|
+
def host_known? (host)
|
385
|
+
begin
|
386
|
+
host=host.strip.downcase unless host.nil?
|
387
|
+
return false if @known_hosts==nil
|
388
|
+
return @known_hosts.key?(host.strip)
|
389
|
+
rescue => ee
|
390
|
+
if @verbose
|
391
|
+
puts "Host Lookup Error: #{ee}"
|
392
|
+
end
|
393
|
+
return false
|
394
|
+
end
|
395
|
+
end
|
396
|
+
alias_method :is_known?, :host_known?
|
397
|
+
|
398
|
+
# Perform reverse DNS lookup on the local host repository. Not to confuse with the reverse DNS lookup from the Internet
|
399
|
+
def local_ip_2_host (ip)
|
400
|
+
puts "Reverse DNS lookup from the local host repository" if @verbose
|
401
|
+
begin
|
402
|
+
ip=ip.strip unless ip.nil?
|
403
|
+
if @known_hosts.key?(ip)
|
404
|
+
return @known_hosts[ip]
|
405
|
+
else
|
406
|
+
return nil
|
407
|
+
end
|
408
|
+
rescue => ee
|
409
|
+
puts "Exception on method #{__method__}: #{ee}"
|
410
|
+
end
|
411
|
+
return nil
|
412
|
+
end
|
413
|
+
|
414
|
+
# Perform DNS lookup on the local host repository. Not to confuse with the DNS lookup from the Internet
|
415
|
+
def local_host_2_ip (host)
|
416
|
+
puts "DNS lookup from the local host repository" if @verbose
|
417
|
+
begin
|
418
|
+
host=host.strip unless host.nil?
|
419
|
+
if @known_hosts.key?(host)
|
420
|
+
return @known_hosts[host]
|
421
|
+
else
|
422
|
+
return nil
|
423
|
+
end
|
424
|
+
rescue => ee
|
425
|
+
puts "Exception on method #{__method__}: #{ee}"
|
426
|
+
return nil
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
# Extract a list of sub-domains from the local host repository @known_hosts
|
431
|
+
def dump_sub_domains
|
432
|
+
puts "Dump out all active sub domains from the local hosts." if @verbose
|
433
|
+
begin
|
434
|
+
subs=Array.new
|
435
|
+
@known_hosts.keys.each do |hostname|
|
436
|
+
next if is_ip?(hostname)
|
437
|
+
hostname = hostname.strip
|
438
|
+
sub = get_subdomain(hostname)
|
439
|
+
subs.push(sub) unless sub.nil?
|
440
|
+
end
|
441
|
+
subs.uniq!.sort!
|
442
|
+
puts "Found sub domains: #{subs}" if @verbose
|
443
|
+
return subs
|
444
|
+
rescue Exception => ee
|
445
|
+
puts "Exception on method #{__method__}: #{ee}"
|
446
|
+
return subs
|
447
|
+
end
|
448
|
+
end
|
449
|
+
alias_method :get_sub_domains, :dump_sub_domains
|
450
|
+
|
451
|
+
# Based on the current host store, to determine if an entry is a known sub-domain
|
452
|
+
def sub_domain_known?(domain)
|
453
|
+
puts "Validate sub-domain: #{domain}" if @verbose
|
454
|
+
begin
|
455
|
+
domain=domain.strip.downcase
|
456
|
+
subs=dump_sub_domains
|
457
|
+
return subs.include?(domain)
|
458
|
+
rescue Exception => ee
|
459
|
+
puts "Exception on method #{__method__}: #{ee}"
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
# Search potential matching sites from the host store by using simple regular expression. Note that any upper-case char in the search string will be automatically converted into lower case
|
464
|
+
def search (pattern)
|
465
|
+
puts "Search host store based on the regular expression: #{pattern}" if @verbose
|
466
|
+
begin
|
467
|
+
pattern=pattern.strip.downcase
|
468
|
+
results=Array.new
|
469
|
+
@known_hosts.keys.map do |key|
|
470
|
+
if key =~ /#{pattern}/i
|
471
|
+
results.push(key)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
return results
|
475
|
+
rescue Exception => ee
|
476
|
+
puts "Exception on method #{__method__}: #{ee}"
|
477
|
+
return nil
|
478
|
+
end
|
479
|
+
end
|
480
|
+
alias_method :find, :search
|
481
|
+
|
482
|
+
# Search local host repository and return a list of aliases for the host
|
483
|
+
def host_aliases (host)
|
484
|
+
puts "Search aliases in the local hosts data repository for host: #{host}" if @verbose
|
485
|
+
begin
|
486
|
+
host.strip!
|
487
|
+
raise "Unknown method input: #{host} We expect a FQDN host-name string from you. " unless is_fqdn?(host)
|
488
|
+
aliases=Array.new
|
489
|
+
if @known_hosts.key?(host)
|
490
|
+
ip=local_host_2_ip(host)
|
491
|
+
@known_hosts.keys.map do |key|
|
492
|
+
my_ip=local_host_2_ip(key)
|
493
|
+
if ip == my_ip
|
494
|
+
aliases.push(key)
|
495
|
+
end
|
496
|
+
end
|
497
|
+
else
|
498
|
+
raise "Unknown host-name in the local hosts data repository: #{host}"
|
499
|
+
end
|
500
|
+
return aliases-[host]
|
501
|
+
rescue Exception => ee
|
502
|
+
puts "Exception on method #{__method__}: #{ee}"
|
503
|
+
return nil
|
504
|
+
end
|
505
|
+
end
|
506
|
+
alias_method :aliases, :host_aliases
|
507
|
+
|
508
|
+
# Top hostname - sort out most common host-name in the host store in descendant order
|
509
|
+
def top_hostname (num)
|
510
|
+
puts "Sort the host store for the most common hostname. " if @verbose
|
511
|
+
h=Hash.new
|
512
|
+
host_store=Hash.new
|
513
|
+
top=Array.new
|
514
|
+
begin
|
515
|
+
# Build a host table from the host file
|
516
|
+
f=File.open(@file_hosts, 'r')
|
517
|
+
f.each do |line|
|
518
|
+
next unless line =~ /\d+\.\d+\.\d+\.\d+/
|
519
|
+
# skip the domain roots in the host list
|
520
|
+
next if is_domain_root?(line.chomp)
|
521
|
+
entry=line.chomp.split(%r{\t+|\s+|\,})
|
522
|
+
key=entry[0].downcase
|
523
|
+
value=entry[1]
|
524
|
+
puts "Loading value pair: #{key} - #{value}" if @verbose
|
525
|
+
host_store[key] = Hash.new unless known_hosts.key?(key)
|
526
|
+
host_store[key]= value
|
527
|
+
end
|
528
|
+
f.close
|
529
|
+
host_store.keys.map do |key|
|
530
|
+
host=key.split('.')
|
531
|
+
if h.key?(host[0])
|
532
|
+
h[host[0]]+=1
|
533
|
+
else
|
534
|
+
h[host[0]]=1
|
535
|
+
end
|
536
|
+
end
|
537
|
+
result = h.keys.sort { |a,b| h[b] <=> h[a] } # Sort by value descendantly
|
538
|
+
num = result.size if result.size < num
|
539
|
+
for i in 0...num
|
540
|
+
top.push(result[i])
|
541
|
+
end
|
542
|
+
return top
|
543
|
+
rescue Exception => ee
|
544
|
+
puts "Exception on method #{__method__}: #{ee}"
|
545
|
+
return nil
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
private :load_known_hosts_from_file
|
550
|
+
end
|