dnsruby 1.55 → 1.56.0

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