wmap 2.5.5 → 2.5.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{README.rdoc → README.md} +47 -33
- data/bin/wmap +46 -32
- data/lib/wmap/domain_tracker/sub_domain.rb +67 -76
- data/lib/wmap/domain_tracker.rb +176 -208
- data/lib/wmap/host_tracker/primary_host.rb +9 -9
- data/lib/wmap/host_tracker.rb +314 -361
- data/lib/wmap/site_tracker/deactivated_site.rb +3 -4
- data/lib/wmap/site_tracker.rb +586 -640
- data/lib/wmap/utils/url_magic.rb +1 -1
- data/version.txt +2 -2
- data/wmap.gemspec +2 -2
- metadata +4 -5
- data/logs/wmap.log +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6afbdfcdf343c39f15a1af467762bffe90bc12f05b7a7eb1341ef2cacf7e561f
|
4
|
+
data.tar.gz: 95e039be31be2277fcc8e225106c365b1b7b1694d4db372a6f211d552c3d1162
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b522ee4f4830ed50fb4dac0760cf6b15d84d8b791bd6c1593cdc51042747d002b14f46b1173a40fef7c952fb1256c019b118ec47b6c691c3b4fd27f5f0d3d4b3
|
7
|
+
data.tar.gz: 5f0bd019eac486a744dd96c9d36928d27ba2607cfe1d9e6834189d756f85e08b4deec09b45b89bfc7e779e385f44ec862f6e516d04e98b4f3e31b09c458ea76e
|
data/{README.rdoc → README.md}
RENAMED
@@ -1,32 +1,38 @@
|
|
1
|
-
=
|
1
|
+
[<img src='/wmap_logo.jpg' width='350' height='350'>](https://github.com/yangsec888/wmap)
|
2
|
+
=====================
|
2
3
|
|
4
|
+
- [What's this program for?](#whats-this-program-for)
|
5
|
+
- [WMAP in Motion](#wmap-in-motion)
|
6
|
+
- [Installation](#installation)
|
7
|
+
- [Before Using This Program](#before-using-this-program)
|
8
|
+
- [More Document(s)](#more-documents)
|
9
|
+
- [Program Version](#program-version)
|
10
|
+
- [Author Contact](#author-contact)
|
11
|
+
- [Bug Report or Feature Request](#bug-report-or-feature-request)
|
12
|
+
- [Legal Disclaimer](#legal-disclaimer)
|
3
13
|
|
4
|
-
|
14
|
+
# OWASP Web Mapper README
|
15
|
+
|
16
|
+
|
17
|
+
## What's this program for?
|
5
18
|
This program is designed for the web application asset discovery and tracking. It was originally developed to
|
6
19
|
to cover the gaps of a similar commercial product. Over the time it grows to be a more capable and complete replacement (IMHO).
|
7
20
|
|
8
21
|
|
9
|
-
|
22
|
+
## WMAP in Motion
|
10
23
|
Use the demo web app build on top of wmap gem: http://wmap.io
|
11
24
|
|
12
25
|
|
13
|
-
|
14
|
-
The latest release is version 2.4.5. as of fall 2018. Please refer to the CHANGELOG.md for the program's history information.
|
15
|
-
|
16
|
-
|
17
|
-
== Author Contact
|
18
|
-
This program is designed and developed by Yang Li. You can reach him by Email: <yang.li@owasp.org>
|
19
|
-
|
20
|
-
|
21
|
-
== Installation
|
26
|
+
## Installation
|
22
27
|
To take full power of this program, you would need an *nix flavor machine with direct Internet access. I have installed it successfully on both Mac and Linux machines. You'll also need the Ruby environment being setup properly. The easiest way to install OWASP Web Mapper is by using Ruby Gems. You can install it from command line:
|
23
|
-
|
28
|
+
```sh
|
24
29
|
gem install wmap
|
30
|
+
```
|
25
31
|
|
26
|
-
|
32
|
+
### Specific Installation Problem with Nokogiri
|
27
33
|
Nokogiri is a native xml/html parser used by the project. It's fast and powerful. However, it comes with pitfall of installation problem around building native extension for your environment. Please refer to this page for trouble-shooting tip (http://www.nokogiri.org/tutorials/installing_nokogiri.html).
|
28
34
|
|
29
|
-
|
35
|
+
### Dependency
|
30
36
|
You need the Ruby 2.1.0 or above in order to use this program. In my test environment, I was able to set it up with <a href="https://rvm.io/">RVM</a>. Please refer to this page for more installation information: https://www.ruby-lang.org/en/documentation/installation/
|
31
37
|
|
32
38
|
In addition, the following Ruby GEM dependency are needed by different components of this software. The should be installed automatically:
|
@@ -48,31 +54,32 @@ In case you want to install the above gems separately, use the command below:
|
|
48
54
|
|
49
55
|
gem install dnsruby geoip minitest net-ping netaddr nokogiri css_parser open_uri_redirections openssl parallel whois httpclient
|
50
56
|
|
51
|
-
|
57
|
+
### Ruby-whois Gem Patches
|
52
58
|
This software depends on a patched version of Ruby gem ruby-whois (http://www.ruby-whois.org/) for the domain whois lookup feature. For better result, you could manually add the patches into your local whois gem installation directory as shown below:
|
53
|
-
|
59
|
+
```sh
|
54
60
|
cp whois_patches/* [Your_ruby_whois_gem_path]/whois/lib/whois/record/parser/
|
61
|
+
```
|
55
62
|
|
56
63
|
Or you can directly download the branched whois gem from this repository - https://github.com/yangsec888/whois
|
57
64
|
|
58
65
|
|
59
|
-
|
66
|
+
### Before Using This Program
|
60
67
|
You need to define a scope for the program to run successful. The scope includes both your legitimate Internet domain, and your public
|
61
68
|
network block in the CIDR format.
|
62
69
|
|
63
70
|
To add your Internet domain into the scope, use the build-in shell command below:
|
64
|
-
|
71
|
+
```sh
|
65
72
|
trust XYZ.COM
|
66
|
-
|
73
|
+
```
|
67
74
|
To add your public network block into the scope (note current support of IPv4 only):
|
68
|
-
|
75
|
+
```sh
|
69
76
|
trust x.x.x.x/x
|
77
|
+
```
|
70
78
|
|
71
|
-
|
72
|
-
|
73
|
-
|
79
|
+
### Automatic Discovery and Tracking
|
80
|
+
```sh
|
74
81
|
wmap <seed file | target host | target url | target IP or network cidr>
|
75
|
-
|
82
|
+
```
|
76
83
|
The above utility is intelligent enough to take argument as either a seed file, or a string such as a host, an IP, a network block, or a URL. The new discoveries will be automatically tracked in the data file 'lib/wmap/data/target_sites'.
|
77
84
|
Note: seed file - mix of url, cidr and domain seed, one entry per line.
|
78
85
|
url seed - known URL(s) for further discovery via the web crawler.
|
@@ -80,26 +87,33 @@ The above utility is intelligent enough to take argument as either a seed file,
|
|
80
87
|
domain seed - validated internet domain to be used for DNS record brute-forcing; it is also used to validate the ownership of found web service.
|
81
88
|
|
82
89
|
|
83
|
-
|
90
|
+
### Dump Out Discovery Database
|
84
91
|
You can dump out the program output by using the build-in utility 'wdump' as shown below:
|
85
|
-
|
92
|
+
```sh
|
86
93
|
wdump [output file name from you]
|
87
|
-
|
94
|
+
```
|
88
95
|
The above utility will dump out the discovery database into a single file as program output. Currently, the supported file format is Comma-separated Value (.csv) and Extensible Markup Language (.xml)
|
89
96
|
|
90
97
|
|
91
|
-
|
98
|
+
### More Usage Cases:
|
92
99
|
There are more examples under the 'demos' folder of this package. The examples show how to use the 'wmap' API to get your job done easily. Please check out the code - they should be easy and straightforward to be understood.
|
93
100
|
|
94
101
|
|
95
|
-
|
102
|
+
## More Document(s):
|
96
103
|
The software comes with the Ruby doc during your installation as shown above. For your convenience, the Ruby doc is also distributed with this software. You can navigate to the 'doc' folder of your local installation, and click the 'index.html' to open the start page in your favorite browser. You can also download the wmap-x.x.x.rdoc.zip documentation package alone from GitHub, unzip and open the doc/index.html in your browser.
|
97
104
|
|
98
105
|
If you need additional documentation / information other than this README file and the Ruby document package, please be patient - as I'm still working on it :)
|
99
106
|
|
100
|
-
|
101
|
-
|
107
|
+
|
108
|
+
## Program Version
|
109
|
+
The latest release is version [2.5.5+](version.txt). as of fall 2018. Please refer to the [CHANGELOG.md](CHANGELOG.md) for more history information.
|
110
|
+
|
111
|
+
|
112
|
+
## Author Contact
|
113
|
+
This program is designed and developed by Yang Li. You can reach him by Email: <yang.li@owasp.org>
|
114
|
+
## Bug Report or Feature Request?
|
115
|
+
Contact the author Sam (Yang) Li directly at email 'yang.li@owasp.org'.
|
102
116
|
|
103
117
|
|
104
|
-
|
118
|
+
## Legal Disclaimer:
|
105
119
|
This software is provided strictly 'as-if' without any implied warranty. You're free to copy or modify the codes anyway you want - a reference back to this software will be appreciated. Please refer to the 'LICENSE.txt' file for more information.
|
data/bin/wmap
CHANGED
@@ -5,22 +5,25 @@
|
|
5
5
|
# Usage: wmap <Target Host | URL | IP | CIDR | or a seed file with any of the above combo> <Optional Discovery Result Directory>
|
6
6
|
require "wmap"
|
7
7
|
|
8
|
+
# program helper
|
8
9
|
def print_usage
|
9
10
|
abort "Program to perform website asset discovery and tracking. \nUsage: wmap <Target Host | URL | IP | CIDR | or a seed file with any of the above combo> <Optional Discovery Result Directory>"
|
10
11
|
end
|
11
|
-
|
12
|
-
# preparing - spit out the program banner
|
12
|
+
# print program banner
|
13
13
|
puts Wmap.banner
|
14
|
+
|
15
|
+
# Preparing - check out the working logs directory
|
14
16
|
if ARGV.length == 2
|
15
17
|
# Log to the instance running directory
|
16
|
-
Log_dir=
|
18
|
+
Log_dir = Pathname.new(ARGV[1]).join('logs')
|
17
19
|
else
|
18
20
|
# Log the command entry
|
19
|
-
Log_dir=
|
21
|
+
Log_dir=Pathname.new(Gem.loaded_specs['wmap'].full_gem_path).join('logs')
|
20
22
|
end
|
21
23
|
Dir.mkdir(Log_dir) unless Dir.exist?(Log_dir)
|
22
24
|
|
23
|
-
|
25
|
+
# Start wmap logging
|
26
|
+
Wmap.wlog("Execute the command: wmap #{ARGV[0]}","wmap",Log_dir.join("wmap.log").to_s)
|
24
27
|
print_usage unless (ARGV.length==1 or ARGV.length==2)
|
25
28
|
urls = Array.new
|
26
29
|
# first step - construct the host list
|
@@ -64,38 +67,16 @@ else
|
|
64
67
|
print_usage
|
65
68
|
end
|
66
69
|
|
67
|
-
# second step - update the hosts repository
|
68
|
-
if ARGV.length == 1
|
69
|
-
puts puts "Invoke the HostTracker."
|
70
|
-
host_tracker = Wmap::HostTracker.instance
|
71
|
-
host_tracker.verbose=true
|
72
|
-
elsif ARGV.length == 2
|
73
|
-
puts "Invoke the HostTracker with optional directory setter."
|
74
|
-
host_tracker = Wmap::HostTracker.instance
|
75
|
-
host_tracker.verbose=true
|
76
|
-
host_tracker.data_dir = ARGV[1]
|
77
|
-
else
|
78
|
-
aborts "Error firing up HostTracker instance!"
|
79
|
-
end
|
80
|
-
hosts.uniq!
|
81
|
-
if hosts.size > 0
|
82
|
-
hostnames=hosts.dup.delete_if { |h| host_tracker.is_ip?(h) }
|
83
|
-
if hostnames.size > 0
|
84
|
-
puts "Update the local hosts data repository."
|
85
|
-
new_hosts=host_tracker.adds(hostnames)
|
86
|
-
host_tracker.save! if new_hosts.size>0
|
87
|
-
end
|
88
|
-
end
|
89
|
-
host_tracker=nil
|
90
70
|
|
91
|
-
#
|
71
|
+
# second step - port discovery on the above host list, and to build the URL seeds
|
92
72
|
puts "Build up URL list for the web crawler ..."
|
93
73
|
urls0=scanner.scans(hosts)
|
94
74
|
urls+=urls0
|
95
75
|
urls.uniq!
|
96
76
|
scanner=nil
|
97
77
|
|
98
|
-
|
78
|
+
|
79
|
+
# third step - crawling on the URL seeds
|
99
80
|
if ARGV.length == 1
|
100
81
|
puts "Fire up the crawler."
|
101
82
|
crawler = Wmap::UrlCrawler.new(:verbose=>false)
|
@@ -125,14 +106,16 @@ else
|
|
125
106
|
dis_sites.keys.map {|x| puts x}
|
126
107
|
end
|
127
108
|
|
128
|
-
|
109
|
+
|
110
|
+
# fourth step - trace the discovery results into a local log file for debugging and other purposes
|
129
111
|
Wmap.wlog(dis_urls.keys, "wmap", Log_dir+"discovered_urls.log") unless dis_urls.empty?
|
130
112
|
Wmap.wlog(dis_sites.keys, "wmap", Log_dir+"discovered_sites.log") unless dis_sites.empty?
|
131
113
|
#crawler.wlog(c_start.keys,Log_dir+"crawler.log")
|
132
114
|
#crawler.wlog(c_done.keys,Log_dir+"crawler.log")
|
133
115
|
crawler=nil
|
134
116
|
|
135
|
-
|
117
|
+
|
118
|
+
# fifth step - save discovery results into the inventory data repository
|
136
119
|
case dis_sites.keys
|
137
120
|
when nil,[]
|
138
121
|
puts "No new site found. There is no change to the site tracking data repository. "
|
@@ -145,6 +128,8 @@ else
|
|
145
128
|
puts "Start the SiteTracker with the optional directory setter. "
|
146
129
|
inventory=Wmap::SiteTracker.instance
|
147
130
|
inventory.data_dir = ARGV[1]
|
131
|
+
inventory.sites_file = inventory.data_dir + "sites"
|
132
|
+
inventory.load_site_stores_from_file
|
148
133
|
else
|
149
134
|
aborts "Error firing up SiteTracker instance!"
|
150
135
|
end
|
@@ -153,3 +138,32 @@ else
|
|
153
138
|
inventory=nil
|
154
139
|
puts "Done! New found sites are successfully saved. " if new_sites.size > 0
|
155
140
|
end
|
141
|
+
|
142
|
+
|
143
|
+
# seventh step - update the hosts repository
|
144
|
+
if ARGV.length == 1
|
145
|
+
puts puts "Invoke the HostTracker."
|
146
|
+
host_tracker = Wmap::HostTracker.instance
|
147
|
+
host_tracker.verbose=true
|
148
|
+
elsif ARGV.length == 2
|
149
|
+
puts "Invoke the HostTracker with optional directory setter."
|
150
|
+
host_tracker = Wmap::HostTracker.instance
|
151
|
+
host_tracker.verbose=true
|
152
|
+
host_tracker.data_dir = ARGV[1]
|
153
|
+
host_tracker.hosts_file = host_tracker.data_dir + "hosts"
|
154
|
+
host_tracker.load_known_hosts_from_file
|
155
|
+
else
|
156
|
+
aborts "Error firing up HostTracker instance!"
|
157
|
+
end
|
158
|
+
new_hosts = dis_sites.keys.map {|x| host_tracker.url_2_host(x)}
|
159
|
+
hosts += new_hosts
|
160
|
+
hosts.uniq!
|
161
|
+
if hosts.size > 0
|
162
|
+
hostnames=hosts.dup.delete_if { |h| host_tracker.is_ip?(h) }
|
163
|
+
if hostnames.size > 0
|
164
|
+
puts "Update the local hosts data repository with: #{hostnames}"
|
165
|
+
new_hosts=host_tracker.adds(hostnames)
|
166
|
+
host_tracker.save! if new_hosts.size>0
|
167
|
+
end
|
168
|
+
end
|
169
|
+
host_tracker=nil
|
@@ -17,8 +17,7 @@ class SubDomain < Wmap::DomainTracker
|
|
17
17
|
include Wmap::Utils
|
18
18
|
include Singleton
|
19
19
|
|
20
|
-
attr_accessor :verbose, :
|
21
|
-
attr_reader :known_internet_sub_domains
|
20
|
+
attr_accessor :verbose, :sub_domains_file, :max_parallel, :data_dir, :known_internet_sub_domains
|
22
21
|
|
23
22
|
# Set default instance variables
|
24
23
|
def initialize (params = {})
|
@@ -26,111 +25,102 @@ class SubDomain < Wmap::DomainTracker
|
|
26
25
|
@data_dir=params.fetch(:data_dir, File.dirname(__FILE__)+'/../../../data/')
|
27
26
|
@max_parallel=params.fetch(:max_parallel, 40)
|
28
27
|
# Hash table to hold the trusted domains
|
29
|
-
@
|
30
|
-
File.write(@
|
31
|
-
@known_internet_sub_domains=load_domains_from_file(@
|
32
|
-
|
28
|
+
@sub_domains_file=params.fetch(:sub_domains_file, @data_dir + 'sub_domains')
|
29
|
+
File.write(@sub_domains_file, "") unless File.exist?(@sub_domains_file)
|
30
|
+
@known_internet_sub_domains=load_domains_from_file(@sub_domains_file) #unless @known_internet_sub_domains.size>0
|
31
|
+
end
|
33
32
|
|
34
33
|
# 'setter' to add sub-domain entry to the cache one at a time
|
35
34
|
def add(sub)
|
36
35
|
puts "Add entry to the local sub domain cache table: #{sub}" if @verbose
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
if @
|
41
|
-
|
42
|
-
return nil
|
43
|
-
end
|
44
|
-
if zone_transferable?(sub)
|
45
|
-
record[sub]=true
|
46
|
-
else
|
47
|
-
record[sub]=false
|
48
|
-
end
|
49
|
-
puts "Adding new record into the data store: #{record}" if @verbose
|
50
|
-
@known_internet_sub_domains.merge!(record)
|
51
|
-
return record
|
52
|
-
rescue => ee
|
53
|
-
puts "Exception on method #{__method__} for #{sub}: #{ee}" if @verbose
|
36
|
+
record=Hash.new
|
37
|
+
sub=sub.strip.downcase
|
38
|
+
if @known_internet_sub_domains.key?(sub)
|
39
|
+
puts "Skip on known sub-domain: #{sub}" if @verbose
|
40
|
+
return nil
|
54
41
|
end
|
42
|
+
if zone_transferable?(sub)
|
43
|
+
record[sub]=true
|
44
|
+
else
|
45
|
+
record[sub]=false
|
46
|
+
end
|
47
|
+
puts "Adding new record into the data store: #{record}" if @verbose
|
48
|
+
@known_internet_sub_domains.merge!(record)
|
49
|
+
return record
|
50
|
+
rescue => ee
|
51
|
+
puts "Exception on method #{__method__} for #{sub}: #{ee}" if @verbose
|
55
52
|
end
|
56
53
|
|
57
54
|
# 'setter' to add domain entry to the cache in batch (from a list)
|
58
55
|
def bulk_add(list, num=@max_parallel)
|
59
56
|
puts "Add entries to the local domains cache table from list: #{list}" if @verbose
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
results.merge!(process)
|
73
|
-
end
|
57
|
+
results=Hash.new
|
58
|
+
domains=list
|
59
|
+
if domains.size > 0
|
60
|
+
Parallel.map(list, :in_processes => num) { |target|
|
61
|
+
add(target)
|
62
|
+
}.each do |process|
|
63
|
+
if process.nil?
|
64
|
+
next
|
65
|
+
elsif process.empty?
|
66
|
+
#do nothing
|
67
|
+
else
|
68
|
+
results.merge!(process)
|
74
69
|
end
|
75
|
-
@known_internet_sub_domains.merge!(results)
|
76
|
-
puts "Done loading entries."
|
77
|
-
return results
|
78
|
-
else
|
79
|
-
puts "Error: no entry is loaded. Please check your list and try again."
|
80
70
|
end
|
71
|
+
@known_internet_sub_domains.merge!(results)
|
72
|
+
puts "Done loading entries."
|
81
73
|
return results
|
82
|
-
|
83
|
-
puts "
|
74
|
+
else
|
75
|
+
puts "Error: no entry is loaded. Please check your list and try again."
|
84
76
|
end
|
77
|
+
return results
|
78
|
+
rescue => ee
|
79
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
85
80
|
end
|
86
81
|
alias_method :adds, :bulk_add
|
87
82
|
|
88
83
|
# Procedures to identify sub-domain from the hosts store
|
89
84
|
def update_from_host_store!
|
90
85
|
puts "Invoke internal procedures to update the sub-domain list from the host store."
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
unless
|
99
|
-
|
100
|
-
self.bulk_add(subs,@max_parallel)
|
101
|
-
end
|
102
|
-
puts "Update discovered sub-domains into the store: #{@known_internet_sub_domains}"
|
103
|
-
self.save!(file_domains=@file_sub_domains, domains=@known_internet_sub_domains)
|
104
|
-
rescue Exception => ee
|
105
|
-
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
106
|
-
return nil
|
86
|
+
# Step 1 - obtain the latest sub-domains
|
87
|
+
my_tracker = Wmap::HostTracker.instance
|
88
|
+
my_tracker.data_dir=@data_dir
|
89
|
+
subs = my_tracker.dump_sub_domains - [nil,""]
|
90
|
+
my_tracker = nil
|
91
|
+
# Step 2 - update the sub-domain list
|
92
|
+
unless subs.empty?
|
93
|
+
#subs.map { |x| self.add(x) unless domain_known?(x) }
|
94
|
+
self.bulk_add(subs,@max_parallel)
|
107
95
|
end
|
96
|
+
puts "Update discovered sub-domains into the store: #{@known_internet_sub_domains}"
|
97
|
+
self.save!(file_domains=@file_sub_domains, domains=@known_internet_sub_domains)
|
98
|
+
rescue Exception => ee
|
99
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
100
|
+
return nil
|
108
101
|
end
|
109
102
|
alias_method :update!, :update_from_host_store!
|
110
103
|
|
111
104
|
# Save the current domain hash table into a file
|
112
105
|
def save_sub_domains_to_file!(file_domains=@file_sub_domains, domains=@known_internet_sub_domains)
|
113
106
|
puts "Saving the current domains cache table from memory to file: #{file_domains} ..." if @verbose
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
domains
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
f.write "#{key}, no\n"
|
124
|
-
end
|
107
|
+
timestamp=Time.now
|
108
|
+
f=File.open(file_domains, 'w')
|
109
|
+
f.write "# Local domains file created by class #{self.class} method #{__method__} at: #{timestamp}\n"
|
110
|
+
f.write "# domain name, free zone transfer detected?\n"
|
111
|
+
domains.keys.sort.map do |key|
|
112
|
+
if domains[key]
|
113
|
+
f.write "#{key}, yes\n"
|
114
|
+
else
|
115
|
+
f.write "#{key}, no\n"
|
125
116
|
end
|
126
|
-
f.close
|
127
|
-
puts "Domain cache table is successfully saved: #{file_domains}"
|
128
|
-
rescue => ee
|
129
|
-
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
130
117
|
end
|
118
|
+
f.close
|
119
|
+
puts "Domain cache table is successfully saved: #{file_domains}"
|
120
|
+
rescue => ee
|
121
|
+
puts "Exception on method #{__method__}: #{ee}" if @verbose
|
131
122
|
end
|
132
123
|
alias_method :save!, :save_sub_domains_to_file!
|
133
|
-
end
|
134
124
|
|
135
125
|
# Print summary report on all known / trust domains in the domain cache table
|
136
126
|
def print_known_sub_domains
|
@@ -143,3 +133,4 @@ end
|
|
143
133
|
|
144
134
|
end
|
145
135
|
end
|
136
|
+
end
|