dnstraverse 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. data/LICENSE +674 -0
  2. data/README +4 -0
  3. data/Rakefile +19 -0
  4. data/a +44 -0
  5. data/bin/dnstraverse +300 -0
  6. data/doc.tar +0 -0
  7. data/doc/classes/DNSTraverse.html +198 -0
  8. data/doc/classes/DNSTraverse/CachingResolver.html +172 -0
  9. data/doc/classes/DNSTraverse/CachingResolver.src/M000055.html +21 -0
  10. data/doc/classes/DNSTraverse/CachingResolver.src/M000056.html +42 -0
  11. data/doc/classes/DNSTraverse/DecodedQuery.html +475 -0
  12. data/doc/classes/DNSTraverse/DecodedQuery.src/M000020.html +34 -0
  13. data/doc/classes/DNSTraverse/DecodedQuery.src/M000021.html +23 -0
  14. data/doc/classes/DNSTraverse/DecodedQuery.src/M000022.html +19 -0
  15. data/doc/classes/DNSTraverse/DecodedQuery.src/M000023.html +33 -0
  16. data/doc/classes/DNSTraverse/DecodedQuery.src/M000024.html +26 -0
  17. data/doc/classes/DNSTraverse/DecodedQuery.src/M000025.html +24 -0
  18. data/doc/classes/DNSTraverse/DecodedQuery.src/M000026.html +29 -0
  19. data/doc/classes/DNSTraverse/DecodedQuery.src/M000027.html +19 -0
  20. data/doc/classes/DNSTraverse/DecodedQuery.src/M000028.html +18 -0
  21. data/doc/classes/DNSTraverse/DecodedQuery.src/M000029.html +32 -0
  22. data/doc/classes/DNSTraverse/DecodedQuery.src/M000030.html +19 -0
  23. data/doc/classes/DNSTraverse/DecodedQuery.src/M000031.html +19 -0
  24. data/doc/classes/DNSTraverse/DecodedQuery.src/M000032.html +20 -0
  25. data/doc/classes/DNSTraverse/DecodedQuery.src/M000033.html +31 -0
  26. data/doc/classes/DNSTraverse/DecodedQueryCache.html +182 -0
  27. data/doc/classes/DNSTraverse/DecodedQueryCache.src/M000063.html +21 -0
  28. data/doc/classes/DNSTraverse/DecodedQueryCache.src/M000064.html +33 -0
  29. data/doc/classes/DNSTraverse/Fingerprint.html +277 -0
  30. data/doc/classes/DNSTraverse/Fingerprint.src/M000047.html +29 -0
  31. data/doc/classes/DNSTraverse/Fingerprint.src/M000048.html +18 -0
  32. data/doc/classes/DNSTraverse/Fingerprint.src/M000049.html +57 -0
  33. data/doc/classes/DNSTraverse/Fingerprint.src/M000050.html +28 -0
  34. data/doc/classes/DNSTraverse/Fingerprint.src/M000051.html +27 -0
  35. data/doc/classes/DNSTraverse/Fingerprint.src/M000052.html +35 -0
  36. data/doc/classes/DNSTraverse/Fingerprint.src/M000053.html +24 -0
  37. data/doc/classes/DNSTraverse/Fingerprint.src/M000054.html +29 -0
  38. data/doc/classes/DNSTraverse/InfoCache.html +235 -0
  39. data/doc/classes/DNSTraverse/InfoCache.src/M000034.html +20 -0
  40. data/doc/classes/DNSTraverse/InfoCache.src/M000035.html +23 -0
  41. data/doc/classes/DNSTraverse/InfoCache.src/M000036.html +28 -0
  42. data/doc/classes/DNSTraverse/InfoCache.src/M000037.html +25 -0
  43. data/doc/classes/DNSTraverse/InfoCache.src/M000038.html +27 -0
  44. data/doc/classes/DNSTraverse/InfoCache.src/M000039.html +33 -0
  45. data/doc/classes/DNSTraverse/MessageUtility.html +275 -0
  46. data/doc/classes/DNSTraverse/MessageUtility.src/M000011.html +35 -0
  47. data/doc/classes/DNSTraverse/MessageUtility.src/M000012.html +37 -0
  48. data/doc/classes/DNSTraverse/MessageUtility.src/M000013.html +28 -0
  49. data/doc/classes/DNSTraverse/MessageUtility.src/M000014.html +27 -0
  50. data/doc/classes/DNSTraverse/MessageUtility.src/M000015.html +30 -0
  51. data/doc/classes/DNSTraverse/MessageUtility.src/M000016.html +32 -0
  52. data/doc/classes/DNSTraverse/MessageUtility.src/M000017.html +34 -0
  53. data/doc/classes/DNSTraverse/MessageUtility.src/M000018.html +23 -0
  54. data/doc/classes/DNSTraverse/MessageUtility.src/M000019.html +36 -0
  55. data/doc/classes/DNSTraverse/Referral.html +641 -0
  56. data/doc/classes/DNSTraverse/Referral.src/M000065.html +22 -0
  57. data/doc/classes/DNSTraverse/Referral.src/M000066.html +21 -0
  58. data/doc/classes/DNSTraverse/Referral.src/M000067.html +23 -0
  59. data/doc/classes/DNSTraverse/Referral.src/M000068.html +19 -0
  60. data/doc/classes/DNSTraverse/Referral.src/M000069.html +18 -0
  61. data/doc/classes/DNSTraverse/Referral.src/M000070.html +54 -0
  62. data/doc/classes/DNSTraverse/Referral.src/M000071.html +25 -0
  63. data/doc/classes/DNSTraverse/Referral.src/M000072.html +27 -0
  64. data/doc/classes/DNSTraverse/Referral.src/M000073.html +23 -0
  65. data/doc/classes/DNSTraverse/Referral.src/M000074.html +20 -0
  66. data/doc/classes/DNSTraverse/Referral.src/M000075.html +40 -0
  67. data/doc/classes/DNSTraverse/Referral.src/M000076.html +52 -0
  68. data/doc/classes/DNSTraverse/Referral.src/M000077.html +29 -0
  69. data/doc/classes/DNSTraverse/Referral.src/M000078.html +54 -0
  70. data/doc/classes/DNSTraverse/Referral.src/M000079.html +18 -0
  71. data/doc/classes/DNSTraverse/Referral.src/M000080.html +22 -0
  72. data/doc/classes/DNSTraverse/Referral.src/M000081.html +20 -0
  73. data/doc/classes/DNSTraverse/Referral.src/M000082.html +29 -0
  74. data/doc/classes/DNSTraverse/Referral.src/M000083.html +28 -0
  75. data/doc/classes/DNSTraverse/Referral.src/M000084.html +29 -0
  76. data/doc/classes/DNSTraverse/Referral.src/M000085.html +55 -0
  77. data/doc/classes/DNSTraverse/Referral.src/M000086.html +30 -0
  78. data/doc/classes/DNSTraverse/Referral.src/M000087.html +24 -0
  79. data/doc/classes/DNSTraverse/Referral.src/M000088.html +20 -0
  80. data/doc/classes/DNSTraverse/Referral.src/M000089.html +58 -0
  81. data/doc/classes/DNSTraverse/ResolveError.html +111 -0
  82. data/doc/classes/DNSTraverse/Response.html +271 -0
  83. data/doc/classes/DNSTraverse/Response.src/M000057.html +27 -0
  84. data/doc/classes/DNSTraverse/Response.src/M000058.html +21 -0
  85. data/doc/classes/DNSTraverse/Response.src/M000059.html +19 -0
  86. data/doc/classes/DNSTraverse/Response.src/M000060.html +21 -0
  87. data/doc/classes/DNSTraverse/Response.src/M000061.html +31 -0
  88. data/doc/classes/DNSTraverse/Response.src/M000062.html +23 -0
  89. data/doc/classes/DNSTraverse/Response/NoGlue.html +222 -0
  90. data/doc/classes/DNSTraverse/Response/NoGlue.src/M000007.html +32 -0
  91. data/doc/classes/DNSTraverse/Response/NoGlue.src/M000008.html +18 -0
  92. data/doc/classes/DNSTraverse/Response/NoGlue.src/M000009.html +18 -0
  93. data/doc/classes/DNSTraverse/Response/NoGlue.src/M000010.html +18 -0
  94. data/doc/classes/DNSTraverse/Traverser.html +247 -0
  95. data/doc/classes/DNSTraverse/Traverser.src/M000040.html +17 -0
  96. data/doc/classes/DNSTraverse/Traverser.src/M000041.html +52 -0
  97. data/doc/classes/DNSTraverse/Traverser.src/M000042.html +61 -0
  98. data/doc/classes/DNSTraverse/Traverser.src/M000043.html +110 -0
  99. data/doc/classes/DNSTraverse/Traverser.src/M000044.html +63 -0
  100. data/doc/classes/DNSTraverse/Traverser.src/M000045.html +28 -0
  101. data/doc/classes/DNSTraverse/Traverser.src/M000046.html +18 -0
  102. data/doc/classes/FingerprintRules.html +175 -0
  103. data/doc/classes/Log.html +174 -0
  104. data/doc/classes/Log.src/M000002.html +18 -0
  105. data/doc/classes/Log.src/M000003.html +18 -0
  106. data/doc/classes/Log.src/M000004.html +18 -0
  107. data/doc/classes/Log/Formatter.html +165 -0
  108. data/doc/classes/Log/Formatter.src/M000005.html +22 -0
  109. data/doc/classes/Log/Formatter.src/M000006.html +24 -0
  110. data/doc/classes/TestFingerprint.html +137 -0
  111. data/doc/classes/TestFingerprint.src/M000001.html +22 -0
  112. data/doc/created.rid +1 -0
  113. data/doc/files/lib/dnstraverse/caching_resolver_rb.html +132 -0
  114. data/doc/files/lib/dnstraverse/decoded_query_cache_rb.html +132 -0
  115. data/doc/files/lib/dnstraverse/decoded_query_rb.html +132 -0
  116. data/doc/files/lib/dnstraverse/fingerprint_rb.html +134 -0
  117. data/doc/files/lib/dnstraverse/fingerprint_rules_rb.html +143 -0
  118. data/doc/files/lib/dnstraverse/info_cache_rb.html +131 -0
  119. data/doc/files/lib/dnstraverse/log_rb.html +131 -0
  120. data/doc/files/lib/dnstraverse/message_utility_rb.html +124 -0
  121. data/doc/files/lib/dnstraverse/referral_rb.html +134 -0
  122. data/doc/files/lib/dnstraverse/response_noglue_rb.html +124 -0
  123. data/doc/files/lib/dnstraverse/response_rb.html +132 -0
  124. data/doc/files/lib/dnstraverse/traverser_rb.html +137 -0
  125. data/doc/files/test/test_fingerprint_rb.html +133 -0
  126. data/doc/fr_class_index.html +43 -0
  127. data/doc/fr_file_index.html +39 -0
  128. data/doc/fr_method_index.html +115 -0
  129. data/doc/index.html +24 -0
  130. data/doc/rdoc-style.css +208 -0
  131. data/lib/dnstraverse/caching_resolver.rb +63 -0
  132. data/lib/dnstraverse/decoded_query.rb +199 -0
  133. data/lib/dnstraverse/decoded_query_cache.rb +53 -0
  134. data/lib/dnstraverse/fingerprint.rb +166 -0
  135. data/lib/dnstraverse/fingerprint_rules.rb +389 -0
  136. data/lib/dnstraverse/info_cache.rb +108 -0
  137. data/lib/dnstraverse/log.rb +55 -0
  138. data/lib/dnstraverse/message_utility.rb +199 -0
  139. data/lib/dnstraverse/referral.rb +463 -0
  140. data/lib/dnstraverse/response.rb +92 -0
  141. data/lib/dnstraverse/response_noglue.rb +54 -0
  142. data/lib/dnstraverse/traverser.rb +291 -0
  143. data/test/test_fingerprint.rb +29 -0
  144. 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