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
@@ -0,0 +1,305 @@
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/hosts'
17
+ require 'dnsruby/config'
18
+ require "dnsruby/resolver"
19
+ module Dnsruby
20
+
21
+ # == Dnsruby::DNS class
22
+ # Resolv::DNS performs DNS queries.
23
+ #
24
+ # === class methods
25
+ # * Dnsruby::DNS.new(config_info=nil)
26
+ #
27
+ # ((|config_info|)) should be nil, a string or a hash.
28
+ # If nil is given, /etc/resolv.conf and platform specific information is used.
29
+ # If a string is given, it should be a filename which format is same as /etc/resolv.conf.
30
+ # If a hash is given, it may contains information for nameserver, search and ndots as follows.
31
+ #
32
+ # Dnsruby::DNS.new({:nameserver=>["210.251.121.21"], :search=>["ruby-lang.org"], :ndots=>1})
33
+ #
34
+ # * Dnsruby::DNS.open(config_info=nil)
35
+ # * Dnsruby::Resolv::DNS.open(config_info=nil) {|dns| ...}
36
+ #
37
+ # === methods
38
+ # * Dnsruby::DNS#close
39
+ #
40
+ # * Dnsruby::DNS#getaddress(name)
41
+ # * Dnsruby::DNS#getaddresses(name)
42
+ # * Dnsruby::DNS#each_address(name) {|address| ...}
43
+ # address lookup methods.
44
+ #
45
+ # ((|name|)) must be an instance of Dnsruby::Name or String. Resultant
46
+ # address is represented as an instance of Dnsruby::IPv4 or Dnsruby::IPv6.
47
+ #
48
+ # * Dnsruby::DNS#getname(address)
49
+ # * Dnsruby::DNS#getnames(address)
50
+ # * Dnsruby::DNS#each_name(address) {|name| ...}
51
+ # These methods lookup hostnames .
52
+ #
53
+ # ((|address|)) must be an instance of Dnsruby::IPv4, Dnsruby::IPv6 or String.
54
+ # Resultant name is represented as an instance of Dnsruby::Name.
55
+ #
56
+ # * Dnsruby::DNS#getresource(name, type, class)
57
+ # * Dnsruby::DNS#getresources(name, type, class)
58
+ # * Dnsruby::DNS#each_resource(name, type, class) {|resource| ...}
59
+ # These methods lookup DNS resources of ((|name|)).
60
+ # ((|name|)) must be a instance of Dnsruby::Name or String.
61
+ #
62
+ # ((|type|)) must be a member of Dnsruby::Types
63
+ # ((|class|)) must be a member of Dnsruby::Classes
64
+ #
65
+ # Resultant resource is represented as an instance of (a subclass of)
66
+ # Dnsruby::RR.
67
+ # (Dnsruby::RR::IN::A, etc.)
68
+ #
69
+ # The searchlist and other Config info is applied to the domain name if appropriate. All the nameservers
70
+ # are tried (if there is no timely answer from the first).
71
+ #
72
+ # This class uses Resolver to perform the queries.
73
+ #
74
+ # Information taken from the following places :
75
+ # * STD0013
76
+ # * RFC 1035, etc.
77
+ # * ftp://ftp.isi.edu/in-notes/iana/assignments/dns-parameters
78
+ # * etc.
79
+ class DNS
80
+
81
+ attr_accessor :do_caching
82
+
83
+ # Creates a new DNS resolver. See Resolv::DNS.new for argument details.
84
+ #
85
+ # Yields the created DNS resolver to the block, if given, otherwise returns it.
86
+ def self.open(*args)
87
+ dns = new(*args)
88
+ return dns unless block_given?
89
+ begin
90
+ yield dns
91
+ ensure
92
+ dns.close
93
+ end
94
+ end
95
+
96
+ # Closes the resolver
97
+ def close
98
+ @resolver.close
99
+ end
100
+
101
+
102
+ def to_s
103
+ return "DNS : " + @config.to_s
104
+ end
105
+
106
+ # Creates a new DNS resolver
107
+ #
108
+ # +config_info+ can be:
109
+ #
110
+ # * nil:: Uses platform default (e.g. /etc/resolv.conf)
111
+ # * String:: Path to a file using /etc/resolv.conf's format
112
+ # * Hash:: Must contain :nameserver, :search and :ndots keys
113
+ # example :
114
+ #
115
+ # Dnsruby::DNS.new({:nameserver => ['210.251.121.21'],
116
+ # :search => ['ruby-lang.org'],
117
+ # :ndots => 1})
118
+ def initialize(config_info=nil)
119
+ @do_caching = true
120
+ @config = Config.new()
121
+ @config.set_config_info(config_info)
122
+ @resolver = Resolver.new(@config)
123
+ # if (@resolver.single_resolvers.length == 0)
124
+ # raise ArgumentError.new("Must pass at least one valid resolver address")
125
+ # end
126
+ end
127
+
128
+ attr_reader :config
129
+
130
+ # Gets the first IP address of +name+ from the DNS resolver
131
+ #
132
+ # +name+ can be a Dnsruby::Name or a String. Retrieved address will be a
133
+ # Dnsruby::IPv4 or a Dnsruby::IPv6
134
+ def getaddress(name)
135
+ each_address(name) {|address| return address}
136
+ raise ResolvError.new("DNS result has no information for #{name}")
137
+ end
138
+
139
+ # Gets all IP addresses of +name+ from the DNS resolver
140
+ #
141
+ # +name+ can be a Dnsruby::Name or a String. Retrieved address will be a
142
+ # Dnsruby::IPv4 or a Dnsruby::IPv6
143
+ def getaddresses(name)
144
+ ret = []
145
+ each_address(name) {|address| ret << address}
146
+ return ret
147
+ end
148
+
149
+ # Iterates over all IP addresses of +name+ retrieved from the DNS resolver
150
+ #
151
+ # +name+ can be a Dnsruby::Name or a String. Retrieved address will be a
152
+ # Dnsruby::IPv4 or a Dnsruby::IPv6
153
+ def each_address(name)
154
+ each_resource(name) {|resource| yield resource.address}
155
+ end
156
+
157
+ # Gets the first hostname for +address+ from the DNS resolver
158
+ #
159
+ # +address+ must be a Dnsruby::IPv4, Dnsruby::IPv6 or a String. Retrieved
160
+ # name will be a Dnsruby::Name.
161
+ def getname(address)
162
+ each_name(address) {|name| return name}
163
+ raise ResolvError.new("DNS result has no information for #{address}")
164
+ end
165
+
166
+ # Gets all hostnames for +address+ from the DNS resolver
167
+ #
168
+ # +address+ must be a Dnsruby::IPv4, Dnsruby::IPv6 or a String. Retrieved
169
+ # name will be a Dnsruby::Name.
170
+ def getnames(address)
171
+ ret = []
172
+ each_name(address) {|name| ret << name}
173
+ return ret
174
+ end
175
+
176
+ # Iterates over all hostnames for +address+ retrieved from the DNS resolver
177
+ #
178
+ # +address+ must be a Dnsruby::IPv4, Dnsruby::IPv6 or a String. Retrieved
179
+ # name will be a Dnsruby::Name.
180
+ def each_name(address)
181
+ case address
182
+ when Name
183
+ ptr = address
184
+ when IPv4, IPv6
185
+ ptr = address.to_name
186
+ when IPv4::Regex
187
+ ptr = IPv4.create(address).to_name
188
+ when IPv6::Regex
189
+ ptr = IPv6.create(address).to_name
190
+ else
191
+ raise ResolvError.new("cannot interpret as address: #{address}")
192
+ end
193
+ each_resource(ptr, Types.PTR, Classes.IN) {|resource| yield resource.domainname}
194
+ end
195
+
196
+ # Look up the first +type+, +klass+ resource for +name+
197
+ #
198
+ # +type+ defaults to Dnsruby::Types.A
199
+ # +klass+ defaults to Dnsruby::Classes.IN
200
+ #
201
+ # Returned resource is represented as a Dnsruby::RR instance, e.g.
202
+ # Dnsruby::RR::IN::A
203
+ def getresource(name, type=Types.A, klass=Classes.IN)
204
+ each_resource(name, type, klass) {|resource| return resource}
205
+ raise ResolvError.new("DNS result has no information for #{name}")
206
+ end
207
+
208
+ # Look up all +type+, +klass+ resources for +name+
209
+ #
210
+ # +type+ defaults to Dnsruby::Types.A
211
+ # +klass+ defaults to Dnsruby::Classes.IN
212
+ #
213
+ # Returned resource is represented as a Dnsruby::RR instance, e.g.
214
+ # Dnsruby::RR::IN::A
215
+ def getresources(name, type=Types.A, klass=Classes.IN)
216
+ ret = []
217
+ each_resource(name, type, klass) {|resource| ret << resource}
218
+ return ret
219
+ end
220
+
221
+ # Iterates over all +type+, +klass+ resources for +name+
222
+ #
223
+ # +type+ defaults to Dnsruby::Types.A
224
+ # +klass+ defaults to Dnsruby::Classes.IN
225
+ #
226
+ # Yielded resource is represented as a Dnsruby::RR instance, e.g.
227
+ # Dnsruby::RR::IN::A
228
+ def each_resource(name, type=Types.A, klass=Classes.IN, &proc)
229
+ type = Types.new(type)
230
+ klass = Classes.new(klass)
231
+ reply, reply_name = send_query(name, type, klass)
232
+ case reply.rcode.code
233
+ when RCode::NOERROR
234
+ extract_resources(reply, reply_name, type, klass, &proc)
235
+ return
236
+ # when RCode::NXDomain
237
+ # Dnsruby.log.debug("RCode::NXDomain returned - raising error")
238
+ # raise Config::NXDomain.new(reply_name.to_s)
239
+ else
240
+ Dnsruby.log.error{"Unexpected rcode : #{reply.rcode.string}"}
241
+ raise Config::OtherResolvError.new(reply_name.to_s)
242
+ end
243
+ end
244
+
245
+ def extract_resources(msg, name, type, klass) # :nodoc:
246
+ if type == Types.ANY
247
+ n0 = Name.create(name)
248
+ msg.each_answer {|rec|
249
+ yield rec if n0 == rec.name
250
+ }
251
+ end
252
+ yielded = false
253
+ n0 = Name.create(name)
254
+ msg.each_answer {|rec|
255
+ if n0 == rec.name
256
+ case rec.type
257
+ when type
258
+ if (rec.klass == klass)
259
+ yield rec
260
+ yielded = true
261
+ end
262
+ when Types.CNAME
263
+ n0 = rec.domainname
264
+ end
265
+ end
266
+ }
267
+ return if yielded
268
+ msg.each_answer {|rec|
269
+ if n0 == rec.name
270
+ case rec.type
271
+ when type
272
+ if (rec.klass == klass)
273
+ yield rec
274
+ end
275
+ end
276
+ end
277
+ }
278
+ end
279
+
280
+ def send_query(name, type=Types.A, klass=Classes.IN) # :nodoc:
281
+ candidates = @config.generate_candidates(name)
282
+ exception = nil
283
+ candidates.each do |candidate|
284
+ q = Queue.new
285
+ msg = Message.new
286
+ msg.header.rd = 1
287
+ msg.add_question(candidate, type, klass)
288
+ msg.do_validation = false
289
+ msg.header.cd = false
290
+ msg.do_caching = do_caching
291
+ @resolver.do_validation = false
292
+ @resolver.send_async(msg, q)
293
+ id, ret, exception = q.pop
294
+ if (exception == nil && ret && ret.rcode == RCode.NOERROR)
295
+ return ret, ret.question[0].qname
296
+ end
297
+ end
298
+ raise exception
299
+ end
300
+
301
+ end
302
+ end
303
+ # --
304
+ # @TODO@ Asynchronous interface. Some sort of Deferrable?
305
+ # ++
@@ -1,153 +1,153 @@
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
-
17
-
18
- ## This class implements a cache.
19
- # It stores data under qname-qclass-qtype tuples.
20
- # Each tuple indexes a CacheData object (which
21
- # stores a Message, and an expiration).
22
- # If a new Message is stored to a tuple, it will
23
- # overwrite the previous Message.
24
- # When a Message is retrieved from the cache, the header
25
- # and ttls will be "fixed" - i.e. AA cleared, etc.
26
-
27
-
28
-
29
- #@TODO@ Max size for cache?
30
- module Dnsruby
31
- class Cache # :nodoc: all
32
- def initialize()
33
- @cache = Hash.new
34
- @mutex = Mutex.new
35
- end
36
- def cache
37
- @cache
38
- end
39
- def clear()
40
- @mutex.synchronize {
41
- @cache = Hash.new
42
- }
43
- end
44
- def length
45
- return @cache.length
46
- end
47
- def add(message)
48
- q = message.question[0]
49
- key = CacheKey.new(q.qname, q.qtype, q.qclass).to_s
50
- data = CacheData.new(message)
51
- @mutex.synchronize {
52
- if (@cache[key])
53
- TheLog.debug("CACHE REPLACE : #{q.qname}, #{q.qtype}\n")
54
- else
55
- TheLog.debug("CACHE ADD : #{q.qname}, #{q.qtype}\n")
56
- end
57
- @cache[key] = data
58
- }
59
- end
60
- # This method "fixes up" the response, so that the header and ttls are OK
61
- # The resolver will still need to copy the flags and ID across from the query
62
- def find(qname, qtype, qclass = Classes.IN)
63
- # print "CACHE find : #{qname}, #{qtype}\n"
64
- qn = Name.create(qname)
65
- qn.absolute = true
66
- key = CacheKey.new(qn, qtype, qclass).to_s
67
- @mutex.synchronize {
68
- data = @cache[key]
69
- if (!data)
70
- # print "CACHE lookup failed\n"
71
- return nil
72
- end
73
- if (data.expiration <= Time.now.to_i)
74
- @cache.delete(key)
75
- TheLog.debug("CACHE lookup stale\n")
76
- return nil
77
- end
78
- m = data.message
79
- TheLog.debug("CACHE found\n")
80
- return m
81
- }
82
- end
83
- def Cache.delete(qname, qtype, qclass = Classes.IN)
84
- key = CacheKey.new(qname, qtype, qclass)
85
- @mutex.synchronize {
86
- @cache.delete(key)
87
- }
88
- end
89
- class CacheKey # :nodoc: all
90
- attr_accessor :qname, :qtype, :qclass
91
- def initialize(*args)
92
- self.qclass = Classes.IN
93
- if (args.length > 0)
94
- self.qname = Name.create(args[0])
95
- self.qname.absolute = true
96
- if (args.length > 1)
97
- self.qtype = Types.new(args[1])
98
- if (args.length > 2)
99
- self.qclass = Classes.new(args[2])
100
- end
101
- end
102
- end
103
- end
104
- def to_s
105
- return "#{qname.inspect.downcase} #{qclass} #{qtype}"
106
- end
107
- end
108
- class CacheData # :nodoc: all
109
- attr_reader :expiration
110
- def message=(m)
111
- @expiration = get_expiration(m)
112
- @message = Message.decode(m.encode)
113
- @message.cached = true
114
- end
115
- def message
116
- m = Message.decode(@message.encode)
117
- m.cached = true
118
- # @TODO@ What do we do about answerfrom, answersize, etc.?
119
- m.header.aa = false # Anything else to do here?
120
- # Fix up TTLs!!
121
- offset = (Time.now - @time_stored).to_i
122
- m.each_resource {|rr|
123
- next if rr.type == Types::OPT
124
- rr.ttl = rr.ttl - offset
125
- }
126
- return m
127
- end
128
- def get_expiration(m)
129
- # Find the minimum ttl of any of the rrsets
130
- min_ttl = 9999999
131
- m.each_section {|section|
132
- section.rrsets.each {|rrset|
133
- if (rrset.ttl < min_ttl)
134
- min_ttl = rrset.ttl
135
- end
136
- }
137
- }
138
- if (min_ttl == 9999999)
139
- return 0
140
- end
141
- return (Time.now.to_i + min_ttl)
142
- end
143
- def initialize(*args)
144
- @expiration = 0
145
- @time_stored = Time.now.to_i
146
- self.message=(args[0])
147
- end
148
- def to_s
149
- return "#{self.message}"
150
- end
151
- end
152
- end
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
+
17
+
18
+ # # This class implements a cache.
19
+ # It stores data under qname-qclass-qtype tuples.
20
+ # Each tuple indexes a CacheData object (which
21
+ # stores a Message, and an expiration).
22
+ # If a new Message is stored to a tuple, it will
23
+ # overwrite the previous Message.
24
+ # When a Message is retrieved from the cache, the header
25
+ # and ttls will be "fixed" - i.e. AA cleared, etc.
26
+
27
+
28
+
29
+ # @TODO@ Max size for cache?
30
+ module Dnsruby
31
+ class Cache # :nodoc: all
32
+ def initialize()
33
+ @cache = Hash.new
34
+ @mutex = Mutex.new
35
+ end
36
+ def cache
37
+ @cache
38
+ end
39
+ def clear()
40
+ @mutex.synchronize {
41
+ @cache = Hash.new
42
+ }
43
+ end
44
+ def length
45
+ return @cache.length
46
+ end
47
+ def add(message)
48
+ q = message.question[0]
49
+ key = CacheKey.new(q.qname, q.qtype, q.qclass).to_s
50
+ data = CacheData.new(message)
51
+ @mutex.synchronize {
52
+ if (@cache[key])
53
+ TheLog.debug("CACHE REPLACE : #{q.qname}, #{q.qtype}\n")
54
+ else
55
+ TheLog.debug("CACHE ADD : #{q.qname}, #{q.qtype}\n")
56
+ end
57
+ @cache[key] = data
58
+ }
59
+ end
60
+ # This method "fixes up" the response, so that the header and ttls are OK
61
+ # The resolver will still need to copy the flags and ID across from the query
62
+ def find(qname, qtype, qclass = Classes.IN)
63
+ # print "CACHE find : #{qname}, #{qtype}\n"
64
+ qn = Name.create(qname)
65
+ qn.absolute = true
66
+ key = CacheKey.new(qn, qtype, qclass).to_s
67
+ @mutex.synchronize {
68
+ data = @cache[key]
69
+ if (!data)
70
+ # print "CACHE lookup failed\n"
71
+ return nil
72
+ end
73
+ if (data.expiration <= Time.now.to_i)
74
+ @cache.delete(key)
75
+ TheLog.debug("CACHE lookup stale\n")
76
+ return nil
77
+ end
78
+ m = data.message
79
+ TheLog.debug("CACHE found\n")
80
+ return m
81
+ }
82
+ end
83
+ def Cache.delete(qname, qtype, qclass = Classes.IN)
84
+ key = CacheKey.new(qname, qtype, qclass)
85
+ @mutex.synchronize {
86
+ @cache.delete(key)
87
+ }
88
+ end
89
+ class CacheKey # :nodoc: all
90
+ attr_accessor :qname, :qtype, :qclass
91
+ def initialize(*args)
92
+ self.qclass = Classes.IN
93
+ if (args.length > 0)
94
+ self.qname = Name.create(args[0])
95
+ self.qname.absolute = true
96
+ if (args.length > 1)
97
+ self.qtype = Types.new(args[1])
98
+ if (args.length > 2)
99
+ self.qclass = Classes.new(args[2])
100
+ end
101
+ end
102
+ end
103
+ end
104
+ def to_s
105
+ return "#{qname.inspect.downcase} #{qclass} #{qtype}"
106
+ end
107
+ end
108
+ class CacheData # :nodoc: all
109
+ attr_reader :expiration
110
+ def message=(m)
111
+ @expiration = get_expiration(m)
112
+ @message = Message.decode(m.encode)
113
+ @message.cached = true
114
+ end
115
+ def message
116
+ m = Message.decode(@message.encode)
117
+ m.cached = true
118
+ # @TODO@ What do we do about answerfrom, answersize, etc.?
119
+ m.header.aa = false # Anything else to do here?
120
+ # Fix up TTLs!!
121
+ offset = (Time.now - @time_stored).to_i
122
+ m.each_resource {|rr|
123
+ next if rr.type == Types::OPT
124
+ rr.ttl = rr.ttl - offset
125
+ }
126
+ return m
127
+ end
128
+ def get_expiration(m)
129
+ # Find the minimum ttl of any of the rrsets
130
+ min_ttl = 9999999
131
+ m.each_section {|section|
132
+ section.rrsets.each {|rrset|
133
+ if (rrset.ttl < min_ttl)
134
+ min_ttl = rrset.ttl
135
+ end
136
+ }
137
+ }
138
+ if (min_ttl == 9999999)
139
+ return 0
140
+ end
141
+ return (Time.now.to_i + min_ttl)
142
+ end
143
+ def initialize(*args)
144
+ @expiration = 0
145
+ @time_stored = Time.now.to_i
146
+ self.message=(args[0])
147
+ end
148
+ def to_s
149
+ return "#{self.message}"
150
+ end
151
+ end
152
+ end
153
153
  end