dnsruby 1.55 → 1.56.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +96 -0
  3. data/Rakefile +30 -29
  4. data/demo/axfr.rb +93 -93
  5. data/demo/check_soa.rb +99 -99
  6. data/demo/check_zone.rb +59 -59
  7. data/demo/digdlv.rb +43 -43
  8. data/demo/digroot.rb +34 -34
  9. data/demo/example_recurse.rb +14 -14
  10. data/demo/mresolv.rb +30 -30
  11. data/demo/mx.rb +31 -31
  12. data/demo/rubydig.rb +37 -37
  13. data/demo/to_resolve.txt +3088 -3088
  14. data/demo/trace_dns.rb +46 -46
  15. data/lib/dnsruby.rb +161 -526
  16. data/lib/dnsruby/DNS.rb +305 -0
  17. data/lib/{Dnsruby/Cache.rb → dnsruby/cache.rb} +152 -152
  18. data/lib/{Dnsruby → dnsruby}/code_mapper.rb +48 -52
  19. data/lib/dnsruby/code_mappers.rb +295 -0
  20. data/lib/{Dnsruby/Config.rb → dnsruby/config.rb} +454 -454
  21. data/lib/{Dnsruby → dnsruby}/dnssec.rb +91 -91
  22. data/lib/{Dnsruby/Hosts.rb → dnsruby/hosts.rb} +125 -125
  23. data/lib/{Dnsruby → dnsruby}/ipv4.rb +26 -26
  24. data/lib/{Dnsruby → dnsruby}/ipv6.rb +42 -42
  25. data/lib/{Dnsruby → dnsruby}/key_cache.rb +29 -29
  26. data/lib/dnsruby/message/decoder.rb +164 -0
  27. data/lib/dnsruby/message/encoder.rb +75 -0
  28. data/lib/dnsruby/message/header.rb +249 -0
  29. data/lib/dnsruby/message/message.rb +629 -0
  30. data/lib/dnsruby/message/question.rb +86 -0
  31. data/lib/dnsruby/message/section.rb +96 -0
  32. data/lib/{Dnsruby → dnsruby}/name.rb +141 -141
  33. data/lib/dnsruby/packet_sender.rb +661 -0
  34. data/lib/{Dnsruby/Recursor.rb → dnsruby/recursor.rb} +235 -233
  35. data/lib/dnsruby/resolv.rb +113 -0
  36. data/lib/dnsruby/resolver.rb +1192 -0
  37. data/lib/dnsruby/resource/A.rb +56 -0
  38. data/lib/dnsruby/resource/AAAA.rb +54 -0
  39. data/lib/{Dnsruby → dnsruby}/resource/AFSDB.rb +68 -68
  40. data/lib/{Dnsruby → dnsruby}/resource/CERT.rb +105 -105
  41. data/lib/{Dnsruby → dnsruby}/resource/DHCID.rb +54 -54
  42. data/lib/dnsruby/resource/DLV.rb +27 -0
  43. data/lib/{Dnsruby → dnsruby}/resource/DNSKEY.rb +372 -372
  44. data/lib/{Dnsruby → dnsruby}/resource/DS.rb +255 -255
  45. data/lib/{Dnsruby → dnsruby}/resource/HINFO.rb +71 -71
  46. data/lib/{Dnsruby → dnsruby}/resource/HIP.rb +29 -29
  47. data/lib/{Dnsruby → dnsruby}/resource/IN.rb +30 -30
  48. data/lib/{Dnsruby → dnsruby}/resource/IPSECKEY.rb +31 -31
  49. data/lib/{Dnsruby → dnsruby}/resource/ISDN.rb +62 -62
  50. data/lib/{Dnsruby → dnsruby}/resource/KX.rb +65 -65
  51. data/lib/{Dnsruby → dnsruby}/resource/LOC.rb +263 -263
  52. data/lib/{Dnsruby → dnsruby}/resource/MINFO.rb +69 -69
  53. data/lib/{Dnsruby → dnsruby}/resource/MX.rb +65 -65
  54. data/lib/{Dnsruby → dnsruby}/resource/NAPTR.rb +98 -98
  55. data/lib/{Dnsruby → dnsruby}/resource/NSAP.rb +171 -171
  56. data/lib/dnsruby/resource/NSEC.rb +275 -0
  57. data/lib/dnsruby/resource/NSEC3.rb +332 -0
  58. data/lib/dnsruby/resource/NSEC3PARAM.rb +135 -0
  59. data/lib/dnsruby/resource/OPT.rb +272 -0
  60. data/lib/{Dnsruby → dnsruby}/resource/PX.rb +70 -70
  61. data/lib/{Dnsruby → dnsruby}/resource/RP.rb +75 -75
  62. data/lib/dnsruby/resource/RR.rb +421 -0
  63. data/lib/dnsruby/resource/RRSIG.rb +275 -0
  64. data/lib/dnsruby/resource/RRSet.rb +190 -0
  65. data/lib/{Dnsruby → dnsruby}/resource/RT.rb +67 -67
  66. data/lib/{Dnsruby → dnsruby}/resource/SOA.rb +94 -94
  67. data/lib/dnsruby/resource/SPF.rb +29 -0
  68. data/lib/dnsruby/resource/SRV.rb +112 -0
  69. data/lib/{Dnsruby → dnsruby}/resource/SSHFP.rb +14 -14
  70. data/lib/dnsruby/resource/TKEY.rb +163 -0
  71. data/lib/dnsruby/resource/TSIG.rb +593 -0
  72. data/lib/{Dnsruby → dnsruby}/resource/TXT.rb +191 -191
  73. data/lib/dnsruby/resource/X25.rb +55 -0
  74. data/lib/{Dnsruby → dnsruby}/resource/domain_name.rb +25 -25
  75. data/lib/{Dnsruby → dnsruby}/resource/generic.rb +80 -80
  76. data/lib/dnsruby/resource/resource.rb +25 -0
  77. data/lib/{Dnsruby → dnsruby}/select_thread.rb +148 -148
  78. data/lib/{Dnsruby/SingleResolver.rb → dnsruby/single_resolver.rb} +60 -60
  79. data/lib/{Dnsruby → dnsruby}/single_verifier.rb +344 -344
  80. data/lib/dnsruby/the_log.rb +44 -0
  81. data/lib/dnsruby/update.rb +278 -0
  82. data/lib/dnsruby/validator_thread.rb +124 -0
  83. data/lib/dnsruby/version.rb +3 -0
  84. data/lib/{Dnsruby → dnsruby}/zone_reader.rb +93 -93
  85. data/lib/{Dnsruby → dnsruby}/zone_transfer.rb +377 -377
  86. data/test/spec_helper.rb +16 -0
  87. data/test/tc_axfr.rb +31 -34
  88. data/test/tc_cache.rb +32 -32
  89. data/test/tc_dlv.rb +28 -28
  90. data/test/tc_dns.rb +73 -76
  91. data/test/tc_dnskey.rb +31 -32
  92. data/test/tc_dnsruby.rb +50 -44
  93. data/test/tc_ds.rb +36 -36
  94. data/test/tc_escapedchars.rb +252 -255
  95. data/test/tc_hash.rb +17 -21
  96. data/test/tc_header.rb +48 -57
  97. data/test/tc_hip.rb +19 -22
  98. data/test/tc_ipseckey.rb +18 -21
  99. data/test/tc_keith.rb +300 -0
  100. data/test/tc_message.rb +87 -0
  101. data/test/tc_misc.rb +83 -87
  102. data/test/tc_name.rb +81 -84
  103. data/test/tc_naptr.rb +18 -21
  104. data/test/tc_nsec.rb +55 -55
  105. data/test/tc_nsec3.rb +23 -24
  106. data/test/tc_nsec3param.rb +20 -21
  107. data/test/tc_packet.rb +90 -93
  108. data/test/tc_packet_unique_push.rb +48 -51
  109. data/test/tc_question.rb +30 -33
  110. data/test/tc_queue.rb +16 -17
  111. data/test/tc_recur.rb +16 -17
  112. data/test/tc_res_config.rb +38 -41
  113. data/test/tc_res_env.rb +29 -32
  114. data/test/tc_res_file.rb +26 -29
  115. data/test/tc_res_opt.rb +62 -65
  116. data/test/tc_resolver.rb +287 -242
  117. data/test/tc_rr-opt.rb +70 -63
  118. data/test/tc_rr-txt.rb +68 -71
  119. data/test/tc_rr-unknown.rb +45 -48
  120. data/test/tc_rr.rb +76 -70
  121. data/test/tc_rrset.rb +21 -22
  122. data/test/tc_rrsig.rb +19 -20
  123. data/test/tc_single_resolver.rb +294 -297
  124. data/test/tc_soak.rb +199 -202
  125. data/test/tc_soak_base.rb +29 -34
  126. data/test/tc_sshfp.rb +20 -23
  127. data/test/tc_tcp.rb +32 -35
  128. data/test/tc_tkey.rb +41 -44
  129. data/test/tc_tsig.rb +81 -84
  130. data/test/tc_update.rb +108 -111
  131. data/test/tc_validator.rb +29 -29
  132. data/test/tc_verifier.rb +81 -82
  133. data/test/ts_dnsruby.rb +16 -15
  134. data/test/ts_offline.rb +62 -63
  135. data/test/ts_online.rb +115 -115
  136. metadata +155 -90
  137. data/README +0 -59
  138. data/lib/Dnsruby/DNS.rb +0 -305
  139. data/lib/Dnsruby/PacketSender.rb +0 -656
  140. data/lib/Dnsruby/Resolver.rb +0 -1189
  141. data/lib/Dnsruby/TheLog.rb +0 -44
  142. data/lib/Dnsruby/message.rb +0 -1230
  143. data/lib/Dnsruby/resource/A.rb +0 -56
  144. data/lib/Dnsruby/resource/AAAA.rb +0 -54
  145. data/lib/Dnsruby/resource/DLV.rb +0 -27
  146. data/lib/Dnsruby/resource/NSEC.rb +0 -298
  147. data/lib/Dnsruby/resource/NSEC3.rb +0 -340
  148. data/lib/Dnsruby/resource/NSEC3PARAM.rb +0 -135
  149. data/lib/Dnsruby/resource/OPT.rb +0 -213
  150. data/lib/Dnsruby/resource/RRSIG.rb +0 -275
  151. data/lib/Dnsruby/resource/SPF.rb +0 -29
  152. data/lib/Dnsruby/resource/SRV.rb +0 -112
  153. data/lib/Dnsruby/resource/TKEY.rb +0 -163
  154. data/lib/Dnsruby/resource/TSIG.rb +0 -593
  155. data/lib/Dnsruby/resource/X25.rb +0 -55
  156. data/lib/Dnsruby/resource/resource.rb +0 -678
  157. data/lib/Dnsruby/update.rb +0 -278
  158. data/lib/Dnsruby/validator_thread.rb +0 -124
@@ -1,1189 +0,0 @@
1
- #--
2
- #Copyright 2007 Nominet UK
3
- #
4
- #Licensed under the Apache License, Version 2.0 (the "License");
5
- #you may not use this file except in compliance with the License.
6
- #You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- #Unless required by applicable law or agreed to in writing, software
11
- #distributed under the License is distributed on an "AS IS" BASIS,
12
- #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- #See the License for the specific language governing permissions and
14
- #limitations under the License.
15
- #++
16
- #require "Dnsruby/resolver_register.rb"
17
- require "Dnsruby/PacketSender"
18
- require "Dnsruby/Recursor"
19
- module Dnsruby
20
- #== Description
21
- #Dnsruby::Resolver is a DNS stub resolver.
22
- #This class performs queries with retries across multiple nameservers.
23
- #The system configured resolvers are used by default.
24
- #
25
- #The retry policy is a combination of the Net::DNS and dnsjava approach, and has the option of :
26
- #* A total timeout for the query (defaults to 0, meaning "no total timeout")
27
- #* A retransmission system that targets the namervers concurrently once the first query round is
28
- # complete, but in which the total time per query round is split between the number of nameservers
29
- # targetted for the first round. and total time for query round is doubled for each query round
30
- #
31
- # Note that, if a total timeout is specified, then that will apply regardless of the retry policy
32
- #(i.e. it may cut retries short).
33
- #
34
- # Note also that these timeouts are distinct from the SingleResolver's packet_timeout
35
- #
36
- # Timeouts apply to the initial query and response. If DNSSEC validation is to
37
- # be performed, then additional queries may be required (these are performed automatically
38
- # by Dnsruby). Each additional query will be performed with its own timeouts.
39
- # So, even with a query_timeout of 5 seconds, a response which required extensive
40
- # validation may take several times that long.
41
- # (Future versions of Dnsruby may expose finer-grained events for client tracking of
42
- # responses and validation)
43
- #
44
- #== Methods
45
- #
46
- #=== Synchronous
47
- #These methods raise an exception or return a response message with rcode==NOERROR
48
- #
49
- #* Dnsruby::Resolver#send_message(msg)
50
- #* Dnsruby::Resolver#query(name [, type [, klass]])
51
- #
52
- #=== Asynchronous
53
- #These methods use a response queue to return the response and the error
54
- #
55
- #* Dnsruby::Resolver#send_async(msg, response_queue, query_id)
56
- #
57
- #== Event Loop
58
- #Dnsruby runs a pure Ruby event loop to handle I/O in a single thread.
59
- #Support for EventMachine has been deprecated.
60
- class Resolver
61
- DefaultQueryTimeout = 0
62
- DefaultPacketTimeout = 5
63
- DefaultRetryTimes = 1
64
- DefaultRetryDelay = 5
65
- DefaultPort = 53
66
- DefaultDnssec = true
67
- AbsoluteMinDnssecUdpSize = 1220
68
- MinDnssecUdpSize = 4096
69
- DefaultUDPSize = MinDnssecUdpSize
70
-
71
- class EventType
72
- RECEIVED = 0
73
- VALIDATED = 1 # @TODO@ Should be COMPLETE?
74
- ERROR = 2
75
- end
76
-
77
- # The port to send queries to on the resolver
78
- attr_reader :port
79
-
80
- # Should TCP be used as a transport rather than UDP?
81
- # If use_tcp==true, then ONLY TCP will be used as a transport.
82
- attr_reader :use_tcp
83
-
84
- # If no_tcp==true, then ONLY UDP will be used as a transport.
85
- # This should not generally be used, but is provided as a debugging aid.
86
- attr_reader :no_tcp
87
-
88
-
89
- attr_reader :tsig
90
-
91
- # Should truncation be ignored?
92
- # i.e. the TC bit is ignored and thus the resolver will not requery over TCP if TC is set
93
- attr_reader :ignore_truncation
94
-
95
- # The source address to send queries from for IPv4
96
- attr_reader :src_address
97
-
98
- # The source address to send queries from for IPv6
99
- attr_reader :src_address6
100
-
101
- # Should the Recursion Desired bit be set?
102
- attr_reader :recurse
103
-
104
- # The maximum UDP size to be used
105
- attr_reader :udp_size
106
-
107
- # The current Config
108
- attr_reader :config
109
-
110
- # Does this Resolver cache answers, and attempt to retrieve answer from the cache?
111
- attr_reader :do_caching
112
-
113
- # The array of SingleResolvers used for sending query messages
114
- # attr_accessor :single_resolvers # :nodoc:
115
- def single_resolvers=(s) # :nodoc:
116
- @configured = true
117
- # @single_res_mutex.synchronize {
118
- @single_resolvers = s
119
- # }
120
- end
121
- def single_resolvers # :nodoc:
122
- if (!@configured)
123
- add_config_nameservers
124
- end
125
- return @single_resolvers
126
- end
127
-
128
- #The timeout for any individual packet. This is the timeout used by SingleResolver
129
- attr_reader :packet_timeout
130
-
131
- # Note that this timeout represents the total time a query may run for - multiple packets
132
- # can be sent to multiple nameservers in this time.
133
- # This is distinct from the SingleResolver per-packet timeout
134
- # The query_timeout is not required - it will default to 0, which means "do not use query_timeout".
135
- # If this is the case then the timeout will be dictated by the retry_times and retry_delay attributes
136
- attr_accessor :query_timeout
137
-
138
- # The query will be tried across nameservers retry_times times, with a delay of retry_delay seconds
139
- # between each retry. The first time round, retry_delay will be divided by the number of nameservers
140
- # being targetted, and a new nameserver will be queried with the resultant delay.
141
- attr_accessor :retry_times, :retry_delay
142
-
143
- # Use DNSSEC for this Resolver
144
- attr_reader :dnssec
145
-
146
- # Defines whether validation is performed by default on this Resolver when the
147
- # query method is called.
148
- # Note that send_message and send_async expect a
149
- # Message object to be passed in, which is already configured to the callers
150
- # requirements.
151
- attr_accessor :do_validation
152
-
153
- # Defines whether we will cache responses, or pass every request to the
154
- # upstream resolver. This is only really useful when querying authoritative
155
- # servers (as the upstream recursive resolver is likely to cache)
156
- attr_accessor :do_caching
157
-
158
- #--
159
- #@TODO@ add load_balance? i.e. Target nameservers in a random, rather than pre-determined, order?
160
- #This is best done when configuring the Resolver, as it will re-order servers based on their response times.
161
- #
162
- #++
163
-
164
- # Query for a name. If a valid Message is received, then it is returned
165
- # to the caller. Otherwise an exception (a Dnsruby::ResolvError or Dnsruby::ResolvTimeout) is raised.
166
- #
167
- # require 'Dnsruby'
168
- # res = Dnsruby::Resolver.new
169
- # response = res.query("example.com") # defaults to Types.A, Classes.IN
170
- # response = res.query("example.com", Types.MX)
171
- # response = res.query("208.77.188.166") # IPv4 address so PTR query will be made
172
- # response = res.query("208.77.188.166", Types.PTR)
173
- def query(name, type=Types.A, klass=Classes.IN, set_cd=@dnssec)
174
- msg = Message.new
175
- msg.do_caching = @do_caching
176
- msg.header.rd = 1
177
- msg.add_question(name, type, klass)
178
- msg.do_validation = @do_validation
179
- if (@dnssec)
180
- msg.header.cd = set_cd # We do our own validation by default
181
- end
182
- return send_message(msg)
183
- end
184
-
185
- def query_no_validation_or_recursion(name, type=Types.A, klass=Classes.IN) # :nodoc: all
186
- msg = Message.new
187
- msg.do_caching = @do_caching
188
- msg.header.rd = false
189
- msg.do_validation = false
190
- msg.add_question(name, type, klass)
191
- if (@dnssec)
192
- msg.header.cd = true # We do our own validation by default
193
- end
194
- return send_message(msg)
195
- end
196
-
197
- # Send a message, and wait for the response. If a valid Message is received, then it is returned
198
- # to the caller. Otherwise an exception (a Dnsruby::ResolvError or Dnsruby::ResolvTimeout) is raised.
199
- #
200
- # send_async is called internally.
201
- #
202
- # example :
203
- #
204
- # require 'dnsruby'
205
- # include Dnsruby
206
- # res = Dnsruby::Resolver.new
207
- # begin
208
- # response = res.send_message(Message.new("example.com", Types.MX))
209
- # rescue ResolvError
210
- # # ...
211
- # rescue ResolvTimeout
212
- # # ...
213
- # end
214
- def send_message(message)
215
- Dnsruby.log.debug{"Resolver : sending message"}
216
- q = Queue.new
217
- send_async(message, q)
218
- # # @TODO@ Add new queue tuples, e.g. :
219
- # event_type = EventType::RECEIVED
220
- # reply = nil
221
- # while (event_type == EventType::RECEIVED)
222
- # id, event_type, reply, error = q.pop
223
- # Dnsruby.log.debug{"Resolver : result received"}
224
- # if ((error != nil) && (event_type == EventType::ERROR))
225
- # raise error
226
- # end
227
- # print "Reply = #{reply}\n"
228
- # end
229
- # print "Reply = #{reply}\n"
230
- # return reply
231
-
232
- id, result, error = q.pop
233
-
234
- if (error != nil)
235
- raise error
236
- else
237
- return result
238
- end
239
- end
240
-
241
- # This method takes a Message (supplied by the client), and sends it to
242
- # the configured nameservers. No changes are made to the Message before it
243
- # is sent (TSIG signatures will be applied if configured on the Resolver).
244
- # Retries are handled as the Resolver is configured to do.
245
- # Incoming responses to the query are not cached or validated (although TCP
246
- # fallback will be performed if the TC bit is set and the (Single)Resolver has
247
- # ignore_truncation set to false).
248
- # Note that the Message is left untouched - this means that no OPT records are
249
- # added, even if the UDP transport for the server is specified at more than 512
250
- # bytes. If it is desired to use EDNS for this packet, then you should call
251
- # the Dnsruby::PacketSender#prepare_for_dnssec(msg), or
252
- # Dnsruby::PacketSender#add_opt_rr(msg)
253
- # The return value from this method is the [response, error] tuple. Either of
254
- # these values may be nil - it is up to the client to check.
255
- #
256
- # example :
257
- #
258
- # require 'dnsruby'
259
- # include Dnsruby
260
- # res = Dnsruby::Resolver.new
261
- # response, error = res.send_plain_message(Message.new("example.com", Types.MX))
262
- # if (error)
263
- # print "Error returned : #{error}\n"
264
- # else
265
- # process_response(response)
266
- # end
267
- def send_plain_message(message)
268
- Dnsruby::TheLog.debug("Resolver : send_plain_message")
269
- message.do_caching = false
270
- message.do_validation = false
271
- message.send_raw = true
272
- q = Queue.new
273
- send_async(message, q)
274
- id, result, error = q.pop
275
- return [result, error]
276
- end
277
-
278
-
279
- #Asynchronously send a Message to the server. The send can be done using just
280
- #Dnsruby. Support for EventMachine has been deprecated.
281
- #
282
- #== Dnsruby pure Ruby event loop :
283
- #
284
- #A client_queue is supplied by the client,
285
- #along with an optional client_query_id to identify the response. The client_query_id
286
- #is generated, if not supplied, and returned to the client.
287
- #When the response is known,
288
- #a tuple of (query_id, response_message, exception) will be added to the client_queue.
289
- #
290
- #The query is sent synchronously in the caller's thread. The select thread is then used to
291
- #listen for and process the response (up to pushing it to the client_queue). The client thread
292
- #is then used to retrieve the response and deal with it.
293
- #
294
- #Takes :
295
- #
296
- #* msg - the message to send
297
- #* client_queue - a Queue to push the response to, when it arrives
298
- #* client_query_id - an optional ID to identify the query to the client
299
- #* use_tcp - whether to use only TCP (defaults to SingleResolver.use_tcp)
300
- #
301
- #Returns :
302
- #
303
- #* client_query_id - to identify the query response to the client. This ID is
304
- #generated if it is not passed in by the client
305
- #
306
- #=== Example invocations :
307
- #
308
- # id = res.send_async(msg, queue)
309
- # NOT SUPPORTED : id = res.send_async(msg, queue, use_tcp)
310
- # id = res.send_async(msg, queue, id)
311
- # id = res.send_async(msg, queue, id, use_tcp)
312
- #
313
- #=== Example code :
314
- #
315
- # require 'Dnsruby'
316
- # res = Dnsruby::Resolver.newsend
317
- # query_id = 10 # can be any object you like
318
- # query_queue = Queue.new
319
- # res.send_async(Message.new("example.com", Types.MX), query_queue, query_id)
320
- # query_id_2 = res.send_async(Message.new("example.com", Types.A), query_queue)
321
- # # ...do a load of other stuff here...
322
- # 2.times do
323
- # response_id, response, exception = query_queue.pop
324
- # # You can check the ID to see which query has been answered
325
- # if (exception == nil)
326
- # # deal with good response
327
- # else
328
- # # deal with problem
329
- # end
330
- # end
331
- #
332
- def send_async(msg, client_queue, client_query_id = nil)
333
- if (!@configured)
334
- add_config_nameservers
335
- end
336
- # @single_res_mutex.synchronize {
337
- if (!@resolver_ruby) # @TODO@ Synchronize this?
338
- @resolver_ruby = ResolverRuby.new(self)
339
- end
340
- # }
341
- client_query_id = @resolver_ruby.send_async(msg, client_queue, client_query_id)
342
- if (@single_resolvers.length == 0)
343
- Thread.start {
344
- sleep(@query_timeout == 0 ? 1 : @query_timeout)
345
- client_queue.push([client_query_id, nil, ResolvTimeout.new("Query timed out - no nameservers configured")])
346
- }
347
- end
348
- return client_query_id
349
- end
350
-
351
- # Close the Resolver. Unfinished queries are terminated with OtherResolvError.
352
- def close
353
- @resolver_ruby.close if @resolver_ruby
354
- end
355
-
356
- # Create a new Resolver object. If no parameters are passed in, then the default
357
- # system configuration will be used. Otherwise, a Hash may be passed in with the
358
- # following optional elements :
359
- #
360
- #
361
- # * :port
362
- # * :use_tcp
363
- # * :tsig
364
- # * :ignore_truncation
365
- # * :src_address
366
- # * :src_address6
367
- # * :src_port
368
- # * :recurse
369
- # * :udp_size
370
- # * :config_info - see Config
371
- # * :nameserver - can be either a String or an array of Strings
372
- # * :packet_timeout
373
- # * :query_timeout
374
- # * :retry_times
375
- # * :retry_delay
376
- # * :do_caching
377
- def initialize(*args)
378
- # @TODO@ Should we allow :namesver to be an RRSet of NS records? Would then need to randomly order them?
379
- @resolver_ruby = nil
380
- @src_address = nil
381
- @src_address6 = nil
382
- @single_res_mutex = Mutex.new
383
- @configured = false
384
- @do_caching = true
385
- @config = Config.new()
386
- reset_attributes
387
-
388
- # Process args
389
- if (args.length==1)
390
- if (args[0].class == Hash)
391
- args[0].keys.each do |key|
392
- begin
393
- if (key == :config_info)
394
- @config.set_config_info(args[0][:config_info])
395
- elsif (key==:nameserver)
396
- set_config_nameserver(args[0][:nameserver])
397
- elsif (key==:nameservers)
398
- set_config_nameserver(args[0][:nameservers])
399
- else
400
- send(key.to_s+"=", args[0][key])
401
- end
402
- rescue Exception => e
403
- Dnsruby.log.error{"Argument #{key} not valid : #{e}\n"}
404
- end
405
- end
406
- elsif (args[0].class == String)
407
- set_config_nameserver(args[0])
408
- elsif (args[0].class == Config)
409
- # also accepts a Config object from Dnsruby::Resolv
410
- @config = args[0]
411
- end
412
- else
413
- # Anything to do?
414
- end
415
- # if (@single_resolvers==[])
416
- # add_config_nameservers
417
- # end
418
- update
419
- # ResolverRegister::register_resolver(self)
420
- end
421
-
422
- def add_config_nameservers # :nodoc: all
423
- if (!@configured)
424
- @config.get_ready
425
- end
426
- @configured = true
427
- @single_res_mutex.synchronize {
428
- # Add the Config nameservers
429
- @config.nameserver.each do |ns|
430
- res = PacketSender.new({:server=>ns, :dnssec=>@dnssec,
431
- :use_tcp=>@use_tcp, :no_tcp=>@no_tcp, :packet_timeout=>@packet_timeout,
432
- :tsig => @tsig, :ignore_truncation=>@ignore_truncation,
433
- :src_address=>@src_address, :src_address6=>@src_address6, :src_port=>@src_port,
434
- :recurse=>@recurse, :udp_size=>@udp_size})
435
- @single_resolvers.push(res) if res
436
- end
437
- }
438
- end
439
-
440
- def set_config_nameserver(n)
441
- # @TODO@ Should we allow NS RRSet here? If so, then .sort_by {rand}
442
- if (!@configured)
443
- @config.get_ready
444
- end
445
- @configured = true
446
- if (n).kind_of?String
447
- @config.nameserver=[n]
448
- else
449
- @config.nameserver=n
450
- end
451
- add_config_nameservers
452
- end
453
-
454
- def reset_attributes #:nodoc: all
455
- if (@resolver_ruby)
456
- @resolver_ruby.reset_attributes
457
- end
458
-
459
- # Attributes
460
-
461
- # do_validation tells the Resolver whether to try to validate the response
462
- # with DNSSEC. This should work for NSEC-signed domains, but NSEC3
463
- # validation is not currently supported. This attribute now defaults to
464
- # false. Please let me know if you require NSEC3 validation.
465
- @do_validation = false
466
- @query_timeout = DefaultQueryTimeout
467
- @retry_delay = DefaultRetryDelay
468
- @retry_times = DefaultRetryTimes
469
- @packet_timeout = DefaultPacketTimeout
470
- @port = DefaultPort
471
- @udp_size = DefaultUDPSize
472
- @dnssec = DefaultDnssec
473
- @do_caching= true
474
- @use_tcp = false
475
- @no_tcp = false
476
- @tsig = nil
477
- @ignore_truncation = false
478
- @config = Config.new()
479
- @src_address = nil
480
- @src_address6 = nil
481
- @src_port = [0]
482
- @recurse = true
483
- @single_res_mutex.synchronize {
484
- @single_resolvers=[]
485
- }
486
- @configured = false
487
- end
488
-
489
- def update #:nodoc: all
490
- #Update any resolvers we have with the latest config
491
- @single_res_mutex.synchronize {
492
- @single_resolvers.delete(nil) # Just in case...
493
- @single_resolvers.each do |res|
494
- update_internal_res(res)
495
- end
496
- }
497
- end
498
-
499
- # # Add a new SingleResolver to the list of resolvers this Resolver object will
500
- # # query.
501
- # def add_resolver(internal) # :nodoc:
502
- # # @TODO@ Make a new PacketSender from this SingleResolver!!
503
- # @single_resolvers.push(internal)
504
- # end
505
-
506
- def add_server(server)# :nodoc:
507
- @configured = true
508
- res = PacketSender.new(server)
509
- raise ArgumentError.new("Can't create server #{server}") if !res
510
- update_internal_res(res)
511
- @single_res_mutex.synchronize {
512
- @single_resolvers.push(res)
513
- }
514
- end
515
-
516
- def update_internal_res(res)
517
- [:port, :use_tcp, :no_tcp, :tsig, :ignore_truncation, :packet_timeout,
518
- :src_address, :src_address6, :src_port, :recurse,
519
- :udp_size, :dnssec].each do |param|
520
-
521
- res.send(param.to_s+"=", instance_variable_get("@"+param.to_s))
522
- end
523
- end
524
-
525
- def nameservers=(ns)
526
- self.nameserver=(ns)
527
- end
528
- def nameserver=(n)
529
- @configured = true
530
- @single_res_mutex.synchronize {
531
- @single_resolvers=[]
532
- }
533
- set_config_nameserver(n)
534
- add_config_nameservers
535
- end
536
-
537
- #--
538
- #@TODO@ Should really auto-generate these methods.
539
- #Also, any way to tie them up with SingleResolver RDoc?
540
- #++
541
-
542
- def packet_timeout=(t)
543
- @packet_timeout = t
544
- update
545
- end
546
-
547
- # The source port to send queries from
548
- # Returns either a single Fixnum or an Array
549
- # e.g. "0", or "[60001, 60002, 60007]"
550
- #
551
- # Defaults to 0 - random port
552
- def src_port
553
- if (@src_port.length == 1)
554
- return @src_port[0]
555
- end
556
- return @src_port
557
- end
558
-
559
- # Can be a single Fixnum or a Range or an Array
560
- # If an invalid port is selected (one reserved by
561
- # IANA), then an ArgumentError will be raised.
562
- #
563
- # res.src_port=0
564
- # res.src_port=[60001,60005,60010]
565
- # res.src_port=60015..60115
566
- #
567
- def src_port=(p)
568
- if (Resolver.check_port(p))
569
- @src_port = Resolver.get_ports_from(p)
570
- update
571
- end
572
- end
573
-
574
- # Can be a single Fixnum or a Range or an Array
575
- # If an invalid port is selected (one reserved by
576
- # IANA), then an ArgumentError will be raised.
577
- # "0" means "any valid port" - this is only a viable
578
- # option if it is the only port in the list.
579
- # An ArgumentError will be raised if "0" is added to
580
- # an existing set of source ports.
581
- #
582
- # res.add_src_port(60000)
583
- # res.add_src_port([60001,60005,60010])
584
- # res.add_src_port(60015..60115)
585
- #
586
- def add_src_port(p)
587
- if (Resolver.check_port(p, @src_port))
588
- a = Resolver.get_ports_from(p)
589
- a.each do |x|
590
- if ((@src_port.length > 0) && (x == 0))
591
- raise ArgumentError.new("src_port of 0 only allowed as only src_port value (currently #{@src_port.length} values")
592
- end
593
- @src_port.push(x)
594
- end
595
- end
596
- update
597
- end
598
-
599
- def Resolver.check_port(p, src_port=[])
600
- if (p.class != Fixnum)
601
- tmp_src_ports = Array.new(src_port)
602
- p.each do |x|
603
- if (!Resolver.check_port(x, tmp_src_ports))
604
- return false
605
- end
606
- tmp_src_ports.push(x)
607
- end
608
- return true
609
- end
610
- if (Resolver.port_in_range(p))
611
- if ((p == 0) && (src_port.length > 0))
612
- return false
613
- end
614
- return true
615
- else
616
- Dnsruby.log.error("Illegal port (#{p})")
617
- raise ArgumentError.new("Illegal port #{p}")
618
- end
619
- end
620
-
621
- def Resolver.port_in_range(p)
622
- if ((p == 0) || ((p >= 50000) && (p <= 65535)))
623
- # @TODO@ IANA port bitmap - use 50000 - 65535 for now
624
- # ((Iana::IANA_PORTS.index(p)) == nil &&
625
- # (p > 1024) && (p < 65535)))
626
- return true
627
- end
628
- return false
629
- end
630
-
631
- def Resolver.get_ports_from(p)
632
- a = []
633
- if (p.class == Fixnum)
634
- a = [p]
635
- else
636
- p.each do |x|
637
- a.push(x)
638
- end
639
- end
640
- return a
641
- end
642
-
643
- def use_tcp=(on)
644
- @use_tcp = on
645
- update
646
- end
647
-
648
- def no_tcp=(on)
649
- @no_tcp=on
650
- update
651
- end
652
-
653
- #Sets the TSIG to sign outgoing messages with.
654
- #Pass in either a Dnsruby::RR::TSIG, or a key_name and key (or just a key)
655
- #Pass in nil to stop tsig signing.
656
- #* res.tsig=(tsig_rr)
657
- #* res.tsig=(key_name, key) # defaults to hmac-md5
658
- #* res.tsig=(key_name, key, alg) # e.g. alg = "hmac-sha1"
659
- #* res.tsig=nil # Stop the resolver from signing
660
- def tsig=(t)
661
- @tsig=t
662
- update
663
- end
664
-
665
- def Resolver.get_tsig(args)
666
- tsig = nil
667
- if (args.length == 1)
668
- if (args[0])
669
- if (args[0].instance_of?RR::TSIG)
670
- tsig = args[0]
671
- elsif (args[0].instance_of?Array)
672
- if (args[0].length > 2)
673
- tsig = RR.new_from_hash({:type => Types.TSIG, :klass => Classes.ANY, :name => args[0][0], :key => args[0][1], :algorithm => args[0][2]})
674
- else
675
- tsig = RR.new_from_hash({:type => Types.TSIG, :klass => Classes.ANY, :name => args[0][0], :key => args[0][1]})
676
- end
677
- end
678
- else
679
- # Dnsruby.log.debug{"TSIG signing switched off"}
680
- return nil
681
- end
682
- elsif (args.length ==2)
683
- tsig = RR.new_from_hash({:type => Types.TSIG, :klass => Classes.ANY, :name => args[0], :key => args[1]})
684
- elsif (args.length ==3)
685
- tsig = RR.new_from_hash({:type => Types.TSIG, :klass => Classes.ANY, :name => args[0], :key => args[1], :algorithm => args[2]})
686
- else
687
- raise ArgumentError.new("Wrong number of arguments to tsig=")
688
- end
689
- Dnsruby.log.info{"TSIG signing now using #{tsig.name}, key=#{tsig.key}"}
690
- return tsig
691
- end
692
-
693
-
694
- def ignore_truncation=(on)
695
- @ignore_truncation = on
696
- update
697
- end
698
-
699
- def src_address=(a)
700
- @src_address = a
701
- update
702
- end
703
-
704
- def src_address6=(a)
705
- @src_address6 = a
706
- update
707
- end
708
-
709
- def port=(a)
710
- @port = a
711
- update
712
- end
713
-
714
- def persistent_tcp=(on)
715
- @persistent_tcp = on
716
- update
717
- end
718
-
719
- def persistent_udp=(on)
720
- @persistent_udp = on
721
- update
722
- end
723
-
724
- def do_caching=(on)
725
- @do_caching=on
726
- update
727
- end
728
-
729
- def recurse=(a)
730
- @recurse = a
731
- update
732
- end
733
-
734
- def dnssec=(d)
735
- @dnssec = d
736
- if (d)
737
- # Set the UDP size (RFC 4035 section 4.1)
738
- if (@udp_size < MinDnssecUdpSize)
739
- self.udp_size = MinDnssecUdpSize
740
- end
741
- end
742
- update
743
- end
744
-
745
- def udp_size=(s)
746
- @udp_size = s
747
- update
748
- end
749
-
750
- def single_res_mutex # :nodoc: all
751
- return @single_res_mutex
752
- end
753
-
754
- def generate_timeouts(base=0) #:nodoc: all
755
- #These should be be pegged to the single_resolver they are targetting :
756
- # e.g. timeouts[timeout1]=nameserver
757
- timeouts = {}
758
- retry_delay = @retry_delay
759
- # @single_res_mutex.synchronize {
760
- @retry_times.times do |retry_count|
761
- if (retry_count>0)
762
- retry_delay *= 2
763
- end
764
-
765
- @single_resolvers.delete(nil) # Just in case...
766
- @single_resolvers.each_index do |i|
767
- res= @single_resolvers[i]
768
- offset = (i*@retry_delay.to_f/@single_resolvers.length)
769
- if (retry_count==0)
770
- timeouts[base+offset]=[res, retry_count]
771
- else
772
- if (timeouts.has_key?(base+retry_delay+offset))
773
- Dnsruby.log.error{"Duplicate timeout key!"}
774
- raise RuntimeError.new("Duplicate timeout key!")
775
- end
776
- timeouts[base+retry_delay+offset]=[res, retry_count]
777
- end
778
- end
779
- end
780
- # }
781
- return timeouts
782
- end
783
- end
784
-
785
-
786
- # This class implements the I/O using pure Ruby, with no dependencies.
787
- # Support for EventMachine has been deprecated.
788
- class ResolverRuby #:nodoc: all
789
- def initialize(parent)
790
- reset_attributes
791
- @parent=parent
792
- end
793
- def reset_attributes #:nodoc: all
794
- # data structures
795
- # @mutex=Mutex.new
796
- @query_list = {}
797
- @timeouts = {}
798
- end
799
- def send_async(msg, client_queue, client_query_id=nil)
800
- # This is the whole point of the Resolver class.
801
- # We want to use multiple SingleResolvers to run a query.
802
- # So we kick off a system with select_thread where we send
803
- # a query with a queue, but log ourselves as observers for that
804
- # queue. When a new response is pushed on to the queue, then the
805
- # select thread will call this class' handler method IN THAT THREAD.
806
- # When the final response is known, this class then sticks it in
807
- # to the client queue.
808
-
809
- q = Queue.new
810
- if (client_query_id==nil)
811
- client_query_id = Time.now + rand(10000)
812
- end
813
-
814
- if (!client_queue.kind_of?Queue)
815
- Dnsruby.log.error{"Wrong type for client_queue in Resolver#send_async"}
816
- # @TODO@ Handle different queue tuples - push this to generic send_error method
817
- client_queue.push([client_query_id, ArgumentError.new("Wrong type of client_queue passed to Dnsruby::Resolver#send_async - should have been Queue, was #{client_queue.class}")])
818
- return
819
- end
820
-
821
- if (!msg.kind_of?Message)
822
- Dnsruby.log.error{"Wrong type for msg in Resolver#send_async"}
823
- # @TODO@ Handle different queue tuples - push this to generic send_error method
824
- client_queue.push([client_query_id, ArgumentError.new("Wrong type of msg passed to Dnsruby::Resolver#send_async - should have been Message, was #{msg.class}")])
825
- return
826
- end
827
-
828
- tick_needed=false
829
- # add to our data structures
830
- # @mutex.synchronize{
831
- @parent.single_res_mutex.synchronize {
832
- tick_needed = true if @query_list.empty?
833
- if (@query_list.has_key?client_query_id)
834
- Dnsruby.log.error{"Duplicate query id requested (#{client_query_id}"}
835
- # @TODO@ Handle different queue tuples - push this to generic send_error method
836
- client_queue.push([client_query_id, ArgumentError.new("Client query ID already in use")])
837
- return
838
- end
839
- outstanding = []
840
- @query_list[client_query_id]=[msg, client_queue, q, outstanding]
841
-
842
- query_timeout = Time.now+@parent.query_timeout
843
- if (@parent.query_timeout == 0)
844
- query_timeout = Time.now+31536000 # a year from now
845
- end
846
- @timeouts[client_query_id]=[query_timeout, generate_timeouts()]
847
- }
848
-
849
- # Now do querying stuff using SingleResolver
850
- # All this will be handled by the tick method (if we have 0 as the first timeout)
851
- st = SelectThread.instance
852
- st.add_observer(q, self)
853
- tick if tick_needed
854
- return client_query_id
855
- end
856
-
857
- def generate_timeouts() #:nodoc: all
858
- # Create the timeouts for the query from the retry_times and retry_delay attributes.
859
- # These are created at the same time in case the parameters change during the life of the query.
860
- #
861
- # These should be absolute, rather than relative
862
- # The first value should be Time.now[
863
- time_now = Time.now
864
- timeouts=@parent.generate_timeouts(time_now)
865
- return timeouts
866
- end
867
-
868
- # Close the Resolver. Unfinished queries are terminated with OtherResolvError.
869
- def close
870
- # @mutex.synchronize {
871
- @parent.single_res_mutex.synchronize {
872
- @query_list.each do |client_query_id, values|
873
- msg, client_queue, q, outstanding = values
874
- send_result_and_stop_querying(client_queue, client_query_id, q, nil, OtherResolvError.new("Resolver closing!"))
875
- end
876
- }
877
- end
878
-
879
- # MUST BE CALLED IN A SYNCHRONIZED BLOCK!
880
- #
881
- # Send the result back to the client, and close the socket for that query by removing
882
- # the query from the select thread.
883
- def send_result_and_stop_querying(client_queue, client_query_id, select_queue, msg, error) #:nodoc: all
884
- stop_querying(client_query_id)
885
- send_result(client_queue, client_query_id, select_queue, msg, error)
886
- end
887
-
888
- # MUST BE CALLED IN A SYNCHRONIZED BLOCK!
889
- #
890
- # Stops send any more packets for a client-level query
891
- def stop_querying(client_query_id) #:nodoc: all
892
- @timeouts.delete(client_query_id)
893
- end
894
-
895
- # MUST BE CALLED IN A SYNCHRONIZED BLOCK!
896
- #
897
- # Sends the result to the client's queue, and removes the queue observer from the select thread
898
- def send_result(client_queue, client_query_id, select_queue, msg, error) #:nodoc: all
899
- stop_querying(client_query_id) # @TODO@ !
900
- # We might still get some callbacks, which we should ignore
901
- st = SelectThread.instance
902
- st.remove_observer(select_queue, self)
903
- # @mutex.synchronize{
904
- # Remove the query from all of the data structures
905
- @query_list.delete(client_query_id)
906
- # }
907
- # Return the response to the client
908
- if (error != nil)
909
- # client_queue.push([client_query_id, Resolver::EventType::ERROR, msg, error])
910
- client_queue.push([client_query_id, msg, error])
911
- else
912
- # client_queue.push([client_query_id, Resolver::EventType::VALIDATED, msg, error])
913
- client_queue.push([client_query_id, msg, error])
914
- end
915
- end
916
-
917
- # This method is called twice a second from the select loop, in the select thread.
918
- # It should arguably be called from another worker thread... (which also handles the queue)
919
- # Each tick, we check if any timeouts have occurred. If so, we take the appropriate action :
920
- # Return a timeout to the client, or send a new query
921
- def tick #:nodoc: all
922
- # Handle the tick
923
- # Do we have any retries due to be sent yet?
924
- # @mutex.synchronize{
925
- @parent.single_res_mutex.synchronize {
926
- time_now = Time.now
927
- @timeouts.keys.each do |client_query_id|
928
- msg, client_queue, select_queue, outstanding = @query_list[client_query_id]
929
- query_timeout, timeouts = @timeouts[client_query_id]
930
- if (query_timeout < Time.now)
931
- #Time the query out
932
- send_result_and_stop_querying(client_queue, client_query_id, select_queue, nil, ResolvTimeout.new("Query timed out"))
933
- next
934
- end
935
- timeouts_done = []
936
- timeouts.keys.sort.each do |timeout|
937
- if (timeout < time_now)
938
- # Send the next query
939
- res, retry_count = timeouts[timeout]
940
- id = [res, msg, client_query_id, retry_count]
941
- Dnsruby.log.debug{"Sending msg to #{res.server}"}
942
- # We should keep a list of the queries which are outstanding
943
- outstanding.push(id)
944
- timeouts_done.push(timeout)
945
- timeouts.delete(timeout)
946
-
947
- # Pick a new QID here @TODO@ !!!
948
- # msg.header.id = rand(65535);
949
- # print "New query : #{new_msg}\n"
950
- res.send_async(msg, select_queue, id)
951
- else
952
- break
953
- end
954
- end
955
- timeouts_done.each do |t|
956
- timeouts.delete(t)
957
- end
958
- end
959
- }
960
- end
961
-
962
- # This method is called by the SelectThread (in the select thread) when the queue has a new item on it.
963
- # The queue interface is used to separate producer/consumer threads, but we're using it here in one thread.
964
- # It's probably a good idea to create a new "worker thread" to take items from the select thread queue and
965
- # call this method in the worker thread.
966
- #
967
- def handle_queue_event(queue, id) #:nodoc: all
968
- # Time to process a new queue event.
969
- # If we get a callback for an ID we don't know about, don't worry -
970
- # just ignore it. It may be for a query we've already completed.
971
- #
972
- # So, get the next response from the queue (presuming there is one!)
973
- #
974
- # @TODO@ Tick could poll the queue and then call this method if needed - no need for observer interface.
975
- # @TODO@ Currently, tick and handle_queue_event called from select_thread - could have thread chuck events in to tick_queue. But then, clients would have to call in on other thread!
976
- #
977
- # So - two types of response :
978
- # 1) we've got a coherent response (or error) - stop sending more packets for that query!
979
- # 2) we've validated the response - it's ready to be sent to the client
980
- #
981
- # so need two more methods :
982
- # handleValidationResponse : basically calls send_result_and_stop_querying and
983
- # handleValidationError : does the same as handleValidationResponse, but for errors
984
- # can leave handleError alone
985
- # but need to change handleResponse to stop sending, rather than send_result_and_stop_querying.
986
- #
987
- # @TODO@ Also, we could really do with a MaxValidationTimeout - if validation not OK within
988
- # this time, then raise Timeout (and stop validation)?
989
- #
990
- # @TODO@ Also, should there be some facility to stop validator following same chain
991
- # concurrently?
992
- #
993
- # @TODO@ Also, should have option to speak only to configured resolvers (not follow authoritative chain)
994
- #
995
- if (queue.empty?)
996
- Dnsruby.log.fatal{"Queue empty in handle_queue_event!"}
997
- raise RuntimeError.new("Severe internal error - Queue empty in handle_queue_event")
998
- end
999
- event_id, event_type, response, error = queue.pop
1000
- # We should remove this packet from the list of outstanding packets for this query
1001
- resolver, msg, client_query_id, retry_count = id
1002
- if (id != event_id)
1003
- Dnsruby.log.error{"Serious internal error!! #{id} expected, #{event_id} received"}
1004
- raise RuntimeError.new("Serious internal error!! #{id} expected, #{event_id} received")
1005
- end
1006
- # @mutex.synchronize{
1007
- @parent.single_res_mutex.synchronize {
1008
- if (@query_list[client_query_id]==nil)
1009
- # print "Dead query response - ignoring\n"
1010
- Dnsruby.log.debug{"Ignoring response for dead query"}
1011
- return
1012
- end
1013
- msg, client_queue, select_queue, outstanding = @query_list[client_query_id]
1014
- if (event_type == Resolver::EventType::RECEIVED ||
1015
- event_type == Resolver::EventType::ERROR)
1016
- if (!outstanding.include?id)
1017
- Dnsruby.log.error{"Query id not on outstanding list! #{outstanding.length} items. #{id} not on #{outstanding}"}
1018
- # raise RuntimeError.new("Query id not on outstanding!")
1019
- end
1020
- outstanding.delete(id)
1021
- end
1022
- # }
1023
- if (event_type == Resolver::EventType::RECEIVED)
1024
- # if (event.kind_of?(Exception))
1025
- if (error != nil)
1026
- handle_error_response(queue, event_id, error, response)
1027
- else # if (event.kind_of?(Message))
1028
- handle_response(queue, event_id, response)
1029
- # else
1030
- # Dnsruby.log.error("Random object #{event.class} returned through queue to Resolver")
1031
- end
1032
- elsif (event_type == Resolver::EventType::VALIDATED)
1033
- if (error != nil)
1034
- handle_validation_error(queue, event_id, error, response)
1035
- else
1036
- handle_validation_response(queue, event_id, response)
1037
- end
1038
- elsif (event_type == Resolver::EventType::ERROR)
1039
- handle_error_response(queue, event_id, error, response)
1040
- else
1041
- # print "ERROR - UNKNOWN EVENT TYPE IN RESOLVER : #{event_type}\n"
1042
- TheLog.error("ERROR - UNKNOWN EVENT TYPE IN RESOLVER : #{event_type}")
1043
- end
1044
- }
1045
- end
1046
-
1047
- def handle_error_response(select_queue, query_id, error, response) #:nodoc: all
1048
- #Handle an error
1049
- # @mutex.synchronize{
1050
- Dnsruby.log.debug{"handling error #{error.class}, #{error}"}
1051
- # Check what sort of error it was :
1052
- resolver, msg, client_query_id, retry_count = query_id
1053
- msg, client_queue, select_queue, outstanding = @query_list[client_query_id]
1054
- if (error.kind_of?(ResolvTimeout))
1055
- # - if it was a timeout, then check which number it was, and how many retries are expected on that server
1056
- # - if it was the last retry, on the last server, then return a timeout to the client (and clean up)
1057
- # - otherwise, continue
1058
- # Do we have any more packets to send to this resolver?
1059
-
1060
- decrement_resolver_priority(resolver)
1061
- timeouts = @timeouts[client_query_id]
1062
- if (outstanding.empty? && timeouts && timeouts[1].values.empty?)
1063
- Dnsruby.log.debug{"Sending timeout to client"}
1064
- send_result_and_stop_querying(client_queue, client_query_id, select_queue, response, error)
1065
- end
1066
- elsif (error.kind_of?NXDomain)
1067
- # - if it was an NXDomain, then return that to the client, and stop all new queries (and clean up)
1068
- # send_result_and_stop_querying(client_queue, client_query_id, select_queue, response, error)
1069
- increment_resolver_priority(resolver) if (!response.cached)
1070
- stop_querying(client_query_id)
1071
- # @TODO@ Does the client want notified at this point?
1072
- else
1073
- # - if it was any other error, then remove that server from the list for that query
1074
- # If a Too Many Open Files error, then don't remove, but let retry work.
1075
- timeouts = @timeouts[client_query_id]
1076
- if (!(error.to_s=~/Errno::EMFILE/))
1077
- Dnsruby.log.debug{"Removing #{resolver.server} from resolver list for this query"}
1078
- if (timeouts)
1079
- timeouts[1].each do |key, value|
1080
- res = value[0]
1081
- if (res == resolver)
1082
- timeouts[1].delete(key)
1083
- end
1084
- end
1085
- end
1086
- # Also stick it to the back of the list for future queries
1087
- demote_resolver(resolver)
1088
- else
1089
- Dnsruby.log.debug{"NOT Removing #{resolver.server} due to Errno::EMFILE"}
1090
- end
1091
- # - if it was the last server, then return an error to the client (and clean up)
1092
- if (outstanding.empty? && ((!timeouts) || (timeouts && timeouts[1].values.empty?)))
1093
- # if (outstanding.empty?)
1094
- Dnsruby.log.debug{"Sending error to client"}
1095
- send_result_and_stop_querying(client_queue, client_query_id, select_queue, response, error)
1096
- end
1097
- end
1098
- #@TODO@ If we're still sending packets for this query, but none are outstanding, then
1099
- #jumpstart the next query?
1100
- # }
1101
- end
1102
-
1103
- # TO BE CALLED IN A SYNCHRONIZED BLOCK
1104
- def increment_resolver_priority(res)
1105
- TheLog.debug("Incrementing resolver priority for #{res.server}\n")
1106
- # @parent.single_res_mutex.synchronize {
1107
- index = @parent.single_resolvers.index(res)
1108
- if (index > 0)
1109
- @parent.single_resolvers.delete(res)
1110
- @parent.single_resolvers.insert(index-1,res)
1111
- end
1112
- # }
1113
- end
1114
-
1115
- # TO BE CALLED IN A SYNCHRONIZED BLOCK
1116
- def decrement_resolver_priority(res)
1117
- TheLog.debug("Decrementing resolver priority for #{res.server}\n")
1118
- # @parent.single_res_mutex.synchronize {
1119
- index = @parent.single_resolvers.index(res)
1120
- if (index < @parent.single_resolvers.length)
1121
- @parent.single_resolvers.delete(res)
1122
- @parent.single_resolvers.insert(index+1,res)
1123
- end
1124
- # }
1125
- end
1126
-
1127
- # TO BE CALLED IN A SYNCHRONIZED BLOCK
1128
- def demote_resolver(res)
1129
- TheLog.debug("Demoting resolver priority for #{res.server} to bottom\n")
1130
- # @parent.single_res_mutex.synchronize {
1131
- @parent.single_resolvers.delete(res)
1132
- @parent.single_resolvers.push(res)
1133
- # }
1134
- end
1135
-
1136
- def handle_response(select_queue, query_id, response) #:nodoc: all
1137
- # Handle a good response
1138
- # Should also stick resolver more to the front of the list for future queries
1139
- Dnsruby.log.debug{"Handling good response"}
1140
- resolver, msg, client_query_id, retry_count = query_id
1141
- increment_resolver_priority(resolver) if (!response.cached)
1142
- # @mutex.synchronize{
1143
- query, client_queue, s_queue, outstanding = @query_list[client_query_id]
1144
- if (s_queue != select_queue)
1145
- Dnsruby.log.error{"Serious internal error : expected select queue #{s_queue}, got #{select_queue}"}
1146
- raise RuntimeError.new("Serious internal error : expected select queue #{s_queue}, got #{select_queue}")
1147
- end
1148
- stop_querying(client_query_id)
1149
- # @TODO@ Does the client want notified at this point?
1150
- # client_queue.push([client_query_id, Resolver::EventType::RECEIVED, msg, nil])
1151
- # }
1152
- end
1153
-
1154
- def handle_validation_response(select_queue, query_id, response) #:nodoc: all
1155
- resolver, msg, client_query_id, retry_count = query_id
1156
- # @mutex.synchronize {
1157
- query, client_queue, s_queue, outstanding = @query_list[client_query_id]
1158
- if (s_queue != select_queue)
1159
- Dnsruby.log.error{"Serious internal error : expected select queue #{s_queue}, got #{select_queue}"}
1160
- raise RuntimeError.new("Serious internal error : expected select queue #{s_queue}, got #{select_queue}")
1161
- end
1162
- if (response.rcode == RCode.NXDOMAIN)
1163
- send_result(client_queue, client_query_id, select_queue, response, NXDomain.new)
1164
- else
1165
- # @TODO@ Was there an error validating? Should we raise an exception for certain security levels?
1166
- # This should be configurable by the client.
1167
- send_result(client_queue, client_query_id, select_queue, response, nil)
1168
- # }
1169
- end
1170
- end
1171
-
1172
- def handle_validation_error(select_queue, query_id, error, response)
1173
- resolver, msg, client_query_id, retry_count = query_id
1174
- query, client_queue, s_queue, outstanding = @query_list[client_query_id]
1175
- if (s_queue != select_queue)
1176
- Dnsruby.log.error{"Serious internal error : expected select queue #{s_queue}, got #{select_queue}"}
1177
- raise RuntimeError.new("Serious internal error : expected select queue #{s_queue}, got #{select_queue}")
1178
- end
1179
- # For some errors, we immediately send result. For others, should we retry?
1180
- # Either :
1181
- # handle_error_response(queue, event_id, error, response)
1182
- # Or:
1183
- send_result(client_queue, client_query_id, select_queue, response, error)
1184
- #
1185
- #
1186
- end
1187
- end
1188
- end
1189
- require "Dnsruby/SingleResolver"