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.
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