dnstraverse 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/LICENSE +674 -0
- data/README +4 -0
- data/Rakefile +19 -0
- data/a +44 -0
- data/bin/dnstraverse +300 -0
- data/doc.tar +0 -0
- data/doc/classes/DNSTraverse.html +198 -0
- data/doc/classes/DNSTraverse/CachingResolver.html +172 -0
- data/doc/classes/DNSTraverse/CachingResolver.src/M000055.html +21 -0
- data/doc/classes/DNSTraverse/CachingResolver.src/M000056.html +42 -0
- data/doc/classes/DNSTraverse/DecodedQuery.html +475 -0
- data/doc/classes/DNSTraverse/DecodedQuery.src/M000020.html +34 -0
- data/doc/classes/DNSTraverse/DecodedQuery.src/M000021.html +23 -0
- data/doc/classes/DNSTraverse/DecodedQuery.src/M000022.html +19 -0
- data/doc/classes/DNSTraverse/DecodedQuery.src/M000023.html +33 -0
- data/doc/classes/DNSTraverse/DecodedQuery.src/M000024.html +26 -0
- data/doc/classes/DNSTraverse/DecodedQuery.src/M000025.html +24 -0
- data/doc/classes/DNSTraverse/DecodedQuery.src/M000026.html +29 -0
- data/doc/classes/DNSTraverse/DecodedQuery.src/M000027.html +19 -0
- data/doc/classes/DNSTraverse/DecodedQuery.src/M000028.html +18 -0
- data/doc/classes/DNSTraverse/DecodedQuery.src/M000029.html +32 -0
- data/doc/classes/DNSTraverse/DecodedQuery.src/M000030.html +19 -0
- data/doc/classes/DNSTraverse/DecodedQuery.src/M000031.html +19 -0
- data/doc/classes/DNSTraverse/DecodedQuery.src/M000032.html +20 -0
- data/doc/classes/DNSTraverse/DecodedQuery.src/M000033.html +31 -0
- data/doc/classes/DNSTraverse/DecodedQueryCache.html +182 -0
- data/doc/classes/DNSTraverse/DecodedQueryCache.src/M000063.html +21 -0
- data/doc/classes/DNSTraverse/DecodedQueryCache.src/M000064.html +33 -0
- data/doc/classes/DNSTraverse/Fingerprint.html +277 -0
- data/doc/classes/DNSTraverse/Fingerprint.src/M000047.html +29 -0
- data/doc/classes/DNSTraverse/Fingerprint.src/M000048.html +18 -0
- data/doc/classes/DNSTraverse/Fingerprint.src/M000049.html +57 -0
- data/doc/classes/DNSTraverse/Fingerprint.src/M000050.html +28 -0
- data/doc/classes/DNSTraverse/Fingerprint.src/M000051.html +27 -0
- data/doc/classes/DNSTraverse/Fingerprint.src/M000052.html +35 -0
- data/doc/classes/DNSTraverse/Fingerprint.src/M000053.html +24 -0
- data/doc/classes/DNSTraverse/Fingerprint.src/M000054.html +29 -0
- data/doc/classes/DNSTraverse/InfoCache.html +235 -0
- data/doc/classes/DNSTraverse/InfoCache.src/M000034.html +20 -0
- data/doc/classes/DNSTraverse/InfoCache.src/M000035.html +23 -0
- data/doc/classes/DNSTraverse/InfoCache.src/M000036.html +28 -0
- data/doc/classes/DNSTraverse/InfoCache.src/M000037.html +25 -0
- data/doc/classes/DNSTraverse/InfoCache.src/M000038.html +27 -0
- data/doc/classes/DNSTraverse/InfoCache.src/M000039.html +33 -0
- data/doc/classes/DNSTraverse/MessageUtility.html +275 -0
- data/doc/classes/DNSTraverse/MessageUtility.src/M000011.html +35 -0
- data/doc/classes/DNSTraverse/MessageUtility.src/M000012.html +37 -0
- data/doc/classes/DNSTraverse/MessageUtility.src/M000013.html +28 -0
- data/doc/classes/DNSTraverse/MessageUtility.src/M000014.html +27 -0
- data/doc/classes/DNSTraverse/MessageUtility.src/M000015.html +30 -0
- data/doc/classes/DNSTraverse/MessageUtility.src/M000016.html +32 -0
- data/doc/classes/DNSTraverse/MessageUtility.src/M000017.html +34 -0
- data/doc/classes/DNSTraverse/MessageUtility.src/M000018.html +23 -0
- data/doc/classes/DNSTraverse/MessageUtility.src/M000019.html +36 -0
- data/doc/classes/DNSTraverse/Referral.html +641 -0
- data/doc/classes/DNSTraverse/Referral.src/M000065.html +22 -0
- data/doc/classes/DNSTraverse/Referral.src/M000066.html +21 -0
- data/doc/classes/DNSTraverse/Referral.src/M000067.html +23 -0
- data/doc/classes/DNSTraverse/Referral.src/M000068.html +19 -0
- data/doc/classes/DNSTraverse/Referral.src/M000069.html +18 -0
- data/doc/classes/DNSTraverse/Referral.src/M000070.html +54 -0
- data/doc/classes/DNSTraverse/Referral.src/M000071.html +25 -0
- data/doc/classes/DNSTraverse/Referral.src/M000072.html +27 -0
- data/doc/classes/DNSTraverse/Referral.src/M000073.html +23 -0
- data/doc/classes/DNSTraverse/Referral.src/M000074.html +20 -0
- data/doc/classes/DNSTraverse/Referral.src/M000075.html +40 -0
- data/doc/classes/DNSTraverse/Referral.src/M000076.html +52 -0
- data/doc/classes/DNSTraverse/Referral.src/M000077.html +29 -0
- data/doc/classes/DNSTraverse/Referral.src/M000078.html +54 -0
- data/doc/classes/DNSTraverse/Referral.src/M000079.html +18 -0
- data/doc/classes/DNSTraverse/Referral.src/M000080.html +22 -0
- data/doc/classes/DNSTraverse/Referral.src/M000081.html +20 -0
- data/doc/classes/DNSTraverse/Referral.src/M000082.html +29 -0
- data/doc/classes/DNSTraverse/Referral.src/M000083.html +28 -0
- data/doc/classes/DNSTraverse/Referral.src/M000084.html +29 -0
- data/doc/classes/DNSTraverse/Referral.src/M000085.html +55 -0
- data/doc/classes/DNSTraverse/Referral.src/M000086.html +30 -0
- data/doc/classes/DNSTraverse/Referral.src/M000087.html +24 -0
- data/doc/classes/DNSTraverse/Referral.src/M000088.html +20 -0
- data/doc/classes/DNSTraverse/Referral.src/M000089.html +58 -0
- data/doc/classes/DNSTraverse/ResolveError.html +111 -0
- data/doc/classes/DNSTraverse/Response.html +271 -0
- data/doc/classes/DNSTraverse/Response.src/M000057.html +27 -0
- data/doc/classes/DNSTraverse/Response.src/M000058.html +21 -0
- data/doc/classes/DNSTraverse/Response.src/M000059.html +19 -0
- data/doc/classes/DNSTraverse/Response.src/M000060.html +21 -0
- data/doc/classes/DNSTraverse/Response.src/M000061.html +31 -0
- data/doc/classes/DNSTraverse/Response.src/M000062.html +23 -0
- data/doc/classes/DNSTraverse/Response/NoGlue.html +222 -0
- data/doc/classes/DNSTraverse/Response/NoGlue.src/M000007.html +32 -0
- data/doc/classes/DNSTraverse/Response/NoGlue.src/M000008.html +18 -0
- data/doc/classes/DNSTraverse/Response/NoGlue.src/M000009.html +18 -0
- data/doc/classes/DNSTraverse/Response/NoGlue.src/M000010.html +18 -0
- data/doc/classes/DNSTraverse/Traverser.html +247 -0
- data/doc/classes/DNSTraverse/Traverser.src/M000040.html +17 -0
- data/doc/classes/DNSTraverse/Traverser.src/M000041.html +52 -0
- data/doc/classes/DNSTraverse/Traverser.src/M000042.html +61 -0
- data/doc/classes/DNSTraverse/Traverser.src/M000043.html +110 -0
- data/doc/classes/DNSTraverse/Traverser.src/M000044.html +63 -0
- data/doc/classes/DNSTraverse/Traverser.src/M000045.html +28 -0
- data/doc/classes/DNSTraverse/Traverser.src/M000046.html +18 -0
- data/doc/classes/FingerprintRules.html +175 -0
- data/doc/classes/Log.html +174 -0
- data/doc/classes/Log.src/M000002.html +18 -0
- data/doc/classes/Log.src/M000003.html +18 -0
- data/doc/classes/Log.src/M000004.html +18 -0
- data/doc/classes/Log/Formatter.html +165 -0
- data/doc/classes/Log/Formatter.src/M000005.html +22 -0
- data/doc/classes/Log/Formatter.src/M000006.html +24 -0
- data/doc/classes/TestFingerprint.html +137 -0
- data/doc/classes/TestFingerprint.src/M000001.html +22 -0
- data/doc/created.rid +1 -0
- data/doc/files/lib/dnstraverse/caching_resolver_rb.html +132 -0
- data/doc/files/lib/dnstraverse/decoded_query_cache_rb.html +132 -0
- data/doc/files/lib/dnstraverse/decoded_query_rb.html +132 -0
- data/doc/files/lib/dnstraverse/fingerprint_rb.html +134 -0
- data/doc/files/lib/dnstraverse/fingerprint_rules_rb.html +143 -0
- data/doc/files/lib/dnstraverse/info_cache_rb.html +131 -0
- data/doc/files/lib/dnstraverse/log_rb.html +131 -0
- data/doc/files/lib/dnstraverse/message_utility_rb.html +124 -0
- data/doc/files/lib/dnstraverse/referral_rb.html +134 -0
- data/doc/files/lib/dnstraverse/response_noglue_rb.html +124 -0
- data/doc/files/lib/dnstraverse/response_rb.html +132 -0
- data/doc/files/lib/dnstraverse/traverser_rb.html +137 -0
- data/doc/files/test/test_fingerprint_rb.html +133 -0
- data/doc/fr_class_index.html +43 -0
- data/doc/fr_file_index.html +39 -0
- data/doc/fr_method_index.html +115 -0
- data/doc/index.html +24 -0
- data/doc/rdoc-style.css +208 -0
- data/lib/dnstraverse/caching_resolver.rb +63 -0
- data/lib/dnstraverse/decoded_query.rb +199 -0
- data/lib/dnstraverse/decoded_query_cache.rb +53 -0
- data/lib/dnstraverse/fingerprint.rb +166 -0
- data/lib/dnstraverse/fingerprint_rules.rb +389 -0
- data/lib/dnstraverse/info_cache.rb +108 -0
- data/lib/dnstraverse/log.rb +55 -0
- data/lib/dnstraverse/message_utility.rb +199 -0
- data/lib/dnstraverse/referral.rb +463 -0
- data/lib/dnstraverse/response.rb +92 -0
- data/lib/dnstraverse/response_noglue.rb +54 -0
- data/lib/dnstraverse/traverser.rb +291 -0
- data/test/test_fingerprint.rb +29 -0
- metadata +231 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# DNSTraverse traverses the DNS to show statistics and information
|
|
2
|
+
# Copyright (C) 2008 James Ponder
|
|
3
|
+
#
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation, version 3 of the License.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
require 'dnstraverse/info_cache'
|
|
17
|
+
require 'dnstraverse/log'
|
|
18
|
+
|
|
19
|
+
module DNSTraverse
|
|
20
|
+
|
|
21
|
+
# get a response to a query (or pass in the response if you already have one)
|
|
22
|
+
# creates lots of stats and info, caching as much as possible
|
|
23
|
+
class Response
|
|
24
|
+
attr_reader :decoded_query
|
|
25
|
+
attr_reader :infocache
|
|
26
|
+
attr_reader :status # our status, expanding on DecodedQuery status
|
|
27
|
+
attr_reader :starters, :starters_bailiwick # :referral/:restart only
|
|
28
|
+
attr_reader :stats_key
|
|
29
|
+
|
|
30
|
+
# :qname, :qclass, :qtype, :ip, :bailiwick, optional :message
|
|
31
|
+
def initialize(args)
|
|
32
|
+
dqc_args = { :qname => args[:qname], :qclass => args[:qclass],
|
|
33
|
+
:qtype => args[:qtype], :ip => args[:ip],
|
|
34
|
+
:bailiwick => args[:bailiwick], :message => args[:message] }
|
|
35
|
+
@decoded_query = args[:decoded_query_cache].query(dqc_args)
|
|
36
|
+
@infocache = InfoCache.new(args[:infocache]) # our infocache
|
|
37
|
+
@starters = nil # initial servers for :referral/:restart
|
|
38
|
+
@starters_bailiwick = nil # for initial servers for :referral/:restart
|
|
39
|
+
evaluate
|
|
40
|
+
update_stats_key
|
|
41
|
+
return self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def method_missing(key, *args, &block)
|
|
45
|
+
if @decoded_query.respond_to?(key) then
|
|
46
|
+
return @decoded_query.send(key, *args)
|
|
47
|
+
end
|
|
48
|
+
super
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def update_stats_key
|
|
52
|
+
r = @decoded_query
|
|
53
|
+
@stats_key = "key:#{r.ip}:#{@status}:#{r.qname}:#{r.qclass}:#{r.qtype}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# clean up the workings
|
|
57
|
+
def cleanup
|
|
58
|
+
@infocache = nil
|
|
59
|
+
###@cacheable_good = @cacheable_bad = nil
|
|
60
|
+
@starters = @starters_bailiwick = nil
|
|
61
|
+
###@auth_ns = @auth_soa = @auth_other = nil
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# enrich the decoded_query to do the cache, lame checking and get starters
|
|
65
|
+
def evaluate
|
|
66
|
+
@status = @decoded_query.status # use this as a base
|
|
67
|
+
if @status != :exception
|
|
68
|
+
@infocache.add(@decoded_query.cacheable_good)
|
|
69
|
+
end
|
|
70
|
+
case @decoded_query.status
|
|
71
|
+
when :restart
|
|
72
|
+
@starters, @starters_bailiwick = @infocache.get_startservers(@decoded_query.endname)
|
|
73
|
+
when :referral
|
|
74
|
+
@starters, @starters_bailiwick = @infocache.get_startservers(@decoded_query.endname)
|
|
75
|
+
starternames = @starters.map { |x| x[:name].to_s.downcase }
|
|
76
|
+
if starternames.sort != @decoded_query.authoritynames.sort
|
|
77
|
+
@status = :referral_lame
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# convert to string - check for our enrichments, or use decoded_status
|
|
83
|
+
def to_s
|
|
84
|
+
case @status
|
|
85
|
+
when :referral_lame
|
|
86
|
+
return "Lame referral to #{@decoded_query.authoritynames}"
|
|
87
|
+
else
|
|
88
|
+
return @decoded_query.to_s
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# DNSTraverse traverses the DNS to show statistics and information
|
|
2
|
+
# Copyright (C) 2008 James Ponder
|
|
3
|
+
#
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation, version 3 of the License.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
module DNSTraverse
|
|
17
|
+
|
|
18
|
+
class Response::NoGlue < Response
|
|
19
|
+
|
|
20
|
+
attr_reader :qname, :qclass, :qtype, :ip, :bailiwick, :server
|
|
21
|
+
|
|
22
|
+
def initialize(args)
|
|
23
|
+
# we queried @ip about @qname/@qclass/@qtype and received @server as a
|
|
24
|
+
# referral in bailiwick @bailiwick but without any glue
|
|
25
|
+
@qname = args[:qname]
|
|
26
|
+
@qclass = args[:qclass]
|
|
27
|
+
@qtype = args[:qtype]
|
|
28
|
+
@bailiwick = args[:bailiwick]
|
|
29
|
+
@ip = args[:ip]
|
|
30
|
+
@server = args[:server]
|
|
31
|
+
@decoded_query = nil
|
|
32
|
+
@infocache = nil
|
|
33
|
+
@starters = nil
|
|
34
|
+
@starters_bailiwick = nil
|
|
35
|
+
@status = :noglue
|
|
36
|
+
update_stats_key
|
|
37
|
+
return self
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def method_missing(key, *args, &block)
|
|
41
|
+
super # there are no missing methods, we answer directly
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def update_stats_key
|
|
45
|
+
@stats_key = "key:#{@ip}:#{@status}:#{@qname}:#{@qclass}:#{@qtype}:#{@server}:#{@bailiwick}"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def to_s
|
|
49
|
+
return "No glue for #{@server}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# DNSTraverse traverses the DNS to show statistics and information
|
|
2
|
+
# Copyright (C) 2008 James Ponder
|
|
3
|
+
#
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation, version 3 of the License.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
gem 'dnsruby', '>=1.26'
|
|
17
|
+
require 'dnsruby'
|
|
18
|
+
require 'dnstraverse/info_cache'
|
|
19
|
+
require 'dnstraverse/log'
|
|
20
|
+
require 'dnstraverse/message_utility'
|
|
21
|
+
require 'dnstraverse/caching_resolver'
|
|
22
|
+
require 'dnstraverse/referral'
|
|
23
|
+
require 'socket'
|
|
24
|
+
|
|
25
|
+
module DNSTraverse
|
|
26
|
+
|
|
27
|
+
TYPE_ARRAY_AAAA = ['AAAA', 'A'].freeze
|
|
28
|
+
TYPE_ARRAY_A = ['A'].freeze
|
|
29
|
+
|
|
30
|
+
class Traverser
|
|
31
|
+
include MessageUtility
|
|
32
|
+
|
|
33
|
+
def progress_null(args)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def initialize(args)
|
|
37
|
+
Socket.do_not_reverse_lookup = true
|
|
38
|
+
Log.level = args[:loglevel] if args[:loglevel]
|
|
39
|
+
Log.debug { "Initialize with args: " + args.inspect }
|
|
40
|
+
Dnsruby.log.level = args[:libloglevel] if args[:libloglevel]
|
|
41
|
+
@state = args[:state] || nil
|
|
42
|
+
@maxdepth = args[:maxdepth] || 10
|
|
43
|
+
@progress_main = args[:progress_main] || method(:progress_null)
|
|
44
|
+
@progress_resolve = args[:progress_resolve] || method(:progress_null)
|
|
45
|
+
@fast = args[:fast] || false # use fast algorithm, less accurate
|
|
46
|
+
@answered = @fast ? Hash.new : nil # for fast algorithm
|
|
47
|
+
@seen = Hash.new # servernames to IP addresses of anything we see
|
|
48
|
+
retries = args[:retries] || 2
|
|
49
|
+
retry_delay = args[:retry_delay] || 2
|
|
50
|
+
packet_timeout = args[:packet_timeout] || 2
|
|
51
|
+
dnssec = args[:dnssec] || false
|
|
52
|
+
srcaddr = args[:srcaddr] || '0.0.0.0'
|
|
53
|
+
use_tcp = args[:always_tcp] || false
|
|
54
|
+
ignore_truncation = args[:allow_tcp] ? false : true
|
|
55
|
+
udpsize = args[:udpsize] || 512
|
|
56
|
+
cfg = Dnsruby::Config.new
|
|
57
|
+
rescfg = { :nameserver => cfg.nameserver, :ndots => cfg.ndots,
|
|
58
|
+
:apply_domain => false, :apply_search_list => false}
|
|
59
|
+
resargs = { :config_info => rescfg, :use_tcp => use_tcp, :recurse => false,
|
|
60
|
+
:retry_times => retries, :retry_delay => retry_delay, :dnssec => dnssec,
|
|
61
|
+
:ignore_truncation => ignore_truncation, :src_address => srcaddr,
|
|
62
|
+
:udp_size => udpsize.to_i, :packet_timeout => packet_timeout }
|
|
63
|
+
Log.debug { "Creating remote resolver object"}
|
|
64
|
+
CachingResolver.use_eventmachine(false)
|
|
65
|
+
@resolver = CachingResolver.new(resargs) # used for set nameservers
|
|
66
|
+
@resolver.udp_size = udpsize.to_i
|
|
67
|
+
Log.debug { "Creating local resolver object"}
|
|
68
|
+
resargs[:recurse] = true
|
|
69
|
+
@lresolver = Dnsruby::Resolver.new(resargs) # left on local default
|
|
70
|
+
@lresolver.udp_size = udpsize.to_i
|
|
71
|
+
self
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
### change to get_all or something?
|
|
75
|
+
def get_a_root(args)
|
|
76
|
+
aaaa = args[:aaaa] || false
|
|
77
|
+
Log.debug { "get_a_root entry" }
|
|
78
|
+
# get nameservers for root
|
|
79
|
+
begin
|
|
80
|
+
msg = @lresolver.query('', 'NS')
|
|
81
|
+
rescue Exception => e
|
|
82
|
+
puts "Failed to get roots, local resolver returned exception: #{e}"
|
|
83
|
+
raise e
|
|
84
|
+
end
|
|
85
|
+
msg_validate(msg, :qname => '', :qtype => 'NS')
|
|
86
|
+
msg_comment(msg, :want_recursion => true)
|
|
87
|
+
ans1 = msg_answers?(msg, :qname => '', :qtype => 'NS')
|
|
88
|
+
unless ans1 then
|
|
89
|
+
raise ResolveError, "No root nameservers found"
|
|
90
|
+
end
|
|
91
|
+
roots = ans1.map {|x| x.domainname.to_s }
|
|
92
|
+
Log.debug { "Local resolver lists: " + roots.join(', ') }
|
|
93
|
+
types = aaaa ? TYPE_ARRAY_AAAA : TYPE_ARRAY_A
|
|
94
|
+
# loop through all root nameservers to get an appropriate address
|
|
95
|
+
for type in types do
|
|
96
|
+
for root in roots do
|
|
97
|
+
if (add = msg_additional?(msg, :qname => root, :qtype => type)) then
|
|
98
|
+
rootip = add[0].rdata.to_s
|
|
99
|
+
return root, rootip
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
Log.debug { "Nothing in additional section of help" }
|
|
104
|
+
for type in types do
|
|
105
|
+
for root in roots do
|
|
106
|
+
Log.debug { "Resolving root #{root} type #{type}" }
|
|
107
|
+
msg = @lresolver.query(root, type)
|
|
108
|
+
msg_validate(msg, :qname => root, :qtype => type)
|
|
109
|
+
msg_comment(msg, :want_recursion => true)
|
|
110
|
+
ans2 = msg_answers?(msg, :qname => root, :qtype => type)
|
|
111
|
+
if ans2 then
|
|
112
|
+
rootip = ans2[0].rdata.to_s # use first one
|
|
113
|
+
Log.debug { "get_a_root exit: #{root} #{rootip}" }
|
|
114
|
+
return root, rootip
|
|
115
|
+
end
|
|
116
|
+
Log.debug { "#{root}/#{type}: No suitable answers found" }
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
raise ResolveError, "No address could be found for any root server"
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def run(r, args = {})
|
|
123
|
+
Log.debug { "run entry, initialising stack to: " + r.to_s }
|
|
124
|
+
cleanup = args[:cleanup]
|
|
125
|
+
stack = Array.new
|
|
126
|
+
stack << r
|
|
127
|
+
while stack.size > 0 do
|
|
128
|
+
Log.debug { "stack size is #{stack.size}" }
|
|
129
|
+
Log.debug {
|
|
130
|
+
counter = 0
|
|
131
|
+
output = ""
|
|
132
|
+
for entry in stack.reverse do
|
|
133
|
+
output+= sprintf "%04d %s\n", counter, entry.to_s
|
|
134
|
+
counter+= 1
|
|
135
|
+
end
|
|
136
|
+
output
|
|
137
|
+
}
|
|
138
|
+
raise "bad stack" if stack.size > 1000
|
|
139
|
+
r = stack.pop
|
|
140
|
+
Log.debug { "running on stack entry #{r}" }
|
|
141
|
+
case r
|
|
142
|
+
when :calc_resolve
|
|
143
|
+
r = stack.pop
|
|
144
|
+
r.resolve_calculate
|
|
145
|
+
refres = r.referral_resolution?
|
|
146
|
+
p = (refres == true ? @progress_resolve : @progress_main)
|
|
147
|
+
p.call(:state => @state, :referral => r, :stage => :resolve)
|
|
148
|
+
stack << r # now need to process
|
|
149
|
+
next
|
|
150
|
+
when :calc_answer
|
|
151
|
+
r = stack.pop
|
|
152
|
+
r.answer_calculate
|
|
153
|
+
refres = r.referral_resolution?
|
|
154
|
+
p = (refres == true ? @progress_resolve : @progress_main)
|
|
155
|
+
p.call(:state => @state, :referral => r, :stage => :answer)
|
|
156
|
+
r.cleanup(cleanup)
|
|
157
|
+
if @fast then
|
|
158
|
+
# store away in @answered hash so we can lookup later
|
|
159
|
+
# XXX fast method should use IP and not server name?
|
|
160
|
+
# or maybe we should append IPs to end...
|
|
161
|
+
key = "#{r.qname}:#{r.qclass}:#{r.qtype}:#{r.server}:#{r.txt_ips_verbose}"
|
|
162
|
+
key.downcase!
|
|
163
|
+
Log.debug { "Fast mode cache store: #{key}" }
|
|
164
|
+
@answered[key] = r
|
|
165
|
+
end
|
|
166
|
+
unless r.server.nil? then
|
|
167
|
+
@seen[r.server.downcase] = [] unless @seen.has_key?(r.server)
|
|
168
|
+
@seen[r.server.downcase].concat(r.ips_as_array)
|
|
169
|
+
@seen[r.server.downcase].uniq!
|
|
170
|
+
end
|
|
171
|
+
next
|
|
172
|
+
else
|
|
173
|
+
refres = r.referral_resolution?
|
|
174
|
+
p = (refres == true ? @progress_resolve : @progress_main)
|
|
175
|
+
p.call(:state => @state, :referral => r, :stage => :start)
|
|
176
|
+
end
|
|
177
|
+
unless r.resolved? then
|
|
178
|
+
# get resolve Referral objects, place on stack with placeholder
|
|
179
|
+
stack << r << :calc_resolve
|
|
180
|
+
stack.push(*r.resolve({}).reverse)
|
|
181
|
+
next
|
|
182
|
+
end
|
|
183
|
+
unless r.processed? then
|
|
184
|
+
# get Referral objects, place on stack with placeholder
|
|
185
|
+
stack << r << :calc_answer
|
|
186
|
+
children = r.process({})
|
|
187
|
+
if @fast then
|
|
188
|
+
Log.debug { "Checking #{r} for already completed children" }
|
|
189
|
+
newchildren = []
|
|
190
|
+
for c in children do
|
|
191
|
+
key = "#{c.qname}:#{c.qclass}:#{c.qtype}:#{c.server}:#{c.txt_ips_verbose}"
|
|
192
|
+
key.downcase!
|
|
193
|
+
Log.debug { "Fast mode cache lookup: #{key}" }
|
|
194
|
+
# check for previously stored answer
|
|
195
|
+
# special case noglue situation, don't use previous answer
|
|
196
|
+
# because attributes are complicated for stats collection and
|
|
197
|
+
# we don't want to merge them together - creating the noglue
|
|
198
|
+
# response object is fast anyway
|
|
199
|
+
if @answered.key?(key) and (not c.noglue?) then
|
|
200
|
+
Log.debug { "Fast method - completed #{c}" }
|
|
201
|
+
r.replace_child(c, @answered[key])
|
|
202
|
+
refres = r.referral_resolution?
|
|
203
|
+
p = (refres == true ? @progress_resolve : @progress_main)
|
|
204
|
+
p.call(:state => @state, :referral => c, :stage => :answer_fast)
|
|
205
|
+
else
|
|
206
|
+
newchildren << c
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
children = newchildren
|
|
210
|
+
end
|
|
211
|
+
stack.push(*children.reverse)
|
|
212
|
+
next
|
|
213
|
+
end
|
|
214
|
+
raise "Fatal stack error at #{r} - size still #{stack.size}"
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# asks the :root/:rootip server for all the roots, fills in any missing
|
|
219
|
+
# IP addresses from local resolver
|
|
220
|
+
def find_all_roots(args)
|
|
221
|
+
root = args[:root] || 'localhost'
|
|
222
|
+
rootip = args[:rootip] || '127.0.0.1'
|
|
223
|
+
aaaa = args[:aaaa] || false
|
|
224
|
+
types = aaaa ? TYPE_ARRAY_AAAA : TYPE_ARRAY_A
|
|
225
|
+
Log.debug { "find_roots entry #{root}" }
|
|
226
|
+
@resolver.nameserver = rootip
|
|
227
|
+
# query for all the root nameservers
|
|
228
|
+
msg = @resolver.query('', 'NS')
|
|
229
|
+
raise msg if msg.is_a? Exception
|
|
230
|
+
msg_validate(msg, :qname => '', :qtype => 'NS')
|
|
231
|
+
msg_comment(msg, :want_recursion => false)
|
|
232
|
+
ns = msg_answers?(msg, :qname => '', :qtype => 'NS')
|
|
233
|
+
return nil unless ns
|
|
234
|
+
roots = Array.new
|
|
235
|
+
# look at each root in turn
|
|
236
|
+
for rr in ns do
|
|
237
|
+
ips = []
|
|
238
|
+
# find IP addresses in the additional section
|
|
239
|
+
for type in types do
|
|
240
|
+
iprrs = msg_additional?(msg, :qname => rr.domainname, :qtype => type)
|
|
241
|
+
if iprrs then
|
|
242
|
+
ips.concat iprrs.map {|iprr| iprr.address.to_s }
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
# if none, query for the IP addresses
|
|
246
|
+
unless ips then
|
|
247
|
+
Log.debug { "Locally resolving root #{rr.domainname}" }
|
|
248
|
+
for type in types do
|
|
249
|
+
msg = @lresolver.query(rr.domainname, type)
|
|
250
|
+
msg_validate(msg, :qname => rr.domainname, :qtype => type)
|
|
251
|
+
msg_comment(msg, :want_recursion => true)
|
|
252
|
+
iprrs = msg_answers?(msg, :qname => rr.domainname, :qtype => type)
|
|
253
|
+
if iprrs then
|
|
254
|
+
ips.concat iprrs.map {|iprr| iprr.address.to_s }
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
# if we still don't have any IP address, skip this root
|
|
259
|
+
unless ips.size > 0 then
|
|
260
|
+
Log.warn { "Failed to resolve #{rr.domainname} type #{qtype}" }
|
|
261
|
+
next
|
|
262
|
+
end
|
|
263
|
+
roots.push({ :name => rr.domainname, :ips => ips })
|
|
264
|
+
end
|
|
265
|
+
Log.debug { "find_roots exit, #{roots.map { |x| x[:name] }.join(', ') }" }
|
|
266
|
+
return roots
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def run_query(args)
|
|
270
|
+
qname = args[:qname]
|
|
271
|
+
qtype = args[:qtype] || 'A'
|
|
272
|
+
maxdepth = args[:maxdepth] || 10
|
|
273
|
+
cleanup = args[:cleanup]
|
|
274
|
+
Log.debug { "run_query entry qname=#{qname} qtype=#{qtype}" }
|
|
275
|
+
r = Referral.new(:qname => qname, :qtype => qtype, :roots => args[:roots],
|
|
276
|
+
:maxdepth => maxdepth, :resolver => @resolver,
|
|
277
|
+
:nsatype => 'A')
|
|
278
|
+
run(r, :cleanup => cleanup)
|
|
279
|
+
Log.debug { "run_query exit" }
|
|
280
|
+
return r
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# returns a Hash of all the servernames we've seen so far
|
|
284
|
+
# servername is the key, the value is an Array of IP addresses (strings)
|
|
285
|
+
def servers_encountered
|
|
286
|
+
return @seen
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# DNSTraverse traverses the DNS to show statistics and information
|
|
2
|
+
# Copyright (C) 2008 James Ponder
|
|
3
|
+
#
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation, version 3 of the License.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
require 'rubygems'
|
|
17
|
+
gem 'dnsruby', '>=1.19'
|
|
18
|
+
require "test/unit"
|
|
19
|
+
require "dnstraverse/fingerprint"
|
|
20
|
+
|
|
21
|
+
class TestFingerprint < Test::Unit::TestCase
|
|
22
|
+
def test_squishnet
|
|
23
|
+
fp = DNSTraverse::Fingerprint.new
|
|
24
|
+
ip = Socket.getaddrinfo("ns.squish.net", 0,
|
|
25
|
+
Socket::AF_UNSPEC, Socket::SOCK_STREAM)[0][3]
|
|
26
|
+
squish = fp.fingerprint(ip)
|
|
27
|
+
assert_equal(squish[:product], "BIND")
|
|
28
|
+
end
|
|
29
|
+
end
|