dnstraverse 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|